Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 516324 Details for
Bug 426518
media-tv/oscam ebuild request
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
oscam-2018_0123_emu.patch
oscam-emu.patch (text/plain), 378.15 KB, created by
Wojciech Myrda
on 2018-01-24 09:06:02 UTC
(
hide
)
Description:
oscam-2018_0123_emu.patch
Filename:
MIME Type:
Creator:
Wojciech Myrda
Created:
2018-01-24 09:06:02 UTC
Size:
378.15 KB
patch
obsolete
>Index: CMakeLists.txt >=================================================================== >--- CMakeLists.txt (revision 11398) >+++ CMakeLists.txt (working copy) >@@ -101,6 +101,7 @@ > ${CMAKE_CURRENT_SOURCE_DIR}/csctapi > ${CMAKE_CURRENT_SOURCE_DIR}/cscrypt > ${CMAKE_CURRENT_SOURCE_DIR}/minilzo >+ ${CMAKE_CURRENT_SOURCE_DIR}/ffdecsa > ${CMAKE_CURRENT_SOURCE_DIR}/extapi/cygwin > /usr/include/w32api > ${OPTIONAL_INCLUDE_DIR} >@@ -110,6 +111,7 @@ > ${CMAKE_CURRENT_SOURCE_DIR}/csctapi > ${CMAKE_CURRENT_SOURCE_DIR}/cscrypt > ${CMAKE_CURRENT_SOURCE_DIR}/minilzo >+ ${CMAKE_CURRENT_SOURCE_DIR}/ffdecsa > ${OPTIONAL_INCLUDE_DIR} > ) > endif (OSCamOperatingSystem MATCHES "Windows/Cygwin") >@@ -420,6 +422,13 @@ > # Manage config.h based on command line parameters > # Manipulate config file based on given parameters and read unset parameters > >+execute_process (COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/config.sh --enabled WITH_EMU OUTPUT_VARIABLE CONFIG_WITH_EMU OUTPUT_STRIP_TRAILING_WHITESPACE) >+if (CONFIG_WITH_EMU MATCHES "Y" AND NOT WITH_EMU EQUAL 1) >+ add_definitions ("-DWITH_EMU") >+ set (WITH_EMU "1") >+ message(STATUS " EMU is added by config compiling with EMU") >+endif(CONFIG_WITH_EMU MATCHES "Y" AND NOT WITH_EMU EQUAL 1) >+ > execute_process (COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/config.sh --show-valid OUTPUT_VARIABLE config_vars_string OUTPUT_STRIP_TRAILING_WHITESPACE) > string(REGEX MATCHALL "[A-Z0-9_]+" config_vars ${config_vars_string}) > >@@ -449,6 +458,7 @@ > add_subdirectory (csctapi) > add_subdirectory (minilzo) > add_subdirectory (cscrypt) >+add_subdirectory (ffdecsa) > > #----------------------- file groups ------------------------------ > execute_process (COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/config.sh --enabled MODULE_CAMD33 OUTPUT_VARIABLE CAMD33 OUTPUT_STRIP_TRAILING_WHITESPACE) >@@ -498,7 +508,7 @@ > > set (exe_name "oscam") > add_executable (${exe_name} ${exe_srcs} ${exe_hdrs}) >-target_link_libraries (${exe_name} ${csoscam} ${csmodules} ${csreaders} csctapi cscrypt minilzo) >+target_link_libraries (${exe_name} ${csoscam} ${csmodules} ${csreaders} csctapi cscrypt minilzo ffdecsa) > if(HAVE_LIBRT AND HAVE_LIBUSB) > if (LIBUSBDIR) > set (libusb_link "imp_libusb") >@@ -647,6 +657,11 @@ > execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpmachine COMMAND tr -d '\n' OUTPUT_VARIABLE CS_TARGET) > add_definitions ("-D'CS_TARGET=\"${CS_TARGET}\"'") > #----------------------- global compile and link options ------------------------------ >+#enable sse2 on x86 >+if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") >+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse -msse2 -msse3") >+endif (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") >+ > # disable warning about unused but set variables in gcc 4.6+ > if (CMAKE_COMPILER_IS_GNUCC) > execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) >@@ -731,6 +746,22 @@ > > #-------------------------------------------------------------------------------- > >+if (NOT OSCamOperatingSystem MATCHES "Mac OS X") >+if (NOT DEFINED ENV{ANDROID_NDK}) >+if (NOT DEFINED ENV{ANDROID_STANDALONE_TOOLCHAIN}) >+ if(WITH_EMU) >+ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key) >+ execute_process(COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key ${CMAKE_CURRENT_BINARY_DIR}/SoftCam.Key) >+ else(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key) >+ execute_process(COMMAND touch ${CMAKE_CURRENT_BINARY_DIR}/SoftCam.Key) >+ endif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key) >+ execute_process(COMMAND touch ${CMAKE_CURRENT_BINARY_DIR}/utils/SoftCam.Key) >+ set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--format=binary -Wl,SoftCam.Key -Wl,--format=default" ) >+ endif(WITH_EMU) >+endif (NOT DEFINED ENV{ANDROID_STANDALONE_TOOLCHAIN}) >+endif (NOT DEFINED ENV{ANDROID_NDK}) >+endif (NOT OSCamOperatingSystem MATCHES "Mac OS X") >+ > #----------------------- installation ----------------------------- > > file (GLOB config_files "${CMAKE_CURRENT_SOURCE_DIR}/Distribution/oscam.*") >@@ -819,4 +850,8 @@ > endif(STATICLIBUSB AND NOT LIBUSBDIR) > endif (HAVE_LIBUSB) > >+if (WITH_EMU) >+ message(STATUS " Compile with EMU support") >+endif (WITH_EMU) >+ > message (STATUS "") >Index: Makefile >=================================================================== >--- Makefile (revision 11398) >+++ Makefile (working copy) >@@ -65,6 +65,13 @@ > > LDFLAGS = -Wl,--gc-sections > >+TARGETHELP := $(shell $(CC) --target-help 2>&1) >+ifneq (,$(findstring sse2,$(TARGETHELP))) >+override CFLAGS += -fexpensive-optimizations -mmmx -msse -msse2 -msse3 >+else >+override CFLAGS += -fexpensive-optimizations >+endif >+ > # The linker for powerpc have bug that prevents --gc-sections from working > # Check for the linker version and if it matches disable --gc-sections > # For more information about the bug see: >@@ -268,6 +275,21 @@ > SRC-$(CONFIG_MODULE_CCCAM) += module-cccam.c > SRC-$(CONFIG_MODULE_CCCSHARE) += module-cccshare.c > SRC-$(CONFIG_MODULE_CONSTCW) += module-constcw.c >+SRC-$(CONFIG_WITH_EMU) += module-emulator.c >+SRC-$(CONFIG_WITH_EMU) += module-emulator-osemu.c >+SRC-$(CONFIG_WITH_EMU) += module-emulator-stream.c >+SRC-$(CONFIG_WITH_EMU) += ffdecsa/ffdecsa.c >+UNAME := $(shell uname -s) >+ifneq ($(UNAME),Darwin) >+ifndef ANDROID_NDK >+ifndef ANDROID_STANDALONE_TOOLCHAIN >+ifeq "$(CONFIG_WITH_EMU)" "y" >+TOUCH_SK := $(shell touch SoftCam.Key) >+override LDFLAGS += -Wl,--format=binary -Wl,SoftCam.Key -Wl,--format=default >+endif >+endif >+endif >+endif > SRC-$(CONFIG_CS_CACHEEX) += module-csp.c > SRC-$(CONFIG_CW_CYCLE_CHECK) += module-cw-cycle-check.c > SRC-$(CONFIG_WITH_AZBOX) += module-dvbapi-azbox.c >@@ -365,7 +387,7 @@ > # starts the compilation. > all: > @./config.sh --use-flags "$(USE_FLAGS)" --objdir "$(OBJDIR)" --make-config.mak >- @-mkdir -p $(OBJDIR)/cscrypt $(OBJDIR)/csctapi $(OBJDIR)/minilzo $(OBJDIR)/webif >+ @-mkdir -p $(OBJDIR)/cscrypt $(OBJDIR)/csctapi $(OBJDIR)/minilzo $(OBJDIR)/ffdecsa $(OBJDIR)/webif > @-printf "\ > +-------------------------------------------------------------------------------\n\ > | OSCam ver: $(VER) rev: $(SVN_REV) target: $(TARGET)\n\ >Index: config.h >=================================================================== >--- config.h (revision 11398) >+++ config.h (working copy) >@@ -1,6 +1,7 @@ > #ifndef CONFIG_H_ > #define CONFIG_H_ > >+#define WITH_EMU 1 > #define WEBIF 1 > #define WEBIF_LIVELOG 1 > #define WEBIF_JQUERY 1 >Index: config.sh >=================================================================== >--- config.sh (revision 11398) >+++ config.sh (working copy) >@@ -1,6 +1,6 @@ > #!/bin/sh > >-addons="WEBIF WEBIF_LIVELOG WEBIF_JQUERY TOUCH WITH_SSL HAVE_DVBAPI READ_SDT_CHARSETS IRDETO_GUESSING CS_ANTICASC WITH_DEBUG MODULE_MONITOR WITH_LB CS_CACHEEX CW_CYCLE_CHECK LCDSUPPORT LEDSUPPORT CLOCKFIX IPV6SUPPORT" >+addons="WEBIF WEBIF_LIVELOG WEBIF_JQUERY TOUCH WITH_SSL HAVE_DVBAPI READ_SDT_CHARSETS IRDETO_GUESSING CS_ANTICASC WITH_DEBUG MODULE_MONITOR WITH_LB CS_CACHEEX CW_CYCLE_CHECK LCDSUPPORT LEDSUPPORT CLOCKFIX IPV6SUPPORT WITH_EMU" > protocols="MODULE_CAMD33 MODULE_CAMD35 MODULE_CAMD35_TCP MODULE_NEWCAMD MODULE_CCCAM MODULE_CCCSHARE MODULE_GBOX MODULE_RADEGAST MODULE_SCAM MODULE_SERIAL MODULE_CONSTCW MODULE_PANDORA MODULE_GHTTP" > readers="READER_NAGRA READER_IRDETO READER_CONAX READER_CRYPTOWORKS READER_SECA READER_VIACCESS READER_VIDEOGUARD READER_DRE READER_TONGFANG READER_BULCRYPT READER_GRIFFIN READER_DGCRYPT" > card_readers="CARDREADER_PHOENIX CARDREADER_INTERNAL CARDREADER_SC8IN1 CARDREADER_MP35 CARDREADER_SMARGO CARDREADER_DB2COM CARDREADER_STAPI CARDREADER_STAPI5 CARDREADER_STINGER CARDREADER_DRECAS" >@@ -24,6 +24,7 @@ > # CONFIG_LEDSUPPORT=n > CONFIG_CLOCKFIX=y > # CONFIG_IPV6SUPPORT=n >+CONFIG_WITH_EMU=y > # CONFIG_MODULE_CAMD33=n > CONFIG_MODULE_CAMD35=y > CONFIG_MODULE_CAMD35_TCP=y >@@ -289,12 +290,15 @@ > > update_deps() { > # Calculate dependencies >- enabled_any $(get_opts readers) $(get_opts card_readers) && enable_opt WITH_CARDREADER >/dev/null >- disabled_all $(get_opts readers) $(get_opts card_readers) && disable_opt WITH_CARDREADER >/dev/null >+ enabled_any $(get_opts readers) $(get_opts card_readers) WITH_EMU && enable_opt WITH_CARDREADER >/dev/null >+ disabled_all $(get_opts readers) $(get_opts card_readers) WITH_EMU && disable_opt WITH_CARDREADER >/dev/null > disabled WEBIF && disable_opt WEBIF_LIVELOG >/dev/null > disabled WEBIF && disable_opt WEBIF_JQUERY >/dev/null > enabled MODULE_CCCSHARE && enable_opt MODULE_CCCAM >/dev/null > enabled_any CARDREADER_DB2COM CARDREADER_MP35 CARDREADER_SC8IN1 CARDREADER_STINGER && enable_opt CARDREADER_PHOENIX >/dev/null >+ enabled WITH_EMU && enable_opt READER_VIACCESS >/dev/null >+ enabled WITH_EMU && enable_opt READER_DRE >/dev/null >+ enabled WITH_EMU && enable_opt MODULE_NEWCAMD >/dev/null > } > > list_config() { >@@ -344,9 +348,9 @@ > not_have_flag USE_LIBCRYPTO && echo "CONFIG_LIB_AES=y" || echo "# CONFIG_LIB_AES=n" > enabled MODULE_CCCAM && echo "CONFIG_LIB_RC6=y" || echo "# CONFIG_LIB_RC6=n" > not_have_flag USE_LIBCRYPTO && enabled MODULE_CCCAM && echo "CONFIG_LIB_SHA1=y" || echo "# CONFIG_LIB_SHA1=n" >- enabled_any READER_DRE MODULE_SCAM READER_VIACCESS && echo "CONFIG_LIB_DES=y" || echo "# CONFIG_LIB_DES=n" >- enabled_any MODULE_CCCAM READER_NAGRA READER_SECA && echo "CONFIG_LIB_IDEA=y" || echo "# CONFIG_LIB_IDEA=n" >- not_have_flag USE_LIBCRYPTO && enabled_any READER_CONAX READER_CRYPTOWORKS READER_NAGRA && echo "CONFIG_LIB_BIGNUM=y" || echo "# CONFIG_LIB_BIGNUM=n" >+ enabled_any READER_DRE MODULE_SCAM READER_VIACCESS WITH_EMU && echo "CONFIG_LIB_DES=y" || echo "# CONFIG_LIB_DES=n" >+ enabled_any MODULE_CCCAM READER_NAGRA READER_SECA WITH_EMU && echo "CONFIG_LIB_IDEA=y" || echo "# CONFIG_LIB_IDEA=n" >+ not_have_flag USE_LIBCRYPTO && enabled_any READER_CONAX READER_CRYPTOWORKS READER_NAGRA WITH_EMU && echo "CONFIG_LIB_BIGNUM=y" || echo "# CONFIG_LIB_BIGNUM=n" > } > > make_config_c() { >@@ -457,6 +461,7 @@ > LEDSUPPORT "LED support" $(check_test "LEDSUPPORT") \ > CLOCKFIX "Clockfix (disable on old systems!)" $(check_test "CLOCKFIX") \ > IPV6SUPPORT "IPv6 support (experimental)" $(check_test "IPV6SUPPORT") \ >+ WITH_EMU "Emulator support" $(check_test "WITH_EMU") \ > 2> ${tempfile} > > opt=${?} >Index: cscrypt/aes.c >=================================================================== >--- cscrypt/aes.c (revision 11398) >+++ cscrypt/aes.c (working copy) >@@ -1250,4 +1250,71 @@ > rk[3]; > PUTU32(out + 12, s3); > } >+ >+void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, >+ const unsigned long length, const AES_KEY *key, >+ unsigned char *ivec, const int enc) >+{ >+ unsigned long n; >+ unsigned long len = length; >+ unsigned char tmp[AES_BLOCK_SIZE]; >+ >+ assert(in && out && key && ivec); >+ assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc)); >+ >+ if(AES_ENCRYPT == enc) >+ { >+ while(len >= AES_BLOCK_SIZE) >+ { >+ for(n=0; n < AES_BLOCK_SIZE; ++n) >+ tmp[n] = in[n] ^ ivec[n]; >+ >+ AES_encrypt(tmp, out, key); >+ memcpy(ivec, out, AES_BLOCK_SIZE); >+ len -= AES_BLOCK_SIZE; >+ in += AES_BLOCK_SIZE; >+ out += AES_BLOCK_SIZE; >+ } >+ >+ if(len) >+ { >+ for(n=0; n < len; ++n) >+ tmp[n] = in[n] ^ ivec[n]; >+ >+ for(n=len; n < AES_BLOCK_SIZE; ++n) >+ tmp[n] = ivec[n]; >+ >+ AES_encrypt(tmp, tmp, key); >+ memcpy(out, tmp, AES_BLOCK_SIZE); >+ memcpy(ivec, tmp, AES_BLOCK_SIZE); >+ } >+ } >+ else >+ { >+ while(len >= AES_BLOCK_SIZE) >+ { >+ memcpy(tmp, in, AES_BLOCK_SIZE); >+ AES_decrypt(in, out, key); >+ >+ for(n=0; n < AES_BLOCK_SIZE; ++n) >+ out[n] ^= ivec[n]; >+ >+ memcpy(ivec, tmp, AES_BLOCK_SIZE); >+ len -= AES_BLOCK_SIZE; >+ in += AES_BLOCK_SIZE; >+ out += AES_BLOCK_SIZE; >+ } >+ >+ if(len) >+ { >+ memcpy(tmp, in, AES_BLOCK_SIZE); >+ AES_decrypt(tmp, tmp, key); >+ >+ for(n=0; n < len; ++n) >+ out[n] ^= ivec[n]; >+ >+ memcpy(ivec, tmp, AES_BLOCK_SIZE); >+ } >+ } >+} > #endif >Index: cscrypt/aes.h >=================================================================== >--- cscrypt/aes.h (revision 11398) >+++ cscrypt/aes.h (working copy) >@@ -42,6 +42,9 @@ > void AES_decrypt(const unsigned char *in, unsigned char *out, > const AES_KEY *key); > >+void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, >+ const unsigned long length, const AES_KEY *key, >+ unsigned char *ivec, const int enc); > #endif /* !HEADER_AES_H */ > > #endif >Index: cscrypt/md5.c >=================================================================== >--- cscrypt/md5.c (revision 11398) >+++ cscrypt/md5.c (working copy) >@@ -25,13 +25,6 @@ > > #if !defined(WITH_SSL) && !defined(WITH_LIBCRYPTO) > >-typedef struct MD5Context >-{ >- uint32_t buf[4]; >- uint32_t bits[2]; >- uint32_t in[16]; >-} MD5_CTX; >- > #ifdef __i386__ > #define byteReverse(a, b) > #else >@@ -155,7 +148,7 @@ > * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious > * initialization constants. > */ >-static void MD5_Init(MD5_CTX *ctx) >+void MD5_Init(MD5_CTX *ctx) > { > ctx->buf[0] = 0x67452301; > ctx->buf[1] = 0xefcdab89; >@@ -170,7 +163,7 @@ > * Update context to reflect the concatenation of another buffer full > * of bytes. > */ >-static void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, unsigned int len) >+void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, unsigned int len) > { > uint32_t t; > >@@ -219,7 +212,7 @@ > * Final wrapup - pad to 64-byte boundary with the bit pattern > * 1 0* (64-bit count of bits processed, MSB-first) > */ >-static void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) >+void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) > { > unsigned count; > unsigned char *p; >Index: cscrypt/md5.h >=================================================================== >--- cscrypt/md5.h (revision 11398) >+++ cscrypt/md5.h (working copy) >@@ -7,8 +7,16 @@ > #define MD5_DIGEST_LENGTH 16 > > unsigned char *MD5(const unsigned char *input, unsigned long len, unsigned char *output_hash); >-#endif > >-char *__md5_crypt(const char *text_pass, const char *salt, char *crypted_passwd); >+typedef struct MD5Context { >+ uint32_t buf[4]; >+ uint32_t bits[2]; >+ uint32_t in[16]; >+} MD5_CTX; > >+void MD5_Init(MD5_CTX *ctx); >+void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, unsigned int len); >+void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx); > #endif >+char *__md5_crypt(const char *text_pass, const char *salt, char *crypted_passwd); >+#endif >Index: csctapi/cardreaders.h >=================================================================== >--- csctapi/cardreaders.h (revision 11398) >+++ csctapi/cardreaders.h (working copy) >@@ -14,5 +14,6 @@ > extern const struct s_cardreader cardreader_stapi; > extern const struct s_cardreader cardreader_stinger; > extern const struct s_cardreader cardreader_drecas; >+extern const struct s_cardreader cardreader_emu; > > #endif >Index: ffdecsa/CMakeLists.txt >=================================================================== >--- ffdecsa/CMakeLists.txt (revision 0) >+++ ffdecsa/CMakeLists.txt (working copy) >@@ -0,0 +1,8 @@ >+project (ffdecsa) >+ >+file (GLOB ffdecsa_srcs "ffdecsa.c") >+file (GLOB ffdecsa_hdrs "*.h") >+ >+set (lib_name "ffdecsa") >+ >+add_library (${lib_name} STATIC ${ffdecsa_srcs} ${ffdecsa_hdrs}) >Index: ffdecsa/COPYING >=================================================================== >--- ffdecsa/COPYING (revision 0) >+++ ffdecsa/COPYING (working copy) >@@ -0,0 +1,339 @@ >+ GNU GENERAL PUBLIC LICENSE >+ Version 2, June 1991 >+ >+ Copyright (C) 1989, 1991 Free Software Foundation, Inc. >+ 675 Mass Ave, Cambridge, MA 02139, USA >+ Everyone is permitted to copy and distribute verbatim copies >+ of this license document, but changing it is not allowed. >+ >+ Preamble >+ >+ The licenses for most software are designed to take away your >+freedom to share and change it. By contrast, the GNU General Public >+License is intended to guarantee your freedom to share and change free >+software--to make sure the software is free for all its users. This >+General Public License applies to most of the Free Software >+Foundation's software and to any other program whose authors commit to >+using it. (Some other Free Software Foundation software is covered by >+the GNU Library General Public License instead.) You can apply it to >+your programs, too. >+ >+ When we speak of free software, we are referring to freedom, not >+price. Our General Public Licenses are designed to make sure that you >+have the freedom to distribute copies of free software (and charge for >+this service if you wish), that you receive source code or can get it >+if you want it, that you can change the software or use pieces of it >+in new free programs; and that you know you can do these things. >+ >+ To protect your rights, we need to make restrictions that forbid >+anyone to deny you these rights or to ask you to surrender the rights. >+These restrictions translate to certain responsibilities for you if you >+distribute copies of the software, or if you modify it. >+ >+ For example, if you distribute copies of such a program, whether >+gratis or for a fee, you must give the recipients all the rights that >+you have. You must make sure that they, too, receive or can get the >+source code. And you must show them these terms so they know their >+rights. >+ >+ We protect your rights with two steps: (1) copyright the software, and >+(2) offer you this license which gives you legal permission to copy, >+distribute and/or modify the software. >+ >+ Also, for each author's protection and ours, we want to make certain >+that everyone understands that there is no warranty for this free >+software. If the software is modified by someone else and passed on, we >+want its recipients to know that what they have is not the original, so >+that any problems introduced by others will not reflect on the original >+authors' reputations. >+ >+ Finally, any free program is threatened constantly by software >+patents. We wish to avoid the danger that redistributors of a free >+program will individually obtain patent licenses, in effect making the >+program proprietary. To prevent this, we have made it clear that any >+patent must be licensed for everyone's free use or not licensed at all. >+ >+ The precise terms and conditions for copying, distribution and >+modification follow. >+ >+ GNU GENERAL PUBLIC LICENSE >+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION >+ >+ 0. This License applies to any program or other work which contains >+a notice placed by the copyright holder saying it may be distributed >+under the terms of this General Public License. The "Program", below, >+refers to any such program or work, and a "work based on the Program" >+means either the Program or any derivative work under copyright law: >+that is to say, a work containing the Program or a portion of it, >+either verbatim or with modifications and/or translated into another >+language. (Hereinafter, translation is included without limitation in >+the term "modification".) Each licensee is addressed as "you". >+ >+Activities other than copying, distribution and modification are not >+covered by this License; they are outside its scope. The act of >+running the Program is not restricted, and the output from the Program >+is covered only if its contents constitute a work based on the >+Program (independent of having been made by running the Program). >+Whether that is true depends on what the Program does. >+ >+ 1. You may copy and distribute verbatim copies of the Program's >+source code as you receive it, in any medium, provided that you >+conspicuously and appropriately publish on each copy an appropriate >+copyright notice and disclaimer of warranty; keep intact all the >+notices that refer to this License and to the absence of any warranty; >+and give any other recipients of the Program a copy of this License >+along with the Program. >+ >+You may charge a fee for the physical act of transferring a copy, and >+you may at your option offer warranty protection in exchange for a fee. >+ >+ 2. You may modify your copy or copies of the Program or any portion >+of it, thus forming a work based on the Program, and copy and >+distribute such modifications or work under the terms of Section 1 >+above, provided that you also meet all of these conditions: >+ >+ a) You must cause the modified files to carry prominent notices >+ stating that you changed the files and the date of any change. >+ >+ b) You must cause any work that you distribute or publish, that in >+ whole or in part contains or is derived from the Program or any >+ part thereof, to be licensed as a whole at no charge to all third >+ parties under the terms of this License. >+ >+ c) If the modified program normally reads commands interactively >+ when run, you must cause it, when started running for such >+ interactive use in the most ordinary way, to print or display an >+ announcement including an appropriate copyright notice and a >+ notice that there is no warranty (or else, saying that you provide >+ a warranty) and that users may redistribute the program under >+ these conditions, and telling the user how to view a copy of this >+ License. (Exception: if the Program itself is interactive but >+ does not normally print such an announcement, your work based on >+ the Program is not required to print an announcement.) >+ >+These requirements apply to the modified work as a whole. If >+identifiable sections of that work are not derived from the Program, >+and can be reasonably considered independent and separate works in >+themselves, then this License, and its terms, do not apply to those >+sections when you distribute them as separate works. But when you >+distribute the same sections as part of a whole which is a work based >+on the Program, the distribution of the whole must be on the terms of >+this License, whose permissions for other licensees extend to the >+entire whole, and thus to each and every part regardless of who wrote it. >+ >+Thus, it is not the intent of this section to claim rights or contest >+your rights to work written entirely by you; rather, the intent is to >+exercise the right to control the distribution of derivative or >+collective works based on the Program. >+ >+In addition, mere aggregation of another work not based on the Program >+with the Program (or with a work based on the Program) on a volume of >+a storage or distribution medium does not bring the other work under >+the scope of this License. >+ >+ 3. You may copy and distribute the Program (or a work based on it, >+under Section 2) in object code or executable form under the terms of >+Sections 1 and 2 above provided that you also do one of the following: >+ >+ a) Accompany it with the complete corresponding machine-readable >+ source code, which must be distributed under the terms of Sections >+ 1 and 2 above on a medium customarily used for software interchange; or, >+ >+ b) Accompany it with a written offer, valid for at least three >+ years, to give any third party, for a charge no more than your >+ cost of physically performing source distribution, a complete >+ machine-readable copy of the corresponding source code, to be >+ distributed under the terms of Sections 1 and 2 above on a medium >+ customarily used for software interchange; or, >+ >+ c) Accompany it with the information you received as to the offer >+ to distribute corresponding source code. (This alternative is >+ allowed only for noncommercial distribution and only if you >+ received the program in object code or executable form with such >+ an offer, in accord with Subsection b above.) >+ >+The source code for a work means the preferred form of the work for >+making modifications to it. For an executable work, complete source >+code means all the source code for all modules it contains, plus any >+associated interface definition files, plus the scripts used to >+control compilation and installation of the executable. However, as a >+special exception, the source code distributed need not include >+anything that is normally distributed (in either source or binary >+form) with the major components (compiler, kernel, and so on) of the >+operating system on which the executable runs, unless that component >+itself accompanies the executable. >+ >+If distribution of executable or object code is made by offering >+access to copy from a designated place, then offering equivalent >+access to copy the source code from the same place counts as >+distribution of the source code, even though third parties are not >+compelled to copy the source along with the object code. >+ >+ 4. You may not copy, modify, sublicense, or distribute the Program >+except as expressly provided under this License. Any attempt >+otherwise to copy, modify, sublicense or distribute the Program is >+void, and will automatically terminate your rights under this License. >+However, parties who have received copies, or rights, from you under >+this License will not have their licenses terminated so long as such >+parties remain in full compliance. >+ >+ 5. You are not required to accept this License, since you have not >+signed it. However, nothing else grants you permission to modify or >+distribute the Program or its derivative works. These actions are >+prohibited by law if you do not accept this License. Therefore, by >+modifying or distributing the Program (or any work based on the >+Program), you indicate your acceptance of this License to do so, and >+all its terms and conditions for copying, distributing or modifying >+the Program or works based on it. >+ >+ 6. Each time you redistribute the Program (or any work based on the >+Program), the recipient automatically receives a license from the >+original licensor to copy, distribute or modify the Program subject to >+these terms and conditions. You may not impose any further >+restrictions on the recipients' exercise of the rights granted herein. >+You are not responsible for enforcing compliance by third parties to >+this License. >+ >+ 7. If, as a consequence of a court judgment or allegation of patent >+infringement or for any other reason (not limited to patent issues), >+conditions are imposed on you (whether by court order, agreement or >+otherwise) that contradict the conditions of this License, they do not >+excuse you from the conditions of this License. If you cannot >+distribute so as to satisfy simultaneously your obligations under this >+License and any other pertinent obligations, then as a consequence you >+may not distribute the Program at all. For example, if a patent >+license would not permit royalty-free redistribution of the Program by >+all those who receive copies directly or indirectly through you, then >+the only way you could satisfy both it and this License would be to >+refrain entirely from distribution of the Program. >+ >+If any portion of this section is held invalid or unenforceable under >+any particular circumstance, the balance of the section is intended to >+apply and the section as a whole is intended to apply in other >+circumstances. >+ >+It is not the purpose of this section to induce you to infringe any >+patents or other property right claims or to contest validity of any >+such claims; this section has the sole purpose of protecting the >+integrity of the free software distribution system, which is >+implemented by public license practices. Many people have made >+generous contributions to the wide range of software distributed >+through that system in reliance on consistent application of that >+system; it is up to the author/donor to decide if he or she is willing >+to distribute software through any other system and a licensee cannot >+impose that choice. >+ >+This section is intended to make thoroughly clear what is believed to >+be a consequence of the rest of this License. >+ >+ 8. If the distribution and/or use of the Program is restricted in >+certain countries either by patents or by copyrighted interfaces, the >+original copyright holder who places the Program under this License >+may add an explicit geographical distribution limitation excluding >+those countries, so that distribution is permitted only in or among >+countries not thus excluded. In such case, this License incorporates >+the limitation as if written in the body of this License. >+ >+ 9. The Free Software Foundation may publish revised and/or new versions >+of the General Public License from time to time. Such new versions will >+be similar in spirit to the present version, but may differ in detail to >+address new problems or concerns. >+ >+Each version is given a distinguishing version number. If the Program >+specifies a version number of this License which applies to it and "any >+later version", you have the option of following the terms and conditions >+either of that version or of any later version published by the Free >+Software Foundation. If the Program does not specify a version number of >+this License, you may choose any version ever published by the Free Software >+Foundation. >+ >+ 10. If you wish to incorporate parts of the Program into other free >+programs whose distribution conditions are different, write to the author >+to ask for permission. For software which is copyrighted by the Free >+Software Foundation, write to the Free Software Foundation; we sometimes >+make exceptions for this. Our decision will be guided by the two goals >+of preserving the free status of all derivatives of our free software and >+of promoting the sharing and reuse of software generally. >+ >+ NO WARRANTY >+ >+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY >+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN >+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES >+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED >+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF >+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS >+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE >+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, >+REPAIR OR CORRECTION. >+ >+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING >+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR >+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, >+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING >+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED >+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY >+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER >+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE >+POSSIBILITY OF SUCH DAMAGES. >+ >+ END OF TERMS AND CONDITIONS >+ >+ Appendix: How to Apply These Terms to Your New Programs >+ >+ If you develop a new program, and you want it to be of the greatest >+possible use to the public, the best way to achieve this is to make it >+free software which everyone can redistribute and change under these terms. >+ >+ To do so, attach the following notices to the program. It is safest >+to attach them to the start of each source file to most effectively >+convey the exclusion of warranty; and each file should have at least >+the "copyright" line and a pointer to where the full notice is found. >+ >+ <one line to give the program's name and a brief idea of what it does.> >+ Copyright (C) 19yy <name of author> >+ >+ This program is free software; you can redistribute it and/or modify >+ it under the terms of the GNU General Public License as published by >+ the Free Software Foundation; either version 2 of the License, or >+ (at your option) any later version. >+ >+ This program is distributed in the hope that it will be useful, >+ but WITHOUT ANY WARRANTY; without even the implied warranty of >+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ GNU General Public License for more details. >+ >+ You should have received a copy of the GNU General Public License >+ along with this program; if not, write to the Free Software >+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ >+Also add information on how to contact you by electronic and paper mail. >+ >+If the program is interactive, make it output a short notice like this >+when it starts in an interactive mode: >+ >+ Gnomovision version 69, Copyright (C) 19yy name of author >+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. >+ This is free software, and you are welcome to redistribute it >+ under certain conditions; type `show c' for details. >+ >+The hypothetical commands `show w' and `show c' should show the appropriate >+parts of the General Public License. Of course, the commands you use may >+be called something other than `show w' and `show c'; they could even be >+mouse-clicks or menu items--whatever suits your program. >+ >+You should also get your employer (if you work as a programmer) or your >+school, if any, to sign a "copyright disclaimer" for the program, if >+necessary. Here is a sample; alter the names: >+ >+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program >+ `Gnomovision' (which makes passes at compilers) written by James Hacker. >+ >+ <signature of Ty Coon>, 1 April 1989 >+ Ty Coon, President of Vice >+ >+This General Public License does not permit incorporating your program into >+proprietary programs. If your program is a subroutine library, you may >+consider it more useful to permit linking proprietary applications with the >+library. If this is what you want to do, use the GNU Library General >+Public License instead of this License. >Index: ffdecsa/Makefile >=================================================================== >--- ffdecsa/Makefile (revision 0) >+++ ffdecsa/Makefile (working copy) >@@ -0,0 +1,2 @@ >+parent: >+ @$(MAKE) --no-print-directory -C .. >Index: ffdecsa/ffdecsa.c >=================================================================== >--- ffdecsa/ffdecsa.c (revision 0) >+++ ffdecsa/ffdecsa.c (working copy) >@@ -0,0 +1,926 @@ >+/* FFdecsa -- fast decsa algorithm >+ * >+ * Copyright (C) 2003-2004 fatih89r >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License as published by >+ * the Free Software Foundation; either version 2 of the License, or >+ * (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program; if not, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+ >+#include <sys/types.h> >+#include <string.h> >+#include <stdio.h> >+#include <stdlib.h> >+ >+#include "ffdecsa.h" >+ >+#ifndef NULL >+#define NULL 0 >+#endif >+ >+//#define DEBUG >+#ifdef DEBUG >+#define DBG(a) a >+#else >+#define DBG(a) >+#endif >+ >+//// parallelization stuff, large speed differences are possible >+// possible choices >+#define PARALLEL_32_4CHAR 320 >+#define PARALLEL_32_4CHARA 321 >+#define PARALLEL_32_INT 322 >+#define PARALLEL_64_8CHAR 640 >+#define PARALLEL_64_8CHARA 641 >+#define PARALLEL_64_2INT 642 >+#define PARALLEL_64_LONG 643 >+#define PARALLEL_64_MMX 644 >+#define PARALLEL_128_16CHAR 1280 >+#define PARALLEL_128_16CHARA 1281 >+#define PARALLEL_128_4INT 1282 >+#define PARALLEL_128_2LONG 1283 >+#define PARALLEL_128_2MMX 1284 >+#define PARALLEL_128_SSE 1285 >+#define PARALLEL_128_SSE2 1286 >+ >+//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// >+#ifndef PARALLEL_MODE >+ >+#if defined(__x86_64__) || defined(_M_X64) >+#define PARALLEL_MODE PARALLEL_128_SSE2 >+ >+#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) >+#define PARALLEL_MODE PARALLEL_64_LONG >+ >+#elif defined(__sh__) || defined(__SH4__) >+#define PARALLEL_MODE PARALLEL_32_INT >+#define COPY_UNALIGNED_PKT >+#define MEMALIGN_VAL 4 >+ >+#else >+#define PARALLEL_MODE PARALLEL_32_INT >+#endif >+ >+#endif >+//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// >+ >+#include "parallel_generic.h" >+//// conditionals >+#if PARALLEL_MODE==PARALLEL_32_4CHAR >+#include "parallel_032_4char.h" >+#elif PARALLEL_MODE==PARALLEL_32_4CHARA >+#include "parallel_032_4charA.h" >+#elif PARALLEL_MODE==PARALLEL_32_INT >+#include "parallel_032_int.h" >+#elif PARALLEL_MODE==PARALLEL_64_8CHAR >+#include "parallel_064_8char.h" >+#elif PARALLEL_MODE==PARALLEL_64_8CHARA >+#include "parallel_064_8charA.h" >+#elif PARALLEL_MODE==PARALLEL_64_2INT >+#include "parallel_064_2int.h" >+#elif PARALLEL_MODE==PARALLEL_64_LONG >+#include "parallel_064_long.h" >+#elif PARALLEL_MODE==PARALLEL_64_MMX >+#include "parallel_064_mmx.h" >+#elif PARALLEL_MODE==PARALLEL_128_16CHAR >+#include "parallel_128_16char.h" >+#elif PARALLEL_MODE==PARALLEL_128_16CHARA >+#include "parallel_128_16charA.h" >+#elif PARALLEL_MODE==PARALLEL_128_4INT >+#include "parallel_128_4int.h" >+#elif PARALLEL_MODE==PARALLEL_128_2LONG >+#include "parallel_128_2long.h" >+#elif PARALLEL_MODE==PARALLEL_128_2MMX >+#include "parallel_128_2mmx.h" >+#elif PARALLEL_MODE==PARALLEL_128_SSE >+#include "parallel_128_sse.h" >+#elif PARALLEL_MODE==PARALLEL_128_SSE2 >+#include "parallel_128_sse2.h" >+#else >+#error "unknown/undefined parallel mode" >+#endif >+ >+// stuff depending on conditionals >+ >+#define BYTES_PER_GROUP (GROUP_PARALLELISM/8) >+#define BYPG BYTES_PER_GROUP >+#define BITS_PER_GROUP GROUP_PARALLELISM >+#define BIPG BITS_PER_GROUP >+ >+// platform specific >+ >+#ifdef __arm__ >+#if !defined(MEMALIGN_VAL) || MEMALIGN_VAL<4 >+#undef MEMALIGN_VAL >+#define MEMALIGN_VAL 4 >+#endif >+#define COPY_UNALIGNED_PKT >+#endif >+ >+// >+ >+#ifndef MALLOC >+#define MALLOC(X) malloc(X) >+#endif >+#ifndef FREE >+#define FREE(X) free(X) >+#endif >+#ifdef MEMALIGN_VAL >+#define MEMALIGN __attribute__((aligned(MEMALIGN_VAL))) >+#else >+#define MEMALIGN >+#endif >+ >+//// debug tool >+ >+#ifdef DEBUG >+static void dump_mem(const char *string, const unsigned char *p, int len, int linelen){ >+ int i; >+ for(i=0;i<len;i++){ >+ if(i%linelen==0&&i) fprintf(stderr,"\n"); >+ if(i%linelen==0) fprintf(stderr,"%s %08x:",string,i); >+ else{ >+ if(i%8==0) fprintf(stderr," "); >+ if(i%4==0) fprintf(stderr," "); >+ } >+ fprintf(stderr," %02x",p[i]); >+ } >+ if(i%linelen==0) fprintf(stderr,"\n"); >+} >+#endif >+ >+////////////////////////////////////////////////////////////////////////////////// >+ >+struct csa_key_t{ >+ unsigned char ck[8]; >+// used by stream >+ int iA[8]; // iA[0] is for A1, iA[7] is for A8 >+ int iB[8]; // iB[0] is for B1, iB[7] is for B8 >+// used by stream (group) >+ MEMALIGN group ck_g[8][8]; // [byte][bit:0=LSB,7=MSB] >+ MEMALIGN group iA_g[8][4]; // [0 for A1][0 for LSB] >+ MEMALIGN group iB_g[8][4]; // [0 for B1][0 for LSB] >+// used by block >+ unsigned char kk[56]; >+// used by block (group) >+ MEMALIGN batch kkmulti[56]; // many times the same byte in every batch >+}; >+ >+struct csa_keys_t{ >+ struct csa_key_t even; >+ struct csa_key_t odd; >+}; >+ >+//-----stream cypher >+ >+//-----key schedule for stream decypher >+static void key_schedule_stream( >+ unsigned char *ck, // [In] ck[0]-ck[7] 8 bytes | Key. >+ int *iA, // [Out] iA[0]-iA[7] 8 nibbles | Key schedule. >+ int *iB) // [Out] iB[0]-iB[7] 8 nibbles | Key schedule. >+{ >+ iA[0]=(ck[0]>>4)&0xf; >+ iA[1]=(ck[0] )&0xf; >+ iA[2]=(ck[1]>>4)&0xf; >+ iA[3]=(ck[1] )&0xf; >+ iA[4]=(ck[2]>>4)&0xf; >+ iA[5]=(ck[2] )&0xf; >+ iA[6]=(ck[3]>>4)&0xf; >+ iA[7]=(ck[3] )&0xf; >+ iB[0]=(ck[4]>>4)&0xf; >+ iB[1]=(ck[4] )&0xf; >+ iB[2]=(ck[5]>>4)&0xf; >+ iB[3]=(ck[5] )&0xf; >+ iB[4]=(ck[6]>>4)&0xf; >+ iB[5]=(ck[6] )&0xf; >+ iB[6]=(ck[7]>>4)&0xf; >+ iB[7]=(ck[7] )&0xf; >+} >+ >+//----- stream main function >+ >+#define STREAM_INIT >+#include "stream.c" >+#undef STREAM_INIT >+ >+#define STREAM_NORMAL >+#include "stream.c" >+#undef STREAM_NORMAL >+ >+ >+//-----block decypher >+ >+//-----key schedule for block decypher >+ >+static void key_schedule_block( >+ unsigned char *ck, // [In] ck[0]-ck[7] 8 bytes | Key. >+ unsigned char *kk) // [Out] kk[0]-kk[55] 56 bytes | Key schedule. >+{ >+ static const unsigned char key_perm[0x40] = { >+ 0x12,0x24,0x09,0x07,0x2A,0x31,0x1D,0x15, 0x1C,0x36,0x3E,0x32,0x13,0x21,0x3B,0x40, >+ 0x18,0x14,0x25,0x27,0x02,0x35,0x1B,0x01, 0x22,0x04,0x0D,0x0E,0x39,0x28,0x1A,0x29, >+ 0x33,0x23,0x34,0x0C,0x16,0x30,0x1E,0x3A, 0x2D,0x1F,0x08,0x19,0x17,0x2F,0x3D,0x11, >+ 0x3C,0x05,0x38,0x2B,0x0B,0x06,0x0A,0x2C, 0x20,0x3F,0x2E,0x0F,0x03,0x26,0x10,0x37, >+ }; >+ >+ int i,j,k; >+ int bit[64]; >+ int newbit[64]; >+ int kb[7][8]; >+ >+ // 56 steps >+ // 56 key bytes kk(55)..kk(0) by key schedule from ck >+ >+ // kb(6,0) .. kb(6,7) = ck(0) .. ck(7) >+ kb[6][0] = ck[0]; >+ kb[6][1] = ck[1]; >+ kb[6][2] = ck[2]; >+ kb[6][3] = ck[3]; >+ kb[6][4] = ck[4]; >+ kb[6][5] = ck[5]; >+ kb[6][6] = ck[6]; >+ kb[6][7] = ck[7]; >+ >+ // calculate kb[5] .. kb[0] >+ for(i=5; i>=0; i--){ >+ // 64 bit perm on kb >+ for(j=0; j<8; j++){ >+ for(k=0; k<8; k++){ >+ bit[j*8+k] = (kb[i+1][j] >> (7-k)) & 1; >+ newbit[key_perm[j*8+k]-1] = bit[j*8+k]; >+ } >+ } >+ for(j=0; j<8; j++){ >+ kb[i][j] = 0; >+ for(k=0; k<8; k++){ >+ kb[i][j] |= newbit[j*8+k] << (7-k); >+ } >+ } >+ } >+ >+ // xor to give kk >+ for(i=0; i<7; i++){ >+ for(j=0; j<8; j++){ >+ kk[i*8+j] = kb[i][j] ^ i; >+ } >+ } >+ >+} >+ >+//-----block utils >+ >+static inline __attribute__((always_inline)) void trasp_N_8 (unsigned char *in,unsigned char* out,int count){ >+ int *ri=(int *)in; >+ int *ibi=(int *)out; >+ int j,i,k,g; >+ // copy and first step >+ for(g=0;g<count;g++){ >+ ri[g]=ibi[2*g]; >+ ri[GROUP_PARALLELISM+g]=ibi[2*g+1]; >+ } >+//dump_mem("NE1 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); >+// now 01230123 >+#define INTS_PER_ROW (GROUP_PARALLELISM/8*2) >+ for(j=0;j<8;j+=4){ >+ for(i=0;i<2;i++){ >+ for(k=0;k<INTS_PER_ROW;k++){ >+ unsigned int t,b; >+ t=ri[INTS_PER_ROW*(j+i)+k]; >+ b=ri[INTS_PER_ROW*(j+i+2)+k]; >+ ri[INTS_PER_ROW*(j+i)+k]= (t&0x0000ffff) | ((b )<<16); >+ ri[INTS_PER_ROW*(j+i+2)+k]= ((t )>>16) | (b&0xffff0000) ; >+ } >+ } >+ } >+//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); >+// now 01010101 >+ for(j=0;j<8;j+=2){ >+ for(i=0;i<1;i++){ >+ for(k=0;k<INTS_PER_ROW;k++){ >+ unsigned int t,b; >+ t=ri[INTS_PER_ROW*(j+i)+k]; >+ b=ri[INTS_PER_ROW*(j+i+1)+k]; >+ ri[INTS_PER_ROW*(j+i)+k]= (t&0x00ff00ff) | ((b&0x00ff00ff)<<8); >+ ri[INTS_PER_ROW*(j+i+1)+k]= ((t&0xff00ff00)>>8) | (b&0xff00ff00); >+ } >+ } >+ } >+//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); >+// now 00000000 >+} >+ >+static inline __attribute__((always_inline)) void trasp_8_N (unsigned char *in,unsigned char* out,int count){ >+ int *ri=(int *)in; >+ int *bdi=(int *)out; >+ int j,i,k,g; >+#define INTS_PER_ROW (GROUP_PARALLELISM/8*2) >+//dump_mem("NE1 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); >+// now 00000000 >+ for(j=0;j<8;j+=2){ >+ for(i=0;i<1;i++){ >+ for(k=0;k<INTS_PER_ROW;k++){ >+ unsigned int t,b; >+ t=ri[INTS_PER_ROW*(j+i)+k]; >+ b=ri[INTS_PER_ROW*(j+i+1)+k]; >+ ri[INTS_PER_ROW*(j+i)+k]= (t&0x00ff00ff) | ((b&0x00ff00ff)<<8); >+ ri[INTS_PER_ROW*(j+i+1)+k]= ((t&0xff00ff00)>>8) | (b&0xff00ff00); >+ } >+ } >+ } >+//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); >+// now 01010101 >+ for(j=0;j<8;j+=4){ >+ for(i=0;i<2;i++){ >+ for(k=0;k<INTS_PER_ROW;k++){ >+ unsigned int t,b; >+ t=ri[INTS_PER_ROW*(j+i)+k]; >+ b=ri[INTS_PER_ROW*(j+i+2)+k]; >+ ri[INTS_PER_ROW*(j+i)+k]= (t&0x0000ffff) | ((b )<<16); >+ ri[INTS_PER_ROW*(j+i+2)+k]= ((t )>>16) | (b&0xffff0000) ; >+ } >+ } >+ } >+//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); >+// now 01230123 >+ for(g=0;g<count;g++){ >+ bdi[2*g]=ri[g]; >+ bdi[2*g+1]=ri[GROUP_PARALLELISM+g]; >+ } >+} >+ >+//-----block main function >+ >+// block group >+static void block_decypher_group( >+ batch *kkmulti, // [In] kkmulti[0]-kkmulti[55] 56 batches | Key schedule (each batch has repeated equal bytes). >+ unsigned char *ib, // [In] (ib0,ib1,...ib7)...x32 32*8 bytes | Initialization vector. >+ unsigned char *bd, // [Out] (bd0,bd1,...bd7)...x32 32*8 bytes | Block decipher. >+ int count) >+{ >+ // int is faster than unsigned char. apparently not >+ static const unsigned char block_sbox[0x100] = { >+ 0x3A,0xEA,0x68,0xFE,0x33,0xE9,0x88,0x1A, 0x83,0xCF,0xE1,0x7F,0xBA,0xE2,0x38,0x12, >+ 0xE8,0x27,0x61,0x95,0x0C,0x36,0xE5,0x70, 0xA2,0x06,0x82,0x7C,0x17,0xA3,0x26,0x49, >+ 0xBE,0x7A,0x6D,0x47,0xC1,0x51,0x8F,0xF3, 0xCC,0x5B,0x67,0xBD,0xCD,0x18,0x08,0xC9, >+ 0xFF,0x69,0xEF,0x03,0x4E,0x48,0x4A,0x84, 0x3F,0xB4,0x10,0x04,0xDC,0xF5,0x5C,0xC6, >+ 0x16,0xAB,0xAC,0x4C,0xF1,0x6A,0x2F,0x3C, 0x3B,0xD4,0xD5,0x94,0xD0,0xC4,0x63,0x62, >+ 0x71,0xA1,0xF9,0x4F,0x2E,0xAA,0xC5,0x56, 0xE3,0x39,0x93,0xCE,0x65,0x64,0xE4,0x58, >+ 0x6C,0x19,0x42,0x79,0xDD,0xEE,0x96,0xF6, 0x8A,0xEC,0x1E,0x85,0x53,0x45,0xDE,0xBB, >+ 0x7E,0x0A,0x9A,0x13,0x2A,0x9D,0xC2,0x5E, 0x5A,0x1F,0x32,0x35,0x9C,0xA8,0x73,0x30, >+ >+ 0x29,0x3D,0xE7,0x92,0x87,0x1B,0x2B,0x4B, 0xA5,0x57,0x97,0x40,0x15,0xE6,0xBC,0x0E, >+ 0xEB,0xC3,0x34,0x2D,0xB8,0x44,0x25,0xA4, 0x1C,0xC7,0x23,0xED,0x90,0x6E,0x50,0x00, >+ 0x99,0x9E,0x4D,0xD9,0xDA,0x8D,0x6F,0x5F, 0x3E,0xD7,0x21,0x74,0x86,0xDF,0x6B,0x05, >+ 0x8E,0x5D,0x37,0x11,0xD2,0x28,0x75,0xD6, 0xA7,0x77,0x24,0xBF,0xF0,0xB0,0x02,0xB7, >+ 0xF8,0xFC,0x81,0x09,0xB1,0x01,0x76,0x91, 0x7D,0x0F,0xC8,0xA0,0xF2,0xCB,0x78,0x60, >+ 0xD1,0xF7,0xE0,0xB5,0x98,0x22,0xB3,0x20, 0x1D,0xA6,0xDB,0x7B,0x59,0x9F,0xAE,0x31, >+ 0xFB,0xD3,0xB6,0xCA,0x43,0x72,0x07,0xF4, 0xD8,0x41,0x14,0x55,0x0D,0x54,0x8B,0xB9, >+ 0xAD,0x46,0x0B,0xAF,0x80,0x52,0x2C,0xFA, 0x8C,0x89,0x66,0xFD,0xB2,0xA9,0x9B,0xC0, >+ }; >+ MEMALIGN unsigned char r[GROUP_PARALLELISM*(8+56)]; /* 56 because we will move back in memory while looping */ >+ MEMALIGN unsigned char sbox_in[GROUP_PARALLELISM],sbox_out[GROUP_PARALLELISM],perm_out[GROUP_PARALLELISM]; >+ int roff; >+ int i,g,count_all=GROUP_PARALLELISM; >+ >+ roff=GROUP_PARALLELISM*56; >+ >+#define FASTTRASP1 >+#ifndef FASTTRASP1 >+ for(g=0;g<count;g++){ >+ // Init registers >+ int j; >+ for(j=0;j<8;j++){ >+ r[roff+GROUP_PARALLELISM*j+g]=ib[8*g+j]; >+ } >+ } >+#else >+ trasp_N_8((unsigned char *)&r[roff],(unsigned char *)ib,count); >+#endif >+//dump_mem("OLD r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); >+ >+ // loop over kk[55]..kk[0] >+ for(i=55;i>=0;i--){ >+ { >+ MEMALIGN batch tkkmulti=kkmulti[i]; >+ batch *si=(batch *)sbox_in; >+ batch *r6_N=(batch *)(r+roff+GROUP_PARALLELISM*6); >+ for(g=0;g<count_all/BYTES_PER_BATCH;g++){ >+ si[g]=B_FFXOR(tkkmulti,r6_N[g]); //FIXME: introduce FASTBATCH? >+ } >+ } >+ >+ // table lookup, this works on only one byte at a time >+ // most difficult part of all >+ // - can't be parallelized >+ // - can't be synthetized through boolean terms (8 input bits are too many) >+ for(g=0;g<count_all;g++){ >+ sbox_out[g]=block_sbox[sbox_in[g]]; >+ } >+ >+ // bit permutation >+ { >+ unsigned char *po=(unsigned char *)perm_out; >+ unsigned char *so=(unsigned char *)sbox_out; >+//dump_mem("pre perm ",(unsigned char *)so,GROUP_PARALLELISM,GROUP_PARALLELISM); >+ for(g=0;g<count_all;g+=BYTES_PER_BATCH){ >+ MEMALIGN batch in,out; >+ in=*(batch *)&so[g]; >+ >+ out=B_FFOR( >+ B_FFOR( >+ B_FFOR( >+ B_FFOR( >+ B_FFOR( >+ B_FFSH8L(B_FFAND(in,B_FFN_ALL_29()),1), >+ B_FFSH8L(B_FFAND(in,B_FFN_ALL_02()),6)), >+ B_FFSH8L(B_FFAND(in,B_FFN_ALL_04()),3)), >+ B_FFSH8R(B_FFAND(in,B_FFN_ALL_10()),2)), >+ B_FFSH8R(B_FFAND(in,B_FFN_ALL_40()),6)), >+ B_FFSH8R(B_FFAND(in,B_FFN_ALL_80()),4)); >+ >+ *(batch *)&po[g]=out; >+ } >+//dump_mem("post perm",(unsigned char *)po,GROUP_PARALLELISM,GROUP_PARALLELISM); >+ } >+ >+ roff-=GROUP_PARALLELISM; /* virtual shift of registers */ >+ >+#if 0 >+/* one by one */ >+ for(g=0;g<count_all;g++){ >+ r[roff+GROUP_PARALLELISM*0+g]=r[roff+GROUP_PARALLELISM*8+g]^sbox_out[g]; >+ r[roff+GROUP_PARALLELISM*6+g]^=perm_out[g]; >+ r[roff+GROUP_PARALLELISM*4+g]^=r[roff+GROUP_PARALLELISM*0+g]; >+ r[roff+GROUP_PARALLELISM*3+g]^=r[roff+GROUP_PARALLELISM*0+g]; >+ r[roff+GROUP_PARALLELISM*2+g]^=r[roff+GROUP_PARALLELISM*0+g]; >+ } >+#else >+ for(g=0;g<count_all;g+=BEST_SPAN){ >+ XOR_BEST_BY(&r[roff+GROUP_PARALLELISM*0+g],&r[roff+GROUP_PARALLELISM*8+g],&sbox_out[g]); >+ XOREQ_BEST_BY(&r[roff+GROUP_PARALLELISM*6+g],&perm_out[g]); >+ XOREQ_BEST_BY(&r[roff+GROUP_PARALLELISM*4+g],&r[roff+GROUP_PARALLELISM*0+g]); >+ XOREQ_BEST_BY(&r[roff+GROUP_PARALLELISM*3+g],&r[roff+GROUP_PARALLELISM*0+g]); >+ XOREQ_BEST_BY(&r[roff+GROUP_PARALLELISM*2+g],&r[roff+GROUP_PARALLELISM*0+g]); >+ } >+#endif >+ } >+ >+#define FASTTRASP2 >+#ifndef FASTTRASP2 >+ for(g=0;g<count;g++){ >+ // Copy results >+ int j; >+ for(j=0;j<8;j++){ >+ bd[8*g+j]=r[roff+GROUP_PARALLELISM*j+g]; >+ } >+ } >+#else >+ trasp_8_N((unsigned char *)&r[roff],(unsigned char *)bd,count); >+#endif >+} >+ >+//-----------------------------------EXTERNAL INTERFACE >+ >+//-----get internal parallelism >+ >+int get_internal_parallelism(void){ >+ return GROUP_PARALLELISM; >+} >+ >+//-----get suggested cluster size >+ >+int get_suggested_cluster_size(void){ >+ int r; >+ r=GROUP_PARALLELISM+GROUP_PARALLELISM/10; >+ if(r<GROUP_PARALLELISM+5) r=GROUP_PARALLELISM+5; >+ return r; >+} >+ >+//-----key structure >+ >+void *get_key_struct(void){ >+ struct csa_keys_t *keys=(struct csa_keys_t *)MALLOC(sizeof(struct csa_keys_t)); >+ if(keys) { >+ static const unsigned char pk[8] = { 0,0,0,0,0,0,0,0 }; >+ set_control_words(keys,pk,pk); >+ } >+ return keys; >+} >+ >+void free_key_struct(void *keys){ >+ return FREE(keys); >+} >+ >+//-----set control words >+ >+static void schedule_key(struct csa_key_t *key, const unsigned char *pk){ >+ // could be made faster, but is not run often >+ int bi,by; >+ int i,j; >+// key >+ memcpy(key->ck,pk,8); >+// precalculations for stream >+ key_schedule_stream(key->ck,key->iA,key->iB); >+ for(by=0;by<8;by++){ >+ for(bi=0;bi<8;bi++){ >+ key->ck_g[by][bi]=(key->ck[by]&(1<<bi))?FF1():FF0(); >+ } >+ } >+ for(by=0;by<8;by++){ >+ for(bi=0;bi<4;bi++){ >+ key->iA_g[by][bi]=(key->iA[by]&(1<<bi))?FF1():FF0(); >+ key->iB_g[by][bi]=(key->iB[by]&(1<<bi))?FF1():FF0(); >+ } >+ } >+// precalculations for block >+ key_schedule_block(key->ck,key->kk); >+ for(i=0;i<56;i++){ >+ for(j=0;j<BYTES_PER_BATCH;j++){ >+ *(((unsigned char *)&key->kkmulti[i])+j)=key->kk[i]; >+ } >+ } >+} >+ >+void set_control_words(void *keys, const unsigned char *ev, const unsigned char *od){ >+ schedule_key(&((struct csa_keys_t *)keys)->even,ev); >+ schedule_key(&((struct csa_keys_t *)keys)->odd,od); >+} >+ >+void set_even_control_word(void *keys, const unsigned char *pk){ >+ schedule_key(&((struct csa_keys_t *)keys)->even,pk); >+} >+ >+void set_odd_control_word(void *keys, const unsigned char *pk){ >+ schedule_key(&((struct csa_keys_t *)keys)->odd,pk); >+} >+ >+//-----get control words >+ >+void get_control_words(void *keys, unsigned char *even, unsigned char *odd){ >+ memcpy(even,&((struct csa_keys_t *)keys)->even.ck,8); >+ memcpy(odd,&((struct csa_keys_t *)keys)->odd.ck,8); >+} >+ >+//----- decrypt >+ >+int decrypt_packets(void *keys, unsigned char **cluster){ >+ // statistics, currently unused >+ int stat_no_scramble=0; >+ int stat_reserved=0; >+ int stat_decrypted[2]={0,0}; >+ int stat_decrypted_mini=0; >+ unsigned char **clst; >+ unsigned char **clst2; >+ int grouped; >+ int group_ev_od; >+ int advanced; >+ int can_advance; >+ unsigned char *g_pkt[GROUP_PARALLELISM]; >+ int g_len[GROUP_PARALLELISM]; >+ int g_offset[GROUP_PARALLELISM]; >+ int g_n[GROUP_PARALLELISM]; >+ int g_residue[GROUP_PARALLELISM]; >+ unsigned char *pkt; >+ int xc0,ev_od,len,offset,n,residue; >+ struct csa_key_t* k; >+ int i,j,iter,g; >+ int t23,tsmall; >+ int alive[24]; >+//icc craziness int pad1=0; //////////align! FIXME >+ unsigned char *encp[GROUP_PARALLELISM]; >+ MEMALIGN unsigned char stream_in[GROUP_PARALLELISM*8]; >+ MEMALIGN unsigned char stream_out[GROUP_PARALLELISM*8]; >+ MEMALIGN unsigned char ib[GROUP_PARALLELISM*8]; >+ MEMALIGN unsigned char block_out[GROUP_PARALLELISM*8]; >+#ifdef COPY_UNALIGNED_PKT >+ unsigned char *unaligned[GROUP_PARALLELISM]; >+ MEMALIGN unsigned char alignedBuff[GROUP_PARALLELISM][188]; >+#endif >+ struct stream_regs regs; >+ >+//icc craziness i=(int)&pad1;//////////align!!! FIXME >+ >+ // build a list of packets to be processed >+ clst=cluster; >+ grouped=0; >+ advanced=0; >+ can_advance=1; >+ group_ev_od=-1; // silence incorrect compiler warning >+ pkt=*clst; >+ do{ // find a new packet >+ if(grouped==GROUP_PARALLELISM){ >+ // full >+ break; >+ } >+ if(pkt==NULL){ >+ // no more ranges >+ break; >+ } >+ if(pkt>=*(clst+1)){ >+ // out of this range, try next >+ clst++;clst++; >+ pkt=*clst; >+ continue; >+ } >+ >+ do{ // handle this packet >+ xc0=pkt[3]&0xc0; >+ DBG(fprintf(stderr," exam pkt=%p, xc0=%02x, can_adv=%i\n",pkt,xc0,can_advance)); >+ if(xc0==0x00){ >+ DBG(fprintf(stderr,"skip clear pkt %p (can_advance is %i)\n",pkt,can_advance)); >+ advanced+=can_advance; >+ stat_no_scramble++; >+ break; >+ } >+ if(xc0==0x40){ >+ DBG(fprintf(stderr,"skip reserved pkt %p (can_advance is %i)\n",pkt,can_advance)); >+ advanced+=can_advance; >+ stat_reserved++; >+ break; >+ } >+ if(xc0==0x80||xc0==0xc0){ // encrypted >+ ev_od=(xc0&0x40)>>6; // 0 even, 1 odd >+ if(grouped==0) group_ev_od=ev_od; // this group will be all even (or odd) >+ if(group_ev_od==ev_od){ // could be added to group >+ pkt[3]&=0x3f; // consider it decrypted now >+ if(pkt[3]&0x20){ // incomplete packet >+ offset=4+pkt[4]+1; >+ len=188-offset; >+ n=len>>3; >+ residue=len-(n<<3); >+ if(n==0){ // decrypted==encrypted! >+ DBG(fprintf(stderr,"DECRYPTED MINI! (can_advance is %i)\n",can_advance)); >+ advanced+=can_advance; >+ stat_decrypted_mini++; >+ break; // this doesn't need more processing >+ } >+ }else{ >+ len=184; >+ offset=4; >+ n=23; >+ residue=0; >+ } >+ g_pkt[grouped]=pkt; >+ g_len[grouped]=len; >+ g_offset[grouped]=offset; >+ g_n[grouped]=n; >+ g_residue[grouped]=residue; >+ DBG(fprintf(stderr,"%2i: eo=%i pkt=%p len=%03i n=%2i residue=%i\n",grouped,ev_od,pkt,len,n,residue)); >+ grouped++; >+ advanced+=can_advance; >+ stat_decrypted[ev_od]++; >+ } >+ else{ >+ can_advance=0; >+ DBG(fprintf(stderr,"skip pkt %p and can_advance set to 0\n",pkt)); >+ break; // skip and go on >+ } >+ } >+ } while(0); >+ >+ if(can_advance){ >+ // move range start forward >+ *clst+=188; >+ } >+ // next packet, if there is one >+ pkt+=188; >+ } while(1); >+ DBG(fprintf(stderr,"-- result: grouped %i pkts, advanced %i pkts\n",grouped,advanced)); >+ >+ // delete empty ranges and compact list >+ clst2=cluster; >+ for(clst=cluster;*clst!=NULL;clst+=2){ >+ // if not empty >+ if(*clst<*(clst+1)){ >+ // it will remain >+ *clst2=*clst; >+ *(clst2+1)=*(clst+1); >+ clst2+=2; >+ } >+ } >+ *clst2=NULL; >+ >+ if(grouped==0){ >+ // no processing needed >+ return advanced; >+ } >+ >+ // sort them, longest payload first >+ // we expect many n=23 packets and a few n<23 >+ DBG(fprintf(stderr,"PRESORTING\n")); >+ for(i=0;i<grouped;i++){ >+ DBG(fprintf(stderr,"%2i of %2i: pkt=%p len=%03i n=%2i residue=%i\n",i,grouped,g_pkt[i],g_len[i],g_n[i],g_residue[i])); >+ } >+ // grouped is always <= GROUP_PARALLELISM >+ >+#define g_swap(a,b) \ >+ pkt=g_pkt[a]; \ >+ g_pkt[a]=g_pkt[b]; \ >+ g_pkt[b]=pkt; \ >+\ >+ len=g_len[a]; \ >+ g_len[a]=g_len[b]; \ >+ g_len[b]=len; \ >+\ >+ offset=g_offset[a]; \ >+ g_offset[a]=g_offset[b]; \ >+ g_offset[b]=offset; \ >+\ >+ n=g_n[a]; \ >+ g_n[a]=g_n[b]; \ >+ g_n[b]=n; \ >+\ >+ residue=g_residue[a]; \ >+ g_residue[a]=g_residue[b]; \ >+ g_residue[b]=residue; >+ >+ // step 1: move n=23 packets before small packets >+ t23=0; >+ tsmall=grouped-1; >+ for(;;){ >+ for(;t23<grouped;t23++){ >+ if(g_n[t23]!=23) break; >+ } >+DBG(fprintf(stderr,"t23 after for =%i\n",t23)); >+ >+ for(;tsmall>=0;tsmall--){ >+ if(g_n[tsmall]==23) break; >+ } >+DBG(fprintf(stderr,"tsmall after for =%i\n",tsmall)); >+ >+ if(tsmall-t23<1) break; >+ >+DBG(fprintf(stderr,"swap t23=%i,tsmall=%i\n",t23,tsmall)); >+ >+ g_swap(t23,tsmall); >+ >+ t23++; >+ tsmall--; >+DBG(fprintf(stderr,"new t23=%i,tsmall=%i\n\n",t23,tsmall)); >+ } >+ DBG(fprintf(stderr,"packets with n=23, t23=%i grouped=%i\n",t23,grouped)); >+ DBG(fprintf(stderr,"MIDSORTING\n")); >+ for(i=0;i<grouped;i++){ >+ DBG(fprintf(stderr,"%2i of %2i: pkt=%p len=%03i n=%2i residue=%i\n",i,grouped,g_pkt[i],g_len[i],g_n[i],g_residue[i])); >+ } >+ >+ // step 2: sort small packets in decreasing order of n (bubble sort is enough) >+ for(i=t23;i<grouped;i++){ >+ for(j=i+1;j<grouped;j++){ >+ if(g_n[j]>g_n[i]){ >+ g_swap(i,j); >+ } >+ } >+ } >+ DBG(fprintf(stderr,"POSTSORTING\n")); >+ for(i=0;i<grouped;i++){ >+ DBG(fprintf(stderr,"%2i of %2i: pkt=%p len=%03i n=%2i residue=%i\n",i,grouped,g_pkt[i],g_len[i],g_n[i],g_residue[i])); >+ } >+ >+ // we need to know how many packets need 23 iterations, how many 22... >+ for(i=0;i<=23;i++){ >+ alive[i]=0; >+ } >+ // count >+ alive[23-1]=t23; >+ for(i=t23;i<grouped;i++){ >+ alive[g_n[i]-1]++; >+ } >+ // integrate >+ for(i=22;i>=0;i--){ >+ alive[i]+=alive[i+1]; >+ } >+ DBG(fprintf(stderr,"ALIVE\n")); >+ for(i=0;i<=23;i++){ >+ DBG(fprintf(stderr,"alive%2i=%i\n",i,alive[i])); >+ } >+ >+ // choose key >+ if(group_ev_od==0){ >+ k=&((struct csa_keys_t *)keys)->even; >+ } >+ else{ >+ k=&((struct csa_keys_t *)keys)->odd; >+ } >+ >+ //INIT >+//#define INITIALIZE_UNUSED_INPUT >+#ifdef INITIALIZE_UNUSED_INPUT >+// unnecessary zeroing. >+// without this, we operate on uninitialized memory >+// when grouped<GROUP_PARALLELISM, but it's not a problem, >+// as final results will be discarded. >+// random data makes debugging sessions difficult. >+ for(j=0;j<GROUP_PARALLELISM*8;j++) stream_in[j]=0; >+DBG(fprintf(stderr,"--- WARNING: you could gain speed by not initializing unused memory ---\n")); >+#else >+DBG(fprintf(stderr,"--- WARNING: DEBUGGING IS MORE DIFFICULT WHEN PROCESSING RANDOM DATA CHANGING AT EVERY RUN! ---\n")); >+#endif >+ >+ for(g=0;g<grouped;g++){ >+ encp[g]=g_pkt[g]; >+ DBG(fprintf(stderr,"header[%i]=%p (%02x)\n",g,encp[g],*(encp[g]))); >+ encp[g]+=g_offset[g]; // skip header >+#ifdef COPY_UNALIGNED_PKT >+ if(((int)encp[g])&0x03) { >+ memcpy(alignedBuff[g],encp[g],g_len[g]); >+ unaligned[g]=encp[g]; >+ encp[g]=alignedBuff[g]; >+ } >+ else unaligned[g]=0; >+#endif >+ FFTABLEIN(stream_in,g,encp[g]); >+ } >+//dump_mem("stream_in",stream_in,GROUP_PARALLELISM*8,BYPG); >+ >+ >+ // ITER 0 >+DBG(fprintf(stderr,">>>>>ITER 0\n")); >+ iter=0; >+ stream_cypher_group_init(®s,k->iA_g,k->iB_g,stream_in); >+ // fill first ib >+ for(g=0;g<alive[iter];g++){ >+ COPY_8_BY(ib+8*g,encp[g]); >+ } >+DBG(dump_mem("IB ",ib,8*alive[iter],8)); >+ // ITER 1..N-1 >+ for (iter=1;iter<23&&alive[iter-1]>0;iter++){ >+DBG(fprintf(stderr,">>>>>ITER %i\n",iter)); >+ // alive and just dead packets: calc block >+ block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]); >+DBG(dump_mem("BLO_ib ",block_out,8*alive[iter-1],8)); >+ // all packets (dead too): calc stream >+ stream_cypher_group_normal(®s,stream_out); >+//dump_mem("stream_out",stream_out,GROUP_PARALLELISM*8,BYPG); >+ >+ // alive packets: calc ib >+ for(g=0;g<alive[iter];g++){ >+ FFTABLEOUT(ib+8*g,stream_out,g); >+DBG(dump_mem("stream_out_ib ",ib+8*g,8,8)); >+// XOREQ8BY gcc bug? 2x4 ok, 8 ko UPDATE: result ok but speed 1-2% slower (!!!???) >+#if 1 >+ XOREQ_4_BY(ib+8*g,encp[g]+8); >+ XOREQ_4_BY(ib+8*g+4,encp[g]+8+4); >+#else >+ XOREQ_8_BY(ib+8*g,encp[g]+8); >+#endif >+DBG(dump_mem("after_stream_xor_ib ",ib+8*g,8,8)); >+ } >+ // alive packets: decrypt data >+ for(g=0;g<alive[iter];g++){ >+DBG(dump_mem("before_ib_decrypt_data ",encp[g],8,8)); >+ XOR_8_BY(encp[g],ib+8*g,block_out+8*g); >+DBG(dump_mem("after_ib_decrypt_data ",encp[g],8,8)); >+ } >+ // just dead packets: write decrypted data >+ for(g=alive[iter];g<alive[iter-1];g++){ >+DBG(dump_mem("jd_before_ib_decrypt_data ",encp[g],8,8)); >+ COPY_8_BY(encp[g],block_out+8*g); >+DBG(dump_mem("jd_after_ib_decrypt_data ",encp[g],8,8)); >+ } >+ // just dead packets: decrypt residue >+ for(g=alive[iter];g<alive[iter-1];g++){ >+DBG(dump_mem("jd_before_decrypt_residue ",encp[g]+8,g_residue[g],g_residue[g])); >+ FFTABLEOUTXORNBY(g_residue[g],encp[g]+8,stream_out,g); >+DBG(dump_mem("jd_after_decrypt_residue ",encp[g]+8,g_residue[g],g_residue[g])); >+ } >+ // alive packets: pointers++ >+ for(g=0;g<alive[iter];g++) encp[g]+=8; >+ }; >+ // ITER N >+DBG(fprintf(stderr,">>>>>ITER 23\n")); >+ iter=23; >+ // calc block >+ block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]); >+DBG(dump_mem("23BLO_ib ",block_out,8*alive[iter-1],8)); >+ // just dead packets: write decrypted data >+ for(g=alive[iter];g<alive[iter-1];g++){ >+DBG(dump_mem("23jd_before_ib_decrypt_data ",encp[g],8,8)); >+ COPY_8_BY(encp[g],block_out+8*g); >+DBG(dump_mem("23jd_after_ib_decrypt_data ",encp[g],8,8)); >+ } >+ // no residue possible >+ // so do nothing >+ >+ DBG(fprintf(stderr,"returning advanced=%i\n",advanced)); >+ >+#ifdef COPY_UNALIGNED_PKT >+ for(g=0;g<grouped;g++) >+ if(unaligned[g]) memcpy(unaligned[g],alignedBuff[g],g_len[g]); >+#endif >+ >+ M_EMPTY(); // restore CPU multimedia state >+ >+ return advanced; >+} >Index: ffdecsa/ffdecsa.h >=================================================================== >--- ffdecsa/ffdecsa.h (revision 0) >+++ ffdecsa/ffdecsa.h (working copy) >@@ -0,0 +1,62 @@ >+/* FFdecsa -- fast decsa algorithm >+ * >+ * Copyright (C) 2003-2004 fatih89r >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License as published by >+ * the Free Software Foundation; either version 2 of the License, or >+ * (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program; if not, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+ >+#ifndef FFDECSA_H >+#define FFDECSA_H >+ >+//----- public interface >+ >+// -- how many packets can be decrypted at the same time >+// This is an info about internal decryption parallelism. >+// You should try to call decrypt_packets with more packets than the number >+// returned here for performance reasons (use get_suggested_cluster_size to know >+// how many). >+int get_internal_parallelism(void); >+ >+// -- how many packets you should have in a cluster when calling decrypt_packets >+// This is a suggestion to achieve optimal performance; typically a little >+// higher than what get_internal_parallelism returns. >+// Passing less packets could slow down the decryption. >+// Passing more packets is never bad (if you don't spend a lot of time building >+// the list). >+int get_suggested_cluster_size(void); >+ >+// -- alloc & free the key structure >+void *get_key_struct(void); >+void free_key_struct(void *keys); >+ >+// -- set control words, 8 bytes each >+void set_control_words(void *keys, const unsigned char *even, const unsigned char *odd); >+ >+// -- set even control word, 8 bytes >+void set_even_control_word(void *keys, const unsigned char *even); >+ >+// -- set odd control word, 8 bytes >+void set_odd_control_word(void *keys, const unsigned char *odd); >+ >+// -- get control words, 8 bytes each >+//void get_control_words(void *keys, unsigned char *even, unsigned char *odd); >+ >+// -- decrypt many TS packets >+// This interface is a bit complicated because it is designed for maximum speed. >+// Please read doc/how_to_use.txt. >+int decrypt_packets(void *keys, unsigned char **cluster); >+ >+#endif >Index: ffdecsa/fftable.h >=================================================================== >--- ffdecsa/fftable.h (revision 0) >+++ ffdecsa/fftable.h (working copy) >@@ -0,0 +1,56 @@ >+/* FFdecsa -- fast decsa algorithm >+ * >+ * Copyright (C) 2007 Dark Avenger >+ * 2003-2004 fatih89r >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License as published by >+ * the Free Software Foundation; either version 2 of the License, or >+ * (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program; if not, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#ifndef FFTABLE_H >+#define FFTABLE_H >+ >+inline static void FFTABLEIN(unsigned char *tab, int g, unsigned char *data) >+{ >+#if 0 >+ *(((int *)tab)+2*g)=*((int *)data); >+ *(((int *)tab)+2*g+1)=*(((int *)data)+1); >+#else >+ *(((long long *)tab)+g)=*((long long *)data); >+#endif >+} >+ >+inline static void FFTABLEOUT(unsigned char *data, unsigned char *tab, int g) >+{ >+#if 1 >+ *((int *)data)=*(((int *)tab)+2*g); >+ *(((int *)data)+1)=*(((int *)tab)+2*g+1); >+#else >+ *((long long *)data)=*(((long long *)tab)+g); >+#endif >+} >+ >+inline static void FFTABLEOUTXORNBY(int n, unsigned char *data, unsigned char *tab, int g) >+{ >+ int j; >+ for(j=0;j<n;j++) *(data+j)^=*(tab+8*g+j); >+} >+ >+#undef XOREQ_BEST_BY >+inline static void XOREQ_BEST_BY(unsigned char *d, unsigned char *s) >+{ >+ XOR_BEST_BY(d, d, s); >+} >+ >+#endif //FFTABLE_H >Index: ffdecsa/parallel_032_int.h >=================================================================== >--- ffdecsa/parallel_032_int.h (revision 0) >+++ ffdecsa/parallel_032_int.h (working copy) >@@ -0,0 +1,55 @@ >+/* FFdecsa -- fast decsa algorithm >+ * >+ * Copyright (C) 2003-2004 fatih89r >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License as published by >+ * the Free Software Foundation; either version 2 of the License, or >+ * (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program; if not, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#include "parallel_std_def.h" >+ >+typedef unsigned int group; >+#define GROUP_PARALLELISM 32 >+#define FF0() 0x0 >+#define FF1() 0xffffffff >+ >+/* 64 rows of 32 bits */ >+ >+inline static void FFTABLEIN(unsigned char *tab, int g, unsigned char *data){ >+ *(((int *)tab)+g)=*((int *)data); >+ *(((int *)tab)+32+g)=*(((int *)data)+1); >+} >+ >+inline static void FFTABLEOUT(unsigned char *data, unsigned char *tab, int g){ >+ *((int *)data)=*(((int *)tab)+g); >+ *(((int *)data)+1)=*(((int *)tab)+32+g); >+} >+ >+inline static void FFTABLEOUTXORNBY(int n, unsigned char *data, unsigned char *tab, int g){ >+ int j; >+ for(j=0;j<n;j++){ >+ *(data+j)^=*(tab+4*(g+(j>=4?32-1:0))+j); >+ } >+} >+ >+typedef unsigned int batch; >+#define BYTES_PER_BATCH 4 >+#define B_FFN_ALL_29() 0x29292929 >+#define B_FFN_ALL_02() 0x02020202 >+#define B_FFN_ALL_04() 0x04040404 >+#define B_FFN_ALL_10() 0x10101010 >+#define B_FFN_ALL_40() 0x40404040 >+#define B_FFN_ALL_80() 0x80808080 >+ >+#define M_EMPTY() >Index: ffdecsa/parallel_064_long.h >=================================================================== >--- ffdecsa/parallel_064_long.h (revision 0) >+++ ffdecsa/parallel_064_long.h (working copy) >@@ -0,0 +1,39 @@ >+/* FFdecsa -- fast decsa algorithm >+ * >+ * Copyright (C) 2007 Dark Avenger >+ * 2003-2004 fatih89r >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License as published by >+ * the Free Software Foundation; either version 2 of the License, or >+ * (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program; if not, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#include "parallel_std_def.h" >+ >+typedef unsigned long long group; >+#define GROUP_PARALLELISM 64 >+#define FF0() 0x0ULL >+#define FF1() 0xffffffffffffffffULL >+ >+typedef unsigned long long batch; >+#define BYTES_PER_BATCH 8 >+#define B_FFN_ALL_29() 0x2929292929292929ULL >+#define B_FFN_ALL_02() 0x0202020202020202ULL >+#define B_FFN_ALL_04() 0x0404040404040404ULL >+#define B_FFN_ALL_10() 0x1010101010101010ULL >+#define B_FFN_ALL_40() 0x4040404040404040ULL >+#define B_FFN_ALL_80() 0x8080808080808080ULL >+ >+#define M_EMPTY() >+ >+#include "fftable.h" >Index: ffdecsa/parallel_128_sse2.h >=================================================================== >--- ffdecsa/parallel_128_sse2.h (revision 0) >+++ ffdecsa/parallel_128_sse2.h (working copy) >@@ -0,0 +1,82 @@ >+/* FFdecsa -- fast decsa algorithm >+ * >+ * Copyright (C) 2007 Dark Avenger >+ * 2003-2004 fatih89r >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License as published by >+ * the Free Software Foundation; either version 2 of the License, or >+ * (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program; if not, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#include <emmintrin.h> >+ >+#define MEMALIGN_VAL 16 >+ >+union __u128i { >+ unsigned int u[4]; >+ __m128i v; >+}; >+ >+static const union __u128i ff0 = {{0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}}; >+static const union __u128i ff1 = {{0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU}}; >+ >+typedef __m128i group; >+#define GROUP_PARALLELISM 128 >+#define FF0() ff0.v >+#define FF1() ff1.v >+#define FFAND(a,b) _mm_and_si128((a),(b)) >+#define FFOR(a,b) _mm_or_si128((a),(b)) >+#define FFXOR(a,b) _mm_xor_si128((a),(b)) >+#define FFNOT(a) _mm_xor_si128((a),FF1()) >+#define MALLOC(X) _mm_malloc(X,16) >+#define FREE(X) _mm_free(X) >+ >+/* BATCH */ >+ >+static const union __u128i ff29 = {{0x29292929U, 0x29292929U, 0x29292929U, 0x29292929U}}; >+static const union __u128i ff02 = {{0x02020202U, 0x02020202U, 0x02020202U, 0x02020202U}}; >+static const union __u128i ff04 = {{0x04040404U, 0x04040404U, 0x04040404U, 0x04040404U}}; >+static const union __u128i ff10 = {{0x10101010U, 0x10101010U, 0x10101010U, 0x10101010U}}; >+static const union __u128i ff40 = {{0x40404040U, 0x40404040U, 0x40404040U, 0x40404040U}}; >+static const union __u128i ff80 = {{0x80808080U, 0x80808080U, 0x80808080U, 0x80808080U}}; >+ >+typedef __m128i batch; >+#define BYTES_PER_BATCH 16 >+#define B_FFN_ALL_29() ff29.v >+#define B_FFN_ALL_02() ff02.v >+#define B_FFN_ALL_04() ff04.v >+#define B_FFN_ALL_10() ff10.v >+#define B_FFN_ALL_40() ff40.v >+#define B_FFN_ALL_80() ff80.v >+ >+#define B_FFAND(a,b) FFAND(a,b) >+#define B_FFOR(a,b) FFOR(a,b) >+#define B_FFXOR(a,b) FFXOR(a,b) >+#define B_FFSH8L(a,n) _mm_slli_epi64((a),(n)) >+#define B_FFSH8R(a,n) _mm_srli_epi64((a),(n)) >+ >+#define M_EMPTY() >+ >+#undef BEST_SPAN >+#define BEST_SPAN 16 >+ >+#undef XOR_BEST_BY >+inline static void XOR_BEST_BY(unsigned char *d, unsigned char *s1, unsigned char *s2) >+{ >+ __m128i vs1 = _mm_load_si128((__m128i*)s1); >+ __m128i vs2 = _mm_load_si128((__m128i*)s2); >+ vs1 = _mm_xor_si128(vs1, vs2); >+ _mm_store_si128((__m128i*)d, vs1); >+} >+ >+#include "fftable.h" >Index: ffdecsa/parallel_generic.h >=================================================================== >--- ffdecsa/parallel_generic.h (revision 0) >+++ ffdecsa/parallel_generic.h (working copy) >@@ -0,0 +1,102 @@ >+/* FFdecsa -- fast decsa algorithm >+ * >+ * Copyright (C) 2003-2004 fatih89r >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License as published by >+ * the Free Software Foundation; either version 2 of the License, or >+ * (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program; if not, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+ >+ >+#if 0 >+//// generics >+#define COPY4BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ >+ *pd = *ps; }while(0) >+#define COPY8BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ >+ *pd = *ps; }while(0) >+#define COPY16BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ >+ *pd = *ps; \ >+ *(pd+1) = *(ps+1); }while(0) >+#define COPY32BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ >+ *pd = *ps; \ >+ *(pd+1) = *(ps+1) \ >+ *(pd+2) = *(ps+2) \ >+ *(pd+3) = *(ps+3); }while(0) >+#define XOR4BY(d,s1,s2) do{ int *pd=(int *)(d), *ps1=(int *)(s1), *ps2=(int *)(s2); \ >+ *pd = *ps1 ^ *ps2; }while(0) >+#define XOR8BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ >+ *pd = *ps1 ^ *ps2; }while(0) >+#define XOR16BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ >+ *pd = *ps1 ^ *ps2; \ >+ *(pd+8) = *(ps1+8) ^ *(ps2+8); }while(0) >+#define XOR32BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ >+ *pd = *ps1 ^ *ps2; \ >+ *(pd+1) = *(ps1+1) ^ *(ps2+1); \ >+ *(pd+2) = *(ps1+2) ^ *(ps2+2); \ >+ *(pd+3) = *(ps1+3) ^ *(ps2+3); }while(0) >+#define XOR32BV(d,s1,s2) do{ int *const pd=(int *const)(d), *ps1=(const int *const)(s1), *ps2=(const int *const)(s2); \ >+ int z; \ >+ for(z=0;z<8;z++){ \ >+ pd[z]=ps1[z]^ps2[z]; \ >+ } \ >+ }while(0) >+#define XOREQ4BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ >+ *pd ^= *ps; }while(0) >+#define XOREQ8BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ >+ *pd ^= *ps; }while(0) >+#define XOREQ16BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ >+ *pd ^= *ps; \ >+ *(pd+1) ^=*(ps+1); }while(0) >+#define XOREQ32BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ >+ *pd ^= *ps; \ >+ *(pd+1) ^=*(ps+1); \ >+ *(pd+2) ^=*(ps+2); \ >+ *(pd+3) ^=*(ps+3); }while(0) >+#define XOREQ32BY4(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ >+ *pd ^= *ps; \ >+ *(pd+1) ^=*(ps+1); \ >+ *(pd+2) ^=*(ps+2); \ >+ *(pd+3) ^=*(ps+3); \ >+ *(pd+4) ^=*(ps+4); \ >+ *(pd+5) ^=*(ps+5); \ >+ *(pd+6) ^=*(ps+6); \ >+ *(pd+7) ^=*(ps+7); }while(0) >+#define XOREQ32BV(d,s) do{ unsigned char *pd=(unsigned char *)(d), *ps=(unsigned char *)(s); \ >+ int z; \ >+ for(z=0;z<32;z++){ \ >+ pd[z]^=ps[z]; \ >+ } \ >+ }while(0) >+ >+#else >+#define XOR_4_BY(d,s1,s2) do{ int *pd=(int *)(d), *ps1=(int *)(s1), *ps2=(int *)(s2); \ >+ *pd = *ps1 ^ *ps2; }while(0) >+#define XOR_8_BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ >+ *pd = *ps1 ^ *ps2; }while(0) >+#define XOREQ_4_BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ >+ *pd ^= *ps; }while(0) >+#define XOREQ_8_BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ >+ *pd ^= *ps; }while(0) >+#define COPY_4_BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ >+ *pd = *ps; }while(0) >+#define COPY_8_BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ >+ *pd = *ps; }while(0) >+ >+#define BEST_SPAN 8 >+#define XOR_BEST_BY(d,s1,s2) do{ XOR_8_BY(d,s1,s2); }while(0); >+#define XOREQ_BEST_BY(d,s) do{ XOREQ_8_BY(d,s); }while(0); >+#define COPY_BEST_BY(d,s) do{ COPY_8_BY(d,s); }while(0); >+ >+#define END_MM do{ }while(0); >+#endif >Index: ffdecsa/parallel_std_def.h >=================================================================== >--- ffdecsa/parallel_std_def.h (revision 0) >+++ ffdecsa/parallel_std_def.h (working copy) >@@ -0,0 +1,29 @@ >+/* FFdecsa -- fast decsa algorithm >+ * >+ * Copyright (C) 2003-2004 fatih89r >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License as published by >+ * the Free Software Foundation; either version 2 of the License, or >+ * (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program; if not, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+#define FFXOR(a,b) ((a)^(b)) >+#define FFAND(a,b) ((a)&(b)) >+#define FFOR(a,b) ((a)|(b)) >+#define FFNOT(a) (~(a)) >+ >+#define B_FFAND(a,b) ((a)&(b)) >+#define B_FFOR(a,b) ((a)|(b)) >+#define B_FFXOR(a,b) ((a)^(b)) >+#define B_FFSH8L(a,n) ((a)<<(n)) >+#define B_FFSH8R(a,n) ((a)>>(n)) >Index: ffdecsa/stream.c >=================================================================== >--- ffdecsa/stream.c (revision 0) >+++ ffdecsa/stream.c (working copy) >@@ -0,0 +1,906 @@ >+/* FFdecsa -- fast decsa algorithm >+ * >+ * Copyright (C) 2003-2004 fatih89r >+ * >+ * This program is free software; you can redistribute it and/or modify >+ * it under the terms of the GNU General Public License as published by >+ * the Free Software Foundation; either version 2 of the License, or >+ * (at your option) any later version. >+ * >+ * This program is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+ * GNU General Public License for more details. >+ * >+ * You should have received a copy of the GNU General Public License >+ * along with this program; if not, write to the Free Software >+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. >+ */ >+ >+ >+ >+// define statics only once, when STREAM_INIT >+#ifdef STREAM_INIT >+struct stream_regs { >+ group A[32+10][4]; // 32 because we will move back (virtual shift register) >+ group B[32+10][4]; // 32 because we will move back (virtual shift register) >+ group X[4]; >+ group Y[4]; >+ group Z[4]; >+ group D[4]; >+ group E[4]; >+ group F[4]; >+ group p; >+ group q; >+ group r; >+ }; >+ >+static inline void trasp64_32_88ccw(unsigned char *data){ >+/* 64 rows of 32 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ >+#define row ((unsigned int *)data) >+ int i,j; >+ for(j=0;j<64;j+=32){ >+ unsigned int t,b; >+ for(i=0;i<16;i++){ >+ t=row[j+i]; >+ b=row[j+16+i]; >+ row[j+i] = (t&0x0000ffff) | ((b )<<16); >+ row[j+16+i]=((t )>>16) | (b&0xffff0000) ; >+ } >+ } >+ for(j=0;j<64;j+=16){ >+ unsigned int t,b; >+ for(i=0;i<8;i++){ >+ t=row[j+i]; >+ b=row[j+8+i]; >+ row[j+i] = (t&0x00ff00ff) | ((b&0x00ff00ff)<<8); >+ row[j+8+i] =((t&0xff00ff00)>>8) | (b&0xff00ff00); >+ } >+ } >+ for(j=0;j<64;j+=8){ >+ unsigned int t,b; >+ for(i=0;i<4;i++){ >+ t=row[j+i]; >+ b=row[j+4+i]; >+ row[j+i] =((t&0x0f0f0f0f)<<4) | (b&0x0f0f0f0f); >+ row[j+4+i] = (t&0xf0f0f0f0) | ((b&0xf0f0f0f0)>>4); >+ } >+ } >+ for(j=0;j<64;j+=4){ >+ unsigned int t,b; >+ for(i=0;i<2;i++){ >+ t=row[j+i]; >+ b=row[j+2+i]; >+ row[j+i] =((t&0x33333333)<<2) | (b&0x33333333); >+ row[j+2+i] = (t&0xcccccccc) | ((b&0xcccccccc)>>2); >+ } >+ } >+ for(j=0;j<64;j+=2){ >+ unsigned int t,b; >+ for(i=0;i<1;i++){ >+ t=row[j+i]; >+ b=row[j+1+i]; >+ row[j+i] =((t&0x55555555)<<1) | (b&0x55555555); >+ row[j+1+i] = (t&0xaaaaaaaa) | ((b&0xaaaaaaaa)>>1); >+ } >+ } >+#undef row >+} >+ >+static inline void trasp64_32_88cw(unsigned char *data){ >+/* 64 rows of 32 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ >+#define row ((unsigned int *)data) >+ int i,j; >+ for(j=0;j<64;j+=32){ >+ unsigned int t,b; >+ for(i=0;i<16;i++){ >+ t=row[j+i]; >+ b=row[j+16+i]; >+ row[j+i] = (t&0x0000ffff) | ((b )<<16); >+ row[j+16+i]=((t )>>16) | (b&0xffff0000) ; >+ } >+ } >+ for(j=0;j<64;j+=16){ >+ unsigned int t,b; >+ for(i=0;i<8;i++){ >+ t=row[j+i]; >+ b=row[j+8+i]; >+ row[j+i] = (t&0x00ff00ff) | ((b&0x00ff00ff)<<8); >+ row[j+8+i] =((t&0xff00ff00)>>8) | (b&0xff00ff00); >+ } >+ } >+ for(j=0;j<64;j+=8){ >+ unsigned int t,b; >+ for(i=0;i<4;i++){ >+ t=row[j+i]; >+ b=row[j+4+i]; >+ row[j+i] =((t&0xf0f0f0f0)>>4) | (b&0xf0f0f0f0); >+ row[j+4+i]= (t&0x0f0f0f0f) | ((b&0x0f0f0f0f)<<4); >+ } >+ } >+ for(j=0;j<64;j+=4){ >+ unsigned int t,b; >+ for(i=0;i<2;i++){ >+ t=row[j+i]; >+ b=row[j+2+i]; >+ row[j+i] =((t&0xcccccccc)>>2) | (b&0xcccccccc); >+ row[j+2+i]= (t&0x33333333) | ((b&0x33333333)<<2); >+ } >+ } >+ for(j=0;j<64;j+=2){ >+ unsigned int t,b; >+ for(i=0;i<1;i++){ >+ t=row[j+i]; >+ b=row[j+1+i]; >+ row[j+i] =((t&0xaaaaaaaa)>>1) | (b&0xaaaaaaaa); >+ row[j+1+i]= (t&0x55555555) | ((b&0x55555555)<<1); >+ } >+ } >+#undef row >+} >+ >+//64-64---------------------------------------------------------- >+static inline void trasp64_64_88ccw(unsigned char *data){ >+/* 64 rows of 64 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ >+#define row ((unsigned long long int *)data) >+ int i,j; >+ for(j=0;j<64;j+=64){ >+ unsigned long long int t,b; >+ for(i=0;i<32;i++){ >+ t=row[j+i]; >+ b=row[j+32+i]; >+ row[j+i] = (t&0x00000000ffffffffULL) | ((b )<<32); >+ row[j+32+i]=((t )>>32) | (b&0xffffffff00000000ULL) ; >+ } >+ } >+ for(j=0;j<64;j+=32){ >+ unsigned long long int t,b; >+ for(i=0;i<16;i++){ >+ t=row[j+i]; >+ b=row[j+16+i]; >+ row[j+i] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); >+ row[j+16+i]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; >+ } >+ } >+ for(j=0;j<64;j+=16){ >+ unsigned long long int t,b; >+ for(i=0;i<8;i++){ >+ t=row[j+i]; >+ b=row[j+8+i]; >+ row[j+i] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); >+ row[j+8+i] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); >+ } >+ } >+ for(j=0;j<64;j+=8){ >+ unsigned long long int t,b; >+ for(i=0;i<4;i++){ >+ t=row[j+i]; >+ b=row[j+4+i]; >+ row[j+i] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); >+ row[j+4+i] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); >+ } >+ } >+ for(j=0;j<64;j+=4){ >+ unsigned long long int t,b; >+ for(i=0;i<2;i++){ >+ t=row[j+i]; >+ b=row[j+2+i]; >+ row[j+i] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); >+ row[j+2+i] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); >+ } >+ } >+ for(j=0;j<64;j+=2){ >+ unsigned long long int t,b; >+ for(i=0;i<1;i++){ >+ t=row[j+i]; >+ b=row[j+1+i]; >+ row[j+i] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); >+ row[j+1+i] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); >+ } >+ } >+#undef row >+} >+ >+static inline void trasp64_64_88cw(unsigned char *data){ >+/* 64 rows of 64 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ >+#define row ((unsigned long long int *)data) >+ int i,j; >+ for(j=0;j<64;j+=64){ >+ unsigned long long int t,b; >+ for(i=0;i<32;i++){ >+ t=row[j+i]; >+ b=row[j+32+i]; >+ row[j+i] = (t&0x00000000ffffffffULL) | ((b )<<32); >+ row[j+32+i]=((t )>>32) | (b&0xffffffff00000000ULL) ; >+ } >+ } >+ for(j=0;j<64;j+=32){ >+ unsigned long long int t,b; >+ for(i=0;i<16;i++){ >+ t=row[j+i]; >+ b=row[j+16+i]; >+ row[j+i] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); >+ row[j+16+i]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; >+ } >+ } >+ for(j=0;j<64;j+=16){ >+ unsigned long long int t,b; >+ for(i=0;i<8;i++){ >+ t=row[j+i]; >+ b=row[j+8+i]; >+ row[j+i] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); >+ row[j+8+i] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); >+ } >+ } >+ for(j=0;j<64;j+=8){ >+ unsigned long long int t,b; >+ for(i=0;i<4;i++){ >+ t=row[j+i]; >+ b=row[j+4+i]; >+ row[j+i] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); >+ row[j+4+i] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); >+ } >+ } >+ for(j=0;j<64;j+=4){ >+ unsigned long long int t,b; >+ for(i=0;i<2;i++){ >+ t=row[j+i]; >+ b=row[j+2+i]; >+ row[j+i] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); >+ row[j+2+i] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); >+ } >+ } >+ for(j=0;j<64;j+=2){ >+ unsigned long long int t,b; >+ for(i=0;i<1;i++){ >+ t=row[j+i]; >+ b=row[j+1+i]; >+ row[j+i] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); >+ row[j+1+i] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); >+ } >+ } >+#undef row >+} >+ >+//64-128---------------------------------------------------------- >+static inline void trasp64_128_88ccw(unsigned char *data){ >+/* 64 rows of 128 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ >+#define halfrow ((unsigned long long int *)data) >+ int i,j; >+ for(j=0;j<64;j+=64){ >+ unsigned long long int t,b; >+ for(i=0;i<32;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+32+i)]; >+ halfrow[2*(j+i)] = (t&0x00000000ffffffffULL) | ((b )<<32); >+ halfrow[2*(j+32+i)]=((t )>>32) | (b&0xffffffff00000000ULL) ; >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+32+i)+1]; >+ halfrow[2*(j+i)+1] = (t&0x00000000ffffffffULL) | ((b )<<32); >+ halfrow[2*(j+32+i)+1]=((t )>>32) | (b&0xffffffff00000000ULL) ; >+ } >+ } >+ for(j=0;j<64;j+=32){ >+ unsigned long long int t,b; >+ for(i=0;i<16;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+16+i)]; >+ halfrow[2*(j+i)] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); >+ halfrow[2*(j+16+i)]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+16+i)+1]; >+ halfrow[2*(j+i)+1] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); >+ halfrow[2*(j+16+i)+1]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; >+ } >+ } >+ for(j=0;j<64;j+=16){ >+ unsigned long long int t,b; >+ for(i=0;i<8;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+8+i)]; >+ halfrow[2*(j+i)] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); >+ halfrow[2*(j+8+i)] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+8+i)+1]; >+ halfrow[2*(j+i)+1] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); >+ halfrow[2*(j+8+i)+1] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); >+ } >+ } >+ for(j=0;j<64;j+=8){ >+ unsigned long long int t,b; >+ for(i=0;i<4;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+4+i)]; >+ halfrow[2*(j+i)] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); >+ halfrow[2*(j+4+i)] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+4+i)+1]; >+ halfrow[2*(j+i)+1] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); >+ halfrow[2*(j+4+i)+1] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); >+ } >+ } >+ for(j=0;j<64;j+=4){ >+ unsigned long long int t,b; >+ for(i=0;i<2;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+2+i)]; >+ halfrow[2*(j+i)] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); >+ halfrow[2*(j+2+i)] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+2+i)+1]; >+ halfrow[2*(j+i)+1] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); >+ halfrow[2*(j+2+i)+1] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); >+ } >+ } >+ for(j=0;j<64;j+=2){ >+ unsigned long long int t,b; >+ for(i=0;i<1;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+1+i)]; >+ halfrow[2*(j+i)] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); >+ halfrow[2*(j+1+i)] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+1+i)+1]; >+ halfrow[2*(j+i)+1] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); >+ halfrow[2*(j+1+i)+1] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); >+ } >+ } >+#undef halfrow >+} >+ >+static inline void trasp64_128_88cw(unsigned char *data){ >+/* 64 rows of 128 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ >+#define halfrow ((unsigned long long int *)data) >+ int i,j; >+ for(j=0;j<64;j+=64){ >+ unsigned long long int t,b; >+ for(i=0;i<32;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+32+i)]; >+ halfrow[2*(j+i)] = (t&0x00000000ffffffffULL) | ((b )<<32); >+ halfrow[2*(j+32+i)]=((t )>>32) | (b&0xffffffff00000000ULL) ; >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+32+i)+1]; >+ halfrow[2*(j+i)+1] = (t&0x00000000ffffffffULL) | ((b )<<32); >+ halfrow[2*(j+32+i)+1]=((t )>>32) | (b&0xffffffff00000000ULL) ; >+ } >+ } >+ for(j=0;j<64;j+=32){ >+ unsigned long long int t,b; >+ for(i=0;i<16;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+16+i)]; >+ halfrow[2*(j+i)] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); >+ halfrow[2*(j+16+i)]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+16+i)+1]; >+ halfrow[2*(j+i)+1] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); >+ halfrow[2*(j+16+i)+1]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; >+ } >+ } >+ for(j=0;j<64;j+=16){ >+ unsigned long long int t,b; >+ for(i=0;i<8;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+8+i)]; >+ halfrow[2*(j+i)] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); >+ halfrow[2*(j+8+i)] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+8+i)+1]; >+ halfrow[2*(j+i)+1] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); >+ halfrow[2*(j+8+i)+1] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); >+ } >+ } >+ for(j=0;j<64;j+=8){ >+ unsigned long long int t,b; >+ for(i=0;i<4;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+4+i)]; >+ halfrow[2*(j+i)] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); >+ halfrow[2*(j+4+i)] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+4+i)+1]; >+ halfrow[2*(j+i)+1] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); >+ halfrow[2*(j+4+i)+1] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); >+ } >+ } >+ for(j=0;j<64;j+=4){ >+ unsigned long long int t,b; >+ for(i=0;i<2;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+2+i)]; >+ halfrow[2*(j+i)] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); >+ halfrow[2*(j+2+i)] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+2+i)+1]; >+ halfrow[2*(j+i)+1] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); >+ halfrow[2*(j+2+i)+1] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); >+ } >+ } >+ for(j=0;j<64;j+=2){ >+ unsigned long long int t,b; >+ for(i=0;i<1;i++){ >+ t=halfrow[2*(j+i)]; >+ b=halfrow[2*(j+1+i)]; >+ halfrow[2*(j+i)] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); >+ halfrow[2*(j+1+i)] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); >+ t=halfrow[2*(j+i)+1]; >+ b=halfrow[2*(j+1+i)+1]; >+ halfrow[2*(j+i)+1] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); >+ halfrow[2*(j+1+i)+1] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); >+ } >+ } >+#undef halfrow >+} >+#endif >+ >+ >+#ifdef STREAM_INIT >+void stream_cypher_group_init( >+ struct stream_regs *regs, >+ group iA[8][4], // [In] iA00,iA01,...iA73 32 groups | Derived from key. >+ group iB[8][4], // [In] iB00,iB01,...iB73 32 groups | Derived from key. >+ unsigned char *sb) // [In] (SB0,SB1,...SB7)...x32 32*8 bytes | Extra input. >+#endif >+#ifdef STREAM_NORMAL >+void stream_cypher_group_normal( >+ struct stream_regs *regs, >+ unsigned char *cb) // [Out] (CB0,CB1,...CB7)...x32 32*8 bytes | Output. >+#endif >+{ >+#ifdef STREAM_INIT >+ group in1[4]; >+ group in2[4]; >+#endif >+ group extra_B[4]; >+ group fa,fb,fc,fd,fe; >+ group s1a,s1b,s2a,s2b,s3a,s3b,s4a,s4b,s5a,s5b,s6a,s6b,s7a,s7b; >+ group next_E[4]; >+ group tmp0,tmp1,tmp2,tmp3,tmp4; >+#ifdef STREAM_INIT >+ group *sb_g=(group *)sb; >+#endif >+#ifdef STREAM_NORMAL >+ group *cb_g=(group *)cb; >+#endif >+ int aboff; >+ int i,j,k,b; >+ int dbg; >+ >+#ifdef STREAM_INIT >+ DBG(fprintf(stderr,":::::::::: BEGIN STREAM INIT\n")); >+#endif >+#ifdef STREAM_NORMAL >+ DBG(fprintf(stderr,":::::::::: BEGIN STREAM NORMAL\n")); >+#endif >+#ifdef STREAM_INIT >+for(j=0;j<64;j++){ >+ DBG(fprintf(stderr,"precall prerot stream_in[%2i]=",j)); >+ DBG(dump_mem("",sb+BYPG*j,BYPG,BYPG)); >+} >+ >+DBG(dump_mem("stream_prerot ",sb,GROUP_PARALLELISM*8,BYPG)); >+#if GROUP_PARALLELISM==32 >+trasp64_32_88ccw(sb); >+#endif >+#if GROUP_PARALLELISM==64 >+trasp64_64_88ccw(sb); >+#endif >+#if GROUP_PARALLELISM==128 >+trasp64_128_88ccw(sb); >+#endif >+DBG(dump_mem("stream_postrot",sb,GROUP_PARALLELISM*8,BYPG)); >+ >+for(j=0;j<64;j++){ >+ DBG(fprintf(stderr,"precall stream_in[%2i]=",j)); >+ DBG(dump_mem("",sb+BYPG*j,BYPG,BYPG)); >+} >+#endif >+ >+ aboff=32; >+ >+#ifdef STREAM_INIT >+ // load first 32 bits of ck into A[aboff+0]..A[aboff+7] >+ // load last 32 bits of ck into B[aboff+0]..B[aboff+7] >+ // all other regs = 0 >+ for(i=0;i<8;i++){ >+ for(b=0;b<4;b++){ >+DBG(fprintf(stderr,"dbg from iA A[%i][%i]=",i,b)); >+DBG(dump_mem("",(unsigned char *)&iA[i][b],BYPG,BYPG)); >+DBG(fprintf(stderr," dbg from iB B[%i][%i]=",i,b)); >+DBG(dump_mem("",(unsigned char *)&iB[i][b],BYPG,BYPG)); >+ regs->A[aboff+i][b]=iA[i][b]; >+ regs->B[aboff+i][b]=iB[i][b]; >+ } >+ } >+ for(b=0;b<4;b++){ >+ regs->A[aboff+8][b]=FF0(); >+ regs->A[aboff+9][b]=FF0(); >+ regs->B[aboff+8][b]=FF0(); >+ regs->B[aboff+9][b]=FF0(); >+ } >+ for(b=0;b<4;b++){ >+ regs->X[b]=FF0(); >+ regs->Y[b]=FF0(); >+ regs->Z[b]=FF0(); >+ regs->D[b]=FF0(); >+ regs->E[b]=FF0(); >+ regs->F[b]=FF0(); >+ } >+ regs->p=FF0(); >+ regs->q=FF0(); >+ regs->r=FF0(); >+#endif >+ >+for(dbg=0;dbg<4;dbg++){ >+ DBG(fprintf(stderr,"dbg A0[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)®s->A[aboff+0][dbg],BYPG,BYPG)); >+ DBG(fprintf(stderr,"dbg B0[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)®s->B[aboff+0][dbg],BYPG,BYPG)); >+} >+ >+//////////////////////////////////////////////////////////////////////////////// >+ >+ // EXTERNAL LOOP - 8 bytes per operation >+ for(i=0;i<8;i++){ >+ >+ DBG(fprintf(stderr,"--BEGIN EXTERNAL LOOP %i\n",i)); >+ >+#ifdef STREAM_INIT >+ for(b=0;b<4;b++){ >+ in1[b]=sb_g[8*i+4+b]; >+ in2[b]=sb_g[8*i+b]; >+ } >+#endif >+ >+ // INTERNAL LOOP - 2 bits per iteration >+ for(j=0; j<4; j++){ >+ >+ DBG(fprintf(stderr,"---BEGIN INTERNAL LOOP %i (EXT %i, INT %i)\n",j,i,j)); >+ >+ // from A0..A9, 35 bits are selected as inputs to 7 s-boxes >+ // 5 bits input per s-box, 2 bits output per s-box >+ >+ // we can select bits with zero masking and shifting operations >+ // and synthetize s-boxes with optimized boolean functions. >+ // this is the actual reason we do all the crazy transposition >+ // stuff to switch between normal and bit slice representations. >+ // this code really flies. >+ >+ fe=regs->A[aboff+3][0];fa=regs->A[aboff+0][2];fb=regs->A[aboff+5][1];fc=regs->A[aboff+6][3];fd=regs->A[aboff+8][0]; >+/* 1000 1110 1110 0001 : lev 7: */ //tmp0=( fa^( fb^( ( ( ( fa|fb )^fc )|( fc^fd ) )^ALL_ONES ) ) ); >+/* 1110 0010 0011 0011 : lev 6: */ //tmp1=( ( fa|fb )^( ( fc&( fa|( fb^fd ) ) )^ALL_ONES ) ); >+/* 0011 0110 1000 1101 : lev 5: */ //tmp2=( fa^( ( fb&fd )^( ( fa&fd )|fc ) ) ); >+/* 0101 0101 1001 0011 : lev 5: */ //tmp3=( ( fa&fc )^( fa^( ( fa&fb )|fd ) ) ); >+/* 1000 1110 1110 0001 : lev 7: */ tmp0=FFXOR(fa,FFXOR(fb,FFXOR(FFOR(FFXOR(FFOR(fa,fb),fc),FFXOR(fc,fd)),FF1()))); >+/* 1110 0010 0011 0011 : lev 6: */ tmp1=FFXOR(FFOR(fa,fb),FFXOR(FFAND(fc,FFOR(fa,FFXOR(fb,fd))),FF1())); >+/* 0011 0110 1000 1101 : lev 5: */ tmp2=FFXOR(fa,FFXOR(FFAND(fb,fd),FFOR(FFAND(fa,fd),fc))); >+/* 0101 0101 1001 0011 : lev 5: */ tmp3=FFXOR(FFAND(fa,fc),FFXOR(fa,FFOR(FFAND(fa,fb),fd))); >+ s1a=FFXOR(tmp0,FFAND(fe,tmp1)); >+ s1b=FFXOR(tmp2,FFAND(fe,tmp3)); >+//dump_mem("s1as1b-fe",&fe,BYPG,BYPG); >+//dump_mem("s1as1b-fa",&fa,BYPG,BYPG); >+//dump_mem("s1as1b-fb",&fb,BYPG,BYPG); >+//dump_mem("s1as1b-fc",&fc,BYPG,BYPG); >+//dump_mem("s1as1b-fd",&fd,BYPG,BYPG); >+ >+ fe=regs->A[aboff+1][1];fa=regs->A[aboff+2][2];fb=regs->A[aboff+5][3];fc=regs->A[aboff+6][0];fd=regs->A[aboff+8][1]; >+/* 1001 1110 0110 0001 : lev 6: */ //tmp0=( fa^( ( fb&( fc|fd ) )^( fc^( fd^ALL_ONES ) ) ) ); >+/* 0000 0011 0111 1011 : lev 5: */ //tmp1=( ( fa&( fb^fd ) )|( ( fa|fb )&fc ) ); >+/* 1100 0110 1101 0010 : lev 6: */ //tmp2=( ( fb&fd )^( ( fa&fd )|( fb^( fc^ALL_ONES ) ) ) ); >+/* 0001 1110 1111 0101 : lev 5: */ //tmp3=( ( fa&fd )|( fa^( fb^( fc&fd ) ) ) ); >+/* 1001 1110 0110 0001 : lev 6: */ tmp0=FFXOR(fa,FFXOR(FFAND(fb,FFOR(fc,fd)),FFXOR(fc,FFXOR(fd,FF1())))); >+/* 0000 0011 0111 1011 : lev 5: */ tmp1=FFOR(FFAND(fa,FFXOR(fb,fd)),FFAND(FFOR(fa,fb),fc)); >+/* 1100 0110 1101 0010 : lev 6: */ tmp2=FFXOR(FFAND(fb,fd),FFOR(FFAND(fa,fd),FFXOR(fb,FFXOR(fc,FF1())))); >+/* 0001 1110 1111 0101 : lev 5: */ tmp3=FFOR(FFAND(fa,fd),FFXOR(fa,FFXOR(fb,FFAND(fc,fd)))); >+ s2a=FFXOR(tmp0,FFAND(fe,tmp1)); >+ s2b=FFXOR(tmp2,FFAND(fe,tmp3)); >+ >+ fe=regs->A[aboff+0][3];fa=regs->A[aboff+1][0];fb=regs->A[aboff+4][1];fc=regs->A[aboff+4][3];fd=regs->A[aboff+5][2]; >+/* 0100 1011 1001 0110 : lev 5: */ //tmp0=( fa^( fb^( ( fc&( fa|fd ) )^fd ) ) ); >+/* 1101 0101 1000 1100 : lev 7: */ //tmp1=( ( fa&fc )^( ( fa^fd )|( ( fb|fc )^( fd^ALL_ONES ) ) ) ); >+/* 0010 0111 1101 1000 : lev 4: */ //tmp2=( fa^( ( ( fb^fc )&fd )^fc ) ); >+/* 1111 1111 1111 1111 : lev 0: */ //tmp3=ALL_ONES; >+/* 0100 1011 1001 0110 : lev 5: */ tmp0=FFXOR(fa,FFXOR(fb,FFXOR(FFAND(fc,FFOR(fa,fd)),fd))); >+/* 1101 0101 1000 1100 : lev 7: */ tmp1=FFXOR(FFAND(fa,fc),FFOR(FFXOR(fa,fd),FFXOR(FFOR(fb,fc),FFXOR(fd,FF1())))); >+/* 0010 0111 1101 1000 : lev 4: */ tmp2=FFXOR(fa,FFXOR(FFAND(FFXOR(fb,fc),fd),fc)); >+/* 1111 1111 1111 1111 : lev 0: */ tmp3=FF1(); >+ s3a=FFXOR(tmp0,FFAND(FFNOT(fe),tmp1)); >+ s3b=FFXOR(tmp2,FFAND(fe,tmp3)); >+ >+ fe=regs->A[aboff+2][3];fa=regs->A[aboff+0][1];fb=regs->A[aboff+1][3];fc=regs->A[aboff+3][2];fd=regs->A[aboff+7][0]; >+/* 1011 0101 0100 1001 : lev 7: */ //tmp0=( fa^( ( fc&( fa^fd ) )|( fb^( fc|( fd^ALL_ONES ) ) ) ) ); >+/* 0010 1101 0110 0110 : lev 6: */ //tmp1=( ( fa&fb )^( fb^( ( ( fa|fc )&fd )^fc ) ) ); >+/* 0110 0111 1101 0000 : lev 7: */ //tmp2=( fa^( ( fb&fc )|( ( ( fa&( fb^fd ) )|fc )^fd ) ) ); >+/* 1111 1111 1111 1111 : lev 0: */ //tmp3=ALL_ONES; >+/* 1011 0101 0100 1001 : lev 7: */ tmp0=FFXOR(fa,FFOR(FFAND(fc,FFXOR(fa,fd)),FFXOR(fb,FFOR(fc,FFXOR(fd,FF1()))))); >+/* 0010 1101 0110 0110 : lev 6: */ tmp1=FFXOR(FFAND(fa,fb),FFXOR(fb,FFXOR(FFAND(FFOR(fa,fc),fd),fc))); >+/* 0110 0111 1101 0000 : lev 7: */ tmp2=FFXOR(fa,FFOR(FFAND(fb,fc),FFXOR(FFOR(FFAND(fa,FFXOR(fb,fd)),fc),fd))); >+/* 1111 1111 1111 1111 : lev 0: */ tmp3=FF1(); >+ s4a=FFXOR(tmp0,FFAND(fe,FFXOR(tmp1,tmp0))); >+ s4b=FFXOR(FFXOR(s4a,tmp2),FFAND(fe,tmp3)); >+ >+ fe=regs->A[aboff+4][2];fa=regs->A[aboff+3][3];fb=regs->A[aboff+5][0];fc=regs->A[aboff+7][1];fd=regs->A[aboff+8][2]; >+/* 1000 1111 0011 0010 : lev 7: */ //tmp0=( ( ( fa&( fb|fc ) )^fb )|( ( ( fa^fc )|fd )^ALL_ONES ) ); >+/* 0110 1011 0000 1011 : lev 6: */ //tmp1=( fb^( ( fc^fd )&( fc^( fb|( fa^fd ) ) ) ) ); >+/* 0001 1010 0111 1001 : lev 6: */ //tmp2=( ( fa&fc )^( fb^( ( fb|( fa^fc ) )&fd ) ) ); >+/* 0101 1101 1101 0101 : lev 4: */ //tmp3=( ( ( fa^fb )&( fc^ALL_ONES ) )|fd ); >+/* 1000 1111 0011 0010 : lev 7: */ tmp0=FFOR(FFXOR(FFAND(fa,FFOR(fb,fc)),fb),FFXOR(FFOR(FFXOR(fa,fc),fd),FF1())); >+/* 0110 1011 0000 1011 : lev 6: */ tmp1=FFXOR(fb,FFAND(FFXOR(fc,fd),FFXOR(fc,FFOR(fb,FFXOR(fa,fd))))); >+/* 0001 1010 0111 1001 : lev 6: */ tmp2=FFXOR(FFAND(fa,fc),FFXOR(fb,FFAND(FFOR(fb,FFXOR(fa,fc)),fd))); >+/* 0101 1101 1101 0101 : lev 4: */ tmp3=FFOR(FFAND(FFXOR(fa,fb),FFXOR(fc,FF1())),fd); >+ s5a=FFXOR(tmp0,FFAND(fe,tmp1)); >+ s5b=FFXOR(tmp2,FFAND(fe,tmp3)); >+ >+ fe=regs->A[aboff+2][1];fa=regs->A[aboff+3][1];fb=regs->A[aboff+4][0];fc=regs->A[aboff+6][2];fd=regs->A[aboff+8][3]; >+/* 0011 0110 0010 1101 : lev 6: */ //tmp0=( ( ( fa&fc )&fd )^( ( fb&( fa|fd ) )^fc ) ); >+/* 1110 1110 1011 1011 : lev 3: */ //tmp1=( ( ( fa^fc )&fd )^ALL_ONES ); >+/* 0101 1000 0110 0111 : lev 6: */ //tmp2=( ( fa&( fb|fc ) )^( fb^( ( fb&fc )|fd ) ) ); >+/* 0001 0011 0000 0001 : lev 5: */ //tmp3=( fc&( ( fa&( fb^fd ) )^( fb|fd ) ) ); >+/* 0011 0110 0010 1101 : lev 6: */ tmp0=FFXOR(FFAND(FFAND(fa,fc),fd),FFXOR(FFAND(fb,FFOR(fa,fd)),fc)); >+/* 1110 1110 1011 1011 : lev 3: */ tmp1=FFXOR(FFAND(FFXOR(fa,fc),fd),FF1()); >+/* 0101 1000 0110 0111 : lev 6: */ tmp2=FFXOR(FFAND(fa,FFOR(fb,fc)),FFXOR(fb,FFOR(FFAND(fb,fc),fd))); >+/* 0001 0011 0000 0001 : lev 5: */ tmp3=FFAND(fc,FFXOR(FFAND(fa,FFXOR(fb,fd)),FFOR(fb,fd))); >+ s6a=FFXOR(tmp0,FFAND(fe,tmp1)); >+ s6b=FFXOR(tmp2,FFAND(fe,tmp3)); >+ >+ fe=regs->A[aboff+1][2];fa=regs->A[aboff+2][0];fb=regs->A[aboff+6][1];fc=regs->A[aboff+7][2];fd=regs->A[aboff+7][3]; >+/* 0111 1000 1001 0110 : lev 5: */ //tmp0=( fb^( ( fc&fd )|( fa^( fc^fd ) ) ) ); >+/* 0100 1001 0101 1011 : lev 6: */ //tmp1=( ( fb|fd )&( ( fa&fc )|( fb^( fc^fd ) ) ) ); >+/* 0100 1001 1011 1001 : lev 5: */ //tmp2=( ( fa|fb )^( ( fc&( fb|fd ) )^fd ) ); >+/* 1111 1111 1101 1101 : lev 3: */ //tmp3=( fd|( ( fa&fc )^ALL_ONES ) ); >+/* 0111 1000 1001 0110 : lev 5: */ tmp0=FFXOR(fb,FFOR(FFAND(fc,fd),FFXOR(fa,FFXOR(fc,fd)))); >+/* 0100 1001 0101 1011 : lev 6: */ tmp1=FFAND(FFOR(fb,fd),FFOR(FFAND(fa,fc),FFXOR(fb,FFXOR(fc,fd)))); >+/* 0100 1001 1011 1001 : lev 5: */ tmp2=FFXOR(FFOR(fa,fb),FFXOR(FFAND(fc,FFOR(fb,fd)),fd)); >+/* 1111 1111 1101 1101 : lev 3: */ tmp3=FFOR(fd,FFXOR(FFAND(fa,fc),FF1())); >+ s7a=FFXOR(tmp0,FFAND(fe,tmp1)); >+ s7b=FFXOR(tmp2,FFAND(fe,tmp3)); >+ >+ >+/* >+ we have just done this: >+ >+ int sbox1[0x20] = {2,0,1,1,2,3,3,0, 3,2,2,0,1,1,0,3, 0,3,3,0,2,2,1,1, 2,2,0,3,1,1,3,0}; >+ int sbox2[0x20] = {3,1,0,2,2,3,3,0, 1,3,2,1,0,0,1,2, 3,1,0,3,3,2,0,2, 0,0,1,2,2,1,3,1}; >+ int sbox3[0x20] = {2,0,1,2,2,3,3,1, 1,1,0,3,3,0,2,0, 1,3,0,1,3,0,2,2, 2,0,1,2,0,3,3,1}; >+ int sbox4[0x20] = {3,1,2,3,0,2,1,2, 1,2,0,1,3,0,0,3, 1,0,3,1,2,3,0,3, 0,3,2,0,1,2,2,1}; >+ int sbox5[0x20] = {2,0,0,1,3,2,3,2, 0,1,3,3,1,0,2,1, 2,3,2,0,0,3,1,1, 1,0,3,2,3,1,0,2}; >+ int sbox6[0x20] = {0,1,2,3,1,2,2,0, 0,1,3,0,2,3,1,3, 2,3,0,2,3,0,1,1, 2,1,1,2,0,3,3,0}; >+ int sbox7[0x20] = {0,3,2,2,3,0,0,1, 3,0,1,3,1,2,2,1, 1,0,3,3,0,1,1,2, 2,3,1,0,2,3,0,2}; >+ >+ s12 = sbox1[ (((A3>>0)&1)<<4) | (((A0>>2)&1)<<3) | (((A5>>1)&1)<<2) | (((A6>>3)&1)<<1) | (((A8>>0)&1)<<0) ] >+ |sbox2[ (((A1>>1)&1)<<4) | (((A2>>2)&1)<<3) | (((A5>>3)&1)<<2) | (((A6>>0)&1)<<1) | (((A8>>1)&1)<<0) ]; >+ s34 = sbox3[ (((A0>>3)&1)<<4) | (((A1>>0)&1)<<3) | (((A4>>1)&1)<<2) | (((A4>>3)&1)<<1) | (((A5>>2)&1)<<0) ] >+ |sbox4[ (((A2>>3)&1)<<4) | (((A0>>1)&1)<<3) | (((A1>>3)&1)<<2) | (((A3>>2)&1)<<1) | (((A7>>0)&1)<<0) ]; >+ s56 = sbox5[ (((A4>>2)&1)<<4) | (((A3>>3)&1)<<3) | (((A5>>0)&1)<<2) | (((A7>>1)&1)<<1) | (((A8>>2)&1)<<0) ] >+ |sbox6[ (((A2>>1)&1)<<4) | (((A3>>1)&1)<<3) | (((A4>>0)&1)<<2) | (((A6>>2)&1)<<1) | (((A8>>3)&1)<<0) ]; >+ s7 = sbox7[ (((A1>>2)&1)<<4) | (((A2>>0)&1)<<3) | (((A6>>1)&1)<<2) | (((A7>>2)&1)<<1) | (((A7>>3)&1)<<0) ]; >+*/ >+ >+ // use 4x4 xor to produce extra nibble for T3 >+ >+ extra_B[3]=FFXOR(FFXOR(FFXOR(regs->B[aboff+2][0],regs->B[aboff+5][1]),regs->B[aboff+6][2]),regs->B[aboff+8][3]); >+ extra_B[2]=FFXOR(FFXOR(FFXOR(regs->B[aboff+5][0],regs->B[aboff+7][1]),regs->B[aboff+2][3]),regs->B[aboff+3][2]); >+ extra_B[1]=FFXOR(FFXOR(FFXOR(regs->B[aboff+4][3],regs->B[aboff+7][2]),regs->B[aboff+3][0]),regs->B[aboff+4][1]); >+ extra_B[0]=FFXOR(FFXOR(FFXOR(regs->B[aboff+8][2],regs->B[aboff+5][3]),regs->B[aboff+2][1]),regs->B[aboff+7][0]); >+for(dbg=0;dbg<4;dbg++){ >+ DBG(fprintf(stderr,"extra_B[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)&extra_B[dbg],BYPG,BYPG)); >+} >+ >+ // T1 = xor all inputs >+ // in1, in2, D are only used in T1 during initialisation, not generation >+ for(b=0;b<4;b++){ >+ regs->A[aboff-1][b]=FFXOR(regs->A[aboff+9][b],regs->X[b]); >+ } >+ >+#ifdef STREAM_INIT >+ for(b=0;b<4;b++){ >+ regs->A[aboff-1][b]=FFXOR(FFXOR(regs->A[aboff-1][b],regs->D[b]),((j % 2) ? in2[b] : in1[b])); >+ } >+#endif >+ >+for(dbg=0;dbg<4;dbg++){ >+ DBG(fprintf(stderr,"next_A0[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)®s->A[aboff-1][dbg],BYPG,BYPG)); >+} >+ >+ // T2 = xor all inputs >+ // in1, in2 are only used in T1 during initialisation, not generation >+ // if p=0, use this, if p=1, rotate the result left >+ for(b=0;b<4;b++){ >+ regs->B[aboff-1][b]=FFXOR(FFXOR(regs->B[aboff+6][b],regs->B[aboff+9][b]),regs->Y[b]); >+ } >+ >+#ifdef STREAM_INIT >+ for(b=0;b<4;b++){ >+ regs->B[aboff-1][b]=FFXOR(regs->B[aboff-1][b],((j % 2) ? in1[b] : in2[b])); >+ } >+#endif >+ >+for(dbg=0;dbg<4;dbg++){ >+ DBG(fprintf(stderr,"next_B0[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)®s->B[aboff-1][dbg],BYPG,BYPG)); >+} >+ >+ // if p=1, rotate left (yes, this is what we're doing) >+ tmp3=regs->B[aboff-1][3]; >+ regs->B[aboff-1][3]=FFXOR(regs->B[aboff-1][3],FFAND(FFXOR(regs->B[aboff-1][3],regs->B[aboff-1][2]),regs->p)); >+ regs->B[aboff-1][2]=FFXOR(regs->B[aboff-1][2],FFAND(FFXOR(regs->B[aboff-1][2],regs->B[aboff-1][1]),regs->p)); >+ regs->B[aboff-1][1]=FFXOR(regs->B[aboff-1][1],FFAND(FFXOR(regs->B[aboff-1][1],regs->B[aboff-1][0]),regs->p)); >+ regs->B[aboff-1][0]=FFXOR(regs->B[aboff-1][0],FFAND(FFXOR(regs->B[aboff-1][0],tmp3),regs->p)); >+ >+for(dbg=0;dbg<4;dbg++){ >+ DBG(fprintf(stderr,"next_B0[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)®s->B[aboff-1][dbg],BYPG,BYPG)); >+} >+ >+ // T3 = xor all inputs >+ for(b=0;b<4;b++){ >+ regs->D[b]=FFXOR(FFXOR(regs->E[b],regs->Z[b]),extra_B[b]); >+ } >+ >+for(dbg=0;dbg<4;dbg++){ >+ DBG(fprintf(stderr,"D[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)®s->D[dbg],BYPG,BYPG)); >+} >+ >+ // T4 = sum, carry of Z + E + r >+ for(b=0;b<4;b++){ >+ next_E[b]=regs->F[b]; >+ } >+ >+ tmp0=FFXOR(regs->Z[0],regs->E[0]); >+ tmp1=FFAND(regs->Z[0],regs->E[0]); >+ regs->F[0]=FFXOR(regs->E[0],FFAND(regs->q,FFXOR(regs->Z[0],regs->r))); >+ tmp3=FFAND(tmp0,regs->r); >+ tmp4=FFOR(tmp1,tmp3); >+ >+ tmp0=FFXOR(regs->Z[1],regs->E[1]); >+ tmp1=FFAND(regs->Z[1],regs->E[1]); >+ regs->F[1]=FFXOR(regs->E[1],FFAND(regs->q,FFXOR(regs->Z[1],tmp4))); >+ tmp3=FFAND(tmp0,tmp4); >+ tmp4=FFOR(tmp1,tmp3); >+ >+ tmp0=FFXOR(regs->Z[2],regs->E[2]); >+ tmp1=FFAND(regs->Z[2],regs->E[2]); >+ regs->F[2]=FFXOR(regs->E[2],FFAND(regs->q,FFXOR(regs->Z[2],tmp4))); >+ tmp3=FFAND(tmp0,tmp4); >+ tmp4=FFOR(tmp1,tmp3); >+ >+ tmp0=FFXOR(regs->Z[3],regs->E[3]); >+ tmp1=FFAND(regs->Z[3],regs->E[3]); >+ regs->F[3]=FFXOR(regs->E[3],FFAND(regs->q,FFXOR(regs->Z[3],tmp4))); >+ tmp3=FFAND(tmp0,tmp4); >+ regs->r=FFXOR(regs->r,FFAND(regs->q,FFXOR(FFOR(tmp1,tmp3),regs->r))); // ultimate carry >+ >+/* >+ we have just done this: (believe it or not) >+ >+ if (q) { >+ F = Z + E + r; >+ r = (F >> 4) & 1; >+ F = F & 0x0f; >+ } >+ else { >+ F = E; >+ } >+*/ >+ for(b=0;b<4;b++){ >+ regs->E[b]=next_E[b]; >+ } >+for(dbg=0;dbg<4;dbg++){ >+ DBG(fprintf(stderr,"F[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)®s->F[dbg],BYPG,BYPG)); >+} >+DBG(fprintf(stderr,"r=")); >+DBG(dump_mem("",(unsigned char *)®s->r,BYPG,BYPG)); >+for(dbg=0;dbg<4;dbg++){ >+ DBG(fprintf(stderr,"E[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)®s->E[dbg],BYPG,BYPG)); >+} >+ >+ // this simple instruction is virtually shifting all the shift registers >+ aboff--; >+ >+/* >+ we've just done this: >+ >+ A9=A8;A8=A7;A7=A6;A6=A5;A5=A4;A4=A3;A3=A2;A2=A1;A1=A0;A0=next_A0; >+ B9=B8;B8=B7;B7=B6;B6=B5;B5=B4;B4=B3;B3=B2;B2=B1;B1=B0;B0=next_B0; >+*/ >+ >+ regs->X[0]=s1a; >+ regs->X[1]=s2a; >+ regs->X[2]=s3b; >+ regs->X[3]=s4b; >+ regs->Y[0]=s3a; >+ regs->Y[1]=s4a; >+ regs->Y[2]=s5b; >+ regs->Y[3]=s6b; >+ regs->Z[0]=s5a; >+ regs->Z[1]=s6a; >+ regs->Z[2]=s1b; >+ regs->Z[3]=s2b; >+ regs->p=s7a; >+ regs->q=s7b; >+for(dbg=0;dbg<4;dbg++){ >+ DBG(fprintf(stderr,"X[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)®s->X[dbg],BYPG,BYPG)); >+} >+for(dbg=0;dbg<4;dbg++){ >+ DBG(fprintf(stderr,"Y[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)®s->Y[dbg],BYPG,BYPG)); >+} >+for(dbg=0;dbg<4;dbg++){ >+ DBG(fprintf(stderr,"Z[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)®s->Z[dbg],BYPG,BYPG)); >+} >+DBG(fprintf(stderr,"p=")); >+DBG(dump_mem("",(unsigned char *)®s->p,BYPG,BYPG)); >+DBG(fprintf(stderr,"q=")); >+DBG(dump_mem("",(unsigned char *)®s->q,BYPG,BYPG)); >+ >+#ifdef STREAM_NORMAL >+ // require 4 loops per output byte >+ // 2 output bits are a function of the 4 bits of D >+ // xor 2 by 2 >+ cb_g[8*i+7-2*j]=FFXOR(regs->D[2],regs->D[3]); >+ cb_g[8*i+6-2*j]=FFXOR(regs->D[0],regs->D[1]); >+for(dbg=0;dbg<8;dbg++){ >+ DBG(fprintf(stderr,"op[%i]=",dbg)); >+ DBG(dump_mem("",(unsigned char *)&cb_g[8*i+dbg],BYPG,BYPG)); >+} >+#endif >+ >+DBG(fprintf(stderr,"---END INTERNAL LOOP\n")); >+ >+ } // INTERNAL LOOP >+ >+DBG(fprintf(stderr,"--END EXTERNAL LOOP\n")); >+ >+ } // EXTERNAL LOOP >+ >+ // move 32 steps forward, ready for next call >+ for(k=0;k<10;k++){ >+ for(b=0;b<4;b++){ >+DBG(fprintf(stderr,"moving forward AB k=%i b=%i\n",k,b)); >+ regs->A[32+k][b]=regs->A[k][b]; >+ regs->B[32+k][b]=regs->B[k][b]; >+ } >+ } >+ >+ >+//////////////////////////////////////////////////////////////////////////////// >+ >+#ifdef STREAM_NORMAL >+for(j=0;j<64;j++){ >+ DBG(fprintf(stderr,"postcall prerot cb[%2i]=",j)); >+ DBG(dump_mem("",(unsigned char *)(cb+BYPG*j),BYPG,BYPG)); >+} >+ >+#if GROUP_PARALLELISM==32 >+trasp64_32_88cw(cb); >+#endif >+#if GROUP_PARALLELISM==64 >+trasp64_64_88cw(cb); >+#endif >+#if GROUP_PARALLELISM==128 >+trasp64_128_88cw(cb); >+#endif >+ >+for(j=0;j<64;j++){ >+ DBG(fprintf(stderr,"postcall postrot cb[%2i]=",j)); >+ DBG(dump_mem("",(unsigned char *)(cb+BYPG*j),BYPG,BYPG)); >+} >+#endif >+ >+#ifdef STREAM_INIT >+ DBG(fprintf(stderr,":::::::::: END STREAM INIT\n")); >+#endif >+#ifdef STREAM_NORMAL >+ DBG(fprintf(stderr,":::::::::: END STREAM NORMAL\n")); >+#endif >+ >+} >+ >Index: globals.h >=================================================================== >--- globals.h (revision 11398) >+++ globals.h (working copy) >@@ -389,17 +389,17 @@ > #define CS_ECM_RINGBUFFER_MAX 0x10 // max size for ECM last responsetimes ringbuffer. Keep this set to power of 2 values! > > // Support for multiple CWs per channel and other encryption algos >-//#define WITH_EXTENDED_CW 1 >+#define WITH_EXTENDED_CW 1 > > #if defined(READER_DRE) || defined(READER_DRECAS) || defined(READER_VIACCESS) > #define MAX_ECM_SIZE 1024 > #define MAX_EMM_SIZE 1024 > #else >-#define MAX_ECM_SIZE 596 >-#define MAX_EMM_SIZE 512 >+#define MAX_ECM_SIZE 1024 >+#define MAX_EMM_SIZE 1024 > #endif > >-#define CS_EMMCACHESIZE 512 //nr of EMMs that each reader will cache >+#define CS_EMMCACHESIZE 1024 //nr of EMMs that each reader will cache > #define MSGLOGSIZE 64 //size of string buffer for a ecm to return messages > > #define D_TRACE 0x0001 // Generate very detailed error/trace messages per routine >@@ -431,6 +431,7 @@ > #define R_SMART 0x7 // Smartreader+ > #define R_PCSC 0x8 // PCSC > #define R_DRECAS 0x9 // Reader DRECAS >+#define R_EMU 0x17 // Reader EMU > /////////////////// proxy readers after R_CS378X > #define R_CAMD35 0x20 // Reader cascading camd 3.5x > #define R_CAMD33 0x21 // Reader cascading camd 3.3x >@@ -858,6 +859,13 @@ > uint32_t class; // the class needed for some systems > time_t start; // startdate > time_t end; // enddate >+#ifdef WITH_EMU >+ bool isKey; >+ bool isData; >+ char name[8]; >+ uint8_t *key; >+ uint32_t keyLength; >+#endif > } S_ENTITLEMENT; > > struct s_client ; >@@ -982,6 +990,7 @@ > void (*post_process)(struct s_reader *); > int32_t (*get_emm_type)(struct emm_packet_t *, struct s_reader *); > int32_t (*get_emm_filter)(struct s_reader *, struct s_csystem_emm_filter **, unsigned int *); >+ int32_t (*get_emm_filter_adv)(struct s_reader *, struct s_csystem_emm_filter **, unsigned int *, uint16_t, uint32_t, uint16_t); > int32_t (*get_tunemm_filter)(struct s_reader *, struct s_csystem_emm_filter **, unsigned int *); > }; > >@@ -1714,6 +1723,14 @@ > #ifdef MODULE_GHTTP > uint8_t ghttp_use_ssl; > #endif >+#ifdef WITH_EMU >+ FTAB emu_auproviders; // AU providers for Emu reader >+ int8_t emu_datecodedenabled; // date-coded keys for BISS >+ char *extee36; // path to "ee36.bin" - Set by the user via the webif >+ char *extee56; // path to "ee56.bin" - Set by the user via the webif >+ uint8_t dre36_force_group; >+ uint8_t dre56_force_group; >+#endif > uint8_t cnxlastecm; // == 0 - las ecm has not been paired ecm, > 0 last ecm has been paired ecm > LLIST *emmstat; //emm stats > CS_MUTEX_LOCK emmstat_lock; >@@ -2161,6 +2178,7 @@ > int8_t dvbapi_read_sdt; > int8_t dvbapi_write_sdt_prov; > int8_t dvbapi_extended_cw_api; >+ int8_t dvbapi_extended_cw_pids; // pid limiter > #endif > > #ifdef CS_ANTICASC >@@ -2207,6 +2225,18 @@ > IN_ADDR_T scam_srvip; > struct s_ip *scam_allowed; > #endif >+ >+#ifdef WITH_EMU >+ char *emu_stream_source_host; >+ int32_t emu_stream_source_port; >+ char *emu_stream_source_auth_user; >+ char *emu_stream_source_auth_password; >+ int32_t emu_stream_relay_port; >+ uint32_t emu_stream_ecm_delay; >+ int8_t emu_stream_relay_enabled; >+ int8_t emu_stream_emm_enabled; >+#endif >+ > int32_t max_cache_time; //seconds ecms are stored in ecmcwcache > int32_t max_hitcache_time; //seconds hits are stored in cspec_hitcache (to detect dyn wait_time) > >@@ -2388,4 +2418,8 @@ > static inline bool caid_is_dre(uint16_t caid) { return caid == 0x4AE0 || caid == 0x4AE1 || caid == 0x2710;} > const char *get_cardsystem_desc_by_caid(uint16_t caid); > >+#ifdef WITH_EMU >+FILTER* get_emu_prids_for_caid(struct s_reader *rdr, uint16_t caid); >+#endif >+ > #endif >Index: module-dvbapi.c >=================================================================== >--- module-dvbapi.c (revision 11398) >+++ module-dvbapi.c (working copy) >@@ -1471,7 +1471,15 @@ > } > if(match) > { >- csystem = get_cardsystem_by_caid(caid); >+ if(rdr->typ == R_EMU) >+ { >+ csystem = rdr->csystem; >+ } >+ else >+ { >+ csystem = get_cardsystem_by_caid(caid); >+ } >+ > if(csystem) > { > if(caid != ncaid) >@@ -1490,7 +1498,14 @@ > } > else if (csystem->get_emm_filter) > { >- csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); >+ if(rdr->typ == R_EMU) >+ { >+ csystem->get_emm_filter_adv(rdr, &dmx_filter, &filter_count, caid, provid, demux[demux_index].program_number); >+ } >+ else >+ { >+ csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); >+ } > } > } > else >@@ -2076,6 +2091,8 @@ > er->vpid = demux[demux_id].ECMpids[pid].VPID; > er->pmtpid = demux[demux_id].pmtpid; > er->onid = demux[demux_id].onid; >+ er->tsid = demux[demux_id].tsid; >+ er->ens = demux[demux_id].enigma_namespace; > er->msgid = msgid; > > #ifdef WITH_STAPI5 >@@ -2113,19 +2130,30 @@ > if(caid_is_fake(demux[demux_id].ECMpids[pid].CAID) || caid_is_biss(demux[demux_id].ECMpids[pid].CAID)) > { > int32_t j, n; >- er->ecmlen = 5; >+ er->ecmlen = 7; > er->ecm[0] = 0x80; // to pass the cache check it must be 0x80 or 0x81 > er->ecm[1] = 0x00; >- er->ecm[2] = 0x02; >+ er->ecm[2] = 0x04; > i2b_buf(2, er->srvid, er->ecm + 3); >+ i2b_buf(2, er->pmtpid, er->ecm + 5); > >- for(j = 0, n = 5; j < demux[demux_id].STREAMpidcount; j++, n += 2) >+ for(j = 0, n = 7; j < demux[demux_id].STREAMpidcount; j++, n += 2) > { > i2b_buf(2, demux[demux_id].STREAMpids[j], er->ecm + n); > er->ecm[2] += 2; > er->ecmlen += 2; > } > >+ er->ens &= 0x0FFFFFFF; // clear top 4 bits (in case of DVB-T/C or garbage), prepare for flagging >+ er->ens |= 0xA0000000; // flag to emu: this is the namespace, not a pid >+ >+ i2b_buf(2, er->tsid, er->ecm + 3 + er->ecm[2]); // place tsid after the last stream pid >+ i2b_buf(2, er->onid, er->ecm + 3 + er->ecm[2] + 2); // place onid right after tsid >+ i2b_buf(4, er->ens, er->ecm + 3 + er->ecm[2] + 4); // place namespace at the end of the ecm >+ >+ er->ecm[2] += 8; >+ er->ecmlen += 8; >+ > cs_log("Demuxer %d trying to descramble PID %d CAID %04X PROVID %06X ECMPID %04X ANY CHID PMTPID %04X VPID %04X", demux_id, pid, > demux[demux_id].ECMpids[pid].CAID, demux[demux_id].ECMpids[pid].PROVID, demux[demux_id].ECMpids[pid].ECM_PID, > demux[demux_id].pmtpid, demux[demux_id].ECMpids[pid].VPID); >@@ -3192,6 +3220,7 @@ > { > uint32_t i = 0, start_descrambling = 0; > int32_t j = 0; >+ int32_t max_pids = 64; > int32_t demux_id = -1; > uint16_t demux_index, adapter_index, pmtpid; > uint32_t ca_mask; >@@ -3354,6 +3383,12 @@ > uint32_t es_info_length = 0, vpid = 0; > struct s_dvbapi_priority *addentry; > >+ // pid limiter for PowerVu >+ if(demux[demux_id].ECMpids[0].CAID >> 8 == 0x0E) >+ { >+ max_pids = cfg.dvbapi_extended_cw_pids; >+ } >+ > for(i = program_info_length + program_info_start; i + 4 < length; i += es_info_length + 5) > { > uint8_t stream_type = buffer[i]; >@@ -3361,7 +3396,7 @@ > uint8_t is_audio = 0; > es_info_length = b2i(2, buffer + i +3)&0x0FFF; > >- if(demux[demux_id].STREAMpidcount < ECM_PIDS) >+ if(demux[demux_id].STREAMpidcount < max_pids) // was "ECM_PIDS" (pid limiter) > { > > demux[demux_id].STREAMpids[demux[demux_id].STREAMpidcount] = elementary_pid; >@@ -4375,6 +4410,7 @@ > if(filtertype == TYPE_ECM) > { > uint32_t chid = 0x10000; >+ int8_t pvu_skip = 0; > ECM_REQUEST *er; > > if(len != 0) // len = 0 receiver encountered an internal bufferoverflow! >@@ -4401,9 +4437,24 @@ > return; > } > >- if(curpid->table == buffer[0] && !caid_is_irdeto(curpid->CAID)) // wait for odd / even ecm change (only not for irdeto!) >+ if(curpid->CAID >> 8 == 0x0E) > { >- >+ pvu_skip = 1; >+ >+ if(sctlen - 11 > buffer[9]) >+ { >+ if(buffer[11 + buffer[9]] > curpid->pvu_counter || (curpid->pvu_counter == 255 && buffer[11 + buffer[9]] == 0) >+ || ((curpid->pvu_counter - buffer[11 + buffer[9]]) > 5)) >+ { >+ curpid->pvu_counter = buffer[11 + buffer[9]]; >+ pvu_skip = 0; >+ } >+ } >+ } >+ >+ if((curpid->table == buffer[0] && !caid_is_irdeto(curpid->CAID)) || pvu_skip) // wait for odd / even ecm change (only not for irdeto!) >+ { >+ > if(!(er = get_ecmtask())) > { > return; >@@ -4685,6 +4736,40 @@ > dvbapi_stop_filternum(demux_id, filter_num, msgid); > return; > } >+ >+#ifdef WITH_EMU >+ if((demux[demux_id].demux_fd[filter_num].caid>>8) == 0x10) >+ { >+ uint32_t i; >+ uint32_t emmhash; >+ >+ if(sctlen < 4) >+ { >+ return; >+ } >+ >+ for(i=0; i+2<sctlen; i++) >+ { >+ if(buffer[i] == 0xF0 && (buffer[i+2] == 0xE1 || buffer[i+2] == 0xE4)) >+ { >+ emmhash = (buffer[3]<<8) | buffer[sctlen-2]; >+ >+ if(demux[demux_id].demux_fd[filter_num].cadata == emmhash) >+ { >+ return; >+ } >+ >+ demux[demux_id].demux_fd[filter_num].cadata = emmhash; >+ >+ dvbapi_process_emm(demux_id, filter_num, buffer, sctlen); >+ return; >+ } >+ } >+ >+ return; >+ } >+#endif >+ > dvbapi_process_emm(demux_id, filter_num, buffer, sctlen); > } > >@@ -6203,6 +6288,9 @@ > > delayer(er, delay); > >+#ifdef WITH_EMU >+ if(er->caid>>8 != 0x0E || !cfg.emu_stream_relay_enabled) >+#endif > switch(selected_api) > { > #if defined(WITH_STAPI) || defined(WITH_STAPI5) >Index: module-dvbapi.h >=================================================================== >--- module-dvbapi.h (revision 11398) >+++ module-dvbapi.h (working copy) >@@ -136,6 +136,7 @@ > int8_t useMultipleIndices; > uint32_t streams; > uint32_t cadata; >+ int16_t pvu_counter; > }; > > typedef struct filter_s >@@ -158,6 +159,9 @@ > uint32_t SlotHandle[10]; > uint32_t BufferHandle[10]; > #endif >+#ifdef WITH_EMU >+ uint32_t cadata; >+#endif > } FILTERTYPE; > > struct s_emmpids >Index: module-emulator-osemu.c >=================================================================== >--- module-emulator-osemu.c (revision 0) >+++ module-emulator-osemu.c (working copy) >@@ -0,0 +1,6461 @@ >+#define MODULE_LOG_PREFIX "emu" >+ >+#include "globals.h" >+#include "ffdecsa/ffdecsa.h" >+#include "cscrypt/bn.h" >+#include "cscrypt/des.h" >+#include "cscrypt/idea.h" >+#include "cscrypt/md5.h" >+ >+#ifdef WITH_EMU >+#include "oscam-aes.h" >+#include "oscam-string.h" >+#include "oscam-config.h" >+#include "oscam-conf-chk.h" >+#include "oscam-time.h" >+#include "module-newcamd-des.h" >+#include "reader-dre-common.h" >+// from reader-viaccess.c: >+void hdSurEncPhase1_D2_0F_11(uint8_t *CWs); >+void hdSurEncPhase2_D2_0F_11(uint8_t *CWs); >+void hdSurEncPhase1_D2_13_15(uint8_t *cws); >+void hdSurEncPhase2_D2_13_15(uint8_t *cws); >+#else >+#include "cscrypt/viades.h" >+#include "via3surenc.h" >+#include "dre2overcrypt.h" >+#endif >+ >+#include "module-emulator-osemu.h" >+#include "module-emulator-stream.h" >+ >+// Version info >+uint32_t GetOSemuVersion(void) >+{ >+ return atoi("$Version: 766 $"+10); >+} >+ >+/* >+ * Key DB >+ * >+ * The Emu reader gets keys from the OSCcam-Emu binary and the "SoftCam.Key" file. >+ * >+ * The keys are stored in structures of type "KeyDataContainer", one per CAS. Each >+ * container points to a dynamically allocated array of type "KeyData", which holds >+ * the actual keys. The array initially holds up to 64 keys (64 * KeyData), and it >+ * is expanded by 16 every time it's filled with keys. The "KeyDataContainer" also >+ * includes info about the number of keys it contains ("KeyCount") and the maximum >+ * number of keys it can store ("KeyMax"). >+ * >+ * The "KeyData" structure on the other hand, stores the actual key information, >+ * including the "identifier", "provider", "keyName", "key" and "keyLength". There >+ * is also a "nextKey" pointer to a similar "KeyData" structure which is only used >+ * for Irdeto multiple keys, in a linked list style structure. For all other CAS, >+ * the "nextKey" is a "NULL" pointer. >+ * >+ * For storing keys, the "SetKey" function is used. Duplicate keys are not allowed. >+ * When storing a key that is already present in the database, its "key" value is >+ * updated with the new one. For reading keys from the database, the "FindKey" >+ * function is used. To delete all keys in a container, the "DeleteKeysInContainer" >+ * function can be called. >+*/ >+ >+static char *emu_keyfile_path = NULL; >+ >+void set_emu_keyfile_path(const char *path) >+{ >+ if(emu_keyfile_path != NULL) { >+ free(emu_keyfile_path); >+ } >+ emu_keyfile_path = (char*)malloc(strlen(path)+1); >+ if(emu_keyfile_path == NULL) { >+ return; >+ } >+ memcpy(emu_keyfile_path, path, strlen(path)); >+ emu_keyfile_path[strlen(path)] = 0; >+} >+ >+int32_t CharToBin(uint8_t *out, const char *in, uint32_t inLen) >+{ >+ uint32_t i, tmp; >+ for(i=0; i<inLen/2; i++) { >+ if(sscanf(in + i*2, "%02X", &tmp) != 1) { >+ return 0; >+ } >+ out[i] = (uint8_t)tmp; >+ } >+ return 1; >+} >+ >+KeyDataContainer CwKeys = { NULL, 0, 0 }; >+KeyDataContainer ViKeys = { NULL, 0, 0 }; >+KeyDataContainer NagraKeys = { NULL, 0, 0 }; >+KeyDataContainer IrdetoKeys = { NULL, 0, 0 }; >+KeyDataContainer NDSKeys = { NULL, 0, 0 }; >+KeyDataContainer BissKeys = { NULL, 0, 0 }; >+KeyDataContainer PowervuKeys = { NULL, 0, 0 }; >+KeyDataContainer DreKeys = { NULL, 0, 0 }; >+KeyDataContainer TandbergKeys = { NULL, 0, 0 }; >+ >+static KeyDataContainer *GetKeyContainer(char identifier) >+{ >+ switch(identifier) { >+ case 'W': >+ return &CwKeys; >+ case 'V': >+ return &ViKeys; >+ case 'N': >+ return &NagraKeys; >+ case 'I': >+ return &IrdetoKeys; >+ case 'S': >+ return &NDSKeys; >+ case 'F': >+ return &BissKeys; >+ case 'P': >+ return &PowervuKeys; >+ case 'D': >+ return &DreKeys; >+ case 'T': >+ return &TandbergKeys; >+ default: >+ return NULL; >+ } >+} >+ >+static void Date2Str(char *dateStr, uint8_t len, int8_t offset, uint8_t format) >+{ >+ // Creates a formatted date string for use in various functions. >+ // A positive or negative time offset (in hours) can be set as well >+ // as the format of the output string. >+ >+ time_t rawtime; >+ struct tm timeinfo; >+ >+ time(&rawtime); >+ rawtime += (time_t) offset * 60 * 60; // Add a positive or negative offset >+ localtime_r(&rawtime, &timeinfo); >+ >+ switch (format) >+ { >+ case 1: // Use in WriteKeyToFile() >+ strftime(dateStr, len, "%c", &timeinfo); >+ break; >+ >+ case 2: // Used in BissAnnotate() >+ strftime(dateStr, len, "%F @ %R", &timeinfo); >+ break; >+ >+ case 3: // Used in SetKey(), BissAnnotate() >+ strftime(dateStr, len, "%y%m%d%H", &timeinfo); >+ break; >+ } >+} >+ >+static void WriteKeyToFile(char identifier, uint32_t provider, const char *keyName, uint8_t *key, uint32_t keyLength, char* comment) >+{ >+ char line[1200], dateText[100]; >+ uint32_t pathLength; >+ struct dirent *pDirent; >+ DIR *pDir; >+ char *path, *filepath, filename[EMU_KEY_FILENAME_MAX_LEN+1], *keyValue; >+ FILE *file = NULL; >+ uint8_t fileNameLen = strlen(EMU_KEY_FILENAME); >+ >+ pathLength = strlen(emu_keyfile_path); >+ path = (char*)malloc(pathLength+1); >+ if(path == NULL) { >+ return; >+ } >+ strncpy(path, emu_keyfile_path, pathLength+1); >+ >+ pathLength = strlen(path); >+ if(pathLength >= fileNameLen && strcasecmp(path+pathLength-fileNameLen, EMU_KEY_FILENAME) == 0) { >+ // cut file name >+ path[pathLength-fileNameLen] = '\0'; >+ } >+ >+ pathLength = strlen(path); >+ if(path[pathLength-1] == '/' || path[pathLength-1] == '\\') { >+ // cut trailing / >+ path[pathLength-1] = '\0'; >+ } >+ >+ pDir = opendir(path); >+ if (pDir == NULL) { >+ cs_log("Cannot open key file path: %s", path); >+ free(path); >+ return; >+ } >+ >+ while((pDirent = readdir(pDir)) != NULL) { >+ if(strcasecmp(pDirent->d_name, EMU_KEY_FILENAME) == 0) { >+ strncpy(filename, pDirent->d_name, sizeof(filename)); >+ break; >+ } >+ } >+ closedir(pDir); >+ >+ if(pDirent == NULL) { >+ strncpy(filename, EMU_KEY_FILENAME, sizeof(filename)); >+ } >+ >+ pathLength = strlen(path)+1+strlen(filename)+1; >+ filepath = (char*)malloc(pathLength); >+ if(filepath == NULL) { >+ free(path); >+ return; >+ } >+ snprintf(filepath, pathLength, "%s/%s", path, filename); >+ free(path); >+ >+ cs_log("Writing key file: %s", filepath); >+ >+ file = fopen(filepath, "a"); >+ free(filepath); >+ if(file == NULL) { >+ return; >+ } >+ >+ Date2Str(dateText, sizeof(dateText), 0, 1); >+ >+ keyValue = (char*)malloc((keyLength*2)+1); >+ if(keyValue == NULL) { >+ fclose(file); >+ return; >+ } >+ cs_hexdump(0, key, keyLength, keyValue, (keyLength*2)+1); >+ >+ if(comment) >+ { >+ snprintf(line, sizeof(line), "\n%c %.4X %s %s ; added by OSEmu %s %s\n", identifier, provider, keyName, keyValue, dateText, comment); >+ } >+ else >+ { >+ snprintf(line, sizeof(line), "\n%c %.4X %s %s ; added by OSEmu %s\n", identifier, provider, keyName, keyValue, dateText); >+ } >+ >+ cs_log("Key written: %c %.4X %s %s", identifier, provider, keyName, keyValue); >+ >+ free(keyValue); >+ >+ fwrite(line, strlen(line), 1, file); >+ fclose(file); >+} >+ >+int32_t SetKey(char identifier, uint32_t provider, char *keyName, uint8_t *orgKey, uint32_t keyLength, >+ uint8_t writeKey, char *comment, struct s_reader *rdr) >+{ >+ uint32_t i, j; >+ uint8_t *tmpKey = NULL; >+ KeyDataContainer *KeyDB; >+ KeyData *tmpKeyData, *newKeyData; >+ identifier = (char)toupper((int)identifier); >+ >+ KeyDB = GetKeyContainer(identifier); >+ if(KeyDB == NULL) { >+ return 0; >+ } >+ >+ keyName = strtoupper(keyName); >+ >+ if (identifier == 'F') // Prepare BISS keys before saving to the db >+ { >+ // Convert legacy BISS "00" & "01" keynames >+ if (0 == strcmp(keyName, "00") || 0 == strcmp(keyName, "01")) >+ { >+ keyName = "00000000"; >+ } >+ >+ // All keyNames should have a length of 8 after converting >+ if (strlen(keyName) != 8) >+ { >+ cs_log("WARNING: Wrong key format in %s: F %08X %s", EMU_KEY_FILENAME, provider, keyName); >+ return 0; >+ } >+ >+ // Verify date-coded keyName (if enabled), ignoring old (expired) keys >+ if (rdr->emu_datecodedenabled) >+ { >+ char timeStr[9]; >+ Date2Str(timeStr, sizeof(timeStr), 0, 3); >+ >+ // Reject old date-coded keys, but allow our "00000000" evergreen label >+ if (strcmp("00000000", keyName) != 0 && strcmp(timeStr, keyName) >= 0) >+ { >+ return 0; >+ } >+ } >+ } >+ >+ // fix checksum for BISS keys with a length of 6 >+ if (identifier == 'F' && keyLength == 6) >+ { >+ tmpKey = (uint8_t*)malloc(8*sizeof(uint8_t)); >+ if(tmpKey == NULL) { >+ return 0; >+ } >+ >+ tmpKey[0] = orgKey[0]; >+ tmpKey[1] = orgKey[1]; >+ tmpKey[2] = orgKey[2]; >+ tmpKey[3] = ((orgKey[0] + orgKey[1] + orgKey[2]) & 0xff); >+ tmpKey[4] = orgKey[3]; >+ tmpKey[5] = orgKey[4]; >+ tmpKey[6] = orgKey[5]; >+ tmpKey[7] = ((orgKey[3] + orgKey[4] + orgKey[5]) & 0xff); >+ >+ keyLength = 8; >+ } >+ else // All keys with a length of 8, including BISS >+ { >+ tmpKey = (uint8_t*)malloc(keyLength*sizeof(uint8_t)); >+ if(tmpKey == NULL) { >+ return 0; >+ } >+ >+ memcpy(tmpKey, orgKey, keyLength); >+ } >+ >+ // fix patched mgcamd format for Irdeto >+ if(identifier == 'I' && provider < 0xFFFF) { >+ provider = provider<<8; >+ } >+ >+ // key already exists on db, update its value >+ for(i=0; i<KeyDB->keyCount; i++) { >+ >+ if(KeyDB->EmuKeys[i].provider != provider) { >+ continue; >+ } >+ >+ // Don't match keyName (i.e. expiration date) for BISS >+ if(identifier != 'F' && strcmp(KeyDB->EmuKeys[i].keyName, keyName)) { >+ continue; >+ } >+ >+ // allow multiple keys for Irdeto >+ if(identifier == 'I') >+ { >+ // reject duplicates >+ tmpKeyData = &KeyDB->EmuKeys[i]; >+ do { >+ if(memcmp(tmpKeyData->key, tmpKey, tmpKeyData->keyLength < keyLength ? tmpKeyData->keyLength : keyLength) == 0) { >+ free(tmpKey); >+ return 0; >+ } >+ tmpKeyData = tmpKeyData->nextKey; >+ } >+ while(tmpKeyData != NULL); >+ >+ // add new key >+ newKeyData = (KeyData*)malloc(sizeof(KeyData)); >+ if(newKeyData == NULL) { >+ free(tmpKey); >+ return 0; >+ } >+ newKeyData->identifier = identifier; >+ newKeyData->provider = provider; >+ if(strlen(keyName) < EMU_MAX_CHAR_KEYNAME) { >+ strncpy(newKeyData->keyName, keyName, EMU_MAX_CHAR_KEYNAME); >+ } >+ else { >+ memcpy(newKeyData->keyName, keyName, EMU_MAX_CHAR_KEYNAME); >+ } >+ newKeyData->keyName[EMU_MAX_CHAR_KEYNAME-1] = 0; >+ newKeyData->key = tmpKey; >+ newKeyData->keyLength = keyLength; >+ newKeyData->nextKey = NULL; >+ >+ tmpKeyData = &KeyDB->EmuKeys[i]; >+ j = 0; >+ while(tmpKeyData->nextKey != NULL) { >+ if(j == 0xFE) >+ { >+ break; >+ } >+ tmpKeyData = tmpKeyData->nextKey; >+ j++; >+ } >+ if(tmpKeyData->nextKey) >+ { >+ NULLFREE(tmpKeyData->nextKey->key); >+ NULLFREE(tmpKeyData->nextKey); >+ } >+ tmpKeyData->nextKey = newKeyData; >+ >+ if(writeKey) { >+ WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); >+ } >+ } >+ else // identifier != 'I' >+ { >+ free(KeyDB->EmuKeys[i].key); >+ KeyDB->EmuKeys[i].key = tmpKey; >+ KeyDB->EmuKeys[i].keyLength = keyLength; >+ >+ if (identifier == 'F') // Update keyName (i.e. expiration date) for BISS >+ { >+ strncpy(KeyDB->EmuKeys[i].keyName, keyName, EMU_MAX_CHAR_KEYNAME); >+ } >+ >+ if(writeKey) { >+ WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); >+ } >+ } >+ >+ return 1; >+ } >+ >+ // key does not exist on db >+ if(KeyDB->keyCount+1 > KeyDB->keyMax) >+ { >+ if(KeyDB->EmuKeys == NULL) // db is empty >+ { >+ KeyDB->EmuKeys = (KeyData*)malloc(sizeof(KeyData)*(KeyDB->keyMax+64)); >+ if(KeyDB->EmuKeys == NULL) { >+ free(tmpKey); >+ return 0; >+ } >+ KeyDB->keyMax+=64; >+ } >+ else // db is full, expand it >+ { >+ tmpKeyData = (KeyData*)realloc(KeyDB->EmuKeys, sizeof(KeyData)*(KeyDB->keyMax+16)); >+ if(tmpKeyData == NULL) { >+ free(tmpKey); >+ return 0; >+ } >+ KeyDB->EmuKeys = tmpKeyData; >+ KeyDB->keyMax+=16; >+ } >+ } >+ >+ KeyDB->EmuKeys[KeyDB->keyCount].identifier = identifier; >+ KeyDB->EmuKeys[KeyDB->keyCount].provider = provider; >+ if(strlen(keyName) < EMU_MAX_CHAR_KEYNAME) { >+ strncpy(KeyDB->EmuKeys[KeyDB->keyCount].keyName, keyName, EMU_MAX_CHAR_KEYNAME); >+ } >+ else { >+ memcpy(KeyDB->EmuKeys[KeyDB->keyCount].keyName, keyName, EMU_MAX_CHAR_KEYNAME); >+ } >+ KeyDB->EmuKeys[KeyDB->keyCount].keyName[EMU_MAX_CHAR_KEYNAME-1] = 0; >+ KeyDB->EmuKeys[KeyDB->keyCount].key = tmpKey; >+ KeyDB->EmuKeys[KeyDB->keyCount].keyLength = keyLength; >+ KeyDB->EmuKeys[KeyDB->keyCount].nextKey = NULL; >+ KeyDB->keyCount++; >+ >+ if(writeKey) { >+ WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); >+ } >+ >+ return 1; >+} >+ >+int32_t FindKey(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, uint8_t *key, >+ uint32_t maxKeyLength, uint8_t isCriticalKey, uint32_t keyRef, uint8_t matchLength, uint32_t *getProvider) >+{ >+ uint32_t i; >+ uint16_t j; >+ uint8_t provider_matching_key_count = 0; >+ KeyDataContainer *KeyDB; >+ KeyData *tmpKeyData; >+ >+ KeyDB = GetKeyContainer(identifier); >+ if(KeyDB == NULL) { >+ return 0; >+ } >+ >+ for(i=0; i<KeyDB->keyCount; i++) { >+ >+ if((KeyDB->EmuKeys[i].provider & ~providerIgnoreMask) != provider) { >+ continue; >+ } >+ >+ // Don't match keyName (i.e. expiration date) for BISS >+ if(identifier != 'F' && strcmp(KeyDB->EmuKeys[i].keyName, keyName)) { >+ continue; >+ } >+ >+ //matchLength cannot be used when multiple keys are allowed >+ //for a single provider/keyName combination. >+ //Currently this is only the case for Irdeto keys. >+ if(matchLength && KeyDB->EmuKeys[i].keyLength != maxKeyLength) { >+ continue; >+ } >+ >+ if(providerIgnoreMask) { >+ if(provider_matching_key_count < keyRef) { >+ provider_matching_key_count++; >+ continue; >+ } >+ else { >+ keyRef = 0; >+ } >+ } >+ >+ tmpKeyData = &KeyDB->EmuKeys[i]; >+ >+ j = 0; >+ while(j<keyRef && tmpKeyData->nextKey != NULL) { >+ j++; >+ tmpKeyData = tmpKeyData->nextKey; >+ } >+ >+ if(j == keyRef) { >+ memcpy(key, tmpKeyData->key, tmpKeyData->keyLength > maxKeyLength ? maxKeyLength : tmpKeyData->keyLength); >+ if(tmpKeyData->keyLength < maxKeyLength) { >+ memset(key+tmpKeyData->keyLength, 0, maxKeyLength - tmpKeyData->keyLength); >+ } >+ >+ if (identifier == 'F') // Report the keyName of found key back to BissGetKey() >+ { >+ strncpy(keyName, tmpKeyData->keyName, EMU_MAX_CHAR_KEYNAME); >+ } >+ >+ if(getProvider != NULL) { >+ (*getProvider) = tmpKeyData->provider; >+ } >+ return 1; >+ } >+ else { >+ break; >+ } >+ } >+ >+ if (isCriticalKey) >+ { >+ cs_log("Key not found: %c %X %s", identifier, provider, keyName); >+ } >+ >+ return 0; >+} >+ >+static int32_t UpdateKey(char identifier, uint32_t provider, char *keyName, uint8_t *key, uint32_t keyLength, uint8_t writeKey, char *comment) >+{ >+ uint32_t keyRef = 0; >+ uint8_t *tmpKey = (uint8_t*)malloc(sizeof(uint8_t)*keyLength); >+ if(tmpKey == NULL) >+ { >+ return 0; >+ } >+ >+ while(FindKey(identifier, provider, 0, keyName, tmpKey, keyLength, 0, keyRef, 0, NULL)) >+ { >+ if(memcmp(tmpKey, key, keyLength) == 0) >+ { >+ free(tmpKey); >+ return 0; >+ } >+ >+ keyRef++; >+ } >+ >+ free(tmpKey); >+ return SetKey(identifier, provider, keyName, key, keyLength, writeKey, comment, NULL); >+} >+ >+static int32_t UpdateKeysByProviderMask(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, uint8_t *key, >+ uint32_t keyLength, char *comment) >+{ >+ int32_t ret = 0; >+ uint32_t foundProvider = 0; >+ uint32_t keyRef = 0; >+ uint8_t *tmpKey = (uint8_t*)malloc(sizeof(uint8_t)*keyLength); >+ if(tmpKey == NULL) >+ { >+ return 0; >+ } >+ >+ while(FindKey(identifier, (provider & ~providerIgnoreMask), providerIgnoreMask, keyName, tmpKey, keyLength, 0, keyRef, 0, &foundProvider)) >+ { >+ keyRef++; >+ >+ if(memcmp(tmpKey, key, keyLength) == 0) >+ { >+ continue; >+ } >+ >+ if(SetKey(identifier, foundProvider, keyName, key, keyLength, 1, comment, NULL)) >+ { >+ ret = 1; >+ } >+ } >+ >+ free(tmpKey); >+ return ret; >+} >+ >+int32_t DeleteKeysInContainer(char identifier) >+{ >+ // Deletes all keys stored in memory for the specified identifier, >+ // but keeps the container itself, re-initialized at { NULL, 0, 0 }. >+ // Returns the count of deleted keys. >+ >+ uint32_t oldKeyCount, i; >+ KeyData *tmpKeyData; >+ KeyDataContainer *KeyDB = GetKeyContainer(identifier); >+ >+ if (KeyDB == NULL || KeyDB->EmuKeys == NULL || KeyDB->keyCount == 0) >+ { >+ return 0; >+ } >+ >+ for (i = 0; i < KeyDB->keyCount; i++) >+ { >+ // For Irdeto multiple keys only (linked list structure) >+ while (KeyDB->EmuKeys[i].nextKey != NULL) >+ { >+ tmpKeyData = KeyDB->EmuKeys[i].nextKey; >+ KeyDB->EmuKeys[i].nextKey = KeyDB->EmuKeys[i].nextKey->nextKey; >+ free(tmpKeyData->key); // Free key >+ free(tmpKeyData); // Free KeyData >+ } >+ >+ // For single keys (all identifiers, including Irdeto) >+ free(KeyDB->EmuKeys[i].key); // Free key >+ } >+ >+ // Free the KeyData array >+ NULLFREE(KeyDB->EmuKeys); >+ oldKeyCount = KeyDB->keyCount; >+ KeyDB->keyCount = 0; >+ KeyDB->keyMax = 0; >+ >+ return oldKeyCount; >+} >+ >+void clear_emu_keydata(void) >+{ >+ uint32_t total = 0; >+ >+ total = CwKeys.keyCount; >+ total += ViKeys.keyCount; >+ total += NagraKeys.keyCount; >+ total += IrdetoKeys.keyCount; >+ total += NDSKeys.keyCount; >+ total += BissKeys.keyCount; >+ total += PowervuKeys.keyCount; >+ total += DreKeys.keyCount; >+ total += TandbergKeys.keyCount; >+ >+ if (total != 0) >+ { >+ cs_log("Freeing keys in memory: W:%d V:%d N:%d I:%d S:%d F:%d P:%d D:%d T:%d", \ >+ CwKeys.keyCount, ViKeys.keyCount, NagraKeys.keyCount, \ >+ IrdetoKeys.keyCount, NDSKeys.keyCount, BissKeys.keyCount, \ >+ PowervuKeys.keyCount, DreKeys.keyCount, TandbergKeys.keyCount); >+ >+ DeleteKeysInContainer('W'); >+ DeleteKeysInContainer('V'); >+ DeleteKeysInContainer('N'); >+ DeleteKeysInContainer('I'); >+ DeleteKeysInContainer('S'); >+ DeleteKeysInContainer('F'); >+ DeleteKeysInContainer('P'); >+ DeleteKeysInContainer('D'); >+ DeleteKeysInContainer('T'); >+ } >+} >+ >+uint8_t read_emu_keyfile(struct s_reader *rdr, const char *opath) >+{ >+ char line[1200], keyName[EMU_MAX_CHAR_KEYNAME], keyString[1026]; >+ uint32_t pathLength, provider, keyLength; >+ uint8_t *key; >+ struct dirent *pDirent; >+ DIR *pDir; >+ char *path, *filepath, filename[EMU_KEY_FILENAME_MAX_LEN+1]; >+ FILE *file = NULL; >+ char identifier; >+ uint8_t fileNameLen = strlen(EMU_KEY_FILENAME); >+ >+ pathLength = strlen(opath); >+ path = (char*)malloc(pathLength+1); >+ if(path == NULL) { >+ return 0; >+ } >+ strncpy(path, opath, pathLength+1); >+ >+ pathLength = strlen(path); >+ if(pathLength >= fileNameLen && strcasecmp(path+pathLength-fileNameLen, EMU_KEY_FILENAME) == 0) { >+ // cut file name >+ path[pathLength-fileNameLen] = '\0'; >+ } >+ >+ pathLength = strlen(path); >+ if(path[pathLength-1] == '/' || path[pathLength-1] == '\\') { >+ // cut trailing / >+ path[pathLength-1] = '\0'; >+ } >+ >+ pDir = opendir(path); >+ if (pDir == NULL) { >+ cs_log("Cannot open key file path: %s", path); >+ free(path); >+ return 0; >+ } >+ >+ while((pDirent = readdir(pDir)) != NULL) { >+ if(strcasecmp(pDirent->d_name, EMU_KEY_FILENAME) == 0) { >+ strncpy(filename, pDirent->d_name, sizeof(filename)); >+ break; >+ } >+ } >+ closedir(pDir); >+ >+ if(pDirent == NULL) { >+ cs_log("Key file not found in: %s", path); >+ free(path); >+ return 0; >+ } >+ >+ pathLength = strlen(path)+1+strlen(filename)+1; >+ filepath = (char*)malloc(pathLength); >+ if(filepath == NULL) { >+ free(path); >+ return 0; >+ } >+ snprintf(filepath, pathLength, "%s/%s", path, filename); >+ free(path); >+ >+ cs_log("Reading key file: %s", filepath); >+ >+ file = fopen(filepath, "r"); >+ free(filepath); >+ if(file == NULL) { >+ return 0; >+ } >+ >+ set_emu_keyfile_path(opath); >+ >+ while(fgets(line, 1200, file)) { >+ if(sscanf(line, "%c %8x %11s %1024s", &identifier, &provider, keyName, keyString) != 4) { >+ continue; >+ } >+ >+ keyLength = strlen(keyString)/2; >+ key = (uint8_t*)malloc(keyLength); >+ if(key == NULL) { >+ fclose(file); >+ return 0; >+ } >+ >+ if (CharToBin(key, keyString, strlen(keyString))) // Conversion OK >+ { >+ SetKey(identifier, provider, keyName, key, keyLength, 0, NULL, rdr); >+ } >+ else // Non-hex characters in keyString >+ { >+ if ((identifier != ';' && identifier != '#' && // Skip warning for comments, etc. >+ identifier != '=' && identifier != '-' && >+ identifier != ' ') && >+ !(identifier == 'F' && 0 == strncmp(keyString, "XXXXXXXXXXXX", 12))) // Skip warning for BISS 'Example key' lines >+ { >+ // Alert user regarding faulty line >+ cs_log("WARNING: non-hex value in %s at %c %04X %s %s", EMU_KEY_FILENAME, identifier, provider, keyName, keyString); >+ } >+ } >+ free(key); >+ } >+ fclose(file); >+ >+ return 1; >+} >+ >+#if !defined(__APPLE__) && !defined(__ANDROID__) >+extern uint8_t SoftCamKey_Data[] __asm__("_binary_SoftCam_Key_start"); >+extern uint8_t SoftCamKey_DataEnd[] __asm__("_binary_SoftCam_Key_end"); >+ >+void read_emu_keymemory(struct s_reader *rdr) >+{ >+ char *keyData, *line, *saveptr, keyName[EMU_MAX_CHAR_KEYNAME], keyString[1026]; >+ uint32_t provider, keyLength; >+ uint8_t *key; >+ char identifier; >+ >+ keyData = (char*)malloc(SoftCamKey_DataEnd-SoftCamKey_Data+1); >+ if(keyData == NULL) { >+ return; >+ } >+ memcpy(keyData, SoftCamKey_Data, SoftCamKey_DataEnd-SoftCamKey_Data); >+ keyData[SoftCamKey_DataEnd-SoftCamKey_Data] = 0x00; >+ >+ line = strtok_r(keyData, "\n", &saveptr); >+ while(line != NULL) { >+ if(sscanf(line, "%c %8x %11s %1024s", &identifier, &provider, keyName, keyString) != 4) { >+ line = strtok_r(NULL, "\n", &saveptr); >+ continue; >+ } >+ keyLength = strlen(keyString)/2; >+ key = (uint8_t*)malloc(keyLength); >+ if(key == NULL) { >+ free(keyData); >+ return; >+ } >+ >+ if (CharToBin(key, keyString, strlen(keyString))) // Conversion OK >+ { >+ SetKey(identifier, provider, keyName, key, keyLength, 0, NULL, rdr); >+ } >+ else // Non-hex characters in keyString >+ { >+ if ((identifier != ';' && identifier != '#' && // Skip warning for comments, etc. >+ identifier != '=' && identifier != '-' && >+ identifier != ' ') && >+ !(identifier == 'F' && 0 == strncmp(keyString, "XXXXXXXXXXXX", 12))) // Skip warning for BISS 'Example key' lines >+ { >+ // Alert user regarding faulty line >+ cs_log("WARNING: non-hex value in internal keyfile at %c %04X %s %s", identifier, provider, keyName, keyString); >+ } >+ } >+ free(key); >+ line = strtok_r(NULL, "\n", &saveptr); >+ } >+ free(keyData); >+} >+#endif >+ >+void read_emu_eebin(const char *path, const char *name) >+{ >+ char tmp[256]; >+ FILE *file = NULL; >+ uint8_t i, buffer[64][32], dummy[2][32]; >+ uint32_t prvid; >+ >+ // Set path >+ if (path != NULL) >+ { >+ snprintf(tmp, 256, "%s%s", path, name); >+ } >+ else // No path set, use SoftCam.Keys's path >+ { >+ snprintf(tmp, 256, "%s%s", emu_keyfile_path, name); >+ } >+ >+ // Read file to buffer >+ if ((file = fopen(tmp, "rb")) != NULL) >+ { >+ cs_log("Reading key file: %s", tmp); >+ >+ if (fread(buffer, 1, sizeof(buffer), file) != sizeof(buffer)) >+ { >+ cs_log("Corrupt key file: %s", tmp); >+ fclose(file); >+ return; >+ } >+ >+ fclose(file); >+ } >+ else >+ { >+ if (path != NULL) >+ { >+ cs_log("Cannot open key file: %s", tmp); >+ } >+ >+ return; >+ } >+ >+ // Save keys to db >+ memset(dummy[0], 0x00, 32); >+ memset(dummy[1], 0xFF, 32); >+ prvid = (strncmp(name, "ee36.bin", 9) == 0) ? 0x4AE111 : 0x4AE114; >+ >+ for (i = 0; i < 32; i++) // Set "3B" type keys >+ { >+ // Write keys if they have "real" values >+ if ((memcmp(buffer[i], dummy[0], 32) !=0) && (memcmp(buffer[i], dummy[1], 32) != 0)) >+ { >+ snprintf(tmp, 5, "3B%02X", i); >+ SetKey('D', prvid, tmp, buffer[i], 32, 0, NULL, NULL); >+ } >+ } >+ >+ for (i = 0; i < 32; i++) // Set "56" type keys >+ { >+ // Write keys if they have "real" values >+ if ((memcmp(buffer[32 + i], dummy[0], 32) !=0) && (memcmp(buffer[32 + i], dummy[1], 32) != 0)) >+ { >+ snprintf(tmp, 5, "56%02X", i); >+ SetKey('D', prvid, tmp, buffer[32 + i], 32, 0, NULL, NULL); >+ } >+ } >+} >+ >+void read_emu_deskey(uint8_t *dreOverKey, uint8_t len) >+{ >+ uint8_t i; >+ >+ if (len == 128) >+ { >+ cs_log("Reading DreCrypt overcrypt (ADEC) key"); >+ >+ for (i = 0; i < 16; i++) >+ { >+ SetKey('D', i, "OVER", dreOverKey + (i * 8), 8, 0, NULL, NULL); >+ } >+ } >+ else if ((len != 0 && len < 128) || len > 128) >+ { >+ cs_log("DreCrypt overcrypt (ADEC) key has wrong length"); >+ } >+} >+ >+// Shared functions >+ >+static inline uint16_t GetEcmLen(const uint8_t *ecm) >+{ >+ return (((ecm[1] & 0x0f)<< 8) | ecm[2]) +3; >+} >+ >+static void ReverseMem(uint8_t *in, int32_t len) >+{ >+ uint8_t temp; >+ int32_t i; >+ for(i = 0; i < (len / 2); i++) { >+ temp = in[i]; >+ in[i] = in[len - i - 1]; >+ in[len - i - 1] = temp; >+ } >+} >+ >+static void ReverseMemInOut(uint8_t *out, const uint8_t *in, int32_t n) >+{ >+ if(n>0) { >+ out+=n; >+ do { >+ *(--out)=*(in++); >+ } >+ while(--n); >+ } >+} >+ >+static int8_t EmuRSAInput(BIGNUM *d, const uint8_t *in, int32_t n, int8_t le) >+{ >+ int8_t result = 0; >+ >+ if(le) { >+ uint8_t *tmp = (uint8_t *)malloc(sizeof(uint8_t)*n); >+ if(tmp == NULL) { >+ return 0; >+ } >+ ReverseMemInOut(tmp,in,n); >+ result = BN_bin2bn(tmp,n,d)!=0; >+ free(tmp); >+ } >+ else { >+ result = BN_bin2bn(in,n,d)!=0; >+ } >+ return result; >+} >+ >+static int32_t EmuRSAOutput(uint8_t *out, int32_t n, BIGNUM *r, int8_t le) >+{ >+ int32_t s = BN_num_bytes(r); >+ if(s>n) { >+ uint8_t *buff = (uint8_t *)malloc(sizeof(uint8_t)*s); >+ if(buff == NULL) { >+ return 0; >+ } >+ BN_bn2bin(r,buff); >+ memcpy(out,buff+s-n,n); >+ free(buff); >+ } >+ else if(s<n) { >+ int32_t l=n-s; >+ memset(out,0,l); >+ BN_bn2bin(r,out+l); >+ } >+ else { >+ BN_bn2bin(r,out); >+ } >+ if(le) { >+ ReverseMem(out,n); >+ } >+ return s; >+} >+ >+static int32_t EmuRSA(uint8_t *out, const uint8_t *in, int32_t n, BIGNUM *exp, BIGNUM *mod, int8_t le) >+{ >+ BN_CTX *ctx; >+ BIGNUM *r, *d; >+ int32_t result = 0; >+ >+ ctx = BN_CTX_new(); >+ r = BN_new(); >+ d = BN_new(); >+ >+ if(EmuRSAInput(d,in,n,le) && BN_mod_exp(r,d,exp,mod,ctx)) { >+ result = EmuRSAOutput(out,n,r,le); >+ } >+ >+ BN_free(d); >+ BN_free(r); >+ BN_CTX_free(ctx); >+ return result; >+} >+ >+static inline void xxor(uint8_t *data, int32_t len, const uint8_t *v1, const uint8_t *v2) >+{ >+ uint32_t i; >+ switch(len) >+ { >+ case 16: >+ for(i = 8; i < 16; ++i) >+ { >+ data[i] = v1[i] ^ v2[i]; >+ } >+ case 8: >+ for(i = 4; i < 8; ++i) >+ { >+ data[i] = v1[i] ^ v2[i]; >+ } >+ case 4: >+ for(i = 0; i < 4; ++i) >+ { >+ data[i] = v1[i] ^ v2[i]; >+ } >+ break; >+ default: >+ while(len--) { *data++ = *v1++ ^ *v2++; } >+ break; >+ } >+} >+ >+static int8_t isValidDCW(uint8_t *dw) >+{ >+ if (((dw[0]+dw[1]+dw[2]) & 0xFF) != dw[3]) { >+ return 0; >+ } >+ if (((dw[4]+dw[5]+dw[6]) & 0xFF) != dw[7]) { >+ return 0; >+ } >+ if (((dw[8]+dw[9]+dw[10]) & 0xFF) != dw[11]) { >+ return 0; >+ } >+ if (((dw[12]+dw[13]+dw[14]) & 0xFF) != dw[15]) { >+ return 0; >+ } >+ return 1; >+} >+ >+static inline uint8_t GetBit(uint8_t byte, uint8_t bitnb) >+{ >+ return ((byte&(1<<bitnb)) ? 1: 0); >+} >+ >+static inline uint8_t SetBit(uint8_t val, uint8_t bitnb, uint8_t biton) >+{ >+ return (biton ? (val | (1<<bitnb)) : (val & ~(1<<bitnb))); >+} >+ >+static void ExpandDesKey(unsigned char *key) >+{ >+ uint8_t i, j, parity; >+ uint8_t tmpKey[7]; >+ >+ memcpy(tmpKey, key, 7); >+ >+ key[0] = (tmpKey[0] & 0xFE); >+ key[1] = ((tmpKey[0] << 7) | ((tmpKey[1] >> 1) & 0xFE)); >+ key[2] = ((tmpKey[1] << 6) | ((tmpKey[2] >> 2) & 0xFE)); >+ key[3] = ((tmpKey[2] << 5) | ((tmpKey[3] >> 3) & 0xFE)); >+ key[4] = ((tmpKey[3] << 4) | ((tmpKey[4] >> 4) & 0xFE)); >+ key[5] = ((tmpKey[4] << 3) | ((tmpKey[5] >> 5) & 0xFE)); >+ key[6] = ((tmpKey[5] << 2) | ((tmpKey[6] >> 6) & 0xFE)); >+ key[7] = (tmpKey[6] << 1); >+ >+ for (i = 0; i < 8; i++) >+ { >+ parity = 1; >+ for (j = 1; j < 8; j++) if ((key[i] >> j) & 0x1) { parity = ~parity & 0x01; } >+ key[i] |= parity; >+ } >+} >+ >+// Cryptoworks EMU >+static int8_t GetCwKey(uint8_t *buf,uint32_t ident, uint8_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey) >+{ >+ >+ char keyName[EMU_MAX_CHAR_KEYNAME]; >+ uint32_t tmp; >+ >+ if((ident >> 4) == 0xD02A) { >+ keyIndex &=0xFE; // map to even number key indexes >+ } >+ if((ident >> 4) == 0xD00C) { >+ ident = 0x0D00C0; // map provider C? to C0 >+ } >+ else if(keyIndex == 6 && ((ident >> 8) == 0x0D05)) { >+ ident = 0x0D0504; // always use provider 04 system key >+ } >+ >+ tmp = keyIndex; >+ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", tmp); >+ if(FindKey('W', ident, 0, keyName, buf, keyLength, isCriticalKey, 0, 0, NULL)) { >+ return 1; >+ } >+ >+ return 0; >+} >+ >+static const uint8_t cw_sbox1[64] = { >+ 0xD8,0xD7,0x83,0x3D,0x1C,0x8A,0xF0,0xCF,0x72,0x4C,0x4D,0xF2,0xED,0x33,0x16,0xE0, >+ 0x8F,0x28,0x7C,0x82,0x62,0x37,0xAF,0x59,0xB7,0xE0,0x00,0x3F,0x09,0x4D,0xF3,0x94, >+ 0x16,0xA5,0x58,0x83,0xF2,0x4F,0x67,0x30,0x49,0x72,0xBF,0xCD,0xBE,0x98,0x81,0x7F, >+ 0xA5,0xDA,0xA7,0x7F,0x89,0xC8,0x78,0xA7,0x8C,0x05,0x72,0x84,0x52,0x72,0x4D,0x38 >+}; >+static const uint8_t cw_sbox2[64] = { >+ 0xD8,0x35,0x06,0xAB,0xEC,0x40,0x79,0x34,0x17,0xFE,0xEA,0x47,0xA3,0x8F,0xD5,0x48, >+ 0x0A,0xBC,0xD5,0x40,0x23,0xD7,0x9F,0xBB,0x7C,0x81,0xA1,0x7A,0x14,0x69,0x6A,0x96, >+ 0x47,0xDA,0x7B,0xE8,0xA1,0xBF,0x98,0x46,0xB8,0x41,0x45,0x9E,0x5E,0x20,0xB2,0x35, >+ 0xE4,0x2F,0x9A,0xB5,0xDE,0x01,0x65,0xF8,0x0F,0xB2,0xD2,0x45,0x21,0x4E,0x2D,0xDB >+}; >+static const uint8_t cw_sbox3[64] = { >+ 0xDB,0x59,0xF4,0xEA,0x95,0x8E,0x25,0xD5,0x26,0xF2,0xDA,0x1A,0x4B,0xA8,0x08,0x25, >+ 0x46,0x16,0x6B,0xBF,0xAB,0xE0,0xD4,0x1B,0x89,0x05,0x34,0xE5,0x74,0x7B,0xBB,0x44, >+ 0xA9,0xC6,0x18,0xBD,0xE6,0x01,0x69,0x5A,0x99,0xE0,0x87,0x61,0x56,0x35,0x76,0x8E, >+ 0xF7,0xE8,0x84,0x13,0x04,0x7B,0x9B,0xA6,0x7A,0x1F,0x6B,0x5C,0xA9,0x86,0x54,0xF9 >+}; >+static const uint8_t cw_sbox4[64] = { >+ 0xBC,0xC1,0x41,0xFE,0x42,0xFB,0x3F,0x10,0xB5,0x1C,0xA6,0xC9,0xCF,0x26,0xD1,0x3F, >+ 0x02,0x3D,0x19,0x20,0xC1,0xA8,0xBC,0xCF,0x7E,0x92,0x4B,0x67,0xBC,0x47,0x62,0xD0, >+ 0x60,0x9A,0x9E,0x45,0x79,0x21,0x89,0xA9,0xC3,0x64,0x74,0x9A,0xBC,0xDB,0x43,0x66, >+ 0xDF,0xE3,0x21,0xBE,0x1E,0x16,0x73,0x5D,0xA2,0xCD,0x8C,0x30,0x67,0x34,0x9C,0xCB >+}; >+static const uint8_t AND_bit1[8] = {0x00,0x40,0x04,0x80,0x21,0x10,0x02,0x08}; >+static const uint8_t AND_bit2[8] = {0x80,0x08,0x01,0x40,0x04,0x20,0x10,0x02}; >+static const uint8_t AND_bit3[8] = {0x82,0x40,0x01,0x10,0x00,0x20,0x04,0x08}; >+static const uint8_t AND_bit4[8] = {0x02,0x10,0x04,0x40,0x80,0x08,0x01,0x20}; >+ >+static void CW_SWAP_KEY(uint8_t *key) >+{ >+ uint8_t k[8]; >+ memcpy(k, key, 8); >+ memcpy(key, key + 8, 8); >+ memcpy(key + 8, k, 8); >+} >+ >+static void CW_SWAP_DATA(uint8_t *k) >+{ >+ uint8_t d[4]; >+ memcpy(d, k + 4, 4); >+ memcpy(k + 4 ,k ,4); >+ memcpy(k, d, 4); >+} >+ >+static void CW_DES_ROUND(uint8_t *d, uint8_t *k) >+{ >+ uint8_t aa[44] = {1,0,3,1,2,2,3,2,1,3,1,1,3,0,1,2,3,1,3,2,2,0,7,6,5,4,7,6,5,7,6,5,6,7,5,7,5,7,6,6,7,5,4,4}; >+ uint8_t bb[44] = {0x80,0x08,0x10,0x02,0x08,0x40,0x01,0x20,0x40,0x80,0x04,0x10,0x04,0x01,0x01,0x02,0x20,0x20,0x02,0x01, >+ 0x80,0x04,0x02,0x02,0x08,0x02,0x10,0x80,0x01,0x20,0x08,0x80,0x01,0x08,0x40,0x01,0x02,0x80,0x10,0x40,0x40,0x10,0x08,0x01 >+ }; >+ uint8_t ff[4] = {0x02,0x10,0x04,0x04}; >+ uint8_t l[24] = {0,2,4,6,7,5,3,1,4,5,6,7,7,6,5,4,7,4,5,6,4,7,6,5}; >+ >+ uint8_t des_td[8], i, o, n, c = 1, m = 0, r = 0, *a = aa, *b = bb, *f = ff, *p1 = l, *p2 = l+8, *p3 = l+16; >+ >+ for (m = 0; m < 2; m++) { >+ for(i = 0; i < 4; i++) { >+ des_td[*p1++] = >+ (m) ? ((d[*p2++]*2) & 0x3F) | ((d[*p3++] & 0x80) ? 0x01 : 0x00): (d[*p2++]/2) | ((d[*p3++] & 0x01) ? 0x80 : 0x00); >+ } >+ } >+ >+ for (i = 0; i < 8; i++) { >+ c = (c) ? 0 : 1; >+ r = (c) ? 6 : 7; >+ n = (i) ? i-1 : 1; >+ o = (c) ? ((k[n] & *f++) ? 1 : 0) : des_td[n]; >+ for (m = 1; m < r; m++) { >+ o = (c) ? (o*2) | ((k[*a++] & *b++) ? 0x01 : 0x00) : (o/2) | ((k[*a++] & *b++) ? 0x80 : 0x00); >+ } >+ n = (i) ? n+1 : 0; >+ des_td[n] = (c) ? des_td[n] ^ o : (o ^ des_td[n] )/4; >+ } >+ >+ for( i = 0; i < 8; i++) { >+ d[0] ^= (AND_bit1[i] & cw_sbox1[des_td[i]]); >+ d[1] ^= (AND_bit2[i] & cw_sbox2[des_td[i]]); >+ d[2] ^= (AND_bit3[i] & cw_sbox3[des_td[i]]); >+ d[3] ^= (AND_bit4[i] & cw_sbox4[des_td[i]]); >+ } >+ >+ CW_SWAP_DATA(d); >+} >+ >+static void CW_48_Key(uint8_t *inkey, uint8_t *outkey, uint8_t algotype) >+{ >+ uint8_t Round_Counter, i = 8, *key128 = inkey, *key48 = inkey + 0x10; >+ Round_Counter = 7 - (algotype & 7); >+ >+ memset(outkey, 0, 16); >+ memcpy(outkey, key48, 6); >+ >+ for( ; i > Round_Counter; i--) { >+ if (i > 1) { >+ outkey[i-2] = key128[i]; >+ } >+ } >+} >+ >+static void CW_LS_DES_KEY(uint8_t *key,uint8_t Rotate_Counter) >+{ >+ uint8_t round[] = {1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,1}; >+ uint8_t i, n; >+ uint16_t k[8]; >+ >+ n = round[Rotate_Counter]; >+ >+ for (i = 0; i < 8; i++) { >+ k[i] = key[i]; >+ } >+ >+ for (i = 1; i < n + 1; i++) { >+ k[7] = (k[7]*2) | ((k[4] & 0x008) ? 1 : 0); >+ k[6] = (k[6]*2) | ((k[7] & 0xF00) ? 1 : 0); >+ k[7] &=0xff; >+ k[5] = (k[5]*2) | ((k[6] & 0xF00) ? 1 : 0); >+ k[6] &=0xff; >+ k[4] = ((k[4]*2) | ((k[5] & 0xF00) ? 1 : 0)) & 0xFF; >+ k[5] &= 0xff; >+ k[3] = (k[3]*2) | ((k[0] & 0x008) ? 1 : 0); >+ k[2] = (k[2]*2) | ((k[3] & 0xF00) ? 1 : 0); >+ k[3] &= 0xff; >+ k[1] = (k[1]*2) | ((k[2] & 0xF00) ? 1 : 0); >+ k[2] &= 0xff; >+ k[0] = ((k[0]*2) | ((k[1] & 0xF00) ? 1 : 0)) & 0xFF; >+ k[1] &= 0xff; >+ } >+ for (i = 0; i < 8; i++) { >+ key[i] = (uint8_t) k[i]; >+ } >+} >+ >+static void CW_RS_DES_KEY(uint8_t *k, uint8_t Rotate_Counter) >+{ >+ uint8_t i,c; >+ for (i = 1; i < Rotate_Counter+1; i++) { >+ c = (k[3] & 0x10) ? 0x80 : 0; >+ k[3] /= 2; >+ if (k[2] & 1) { >+ k[3] |= 0x80; >+ } >+ k[2] /= 2; >+ if (k[1] & 1) { >+ k[2] |= 0x80; >+ } >+ k[1] /= 2; >+ if (k[0] & 1) { >+ k[1] |= 0x80; >+ } >+ k[0] /= 2; >+ k[0] |= c ; >+ c = (k[7] & 0x10) ? 0x80 : 0; >+ k[7] /= 2; >+ if (k[6] & 1) { >+ k[7] |= 0x80; >+ } >+ k[6] /= 2; >+ if (k[5] & 1) { >+ k[6] |= 0x80; >+ } >+ k[5] /= 2; >+ if (k[4] & 1) { >+ k[5] |= 0x80; >+ } >+ k[4] /= 2; >+ k[4] |= c; >+ } >+} >+ >+static void CW_RS_DES_SUBKEY(uint8_t *k, uint8_t Rotate_Counter) >+{ >+ uint8_t round[] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1}; >+ CW_RS_DES_KEY(k, round[Rotate_Counter]); >+} >+ >+static void CW_PREP_KEY(uint8_t *key ) >+{ >+ uint8_t DES_key[8],j; >+ int32_t Round_Counter = 6,i,a; >+ key[7] = 6; >+ memset(DES_key, 0 , 8); >+ do { >+ a = 7; >+ i = key[7]; >+ j = key[Round_Counter]; >+ do { >+ DES_key[i] = ( (DES_key[i] * 2) | ((j & 1) ? 1: 0) ) & 0xFF; >+ j /=2; >+ i--; >+ if (i < 0) { >+ i = 6; >+ } >+ a--; >+ } >+ while (a >= 0); >+ key[7] = i; >+ Round_Counter--; >+ } >+ while ( Round_Counter >= 0 ); >+ a = DES_key[4]; >+ DES_key[4] = DES_key[6]; >+ DES_key[6] = a; >+ DES_key[7] = (DES_key[3] * 16) & 0xFF; >+ memcpy(key,DES_key,8); >+ CW_RS_DES_KEY(key,4); >+} >+ >+static void CW_L2DES(uint8_t *data, uint8_t *key, uint8_t algo) >+{ >+ uint8_t i, k0[22], k1[22]; >+ memcpy(k0,key,22); >+ memcpy(k1,key,22); >+ CW_48_Key(k0, k1,algo); >+ CW_PREP_KEY(k1); >+ for (i = 0; i< 2; i++) { >+ CW_LS_DES_KEY( k1,15); >+ CW_DES_ROUND( data ,k1); >+ } >+} >+ >+static void CW_R2DES(uint8_t *data, uint8_t *key, uint8_t algo) >+{ >+ uint8_t i, k0[22],k1[22]; >+ memcpy(k0,key,22); >+ memcpy(k1,key,22); >+ CW_48_Key(k0, k1, algo); >+ CW_PREP_KEY(k1); >+ for (i = 0; i< 2; i++) { >+ CW_LS_DES_KEY(k1,15); >+ } >+ for (i = 0; i< 2; i++) { >+ CW_DES_ROUND( data ,k1); >+ CW_RS_DES_SUBKEY(k1,1); >+ } >+ CW_SWAP_DATA(data); >+} >+ >+static void CW_DES(uint8_t *data, uint8_t *inkey, uint8_t m) >+{ >+ uint8_t key[22], i; >+ memcpy(key, inkey + 9, 8); >+ CW_PREP_KEY( key ); >+ for (i = 16; i > 0; i--) { >+ if (m == 1) { >+ CW_LS_DES_KEY(key, (uint8_t) (i-1)); >+ } >+ CW_DES_ROUND( data ,key); >+ if (m == 0) { >+ CW_RS_DES_SUBKEY(key, (uint8_t) (i-1)); >+ } >+ } >+} >+ >+static void CW_DEC_ENC(uint8_t *d, uint8_t *k, uint8_t a,uint8_t m) >+{ >+ uint8_t n = m & 1; >+ CW_L2DES(d , k, a); >+ CW_DES (d , k, n); >+ CW_R2DES(d , k, a); >+ if (m & 2) { >+ CW_SWAP_KEY(k); >+ } >+} >+ >+static void Cryptoworks3DES(uint8_t *data, uint8_t *key) >+{ >+ uint32_t ks1[32], ks2[32]; >+ >+ des_set_key(key, ks1); >+ des_set_key(key+8, ks2); >+ >+ des(data, ks1, 0); >+ des(data, ks2, 1); >+ des(data, ks1, 0); >+} >+ >+static uint8_t CryptoworksProcessNano80(uint8_t *data, uint32_t caid, int32_t provider, uint8_t *opKey, uint8_t nanoLength, uint8_t nano80Algo) >+{ >+ int32_t i, j; >+ uint8_t key[16], desKey[16], t[8], dat1[8], dat2[8], k0D00C000[16]; >+ if(nanoLength < 11) { >+ return 0; >+ } >+ if(caid == 0x0D00 && provider != 0xA0 && !GetCwKey(k0D00C000, 0x0D00C0, 0, 16, 1)) { >+ return 0; >+ } >+ >+ if(nano80Algo > 1) { >+ return 0; >+ } >+ >+ memset(t, 0, 8); >+ memcpy(dat1, data, 8); >+ >+ if(caid == 0x0D00 && provider != 0xA0) { >+ memcpy(key, k0D00C000, 16); >+ } >+ else { >+ memcpy(key, opKey, 16); >+ } >+ Cryptoworks3DES(data, key); >+ memcpy(desKey, data, 8); >+ >+ memcpy(data, dat1, 8); >+ if(caid == 0x0D00 && provider != 0xA0) { >+ memcpy(key, &k0D00C000[8], 8); >+ memcpy(&key[8], k0D00C000, 8); >+ } >+ else { >+ memcpy(key, &opKey[8], 8); >+ memcpy(&key[8], opKey, 8); >+ } >+ Cryptoworks3DES(data, key); >+ memcpy(&desKey[8], data, 8); >+ >+ for(i=8; i+7<nanoLength; i+=8) { >+ memcpy(dat1, &data[i], 8); >+ memcpy(dat2, dat1, 8); >+ memcpy(key, desKey, 16); >+ Cryptoworks3DES(dat1, key); >+ for(j=0; j<8; j++) { >+ dat1[j] ^= t[j]; >+ } >+ memcpy(&data[i], dat1, 8); >+ memcpy(t, dat2, 8); >+ } >+ >+ return data[10] + 5; >+} >+ >+static void CryptoworksSignature(const uint8_t *data, uint32_t length, uint8_t *key, uint8_t *signature) >+{ >+ uint32_t i, sigPos; >+ int8_t algo, first; >+ >+ algo = data[0] & 7; >+ if(algo == 7) { >+ algo = 6; >+ } >+ memset(signature, 0, 8); >+ first = 1; >+ sigPos = 0; >+ for(i=0; i<length; i++) { >+ signature[sigPos] ^= data[i]; >+ sigPos++; >+ >+ if(sigPos > 7) { >+ if (first) { >+ CW_L2DES(signature, key, algo); >+ } >+ CW_DES(signature, key, 1); >+ >+ sigPos = 0; >+ first = 0; >+ } >+ } >+ if(sigPos > 0) { >+ CW_DES(signature, key, 1); >+ } >+ CW_R2DES(signature, key, algo); >+} >+ >+static void CryptoworksDecryptDes(uint8_t *data, uint8_t algo, uint8_t *key) >+{ >+ int32_t i; >+ uint8_t k[22], t[8]; >+ >+ algo &= 7; >+ if(algo<7) { >+ CW_DEC_ENC(data, key, algo, 0); >+ } >+ else { >+ memcpy(k, key, 22); >+ for(i=0; i<3; i++) { >+ CW_DEC_ENC(data, k, algo, i&1); >+ memcpy(t,k,8); >+ memcpy(k,k+8,8); >+ memcpy(k+8,t,8); >+ } >+ } >+} >+ >+static int8_t CryptoworksECM(uint32_t caid, uint8_t *ecm, uint8_t *cw) >+{ >+ uint32_t ident; >+ uint8_t keyIndex = 0, nanoLength, newEcmLength, key[22], signature[8], nano80Algo = 1; >+ int32_t provider = -1; >+ uint16_t i, j, ecmLen = GetEcmLen(ecm); >+ >+ if(ecmLen < 8) { >+ return 1; >+ } >+ if(ecm[7] != ecmLen - 8) { >+ return 1; >+ } >+ >+ memset(key, 0, 22); >+ >+ for(i = 8; i+1 < ecmLen; i += ecm[i+1] + 2) { >+ if(ecm[i] == 0x83 && i+2 < ecmLen) { >+ provider = ecm[i+2] & 0xFC; >+ keyIndex = ecm[i+2] & 3; >+ keyIndex = keyIndex ? 1 : 0; >+ } >+ else if(ecm[i] == 0x84 && i+3 < ecmLen) { >+ //nano80Provider = ecm[i+2] & 0xFC; >+ //nano80KeyIndex = ecm[i+2] & 3; >+ //nano80KeyIndex = nano80KeyIndex ? 1 : 0; >+ nano80Algo = ecm[i+3]; >+ } >+ } >+ >+ if(provider < 0) { >+ switch(caid) { >+ case 0x0D00: >+ provider = 0xC0; >+ break; >+ case 0x0D02: >+ provider = 0xA0; >+ break; >+ case 0x0D03: >+ provider = 0x04; >+ break; >+ case 0x0D05: >+ provider = 0x04; >+ break; >+ default: >+ return 1; >+ } >+ } >+ >+ ident = (caid << 8) | provider; >+ if(!GetCwKey(key, ident, keyIndex, 16, 1)) { >+ return 2; >+ } >+ if(!GetCwKey(&key[16], ident, 6, 6, 1)) { >+ return 2; >+ } >+ >+ for(i = 8; i+1 < ecmLen; i += ecm[i+1] + 2) { >+ if(ecm[i] == 0x80 && i+2+7 < ecmLen && i+2+ecm[i+1] <= ecmLen >+ && (provider == 0xA0 || provider == 0xC0 || provider == 0xC4 || provider == 0xC8)) { >+ nanoLength = ecm[i+1]; >+ newEcmLength = CryptoworksProcessNano80(ecm+i+2, caid, provider, key, nanoLength, nano80Algo); >+ if(newEcmLength == 0 || newEcmLength > ecmLen-(i+2+3)) { >+ return 1; >+ } >+ ecm[i+2+3] = 0x81; >+ ecm[i+2+4] = 0x70; >+ ecm[i+2+5] = newEcmLength; >+ ecm[i+2+6] = 0x81; >+ ecm[i+2+7] = 0xFF; >+ return CryptoworksECM(caid, ecm+i+2+3, cw); >+ } >+ } >+ >+ if(ecmLen - 15 < 1) { >+ return 1; >+ } >+ CryptoworksSignature(ecm + 5, ecmLen - 15, key, signature); >+ for(i = 8; i+1 < ecmLen; i += ecm[i+1]+2) { >+ switch(ecm[i]) { >+ case 0xDA: >+ case 0xDB: >+ case 0xDC: >+ if(i+2+ecm[i+1] > ecmLen) { >+ break; >+ } >+ for(j=0; j+7<ecm[i+1]; j+=8) { >+ CryptoworksDecryptDes(&ecm[i+2+j], ecm[5], key); >+ } >+ break; >+ case 0xDF: >+ if(i+2+8 > ecmLen) { >+ break; >+ } >+ if(memcmp(&ecm[i+2], signature, 8)) { >+ return 6; >+ } >+ break; >+ } >+ } >+ >+ for(i = 8; i+1 < ecmLen; i += ecm[i+1]+2) { >+ switch(ecm[i]) { >+ case 0xDB: >+ if(i+2+ecm[i+1] <= ecmLen && ecm[i+1] == 16) { >+ memcpy(cw, &ecm[i+2], 16); >+ return 0; >+ } >+ break; >+ } >+ } >+ >+ return 5; >+} >+ >+// SoftNDS EMU >+static const uint8_t nds_const[]= {0x0F,0x1E,0x2D,0x3C,0x4B,0x5A,0x69,0x78,0x87,0x96,0xA5,0xB4,0xC3,0xD2,0xE1,0xF0}; >+ >+uint8_t viasat_const[]= { >+ 0x15,0x85,0xC5,0xE4,0xB8,0x52,0xEC,0xF7,0xC3,0xD9,0x08,0xBA,0x22,0x4A,0x66,0xF2, >+ 0x82,0x15,0x4F,0xB2,0x18,0x48,0x63,0x97,0xDC,0x19,0xD8,0x51,0x9A,0x39,0xFC,0xCA, >+ 0x1C,0x24,0xD0,0x65,0xA9,0x66,0x2D,0xD6,0x53,0x3B,0x86,0xBA,0x40,0xEA,0x4C,0x6D, >+ 0xD9,0x1E,0x41,0x14,0xFE,0x15,0xAF,0xC3,0x18,0xC5,0xF8,0xA7,0xA8,0x01,0x00,0x01, >+}; >+ >+static int8_t SoftNDSECM(uint16_t caid, uint8_t *ecm, uint8_t *dw) >+{ >+ int32_t i; >+ uint8_t *tDW, irdEcmLen, offsetCw = 0, offsetP2 = 0; >+ uint8_t digest[16], md5_const[64]; >+ MD5_CTX mdContext; >+ uint16_t ecmLen = GetEcmLen(ecm); >+ >+ if(ecmLen < 7) { >+ return 1; >+ } >+ >+ if(ecm[3] != 0x00 || ecm[4] != 0x00 || ecm[5] != 0x01) { >+ return 1; >+ } >+ >+ irdEcmLen = ecm[6]; >+ if(irdEcmLen < (10+3+8+4) || irdEcmLen+6 >= ecmLen) { >+ return 1; >+ } >+ >+ for(i=0; 10+i+2 < irdEcmLen; i++) { >+ if(ecm[17+i] == 0x0F && ecm[17+i+1] == 0x40 && ecm[17+i+2] == 0x00) { >+ offsetCw = 17+i+3; >+ offsetP2 = offsetCw+9; >+ } >+ } >+ >+ if(offsetCw == 0 || offsetP2 == 0) { >+ return 1; >+ } >+ >+ if(offsetP2-7+4 > irdEcmLen) { >+ return 1; >+ } >+ >+ if(caid == 0x090F || caid == 0x093E) { >+ memcpy(md5_const, viasat_const, 64); >+ } >+ else if(!FindKey('S', caid, 0, "00", md5_const, 64, 1, 0, 0, NULL)) { >+ return 2; >+ } >+ >+ memset(dw,0,16); >+ tDW = &dw[ecm[0] == 0x81 ? 8 : 0]; >+ >+ MD5_Init(&mdContext); >+ MD5_Update(&mdContext, ecm+7, 10); >+ MD5_Update(&mdContext, ecm+offsetP2, 4); >+ MD5_Update(&mdContext, md5_const, 64); >+ MD5_Update(&mdContext, nds_const, 16); >+ MD5_Final(digest, &mdContext); >+ >+ for (i=0; i<8; i++) { >+ tDW[i] = digest[i+8] ^ ecm[offsetCw+i]; >+ } >+ >+ if(((tDW[0]+tDW[1]+tDW[2])&0xFF)-tDW[3]) { >+ return 6; >+ } >+ if(((tDW[4]+tDW[5]+tDW[6])&0xFF)-tDW[7]) { >+ return 6; >+ } >+ >+ return 0; >+} >+ >+// Viaccess EMU >+static int8_t GetViaKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey) >+{ >+ >+ char keyStr[EMU_MAX_CHAR_KEYNAME]; >+ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); >+ if(FindKey('V', ident, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) { >+ return 1; >+ } >+ >+ if(ident == 0xD00040 && FindKey('V', 0x030B00, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) { >+ return 1; >+ } >+ >+ return 0; >+} >+ >+static void Via1Mod(const uint8_t* key2, uint8_t* data) >+{ >+ int32_t kb, db; >+ for (db=7; db>=0; db--) { >+ for (kb=7; kb>3; kb--) { >+ int32_t a0=kb^db; >+ int32_t pos=7; >+ if (a0&4) { >+ a0^=7; >+ pos^=7; >+ } >+ a0=(a0^(kb&3)) + (kb&3); >+ if (!(a0&4)) { >+ data[db]^=(key2[kb] ^ ((data[kb^pos]*key2[kb^4]) & 0xFF)); >+ } >+ } >+ } >+ for (db=0; db<8; db++) { >+ for (kb=0; kb<4; kb++) { >+ int32_t a0=kb^db; >+ int32_t pos=7; >+ if (a0&4) { >+ a0^=7; >+ pos^=7; >+ } >+ a0=(a0^(kb&3)) + (kb&3); >+ if (!(a0&4)) { >+ data[db]^=(key2[kb] ^ ((data[kb^pos]*key2[kb^4]) & 0xFF)); >+ } >+ } >+ } >+} >+ >+static void Via1Decode(uint8_t *data, uint8_t *key) >+{ >+ Via1Mod(key+8, data); >+ nc_des(key, DES_ECM_CRYPT, data); >+ Via1Mod(key+8, data); >+} >+ >+static void Via1Hash(uint8_t *data, uint8_t *key) >+{ >+ Via1Mod(key+8, data); >+ nc_des(key, DES_ECM_HASH, data); >+ Via1Mod(key+8, data); >+} >+ >+static inline void Via1DoHash(uint8_t *hashbuffer, uint8_t *pH, uint8_t data, uint8_t *hashkey) >+{ >+ hashbuffer[*pH] ^= data; >+ (*pH)++; >+ >+ if(*pH == 8) { >+ Via1Hash(hashbuffer, hashkey); >+ *pH = 0; >+ } >+} >+ >+static int8_t Via1Decrypt(uint8_t* ecm, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex) >+{ >+ uint8_t work_key[16]; >+ uint8_t *data, *des_data1, *des_data2; >+ uint16_t ecmLen = GetEcmLen(ecm); >+ int32_t msg_pos; >+ int32_t encStart = 0, hash_start, i; >+ uint8_t signature[8], hashbuffer[8], prepared_key[16], hashkey[16]; >+ uint8_t tmp, k, pH, foundData = 0; >+ >+ if (ident == 0) { >+ return 4; >+ } >+ memset(work_key, 0, 16); >+ if(!GetViaKey(work_key, ident, '0', desKeyIndex, 8, 1)) { >+ return 2; >+ } >+ >+ if(ecmLen < 11) { >+ return 1; >+ } >+ data = ecm+9; >+ des_data1 = dw; >+ des_data2 = dw+8; >+ >+ msg_pos = 0; >+ pH = 0; >+ memset(hashbuffer, 0, sizeof(hashbuffer)); >+ memcpy(hashkey, work_key, sizeof(hashkey)); >+ memset(signature, 0, 8); >+ >+ while(9+msg_pos+2 < ecmLen) { >+ switch (data[msg_pos]) { >+ case 0xea: >+ if(9+msg_pos+2+15 < ecmLen) { >+ encStart = msg_pos + 2; >+ memcpy(des_data1, &data[msg_pos+2], 8); >+ memcpy(des_data2, &data[msg_pos+2+8], 8); >+ foundData |= 1; >+ } >+ break; >+ case 0xf0: >+ if(9+msg_pos+2+7 < ecmLen) { >+ memcpy(signature, &data[msg_pos+2], 8); >+ foundData |= 2; >+ } >+ break; >+ } >+ msg_pos += data[msg_pos+1]+2; >+ } >+ >+ if(foundData != 3) { >+ return 1; >+ } >+ >+ pH=i=0; >+ >+ if(data[0] == 0x9f && 10+data[1] <= ecmLen) { >+ Via1DoHash(hashbuffer, &pH, data[i++], hashkey); >+ Via1DoHash(hashbuffer, &pH, data[i++], hashkey); >+ >+ for (hash_start=0; hash_start < data[1]; hash_start++) { >+ Via1DoHash(hashbuffer, &pH, data[i++], hashkey); >+ } >+ >+ while (pH != 0) { >+ Via1DoHash(hashbuffer, &pH, 0, hashkey); >+ } >+ } >+ >+ if (work_key[7] == 0) { >+ for (; i < encStart + 16; i++) { >+ Via1DoHash(hashbuffer, &pH, data[i], hashkey); >+ } >+ memcpy(prepared_key, work_key, 8); >+ } >+ else { >+ prepared_key[0] = work_key[2]; >+ prepared_key[1] = work_key[3]; >+ prepared_key[2] = work_key[4]; >+ prepared_key[3] = work_key[5]; >+ prepared_key[4] = work_key[6]; >+ prepared_key[5] = work_key[0]; >+ prepared_key[6] = work_key[1]; >+ prepared_key[7] = work_key[7]; >+ memcpy(prepared_key+8, work_key+8, 8); >+ >+ if (work_key[7] & 1) { >+ for (; i < encStart; i++) { >+ Via1DoHash(hashbuffer, &pH, data[i], hashkey); >+ } >+ >+ k = ((work_key[7] & 0xf0) == 0) ? 0x5a : 0xa5; >+ >+ for (i=0; i<8; i++) { >+ tmp = des_data1[i]; >+ des_data1[i] = (k & hashbuffer[pH] ) ^ tmp; >+ Via1DoHash(hashbuffer, &pH, tmp, hashkey); >+ } >+ >+ for (i = 0; i < 8; i++) { >+ tmp = des_data2[i]; >+ des_data2[i] = (k & hashbuffer[pH] ) ^ tmp; >+ Via1DoHash(hashbuffer, &pH, tmp, hashkey); >+ } >+ } >+ else { >+ for (; i < encStart + 16; i++) { >+ Via1DoHash(hashbuffer, &pH, data[i], hashkey); >+ } >+ } >+ } >+ Via1Decode(des_data1, prepared_key); >+ Via1Decode(des_data2, prepared_key); >+ Via1Hash(hashbuffer, hashkey); >+ if(memcmp(signature, hashbuffer, 8)) { >+ return 6; >+ } >+ return 0; >+} >+ >+static int8_t Via26ProcessDw(uint8_t *indata, uint32_t ident, uint8_t desKeyIndex) >+{ >+ uint8_t pv1,pv2, i; >+ uint8_t Tmp[8], T1Key[300], P1Key[8], KeyDes1[16], KeyDes2[16], XorKey[8]; >+ uint32_t ks1[32], ks2[32]; >+ >+ if(!GetViaKey(T1Key, ident, 'T', 1, 300, 1)) { >+ return 2; >+ } >+ if(!GetViaKey(P1Key, ident, 'P', 1, 8, 1)) { >+ return 2; >+ } >+ if(!GetViaKey(KeyDes1, ident, 'D', 1, 16, 1)) { >+ return 2; >+ } >+ if(!GetViaKey(KeyDes2, ident, '0', desKeyIndex, 16, 1)) { >+ return 2; >+ } >+ if(!GetViaKey(XorKey, ident, 'X', 1, 8, 1)) { >+ return 2; >+ } >+ >+ for (i=0; i<8; i++) { >+ pv1 = indata[i]; >+ Tmp[i] = T1Key[pv1]; >+ } >+ for (i=0; i<8; i++) { >+ pv1 = P1Key[i]; >+ pv2 = Tmp[pv1]; >+ indata[i]=pv2; >+ } >+ >+ des_set_key(KeyDes1, ks1); >+ des(indata, ks1, 1); >+ >+ for (i=0; i<8; i++) { >+ indata[i] ^= XorKey[i]; >+ } >+ >+ des_set_key(KeyDes2, ks1); >+ des_set_key(KeyDes2+8, ks2); >+ des(indata, ks1, 0); >+ des(indata, ks2, 1); >+ des(indata, ks1, 0); >+ >+ for (i=0; i<8; i++) { >+ indata[i] ^= XorKey[i]; >+ } >+ >+ des_set_key(KeyDes1, ks1); >+ des(indata, ks1, 0); >+ >+ for (i=0; i<8; i++) { >+ pv1 = indata[i]; >+ pv2 = P1Key[i]; >+ Tmp[pv2] = pv1; >+ } >+ for (i=0; i<8; i++) { >+ pv1 = Tmp[i]; >+ pv2 = T1Key[pv1]; >+ indata[i] = pv2; >+ } >+ return 0; >+} >+ >+static int8_t Via26Decrypt(uint8_t* source, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex) >+{ >+ uint8_t tmpData[8], C1[8]; >+ uint8_t *pXorVector; >+ int32_t i,j; >+ >+ if (ident == 0) { >+ return 4; >+ } >+ if(!GetViaKey(C1, ident, 'C', 1, 8, 1)) { >+ return 2; >+ } >+ >+ for (i=0; i<2; i++) { >+ memcpy(tmpData, source+ i*8, 8); >+ Via26ProcessDw(tmpData, ident, desKeyIndex); >+ if (i!=0) { >+ pXorVector = source; >+ } >+ else { >+ pXorVector = &C1[0]; >+ } >+ for (j=0; j<8; j++) { >+ dw[i*8+j] = tmpData[j]^pXorVector[j]; >+ } >+ } >+ return 0; >+} >+ >+static void Via3Core(uint8_t *data, uint8_t Off, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) >+{ >+ uint8_t i; >+ uint32_t lR2, lR3, lR4, lR6, lR7; >+ >+ switch (ident) { >+ case 0x032820: { >+ for (i=0; i<4; i++) { >+ data[i]^= XorKey[(Off+i) & 0x07]; >+ } >+ lR2 = (data[0]^0xBD)+data[0]; >+ lR3 = (data[3]^0xEB)+data[3]; >+ lR2 = (lR2-lR3)^data[2]; >+ lR3 = ((0x39*data[1])<<2); >+ data[4] = (lR2|lR3)+data[2]; >+ lR3 = ((((data[0]+6)^data[0]) | (data[2]<<1))^0x65)+data[0]; >+ lR2 = (data[1]^0xED)+data[1]; >+ lR7 = ((data[3]+0x29)^data[3])*lR2; >+ data[5] = lR7+lR3; >+ lR2 = ((data[2]^0x33)+data[2]) & 0x0A; >+ lR3 = (data[0]+0xAD)^data[0]; >+ lR3 = lR3+lR2; >+ lR2 = data[3]*data[3]; >+ lR7 = (lR2 | 1) + data[1]; >+ data[6] = (lR3|lR7)+data[1]; >+ lR3 = data[1] & 0x07; >+ lR2 = (lR3-data[2]) & (data[0] | lR2 |0x01); >+ data[7] = lR2+data[3]; >+ for (i=0; i<4; i++) { >+ data[i+4] = T1Key[data[i+4]]; >+ } >+ } >+ break; >+ case 0x030B00: { >+ for (i=0; i<4; i++) { >+ data[i]^= XorKey[(Off+i) & 0x07]; >+ } >+ lR6 = (data[3] + 0x6E) ^ data[3]; >+ lR6 = (lR6*(data[2] << 1)) + 0x17; >+ lR3 = (data[1] + 0x77) ^ data[1]; >+ lR4 = (data[0] + 0xD7) ^ data[0]; >+ data[4] = ((lR4 & lR3) | lR6) + data[0]; >+ lR4 = ((data[3] + 0x71) ^ data[3]) ^ 0x90; >+ lR6 = (data[1] + 0x1B) ^ data[1]; >+ lR4 = (lR4*lR6) ^ data[0]; >+ data[5] = (lR4 ^ (data[2] << 1)) + data[1]; >+ lR3 = (data[3] * data[3])| 0x01; >+ lR4 = (((data[2] ^ 0x35) + data[2]) | lR3) + data[2]; >+ lR6 = data[1] ^ (data[0] + 0x4A); >+ data[6] = lR6 + lR4; >+ lR3 = (data[0] * (data[2] << 1)) | data[1]; >+ lR4 = 0xFE - data[3]; >+ lR3 = lR4 ^ lR3; >+ data[7] = lR3 + data[3]; >+ for (i=0; i<4; i++) { >+ data[4+i] = T1Key[data[4+i]]; >+ } >+ } >+ break; >+ default: >+ break; >+ } >+} >+ >+static void Via3Fct1(uint8_t *data, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) >+{ >+ uint8_t t; >+ Via3Core(data, 0, ident, XorKey, T1Key); >+ >+ switch (ident) { >+ case 0x032820: { >+ t = data[4]; >+ data[4] = data[7]; >+ data[7] = t; >+ } >+ break; >+ case 0x030B00: { >+ t = data[5]; >+ data[5] = data[7]; >+ data[7] = t; >+ } >+ break; >+ default: >+ break; >+ } >+} >+ >+static void Via3Fct2(uint8_t *data, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) >+{ >+ uint8_t t; >+ Via3Core(data, 4, ident, XorKey, T1Key); >+ >+ switch (ident) { >+ case 0x032820: { >+ t = data[4]; >+ data[4] = data[7]; >+ data[7] = data[5]; >+ data[5] = data[6]; >+ data[6] = t; >+ } >+ break; >+ case 0x030B00: { >+ t = data[6]; >+ data[6] = data[7]; >+ data[7] = t; >+ } >+ break; >+ default: >+ break; >+ } >+} >+ >+static int8_t Via3ProcessDw(uint8_t *data, uint32_t ident, uint8_t desKeyIndex) >+{ >+ uint8_t i; >+ uint8_t tmp[8], T1Key[300], P1Key[8], KeyDes[16], XorKey[8]; >+ uint32_t ks1[32], ks2[32]; >+ >+ if(!GetViaKey(T1Key, ident, 'T', 1, 300, 1)) { >+ return 2; >+ } >+ if(!GetViaKey(P1Key, ident, 'P', 1, 8, 1)) { >+ return 2; >+ } >+ if(!GetViaKey(KeyDes, ident, '0', desKeyIndex, 16, 1)) { >+ return 2; >+ } >+ if(!GetViaKey(XorKey, ident, 'X', 1, 8, 1)) { >+ return 2; >+ } >+ >+ for (i=0; i<4; i++) { >+ tmp[i] = data[i+4]; >+ } >+ Via3Fct1(tmp, ident, XorKey, T1Key); >+ for (i=0; i<4; i++) { >+ tmp[i] = data[i]^tmp[i+4]; >+ } >+ Via3Fct2(tmp, ident, XorKey, T1Key); >+ for (i=0; i<4; i++) { >+ tmp[i]^= XorKey[i+4]; >+ } >+ for (i=0; i<4; i++) { >+ data[i] = data[i+4]^tmp[i+4]; >+ data[i+4] = tmp[i]; >+ } >+ >+ des_set_key(KeyDes, ks1); >+ des_set_key(KeyDes+8, ks2); >+ >+ des(data, ks1, 0); >+ des(data, ks2, 1); >+ des(data, ks1, 0); >+ >+ for (i=0; i<4; i++) { >+ tmp[i] = data[i+4]; >+ } >+ Via3Fct2(tmp, ident, XorKey, T1Key); >+ for (i=0; i<4; i++) { >+ tmp[i] = data[i]^tmp[i+4]; >+ } >+ Via3Fct1(tmp, ident, XorKey, T1Key); >+ for (i=0; i<4; i++) { >+ tmp[i]^= XorKey[i]; >+ } >+ for (i=0; i<4; i++) { >+ data[i] = data[i+4]^tmp[i+4]; >+ data[i+4] = tmp[i]; >+ } >+ return 0; >+} >+ >+static void Via3FinalMix(uint8_t *dw) >+{ >+ uint8_t tmp[4]; >+ >+ memcpy(tmp, dw, 4); >+ memcpy(dw, dw + 4, 4); >+ memcpy(dw + 4, tmp, 4); >+ >+ memcpy(tmp, dw + 8, 4); >+ memcpy(dw + 8, dw + 12, 4); >+ memcpy(dw + 12, tmp, 4); >+} >+ >+static int8_t Via3Decrypt(uint8_t* source, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex, uint8_t aesKeyIndex, uint8_t aesMode, int8_t doFinalMix) >+{ >+ int8_t aesAfterCore = 0; >+ int8_t needsAES = (aesKeyIndex != 0xFF); >+ uint8_t tmpData[8], C1[8]; >+ uint8_t *pXorVector; >+ char aesKey[16]; >+ int32_t i, j; >+ >+ if(ident == 0) { >+ return 4; >+ } >+ if(!GetViaKey(C1, ident, 'C', 1, 8, 1)) { >+ return 2; >+ } >+ if(needsAES && !GetViaKey((uint8_t*)aesKey, ident, 'E', aesKeyIndex, 16, 1)) { >+ return 2; >+ } >+ if(aesMode == 0x0D || aesMode == 0x11 || aesMode == 0x15) { >+ aesAfterCore = 1; >+ } >+ >+ if(needsAES && !aesAfterCore) { >+ if(aesMode == 0x0F) { >+ hdSurEncPhase1_D2_0F_11(source); >+ hdSurEncPhase2_D2_0F_11(source); >+ } >+ else if(aesMode == 0x13) { >+ hdSurEncPhase1_D2_13_15(source); >+ } >+ struct aes_keys aes; >+ aes_set_key(&aes, aesKey); >+ aes_decrypt(&aes, source, 16); >+ if(aesMode == 0x0F) { >+ hdSurEncPhase1_D2_0F_11(source); >+ } >+ else if(aesMode == 0x13) { >+ hdSurEncPhase2_D2_13_15(source); >+ } >+ } >+ >+ for(i=0; i<2; i++) { >+ memcpy(tmpData, source+i*8, 8); >+ Via3ProcessDw(tmpData, ident, desKeyIndex); >+ if (i!=0) { >+ pXorVector = source; >+ } >+ else { >+ pXorVector = &C1[0]; >+ } >+ for (j=0; j<8; j++) { >+ dw[i*8+j] = tmpData[j]^pXorVector[j]; >+ } >+ } >+ >+ if(needsAES && aesAfterCore) { >+ if(aesMode == 0x11) { >+ hdSurEncPhase1_D2_0F_11(dw); >+ hdSurEncPhase2_D2_0F_11(dw); >+ } >+ else if(aesMode == 0x15) { >+ hdSurEncPhase1_D2_13_15(dw); >+ } >+ struct aes_keys aes; >+ aes_set_key(&aes, aesKey); >+ aes_decrypt(&aes, dw, 16); >+ if(aesMode == 0x11) { >+ hdSurEncPhase1_D2_0F_11(dw); >+ } >+ if(aesMode == 0x15) { >+ hdSurEncPhase2_D2_13_15(dw); >+ } >+ } >+ >+ if(ident == 0x030B00) { >+ if(doFinalMix) { >+ Via3FinalMix(dw); >+ } >+ if(!isValidDCW(dw)) { >+ return 6; >+ } >+ } >+ return 0; >+} >+ >+static int8_t ViaccessECM(uint8_t *ecm, uint8_t *dw) >+{ >+ uint32_t currentIdent = 0; >+ uint8_t nanoCmd = 0, nanoLen = 0, version = 0, providerKeyLen = 0, desKeyIndex = 0, aesMode = 0, aesKeyIndex = 0xFF; >+ int8_t doFinalMix = 0, result = 1; >+ uint16_t i = 0, keySelectPos = 0, ecmLen = GetEcmLen(ecm); >+ >+ for (i=4; i+2<ecmLen; ) { >+ nanoCmd = ecm[i++]; >+ nanoLen = ecm[i++]; >+ if(i+nanoLen > ecmLen) { >+ return 1; >+ } >+ >+ switch (nanoCmd) { >+ case 0x40: >+ if (nanoLen < 0x03) { >+ break; >+ } >+ version = ecm[i]; >+ if (nanoLen == 3) { >+ currentIdent = ((ecm[i]<<16)|(ecm[i+1]<<8))|(ecm[i+2]&0xF0); >+ desKeyIndex = ecm[i+2]&0x0F; >+ keySelectPos = i+3; >+ } >+ else { >+ currentIdent = (ecm[i]<<16)|(ecm[i+1]<<8)|((ecm[i+2]>>4)&0x0F); >+ desKeyIndex = ecm[i+3]; >+ keySelectPos = i+4; >+ } >+ providerKeyLen = nanoLen; >+ break; >+ case 0x90: >+ if (nanoLen < 0x03) { >+ break; >+ } >+ version = ecm[i]; >+ currentIdent = ((ecm[i]<<16)|(ecm[i+1]<<8))|(ecm[i+2]&0xF0); >+ desKeyIndex = ecm[i+2]&0x0F; >+ keySelectPos = i+4; >+ if((version == 3) && (nanoLen > 3)) { >+ desKeyIndex = ecm[i+(nanoLen-4)]&0x0F; >+ } >+ providerKeyLen = nanoLen; >+ break; >+ case 0x80: >+ nanoLen = 0; >+ break; >+ case 0xD2: >+ if (nanoLen < 0x02) { >+ break; >+ } >+ aesMode = ecm[i]; >+ aesKeyIndex = ecm[i+1]; >+ break; >+ case 0xDD: >+ nanoLen = 0; >+ break; >+ case 0xEA: >+ if (nanoLen < 0x10) { >+ break; >+ } >+ >+ if (version < 2) { >+ return Via1Decrypt(ecm, dw, currentIdent, desKeyIndex); >+ } >+ else if (version == 2) { >+ return Via26Decrypt(ecm + i, dw, currentIdent, desKeyIndex); >+ } >+ else if (version == 3) { >+ doFinalMix = 0; >+ if (currentIdent == 0x030B00 && providerKeyLen>3) { >+ if(keySelectPos+2 >= ecmLen) { >+ break; >+ } >+ if (ecm[keySelectPos] == 0x05 && ecm[keySelectPos+1] == 0x67 && (ecm[keySelectPos+2] == 0x00 || ecm[keySelectPos+2] == 0x01)) { >+ if(ecm[keySelectPos+2] == 0x01) { >+ doFinalMix = 1; >+ } >+ } >+ else { >+ break; >+ } >+ } >+ return Via3Decrypt(ecm + i, dw, currentIdent, desKeyIndex, aesKeyIndex, aesMode, doFinalMix); >+ } >+ break; >+ default: >+ break; >+ } >+ i += nanoLen; >+ } >+ return result; >+} >+ >+// Nagra EMU >+static int8_t GetNagraKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint8_t isCriticalKey) >+{ >+ char keyStr[EMU_MAX_CHAR_KEYNAME]; >+ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); >+ if(FindKey('N', ident, 0, keyStr, buf, keyName == 'M' ? 64 : 16, isCriticalKey, 0, 0, NULL)) { >+ return 1; >+ } >+ >+ return 0; >+} >+ >+static int8_t Nagra2Signature(const uint8_t *vkey, const uint8_t *sig, const uint8_t *msg, int32_t len) >+{ >+ uint8_t buff[16]; >+ uint8_t iv[8]; >+ int32_t i,j; >+ >+ memcpy(buff,vkey,sizeof(buff)); >+ for(i=0; i+7<len; i+=8) { >+ IDEA_KEY_SCHEDULE ek; >+ idea_set_encrypt_key(buff, &ek); >+ memcpy(buff,buff+8,8); >+ memset(iv,0,sizeof(iv)); >+ idea_cbc_encrypt(msg+i,buff+8,8,&ek,iv,IDEA_ENCRYPT); >+ for(j=7; j>=0; j--) { >+ buff[j+8]^=msg[i+j]; >+ } >+ } >+ buff[8]&=0x7F; >+ return (memcmp(sig, buff+8, 8) == 0); >+} >+ >+static int8_t DecryptNagra2ECM(uint8_t *in, uint8_t *out, const uint8_t *key, int32_t len, const uint8_t *vkey, uint8_t *keyM) >+{ >+ BIGNUM *exp, *mod; >+ uint8_t iv[8]; >+ int32_t i = 0, sign = in[0] & 0x80; >+ uint8_t binExp = 3; >+ int8_t result = 1; >+ >+ exp = BN_new(); >+ mod = BN_new(); >+ BN_bin2bn(&binExp, 1, exp); >+ BN_bin2bn(keyM, 64, mod); >+ >+ if(EmuRSA(out,in+1,64,exp,mod,1)<=0) { >+ BN_free(exp); >+ BN_free(mod); >+ return 0; >+ } >+ out[63]|=sign; >+ if(len>64) { >+ memcpy(out+64,in+65,len-64); >+ } >+ >+ memset(iv,0,sizeof(iv)); >+ if(in[0]&0x04) { >+ uint8_t key1[8], key2[8]; >+ ReverseMemInOut(key1,&key[0],8); >+ ReverseMemInOut(key2,&key[8],8); >+ >+ for(i=7; i>=0; i--) { >+ ReverseMem(out+8*i,8); >+ } >+ des_ede2_cbc_decrypt(out, iv, key1, key2, len); >+ for(i=7; i>=0; i--) { >+ ReverseMem(out+8*i,8); >+ } >+ } >+ else { >+ IDEA_KEY_SCHEDULE ek; >+ idea_set_encrypt_key(key, &ek); >+ idea_cbc_encrypt(out, out, len&~7, &ek, iv, IDEA_DECRYPT); >+ } >+ >+ ReverseMem(out,64); >+ if(result && EmuRSA(out,out,64,exp,mod,0)<=0) { >+ result = 0; >+ } >+ if(result && vkey && !Nagra2Signature(vkey,out,out+8,len-8)) { >+ result = 0; >+ } >+ >+ BN_free(exp); >+ BN_free(mod); >+ return result; >+} >+ >+static int8_t Nagra2ECM(uint8_t *ecm, uint8_t *dw) >+{ >+ uint32_t ident, identMask, tmp1, tmp2, tmp3; >+ uint8_t cmdLen, ideaKeyNr, *dec, ideaKey[16], vKey[16], m1Key[64], mecmAlgo = 0; >+ int8_t useVerifyKey = 0; >+ int32_t l=0, s; >+ uint16_t i = 0, ecmLen = GetEcmLen(ecm); >+ >+ if(ecmLen < 8) { >+ return 1; >+ } >+ cmdLen = ecm[4] - 5; >+ ident = (ecm[5] << 8) + ecm[6]; >+ ideaKeyNr = (ecm[7]&0x10)>>4; >+ if(ideaKeyNr) { >+ ideaKeyNr = 1; >+ } >+ if(ident == 1283 || ident == 1285 || ident == 1297) { >+ ident = 1281; >+ } >+ if(cmdLen <= 63 || ecmLen < cmdLen + 10) { >+ return 1; >+ } >+ >+ if(!GetNagraKey(ideaKey, ident, '0', ideaKeyNr, 1)) { >+ return 2; >+ } >+ if(GetNagraKey(vKey, ident, 'V', 0, 0)) { >+ useVerifyKey = 1; >+ } >+ if(!GetNagraKey(m1Key, ident, 'M', 1, 1)) { >+ return 2; >+ } >+ ReverseMem(m1Key, 64); >+ >+ dec = (uint8_t*)malloc(sizeof(uint8_t)*cmdLen); >+ if(dec == NULL) { >+ return 7; >+ } >+ if(!DecryptNagra2ECM(ecm+9, dec, ideaKey, cmdLen, useVerifyKey?vKey:0, m1Key)) { >+ free(dec); >+ return 1; >+ } >+ >+ for(i=(dec[14]&0x10)?16:20; i<cmdLen && l!=3; ) { >+ switch(dec[i]) { >+ case 0x10: >+ case 0x11: >+ if(i+10 < cmdLen && dec[i+1] == 0x09) { >+ s = (~dec[i])&1; >+ mecmAlgo = dec[i+2]&0x60; >+ memcpy(dw+(s<<3), &dec[i+3], 8); >+ i+=11; >+ l|=(s+1); >+ } >+ else { >+ i++; >+ } >+ break; >+ case 0x00: >+ i+=2; >+ break; >+ case 0x30: >+ case 0x31: >+ case 0x32: >+ case 0x33: >+ case 0x34: >+ case 0x35: >+ case 0x36: >+ case 0xB0: >+ if(i+1 < cmdLen) { >+ i+=dec[i+1]+2; >+ } >+ else { >+ i++; >+ } >+ break; >+ default: >+ i++; >+ continue; >+ } >+ } >+ >+ free(dec); >+ >+ if(l!=3) { >+ return 1; >+ } >+ if(mecmAlgo>0) { >+ return 1; >+ } >+ >+ identMask = ident & 0xFF00; >+ if (identMask == 0x1100 || identMask == 0x500 || identMask == 0x3100) { >+ memcpy(&tmp1, dw, 4); >+ memcpy(&tmp2, dw + 4, 4); >+ memcpy(&tmp3, dw + 12, 4); >+ memcpy(dw, dw + 8, 4); >+ memcpy(dw + 4, &tmp3, 4); >+ memcpy(dw + 8, &tmp1, 4); >+ memcpy(dw + 12, &tmp2, 4); >+ } >+ return 0; >+} >+ >+// Irdeto EMU >+static int8_t GetIrdetoKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint8_t isCriticalKey, uint32_t *keyRef) >+{ >+ char keyStr[EMU_MAX_CHAR_KEYNAME]; >+ >+ if(*keyRef > 0xFF) >+ { >+ return 0; >+ } >+ >+ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); >+ if(FindKey('I', ident, 0, keyStr, buf, 16, *keyRef > 0 ? 0 : isCriticalKey, *keyRef, 0, NULL)) { >+ (*keyRef)++; >+ return 1; >+ } >+ >+ return 0; >+} >+ >+static void Irdeto2Encrypt(uint8_t *data, const uint8_t *seed, const uint8_t *key, int32_t len) >+{ >+ const uint8_t *tmp = seed;; >+ int32_t i; >+ uint32_t ks1[32], ks2[32]; >+ >+ des_set_key(key, ks1); >+ des_set_key(key+8, ks2); >+ >+ len&=~7; >+ >+ for(i=0; i+7<len; i+=8) { >+ xxor(&data[i],8,&data[i],tmp); >+ tmp=&data[i]; >+ des(&data[i], ks1, 1); >+ des(&data[i], ks2, 0); >+ des(&data[i], ks1, 1); >+ } >+} >+ >+static void Irdeto2Decrypt(uint8_t *data, const uint8_t *seed, const uint8_t *key, int32_t len) >+{ >+ uint8_t buf[2][8]; >+ int32_t i, n=0; >+ uint32_t ks1[32], ks2[32]; >+ >+ des_set_key(key, ks1); >+ des_set_key(key+8, ks2); >+ >+ len&=~7; >+ >+ memcpy(buf[n],seed,8); >+ for(i=0; i+7<len; i+=8,data+=8,n^=1) { >+ memcpy(buf[1-n],data,8); >+ des(data, ks1, 0); >+ des(data, ks2, 1); >+ des(data, ks1, 0); >+ xxor(data,8,data,buf[n]); >+ } >+} >+ >+static int8_t Irdeto2CalculateHash(const uint8_t *key, const uint8_t *iv, const uint8_t *data, int32_t len) >+{ >+ uint8_t cbuff[8]; >+ int32_t l, y; >+ uint32_t ks1[32], ks2[32]; >+ >+ des_set_key(key, ks1); >+ des_set_key(key+8, ks2); >+ >+ memset(cbuff,0,sizeof(cbuff)); >+ len-=8; >+ >+ for(y=0; y<len; y+=8) { >+ if(y<len-8) { >+ xxor(cbuff,8,cbuff,&data[y]); >+ } >+ else { >+ l=len-y; >+ xxor(cbuff,l,cbuff,&data[y]); >+ xxor(cbuff+l,8-l,cbuff+l,iv+8); >+ } >+ >+ des(cbuff, ks1, 1); >+ des(cbuff, ks2, 0); >+ des(cbuff, ks1, 1); >+ } >+ >+ return memcmp(cbuff, &data[len], 8) == 0; >+} >+ >+static int8_t Irdeto2ECM(uint16_t caid, uint8_t *oecm, uint8_t *dw) >+{ >+ uint8_t keyNr=0, length, end, key[16], okeySeed[16], keySeed[16], keyIV[16], tmp[16]; >+ uint32_t i, l, ident; >+ uint32_t key0Ref, keySeedRef, keyIVRef; >+ uint8_t ecmCopy[EMU_MAX_ECM_LEN], *ecm = oecm; >+ uint16_t ecmLen = GetEcmLen(ecm); >+ >+ if(ecmLen < 12) { >+ return 1; >+ } >+ >+ length = ecm[11]; >+ keyNr = ecm[9]; >+ ident = ecm[8] | caid << 8; >+ >+ if(ecmLen < length+12) { >+ return 1; >+ } >+ >+ key0Ref = 0; >+ while(GetIrdetoKey(key, ident, '0', keyNr, 1, &key0Ref)) { >+ keySeedRef = 0; >+ while(GetIrdetoKey(okeySeed, ident, 'M', 1, 1, &keySeedRef)) { >+ keyIVRef = 0; >+ while(GetIrdetoKey(keyIV, ident, 'M', 2, 1, &keyIVRef)) { >+ >+ memcpy(keySeed, okeySeed, 16); >+ memcpy(ecmCopy, oecm, ecmLen); >+ ecm = ecmCopy; >+ >+ memset(tmp, 0, 16); >+ Irdeto2Encrypt(keySeed, tmp, key, 16); >+ ecm+=12; >+ Irdeto2Decrypt(ecm, keyIV, keySeed, length); >+ i=(ecm[0]&7)+1; >+ end = length-8 < 0 ? 0 : length-8; >+ >+ while(i<end) { >+ l = ecm[i+1] ? (ecm[i+1]&0x3F)+2 : 1; >+ switch(ecm[i]) { >+ case 0x10: >+ case 0x50: >+ if(l == 0x13 && i <= length-8-l) { >+ Irdeto2Decrypt(&ecm[i+3], keyIV, key, 16); >+ } >+ break; >+ case 0x78: >+ if(l == 0x14 && i <= length-8-l) { >+ Irdeto2Decrypt(&ecm[i+4], keyIV, key, 16); >+ } >+ break; >+ } >+ i+=l; >+ } >+ >+ i=(ecm[0]&7)+1; >+ if(Irdeto2CalculateHash(keySeed, keyIV, ecm-6, length+6)) { >+ while(i<end) { >+ l = ecm[i+1] ? (ecm[i+1]&0x3F)+2 : 1; >+ switch(ecm[i]) { >+ case 0x78: >+ if(l == 0x14 && i <= length-8-l) { >+ memcpy(dw, &ecm[i+4], 16); >+ return 0; >+ } >+ } >+ i+=l; >+ } >+ } >+ } >+ if(keyIVRef == 0) { >+ return 2; >+ } >+ } >+ if(keySeedRef == 0) { >+ return 2; >+ } >+ } >+ if(key0Ref == 0) { >+ return 2; >+ } >+ >+ return 1; >+} >+ >+// BISS EMU >+static void BissUnifyOrbitals(uint32_t *namespace) >+{ >+ // Unify orbitals to produce same namespace among users >+ // Set positions according to http://satellites-xml.org >+ >+ uint16_t pos = (*namespace & 0x0FFF0000) >> 16; >+ >+ switch (pos) >+ { >+ case 29: // Rascom QAF 1R >+ case 31: // Eutelsat 3B >+ { >+ pos = 30; >+ break; >+ } >+ >+ case 49: >+ case 50: // SES 5 >+ { >+ pos = 48; // Astra 4A >+ break; >+ } >+ >+ case 215: >+ { >+ pos = 216; // Eutelsat 21B >+ break; >+ } >+ >+ case 285: // Astra 2E >+ { >+ pos = 282; // Astra 2F/2G >+ break; >+ } >+ >+ case 328: // Intelsat 28 >+ case 329: >+ case 331: // Eutelsat 33C >+ { >+ pos = 330; >+ break; >+ } >+ >+ case 359: // Eutelsat 36B >+ case 361: // Express AMU1 >+ { >+ pos = 360; >+ break; >+ } >+ >+ case 451: // Intelsat 904 >+ { >+ pos = 450; // Intelsat 12 >+ break; >+ } >+ >+ case 550: >+ case 551: // G-Sat 8/16 >+ { >+ pos = 549; // Yamal 402 >+ break; >+ } >+ >+ case 748: >+ case 749: // ABS 2A >+ { >+ pos = 750; >+ break; >+ } >+ >+ case 848: // Horizons 2 >+ case 852: // Intelsat 15 >+ { >+ pos = 850; >+ break; >+ } >+ >+ case 914: // Mesasat 3a >+ { >+ pos = 915; // Mesasat 3/3b >+ break; >+ } >+ >+ case 934: // G-Sat 17 >+ case 936: // Insat 4B >+ { >+ pos = 935; // G-Sat 15 >+ break; >+ } >+ >+ case 3600 - 911: // Nimiq 6 >+ { >+ pos = 3600 - 910; // Galaxy 17 >+ } >+ >+ case 3600 - 870: // SES 2 >+ case 3600 - 872: // TKSat 1 >+ { >+ pos = 3600 - 871; >+ break; >+ } >+ >+ case 3600 - 432: // Sky Brasil 1 >+ case 3600 - 430: // Intelsat 11 >+ { >+ pos = 3600 - 431; >+ break; >+ } >+ >+ case 3600 - 376: // Telstar 11N >+ case 3600 - 374: // NSS 10 >+ { >+ pos = 3600 - 375; >+ break; >+ } >+ >+ case 3600 - 359: // Hispasat 36W-1 >+ { >+ pos = 3600 - 360; // Eutelsat 36 West A >+ break; >+ } >+ >+ case 3600 - 81: // Eutelsat 8 West B >+ { >+ pos = 3600 - 80; >+ break; >+ } >+ >+ case 3600 - 73: // Eutelsat 7 West A >+ case 3600 - 72: >+ case 3600 - 71: >+ { >+ pos = 3600 - 70; // Nilesat 201 >+ break; >+ } >+ >+ case 3600 - 10: // Intelsat 10-02 >+ case 3600 - 9: // Thor 6 >+ case 3600 - 7: // Thor 7 >+ case 3600 - 6: // Thor 7 >+ { >+ pos = 3600 - 8; // Thor 5 >+ break; >+ } >+ } >+ >+ *namespace = (*namespace & 0xF000FFFF) | (pos << 16); >+} >+ >+static void BissAnnotate(char *buf, uint8_t len, const uint8_t *ecm, uint16_t ecmLen, uint32_t hash, int8_t isNamespaceHash, int8_t datecoded) >+{ >+ // Extract useful information to append to the "Example key ..." message. >+ // >+ // For feeds, the orbital position & frequency are usually embedded in the namespace. >+ // See https://github.com/openatv/enigma2/blob/master/lib/dvb/frontend.cpp#L496 >+ // hash = (sat.orbital_position << 16); >+ // hash |= ((sat.frequency/1000)&0xFFFF)|((sat.polarisation&1) << 15); >+ // >+ // If the onid & tsid appear to be a unique DVB identifier, enigma2 strips the frequency >+ // from our namespace. See https://github.com/openatv/enigma2/blob/master/lib/dvb/scan.cpp#L59 >+ // In that case, our annotation contains the onid:tsid:sid triplet in lieu of frequency. >+ // >+ // For the universal case, we print the number of elementary stream pids & pmtpid. >+ // The sid and current time are included for all. Examples: >+ // >+ // F 1A2B3C4D 00000000 XXXXXXXXXXXXXXXX ; 110.5W 12345H sid:0001 added: 2017-10-17 @ 13:14:15 // namespace >+ // F 1A2B3C4D 20180123 XXXXXXXXXXXXXXXX ; 33.5E ABCD:9876:1234 added: 2017-10-17 @ 13:14:15 // stripped namespace >+ // F 1A2B3C4D 20180123 XXXXXXXXXXXXXXXX ; av:5 pmt:0134 sid:0001 added: 2017-10-17 @ 13:14:15 // universal >+ >+ uint8_t pidcount; >+ uint16_t frequency, degrees, pmtpid, srvid, tsid, onid; >+ uint32_t ens; >+ char compass, polarisation, timeStr1[9], timeStr2[19]; >+ >+ if (datecoded) >+ { >+ Date2Str(timeStr1, sizeof(timeStr1), 4, 3); >+ } >+ else >+ { >+ snprintf(timeStr1, sizeof(timeStr1), "00000000"); >+ } >+ >+ Date2Str(timeStr2, sizeof(timeStr2), 0, 2); >+ >+ if (isNamespaceHash) // Namespace hash >+ { >+ ens = b2i(4, ecm + ecmLen - 4); // Namespace will be the last 4 bytes of the ecm >+ degrees = (ens >> 16) & 0x0FFF; // Remove not-a-pid flag >+ >+ if (degrees > 1800) >+ { >+ degrees = 3600 - degrees; >+ compass = 'W'; >+ } >+ else >+ { >+ compass = 'E'; >+ } >+ >+ if (0 == (ens & 0xFFFF)) // Stripped namespace hash >+ { >+ srvid = b2i(2, ecm + 3); >+ tsid = b2i(2, ecm + ecmLen - 8); >+ onid = b2i(2, ecm + ecmLen - 6); >+ // Printing degree sign "\u00B0" requires c99 standard >+ snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; %5.1f%c %04X:%04X:%04X added: %s", >+ hash, timeStr1, degrees / 10.0, compass, onid, tsid, srvid, timeStr2); >+ } >+ else // Full namespace hash >+ { >+ srvid = b2i(2, ecm + 3); >+ frequency = ens & 0x7FFF; // Remove polarity bit >+ polarisation = ens & 0x8000 ? 'V' : 'H'; >+ // Printing degree sign "\u00B0" requires c99 standard >+ snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; %5.1f%c %5d%c sid:%04X added: %s", >+ hash, timeStr1, degrees / 10.0, compass, frequency, polarisation, srvid, timeStr2); >+ } >+ } >+ else // Universal hash >+ { >+ srvid = b2i(2, ecm + 3); >+ pmtpid = b2i(2, ecm + 5); >+ pidcount = (ecmLen - 15) / 2; // video + audio pids count >+ snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; av:%d pmt:%04X sid:%04X added: %s", >+ hash, timeStr1, pidcount, pmtpid, srvid, timeStr2); >+ } >+} >+ >+static int8_t BissIsCommonHash(uint32_t hash) >+{ >+ // Check universal hash against a number of commnon universal >+ // hashes in order to warn users about potential key clashes >+ >+ switch (hash) >+ { >+ case 0xBAFCD9FD: // 0001 0020 0200 1010 1020 (most common hash) >+ return 1; >+ case 0xA6A4FBD4: // 0001 0800 0200 1010 1020 >+ return 1; >+ case 0xEFAB7A4D: // 0001 0800 1010 1020 0200 >+ return 1; >+ case 0x83FA15D1: // 0001 0020 0134 0100 0101 >+ return 1; >+ case 0x58934C38: // 0001 0800 1010 1020 1030 0200 >+ return 1; >+ case 0x2C3CEC17: // 0001 0020 0134 0100 >+ return 1; >+ case 0x73DF7F7E: // 0001 0020 0200 1010 1020 1030 >+ return 1; >+ case 0xAFA85BC8: // 0001 0020 0021 0022 0023 >+ return 1; >+ case 0x8C51F31D: // 0001 0800 0200 1010 1020 1030 1040 >+ return 1; >+ case 0xE2F9BD29: // 0001 0800 0200 1010 1020 1030 >+ return 1; >+ case 0xB9EBE0FF: // 0001 0100 0200 1010 1020 (less common hash) >+ return 1; >+ default: >+ return 0; >+ } >+} >+ >+static int8_t BissIsValidNamespace(uint32_t namespace) >+{ >+ // Note to developers: >+ // If we ever have a satellite at 0.0E, edit to allow stripped namespace >+ // '0xA0000000' with an additional test on tsid and onid being != 0 >+ >+ uint16_t orbital, frequency; >+ >+ orbital = (namespace >> 16) & 0x0FFF; >+ frequency = namespace & 0x7FFF; >+ >+ if ((namespace & 0xA0000000) != 0xA0000000) return 0; // Value isn't flagged as namespace >+ if (namespace == 0xA0000000) return 0; // Empty namespace >+ if (orbital > 3599) return 0; // Allow only DVB-S >+ if (frequency == 0) return 1; // Stripped namespace >+ if (frequency >= 3400 && frequency <= 4200) return 1; // Super extended C band >+ if (frequency >= 10700 && frequency <= 12750) return 1; // Ku band Europe >+ >+ return 0; >+} >+ >+static int8_t BissGetKey(uint32_t provider, uint8_t *key, int8_t dateCoded, int8_t printMsg) >+{ >+ // If date-coded keys are enabled in the webif, this function evaluates the expiration date >+ // of the keys found. Expired keys are not sent to BissECM(). If date-coded keys are disabled, >+ // then all keys found are sent without any evaluation. It takes the "provider" as input and >+ // outputs the "key". Returns 0 (Key not found, or expired) or 1 (Key found). >+ >+ // printMsg: 0 => No message >+ // printMsg: 1 => Print message only if key is found >+ // printMsg: 2 => Always print message, regardless if key is found or not >+ >+ char keyExpDate[9] = "00000000"; >+ >+ if (FindKey('F', provider, 0, keyExpDate, key, 8, 0, 0, 0, NULL)) // Key found >+ { >+ if (dateCoded) // Date-coded keys are enabled, evaluate expiration date >+ { >+ char currentDate[9]; >+ Date2Str(currentDate, sizeof(currentDate), 0, 3); >+ >+ if (strncmp("00000000", keyExpDate, 9) == 0 || strncmp(currentDate, keyExpDate, 9) < 0) // Evergreen or not expired >+ { >+ if (printMsg == 1 || printMsg == 2) cs_log("Key found: F %08X %s", provider, keyExpDate); >+ return 1; >+ } >+ else // Key expired >+ { >+ key = NULL; // Make sure we don't send any expired key >+ if (printMsg == 2) cs_log("Key expired: F %08X %s", provider, keyExpDate); >+ return 0; >+ } >+ } >+ else // Date-coded keys are disabled, don't evaluate expiration date >+ { >+ if (printMsg == 1 || printMsg == 2) cs_log("Key found: F %08X %s", provider, keyExpDate); >+ return 1; >+ } >+ } >+ else // Key not found >+ { >+ if (printMsg == 2) cs_log("Key not found: F %08X", provider); >+ return 0; >+ } >+} >+ >+static int8_t BissECM(struct s_reader *rdr, const uint8_t *ecm, int16_t ecmDataLen, uint8_t *dw, uint16_t srvid, uint16_t ecmpid) >+{ >+ // Oscam's fake ecm consists of [sid] [pmtpid] [pid1] [pid2] ... [pidx] [tsid] [onid] [namespace] >+ // >+ // On enigma boxes tsid, onid and namespace should be non zero, while on non-enigma >+ // boxes they are usually all zero. >+ // The emulator creates a unique channel hash using srvid and enigma namespace or >+ // srvid, tsid, onid and namespace (in case of namespace without frequency) and >+ // another weaker (not unique) hash based on every pid of the channel. This universal >+ // hash should be available on all types of stbs (enigma and non-enigma). >+ >+ // Flags inside [namespace] >+ // >+ // emu r748- : no namespace, no flag >+ // emu r749 : 0x80000000 (full namespase), 0xC0000000 (stripped namespace, injected with tsid^onid^ecmpid^0x1FFF) >+ // emu r752+ : 0xA0000000 (pure namespace, either full, stripped, or null) >+ >+ // Key searches are made in order: >+ // Highest priority / tightest test first >+ // Lowest priority / loosest test last >+ // >+ // 1st: namespace hash (only on enigma boxes) >+ // 2nd: universal hash (all box types with emu r752+) >+ // 3rd: valid tsid, onid combination >+ // 4th: faulty ecmpid (other than 0x1FFF) >+ // 5th: reverse order pid (audio, video, pmt pids) >+ // 6th: standard BISS ecmpid (0x1FFF) >+ // 7th: default "All Feeds" key >+ >+ // If enabled in the webif, a date based key search can be performed. If the expiration >+ // date has passed, the key is not sent from BissGetKey(). This search method is only >+ // used in the namespace hash, universal hash and the default "All Feeds" key. >+ >+ uint8_t ecmCopy[EMU_MAX_ECM_LEN]; >+ uint16_t ecmLen = 0, pid = 0; >+ uint32_t i, ens = 0, hash = 0; >+ char tmpBuffer1[17], tmpBuffer2[90] = "0", tmpBuffer3[90] = "0"; >+ >+ if (ecmDataLen >= 3) >+ { >+ ecmLen = GetEcmLen(ecm); >+ } >+ >+ // First try using the unique namespace hash (enigma only) >+ if (ecmLen >= 13 && ecmLen <= ecmDataLen) // ecmLen >= 13, allow patching the ecmLen for r749 ecms >+ { >+ memcpy(ecmCopy, ecm, ecmLen); >+ ens = b2i(4, ecm + ecmLen - 4); // Namespace will be the last 4 bytes >+ >+ if (BissIsValidNamespace(ens)) // An r752+ extended ecm with valid namespace >+ { >+ BissUnifyOrbitals(&ens); >+ i2b_buf(4, ens, ecmCopy + ecmLen - 4); >+ >+ for (i = 0; i < 5; i++) // Find key matching hash made with frequency modified to: f+0, then f-1, f+1, f-2, lastly f+2 >+ { >+ ecmCopy[ecmLen - 1] = (i & 1) ? ecmCopy[ecmLen - 1] - i : ecmCopy[ecmLen - 1] + i; // frequency +/- 1, 2 MHz >+ >+ if (0 != (ens & 0xFFFF)) // Full namespace - Calculate hash with srvid and namespace only >+ { >+ i2b_buf(2, srvid, ecmCopy + ecmLen - 6); // Put [srvid] right before [namespace] >+ hash = crc32(0x2600, ecmCopy + ecmLen - 6, 6); >+ } >+ else // Namespace without frequency - Calculate hash with srvid, tsid, onid and namespace >+ { >+ i2b_buf(2, srvid, ecmCopy + ecmLen - 10); // Put [srvid] right before [tsid] [onid] [namespace] sequence >+ hash = crc32(0x2600, ecmCopy + ecmLen - 10, 10); >+ } >+ >+ if (BissGetKey(hash, dw, rdr->emu_datecodedenabled, i == 0 ? 2 : 1)) // Do not print "key not found" for frequency off by 1, 2 >+ { >+ memcpy(dw + 8, dw, 8); >+ return 0; >+ } >+ >+ if (i == 0) // No key found matching our hash: create example SoftCam.Key BISS line for the live log >+ { >+ BissAnnotate(tmpBuffer2, sizeof(tmpBuffer2), ecmCopy, ecmLen, hash, 1, rdr->emu_datecodedenabled); >+ } >+ >+ if (0 == (ens & 0xFFFF)) // Namespace without frequency - Do not iterate >+ { >+ break; >+ } >+ } >+ } >+ >+ if ((ens & 0xA0000000) == 0x80000000) // r749 ecms only (exclude r752+ ecms) >+ { >+ cs_log("Hey! Network buddy, you need to upgrade your OSCam-Emu"); >+ ecmCopy[ecmLen] = 0xA0; // Patch ecm to look like r752+ >+ ecmLen += 4; >+ ecmDataLen += 4; >+ } >+ } >+ >+ // Try using the universal channel hash (namespace not available) >+ if (ecmLen >= 17 && ecmLen <= ecmDataLen) // ecmLen >= 17, length of r749 ecms has been patched to match r752+ ecms >+ { >+ ens = b2i(4, ecmCopy + ecmLen - 4); // Namespace will be last 4 bytes >+ >+ if ((ens & 0xE0000000) == 0xA0000000) // We have an r752+ style ecm which contains pmtpid >+ { >+ memcpy(ecmCopy, ecm, ecmLen - 8); // Make a new ecmCopy from the original ecm as the old ecmCopy may be altered in namespace hash (skip [tsid] [onid] [namespace]) >+ hash = crc32(0x2600, ecmCopy + 3, ecmLen - 3 - 8); // ecmCopy doesn't have [tsid] [onid] [namespace] part >+ >+ if (BissGetKey(hash, dw, rdr->emu_datecodedenabled, 2)) // Key found >+ { >+ memcpy(dw + 8, dw, 8); >+ return 0; >+ } >+ >+ // No key found matching our hash: create example SoftCam.Key BISS line for the live log >+ BissAnnotate(tmpBuffer3, sizeof(tmpBuffer3), ecmCopy, ecmLen, hash, 0, rdr->emu_datecodedenabled); >+ } >+ } >+ >+ // Try using only [tsid][onid] (useful when many channels on a transpoder use the same key) >+ if (ecmLen >= 17 && ecmLen <= ecmDataLen) // ecmLen >= 17, length of r749 ecms has been patched to match r752+ ecms >+ { >+ ens = b2i(4, ecmCopy + ecmLen - 4); // Namespace will be last 4 bytes >+ >+ // We have an r752+ style ecm with stripped namespace, thus a valid [tsid][onid] combo to use as provider >+ if ((ens & 0xE000FFFF) == 0xA0000000 && BissGetKey(b2i(4, ecm + ecmLen - 8), dw, 0, 2)) >+ { >+ memcpy(dw + 8, dw, 8); >+ return 0; >+ } >+ >+ if ((ens & 0xE0000000) == 0xA0000000) // Strip [tsid] [onid] [namespace] on r752+ ecms >+ { >+ ecmLen -= 8; >+ ecmDataLen -= 8; >+ } >+ } >+ >+ // Try using ecmpid if it seems to be faulty (should be 0x1FFF always for BISS) >+ if (ecmpid != 0x1FFF && ecmpid != 0) >+ { >+ if (BissGetKey((srvid << 16) | ecmpid, dw, 0, 2)) >+ { >+ memcpy(dw + 8, dw, 8); >+ return 0; >+ } >+ } >+ >+ // Try to get the pid from oscam's fake ecm (only search [pid1] [pid2] ... [pidx] to be compatible with emu r748-) >+ if (ecmLen >= 7 && ecmLen <= ecmDataLen) // Use >= for radio channels with just one (audio) pid >+ { >+ // Reverse search order: last pid in list first >+ // Better identifies channels where they share identical video pid but have variable counts of audio pids >+ for (i = ecmLen - 2; i >= 5; i -= 2) >+ { >+ pid = b2i(2, ecm + i); >+ >+ if (BissGetKey((srvid << 16) | pid, dw, 0, 2)) >+ { >+ memcpy(dw + 8, dw, 8); >+ return 0; >+ } >+ } >+ } >+ >+ // Try using the standard BISS ecm pid >+ if (ecmpid == 0x1FFF || ecmpid == 0) >+ { >+ if (BissGetKey((srvid << 16) | 0x1FFF, dw, 0, 2)) >+ { >+ memcpy(dw + 8, dw, 8); >+ return 0; >+ } >+ } >+ >+ // Default BISS key for events with many feeds sharing same key >+ if (ecmpid != 0 && BissGetKey(0xA11FEED5, dw, rdr->emu_datecodedenabled, 2)) // Limit to local ecms, block netwotk ecms >+ { >+ memcpy(dw + 8, dw, 8); >+ cs_hexdump(0, dw, 8, tmpBuffer1, sizeof(tmpBuffer1)); >+ cs_log("No specific match found. Using 'All Feeds' key: %s", tmpBuffer1); >+ return 0; >+ } >+ >+ // Print example key lines for available hash search methods, if no key is found >+ if (strncmp(tmpBuffer2, "0", 2)) cs_log("Example key based on namespace hash: %s", tmpBuffer2); >+ if (strncmp(tmpBuffer3, "0", 2)) cs_log("Example key based on universal hash: %s", tmpBuffer3); >+ >+ // Check if universal hash is common and warn user >+ if (BissIsCommonHash(hash)) cs_log("Feed has commonly used pids, universal hash clashes in SoftCam.Key are likely!"); >+ >+ return 2; >+} >+ >+// PowerVu Emu >+static uint8_t PowervuCrc8Calc(uint8_t *data, int len) >+{ >+ int i; >+ uint8_t crc = 0x00; >+ uint8_t crcTable[256] = {0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, >+ 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, >+ 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, >+ 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, >+ 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, >+ 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, >+ 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, >+ 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, >+ 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, >+ 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, >+ 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, >+ 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, >+ 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, >+ 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, >+ 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, >+ 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3}; >+ >+ for(i = 0; i < len; i++) >+ { >+ crc = crcTable[data[i] ^ crc]; >+ } >+ >+ return crc; >+} >+ >+static void PowervuPadData(uint8_t *data, int len, uint8_t *dataPadded) >+{ >+ int i; >+ uint8_t pad[] = {0x01, 0x02, 0x22, 0x04, 0x20, 0x2A, 0x1F, 0x03, 0x04, 0x06, 0x02, 0x0C, 0x2B, 0x2B, 0x01, 0x7B}; >+ >+ for(i = 0; i < len; i++) >+ { >+ dataPadded[i] = data[i]; >+ } >+ >+ dataPadded[len] = 0x01; >+ >+ for(i = len + 1; i < 0x2F; i++) >+ { >+ dataPadded[i] = 0x00; >+ } >+ >+ dataPadded[0x2F] = len; >+ >+ for(i = 0; i < 0x10; i++) >+ { >+ dataPadded[0x30 + i] = pad[i]; >+ } >+} >+ >+static void PowervuHashMode01CustomMD5(uint8_t *data, uint8_t *hash) >+{ >+ int i, j, s; >+ uint32_t a, b, c, d, f, g; >+ >+ uint32_t T[] = {0x783E16F6, 0xC267AC13, 0xA2B17F12, 0x6B8A31A4, 0xF910654D, 0xB702DBCB, 0x266CEF60, 0x5145E47C, >+ 0xB92E00D6, 0xE80A4A64, 0x8A07FA77, 0xBA7D89A9, 0xEBED8022, 0x653AAF2B, 0xF118B03B, 0x6CC16544, >+ 0x96EB6583, 0xF4E27E35, 0x1ABB119E, 0x068D3EF2, 0xDAEAA8A5, 0x3C312A3D, 0x59538388, 0xA100772F, >+ 0xAB0165CE, 0x979959E7, 0x5DD8F53D, 0x189662BA, 0xFD021A9C, 0x6BC2D338, 0x1EFF667E, 0x40C66888, >+ 0x6E9F07FF, 0x0CEF442F, 0x82D20190, 0x4E8CAEAC, 0x0F7CB305, 0x2E73FBE7, 0x1CE884A2, 0x7A60BD52, >+ 0xC348B30D, 0x081CE3AA, 0xA12220E7, 0x38C7EC79, 0xCBD8DD3A, 0x62B4FBA5, 0xAD2A63DB, 0xE4D0852E, >+ 0x53DE980F, 0x9C8DDA59, 0xA6B4CEDE, 0xB48A7692, 0x0E2C46A4, 0xEB9367CB, 0x165D72EE, 0x75532B45, >+ 0xB9CA8E97, 0x08C8837B, 0x966F917B, 0x527515B4, 0xF27A5E5D, 0xB71E6267, 0x7603D7E6, 0x9837DD69}; // CUSTOM T >+ >+ uint8_t r[] = {0x06, 0x0A, 0x0F, 0x15, 0x05, 0x09, 0x0E, 0x14, 0x04, 0x0B, 0x10, 0x17, 0x07, 0x0C, 0x11, 0x16}; // STANDARD REORDERED >+ >+ uint8_t tIdxInit[] = {0, 1, 5, 0}; // STANDARD >+ uint8_t tIdxIncr[] = {1, 5, 3, 7}; // STANDARD >+ >+ uint32_t h[] = {0xEAD81D2E, 0xCE4DC6E9, 0xF9B5C301, 0x10325476}; // CUSTOM h0, h1, h2 STANDARD h3 >+ uint32_t dataLongs[0x10]; >+ >+ for(i = 0; i < 0x10; i++) >+ { >+ dataLongs[i] = (data[4 * i + 0] << 0) + (data[4 * i + 1] << 8) + (data[4 * i + 2] << 16) + (data[4 * i + 3] << 24); >+ } >+ >+ a = h[0]; >+ b = h[1]; >+ c = h[2]; >+ d = h[3]; >+ >+ for(i = 0; i < 4; i++) >+ { >+ g = tIdxInit[i]; >+ >+ for(j = 0; j < 16; j++) >+ { >+ if(i == 0) >+ { >+ f = (b & c) | (~b & d); >+ } >+ else if(i == 1) >+ { >+ f = (b & d) | (~d & c); >+ } >+ else if(i == 2) >+ { >+ f = (b ^ c ^ d); >+ } >+ else if (i == 3) >+ { >+ f = (~d | b) ^ c; >+ } >+ >+ f = dataLongs[g] + a + T[16 * i + j] + f; >+ >+ s = r[4 * i + (j & 3)]; >+ f = (f << s) | (f >> (32 - s)); >+ >+ a = d; >+ d = c; >+ c = b; >+ b += f; >+ >+ g = (g + tIdxIncr[i]) & 0xF; >+ } >+ } >+ >+ h[0] += a; >+ h[1] += b; >+ h[2] += c; >+ h[3] += d; >+ >+ for(i = 0; i < 4; i++) >+ { >+ hash[4 * i + 0] = h[i] >> 0; >+ hash[4 * i + 1] = h[i] >> 8; >+ hash[4 * i + 2] = h[i] >> 16; >+ hash[4 * i + 3] = h[i] >> 24; >+ } >+} >+ >+static void PowervuHashMode02(uint8_t *data, uint8_t *hash) >+{ >+ int i; >+ uint32_t a, b, c, d, e, f, tmp; >+ uint32_t h[] = {0x81887F3A, 0x36CCA480, 0x99056FB1, 0x79705BAE}; >+ uint32_t dataLongs[0x50]; >+ >+ for (i = 0; i < 0x10; i++) >+ { >+ dataLongs[i] = (data[4 * i + 0] << 24) + (data[4 * i + 1] << 16) + (data[4 * i + 2] << 8) + (data[4 * i + 3] << 0); >+ } >+ >+ for (i = 0; i < 0x40; i++) >+ { >+ dataLongs[0x10 + i] = dataLongs[0x10 + i - 2]; >+ dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 7]; >+ dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 13]; >+ dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 16]; >+ } >+ >+ a = dataLongs[0]; >+ b = dataLongs[1]; >+ c = dataLongs[2]; >+ d = dataLongs[3]; >+ e = dataLongs[4]; >+ >+ for (i = 0; i < 0x50; i++) >+ { >+ if (i < 0x15) f = (b & c) | (~b & d); >+ else if (i < 0x28) f = (b ^ c ^ d); >+ else if (i < 0x3D) f = (b & c) | (c & d) | (b & d); >+ else if (i < 0x50) f = (b ^ c ^ d); >+ >+ tmp = a; >+ a = e + f + (a << 5) + (a >> 27) + h[i / 0x14] + dataLongs[i]; >+ e = d; >+ d = c; >+ c = (b << 30) + (b >> 2); >+ b = tmp; >+ } >+ >+ dataLongs[0] += a; >+ dataLongs[1] += b; >+ dataLongs[2] += c; >+ dataLongs[3] += d; >+ >+ for (i = 0; i < 4; i++) >+ { >+ hash[4 * i + 0] = dataLongs[i] >> 24; >+ hash[4 * i + 1] = dataLongs[i] >> 16; >+ hash[4 * i + 2] = dataLongs[i] >> 8; >+ hash[4 * i + 3] = dataLongs[i] >> 0; >+ } >+} >+ >+static void PowervuHashMode03(uint8_t *data, uint8_t *hash) >+{ >+ int i, j, k, s, s2, tmp; >+ uint32_t a, b, c, d, f, g; >+ uint32_t a2, b2, c2, d2, f2, g2; >+ >+ uint32_t T[] = { 0xC88F3F2E, 0x967506BA, 0xDA877A7B, 0x0DECCDFE }; >+ uint32_t T2[] = { 0x01F42668, 0x39C7CDA5, 0xD490E2FE, 0x9965235D }; >+ >+ uint8_t r[] = { 0x0B, 0x0E, 0x0F, 0x0C, 0x05, 0x08, 0x07, 0x09, 0x0B, 0x0D, 0x0E, 0x0F, 0x06, 0x07, 0x09, 0x08, >+ 0x07, 0x06, 0x08, 0x0D, 0x0B, 0x09, 0x07, 0x0F, 0x07, 0x0C, 0x0F, 0x09, 0x0B, 0x07, 0x0D, 0x0C }; >+ >+ uint8_t tIdxIncr[] = { 0x07, 0x04, 0x0D, 0x01, 0x0A, 0x06, 0x0F, 0x03, 0x0C, 0x00, 0x09, 0x05, 0x02, 0x0E, 0x0B, 0x08, >+ 0x05, 0x0D, 0x02, 0x00, 0x04, 0x09, 0x03, 0x08, 0x01, 0x0A, 0x07, 0x0B, 0x06, 0x0F, 0x0C, 0x0E }; >+ >+ uint32_t h[] = { 0xC8616857, 0x9D3F5B8E, 0x4D7B8F76, 0x97BC8D80 }; >+ >+ uint32_t dataLongs[0x50]; >+ uint32_t result[4]; >+ >+ for (i = 0; i < 0x10; i++) >+ { >+ dataLongs[i] = (data[4 * i + 0] << 24) + (data[4 * i + 1] << 16) + (data[4 * i + 2] << 8) + (data[4 * i + 3] << 0); >+ } >+ >+ a = h[0]; >+ b = h[1]; >+ c = h[2]; >+ d = h[3]; >+ >+ a2 = h[3]; >+ b2 = h[2]; >+ c2 = h[1]; >+ d2 = h[0]; >+ >+ for (i = 0; i < 4; i++) >+ { >+ for (j = 0; j < 16; j++) >+ { >+ tmp = j; >+ >+ for (k = 0; k < i; k++) >+ { >+ tmp = tIdxIncr[tmp]; >+ } >+ >+ g = 0x0F - tmp; >+ g2 = tmp; >+ >+ if (i == 0) f = (b & d) | (~d & c); >+ else if (i == 1) f = (~c | b) ^ d; >+ else if (i == 2) f = (~b & d) | (b & c); >+ else if (i == 3) f = (b ^ c ^ d); >+ >+ if (i == 0) f2 = (b2 ^ c2 ^ d2); >+ else if (i == 1) f2 = (~b2 & d2) | (b2 & c2); >+ else if (i == 2) f2 = (~c2 | b2) ^ d2; >+ else if (i == 3) f2 = (b2 & d2) | (~d2 & c2); >+ >+ f = dataLongs[g] + a + T[i] + f; >+ s = r[0x0F + (((i & 1) ^ 1) << 4) - j]; >+ f = (f << s) | (f >> (32 - s)); >+ >+ f2 = dataLongs[g2] + a2 + T2[i] + f2; >+ s2 = r[((i & 1) << 4) + j]; >+ f2 = (f2 << s2) | (f2 >> (32 - s2)); >+ >+ a = d; >+ d = (c << 10) | (c >> 22); >+ c = b; >+ b = f; >+ >+ a2 = d2; >+ d2 = (c2 << 10) | (c2 >> 22); >+ c2 = b2; >+ b2 = f2; >+ } >+ } >+ >+ result[0] = h[3] + b + a2; >+ result[1] = h[2] + c + b2; >+ result[2] = h[1] + d + c2; >+ result[3] = h[0] + a + d2; >+ >+ for (i = 0; i < 4; i++) >+ { >+ hash[4 * i + 0] = result[i] >> 0; >+ hash[4 * i + 1] = result[i] >> 8; >+ hash[4 * i + 2] = result[i] >> 16; >+ hash[4 * i + 3] = result[i] >> 24; >+ } >+} >+ >+uint8_t table04[] = { 0x02, 0x03, 0x07, 0x0B, 0x0D, 0x08, 0x00, 0x01, 0x2B, 0x2D, 0x28, 0x20, 0x21, 0x0A, 0x0C, 0x0E, >+ 0x22, 0x36, 0x23, 0x27, 0x29, 0x24, 0x25, 0x26, 0x2A, 0x3C, 0x3E, 0x3F, 0x0F, 0x2C, 0x2E, 0x2F, >+ 0x12, 0x13, 0x17, 0x1B, 0x1C, 0x18, 0x10, 0x11, 0x19, 0x14, 0x15, 0x16, 0x1A, 0x09, 0x04, 0x05, >+ 0x32, 0x33, 0x37, 0x3B, 0x06, 0x1C, 0x1E, 0x1F, 0x3D, 0x38, 0x30, 0x31, 0x39, 0x34, 0x35, 0x3A }; >+ >+uint8_t table05[] = { 0x08, 0x09, 0x0A, 0x03, 0x04, 0x3F, 0x27, 0x28, 0x29, 0x2A, 0x05, 0x0B, 0x1B, 0x1C, 0x1C, 0x1E, >+ 0x20, 0x0C, 0x0D, 0x22, 0x23, 0x24, 0x00, 0x01, 0x02, 0x06, 0x07, 0x25, 0x26, 0x0E, 0x0F, 0x21, >+ 0x10, 0x11, 0x12, 0x2E, 0x2F, 0x13, 0x14, 0x15, 0x2B, 0x2C, 0x2D, 0x16, 0x17, 0x18, 0x19, 0x1A, >+ 0x30, 0x31, 0x37, 0x3B, 0x3C, 0x3D, 0x3E, 0x1F, 0x38, 0x39, 0x32, 0x33, 0x34, 0x35, 0x36, 0x3A }; >+ >+uint8_t table06[] = { 0x00, 0x01, 0x02, 0x06, 0x07, 0x08, 0x03, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x04, 0x05, 0x09, 0x0D, >+ 0x20, 0x21, 0x22, 0x26, 0x27, 0x3A, 0x3B, 0x3C, 0x3E, 0x3F, 0x10, 0x11, 0x12, 0x16, 0x17, 0x28, >+ 0x18, 0x13, 0x14, 0x15, 0x19, 0x1C, 0x1A, 0x1B, 0x1C, 0x1E, 0x1F, 0x23, 0x24, 0x25, 0x29, 0x2D, >+ 0x30, 0x31, 0x32, 0x36, 0x37, 0x38, 0x33, 0x34, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x35, 0x39, 0x3D }; >+ >+uint8_t table09[] = { 0x20, 0x21, 0x24, 0x22, 0x23, 0x2A, 0x2B, 0x33, 0x35, 0x38, 0x39, 0x36, 0x2D, 0x2C, 0x2E, 0x2F, >+ 0x00, 0x01, 0x04, 0x02, 0x25, 0x28, 0x08, 0x09, 0x06, 0x07, 0x0A, 0x0B, 0x0D, 0x0C, 0x0E, 0x0F, >+ 0x10, 0x11, 0x14, 0x12, 0x13, 0x15, 0x19, 0x16, 0x29, 0x26, 0x03, 0x17, 0x1A, 0x1C, 0x1C, 0x1E, >+ 0x30, 0x31, 0x34, 0x32, 0x37, 0x3A, 0x3B, 0x3D, 0x3C, 0x3E, 0x3F, 0x1B, 0x05, 0x18, 0x27, 0x1F }; >+ >+static void PowervuHashModes04to0ATables(uint8_t *data, uint8_t *hash, uint8_t *table) >+{ >+ int i; >+ >+ for (i = 0; i < 0x10; i++) >+ { >+ hash[i] = table[i]; >+ hash[i] ^= data[table[i]]; >+ hash[i] ^= table[0x10 + i]; >+ hash[i] ^= data[table[0x10 + i]]; >+ hash[i] ^= table[0x20 + i]; >+ hash[i] ^= data[table[0x20 + i]]; >+ hash[i] ^= table[0x30 + i]; >+ hash[i] ^= data[table[0x30 + i]]; >+ } >+} >+ >+static void PowervuCreateHash(uint8_t *data, int len, uint8_t *hash, int mode) >+{ >+ uint8_t dataPadded[0x40]; >+ >+ PowervuPadData(data, len, dataPadded); >+ >+ switch(mode) >+ { >+ case 1: >+ PowervuHashMode01CustomMD5(dataPadded, hash); >+ break; >+ >+ case 2: >+ PowervuHashMode02(dataPadded, hash); >+ break; >+ >+ case 3: >+ PowervuHashMode03(dataPadded, hash); >+ break; >+ >+ case 4: >+ PowervuHashModes04to0ATables(dataPadded, hash, table04); >+ break; >+ >+ case 5: >+ PowervuHashModes04to0ATables(dataPadded, hash, table05); >+ break; >+ >+ case 6: >+ PowervuHashModes04to0ATables(dataPadded, hash, table06); >+ break; >+ >+ case 9: >+ PowervuHashModes04to0ATables(dataPadded, hash, table09); >+ break; >+ >+ default: >+ cs_log("A new hash mode [%d] is in use.", mode); >+ break; >+ } >+} >+ >+static void PowervuCreateDataEcmEmm(uint8_t *emmEcm, uint8_t *pos, int lenHeader, int len, uint8_t *data) >+{ >+ int i; >+ >+ for(i = 0; i < len; i++) >+ { >+ data[i] = emmEcm[lenHeader + pos[i]]; >+ } >+} >+ >+static uint8_t PowervuCreateDataCw(uint8_t *seed, uint8_t lenSeed, uint8_t *baseCw, uint8_t val, uint8_t *seedEcmCw, uint8_t *data) >+{ >+ int i; >+ >+ for(i = 0; i < lenSeed; i++) >+ { >+ data[i] = seed[i]; >+ } >+ >+ for(i = 0; i < 7; i++) >+ { >+ data[lenSeed + i] = baseCw[i]; >+ } >+ >+ data[lenSeed + 7] = val; >+ >+ for(i = 0; i < 16; i++) >+ { >+ data[lenSeed + 7 + 1 + i] = seedEcmCw[i]; >+ } >+ >+ return lenSeed + 7 + 1 + 0x10; >+} >+ >+static uint8_t PowervuUnmaskEcm(uint8_t *ecm, uint8_t *seedEcmCw) >+{ >+ int i, l; >+ >+ uint8_t sourcePos[] = {0x04, 0x05, 0x06, 0x07, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x17, 0x1C, 0x1D, 0x1F, 0x23, >+ 0x24, 0x25, 0x26, 0x27, 0x29, 0x2C, 0x2D, 0x2E}; >+ uint8_t destPos[] = {0x08, 0x09, 0x11, 0x18, 0x19, 0x1A, 0x1B, 0x1E, 0x20, 0x21, 0x22, 0x28, 0x2A, 0x2B, 0x2F, 0x30}; >+ uint8_t seedCwPos[] = {0x07, 0x0A, 0x04, 0x0D, 0x05, 0x0E, 0x06, 0x0B, 0x10, 0x0C, 0x0F}; >+ >+ uint8_t data[0x18]; >+ uint8_t mask[0x10]; >+ uint8_t hashModeEcm; >+ uint8_t hashModeCw; >+ uint32_t crc; >+ >+ // Create seed for CW decryption >+ memset(seedEcmCw, 0, 0x10); >+ >+ int extraBytesLen = ecm[9]; >+ int startOffset = extraBytesLen + 0x0A; >+ >+ for (i = 0; i < 0x0B; i++) >+ { >+ seedEcmCw[i] = ecm[startOffset + seedCwPos[i]]; >+ } >+ >+ // Read hash mode CW >+ hashModeCw = ecm[28 + extraBytesLen] ^ PowervuCrc8Calc(seedEcmCw, 0x10); >+ >+ // Create mask for ECM decryption >+ PowervuCreateDataEcmEmm(ecm, sourcePos, startOffset, 0x18, data); >+ >+ hashModeEcm = ecm[8] ^ PowervuCrc8Calc(data, 0x18); >+ >+ PowervuCreateHash(data, 0x18, mask, hashModeEcm); >+ >+ // Fix header >+ ecm[3] &= 0x0F; >+ ecm[3] |= 0x30; >+ ecm[8] = 0x00; >+ ecm[28 + extraBytesLen] = 0x00; >+ >+ // Unmask body >+ for (i = 0; i < 0x10; i++) >+ { >+ ecm[startOffset + destPos[i]] ^= mask[i & 0x0F]; >+ } >+ >+ // Fix CRC (optional) >+ l = (((ecm[1] << 8) + ecm[2]) & 0xFFF) + 3 - 4; >+ >+ crc = fletcher_crc32(ecm, l); >+ >+ ecm[l + 0] = crc >> 24; >+ ecm[l + 1] = crc >> 16; >+ ecm[l + 2] = crc >> 8; >+ ecm[l + 3] = crc >> 0; >+ >+ return hashModeCw; >+} >+ >+static void PowervuCreateCw(uint8_t *seed, uint8_t lenSeed, uint8_t *baseCw, uint8_t val, >+ uint8_t *seedEcmCw, uint8_t *cw, int modeDesCsa, int hashMode) >+{ >+ uint8_t tableFixParity[] = {0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B, 0x0D, 0x0D, 0x0E, 0x0E, >+ 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, 0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, >+ 0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F, >+ 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3B, 0x3B, 0x3D, 0x3D, 0x3E, 0x3E, >+ 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, 0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, >+ 0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E, >+ 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6B, 0x6B, 0x6D, 0x6D, 0x6E, 0x6E, >+ 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, 0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, >+ 0x80, 0x80, 0x83, 0x83, 0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F, >+ 0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9B, 0x9B, 0x9D, 0x9D, 0x9E, 0x9E, >+ 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7, 0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, >+ 0xB0, 0xB0, 0xB3, 0xB3, 0xB5, 0xB5, 0xB6, 0xB6, 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF, >+ 0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, 0xC8, 0xC8, 0xCB, 0xCB, 0xCD, 0xCD, 0xCE, 0xCE, >+ 0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6, 0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, >+ 0xE0, 0xE0, 0xE3, 0xE3, 0xE5, 0xE5, 0xE6, 0xE6, 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF, >+ 0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, 0xF8, 0xF8, 0xFB, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE}; >+ >+ uint8_t data[0x1C]; >+ uint8_t hash[0x10]; >+ uint8_t lenData; >+ int i; >+ >+ lenData = PowervuCreateDataCw(seed, lenSeed, baseCw, val, seedEcmCw, data); >+ PowervuCreateHash(data, lenData, hash, hashMode); >+ >+ for(i = 0; i < 8; i++) >+ { >+ cw[i] = hash[i]; >+ } >+ >+ if(modeDesCsa == 0) // DES - Fix Parity Bits >+ { >+ for(i = 0; i < 8; i++) >+ { >+ cw[i] = tableFixParity[cw[i]]; >+ } >+ } >+ else if(modeDesCsa == 1) // CSA - Fix Checksums >+ { >+ cw[3] = cw[0] + cw[1] + cw[2]; >+ cw[7] = cw[4] + cw[5] + cw[6]; >+ } >+} >+ >+static int8_t GetPowervuKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey, uint32_t keyRef) >+{ >+ char keyStr[EMU_MAX_CHAR_KEYNAME]; >+ >+ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); >+ if(FindKey('P', ident, 0xFFFF0000, keyStr, buf, keyLength, isCriticalKey, keyRef, 0, NULL)) { >+ return 1; >+ } >+ >+ return 0; >+} >+ >+static int8_t GetPowervuEmmKey(uint8_t *buf, uint32_t ident, char *keyName, uint32_t keyLength, uint8_t isCriticalKey, uint32_t keyRef, uint32_t *getProvider) >+{ >+ if(FindKey('P', ident, 0xFFFFFFFF, keyName, buf, keyLength, isCriticalKey, keyRef, 0, getProvider)) { >+ return 1; >+ } >+ >+ return 0; >+} >+ >+static const uint8_t PowerVu_A0_S_1[16] = {0x33, 0xA4, 0x44, 0x3C, 0xCA, 0x2E, 0x75, 0x7B, 0xBC, 0xE6, 0xE5, 0x35, 0xA0, 0x55, 0xC9, 0xA2}; >+static const uint8_t PowerVu_A0_S_2[16] = {0x5A, 0xB0, 0x2C, 0xBC, 0xDA, 0x32, 0xE6, 0x92, 0x40, 0x53, 0x6E, 0xF9, 0x69, 0x11, 0x1E, 0xFB}; >+static const uint8_t PowerVu_A0_S_3[16] = {0x4E, 0x18, 0x9B, 0x19, 0x79, 0xFB, 0x01, 0xFA, 0xE3, 0xE1, 0x28, 0x3D, 0x32, 0xE4, 0x92, 0xEA}; >+static const uint8_t PowerVu_A0_S_4[16] = {0x05, 0x6F, 0x37, 0x66, 0x35, 0xE1, 0x58, 0xD0, 0xB4, 0x6A, 0x97, 0xAE, 0xD8, 0x91, 0x27, 0x56}; >+static const uint8_t PowerVu_A0_S_5[16] = {0x7B, 0x26, 0xAD, 0x34, 0x3D, 0x77, 0x39, 0x51, 0xE0, 0xE0, 0x48, 0x8C, 0x39, 0xF5, 0xE8, 0x47}; >+static const uint8_t PowerVu_A0_S_6[16] = {0x74, 0xFA, 0x4D, 0x79, 0x42, 0x39, 0xD1, 0xA4, 0x99, 0xA3, 0x97, 0x07, 0xDF, 0x14, 0x3A, 0xC4}; >+static const uint8_t PowerVu_A0_S_7[16] = {0xC6, 0x1E, 0x3C, 0x24, 0x11, 0x08, 0x5D, 0x6A, 0xEB, 0x97, 0xB9, 0x25, 0xA7, 0xFA, 0xE9, 0x1A}; >+static const uint8_t PowerVu_A0_S_8[16] = {0x9A, 0xAD, 0x72, 0xD7, 0x7C, 0x68, 0x3B, 0x55, 0x1D, 0x4A, 0xA2, 0xB0, 0x38, 0xB9, 0x56, 0xD0}; >+static const uint8_t PowerVu_A0_S_9[32] = {0x61, 0xDA, 0x5F, 0xB7, 0xEB, 0xC6, 0x3F, 0x6C, 0x09, 0xF3, 0x64, 0x38, 0x33, 0x08, 0xAA, 0x15, >+ 0xCC, 0xEF, 0x22, 0x64, 0x01, 0x2C, 0x12, 0xDE, 0xF4, 0x6E, 0x3C, 0xCD, 0x1A, 0x64, 0x63, 0x7C >+ }; >+ >+static const uint8_t PowerVu_00_S_1[16] = {0x97, 0x13, 0xEB, 0x6B, 0x04, 0x5E, 0x60, 0x3A, 0xD9, 0xCC, 0x91, 0xC2, 0x5A, 0xFD, 0xBA, 0x0C}; >+static const uint8_t PowerVu_00_S_2[16] = {0x61, 0x3C, 0x03, 0xB0, 0xB5, 0x6F, 0xF8, 0x01, 0xED, 0xE0, 0xE5, 0xF3, 0x78, 0x0F, 0x0A, 0x73}; >+static const uint8_t PowerVu_00_S_3[16] = {0xFD, 0xDF, 0xD2, 0x97, 0x06, 0x14, 0x91, 0xB5, 0x36, 0xAD, 0xBC, 0xE1, 0xB3, 0x00, 0x66, 0x41}; >+static const uint8_t PowerVu_00_S_4[16] = {0x8B, 0xD9, 0x18, 0x0A, 0xED, 0xEE, 0x61, 0x34, 0x1A, 0x79, 0x80, 0x8C, 0x1E, 0x7F, 0xC5, 0x9F}; >+static const uint8_t PowerVu_00_S_5[16] = {0xB0, 0xA1, 0xF2, 0xB8, 0xEA, 0x72, 0xDD, 0xD3, 0x30, 0x65, 0x2B, 0x1E, 0xE9, 0xE1, 0x45, 0x29}; >+static const uint8_t PowerVu_00_S_6[16] = {0x5D, 0xCA, 0x53, 0x75, 0xB2, 0x24, 0xCE, 0xAF, 0x21, 0x54, 0x9E, 0xBE, 0x02, 0xA9, 0x4C, 0x5D}; >+static const uint8_t PowerVu_00_S_7[16] = {0x42, 0x66, 0x72, 0x83, 0x1B, 0x2D, 0x22, 0xC9, 0xF8, 0x4D, 0xBA, 0xCD, 0xBB, 0x20, 0xBD, 0x6B}; >+static const uint8_t PowerVu_00_S_8[16] = {0xC4, 0x0C, 0x6B, 0xD3, 0x6D, 0x94, 0x7E, 0x53, 0xCE, 0x96, 0xAC, 0x40, 0x2C, 0x7A, 0xD3, 0xA9}; >+static const uint8_t PowerVu_00_S_9[32] = {0x31, 0x82, 0x4F, 0x9B, 0xCB, 0x6F, 0x9D, 0xB7, 0xAE, 0x68, 0x0B, 0xA0, 0x93, 0x15, 0x32, 0xE2, >+ 0xED, 0xE9, 0x47, 0x29, 0xC2, 0xA8, 0x92, 0xEF, 0xBA, 0x27, 0x22, 0x57, 0x76, 0x54, 0xC0, 0x59, >+ }; >+ >+static uint8_t PowervuSbox(uint8_t *input, uint8_t mode) >+{ >+ uint8_t s_index, bit, last_index, last_bit; >+ uint8_t const *Sbox1, *Sbox2, *Sbox3, *Sbox4, *Sbox5, *Sbox6, *Sbox7, *Sbox8, *Sbox9; >+ >+ if(mode) >+ { >+ Sbox1 = PowerVu_A0_S_1; >+ Sbox2 = PowerVu_A0_S_2; >+ Sbox3 = PowerVu_A0_S_3; >+ Sbox4 = PowerVu_A0_S_4; >+ Sbox5 = PowerVu_A0_S_5; >+ Sbox6 = PowerVu_A0_S_6; >+ Sbox7 = PowerVu_A0_S_7; >+ Sbox8 = PowerVu_A0_S_8; >+ Sbox9 = PowerVu_A0_S_9; >+ } >+ else >+ { >+ Sbox1 = PowerVu_00_S_1; >+ Sbox2 = PowerVu_00_S_2; >+ Sbox3 = PowerVu_00_S_3; >+ Sbox4 = PowerVu_00_S_4; >+ Sbox5 = PowerVu_00_S_5; >+ Sbox6 = PowerVu_00_S_6; >+ Sbox7 = PowerVu_00_S_7; >+ Sbox8 = PowerVu_00_S_8; >+ Sbox9 = PowerVu_00_S_9; >+ } >+ >+ bit = (GetBit(input[2],0)<<2) | (GetBit(input[3],4)<<1) | (GetBit(input[5],3)); >+ s_index = (GetBit(input[0],0)<<3) | (GetBit(input[2],6)<<2) | (GetBit(input[2],4)<<1) | (GetBit(input[5],7)); >+ last_bit = GetBit(Sbox1[s_index],7-bit); >+ >+ bit = (GetBit(input[5],0)<<2) | (GetBit(input[4],0)<<1) | (GetBit(input[6],2)); >+ s_index = (GetBit(input[2],1)<<3) | (GetBit(input[2],2)<<2) | (GetBit(input[5],5)<<1) | (GetBit(input[5],1)); >+ last_bit = last_bit | (GetBit(Sbox2[s_index],7-bit)<<1); >+ >+ bit = (GetBit(input[6],0)<<2) | (GetBit(input[1],7)<<1) | (GetBit(input[6],7)); >+ s_index = (GetBit(input[1],3)<<3) | (GetBit(input[3],7)<<2) | (GetBit(input[1],5)<<1) | (GetBit(input[5],2)); >+ last_bit = last_bit | (GetBit(Sbox3[s_index], 7-bit)<<2); >+ >+ bit = (GetBit(input[1],0)<<2) | (GetBit(input[2],7)<<1) | (GetBit(input[2],5)); >+ s_index = (GetBit(input[6],3)<<3) | (GetBit(input[6],4)<<2) | (GetBit(input[6],6)<<1) | (GetBit(input[3],5)); >+ last_index = GetBit(Sbox4[s_index], 7-bit); >+ >+ bit = (GetBit(input[3],3)<<2) | (GetBit(input[4],6)<<1) | (GetBit(input[3],2)); >+ s_index = (GetBit(input[3],1)<<3) | (GetBit(input[4],5)<<2) | (GetBit(input[3],0)<<1) | (GetBit(input[4],7)); >+ last_index = last_index | (GetBit(Sbox5[s_index], 7-bit)<<1); >+ >+ bit = (GetBit(input[5],4)<<2) | (GetBit(input[4],4)<<1) | (GetBit(input[1],2)); >+ s_index = (GetBit(input[2],3)<<3) | (GetBit(input[6],5)<<2) | (GetBit(input[1],4)<<1) | (GetBit(input[4],1)); >+ last_index = last_index | (GetBit(Sbox6[s_index], 7-bit)<<2); >+ >+ bit = (GetBit(input[0],6)<<2) | (GetBit(input[0],7)<<1) | (GetBit(input[0],4)); >+ s_index = (GetBit(input[0],5)<<3) | (GetBit(input[0],3)<<2) | (GetBit(input[0],1)<<1) | (GetBit(input[0],2)); >+ last_index = last_index | (GetBit(Sbox7[s_index], 7-bit)<<3); >+ >+ bit = (GetBit(input[4],2)<<2) | (GetBit(input[4],3)<<1) | (GetBit(input[1],1)); >+ s_index = (GetBit(input[1],6)<<3) | (GetBit(input[6],1)<<2) | (GetBit(input[5],6)<<1) | (GetBit(input[3],6)); >+ last_index = last_index | (GetBit(Sbox8[s_index], 7-bit)<<4); >+ >+ return (GetBit(Sbox9[last_index&0x1f],7-last_bit)&1) ? 1: 0; >+} >+ >+static void PowervuDecrypt(uint8_t *data, uint32_t length, uint8_t *key, uint8_t sbox) >+{ >+ uint32_t i; >+ int32_t j, k; >+ uint8_t curByte, tmpBit; >+ >+ for(i = 0; i < length; i++) >+ { >+ curByte = data[i]; >+ >+ for(j = 7; j >= 0; j--) >+ { >+ data[i] = SetBit(data[i], j, (GetBit(curByte, j)^PowervuSbox(key, sbox))^GetBit(key[0], 7)); >+ >+ tmpBit = GetBit(data[i], j)^(GetBit(key[6], 0)); >+ if (tmpBit) >+ { >+ key[3] ^= 0x10; >+ } >+ >+ for (k = 6; k > 0; k--) >+ { >+ key[k] = (key[k]>>1) | (key[k-1]<<7); >+ } >+ key[0] = (key[0]>>1); >+ >+ key[0] = SetBit(key[0], 7, tmpBit); >+ } >+ } >+} >+ >+#define PVU_CW_VID 0 // VIDeo >+#define PVU_CW_HSD 1 // High Speed Data >+#define PVU_CW_A1 2 // Audio 1 >+#define PVU_CW_A2 3 // Audio 2 >+#define PVU_CW_A3 4 // Audio 3 >+#define PVU_CW_A4 5 // Audio 4 >+#define PVU_CW_UTL 6 // UTiLity >+#define PVU_CW_VBI 7 // Vertical Blanking Interval >+ >+#define PVU_CONVCW_VID_ECM 0x80 // VIDeo >+#define PVU_CONVCW_HSD_ECM 0x40 // High Speed Data >+#define PVU_CONVCW_A1_ECM 0x20 // Audio 1 >+#define PVU_CONVCW_A2_ECM 0x10 // Audio 2 >+#define PVU_CONVCW_A3_ECM 0x08 // Audio 3 >+#define PVU_CONVCW_A4_ECM 0x04 // Audio 4 >+#define PVU_CONVCW_UTL_ECM 0x02 // UTiLity >+#define PVU_CONVCW_VBI_ECM 0x01 // Vertical Blanking Interval >+ >+static uint8_t PowervuGetConvcwIndex(uint8_t ecmTag) >+{ >+ switch(ecmTag) >+ { >+ case PVU_CONVCW_VID_ECM: >+ return PVU_CW_VID; >+ >+ case PVU_CONVCW_HSD_ECM: >+ return PVU_CW_HSD; >+ >+ case PVU_CONVCW_A1_ECM: >+ return PVU_CW_A1; >+ >+ case PVU_CONVCW_A2_ECM: >+ return PVU_CW_A2; >+ >+ case PVU_CONVCW_A3_ECM: >+ return PVU_CW_A3; >+ >+ case PVU_CONVCW_A4_ECM: >+ return PVU_CW_A4; >+ >+ case PVU_CONVCW_UTL_ECM: >+ return PVU_CW_UTL; >+ >+ case PVU_CONVCW_VBI_ECM: >+ return PVU_CW_VBI; >+ >+ default: >+ return PVU_CW_VBI; >+ } >+} >+ >+static uint16_t PowervuGetSeedIV(uint8_t seedType, uint8_t *ecm) >+{ >+ switch(seedType) >+ { >+ case PVU_CW_VID: >+ return ((ecm[0x10] & 0x1F) <<3) | 0; >+ case PVU_CW_HSD: >+ return ((ecm[0x12] & 0x1F) <<3) | 2; >+ case PVU_CW_A1: >+ return ((ecm[0x11] & 0x3F) <<3) | 1; >+ case PVU_CW_A2: >+ return ((ecm[0x13] & 0x3F) <<3) | 1; >+ case PVU_CW_A3: >+ return ((ecm[0x19] & 0x3F) <<3) | 1; >+ case PVU_CW_A4: >+ return ((ecm[0x1A] & 0x3F) <<3) | 1;; >+ case PVU_CW_UTL: >+ return ((ecm[0x14] & 0x0F) <<3) | 4; >+ case PVU_CW_VBI: >+ return (((ecm[0x15] & 0xF8)>>3)<<3) | 5; >+ default: >+ return 0; >+ } >+} >+ >+static uint8_t PowervuExpandSeed(uint8_t seedType, uint8_t *seed) >+{ >+ uint8_t seedLength = 0, i; >+ >+ switch(seedType) >+ { >+ case PVU_CW_VID: >+ case PVU_CW_HSD: >+ seedLength = 4; >+ break; >+ case PVU_CW_A1: >+ case PVU_CW_A2: >+ case PVU_CW_A3: >+ case PVU_CW_A4: >+ seedLength = 3; >+ break; >+ case PVU_CW_UTL: >+ case PVU_CW_VBI: >+ seedLength = 2; >+ break; >+ default: >+ return seedLength; >+ } >+ >+ for(i=seedLength; i<7; i++) >+ { >+ seed[i] = seed[i%seedLength]; >+ } >+ >+ return seedLength; >+} >+ >+static void PowervuCalculateSeed(uint8_t seedType, uint8_t *ecm, uint8_t *seedBase, uint8_t *key, uint8_t *seed, uint8_t sbox) >+{ >+ uint16_t tmpSeed; >+ >+ tmpSeed = PowervuGetSeedIV(seedType, ecm+23); >+ seed[0] = (tmpSeed >> 2) & 0xFF; >+ seed[1] = ((tmpSeed & 0x3) << 6) | (seedBase[0] >> 2); >+ seed[2] = ( seedBase[0] << 6) | (seedBase[1] >> 2); >+ seed[3] = ( seedBase[1] << 6) | (seedBase[2] >> 2); >+ seed[4] = ( seedBase[2] << 6) | (seedBase[3] >> 2); >+ seed[5] = ( seedBase[3] << 6); >+ >+ PowervuDecrypt(seed, 6, key, sbox); >+ >+ seed[0] = (seed[1] << 2) | (seed[2] >> 6); >+ seed[1] = (seed[2] << 2) | (seed[3] >> 6); >+ seed[2] = (seed[3] << 2) | (seed[4] >> 6); >+ seed[3] = (seed[4] << 2) | (seed[5] >> 6); >+} >+ >+static void PowervuCalculateCw(uint8_t seedType, uint8_t *seed, uint8_t csaUsed, uint8_t *convolvedCw, >+ uint8_t *cw, uint8_t *baseCw, uint8_t *seedEcmCw, uint8_t hashModeCw, >+ uint8_t needsUnmasking, uint8_t xorMode) >+{ >+ int32_t k; >+ uint8_t seedLength, val = 0; >+ >+ seedLength = PowervuExpandSeed(seedType, seed); >+ >+ if(csaUsed) >+ { >+ if(!needsUnmasking || (hashModeCw == 0)) >+ { >+ for(k = 0; k < 7; k++) >+ { >+ seed[k] ^= baseCw[k]; >+ } >+ >+ cw[0] = seed[0] ^ convolvedCw[0]; >+ cw[1] = seed[1] ^ convolvedCw[1]; >+ cw[2] = seed[2] ^ convolvedCw[2]; >+ cw[3] = seed[3] ^ convolvedCw[3]; >+ cw[4] = seed[3] ^ convolvedCw[4]; >+ cw[5] = seed[4] ^ convolvedCw[5]; >+ cw[6] = seed[5] ^ convolvedCw[6]; >+ cw[7] = seed[6] ^ convolvedCw[7]; >+ } >+ } >+ else >+ { >+ if(xorMode == 0) >+ { >+ for(k = 0; k < 7; k++) >+ { >+ cw[k] = seed[k] ^ baseCw[k]; >+ } >+ } >+ >+ if(xorMode == 1) >+ { >+ for(k = 0; k < 3; k++) >+ { >+ cw[k] = seed[k] ^ baseCw[k]; >+ } >+ >+ for(k = 3; k < 7; k++) >+ { >+ cw[k] = baseCw[k]; >+ } >+ } >+ >+ ExpandDesKey(cw); >+ } >+ >+ if(needsUnmasking && (hashModeCw > 0)) >+ { >+ switch(seedType) >+ { >+ case PVU_CW_VID: >+ val = 0; >+ break; >+ >+ case PVU_CW_A1: >+ case PVU_CW_A2: >+ case PVU_CW_A3: >+ case PVU_CW_A4: >+ val = 1; >+ break; >+ >+ case PVU_CW_HSD: >+ val = 2; >+ break; >+ >+ case PVU_CW_UTL: >+ val = 4; >+ break; >+ >+ case PVU_CW_VBI: >+ val = 5; >+ break; >+ } >+ PowervuCreateCw(seed, seedLength, baseCw, val, seedEcmCw, cw, csaUsed, hashModeCw); >+ } >+} >+ >+#ifdef WITH_EMU >+int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, uint16_t srvid, emu_stream_client_key_data *cdata, EXTENDED_CW* cw_ex) >+#else >+int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, emu_stream_client_key_data *cdata) >+#endif >+{ >+ int8_t ret = 1; >+ uint16_t ecmLen = GetEcmLen(ecm); >+ uint32_t ecmCrc32; >+ uint8_t nanoCmd, nanoChecksum, keyType, fixedKey, oddKey, bid, csaUsed; >+ uint16_t nanoLen; >+ uint32_t channelId, ecmSrvid, keyIndex; >+ uint32_t i, j, k; >+ uint8_t convolvedCw[8][8]; >+ uint8_t ecmKey[7], tmpEcmKey[7], seedBase[4], baseCw[7], seed[8][8], cw[8][8]; >+ uint8_t decrypt_ok; >+ uint8_t ecmPart1[14], ecmPart2[27]; >+ uint8_t sbox; >+ uint32_t keyRef1, keyRef2; >+ uint8_t calculateAllCws; >+ uint8_t seedEcmCw[0x10]; >+ uint8_t hashModeCw = 0, needsUnmasking, xorMode; >+#ifdef WITH_EMU >+ uint8_t *dwp; >+ emu_stream_cw_item *cw_item; >+ int8_t update_global_key = 0; >+ int8_t update_global_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+ >+ memset(update_global_keys, 0, sizeof(update_global_keys)); >+#endif >+ >+ if(ecmLen < 7) >+ { >+ return 1; >+ } >+ >+ needsUnmasking = (ecm[3] & 0xF0) == 0x50; >+ >+ if(needsUnmasking) >+ { >+ hashModeCw = PowervuUnmaskEcm(ecm, seedEcmCw); >+ } >+ >+ ecmCrc32 = b2i(4, ecm+ecmLen-4); >+ >+ if(fletcher_crc32(ecm, ecmLen-4) != ecmCrc32) >+ { >+ return 8; >+ } >+ ecmLen -= 4; >+ >+ for(i = 0; i < 8; i++) { >+ memset(convolvedCw[i], 0, 8); >+ } >+ >+ for(i = 3; i+3 < ecmLen; ) { >+ nanoLen = (((ecm[i] & 0x0f) << 8) | ecm[i+1]); >+ i += 2; >+ if(nanoLen > 0) >+ { >+ nanoLen--; >+ } >+ nanoCmd = ecm[i++]; >+ if(i+nanoLen > ecmLen) { >+ return 1; >+ } >+ >+ switch (nanoCmd) { >+ case 0x27: >+ if(nanoLen < 15) >+ { >+ break; >+ } >+ >+ nanoChecksum = 0; >+ for(j = 4; j < 15; j++) >+ { >+ nanoChecksum += ecm[i+j]; >+ } >+ >+ if(nanoChecksum != 0) >+ { >+ break; >+ } >+ >+ keyType = PowervuGetConvcwIndex(ecm[i+4]); >+ memcpy(convolvedCw[keyType], &ecm[i+6], 8); >+ break; >+ >+ default: >+ break; >+ } >+ i += nanoLen; >+ } >+ >+ for(i = 3; i+3 < ecmLen; ) { >+ nanoLen = (((ecm[i] & 0x0f) << 8) | ecm[i+1]); >+ i += 2; >+ if(nanoLen > 0) >+ { >+ nanoLen--; >+ } >+ nanoCmd = ecm[i++]; >+ if(i+nanoLen > ecmLen) { >+ return 1; >+ } >+ >+ switch (nanoCmd) { >+ case 0x20: >+ if(nanoLen < 54) >+ { >+ break; >+ } >+ >+ i += ecm[i + 3]; // Extra Data Length >+ >+ csaUsed = GetBit(ecm[i+7], 7); >+ fixedKey = !GetBit(ecm[i+6], 5); >+ oddKey = GetBit(ecm[i+6], 4); >+ xorMode = GetBit(ecm[i+6], 0); >+ bid = (GetBit(ecm[i+7], 1) << 1) | GetBit(ecm[i+7], 0); >+ sbox = GetBit(ecm[i+6], 3); >+ >+ keyIndex = (fixedKey << 3) | (bid << 2) | oddKey; >+ channelId = b2i(2, ecm+i+23); >+ ecmSrvid = (channelId >> 4) | ((channelId & 0xF) << 12); >+ >+ decrypt_ok = 0; >+ >+ memcpy(ecmPart1, ecm+i+8, 14); >+ memcpy(ecmPart2, ecm+i+27, 27); >+ >+ keyRef1 = 0; >+ keyRef2 = 0; >+ >+ do >+ { >+ if(!GetPowervuKey(ecmKey, ecmSrvid, '0', keyIndex, 7, 0, keyRef1++)) >+ { >+ if(!GetPowervuKey(ecmKey, channelId, '0', keyIndex, 7, 0, keyRef2++)) >+ { >+ cs_log("Key not found: P %04X 0%X", ecmSrvid, keyIndex); >+ return 2; >+ } >+ } >+ >+ PowervuDecrypt(ecm+i+8, 14, ecmKey, sbox); >+ if((ecm[i+6] != ecm[i+6+7]) || (ecm[i+6+8] != ecm[i+6+15])) >+ { >+ memcpy(ecm+i+8, ecmPart1, 14); >+ continue; >+ } >+ >+ memcpy(tmpEcmKey, ecmKey, 7); >+ >+ PowervuDecrypt(ecm+i+27, 27, ecmKey, sbox); >+ if((ecm[i+23] != ecm[i+23+29]) || (ecm[i+23+1] != ecm[i+23+30])) >+ { >+ memcpy(ecm+i+8, ecmPart1, 14); >+ memcpy(ecm+i+27, ecmPart2, 27); >+ continue; >+ } >+ >+ decrypt_ok = 1; >+ } >+ while(!decrypt_ok); >+ >+ memcpy(seedBase, ecm+i+6+2, 4); >+ >+#ifdef WITH_EMU >+ if(cdata == NULL) >+ { >+ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); >+ for(j = 0; j < EMU_STREAM_SERVER_MAX_CONNECTIONS; j++) >+ { >+ if(!stream_server_has_ecm[j] && emu_stream_cur_srvid[j] == srvid) >+ { >+ update_global_key = 1; >+ update_global_keys[j] = 1; >+ } >+ } >+ SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); >+ } >+ >+ if(cdata != NULL || update_global_key || cw_ex != NULL) >+#else >+ if(cdata != NULL) >+#endif >+ { >+ // Calculate all seeds >+ for(j = 0; j < 8; j++) >+ { >+ memcpy(ecmKey, tmpEcmKey, 7); >+ PowervuCalculateSeed(j, ecm+i, seedBase, ecmKey, seed[j], sbox); >+ } >+ } >+ else >+ { >+ // Calculate only video seed >+ memcpy(ecmKey, tmpEcmKey, 7); >+ PowervuCalculateSeed(PVU_CW_VID, ecm+i, seedBase, ecmKey, seed[PVU_CW_VID], sbox); >+ } >+ >+ memcpy(baseCw, ecm+i+6+8, 7); >+ >+#ifdef WITH_EMU >+ calculateAllCws = cdata != NULL || update_global_key || cw_ex != NULL; >+#else >+ calculateAllCws = cdata != NULL; >+#endif >+ if(calculateAllCws) >+ { >+ // Calculate all cws >+ for(j = 0; j < 8; j++) >+ { >+ PowervuCalculateCw(j, seed[j], csaUsed, convolvedCw[j], cw[j], baseCw, >+ seedEcmCw, hashModeCw, needsUnmasking, xorMode); >+ >+ if(csaUsed) >+ { >+ for(k = 0; k < 8; k += 4) { >+ cw[j][k + 3] = ((cw[j][k] + cw[j][k + 1] + cw[j][k + 2]) & 0xff); >+ } >+ } >+ } >+ >+#ifdef WITH_EMU >+ if(update_global_key) >+ { >+ for(j = 0; j < EMU_STREAM_SERVER_MAX_CONNECTIONS; j++) >+ { >+ if(update_global_keys[j]) >+ { >+ cw_item = (emu_stream_cw_item*)malloc(sizeof(emu_stream_cw_item)); >+ if(cw_item != NULL) >+ { >+ cw_item->csa_used = csaUsed; >+ cw_item->is_even = ecm[0] == 0x80 ? 1 : 0; >+ cs_ftime(&cw_item->write_time); >+ add_ms_to_timeb(&cw_item->write_time, cfg.emu_stream_ecm_delay); >+ memcpy(cw_item->cw, cw, sizeof(cw)); >+ ll_append(ll_emu_stream_delayed_keys[j], cw_item); >+ } >+ } >+ } >+ } >+ >+ if(cdata != NULL) >+ { >+#endif >+ for(j = 0; j < 8; j++) >+ { >+ if(csaUsed) >+ { >+ if(cdata->pvu_csa_ks[j] == NULL) >+ { cdata->pvu_csa_ks[j] = get_key_struct(); } >+ >+ if(ecm[0] == 0x80) >+ { set_even_control_word(cdata->pvu_csa_ks[j], cw[j]); } >+ else >+ { set_odd_control_word(cdata->pvu_csa_ks[j], cw[j]); } >+ >+ cdata->pvu_csa_used = 1; >+ } >+ else >+ { >+ if(ecm[0] == 0x80) >+ { des_set_key(cw[j], cdata->pvu_des_ks[j][0]); } >+ else >+ { des_set_key(cw[j], cdata->pvu_des_ks[j][1]); } >+ >+ cdata->pvu_csa_used = 0; >+ } >+ } >+#ifdef WITH_EMU >+ } >+ >+ if(cw_ex != NULL) >+ { >+ cw_ex->mode = CW_MODE_MULTIPLE_CW; >+ >+ if(csaUsed) >+ { >+ cw_ex->algo = CW_ALGO_CSA; >+ cw_ex->algo_mode = CW_ALGO_MODE_ECB; >+ } >+ else >+ { >+ cw_ex->algo = CW_ALGO_DES; >+ cw_ex->algo_mode = CW_ALGO_MODE_ECB; >+ } >+ >+ for(j = 0; j < 4; j++) >+ { >+ dwp = cw_ex->audio[j]; >+ >+ memset(dwp, 0, 16); >+ >+ if(ecm[0] == 0x80) >+ { >+ memcpy(dwp, cw[PVU_CW_A1+j], 8); >+ >+ if(csaUsed) >+ { >+ for(k = 0; k < 8; k += 4) >+ { >+ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); >+ } >+ } >+ } >+ else >+ { >+ memcpy(&dwp[8], cw[PVU_CW_A1+j], 8); >+ >+ if(csaUsed) >+ { >+ for(k = 8; k < 16; k += 4) >+ { >+ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); >+ } >+ } >+ } >+ } >+ >+ dwp = cw_ex->data; >+ >+ memset(dwp, 0, 16); >+ >+ if(ecm[0] == 0x80) >+ { >+ memcpy(dwp, cw[PVU_CW_HSD], 8); >+ >+ if(csaUsed) >+ { >+ for(k = 0; k < 8; k += 4) >+ { >+ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); >+ } >+ } >+ } >+ else >+ { >+ memcpy(&dwp[8], cw[PVU_CW_HSD], 8); >+ >+ if(csaUsed) >+ { >+ for(k = 8; k < 16; k += 4) >+ { >+ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); >+ } >+ } >+ } >+ } >+#endif >+ } >+ else >+ { >+ // Calculate only video cw >+ PowervuCalculateCw(PVU_CW_VID, seed[PVU_CW_VID], csaUsed, convolvedCw[PVU_CW_VID], cw[PVU_CW_VID], baseCw, >+ seedEcmCw, hashModeCw, needsUnmasking, xorMode); >+ } >+ >+ memset(dw, 0, 16); >+ >+ if(ecm[0] == 0x80) >+ { >+ memcpy(dw, cw[PVU_CW_VID], 8); >+ >+ if(csaUsed) >+ { >+ for(k = 0; k < 8; k += 4) >+ { >+ dw[k + 3] = ((dw[k] + dw[k + 1] + dw[k + 2]) & 0xff); >+ } >+ } >+ } >+ else >+ { >+ memcpy(&dw[8], cw[PVU_CW_VID], 8); >+ >+ if(csaUsed) >+ { >+ for(k = 8; k < 16; k += 4) >+ { >+ dw[k + 3] = ((dw[k] + dw[k + 1] + dw[k + 2]) & 0xff); >+ } >+ } >+ } >+ >+ return 0; >+ >+ default: >+ break; >+ } >+ i += nanoLen; >+ } >+ >+ return ret; >+} >+ >+ >+// Drecrypt EMU >+static void DREover(const uint8_t *ECMdata, uint8_t *dw) >+{ >+ uint8_t key[8]; >+ uint32_t key_schedule[32]; >+ >+ if (ECMdata[2] >= (43 + 4) && ECMdata[40] == 0x3A && ECMdata[41] == 0x4B) >+ { >+ if (!FindKey('D', ECMdata[42] & 0x0F, 0, "OVER", key, 8, 1, 0, 0, NULL)) >+ { >+ return; >+ } >+ >+ des_set_key(key, key_schedule); >+ >+ des(dw, key_schedule, 0); // even dw post-process >+ des(dw + 8, key_schedule, 0); // odd dw post-process >+ } >+} >+ >+static uint32_t DreGostDec(uint32_t inData) >+{ >+ static uint8_t Sbox[128] = >+ { >+ 0x0E,0x04,0x0D,0x01,0x02,0x0F,0x0B,0x08,0x03,0x0A,0x06,0x0C,0x05,0x09,0x00,0x07, >+ 0x0F,0x01,0x08,0x0E,0x06,0x0B,0x03,0x04,0x09,0x07,0x02,0x0D,0x0C,0x00,0x05,0x0A, >+ 0x0A,0x00,0x09,0x0E,0x06,0x03,0x0F,0x05,0x01,0x0D,0x0C,0x07,0x0B,0x04,0x02,0x08, >+ 0x07,0x0D,0x0E,0x03,0x00,0x06,0x09,0x0A,0x01,0x02,0x08,0x05,0x0B,0x0C,0x04,0x0F, >+ 0x02,0x0C,0x04,0x01,0x07,0x0A,0x0B,0x06,0x08,0x05,0x03,0x0F,0x0D,0x00,0x0E,0x09, >+ 0x0C,0x01,0x0A,0x0F,0x09,0x02,0x06,0x08,0x00,0x0D,0x03,0x04,0x0E,0x07,0x05,0x0B, >+ 0x04,0x0B,0x02,0x0E,0x0F,0x00,0x08,0x0D,0x03,0x0C,0x09,0x07,0x05,0x0A,0x06,0x01, >+ 0x0D,0x02,0x08,0x04,0x06,0x0F,0x0B,0x01,0x0A,0x09,0x03,0x0E,0x05,0x00,0x0C,0x07 >+ }; >+ uint8_t i, j; >+ >+ for(i = 0; i < 8; i++) >+ { >+ j = (inData >> 28) & 0x0F; >+ inData = (inData << 4) | (Sbox[i * 16 + j] & 0x0F); >+ } >+ >+ inData = (inData << 11) | (inData >> 21); >+ >+ return (inData); >+} >+ >+static void DrecryptDecrypt(uint8_t *Data, uint8_t *Key) // DRE GOST 28147-89 CORE >+{ >+ int i, j; >+ uint32_t L_part = 0, R_part = 0, temp = 0; >+ >+ for(i = 0; i < 4; i++) L_part = (L_part << 8) | (Data[i] & 0xFF), R_part = (R_part << 8) | (Data[i + 4] & 0xFF); >+ >+ for(i = 0; i < 4; i++) >+ { >+ temp = ((Key[i*8+0] & 0xFF) << 24) | ((Key[i*8+1] & 0xFF) << 16) | ((Key[i*8+2] & 0xFF) << 8) | (Key[i*8+3] & 0xFF); >+ R_part ^= DreGostDec(temp + L_part); >+ temp = ((Key[i*8+4] & 0xFF) << 24) | ((Key[i*8+5] & 0xFF) << 16) | ((Key[i*8+6] & 0xFF) << 8) | (Key[i*8+7] & 0xFF); >+ L_part ^= DreGostDec(temp + R_part); >+ } >+ >+ for(j = 0; j < 3; j++) >+ { >+ for(i = 3; i >= 0; i--) >+ { >+ temp = ((Key[i*8+4] & 0xFF) << 24) | ((Key[i*8+5] & 0xFF) << 16) | ((Key[i*8+6] & 0xFF) << 8) | (Key[i*8+7] & 0xFF); >+ R_part ^= DreGostDec(temp + L_part); >+ temp = ((Key[i*8+0] & 0xFF) << 24) | ((Key[i*8+1] & 0xFF) << 16) | ((Key[i*8+2] & 0xFF) << 8) | (Key[i*8+3] & 0xFF); >+ L_part ^= DreGostDec(temp + R_part); >+ } >+ } >+ >+ for(i = 0; i < 4; i++) Data[i] = (R_part >> i*8) & 0xFF, Data[i+4] = (L_part >> i*8) & 0xFF; >+} >+ >+static void DrecryptPostCw(uint8_t* ccw) >+{ >+ uint32_t i, j; >+ uint8_t tmp[4]; >+ >+ for(i = 0; i < 4; i++) >+ { >+ for(j = 0; j < 4; j++) >+ { >+ tmp[j] = ccw[3 - j]; >+ } >+ >+ for(j = 0; j < 4; j++) >+ { >+ ccw[j] = tmp[j]; >+ } >+ >+ ccw += 4; >+ } >+} >+ >+static void DrecryptSwap(uint8_t* ccw) >+{ >+ uint32_t tmp1, tmp2; >+ >+ memcpy(&tmp1, ccw, 4); >+ memcpy(&tmp2, ccw + 4, 4); >+ >+ memcpy(ccw, ccw + 8, 8); >+ >+ memcpy(ccw + 8 , &tmp1, 4); >+ memcpy(ccw + 8 + 4, &tmp2, 4); >+} >+ >+static int8_t Drecrypt2ECM(uint32_t provId, uint8_t *ecm, uint8_t *dw) >+{ >+ uint8_t ecmDataLen, ccw[16], key[32]; >+ uint16_t ecmLen, overcryptId; >+ char keyName[EMU_MAX_CHAR_KEYNAME]; >+ >+ ecmLen = GetEcmLen(ecm); >+ >+ if (ecmLen < 3) >+ { >+ return 1; // Not supported >+ } >+ >+ ecmDataLen = ecm[2]; >+ >+ if (ecmLen < ecmDataLen + 3) >+ { >+ return 4; // Corrupt data >+ } >+ >+ switch (provId & 0xFF) >+ { >+ case 0x11: >+ { >+ if (ecm[3] == 0x56) >+ { >+ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[5]); >+ >+ if (!FindKey('D', 0x4AE111, 0, keyName, key, 32, 1, 0, 0, NULL)) >+ { >+ return 2; >+ } >+ } >+ else >+ { >+ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[3]); >+ >+ if (!FindKey('D', 0x4AE111, 0, keyName, key, 32, 1, 0, 0, NULL)) >+ { >+ return 2; >+ } >+ } >+ >+ break; >+ } >+ >+ case 0x14: >+ { >+ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[5]); >+ >+ if (!FindKey('D', 0x4AE114, 0, keyName, key, 32, 1, 0, 0, NULL)) >+ { >+ return 2; >+ } >+ >+ break; >+ } >+ >+ default: >+ return 1; >+ } >+ >+ memcpy(ccw, ecm + 13, 16); >+ >+ DrecryptPostCw(key); >+ DrecryptPostCw(key + 16); >+ >+ DrecryptDecrypt(ccw, key); >+ DrecryptDecrypt(ccw + 8, key); >+ >+ if (ecm[2] >= 46 && ecm[43] == 1 && provId == 0x11) >+ { >+ DrecryptSwap(ccw); >+ overcryptId = b2i(2, &ecm[44]); >+ >+ Drecrypt2OverCW(overcryptId, ccw); >+ >+ if (isValidDCW(ccw)) >+ { >+ memcpy(dw, ccw, 16); >+ return 0; >+ } >+ >+ return 9; // ICG error >+ } >+ >+ DREover(ecm, ccw); >+ >+ if (isValidDCW(ccw)) >+ { >+ DrecryptSwap(ccw); >+ memcpy(dw, ccw, 16); >+ return 0; >+ } >+ >+ return 1; >+} >+ >+// Tandberg EMU >+static uint16_t TandbergChecksum(uint8_t *data, uint8_t length) >+{ >+ // ECM and EMM checksum calculation >+ // 1. Combine data in 2 byte groups >+ // 2. Add them together >+ // 3. Multiply result by itself (power of 7) >+ // 4. XOR with fixed value 0x17E3 >+ >+ uint8_t i; >+ uint16_t checksum = 0; >+ >+ for(i = 0; i < length; i += 2) >+ { >+ checksum += (data[i] << 8) | data[i + 1]; >+ } >+ >+ checksum = checksum * checksum * checksum * checksum * checksum * checksum * checksum; >+ checksum ^= 0x17E3; >+ >+ return checksum; >+} >+ >+static int8_t GetTandbergKey(uint32_t keyIndex, char *keyName, uint8_t *key, uint32_t keyLength) >+{ >+ // keyIndex: ecm keys --> entitlementId >+ // emm keys --> aeskeyIndex >+ // aes keys --> keyIndex >+ >+ // keyName: ecm keys --> "01" >+ // emm keys --> "MK" or "MK01" >+ // aes keys --> "AES" >+ >+ return FindKey('T', keyIndex, 0, keyName, key, keyLength, 1, 0, 0, NULL); >+} >+ >+static int8_t TandbergECM(uint8_t *ecm, uint8_t *dw) >+{ >+ uint8_t nanoType, nanoLength; >+ uint8_t* nanoData; >+ uint32_t pos = 3; >+ uint32_t entitlementId; >+ uint32_t ks[32]; >+ uint8_t ecmKey[8]; >+ uint16_t ecmLen = GetEcmLen(ecm); >+ >+ if(ecmLen < 5) >+ { >+ return 1; >+ } >+ >+ do >+ { >+ nanoType = ecm[pos]; >+ nanoLength = ecm[pos+1]; >+ >+ if(pos + 2 + nanoLength > ecmLen) >+ { >+ break; >+ } >+ >+ nanoData = ecm + pos + 2; >+ >+ // ECM validation >+ uint16_t payloadChecksum = (nanoData[nanoLength - 2] << 8) | nanoData[nanoLength - 1]; >+ uint16_t calculatedChecksum = TandbergChecksum(nanoData, nanoLength - 2); >+ >+ if(calculatedChecksum != payloadChecksum) >+ { >+ cs_log("ECM checksum error (%.4X instead of %.4X)", calculatedChecksum, payloadChecksum); >+ return 8; >+ } >+ // End of ECM validation >+ >+ switch(nanoType) >+ { >+ case 0xEC: // Director v6 (September 2017) >+ { >+ if(nanoLength != 0x28) >+ { >+ cs_log("WARNING: nanoType EC length (%d) != %d", nanoLength, 0x28); >+ break; >+ } >+ >+ entitlementId = b2i(4, nanoData); >+ >+ if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) >+ { >+ return 2; >+ } >+ >+ cs_log("Active entitlement %.4X", entitlementId); >+ >+ // Step 1 - Decrypt DES CBC with ecmKey and iv = { 0 } (equal to nanoED) >+ uint8_t encryptedData[32] = { 0 }; >+ memcpy(encryptedData, nanoData + 6, 32); >+ >+ uint8_t iv[8] = { 0 }; >+ des_cbc_decrypt(encryptedData, iv, ecmKey, 32); >+ >+ uint8_t nanoMode = nanoData[5]; >+ >+ if ((nanoMode & 0x20) == 0) // Old algo >+ { >+ // Step 2 - Create CW (equal to nano ED) >+ dw[0] = encryptedData[0x05]; >+ dw[1] = encryptedData[0x19]; >+ dw[2] = encryptedData[0x1D]; >+ >+ dw[4] = encryptedData[0x0B]; >+ dw[5] = encryptedData[0x12]; >+ dw[6] = encryptedData[0x1A]; >+ >+ dw[8] = encryptedData[0x16]; >+ dw[9] = encryptedData[0x03]; >+ dw[10] = encryptedData[0x11]; >+ >+ dw[12] = encryptedData[0x18]; >+ dw[13] = encryptedData[0x10]; >+ dw[14] = encryptedData[0x0E]; >+ >+ return 0; >+ } >+ else // New algo (overencryption with AES) >+ { >+ // Step 2 - Prepare data for AES (it is like the creation of CW in nanoED but swapped each 8 bytes) >+ uint8_t dataEC[16] = { 0 }; >+ >+ dataEC[0] = encryptedData[0x02]; >+ dataEC[1] = encryptedData[0x0E]; >+ dataEC[2] = encryptedData[0x10]; >+ dataEC[3] = encryptedData[0x18]; >+ dataEC[4] = encryptedData[0x09]; >+ dataEC[5] = encryptedData[0x11]; >+ dataEC[6] = encryptedData[0x03]; >+ dataEC[7] = encryptedData[0x16]; >+ >+ dataEC[8] = encryptedData[0x13]; >+ dataEC[9] = encryptedData[0x1A]; >+ dataEC[10] = encryptedData[0x12]; >+ dataEC[11] = encryptedData[0x0B]; >+ dataEC[12] = encryptedData[0x04]; >+ dataEC[13] = encryptedData[0x1D]; >+ dataEC[14] = encryptedData[0x19]; >+ dataEC[15] = encryptedData[0x05]; >+ >+ // Step 3 - Decrypt AES CBC with new aesKey and iv 2EBD816A5E749A708AE45ADDD84333DE >+ uint8_t aesKeyIndex = nanoMode & 0x1F; // 32 possible AES keys >+ uint8_t aesKey[16] = { 0 }; >+ >+ if(!GetTandbergKey(aesKeyIndex, "AES", aesKey, 16)) >+ { >+ return 2; >+ } >+ >+ struct aes_keys aes; >+ aes_set_key(&aes, (char *)aesKey); >+ >+ uint8_t ivAes[16] = { 0x2E, 0xBD, 0x81, 0x6A, 0x5E, 0x74, 0x9A, 0x70, 0x8A, 0xE4, 0x5A, 0xDD, 0xD8, 0x43, 0x33, 0xDE }; >+ aes_cbc_decrypt(&aes, dataEC, 16, ivAes); >+ >+ // Step 4 - Create CW (a simple swap) >+ uint8_t offset; >+ for (offset = 0; offset < 16; offset++) >+ { >+ dw[offset] = dataEC[15 - offset]; >+ } >+ >+ return 0; >+ } >+ } >+ >+ case 0xED: // ECM_TAG_CW_DESCRIPTOR >+ { >+ if(nanoLength != 0x26) >+ { >+ cs_log("WARNING: nanoType ED length (%d) != %d", nanoLength, 0x26); >+ break; >+ } >+ >+ entitlementId = b2i(4, nanoData); >+ >+ if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) >+ { >+ return 2; >+ } >+ >+ cs_log("Active entitlement %.4X", entitlementId); >+ >+ uint8_t encryptedData[32] = { 0 }; >+ memcpy(encryptedData, nanoData + 4, 32); >+ >+ uint8_t iv[8] = { 0 }; >+ des_cbc_decrypt(encryptedData, iv, ecmKey, 32); >+ >+ dw[0] = encryptedData[0x05]; >+ dw[1] = encryptedData[0x19]; >+ dw[2] = encryptedData[0x1D]; >+ dw[4] = encryptedData[0x0B]; >+ dw[5] = encryptedData[0x12]; >+ dw[6] = encryptedData[0x1A]; >+ dw[8] = encryptedData[0x16]; >+ dw[9] = encryptedData[0x03]; >+ dw[10] = encryptedData[0x11]; >+ dw[12] = encryptedData[0x18]; >+ dw[13] = encryptedData[0x10]; >+ dw[14] = encryptedData[0x0E]; >+ >+ return 0; >+ } >+ >+ case 0xEE: // ECM_TAG_CW_DESCRIPTOR >+ { >+ if(nanoLength != 0x16) >+ { >+ cs_log("WARNING: nanoType EE length (%d) != %d", nanoLength, 0x16); >+ break; >+ } >+ >+ entitlementId = b2i(4, nanoData); >+ >+ if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) >+ { >+ return 2; >+ } >+ >+ cs_log("Active entitlement %.4X", entitlementId); >+ >+ memcpy(dw, nanoData + 4 + 8, 8); // even >+ memcpy(dw + 8, nanoData + 4, 8); // odd >+ >+ des_set_key(ecmKey, ks); >+ >+ des(dw, ks, 0); >+ des(dw + 8, ks, 0); >+ >+ return 0; >+ } >+ >+ default: >+ cs_log("WARNING: nanoType %.2X not supported", nanoType); >+ break; >+ } >+ >+ pos += 2 + nanoLength; >+ >+ } while (pos < ecmLen); >+ >+ return 1; >+} >+ >+const char* GetProcessECMErrorReason(int8_t result) >+{ >+ switch(result) { >+ case 0: >+ return "No error"; >+ case 1: >+ return "ECM not supported"; >+ case 2: >+ return "Key not found"; >+ case 3: >+ return "Nano80 problem"; >+ case 4: >+ return "Corrupt data"; >+ case 5: >+ return "CW not found"; >+ case 6: >+ return "CW checksum error"; >+ case 7: >+ return "Out of memory"; >+ case 8: >+ return "ECM checksum error"; >+ case 9: >+ return "ICG error"; >+ default: >+ return "Unknown"; >+ } >+} >+ >+/* Error codes >+0 OK >+1 ECM not supported >+2 Key not found >+3 Nano80 problem >+4 Corrupt data >+5 CW not found >+6 CW checksum error >+7 Out of memory >+8 ECM checksum error >+9 ICG error >+*/ >+#ifdef WITH_EMU >+int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, const uint8_t *ecm, >+ uint8_t *dw, uint16_t srvid, uint16_t ecmpid, EXTENDED_CW* cw_ex) >+#else >+int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, const uint8_t *ecm, >+ uint8_t *dw, uint16_t srvid, uint16_t ecmpid) >+#endif >+{ >+ int8_t result = 1, i; >+ uint8_t ecmCopy[EMU_MAX_ECM_LEN]; >+ uint16_t ecmLen = 0; >+ >+ if(ecmDataLen < 3) { >+ // accept requests without ecm only for biss >+ if((caid>>8) != 0x26 && caid != 0xFFFF) { >+ return 1; >+ } >+ } >+ else { >+ ecmLen = GetEcmLen(ecm); >+ } >+ >+ if(ecmLen > ecmDataLen) { >+ return 1; >+ } >+ >+ if(ecmLen > EMU_MAX_ECM_LEN) { >+ return 1; >+ } >+ memcpy(ecmCopy, ecm, ecmLen); >+ >+ if((caid >> 8) == 0x0D) { >+ result = CryptoworksECM(caid, ecmCopy, dw); >+ } >+ else if((caid >> 8) == 0x09) { >+ result = SoftNDSECM(caid, ecmCopy, dw); >+ } >+ else if(caid == 0x0500) { >+ result = ViaccessECM(ecmCopy, dw); >+ } >+ else if((caid >> 8) == 0x18) { >+ result = Nagra2ECM(ecmCopy, dw); >+ } >+ else if((caid >> 8) == 0x06) { >+ result = Irdeto2ECM(caid, ecmCopy, dw); >+ } >+ else if((caid >> 8) == 0x26 || caid == 0xFFFF) { >+ result = BissECM(rdr, ecm, ecmDataLen, dw, srvid, ecmpid); >+ } >+ else if((caid >> 8) == 0x0E) { >+#ifdef WITH_EMU >+ result = PowervuECM(ecmCopy, dw, srvid, NULL, cw_ex); >+#else >+ result = PowervuECM(ecmCopy, dw, NULL); >+#endif >+ } >+ else if(caid == 0x4AE1) { >+ result = Drecrypt2ECM(provider, ecmCopy, dw); >+ } >+ else if((caid >> 8) == 0x10) { >+ result = TandbergECM(ecmCopy, dw); >+ } >+ >+ // fix dcw checksum >+ if(result == 0 && !((caid >> 8) == 0x0E)) { >+ for(i = 0; i < 16; i += 4) { >+ dw[i + 3] = ((dw[i] + dw[i + 1] + dw[i + 2]) & 0xff); >+ } >+ } >+ >+ if(result != 0) { >+ cs_log("ECM failed: %s", GetProcessECMErrorReason(result)); >+ } >+ >+ return result; >+} >+ >+// Viaccess EMM EMU >+static int8_t ViaccessEMM(uint8_t *emm, uint32_t *keysAdded) >+{ >+ uint8_t nanoCmd = 0, subNanoCmd = 0, *tmp; >+ uint16_t i = 0, j = 0, k = 0, emmLen = GetEcmLen(emm); >+ uint8_t ecmKeys[6][16], keyD0[2], emmKey[16], emmXorKey[16], provName[17]; >+ uint8_t ecmKeyCount = 0, emmKeyIndex = 0, aesMode = 0x0D; >+ uint8_t nanoLen = 0, subNanoLen = 0, haveEmmXorKey = 0, haveNewD0 = 0; >+ uint32_t ui1, ui2, ui3, ecmKeyIndex[6], provider = 0, ecmProvider = 0; >+ char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; >+ struct aes_keys aes; >+ >+ memset(keyD0, 0, 2); >+ memset(ecmKeyIndex, 0, sizeof(uint32_t)*6); >+ >+ for(i=3; i+2<emmLen; ) { >+ nanoCmd = emm[i++]; >+ nanoLen = emm[i++]; >+ if(i+nanoLen > emmLen) { >+ return 1; >+ } >+ >+ switch(nanoCmd) { >+ case 0x90: { >+ if(nanoLen < 3) { >+ break; >+ } >+ ui1 = emm[i+2]; >+ ui2 = emm[i+1]; >+ ui3 = emm[i]; >+ provider = (ui1 | (ui2 << 8) | (ui3 << 16)); >+ if(provider == 0x00D00040) { >+ ecmProvider = 0x030B00; >+ } >+ else { >+ return 1; >+ } >+ break; >+ } >+ case 0xD2: { >+ if(nanoLen < 2) { >+ break; >+ } >+ emmKeyIndex = emm[i+1]; >+ break; >+ } >+ case 0x41: { >+ if(nanoLen < 1) { >+ break; >+ } >+ if(!GetViaKey(emmKey, provider, 'M', emmKeyIndex, 16, 1)) { >+ return 2; >+ } >+ memset(provName, 0, 17); >+ memset(emmXorKey, 0, 16); >+ k = nanoLen < 16 ? nanoLen : 16; >+ memcpy(provName, &emm[i], k); >+ aes_set_key(&aes, (char*)emmKey); >+ aes_decrypt(&aes, emmXorKey, 16); >+ for(j=0; j<16; j++) { >+ provName[j] ^= emmXorKey[j]; >+ } >+ provName[k] = 0; >+ >+ if(strcmp((char*)provName, "TNTSAT") != 0 && strcmp((char*)provName, "TNTSATPRO") != 0 >+ &&strcmp((char*)provName, "CSAT V") != 0) { >+ return 1; >+ } >+ break; >+ } >+ case 0xBA: { >+ if(nanoLen < 2) { >+ break; >+ } >+ GetViaKey(keyD0, ecmProvider, 'D', 0, 2, 0); >+ ui1 = (emm[i] << 8) | emm[i+1]; >+ if( (uint32_t)((keyD0[0] << 8) | keyD0[1]) < ui1 || (keyD0[0] == 0x00 && keyD0[1] == 0x00)) { >+ keyD0[0] = emm[i]; >+ keyD0[1] = emm[i+1]; >+ haveNewD0 = 1; >+ break; >+ } >+ return 0; >+ } >+ case 0xBC: { >+ break; >+ } >+ case 0x43: { >+ if(nanoLen < 16) { >+ break; >+ } >+ memcpy(emmXorKey, &emm[i], 16); >+ haveEmmXorKey = 1; >+ break; >+ } >+ case 0x44: { >+ if(nanoLen < 3) { >+ break; >+ } >+ if (!haveEmmXorKey) { >+ memset(emmXorKey, 0, 16); >+ } >+ tmp = (uint8_t*)malloc(((nanoLen/16)+1)*16*sizeof(uint8_t)); >+ if(tmp == NULL) { >+ return 7; >+ } >+ memcpy(tmp, &emm[i], nanoLen); >+ aes_set_key(&aes, (char*)emmKey); >+ for(j=0; j<nanoLen; j+=16) { >+ aes_decrypt(&aes, emmXorKey, 16); >+ for(k=0; k<16; k++) { >+ tmp[j+k] ^= emmXorKey[k]; >+ } >+ } >+ memcpy(&emm[i-2], tmp, nanoLen); >+ free(tmp); >+ nanoLen = 0; >+ i -= 2; >+ break; >+ } >+ case 0x68: { >+ if(ecmKeyCount > 5) { >+ break; >+ } >+ for(j=i; j+2<i+nanoLen; ) { >+ subNanoCmd = emm[j++]; >+ subNanoLen = emm[j++]; >+ if(j+subNanoLen > i+nanoLen) { >+ break; >+ } >+ switch(subNanoCmd) { >+ case 0xD2: { >+ if(nanoLen < 2) { >+ break; >+ } >+ aesMode = emm[j]; >+ emmKeyIndex = emm[j+1]; >+ break; >+ } >+ case 0x01: { >+ if(nanoLen < 17) { >+ break; >+ } >+ ecmKeyIndex[ecmKeyCount] = emm[j]; >+ memcpy(&ecmKeys[ecmKeyCount], &emm[j+1], 16); >+ if(!GetViaKey(emmKey, provider, 'M', emmKeyIndex, 16, 1)) { >+ break; >+ } >+ >+ if(aesMode == 0x0F || aesMode == 0x11) { >+ hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]); >+ hdSurEncPhase2_D2_0F_11(ecmKeys[ecmKeyCount]); >+ } >+ else if(aesMode == 0x13 || aesMode == 0x15) { >+ hdSurEncPhase1_D2_13_15(ecmKeys[ecmKeyCount]); >+ } >+ aes_set_key(&aes, (char*)emmKey); >+ aes_decrypt(&aes, ecmKeys[ecmKeyCount], 16); >+ if(aesMode == 0x0F || aesMode == 0x11) { >+ hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]); >+ } >+ else if(aesMode == 0x13 || aesMode == 0x15) { >+ hdSurEncPhase2_D2_13_15(ecmKeys[ecmKeyCount]); >+ } >+ >+ ecmKeyCount++; >+ break; >+ } >+ default: >+ break; >+ } >+ j += subNanoLen; >+ } >+ break; >+ } >+ case 0xF0: { >+ if(nanoLen != 4) { >+ break; >+ } >+ ui1 = ((emm[i+2] << 8) | (emm[i+1] << 16) | (emm[i] << 24) | emm[i+3]); >+ if(fletcher_crc32(emm + 3, emmLen - 11) != ui1) { >+ return 4; >+ } >+ >+ if(haveNewD0) { >+ >+ SetKey('V', ecmProvider, "D0", keyD0, 2, 1, NULL, NULL); >+ >+ for(j=0; j<ecmKeyCount; j++) { >+ >+ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "E%X", ecmKeyIndex[j]); >+ SetKey('V', ecmProvider, keyName, ecmKeys[j], 16, 1, NULL, NULL); >+ >+ (*keysAdded)++; >+ cs_hexdump(0, ecmKeys[j], 16, keyValue, sizeof(keyValue)); >+ cs_log("Key found in EMM: V %06X %s %s", ecmProvider, keyName, keyValue); >+ } >+ } >+ break; >+ } >+ default: >+ break; >+ } >+ i += nanoLen; >+ } >+ return 0; >+} >+ >+// Irdeto2 EMM EMU >+static int8_t Irdeto2DoEMMTypeOP(uint32_t ident, uint8_t *emm, uint8_t *keySeed, uint8_t *keyIV, uint8_t *keyPMK, >+ uint16_t emmLen, uint8_t startOffset, uint8_t length, uint32_t *keysAdded) >+{ >+ uint32_t end, i, l; >+ uint8_t tmp[16]; >+ char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; >+ >+ memset(tmp, 0, 16); >+ Irdeto2Encrypt(keySeed, tmp, keyPMK, 16); >+ Irdeto2Decrypt(&emm[startOffset], keyIV, keySeed, length); >+ >+ i = 16; >+ end = startOffset + (length-8 < 0 ? 0 : length-8); >+ >+ while(i<end) { >+ l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1; >+ switch(emm[i]) { >+ case 0x10: >+ case 0x50: >+ if(l==0x13 && i<=startOffset+length-8-l) { >+ Irdeto2Decrypt(&emm[i+3], keyIV, keyPMK, 16); >+ } >+ break; >+ case 0x78: >+ if(l==0x14 && i<=startOffset+length-8-l) { >+ Irdeto2Decrypt(&emm[i+4], keyIV, keyPMK, 16); >+ } >+ break; >+ } >+ i+=l; >+ } >+ >+ memmove(emm+6, emm+7, emmLen-7); >+ >+ i = 15; >+ end = startOffset + (length-9 < 0 ? 0 : length-9); >+ >+ if(Irdeto2CalculateHash(keySeed, keyIV, emm+3, emmLen-4)) { >+ while(i<end) { >+ l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1; >+ switch(emm[i]) { >+ case 0x10: >+ case 0x50: >+ if(l==0x13 && i<=startOffset+length-9-l) { >+ >+ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X", emm[i+2]>>2); >+ SetKey('I', ident, keyName, &emm[i+3], 16, 1, NULL, NULL); >+ >+ (*keysAdded)++; >+ cs_hexdump(0, &emm[i+3], 16, keyValue, sizeof(keyValue)); >+ cs_log("Key found in EMM: I %06X %s %s", ident, keyName, keyValue); >+ } >+ } >+ i+=l; >+ } >+ >+ if(*keysAdded > 0) { >+ return 0; >+ } >+ } >+ >+ return 1; >+} >+ >+static int8_t Irdeto2DoEMMTypePMK(uint32_t ident, uint8_t *emm, uint8_t *keySeed, uint8_t *keyIV, uint8_t *keyPMK, >+ uint16_t emmLen, uint8_t startOffset, uint8_t length, uint32_t *keysAdded) >+{ >+ uint32_t end, i, l, j; >+ char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; >+ >+ Irdeto2Decrypt(&emm[startOffset], keyIV, keySeed, length); >+ >+ i = 13; >+ end = startOffset + (length-8 < 0 ? 0 : length-8); >+ >+ while(i<end) { >+ l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1; >+ switch(emm[i]) { >+ case 0x10: >+ case 0x50: >+ if(l==0x13 && i<=startOffset+length-8-l) { >+ Irdeto2Decrypt(&emm[i+3], keyIV, keyPMK, 16); >+ } >+ break; >+ case 0x78: >+ if(l==0x14 && i<=startOffset+length-8-l) { >+ Irdeto2Decrypt(&emm[i+4], keyIV, keyPMK, 16); >+ } >+ break; >+ case 0x68: >+ if(l==0x26 && i<=startOffset+length-8-l) { >+ Irdeto2Decrypt(&emm[i+3], keyIV, keyPMK, 16*2); >+ } >+ break; >+ } >+ i+=l; >+ } >+ >+ memmove(emm+7, emm+9, emmLen-9); >+ >+ i = 11; >+ end = startOffset + (length-10 < 0 ? 0 : length-10); >+ >+ if(Irdeto2CalculateHash(keySeed, keyIV, emm+3, emmLen-5)) { >+ while(i<end) { >+ l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1; >+ switch(emm[i]) { >+ case 0x68: >+ if(l==0x26 && i<=startOffset+length-10-l) { >+ for(j=0; j<2; j++) { >+ >+ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "M%01X", 3+j); >+ SetKey('I', ident, keyName, &emm[i+3+j*16], 16, 1, NULL, NULL); >+ >+ (*keysAdded)++; >+ cs_hexdump(0, &emm[i+3+j*16], 16, keyValue, sizeof(keyValue)); >+ cs_log("Key found in EMM: I %06X %s %s", ident, keyName, keyValue); >+ } >+ } >+ } >+ i+=l; >+ } >+ >+ if(*keysAdded > 0) { >+ return 0; >+ } >+ } >+ >+ return 1; >+} >+ >+static const uint8_t fausto_xor[16] = { 0x22, 0x58, 0xBD, 0x85, 0x2E, 0x8E, 0x52, 0x80, 0xA3, 0x79, 0x98, 0x69, 0x68, 0xE2, 0xD8, 0x4D }; >+ >+static int8_t Irdeto2EMM(uint16_t caid, uint8_t *oemm, uint32_t *keysAdded) >+{ >+ uint8_t length, okeySeed[16], keySeed[16], keyIV[16], keyPMK[16], startOffset, emmType; >+ uint32_t ident; >+ uint32_t keySeedRef, keyIVRef, keyPMK0Ref, keyPMK1Ref, keyPMK0ERef, keyPMK1ERef; >+ uint8_t emmCopy[EMU_MAX_EMM_LEN], *emm = oemm; >+ uint16_t emmLen = GetEcmLen(emm); >+ >+ if(emmLen < 11) { >+ return 1; >+ } >+ >+ if(emm[3] == 0xC3 || emm[3] == 0xCB) { >+ emmType = 2; >+ startOffset = 11; >+ } >+ else { >+ emmType = 1; >+ startOffset = 10; >+ } >+ >+ ident = emm[startOffset-2] | caid << 8; >+ length = emm[startOffset-1]; >+ >+ >+ if(emmLen < length+startOffset) { >+ return 1; >+ } >+ >+ keySeedRef = 0; >+ while(GetIrdetoKey(okeySeed, ident, 'M', emmType == 1 ? 0 : 0xA, 1, &keySeedRef)) { >+ keyIVRef = 0; >+ while(GetIrdetoKey(keyIV, ident, 'M', 2, 1, &keyIVRef)) { >+ >+ keyPMK0Ref = 0; >+ keyPMK1Ref = 0; >+ keyPMK0ERef = 0; >+ keyPMK1ERef = 0; >+ >+ while(GetIrdetoKey(keyPMK, ident, 'M', emmType == 1 ? 3 : 0xB, 1, &keyPMK0Ref)) { >+ memcpy(keySeed, okeySeed, 16); >+ memcpy(emmCopy, oemm, emmLen); >+ emm = emmCopy; >+ if(emmType == 1) { >+ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { >+ return 0; >+ } >+ } >+ else { >+ if(Irdeto2DoEMMTypePMK(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { >+ return 0; >+ } >+ } >+ } >+ >+ if(emmType == 1) { >+ while(GetIrdetoKey(keyPMK, ident, 'M', 4, 1, &keyPMK1Ref)) { >+ memcpy(keySeed, okeySeed, 16); >+ memcpy(emmCopy, oemm, emmLen); >+ emm = emmCopy; >+ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { >+ return 0; >+ } >+ } >+ >+ while(GetIrdetoKey(keyPMK, ident, 'M', 5, 1, &keyPMK0ERef)) { >+ xxor(keyPMK, 16, keyPMK, fausto_xor); >+ memcpy(keySeed, okeySeed, 16); >+ memcpy(emmCopy, oemm, emmLen); >+ emm = emmCopy; >+ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { >+ return 0; >+ } >+ } >+ >+ while(GetIrdetoKey(keyPMK, ident, 'M', 6, 1, &keyPMK1ERef)) { >+ xxor(keyPMK, 16, keyPMK, fausto_xor); >+ memcpy(keySeed, okeySeed, 16); >+ memcpy(emmCopy, oemm, emmLen); >+ emm = emmCopy; >+ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { >+ return 0; >+ } >+ } >+ } >+ >+ if(keyPMK0Ref == 0 && keyPMK1Ref == 0 && keyPMK0ERef == 0 && keyPMK1ERef == 0) { >+ return 2; >+ } >+ } >+ if(keyIVRef == 0) { >+ return 2; >+ } >+ } >+ if(keySeedRef == 0) { >+ return 2; >+ } >+ >+ return 1; >+} >+ >+int32_t GetIrdeto2Hexserial(uint16_t caid, uint8_t *hexserial) >+{ >+ uint32_t i, len; >+ KeyDataContainer *KeyDB; >+ KeyData *tmpKeyData; >+ >+ KeyDB = GetKeyContainer('I'); >+ if(KeyDB == NULL) { >+ return 0; >+ } >+ >+ for(i=0; i<KeyDB->keyCount; i++) { >+ >+ if(KeyDB->EmuKeys[i].provider>>8 != caid) { >+ continue; >+ } >+ if(strcmp(KeyDB->EmuKeys[i].keyName, "MC")) { >+ continue; >+ } >+ >+ tmpKeyData = &KeyDB->EmuKeys[i]; >+ >+ len = tmpKeyData->keyLength; >+ if(len > 3) >+ { len = 3; } >+ >+ memcpy(hexserial+(3-len), tmpKeyData->key, len); >+ return 1; >+ } >+ >+ return 0; >+} >+ >+ >+// PowerVu EMM EMU >+static void PowervuUnmaskEmm(uint8_t *emm) >+{ >+ int i, l; >+ >+ uint8_t sourcePos[] = {0x03, 0x0C, 0x0D, 0x11, 0x15, 0x18, 0x1D, 0x1F, 0x25, 0x2A, 0x32, 0x35, 0x3A, 0x3B, 0x3E, >+ 0x42, 0x47, 0x48, 0x53, 0x58, 0x5C, 0x61, 0x66, 0x69, 0x71, 0x72, 0x78, 0x7B, 0x81, 0x84}; >+ >+ uint8_t destPos[] = {0x02, 0x08, 0x0B, 0x0E, 0x13, 0x16, 0x1E, 0x23, 0x28, 0x2B, 0x2F, 0x33, 0x38, 0x3C, 0x40, >+ 0x44, 0x4A, 0x4D, 0x54, 0x57, 0x5A, 0x63, 0x68, 0x6A, 0x70, 0x75, 0x76, 0x7D, 0x82, 0x85}; >+ >+ uint8_t data[0x1E]; >+ uint8_t hashModeEmm; >+ uint8_t mask[0x10]; >+ uint32_t crc; >+ >+ // Create Mask for ECM decryption >+ PowervuCreateDataEcmEmm(emm, sourcePos, 0x13, 0x1E, data); >+ >+ hashModeEmm = emm[8] ^ PowervuCrc8Calc(data, 0x1E); >+ >+ PowervuCreateHash(data, 0x1E, mask, hashModeEmm); >+ >+ // Fix Header >+ emm[3] &= 0x0F; >+ emm[3] |= 0x10; >+ emm[8] = 0x00; >+ >+ // Unmask Body >+ for(i = 0; i < 0x1E; i++) >+ { >+ emm[0x13 + destPos[i]] ^= mask[i & 0x0F]; >+ } >+ >+ // Fix CRC (optional) >+ l = (((emm[1] << 8) + emm[2]) & 0xFFF) + 3 - 4; >+ crc = fletcher_crc32(emm, l); >+ >+ emm[l + 0] = crc >> 24; >+ emm[l + 1] = crc >> 16; >+ emm[l + 2] = crc >> 8; >+ emm[l + 3] = crc >> 0; >+} >+ >+static int8_t PowervuEMM(uint8_t *emm, uint32_t *keysAdded) >+{ >+ uint8_t emmInfo, emmType, decryptOk = 0; >+ uint16_t emmLen = GetEcmLen(emm); >+ uint32_t i, uniqueAddress, groupId, keyRef = 0; >+ //uint32_t emmCrc32; >+ uint8_t emmKey[7], tmpEmmKey[7], tmp[26]; >+ char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[16]; >+ char uaInfo[4+8+1]; >+ >+ if(emmLen < 50) >+ { >+ return 1; >+ } >+ >+ // Check if unmasking is needed >+ if((emm[3] & 0xF0) == 0x50) >+ { >+ PowervuUnmaskEmm(emm); >+ } >+ >+ // looks like checksum does not work for all EMMs >+ //emmCrc32 = b2i(4, emm+emmLen-4); >+ // >+ //if(fletcher_crc32(emm, emmLen-4) != emmCrc32) >+ //{ >+ // return 8; >+ //} >+ emmLen -= 4; >+ >+ uniqueAddress = b2i(4, emm+12); >+ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.8X", uniqueAddress); >+ >+ do >+ { >+ if(!GetPowervuEmmKey(emmKey, 0, keyName, 7, 0, keyRef++, &groupId)) >+ { >+ cs_log_dbg(D_EMM, "EMM error: AU key for UA %s is missing", keyName); >+ return 2; >+ } >+ >+ for(i=19; i+27<=emmLen; i+=27) { >+ emmInfo = emm[i]; >+ >+ if(!GetBit(emmInfo, 7)) >+ { >+ continue; >+ } >+ >+ //keyNb = emm[i] & 0x0F; >+ >+ memcpy(tmp, emm+i+1, 26); >+ memcpy(tmpEmmKey, emmKey, 7); >+ PowervuDecrypt(emm+i+1, 26, tmpEmmKey, 0); >+ >+ if((emm[13] != emm[i+24]) || (emm[14] != emm[i+25]) || (emm[15] != emm[i+26])) >+ { >+ memcpy(emm+i+1, tmp, 26); >+ memcpy(tmpEmmKey, emmKey, 7); >+ PowervuDecrypt(emm+i+1, 26, tmpEmmKey, 1); >+ >+ if((emm[13] != emm[i+24]) || (emm[14] != emm[i+25]) || (emm[15] != emm[i+26])) >+ { >+ memcpy(emm+i+1, tmp, 26); >+ memcpy(tmpEmmKey, emmKey, 7); >+ continue; >+ } >+ } >+ >+ decryptOk = 1; >+ >+ emmType = emm[i+2] & 0x7F; >+ if(emmType > 1) >+ { >+ continue; >+ } >+ >+ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", emmType); >+ snprintf(uaInfo, sizeof(uaInfo), "UA: %08X", uniqueAddress); >+ >+ if(emm[i+3] == 0 && emm[i+4] == 0) >+ { >+ cs_hexdump(0, &emm[i+3], 7, keyValue, sizeof(keyValue)); >+ cs_log("Key found in EMM: P %.4X**** %s %s -> REJECTED (looks invalid) UA: %.8X", groupId, keyName, keyValue, uniqueAddress); >+ continue; >+ } >+ >+ UpdateKeysByProviderMask('P', groupId<<16, 0x0000FFFF, keyName, &emm[i+3], 7, uaInfo); >+ >+ (*keysAdded)++; >+ cs_hexdump(0, &emm[i+3], 7, keyValue, sizeof(keyValue)); >+ cs_log("Key found in EMM: P %.4X**** %s %s ; UA: %.8X", groupId, keyName, keyValue, uniqueAddress); >+ } >+ >+ } while(!decryptOk); >+ >+ return 0; >+} >+ >+int32_t GetPowervuHexserials(uint16_t srvid, uint8_t hexserials[][4], int32_t length, int32_t* count) >+{ >+ //srvid == 0xFFFF -> get all >+ >+ uint32_t i, j; >+ uint32_t groupid; >+ int32_t len, k; >+ KeyDataContainer *KeyDB; >+ uint8_t tmp[4]; >+ int8_t alreadyAdded; >+ >+ KeyDB = GetKeyContainer('P'); >+ if(KeyDB == NULL) >+ { return 0; } >+ >+ (*count) = 0; >+ >+ for(i=0; i<KeyDB->keyCount && (*count)<length ; i++) { >+ >+ if(KeyDB->EmuKeys[i].provider <= 0x0000FFFF) // skip au keys >+ { continue; } >+ >+ if(srvid != 0xFFFF && (KeyDB->EmuKeys[i].provider & 0x0000FFFF) != srvid) >+ { continue; } >+ >+ groupid = KeyDB->EmuKeys[i].provider>>16; >+ >+ for(j=0; j<KeyDB->keyCount && (*count)<length ; j++) { >+ >+ if(KeyDB->EmuKeys[j].provider != groupid) // search au key with groupip >+ { continue; } >+ >+ len = strlen(KeyDB->EmuKeys[j].keyName); >+ >+ if(len < 3) >+ { continue;} >+ >+ if(len > 8) >+ { len = 8; } >+ >+ memset(tmp, 0, 4); >+ CharToBin(tmp+(4-(len/2)), KeyDB->EmuKeys[j].keyName, len); >+ >+ for(k=0, alreadyAdded=0; k<*count; k++) >+ { >+ if(!memcmp(hexserials[k], tmp, 4)) >+ { >+ alreadyAdded = 1; >+ break; >+ } >+ } >+ >+ if(!alreadyAdded) >+ { >+ memcpy(hexserials[*count], tmp, 4); >+ (*count)++; >+ } >+ } >+ >+ } >+ >+ return 1; >+} >+ >+// Drecrypt EMM EMU >+static int8_t DrecryptGetEmmKey(uint8_t *buf, uint32_t keyIdent, uint16_t keyName, uint8_t isCriticalKey) >+{ >+ char keyStr[EMU_MAX_CHAR_KEYNAME]; >+ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "MK%04X", keyName); >+ return FindKey('D', keyIdent, 0, keyStr, buf, 32, isCriticalKey, 0, 0, NULL); >+} >+ >+static void DrecryptWriteEebin(const char *path, const char *name) >+{ >+ char tmp[256]; >+ FILE *file = NULL; >+ uint8_t i, buffer[64][32]; >+ uint32_t prvid; >+ >+ // Set path >+ if (path != NULL) >+ { >+ snprintf(tmp, 256, "%s%s", path, name); >+ } >+ else // No path set, use SoftCam.Keys's path >+ { >+ snprintf(tmp, 256, "%s%s", emu_keyfile_path, name); >+ } >+ >+ if ((file = fopen(tmp, "wb")) != NULL) >+ { >+ cs_log("Writing key file: %s", tmp); >+ } >+ else >+ { >+ cs_log("Error writing key file: %s", tmp); >+ return; >+ } >+ >+ // Load keys from db to buffer >+ prvid = (strncmp(name, "ee36.bin", 9) == 0) ? 0x4AE111 : 0x4AE114; >+ >+ for (i = 0; i < 32; i++) // Load "3B" type keys >+ { >+ snprintf(tmp, 5, "3B%02X", i); >+ if (!FindKey('D', prvid, 0, tmp, buffer[i], 32, 0, 0, 0, NULL)) >+ { >+ memset(buffer[i], 0xFF, 32); >+ } >+ } >+ >+ for (i = 0; i < 32; i++) // Load "56" type keys >+ { >+ snprintf(tmp, 5, "56%02X", i); >+ if (!FindKey('D', prvid, 0, tmp, buffer[32 + i], 32, 0, 0, 0, NULL)) >+ { >+ memset(buffer[32 + i], 0xFF, 32); >+ } >+ } >+ >+ // Write buffer to ee.bin file >+ fwrite(buffer, 1, sizeof(buffer), file); >+ fclose(file); >+} >+ >+static int8_t DrecryptProcessEMM(struct s_reader *rdr, uint32_t provId, uint8_t *emm, uint32_t *keysAdded) >+{ >+ uint16_t emmLen, emmDataLen; >+ uint32_t i, keyIdent; >+ uint16_t keyName; >+ uint8_t emmKey[32]; >+ uint8_t *curECMkey3B = NULL, *curECMkey56 = NULL; >+ uint8_t keynum =0, keyidx = 0, keyclass = 0, key1offset, key2offset; >+ char newKeyName[EMU_MAX_CHAR_KEYNAME], curKeyName[EMU_MAX_CHAR_KEYNAME], keyValue[100]; >+ >+ emmDataLen = GetEcmLen(emm); >+ emmLen = ((emm[1] & 0xF) << 8) | emm[2]; >+ >+ if (emmDataLen < emmLen + 3) >+ { >+ return 4; // Corrupt data >+ } >+ >+ if (emm[0] == 0x91) >+ { >+ Drecrypt2OverEMM(emm); >+ return 0; >+ } >+ else if (emm[0] == 0x82) >+ { >+ ReasmEMM82(emm); >+ return 0; >+ } >+ else if (emm[0] != 0x86) >+ { >+ return 1; // Not supported >+ } >+ >+ // Emm type 0x86 only >+ switch (emm[4]) >+ { >+ case 0x02: >+ keynum = 0x2C; >+ keyidx = 0x30; >+ keyclass = 0x26; >+ key1offset = 0x35; >+ key2offset = 0x6D; >+ break; >+ >+ case 0x4D: >+ keynum = 0x61; >+ keyidx = 0x60; >+ keyclass = 0x05; >+ key1offset = 0x62; >+ key2offset = 0x8B; >+ break; >+ >+ default: >+ return 1; // Not supported >+ } >+ >+ switch (provId & 0xFF) >+ { >+ case 0x11: >+ { >+ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "3B%02X", emm[keyclass]); >+ FindKey('D', 0x4AE111, 0, curKeyName, curECMkey3B, 32, 0, 0, 0, NULL); >+ >+ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "56%02X", emm[keyclass]); >+ FindKey('D', 0x4AE111, 0, curKeyName, curECMkey56, 32, 0, 0, 0, NULL); >+ >+ break; >+ } >+ >+ case 0x14: >+ { >+ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "3B%02X", emm[keyclass]); >+ FindKey('D', 0x4AE114, 0, curKeyName, curECMkey3B, 32, 0, 0, 0, NULL); >+ >+ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "56%02X", emm[keyclass]); >+ FindKey('D', 0x4AE114, 0, curKeyName, curECMkey56, 32, 0, 0, 0, NULL); >+ >+ break; >+ } >+ >+ default: >+ return 9; // Wrong provider >+ } >+ >+ keyIdent = (0x4AE1 << 8) | provId; >+ keyName = (emm[3] << 8) | emm[keynum]; >+ >+ if (!DrecryptGetEmmKey(emmKey, keyIdent, keyName, 1)) >+ { >+ return 2; >+ } >+ >+ // Key #1 >+ for (i = 0; i < 4; i++) >+ { >+ DrecryptDecrypt(&emm[key1offset + (i * 8)], emmKey); >+ } >+ >+ // Key #2 >+ for (i = 0; i < 4; i++) >+ { >+ DrecryptDecrypt(&emm[key2offset + (i * 8)], emmKey); >+ } >+ >+ // Key #1 >+ keyName = emm[keyidx] << 8 | emm[keyclass]; >+ snprintf(newKeyName, EMU_MAX_CHAR_KEYNAME, "%.4X", keyName); >+ >+ if (memcmp(&emm[key1offset], emm[keyidx] == 0x3b ? curECMkey3B : curECMkey56, 32) != 0) >+ { >+ memcpy(emm[keyidx] == 0x3b ? curECMkey3B : curECMkey56, &emm[key1offset], 32); >+ SetKey('D', keyIdent, newKeyName, &emm[key1offset], 32, 0, NULL, NULL); >+ (*keysAdded)++; >+ >+ cs_hexdump(0, &emm[key1offset], 32, keyValue, sizeof(keyValue)); >+ cs_log("Key found in EMM: D %.6X %s %s class %02X", keyIdent, newKeyName, keyValue, emm[keyclass]); >+ } >+ else >+ { >+ cs_log("Key %.6X %s already exists", keyIdent, newKeyName); >+ } >+ >+ // Key #2 >+ keyName = (emm[keyidx] == 0x56 ? 0x3B00 : 0x5600) | emm[keyclass]; >+ snprintf(newKeyName, EMU_MAX_CHAR_KEYNAME, "%.4X", keyName); >+ >+ if (memcmp(&emm[key2offset], emm[keyidx] == 0x3b ? curECMkey56 : curECMkey3B, 32) != 0) >+ { >+ memcpy(emm[keyidx] == 0x3b ? curECMkey56 : curECMkey3B, &emm[key2offset], 32); >+ SetKey('D', keyIdent, newKeyName, &emm[key2offset], 32, 0, NULL, NULL); >+ (*keysAdded)++; >+ >+ cs_hexdump(0, &emm[key2offset], 32, keyValue, sizeof(keyValue)); >+ cs_log("Key found in EMM: D %.6X %s %s class %02X", keyIdent, newKeyName, keyValue, emm[keyclass]); >+ } >+ else >+ { >+ cs_log("Key %.6X %s already exists", keyIdent, newKeyName); >+ } >+ >+ if (*keysAdded > 0) // Write new ecm keys to ee.bin file >+ { >+ switch (provId & 0xFF) >+ { >+ case 0x11: >+ DrecryptWriteEebin(rdr->extee36, "ee36.bin"); >+ break; >+ >+ case 0x14: >+ DrecryptWriteEebin(rdr->extee56, "ee56.bin"); >+ break; >+ >+ default: >+ cs_log("Provider %02X doesn't have a matching ee.bin file", provId & 0xFF); >+ break; >+ } >+ } >+ >+ return 0; >+} >+ >+static int8_t Drecrypt2EMM(struct s_reader *rdr, uint32_t provId, uint8_t *emm, uint32_t *keysAdded) >+{ >+ int8_t result = DrecryptProcessEMM(rdr, provId, emm, keysAdded); >+ >+ if (result == 2) >+ { >+ uint8_t keynum = 0, emmkey; >+ uint32_t i; >+ KeyDataContainer *KeyDB = GetKeyContainer('D'); >+ >+ if (KeyDB == NULL) >+ { >+ return result; >+ } >+ >+ for (i = 0; i < KeyDB->keyCount; i++) >+ { >+ if (KeyDB->EmuKeys[i].provider != ((0x4AE1 << 8) | provId)) >+ { >+ continue; >+ } >+ >+ if (strlen(KeyDB->EmuKeys[i].keyName) < 6) >+ { >+ continue; >+ } >+ >+ if (memcmp(KeyDB->EmuKeys[i].keyName, "MK", 2)) >+ { >+ continue; >+ } >+ >+ CharToBin(&keynum, KeyDB->EmuKeys[i].keyName + 4, 2); >+ emmkey = (emm[4] == 0x4D) ? emm[0x61] : emm[0x2C]; >+ >+ if (keynum == emmkey) >+ { >+ if (provId == 0x11) >+ { >+ CharToBin(&rdr->dre36_force_group, KeyDB->EmuKeys[i].keyName + 2, 2); >+ } >+ else >+ { >+ CharToBin(&rdr->dre56_force_group, KeyDB->EmuKeys[i].keyName + 2, 2); >+ } >+ >+ break; >+ } >+ } >+ } >+ >+ return result; >+} >+ >+int32_t GetDrecryptHexserials(uint16_t caid, uint32_t provid, uint8_t *hexserials, int32_t length, int32_t *count) >+{ >+ uint32_t i; >+ KeyDataContainer *KeyDB = GetKeyContainer('D'); >+ >+ if (KeyDB == NULL) >+ { >+ return 0; >+ } >+ >+ (*count) = 0; >+ >+ for (i = 0; i < KeyDB->keyCount && (*count) < length; i++) >+ { >+ >+ if (KeyDB->EmuKeys[i].provider != ((caid << 8) | provid)) >+ { >+ continue; >+ } >+ >+ if (strlen(KeyDB->EmuKeys[i].keyName) < 6) >+ { >+ continue; >+ } >+ >+ if (memcmp(KeyDB->EmuKeys[i].keyName, "MK", 2)) >+ { >+ continue; >+ } >+ >+ CharToBin(&hexserials[(*count)], KeyDB->EmuKeys[i].keyName + 2, 2); >+ >+ (*count)++; >+ } >+ >+ return 1; >+} >+ >+// Tandberg EMM EMU >+static uint8_t MixTable[] = >+{ >+ 0x12,0x78,0x4B,0x19,0x13,0x80,0x2F,0x84, >+ 0x86,0x4C,0x09,0x53,0x15,0x79,0x6B,0x49, >+ 0x10,0x4D,0x33,0x43,0x18,0x37,0x83,0x38, >+ 0x82,0x1B,0x6E,0x24,0x2A,0x85,0x3C,0x3D, >+ 0x5A,0x58,0x55,0x5D,0x20,0x41,0x65,0x51, >+ 0x0C,0x45,0x63,0x7F,0x0F,0x46,0x21,0x7C, >+ 0x2C,0x61,0x7E,0x0A,0x42,0x57,0x35,0x16, >+ 0x87,0x3B,0x4F,0x40,0x34,0x22,0x26,0x74, >+ 0x32,0x69,0x44,0x7A,0x6A,0x6D,0x0D,0x56, >+ 0x23,0x2B,0x5C,0x72,0x76,0x36,0x28,0x25, >+ 0x2E,0x52,0x5B,0x6C,0x7D,0x30,0x0B,0x5E, >+ 0x47,0x1F,0x7B,0x31,0x3E,0x11,0x77,0x1E, >+ 0x60,0x75,0x54,0x27,0x50,0x17,0x70,0x59, >+ 0x1A,0x2D,0x4A,0x67,0x3A,0x5F,0x68,0x08, >+ 0x4E,0x3F,0x29,0x6F,0x81,0x71,0x39,0x64, >+ 0x48,0x66,0x73,0x14,0x0E,0x1D,0x62,0x1C >+}; >+ >+void TandbergRotateBytes(unsigned char *in, int n) >+{ >+ if(n > 1) >+ { >+ unsigned char *e = in + n - 1; >+ do >+ { >+ unsigned char temp = *in; >+ *in++ = *e; >+ *e-- = temp; >+ } >+ while (in < e); >+ } >+} >+ >+static void TandbergECMKeyDecrypt(uint8_t* emmKey, uint8_t* tagData, uint8_t* ecmKey) >+{ >+ TandbergRotateBytes(emmKey, 8); >+ uint8_t iv[8] = { 0 }; >+ uint8_t* payLoad = tagData + 4 + 5; >+ des_cbc_decrypt(payLoad, iv, emmKey, 16); >+ >+ ecmKey[0] = payLoad[0x0F]; >+ ecmKey[1] = payLoad[0x01]; >+ ecmKey[2] = payLoad[0x0B]; >+ ecmKey[3] = payLoad[0x03]; >+ ecmKey[4] = payLoad[0x0E]; >+ ecmKey[5] = payLoad[0x04]; >+ ecmKey[6] = payLoad[0x0A]; >+ ecmKey[7] = payLoad[0x08]; >+} >+ >+static int8_t TandbergParseEMMNanoTags(uint8_t* data, uint32_t length, uint8_t keyIndex, uint32_t *keysAdded) >+{ >+ uint8_t tagType, tagLength, blockIndex; >+ uint32_t pos = 0, entitlementId; >+ int32_t i, k; >+ uint32_t ks[32]; >+ uint8_t* tagData; >+ uint8_t emmKey[8]; >+ char keyValue[17]; >+ uint8_t tagDataDecrypted[0x10][8]; >+ >+ if(length < 2) >+ { >+ return 1; >+ } >+ >+ while(pos < length) >+ { >+ tagType = data[pos]; >+ tagLength = data[pos+1]; >+ >+ if(pos + 2 + tagLength > length) >+ { >+ return 1; >+ } >+ >+ tagData = data + pos + 2; >+ >+ switch(tagType) >+ { >+ case 0xE4: // EMM_TAG_SECURITY_TABLE_DESCRIPTOR (ram emm keys) >+ { >+ uint8_t tagMode = data[pos + 2]; >+ >+ switch(tagMode) >+ { >+ case 0x01: // keySet 01 (MK01) >+ { >+ if(tagLength != 0x8A) >+ { >+ cs_log("WARNING: nanoTag E4 length (%d) != %d", tagLength, 0x8A); >+ break; >+ } >+ >+ if(!GetTandbergKey(keyIndex, "MK01", emmKey, 8)) >+ { >+ break; >+ } >+ >+ uint8_t iv[8] = { 0 }; >+ uint8_t* tagPayload = tagData + 2; >+ des_cbc_decrypt(tagPayload, iv, emmKey, 136); >+ >+ for (k = 0; k < 0x10; k++) // loop 0x10 keys >+ { >+ for (i = 0; i < 8; i++) // loop 8 bytes of key >+ { >+ tagDataDecrypted[k][i] = tagPayload[MixTable[8*k + i]]; >+ } >+ } >+ >+ blockIndex = tagData[1] & 0x03; >+ >+ for(i = 0; i < 0x10; i++) >+ { >+ SetKey('T', (blockIndex << 4) + i, "MK01", tagDataDecrypted[i], 8, 0, NULL, NULL); >+ } >+ } >+ break; >+ >+ case 0xFF: // keySet FF (MK) >+ { >+ if(tagLength != 0x82) >+ { >+ cs_log("WARNING: nanoTag E4 length (%d) != %d", tagLength, 0x82); >+ break; >+ } >+ >+ blockIndex = tagData[1] & 0x03; >+ >+ if(!GetTandbergKey(keyIndex, "MK", emmKey, 8)) >+ { >+ break; >+ } >+ >+ des_set_key(emmKey, ks); >+ >+ for(i = 0; i < 0x10; i++) >+ { >+ des(tagData + 2 + (i*8), ks, 0); >+ } >+ >+ for(i = 0; i < 0x10; i++) >+ { >+ SetKey('T', (blockIndex << 4) + i, "MK", tagData + 2 + (i*8), 8, 0, NULL, NULL); >+ } >+ } >+ break; >+ >+ default: >+ cs_log("WARNING: nanoTag E4 mode %.2X not supported", tagMode); >+ break; >+ } >+ break; >+ } >+ >+ case 0xE1: // EMM_TAG_EVENT_ENTITLEMENT_DESCRIPTOR (ecm keys) >+ { >+ uint8_t tagMode = data[pos + 2 + 4]; >+ >+ switch(tagMode) >+ { >+ case 0x00: // ecm keys from mode FF >+ { >+ if(tagLength != 0x12) >+ { >+ cs_log("WARNING: nanoTag E1 length (%d) != %d", tagLength, 0x12); >+ break; >+ } >+ >+ entitlementId = b2i(4, tagData); >+ >+ if(!GetTandbergKey(keyIndex, "MK", emmKey, 8)) >+ { >+ break; >+ } >+ >+ des_set_key(emmKey, ks); >+ des(tagData + 4 + 5, ks, 0); >+ >+ if((tagData + 4 + 5 + 7) != 0x00) // check if key looks valid (last byte 0x00) >+ { >+ break; >+ } >+ >+ if(UpdateKey('T', entitlementId, "01", tagData + 4 + 5, 8, 1, NULL)) >+ { >+ (*keysAdded)++; >+ cs_hexdump(0, tagData + 4 + 5, 8, keyValue, sizeof(keyValue)); >+ cs_log("Key found in EMM: T %.8X 01 %s", entitlementId, keyValue); >+ } >+ } >+ break; >+ >+ case 0x01: // ecm keys from mode 01 >+ { >+ if(tagLength != 0x1A) >+ { >+ cs_log("WARNING: nanoTag E1 length (%d) != %d", tagLength, 0x1A); >+ break; >+ } >+ >+ entitlementId = b2i(4, tagData); >+ >+ if(!GetTandbergKey(keyIndex, "MK01", emmKey, 8)) >+ { >+ break; >+ } >+ >+ uint8_t ecmKey[8] = { 0 }; >+ TandbergECMKeyDecrypt(emmKey, tagData, ecmKey); >+ >+ if(ecmKey[7] != 0x00) // check if key looks valid (last byte 0x00) >+ { >+ break; >+ } >+ >+ if(UpdateKey('T', entitlementId, "01", ecmKey, 8, 1, NULL)) >+ { >+ (*keysAdded)++; >+ cs_hexdump(0, ecmKey, 8, keyValue, sizeof(keyValue)); >+ cs_log("Key found in EMM: T %.8X 01 %s", entitlementId, keyValue); >+ } >+ } >+ break; >+ >+ default: >+ cs_log("WARNING: nanoTag E1 mode %.2X not supported", tagMode); >+ break; >+ } >+ break; >+ } >+ >+ default: >+ cs_log("WARNING: nanoTag %.2X not supported", tagType); >+ break; >+ } >+ >+ pos += 2 + tagLength; >+ } >+ >+ return 0; >+} >+ >+static int8_t TandbergParseEMMNanoData(uint8_t* data, uint32_t* nanoLength, uint32_t maxLength, uint8_t keyIndex, uint32_t *keysAdded) >+{ >+ uint32_t pos = 0; >+ uint16_t sectionLength; >+ int8_t ret = 0; >+ >+ if(maxLength < 2) >+ { >+ (*nanoLength) = 0; >+ return 1; >+ } >+ >+ sectionLength = ((data[pos]<<8) | data[pos+1]) & 0x0FFF; >+ >+ if(pos + 2 + sectionLength > maxLength) >+ { >+ (*nanoLength) = pos; >+ return 1; >+ } >+ >+ ret = TandbergParseEMMNanoTags(data + pos + 2, sectionLength, keyIndex, keysAdded); >+ >+ pos += 2 + sectionLength; >+ >+ (*nanoLength) = pos; >+ return ret; >+} >+ >+static int8_t TandbergEMM(uint8_t *emm, uint32_t *keysAdded) >+{ >+ uint8_t keyIndex, ret = 0; >+ uint16_t emmLen = GetEcmLen(emm); >+ uint32_t pos = 3; >+ uint32_t permissionDataType; >+ uint32_t nanoLength = 0; >+ >+ while (pos < emmLen && !ret) >+ { >+ permissionDataType = emm[pos]; >+ >+ switch(permissionDataType) >+ { >+ case 0x00: >+ { >+ break; >+ } >+ >+ case 0x01: >+ { >+ pos += 0x0A; >+ break; >+ } >+ >+ case 0x02: >+ { >+ pos += 0x26; >+ break; >+ } >+ >+ default: >+ cs_log("ERROR: unknown permissionDataType %.2X (pos: %d)", permissionDataType, pos); >+ return 1; >+ } >+ >+ if(pos+6 >= emmLen) >+ { >+ break; >+ } >+ >+ keyIndex = emm[pos+1]; >+ >+ // EMM validation >+ // Copy payload checksum bytes and then set them to zero, >+ // so they do not affect the calculated checksum. >+ uint16_t payloadChecksum = (emm[pos + 2] << 8) | emm[pos + 3]; >+ memset(emm + pos + 2, 0, 2); >+ uint16_t calculatedChecksum = TandbergChecksum(emm + 3, emmLen - 3); >+ >+ if(calculatedChecksum != payloadChecksum) >+ { >+ cs_log("EMM checksum error (%.4X instead of %.4X)", calculatedChecksum, payloadChecksum); >+ return 8; >+ } >+ // End of EMM validation >+ >+ pos += 0x04; >+ ret = TandbergParseEMMNanoData(emm + pos, &nanoLength, emmLen - pos, keyIndex, keysAdded); >+ pos += nanoLength; >+ } >+ >+ return ret; >+} >+ >+const char* GetProcessEMMErrorReason(int8_t result) >+{ >+ switch(result) { >+ case 0: >+ return "No error"; >+ case 1: >+ return "EMM not supported"; >+ case 2: >+ return "Key not found"; >+ case 3: >+ return "Nano80 problem"; >+ case 4: >+ return "Corrupt data"; >+ case 5: >+ return "Unknown"; >+ case 6: >+ return "Checksum error"; >+ case 7: >+ return "Out of memory"; >+ case 8: >+ return "EMM checksum error"; >+ case 9: >+ return "Wrong provider"; >+ default: >+ return "Unknown"; >+ } >+} >+ >+int8_t ProcessEMM(struct s_reader *rdr, uint16_t caid, uint32_t provider, const uint8_t *emm, uint32_t *keysAdded) >+{ >+ int8_t result = 1; >+ uint8_t emmCopy[EMU_MAX_EMM_LEN]; >+ uint16_t emmLen = GetEcmLen(emm); >+ >+ if(emmLen > EMU_MAX_EMM_LEN) { >+ return 1; >+ } >+ memcpy(emmCopy, emm, emmLen); >+ *keysAdded = 0; >+ >+ if(caid==0x0500) { >+ result = ViaccessEMM(emmCopy, keysAdded); >+ } >+ else if((caid>>8)==0x06) { >+ result = Irdeto2EMM(caid, emmCopy, keysAdded); >+ } >+ else if((caid>>8)==0x0E) { >+ result = PowervuEMM(emmCopy, keysAdded); >+ } >+ else if(caid==0x4AE1) { >+ result = Drecrypt2EMM(rdr, provider, emmCopy, keysAdded); >+ } >+ else if((caid>>8)==0x10) { >+ result = TandbergEMM(emmCopy, keysAdded); >+ } >+ >+ if(result != 0) { >+ cs_log_dbg(D_EMM,"EMM failed: %s", GetProcessEMMErrorReason(result)); >+ } >+ >+ return result; >+} >Index: module-emulator-osemu.h >=================================================================== >--- module-emulator-osemu.h (revision 0) >+++ module-emulator-osemu.h (working copy) >@@ -0,0 +1,127 @@ >+#include "globals.h" >+#include "module-emulator-stream.h" >+ >+#ifndef EMULATOR_H_ >+#define EMULATOR_H_ >+ >+#define EMU_MAX_CHAR_KEYNAME 12 >+#define EMU_KEY_FILENAME "SoftCam.Key" >+#define EMU_KEY_FILENAME_MAX_LEN 31 >+#define EMU_MAX_ECM_LEN MAX_ECM_SIZE >+#define EMU_MAX_EMM_LEN MAX_EMM_SIZE >+ >+typedef struct KeyData KeyData; >+ >+struct KeyData >+{ >+ char identifier; >+ uint32_t provider; >+ char keyName[EMU_MAX_CHAR_KEYNAME]; >+ uint8_t *key; >+ uint32_t keyLength; >+ KeyData *nextKey; >+}; >+ >+typedef struct >+{ >+ KeyData *EmuKeys; >+ uint32_t keyCount; >+ uint32_t keyMax; >+} KeyDataContainer; >+ >+extern KeyDataContainer CwKeys; >+extern KeyDataContainer ViKeys; >+extern KeyDataContainer NagraKeys; >+extern KeyDataContainer IrdetoKeys; >+extern KeyDataContainer NDSKeys; >+extern KeyDataContainer BissKeys; >+extern KeyDataContainer PowervuKeys; >+extern KeyDataContainer DreKeys; >+extern KeyDataContainer TandbergKeys; >+extern uint8_t viasat_const[]; >+ >+uint32_t GetOSemuVersion(void); >+ >+void set_emu_keyfile_path(const char *path); >+void clear_emu_keydata(void); >+uint8_t read_emu_keyfile(struct s_reader *rdr, const char *path); >+ >+#if !defined(__APPLE__) && !defined(__ANDROID__) >+void read_emu_keymemory(struct s_reader *rdr); >+#endif >+ >+void read_emu_eebin(const char *path, const char *name); >+void read_emu_deskey(uint8_t *dreOverKey, uint8_t len); >+ >+int32_t CharToBin(uint8_t *out, const char *in, uint32_t inLen); >+ >+/* Error codes >+0 OK >+1 ECM not supported >+2 Key not found >+3 Nano80 problem >+4 Corrupt data >+5 CW not found >+6 CW checksum error >+7 Out of memory >+8 ECM checksum error >+9 ICG error >+*/ >+#ifdef WITH_EMU >+int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, >+ const uint8_t *ecm, uint8_t *dw, uint16_t srvid, uint16_t ecmpid, EXTENDED_CW* cw_ex); >+#else >+int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, >+ const uint8_t *ecm, uint8_t *dw, uint16_t srvid, uint16_t ecmpid); >+#endif >+ >+const char* GetProcessECMErrorReason(int8_t result); >+ >+/* Error codes >+0 OK >+1 EMM not supported >+2 Key not found >+3 Nano80 problem >+4 Corrupt data >+5 >+6 Checksum error >+7 Out of memory >+*/ >+int8_t ProcessEMM(struct s_reader *rdr, uint16_t caid, uint32_t provider, const uint8_t *emm, uint32_t *keysAdded); >+ >+const char* GetProcessEMMErrorReason(int8_t result); >+ >+// hexserial must be of type "uint8_t hexserial[3]" >+// returns 0 on error, 1 on success >+int32_t GetIrdeto2Hexserial(uint16_t caid, uint8_t* hexserial); >+ >+// hexserials must be of type "uint8_t hexserials[length][4]" >+// if srvid == 0xFFFF all serials are returned (no srvid filtering) >+// returns 0 on error, 1 on success >+int32_t GetPowervuHexserials(uint16_t srvid, uint8_t hexserials[][4], int32_t length, int32_t* count); >+ >+// hexserials must be of type "uint8_t hexserials[length]" >+// returns 0 on error, 1 on success >+int32_t GetDrecryptHexserials(uint16_t caid, uint32_t provid, uint8_t *hexserials, int32_t length, int32_t* count); >+ >+#define PVU_CW_VID 0 // VIDeo >+#define PVU_CW_HSD 1 // High Speed Data >+#define PVU_CW_A1 2 // Audio 1 >+#define PVU_CW_A2 3 // Audio 2 >+#define PVU_CW_A3 4 // Audio 3 >+#define PVU_CW_A4 5 // Audio 4 >+#define PVU_CW_UTL 6 // UTiLity >+#define PVU_CW_VBI 7 // Vertical Blanking Interval >+ >+#ifdef WITH_EMU >+int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, uint16_t srvid, emu_stream_client_key_data *cdata, EXTENDED_CW* cw_ex); >+#else >+int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, emu_stream_client_key_data *cdata); >+#endif >+ >+#ifdef WITH_EMU >+int32_t FindKey(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, uint8_t *key, >+ uint32_t maxKeyLength, uint8_t isCriticalKey, uint32_t keyRef, uint8_t matchLength, uint32_t *getProvider); >+#endif >+ >+#endif >Index: module-emulator-stream.c >=================================================================== >--- module-emulator-stream.c (revision 0) >+++ module-emulator-stream.c (working copy) >@@ -0,0 +1,1105 @@ >+#define MODULE_LOG_PREFIX "emu" >+ >+#include "globals.h" >+#include "cscrypt/des.h" >+ >+#ifdef WITH_EMU >+#include "oscam-string.h" >+#include "oscam-config.h" >+#include "oscam-time.h" >+#include "oscam-net.h" >+ >+extern int32_t exit_oscam; >+#endif >+ >+#include "ffdecsa/ffdecsa.h" >+#include "module-emulator-osemu.h" >+#include "module-emulator-stream.h" >+ >+typedef struct >+{ >+ int32_t connfd; >+ int32_t connid; >+} emu_stream_client_conn_data; >+ >+int8_t stream_server_thread_init = 0; >+char emu_stream_source_host[256] = {"127.0.0.1"}; >+int32_t emu_stream_source_port = 8001; >+char *emu_stream_source_auth = NULL; >+int32_t emu_stream_relay_port = 17999; >+int8_t emu_stream_emm_enabled = 0; >+uint32_t cluster_size = 50; >+ >+static uint8_t emu_stream_server_mutex_init = 0; >+static pthread_mutex_t emu_stream_server_mutex; >+static int32_t glistenfd, gconncount = 0, gconnfd[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+ >+#ifdef WITH_EMU >+pthread_mutex_t emu_fixed_key_srvid_mutex; >+uint16_t emu_stream_cur_srvid[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+int8_t stream_server_has_ecm[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+ >+pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+#endif >+ >+static void SearchTsPackets(uint8_t *buf, uint32_t bufLength, uint16_t *packetSize, uint16_t *startOffset) >+{ >+ uint32_t i; >+ >+ (*packetSize) = 0; >+ (*startOffset) = 0; >+ >+ for(i=0; i<bufLength; i++) { >+ if(buf[i] == 0x47) { >+ if((buf[i+188] == 0x47) & (buf[i+376] == 0x47)) { // if three packets align, probably safe to assume correct size. >+ (*packetSize) = 188; >+ (*startOffset) = i; >+ return; >+ } >+ else if((buf[i+204] == 0x47) & (buf[i+408] == 0x47)) { >+ (*packetSize) = 204; >+ (*startOffset) = i; >+ return; >+ } >+ else if((buf[i+208] == 0x47) & (buf[i+416] == 0x47)) { >+ (*packetSize) = 208; >+ (*startOffset) = i; >+ return; >+ } >+ } >+ } >+} >+ >+typedef void (*ts_data_callback)(emu_stream_client_data *cdata); >+ >+static void ParseTSData(uint8_t table_id, uint8_t table_mask, uint8_t min_table_length, int8_t* flag, uint8_t* data, >+ uint16_t data_length, uint16_t* data_pos, int8_t payloadStart, uint8_t* buf, int32_t len, >+ ts_data_callback func, emu_stream_client_data *cdata) >+{ >+ uint16_t section_length; >+ int32_t i; >+ int8_t found_start = 0; >+ uint16_t offset = 0; >+ int32_t free_data_length; >+ int32_t copySize; >+ >+ if(len < 1) >+ { return; } >+ >+ if(*flag == 0 && !payloadStart) >+ { return; } >+ >+ if(*flag == 0) >+ { >+ *data_pos = 0; >+ offset = 1 + buf[0]; >+ } >+ else if(payloadStart) >+ { >+ offset = 1; >+ } >+ >+ if(len-offset < 1) >+ { return; } >+ >+ free_data_length = data_length - *data_pos; >+ copySize = (len-offset) > free_data_length ? free_data_length : (len-offset); >+ >+ memcpy(data+(*data_pos), buf+offset, copySize); >+ (*data_pos) += copySize; >+ >+ found_start = 0; >+ for(i=0; i < *data_pos; i++) >+ { >+ if((data[i] & table_mask) == table_id) >+ { >+ if(i != 0) >+ { >+ if((*data_pos)-i > i) >+ { memmove(data, &data[i], (*data_pos)-i); } >+ else >+ { memcpy(data, &data[i], (*data_pos)-i); } >+ >+ *data_pos -= i; >+ } >+ found_start = 1; >+ break; >+ } >+ } >+ if(!found_start) >+ { *flag = 0; return; } >+ >+ *flag = 2; >+ >+ if(*data_pos < 3) >+ { return; } >+ >+ section_length = SCT_LEN(data); >+ >+ if(section_length > data_length || section_length < min_table_length) >+ { *flag = 0; return; } >+ >+ if((*data_pos) < section_length) >+ { return; } >+ >+ func(cdata); >+ >+ found_start = 0; >+ for(i=section_length; i < *data_pos; i++) >+ { >+ if((data[i] & table_mask) == table_id) >+ { >+ if((*data_pos)-i > i) >+ { memmove(data, &data[i], (*data_pos)-i); } >+ else >+ { memcpy(data, &data[i], (*data_pos)-i); } >+ >+ *data_pos -= i; >+ found_start = 1; >+ break; >+ } >+ } >+ if(!found_start) >+ { *data_pos = 0; } >+ >+ *flag = 1; >+} >+ >+static void ParsePATData(emu_stream_client_data *cdata) >+{ >+ uint8_t* data = cdata->pat_data; >+ uint16_t section_length = SCT_LEN(data); >+ uint16_t srvid; >+ int32_t i; >+ >+ for(i=8; i+7<section_length; i+=4) >+ { >+ srvid = b2i(2, data+i); >+ >+ if(srvid == 0) >+ { continue; } >+ >+ if(cdata->srvid == srvid) >+ { >+ cdata->pmt_pid = b2i(2, data+i+2) & 0x1FFF; >+ cs_log_dbg(D_READER, "Stream %i found pmt pid: 0x%04X (%i)",cdata->connid, cdata->pmt_pid, cdata->pmt_pid); >+ break; >+ } >+ } >+} >+ >+static void ParsePMTData(emu_stream_client_data *cdata) >+{ >+ uint8_t* data = cdata->pmt_data; >+ >+ uint16_t section_length = SCT_LEN(data); >+ int32_t i; >+ uint16_t program_info_length = 0, es_info_length = 0; >+ uint8_t descriptor_tag = 0, descriptor_length = 0; >+ uint8_t stream_type; >+ uint16_t stream_pid, caid; >+ >+ cdata->pcr_pid = b2i(2, data+8) &0x1FFF; >+ if(cdata->pcr_pid != 0x1FFF) >+ { >+ cs_log_dbg(D_READER, "Stream %i found pcr pid: 0x%04X (%i)",cdata->connid, cdata->pcr_pid, cdata->pcr_pid); >+ } >+ >+ program_info_length = b2i(2, data+10) &0xFFF; >+ >+ if(12+program_info_length >= section_length) >+ { return; } >+ >+ for(i=12; i+1 < 12+program_info_length; i+=descriptor_length+2) >+ { >+ descriptor_tag = data[i]; >+ descriptor_length = data[i+1]; >+ >+ if(descriptor_length < 1) >+ { break; } >+ >+ if(i+1+descriptor_length >= 12+program_info_length) >+ { break; } >+ >+ if(descriptor_tag == 0x09 && descriptor_length >= 4) >+ { >+ caid = b2i(2, data+i+2); >+ >+ if(caid>>8 == 0x0E) >+ { >+ cdata->ecm_pid = b2i(2, data+i+4) &0x1FFF; >+ cs_log_dbg(D_READER, "Stream %i found ecm pid: 0x%04X (%i)", cdata->connid, cdata->ecm_pid, cdata->ecm_pid); >+ break; >+ } >+ } >+ } >+ >+ for(i=12+program_info_length; i+4<section_length; i+=5+es_info_length) >+ { >+ stream_type = data[i]; >+ stream_pid = b2i(2, data+i+1) &0x1FFF; >+ es_info_length = b2i(2, data+i+3) &0xFFF; >+ >+ if(stream_type == 0x01 || stream_type == 0x02 || stream_type == 0x10 || stream_type == 0x1B >+ || stream_type == 0x24 || stream_type == 0x42 || stream_type == 0x80 || stream_type == 0xD1 >+ || stream_type == 0xEA) >+ { >+ cdata->video_pid = stream_pid; >+ cs_log_dbg(D_READER, "Stream %i found video pid: 0x%04X (%i)",cdata->connid, stream_pid, stream_pid); >+ } >+ >+ else if(stream_type == 0x03 || stream_type == 0x04 || stream_type == 0x05 || stream_type == 0x06 || >+ stream_type == 0x0F || stream_type == 0x11 || (stream_type >= 0x81 && stream_type <= 0x87) || stream_type == 0x8A) >+ { >+ if(cdata->audio_pid_count >= EMU_STREAM_MAX_AUDIO_SUB_TRACKS) >+ { continue; } >+ >+ cdata->audio_pids[cdata->audio_pid_count] = stream_pid; >+ cdata->audio_pid_count++; >+ cs_log_dbg(D_READER, "Stream %i found audio pid: 0x%04X (%i)", cdata->connid, stream_pid, stream_pid); >+ } >+ } >+} >+ >+static void ParseCATData(emu_stream_client_data *cdata) >+{ >+ uint8_t* data = cdata->cat_data; >+ uint32_t i; >+ >+ for(i = 8; i < (b2i(2, data + 1)&0xFFF) - 1; i += data[i + 1] + 2) >+ { >+ if(data[i] != 0x09) { continue; } >+ >+ uint16_t caid = b2i(2, data + i + 2); >+ uint16_t emm_pid = b2i(2, data + i +4)&0x1FFF; >+ >+ if(caid>>8 == 0x0E) >+ { >+ cdata->emm_pid = emm_pid; >+ cs_log_dbg(D_READER, "Stream %i found audio pid: 0x%04X (%i)", cdata->connid, emm_pid, emm_pid); >+ break; >+ } >+ } >+} >+ >+static void ParseEMMData(emu_stream_client_data *cdata) >+{ >+ uint8_t* data = cdata->emm_data; >+ uint32_t keysAdded = 0; >+ >+ ProcessEMM(NULL, 0x0E00, 0, data, &keysAdded); >+ >+ if(keysAdded) >+ { >+ cs_log("Stream %i found %i keys", cdata->connid, keysAdded); >+ } >+} >+ >+static void ParseECMData(emu_stream_client_data *cdata) >+{ >+ uint8_t* data = cdata->ecm_data; >+ uint16_t section_length = SCT_LEN(data); >+ uint8_t dcw[16]; >+ >+ if(section_length < 0xb) >+ { return; } >+ >+ if(data[0xb] > cdata->ecm_nb || (cdata->ecm_nb == 255 && data[0xb] == 0) >+ || ((cdata->ecm_nb - data[0xb]) > 5)) >+ { >+ cdata->ecm_nb = data[0xb]; >+#ifdef WITH_EMU >+ PowervuECM(data, dcw, cdata->srvid, &cdata->key, NULL); >+#else >+ PowervuECM(data, dcw, &cdata->key); >+#endif >+ } >+} >+ >+static void ParseTSPackets(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize) >+{ >+ uint32_t i, j, k; >+ uint32_t tsHeader; >+ uint16_t pid, offset; >+ uint8_t scramblingControl, payloadStart, oddeven; >+ int8_t oddKeyUsed; >+ uint32_t *deskey; >+ uint8_t *pdata; >+ uint8_t *packetClusterA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS][64]; // separate cluster arrays for video and each audio track >+ uint8_t *packetClusterV[256]; >+ void *csakeyA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS] = {0}; >+ void *csakeyV = 0; >+ emu_stream_client_key_data *keydata; >+ uint32_t scrambled_packets = 0; >+ uint32_t scrambled_packetsA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS] = {0}; >+ packetClusterV[0] = NULL; >+ uint32_t cs =0; // video cluster start >+ uint32_t ce =1; // video cluster end >+ uint32_t csa[EMU_STREAM_MAX_AUDIO_SUB_TRACKS] = {0}; // cluster index for audio tracks >+ >+ for(i=0; i<bufLength; i+=packetSize) >+ { >+ tsHeader = b2i(4, stream_buf+i); >+ pid = (tsHeader & 0x1fff00) >> 8; >+ scramblingControl = tsHeader & 0xc0; >+ payloadStart = (tsHeader & 0x400000) >> 22; >+ >+ if(tsHeader & 0x20) >+ { offset = 4 + stream_buf[i+4] + 1; } >+ else >+ { offset = 4; } >+ >+ if(packetSize-offset < 1) >+ { continue; } >+ >+ if(pid == 1) >+ { >+ // set to null pid >+ stream_buf[i+1] |= 0x1f; >+ stream_buf[i+2] = 0xff; >+ >+ if(emu_stream_emm_enabled && !data->emm_pid) >+ { >+ ParseTSData(0x01, 0xFF, 8, &data->have_cat_data, data->cat_data, sizeof(data->cat_data), &data->cat_data_pos, payloadStart, >+ stream_buf+i+offset, packetSize-offset, ParseCATData, data); >+ continue; >+ } >+ } >+ >+ if(emu_stream_emm_enabled && data->emm_pid && pid == data->emm_pid) >+ { >+ // set to null pid >+ stream_buf[i+1] |= 0x1f; >+ stream_buf[i+2] = 0xff; >+ >+ ParseTSData(0x80, 0xF0, 3, &data->have_emm_data, data->emm_data, sizeof(data->emm_data), &data->emm_data_pos, payloadStart, >+ stream_buf+i+offset, packetSize-offset, ParseEMMData, data); >+ continue; >+ } >+ >+ if(pid == 0 && !data->pmt_pid) >+ { >+ ParseTSData(0x00, 0xFF, 16, &data->have_pat_data, data->pat_data, sizeof(data->pat_data), &data->pat_data_pos, payloadStart, >+ stream_buf+i+offset, packetSize-offset, ParsePATData, data); >+ continue; >+ } >+ >+ if(!data->ecm_pid && pid == data->pmt_pid) >+ { >+ ParseTSData(0x02, 0xFF, 21, &data->have_pmt_data, data->pmt_data, sizeof(data->pmt_data), &data->pmt_data_pos, payloadStart, >+ stream_buf+i+offset, packetSize-offset, ParsePMTData, data); >+ continue; >+ } >+ >+ if(data->ecm_pid && pid == data->ecm_pid) >+ { >+#ifdef WITH_EMU >+ stream_server_has_ecm[data->connid] = 1; >+#endif >+ >+ // set to null pid >+ stream_buf[i+1] |= 0x1f; >+ stream_buf[i+2] = 0xff; >+ >+ ParseTSData(0x80, 0xFE, 3, &data->have_ecm_data, data->ecm_data, sizeof(data->ecm_data), &data->ecm_data_pos, payloadStart, >+ stream_buf+i+offset, packetSize-offset, ParseECMData, data); >+ continue; >+ } >+ >+ if(scramblingControl == 0) >+ { continue; } >+ >+ if(!(stream_buf[i+3] & 0x10)) >+ { >+ stream_buf[i+3] &= 0x3F; >+ continue; >+ } >+ >+ oddKeyUsed = scramblingControl == 0xC0 ? 1 : 0; >+ >+#ifdef WITH_EMU >+ if(!stream_server_has_ecm[data->connid]) >+ { >+ keydata = &emu_fixed_key_data[data->connid]; >+ SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[data->connid]); >+ data->key.pvu_csa_used = keydata->pvu_csa_used; >+ } >+ else >+ { >+#endif >+ keydata = &data->key; >+#ifdef WITH_EMU >+ } >+#endif >+ >+ if(keydata->pvu_csa_used) >+ { >+ oddeven = scramblingControl; // for detecting odd/even switch >+ >+ if(pid == data->video_pid) // start with video pid, since it is most dominant >+ { >+ csakeyV = keydata->pvu_csa_ks[PVU_CW_VID]; >+ >+ if(csakeyV !=NULL) >+ { >+ cs=0; >+ ce=1; >+ packetClusterV[cs] = stream_buf+i; // set first cluster start >+ packetClusterV[ce] = stream_buf+i+packetSize-1; >+ scrambled_packets=1; >+ >+ for(j = i+packetSize; j < bufLength; j += packetSize) // Now iterate through the rest of the packets and create clusters for batch decryption >+ { >+ tsHeader = b2i(4, stream_buf+j); >+ pid = (tsHeader & 0x1fff00) >> 8; >+ if(pid == data->video_pid) >+ { >+ if(oddeven != (tsHeader & 0xc0)) // changed key so stop adding clusters >+ { >+ break; >+ } >+ if(cs > ce) // First video packet for each cluster >+ { >+ packetClusterV[cs] = stream_buf+j; >+ ce = cs+1; >+ } >+ >+ scrambled_packets++; >+ } >+ else >+ { >+ if(cs < ce) // First non-video packet - need to set end of video cluster >+ { >+ packetClusterV[ce] = stream_buf+j-1; >+ cs = ce+1; >+ } >+ >+ if((tsHeader & 0xc0) == 0) { >+ continue; >+ } >+ >+ if(oddeven != (tsHeader & 0xc0)) // changed key so stop adding clusters >+ { >+ j = bufLength; // to break out of outer loop also >+ break; >+ } >+ >+ for(k = 0; k < data->audio_pid_count; k++) // Check for audio tracks and create single packet clusters >+ { >+ if(pid == data->audio_pids[k]) >+ { >+ packetClusterA[k][csa[k]] = stream_buf+j; >+ csa[k]++; >+ packetClusterA[k][csa[k]] = stream_buf+j+packetSize-1; >+ csa[k]++; >+ scrambled_packetsA[k]++; >+ } >+ } >+ } >+ } >+ >+ if( cs > ce ) // last packet was not a video packet, so set null for end of all clusters >+ { packetClusterV[cs] = NULL; } >+ else >+ { >+ if(scrambled_packets > 1) // last packet was a video packet, so set end of cluster to end of last packet >+ { >+ packetClusterV[ce] = stream_buf+j-1; >+ } >+ packetClusterV[ce+1] = NULL; // add null to end of cluster list >+ } >+ >+ while( j >= cluster_size ) >+ { j = decrypt_packets(csakeyV, packetClusterV); } >+ >+ for(k = 0; k < data->audio_pid_count; k++) >+ { >+ if(scrambled_packetsA[k]) // if audio track has scrambled packets, set null to mark end and decrypt >+ { >+ csakeyA[k] = keydata->pvu_csa_ks[PVU_CW_A1+k]; >+ packetClusterA[k][csa[k]] = NULL; >+ decrypt_packets(csakeyA[k], packetClusterA[k]); >+ csa[k]=0; >+ scrambled_packetsA[k] = 0; >+ } >+ } >+ } >+ } >+ else >+ { >+ for(j = 0; j < data->audio_pid_count; j++) >+ if(pid == data->audio_pids[j]) >+ { csakeyA[0] = keydata->pvu_csa_ks[PVU_CW_A1+j]; } >+ >+ if(csakeyA[0] != NULL) >+ { >+ packetClusterA[0][0] = stream_buf+i; >+ packetClusterA[0][1] = stream_buf+i+packetSize -1; >+ packetClusterA[0][2] = NULL; >+ decrypt_packets(csakeyA[0], packetClusterA[0]); >+ } >+ } >+ } >+ else >+ { >+ deskey = NULL; >+ >+ if(pid == data->video_pid) >+ { deskey = keydata->pvu_des_ks[PVU_CW_VID][oddKeyUsed]; } >+ else >+ { >+ for(j = 0; j < data->audio_pid_count; j++) >+ if(pid == data->audio_pids[j]) >+ { deskey = keydata->pvu_des_ks[PVU_CW_A1+j][oddKeyUsed]; } >+ } >+ >+ if(deskey == NULL) >+ { >+ deskey = keydata->pvu_des_ks[PVU_CW_HSD][oddKeyUsed]; >+ } >+ >+ for(j = offset; j+7 < 188; j += 8) >+ { >+ pdata = stream_buf+i+j; >+ des(pdata, deskey, 0); >+ } >+ >+ stream_buf[i+3] &= 0x3F; >+ } >+ >+#ifdef WITH_EMU >+ if(!stream_server_has_ecm[data->connid]) >+ { >+ SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[data->connid]); >+ } >+#endif >+ } >+} >+ >+static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *stream_path) >+{ >+ struct sockaddr_in cservaddr; >+ IN_ADDR_T in_addr; >+ >+ int32_t streamfd = socket(AF_INET, SOCK_STREAM, 0); >+ if(streamfd == -1) >+ { return -1; } >+ >+ struct timeval tv; >+ tv.tv_sec = 2; >+ tv.tv_usec = 0; >+ if(setsockopt(streamfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv)) >+ { >+ cs_log("ERROR: setsockopt() failed for SO_RCVTIMEO"); >+ return -1; >+ } >+ >+ bzero(&cservaddr, sizeof(cservaddr)); >+ cservaddr.sin_family = AF_INET; >+ cs_resolve(emu_stream_source_host, &in_addr, NULL, NULL); >+ SIN_GET_ADDR(cservaddr) = in_addr; >+ cservaddr.sin_port = htons(emu_stream_source_port); >+ >+ if(connect(streamfd, (struct sockaddr *)&cservaddr, sizeof(cservaddr)) == -1) >+ { return -1; } >+ if(emu_stream_source_auth) >+ { >+ snprintf(http_buf, http_buf_len, "GET %s HTTP/1.1\nHost: %s:%u\n" >+ "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0\n" >+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n" >+ "Accept-Language: en-US\n" >+ "Authorization: Basic %s\n" >+ "Connection: keep-alive\n\n", stream_path, emu_stream_source_host, emu_stream_source_port, emu_stream_source_auth); >+ } >+ else >+ { >+ snprintf(http_buf, http_buf_len, "GET %s HTTP/1.1\nHost: %s:%u\n" >+ "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0\n" >+ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n" >+ "Accept-Language: en-US\n" >+ "Connection: keep-alive\n\n", stream_path, emu_stream_source_host, emu_stream_source_port); >+ } >+ >+ if(send(streamfd, http_buf, strlen(http_buf), 0) == -1) >+ { return -1; } >+ >+ return streamfd; >+} >+ >+static void stream_client_disconnect(emu_stream_client_conn_data *conndata) >+{ >+ int32_t i; >+ >+#ifdef WITH_EMU >+ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); >+ emu_stream_cur_srvid[conndata->connid] = NO_SRVID_VALUE; >+ stream_server_has_ecm[conndata->connid] = 0; >+ SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); >+#endif >+ >+ SAFE_MUTEX_LOCK(&emu_stream_server_mutex); >+ for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++) >+ { >+ if(gconnfd[i] == conndata->connfd) >+ { >+ gconnfd[i] = -1; >+ gconncount--; >+ } >+ } >+ SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex); >+ >+ shutdown(conndata->connfd, 2); >+ close(conndata->connfd); >+ >+ cs_log("Stream client %i disconnected",conndata->connid); >+ >+ NULLFREE(conndata); >+} >+ >+static void *stream_client_handler(void *arg) >+{ >+#define EMU_DVB_MAX_TS_PACKETS 278 >+#define EMU_DVB_BUFFER_SIZE_CSA 188*EMU_DVB_MAX_TS_PACKETS >+#define EMU_DVB_BUFFER_WAIT_CSA 188*(EMU_DVB_MAX_TS_PACKETS-128) >+#define EMU_DVB_BUFFER_SIZE_DES 188*32 >+#define EMU_DVB_BUFFER_WAIT_DES 188*29 >+#define EMU_DVB_BUFFER_SIZE EMU_DVB_BUFFER_SIZE_CSA >+ >+ emu_stream_client_conn_data *conndata = (emu_stream_client_conn_data *)arg; >+ char *http_buf, stream_path[255], stream_path_copy[255]; >+ int32_t streamfd; >+ int32_t clientStatus, streamStatus; >+ uint8_t *stream_buf; >+ uint16_t packetCount = 0, packetSize = 0, startOffset = 0; >+ uint32_t remainingDataPos, remainingDataLength; >+ int32_t cur_dvb_buffer_size, cur_dvb_buffer_wait; >+ int32_t bytesRead = 0; >+ emu_stream_client_data *data; >+ int8_t streamConnectErrorCount = 0; >+ int8_t streamDataErrorCount = 0; >+ int32_t i, srvidtmp; >+ char *saveptr, *token; >+ char http_version[4]; >+ int32_t http_status_code = 0; >+ >+ cs_log("Stream client %i connected", conndata->connid); >+ >+ if(!cs_malloc(&http_buf, 1024)) >+ { >+ stream_client_disconnect(conndata); >+ return NULL; >+ } >+ >+ if(!cs_malloc(&stream_buf, EMU_DVB_BUFFER_SIZE)) >+ { >+ NULLFREE(http_buf); >+ stream_client_disconnect(conndata); >+ return NULL; >+ } >+ >+ if(!cs_malloc(&data, sizeof(emu_stream_client_data))) >+ { >+ NULLFREE(http_buf); >+ NULLFREE(stream_buf); >+ stream_client_disconnect(conndata); >+ return NULL; >+ } >+ >+ clientStatus = recv(conndata->connfd, http_buf, 1024, 0); >+ if(clientStatus < 1) >+ { >+ NULLFREE(http_buf); >+ NULLFREE(stream_buf); >+ NULLFREE(data); >+ stream_client_disconnect(conndata); >+ return NULL; >+ } >+ >+ http_buf[1023] = '\0'; >+ if(sscanf(http_buf, "GET %254s ", stream_path) < 1) >+ { >+ NULLFREE(http_buf); >+ NULLFREE(stream_buf); >+ NULLFREE(data); >+ stream_client_disconnect(conndata); >+ return NULL; >+ } >+ >+ cs_strncpy(stream_path_copy, stream_path, sizeof(stream_path)); >+ >+ token = strtok_r(stream_path_copy, ":", &saveptr); >+ >+ for(i=0; token != NULL && i<3; i++) >+ { >+ token = strtok_r(NULL, ":", &saveptr); >+ if(token == NULL) >+ { break; } >+ } >+ if(token != NULL) >+ { >+ if(sscanf(token, "%x", &srvidtmp) < 1) >+ { >+ token = NULL; >+ } >+ else >+ { >+ data->srvid = srvidtmp & 0xFFFF; >+ } >+ } >+ >+ if(token == NULL) >+ { >+ NULLFREE(http_buf); >+ NULLFREE(stream_buf); >+ NULLFREE(data); >+ stream_client_disconnect(conndata); >+ return NULL; >+ } >+ >+#ifdef WITH_EMU >+ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); >+ emu_stream_cur_srvid[conndata->connid] = data->srvid; >+ stream_server_has_ecm[conndata->connid] = 0; >+ SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); >+#endif >+ >+ cs_log("Stream client %i request %s", conndata->connid, stream_path); >+ >+ snprintf(http_buf, 1024, "HTTP/1.0 200 OK\nConnection: Close\nContent-Type: video/mpeg\nServer: stream_enigma2\n\n"); >+ clientStatus = send(conndata->connfd, http_buf, strlen(http_buf), 0); >+ >+ data->connid = conndata->connid; >+ >+ while(!exit_oscam && clientStatus != -1 && streamConnectErrorCount < 3 && streamDataErrorCount < 15) >+ { >+ streamfd = connect_to_stream(http_buf, 1024, stream_path); >+ if(streamfd == -1) >+ { >+ cs_log("WARNING: stream client %i cannot connect to stream source", conndata->connid); >+ streamConnectErrorCount++; >+ cs_sleepms(500); >+ continue; >+ } >+ >+ streamStatus = 0; >+ bytesRead = 0; >+ >+ while(!exit_oscam && clientStatus != -1 && streamStatus != -1 && streamConnectErrorCount < 3 && streamDataErrorCount < 15) >+ { >+ if(data->key.pvu_csa_used) >+ { >+ cur_dvb_buffer_size = EMU_DVB_BUFFER_SIZE_CSA; >+ cur_dvb_buffer_wait = EMU_DVB_BUFFER_WAIT_CSA; >+ } >+ else >+ { >+ cur_dvb_buffer_size = EMU_DVB_BUFFER_SIZE_DES; >+ cur_dvb_buffer_wait = EMU_DVB_BUFFER_WAIT_DES; >+ } >+ >+ streamStatus = recv(streamfd, stream_buf+bytesRead, cur_dvb_buffer_size-bytesRead, MSG_WAITALL); >+ if(streamStatus == 0) // socket closed >+ { >+ cs_log("WARNING: stream client %i - stream source closed connection", conndata->connid); >+ streamConnectErrorCount++; >+ cs_sleepms(100); >+ break; >+ } >+ >+ if(streamStatus < 0) // error >+ { >+ if ((errno == EWOULDBLOCK) | (errno == EAGAIN)) { >+ cs_log("WARNING: stream client %i no data from stream source", conndata->connid); >+ streamDataErrorCount++; // 2 sec timeout * 15 = 30 seconds no data -> close >+ cs_sleepms(100); >+ continue; >+ } >+ >+ cs_log("WARNING: stream client %i error receiving data from stream source", conndata->connid); >+ streamConnectErrorCount++; >+ cs_sleepms(100); >+ break; >+ } >+ >+ if(streamStatus < cur_dvb_buffer_size-bytesRead) // probably just received header but no stream >+ { >+ if(!bytesRead && streamStatus > 13 && >+ sscanf((const char*)stream_buf, "HTTP/%3s %d ", http_version , &http_status_code) == 2 && >+ http_status_code != 200) >+ { >+ cs_log("ERROR: stream client %i got %d response from stream source", conndata->connid, http_status_code); >+ streamConnectErrorCount++; >+ cs_sleepms(100); >+ break; >+ } >+ else >+ { >+ cs_log_dbg(0, "WARNING: stream client %i non-full buffer from stream source", conndata->connid); >+ streamDataErrorCount++; >+ cs_sleepms(100); >+ } >+ } >+ else >+ { >+ streamDataErrorCount = 0; >+ } >+ >+ streamConnectErrorCount = 0; >+ bytesRead += streamStatus; >+ >+ if(bytesRead >= cur_dvb_buffer_wait) >+ { >+ startOffset = 0; >+ if(stream_buf[0] != 0x47 || packetSize == 0) // only search if not starting on ts packet or unknown packet size >+ { >+ SearchTsPackets(stream_buf, bytesRead, &packetSize, &startOffset); >+ } >+ if(packetSize == 0) >+ { >+ bytesRead = 0; >+ } >+ else >+ { >+ packetCount = ((bytesRead-startOffset) / packetSize); >+ >+ ParseTSPackets(data, stream_buf+startOffset, packetCount*packetSize, packetSize); >+ >+ clientStatus = send(conndata->connfd, stream_buf+startOffset, packetCount*packetSize, 0); >+ >+ remainingDataPos = startOffset+(packetCount*packetSize); >+ remainingDataLength = bytesRead-remainingDataPos; >+ >+ if(remainingDataPos < remainingDataLength) >+ { memmove(stream_buf, stream_buf+remainingDataPos, remainingDataLength); } >+ else >+ { memcpy(stream_buf, stream_buf+remainingDataPos, remainingDataLength); } >+ >+ bytesRead = remainingDataLength; >+ } >+ } >+ } >+ >+ close(streamfd); >+ } >+ >+ NULLFREE(http_buf); >+ NULLFREE(stream_buf); >+ for(i=0; i<8; i++) >+ { >+ if(data->key.pvu_csa_ks[i]) >+ { free_key_struct(data->key.pvu_csa_ks[i]); } >+ } >+ NULLFREE(data); >+ >+ stream_client_disconnect(conndata); >+ return NULL; >+} >+ >+void *stream_server(void *UNUSED(a)) >+{ >+ struct sockaddr_in servaddr, cliaddr; >+ socklen_t clilen; >+ int32_t connfd, reuse = 1, i; >+ int8_t connaccepted; >+ emu_stream_client_conn_data *conndata; >+ >+ cluster_size = get_internal_parallelism(); >+ cs_log("INFO: FFDecsa parallel mode = %d", cluster_size); >+ >+ if(!emu_stream_server_mutex_init) >+ { >+ SAFE_MUTEX_INIT(&emu_stream_server_mutex, NULL); >+ emu_stream_server_mutex_init = 1; >+ } >+ >+#ifdef WITH_EMU >+ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); >+ for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++) >+ { >+ emu_stream_cur_srvid[i] = NO_SRVID_VALUE; >+ stream_server_has_ecm[i] = 0; >+ } >+ SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); >+#endif >+ >+ for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++) >+ { >+ gconnfd[i] = -1; >+ } >+ >+ glistenfd = socket(AF_INET, SOCK_STREAM, 0); >+ if(glistenfd == -1) >+ { >+ cs_log("ERROR: cannot create stream server socket"); >+ return NULL; >+ } >+ >+ bzero(&servaddr,sizeof(servaddr)); >+ servaddr.sin_family = AF_INET; >+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY); >+ servaddr.sin_port = htons(emu_stream_relay_port); >+ setsockopt(glistenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); >+ >+ if(bind(glistenfd,(struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) >+ { >+ cs_log("ERROR: cannot bind to stream server socket"); >+ close(glistenfd); >+ return NULL; >+ } >+ >+ if(listen(glistenfd, 3) == -1) >+ { >+ cs_log("ERROR: cannot listen to stream server socket"); >+ close(glistenfd); >+ return NULL; >+ } >+ >+ while(!exit_oscam) >+ { >+ clilen = sizeof(cliaddr); >+ connfd = accept(glistenfd,(struct sockaddr *)&cliaddr, &clilen); >+ >+ if(connfd == -1) >+ { >+ cs_log("ERROR: accept() failed"); >+ break; >+ } >+ >+ connaccepted = 0; >+ >+ if(cs_malloc(&conndata, sizeof(emu_stream_client_conn_data))) >+ { >+ SAFE_MUTEX_LOCK(&emu_stream_server_mutex); >+ if(gconncount < EMU_STREAM_SERVER_MAX_CONNECTIONS) >+ { >+ for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++) >+ { >+ if(gconnfd[i] == -1) >+ { >+ gconnfd[i] = connfd; >+ gconncount++; >+ connaccepted = 1; >+ >+ conndata->connfd = connfd; >+ conndata->connid = i; >+ >+ break; >+ } >+ } >+ } >+ SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex); >+ } >+ >+ if(connaccepted) >+ { >+ int on = 1; >+ if(setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) >+ { >+ cs_log("ERROR: stream client %i setsockopt() failed for TCP_NODELAY", conndata->connid); >+ } >+ >+ start_thread("emu stream client", stream_client_handler, (void*)conndata, NULL, 1, 0); >+ } >+ else >+ { >+ shutdown(connfd, 2); >+ close(connfd); >+ cs_log("ERROR: stream server client dropped because of too many connections (%i)", EMU_STREAM_SERVER_MAX_CONNECTIONS); >+ } >+ >+ cs_sleepms(20); >+ } >+ >+ close(glistenfd); >+ >+ return NULL; >+} >+ >+#ifdef WITH_EMU >+void *stream_key_delayer(void *UNUSED(arg)) >+{ >+ int32_t i, j; >+ emu_stream_client_key_data* cdata; >+ LL_ITER it; >+ emu_stream_cw_item *item; >+ struct timeb t_now; >+ >+ while(!exit_oscam) >+ { >+ cs_ftime(&t_now); >+ >+ for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++) >+ { >+ it = ll_iter_create(ll_emu_stream_delayed_keys[i]); >+ while((item = ll_iter_next(&it))) >+ { >+ if(comp_timeb(&t_now, &item->write_time) < 0) >+ { >+ break; >+ } >+ >+ SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[i]); >+ >+ cdata = &emu_fixed_key_data[i]; >+ >+ for(j=0; j<8; j++) >+ { >+ if(item->csa_used) >+ { >+ if(cdata->pvu_csa_ks[j] == NULL) >+ { cdata->pvu_csa_ks[j] = get_key_struct(); } >+ >+ if(item->is_even) >+ { set_even_control_word(cdata->pvu_csa_ks[j], item->cw[j]); } >+ else >+ { set_odd_control_word(cdata->pvu_csa_ks[j], item->cw[j]); } >+ >+ cdata->pvu_csa_used = 1; >+ } >+ else >+ { >+ if(item->is_even) >+ { des_set_key(item->cw[j], cdata->pvu_des_ks[j][0]); } >+ else >+ { des_set_key(item->cw[j], cdata->pvu_des_ks[j][1]); } >+ >+ cdata->pvu_csa_used = 0; >+ } >+ } >+ >+ SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[i]); >+ >+ ll_iter_remove_data(&it); >+ } >+ } >+ >+ cs_sleepms(25); >+ } >+ >+ return NULL; >+} >+#endif >+ >+void stop_stream_server(void) >+{ >+ int32_t i; >+ >+ SAFE_MUTEX_LOCK(&emu_stream_server_mutex); >+ for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++) >+ { >+ if(gconnfd[i] != -1) >+ { >+ shutdown(gconnfd[i], 2); >+ close(gconnfd[i]); >+ gconnfd[i] = -1; >+ } >+ } >+ >+ gconncount = 0; >+ SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex); >+ >+ shutdown(glistenfd, 2); >+ close(glistenfd); >+} >Index: module-emulator-stream.h >=================================================================== >--- module-emulator-stream.h (revision 0) >+++ module-emulator-stream.h (working copy) >@@ -0,0 +1,75 @@ >+#ifndef EMU_STREAM_SERVER_H_ >+#define EMU_STREAM_SERVER_H_ >+ >+#define EMU_STREAM_SERVER_MAX_CONNECTIONS 8 >+#define EMU_STREAM_MAX_AUDIO_SUB_TRACKS 16 >+ >+typedef struct >+{ >+ uint32_t pvu_des_ks[8][2][32]; >+ int8_t pvu_csa_used; >+ void* pvu_csa_ks[8]; >+} emu_stream_client_key_data; >+ >+typedef struct >+{ >+ int32_t connid; >+ int8_t have_cat_data; >+ int8_t have_pat_data; >+ int8_t have_pmt_data; >+ int8_t have_ecm_data; >+ int8_t have_emm_data; >+ uint8_t cat_data[1024+208]; >+ uint8_t pat_data[1024+208]; >+ uint8_t pmt_data[1024+208]; >+ uint8_t ecm_data[1024+208]; >+ uint8_t emm_data[1024+208]; >+ uint16_t cat_data_pos; >+ uint16_t pat_data_pos; >+ uint16_t pmt_data_pos; >+ uint16_t ecm_data_pos; >+ uint16_t emm_data_pos; >+ uint16_t srvid; >+ uint16_t pmt_pid; >+ uint16_t ecm_pid; >+ uint16_t emm_pid; >+ uint16_t video_pid; >+ uint16_t pcr_pid; >+ uint16_t audio_pids[EMU_STREAM_MAX_AUDIO_SUB_TRACKS]; >+ uint8_t audio_pid_count; >+ int16_t ecm_nb; >+ emu_stream_client_key_data key; >+} emu_stream_client_data; >+ >+extern char emu_stream_source_host[256]; >+extern int32_t emu_stream_source_port; >+extern char *emu_stream_source_auth; >+extern int32_t emu_stream_relay_port; >+extern int8_t emu_stream_emm_enabled; >+ >+extern int8_t stream_server_thread_init; >+ >+void *stream_server(void *a); >+void stop_stream_server(void); >+ >+#ifdef WITH_EMU >+typedef struct >+{ >+ struct timeb write_time; >+ int8_t csa_used; >+ int8_t is_even; >+ uint8_t cw[8][8]; >+} emu_stream_cw_item; >+ >+extern pthread_mutex_t emu_fixed_key_srvid_mutex; >+extern uint16_t emu_stream_cur_srvid[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+extern int8_t stream_server_has_ecm[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+ >+extern pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+extern emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+extern LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS]; >+ >+void *stream_key_delayer(void *arg); >+#endif >+ >+#endif >Index: module-emulator.c >=================================================================== >--- module-emulator.c (revision 0) >+++ module-emulator.c (working copy) >@@ -0,0 +1,904 @@ >+#define MODULE_LOG_PREFIX "emu" >+ >+#include "globals.h" >+#include "oscam-string.h" >+#include "oscam-config.h" >+#include "oscam-conf-chk.h" >+#include "oscam-time.h" >+#include "oscam-reader.h" >+#include "module-emulator-osemu.h" >+#include "module-emulator-stream.h" >+ >+/* >+ * Readers in OSCam consist of 2 basic parts. >+ * The hardware or the device part. This is where physical smart cards are inserted >+ * and made available to OSCam. >+ * The software or the emulation part. This is where the actual card reading is done, >+ * including ecm and emm processing (i.e emulation of the various cryptosystems). >+ * In the Emu reader, the device part has no meaning, but we have to create it in >+ * order to be compatible with OSCam's reader structure. >+*/ >+ >+/* >+ * Create the Emu "emulation" part. This is of type s_cardsystem. >+ * Similar structures are found in the main sources folder (files reader-xxxxxx.c) >+ * for every cryptosystem supported by OSCam. >+ * Here we read keys from our virtual card (aka the SoftCam.Key file) and we inform >+ * OSCam about them. This is done with the emu_card_info() function. Keep in mind >+ * that Emu holds all its keys to separate structures for faster access. >+ * In addition, ECM and EMM requests are processed here, with the emu_do_ecm() and >+ * emu_do_emm() functions. >+*/ >+ >+#define CS_OK 1 >+#define CS_ERROR 0 >+ >+static uint8_t oneByte = 0x01; >+extern char cs_confdir[128]; >+ >+static void set_hexserial_to_version(struct s_reader *rdr) >+{ >+ char cVersion[32]; >+ uint32_t version = GetOSemuVersion(); >+ uint8_t hversion[2]; >+ memset(hversion, 0, 2); >+ snprintf(cVersion, sizeof(cVersion), "%04d", version); >+ CharToBin(hversion, cVersion, 4); >+ rdr->hexserial[3] = hversion[0]; >+ rdr->hexserial[4] = hversion[1]; >+} >+ >+static void set_prids(struct s_reader *rdr) >+{ >+ int32_t i, j; >+ >+ rdr->nprov = 0; >+ >+ for (i = 0; (i < rdr->emu_auproviders.nfilts) && (rdr->nprov < CS_MAXPROV); i++) >+ { >+ for (j = 0; (j < rdr->emu_auproviders.filts[i].nprids) && (rdr->nprov < CS_MAXPROV); j++) >+ { >+ i2b_buf(4, rdr->emu_auproviders.filts[i].prids[j], rdr->prid[i]); >+ rdr->nprov++; >+ } >+ } >+} >+ >+static void emu_add_entitlement(struct s_reader *rdr, uint16_t caid, uint32_t provid, uint8_t *key, char *keyName, uint32_t keyLength, uint8_t isData) >+{ >+ if (!rdr->ll_entitlements) >+ { >+ rdr->ll_entitlements = ll_create("ll_entitlements"); >+ } >+ >+ S_ENTITLEMENT *item; >+ if (cs_malloc(&item, sizeof(S_ENTITLEMENT))) >+ { >+ // fill item >+ item->caid = caid; >+ item->provid = provid; >+ item->id = 0; >+ item->class = 0; >+ item->start = 0; >+ item->end = 2147472000; >+ item->type = 0; >+ item->isKey = 1; >+ memcpy(item->name, keyName, 8); >+ item->key = key; >+ item->keyLength = keyLength; >+ item->isData = isData; >+ >+ // add item >+ ll_append(rdr->ll_entitlements, item); >+ } >+} >+ >+static void refresh_entitlements(struct s_reader *rdr) >+{ >+ uint32_t i; >+ KeyData *tmpKeyData; >+ >+ cs_clear_entitlement(rdr); >+ >+ for (i = 0; i < CwKeys.keyCount; i++) >+ { >+ emu_add_entitlement(rdr, CwKeys.EmuKeys[i].provider >> 8, CwKeys.EmuKeys[i].provider & 0xFF, >+ CwKeys.EmuKeys[i].key, CwKeys.EmuKeys[i].keyName, CwKeys.EmuKeys[i].keyLength, 0); >+ } >+ >+ for (i = 0; i < ViKeys.keyCount; i++) >+ { >+ emu_add_entitlement(rdr, 0x500, ViKeys.EmuKeys[i].provider, ViKeys.EmuKeys[i].key, >+ ViKeys.EmuKeys[i].keyName, ViKeys.EmuKeys[i].keyLength, 0); >+ } >+ >+ for (i = 0; i < NagraKeys.keyCount; i++) >+ { >+ emu_add_entitlement(rdr, 0x1801, NagraKeys.EmuKeys[i].provider, NagraKeys.EmuKeys[i].key, >+ NagraKeys.EmuKeys[i].keyName, NagraKeys.EmuKeys[i].keyLength, 0); >+ } >+ >+ for (i = 0; i < IrdetoKeys.keyCount; i++) >+ { >+ tmpKeyData = &IrdetoKeys.EmuKeys[i]; >+ do >+ { >+ emu_add_entitlement(rdr, tmpKeyData->provider >> 8, tmpKeyData->provider & 0xFF, >+ tmpKeyData->key, tmpKeyData->keyName, tmpKeyData->keyLength, 0); >+ >+ tmpKeyData = tmpKeyData->nextKey; >+ } >+ while (tmpKeyData != NULL); >+ } >+ >+ for (i = 0; i < NDSKeys.keyCount; i++) >+ { >+ emu_add_entitlement(rdr, NDSKeys.EmuKeys[i].provider, 0, NDSKeys.EmuKeys[i].key, >+ NDSKeys.EmuKeys[i].keyName, NDSKeys.EmuKeys[i].keyLength, 0); >+ } >+ >+ emu_add_entitlement(rdr, 0x090F, 0, viasat_const, "00", 64, 1); >+ emu_add_entitlement(rdr, 0x093E, 0, viasat_const, "00", 64, 1); >+ >+ for (i = 0; i < BissKeys.keyCount; i++) >+ { >+ emu_add_entitlement(rdr, 0x2600, BissKeys.EmuKeys[i].provider, BissKeys.EmuKeys[i].key, >+ BissKeys.EmuKeys[i].keyName, BissKeys.EmuKeys[i].keyLength, 0); >+ } >+ >+ emu_add_entitlement(rdr, 0xFFFF, 0, &oneByte, "00", 1, 1); >+ >+ for (i = 0; i < PowervuKeys.keyCount; i++) >+ { >+ emu_add_entitlement(rdr, 0x0E00, PowervuKeys.EmuKeys[i].provider, PowervuKeys.EmuKeys[i].key, >+ PowervuKeys.EmuKeys[i].keyName, PowervuKeys.EmuKeys[i].keyLength, 0); >+ } >+ >+ for (i = 0; i < DreKeys.keyCount; i++) >+ { >+ emu_add_entitlement(rdr, 0x4AE1, DreKeys.EmuKeys[i].provider, DreKeys.EmuKeys[i].key, >+ DreKeys.EmuKeys[i].keyName, DreKeys.EmuKeys[i].keyLength, 0); >+ } >+ >+ for (i = 0; i < TandbergKeys.keyCount; i++) >+ { >+ emu_add_entitlement(rdr, 0x1010, TandbergKeys.EmuKeys[i].provider, TandbergKeys.EmuKeys[i].key, >+ TandbergKeys.EmuKeys[i].keyName, TandbergKeys.EmuKeys[i].keyLength, 0); >+ } >+} >+ >+static int32_t emu_do_ecm(struct s_reader *rdr, const struct ecm_request_t *er, struct s_ecm_answer *ea) >+{ >+ >+ if (!ProcessECM(rdr, er->ecmlen, er->caid, er->prid, er->ecm, ea->cw, er->srvid, er->pid, &ea->cw_ex)) >+ { >+ return CS_OK; >+ } >+ >+ return CS_ERROR; >+} >+ >+static int32_t emu_do_emm(struct s_reader *rdr, struct emm_packet_t *emm) >+{ >+ uint32_t keysAdded = 0; >+ >+ if (emm->emmlen < 3) >+ { >+ return CS_ERROR; >+ } >+ >+ if (SCT_LEN(emm->emm) > emm->emmlen) >+ { >+ return CS_ERROR; >+ } >+ >+ if (!ProcessEMM(rdr, b2i(2, emm->caid), b2i(4, emm->provid), emm->emm, &keysAdded)) >+ { >+ if (keysAdded > 0) >+ { >+ refresh_entitlements(rdr); >+ } >+ >+ return CS_OK; >+ } >+ >+ return CS_ERROR; >+} >+ >+static int32_t emu_card_info(struct s_reader *rdr) >+{ >+ // Delete keys from Emu's memory >+ clear_emu_keydata(); >+ >+ // Read keys built in the OSCam-Emu binary >+#if !defined(__APPLE__) && !defined(__ANDROID__) >+ read_emu_keymemory(rdr); >+#endif >+ >+ // Read keys from SoftCam.Key file >+ set_emu_keyfile_path(cs_confdir); >+ >+ if (!read_emu_keyfile(rdr, cs_confdir)) >+ { >+ if (read_emu_keyfile(rdr, "/var/keys/")) >+ { >+ set_emu_keyfile_path("/var/keys/"); >+ } >+ } >+ >+ // Load keys from external files (set via the webif or the reader config directly) >+ read_emu_eebin(rdr->extee36, "ee36.bin"); // Read "ee36.bin" >+ read_emu_eebin(rdr->extee56, "ee56.bin"); // Read "ee56.bin" >+ read_emu_deskey(rdr->des_key, rdr->des_key_length); // Read overcrypt keys for DreCrypt ADEC >+ >+ cs_log("Total keys in memory: W:%d V:%d N:%d I:%d S:%d F:%d P:%d D:%d T:%d", \ >+ CwKeys.keyCount, ViKeys.keyCount, NagraKeys.keyCount, \ >+ IrdetoKeys.keyCount, NDSKeys.keyCount, BissKeys.keyCount, \ >+ PowervuKeys.keyCount, DreKeys.keyCount, TandbergKeys.keyCount); >+ >+ // Inform OSCam about all available keys. >+ // This is used for listing the "entitlements" in the webif's reader page. >+ refresh_entitlements(rdr); >+ >+ set_prids(rdr); >+ >+ set_hexserial_to_version(rdr); >+ >+ return CS_OK; >+} >+ >+/* >+static int32_t emu_card_init(struct s_reader *UNUSED(rdr), struct s_ATR *UNUSED(atr)) >+{ >+ return CS_ERROR; >+} >+*/ >+ >+int32_t emu_get_via3_emm_type(EMM_PACKET *ep, struct s_reader *rdr) >+{ >+ uint32_t provid = 0; >+ >+ if(ep->emm[3] == 0x90 && ep->emm[4] == 0x03) >+ { >+ provid = b2i(3, ep->emm+5); >+ provid &=0xFFFFF0; >+ i2b_buf(4, provid, ep->provid); >+ } >+ >+ switch(ep->emm[0]) >+ { >+ case 0x88: >+ ep->type = UNIQUE; >+ memset(ep->hexserial, 0, 8); >+ memcpy(ep->hexserial, ep->emm + 4, 4); >+ rdr_log_dbg(rdr, D_EMM, "UNIQUE"); >+ return 1; >+ >+ case 0x8A: >+ case 0x8B: >+ ep->type = GLOBAL; >+ rdr_log_dbg(rdr, D_EMM, "GLOBAL"); >+ return 1; >+ >+ case 0x8C: >+ case 0x8D: >+ ep->type = SHARED; >+ rdr_log_dbg(rdr, D_EMM, "SHARED (part)"); >+ // We need those packets to pass otherwise we would never >+ // be able to complete EMM reassembly >+ return 1; >+ >+ case 0x8E: >+ ep->type = SHARED; >+ rdr_log_dbg(rdr, D_EMM, "SHARED"); >+ memset(ep->hexserial, 0, 8); >+ memcpy(ep->hexserial, ep->emm + 3, 3); >+ return 1; >+ >+ default: >+ ep->type = UNKNOWN; >+ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); >+ return 1; >+ } >+} >+ >+int32_t emu_get_ird2_emm_type(EMM_PACKET *ep, struct s_reader *rdr) >+{ >+ int32_t l = (ep->emm[3] & 0x07); >+ int32_t base = (ep->emm[3] >> 3); >+ char dumprdrserial[l * 3], dumpemmserial[l * 3]; >+ >+ switch(l) >+ { >+ >+ case 0: >+ // global emm, 0 bytes addressed >+ ep->type = GLOBAL; >+ rdr_log_dbg(rdr, D_EMM, "GLOBAL base = %02x", base); >+ return 1; >+ >+ case 2: >+ // shared emm, 2 bytes addressed >+ ep->type = SHARED; >+ memset(ep->hexserial, 0, 8); >+ memcpy(ep->hexserial, ep->emm + 4, l); >+ cs_hexdump(1, rdr->hexserial, l, dumprdrserial, sizeof(dumprdrserial)); >+ cs_hexdump(1, ep->hexserial, l, dumpemmserial, sizeof(dumpemmserial)); >+ rdr_log_dbg_sensitive(rdr, D_EMM, "SHARED l = %d ep = {%s} rdr = {%s} base = %02x", l, >+ dumpemmserial, dumprdrserial, base); >+ return 1; >+ >+ case 3: >+ // unique emm, 3 bytes addressed >+ ep->type = UNIQUE; >+ memset(ep->hexserial, 0, 8); >+ memcpy(ep->hexserial, ep->emm + 4, l); >+ cs_hexdump(1, rdr->hexserial, l, dumprdrserial, sizeof(dumprdrserial)); >+ cs_hexdump(1, ep->hexserial, l, dumpemmserial, sizeof(dumpemmserial)); >+ rdr_log_dbg_sensitive(rdr, D_EMM, "UNIQUE l = %d ep = {%s} rdr = {%s} base = %02x", l, >+ dumpemmserial, dumprdrserial, base); >+ return 1; >+ >+ default: >+ ep->type = UNKNOWN; >+ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); >+ return 1; >+ } >+} >+ >+int32_t emu_get_pvu_emm_type(EMM_PACKET *ep, struct s_reader *rdr) >+{ >+ if(ep->emm[0] == 0x82) >+ { >+ ep->type = UNIQUE; >+ memset(ep->hexserial, 0, 8); >+ memcpy(ep->hexserial, ep->emm + 12, 4); >+ } >+ else >+ { >+ ep->type = UNKNOWN; >+ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); >+ } >+ return 1; >+} >+ >+int32_t emu_get_dre2_emm_type(EMM_PACKET *ep, struct s_reader *UNUSED(rdr)) >+{ >+ switch (ep->emm[0]) >+ { >+ case 0x82: >+ ep->type = GLOBAL; >+ return 1; >+ >+ case 0x86: >+ ep->type = SHARED; >+ memset(ep->hexserial, 0, 8); >+ ep->hexserial[0] = ep->emm[3]; >+ return 1; >+ >+ //case 0x87: >+ // ep->type = UNIQUE; >+ // return 1; //FIXME: no filling of ep->hexserial >+ >+ case 0x88: >+ ep->type = UNIQUE; >+ return 1; //FIXME: no filling of ep->hexserial >+ >+ case 0x91: >+ ep->type = GLOBAL; >+ return 1; >+ >+ default: >+ ep->type = UNKNOWN; >+ return 1; >+ } >+} >+ >+int32_t emu_get_tan_emm_type(EMM_PACKET *ep, struct s_reader *rdr) >+{ >+ if(ep->emm[0] == 0x82 || ep->emm[0] == 0x83) >+ { >+ ep->type = GLOBAL; >+ } >+ else >+ { >+ ep->type = UNKNOWN; >+ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); >+ } >+ return 1; >+} >+ >+static int32_t emu_get_emm_type(struct emm_packet_t *ep, struct s_reader *rdr) >+{ >+ switch(b2i(2, ep->caid)>>8) >+ { >+ case 0x05: >+ return emu_get_via3_emm_type(ep, rdr); >+ >+ case 0x06: >+ return emu_get_ird2_emm_type(ep, rdr); >+ >+ case 0x0E: >+ return emu_get_pvu_emm_type(ep, rdr); >+ >+ case 0x4A: >+ return emu_get_dre2_emm_type(ep, rdr); >+ >+ case 0x10: >+ return emu_get_tan_emm_type(ep, rdr); >+ >+ default: >+ break; >+ } >+ >+ return CS_ERROR; >+} >+ >+FILTER* get_emu_prids_for_caid(struct s_reader *rdr, uint16_t caid) >+{ >+ int32_t i; >+ >+ for(i = 0; i < rdr->emu_auproviders.nfilts; i++) >+ { >+ if(caid == rdr->emu_auproviders.filts[i].caid) >+ { >+ return &rdr->emu_auproviders.filts[i]; >+ } >+ } >+ >+ return NULL; >+} >+ >+static int32_t emu_get_via3_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid)) >+{ >+ if(*emm_filters == NULL) >+ { >+ const unsigned int max_filter_count = 1; >+ >+ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) >+ { return CS_ERROR; } >+ >+ struct s_csystem_emm_filter *filters = *emm_filters; >+ *filter_count = 0; >+ >+ int32_t idx = 0; >+ >+ filters[idx].type = EMM_GLOBAL; >+ filters[idx].enabled = 1; >+ filters[idx].filter[0] = 0x8A; >+ filters[idx].mask[0] = 0xFE; >+ filters[idx].filter[3] = 0x80; >+ filters[idx].mask[3] = 0x80; >+ idx++; >+ >+ *filter_count = idx; >+ } >+ >+ return CS_OK; >+} >+ >+static int32_t emu_get_ird2_emm_filter(struct s_reader* rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t caid, uint32_t UNUSED(provid)) >+{ >+ uint8_t hexserial[3], prid[4]; >+ FILTER* emu_provids; >+ int8_t have_provid = 0, have_serial = 0; >+ int32_t i; >+ >+ if(GetIrdeto2Hexserial(caid, hexserial)) >+ { have_serial = 1; } >+ >+ emu_provids = get_emu_prids_for_caid(rdr, caid); >+ if(emu_provids != NULL && emu_provids->nprids > 0) >+ { have_provid = 1; } >+ >+ if(*emm_filters == NULL) >+ { >+ const unsigned int max_filter_count = have_serial + (2*(have_provid ? emu_provids->nprids : 0)); >+ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) >+ { return CS_ERROR; } >+ >+ struct s_csystem_emm_filter *filters = *emm_filters; >+ *filter_count = 0; >+ >+ unsigned int idx = 0; >+ >+ if(have_serial) >+ { >+ filters[idx].type = EMM_UNIQUE; >+ filters[idx].enabled = 1; >+ filters[idx].filter[0] = 0x82; >+ filters[idx].mask[0] = 0xFF; >+ filters[idx].filter[1] = 0xFB; >+ filters[idx].mask[1] = 0x07; >+ memcpy(&filters[idx].filter[2], hexserial, 3); >+ memset(&filters[idx].mask[2], 0xFF, 3); >+ idx++; >+ } >+ >+ for(i=0; have_provid && i<emu_provids->nprids; i++) >+ { >+ i2b_buf(4, emu_provids->prids[i], prid); >+ >+ filters[idx].type = EMM_UNIQUE; >+ filters[idx].enabled = 1; >+ filters[idx].filter[0] = 0x82; >+ filters[idx].mask[0] = 0xFF; >+ filters[idx].filter[1] = 0xFB; >+ filters[idx].mask[1] = 0x07; >+ memcpy(&filters[idx].filter[2], &prid[1], 3); >+ memset(&filters[idx].mask[2], 0xFF, 3); >+ idx++; >+ >+ filters[idx].type = EMM_SHARED; >+ filters[idx].enabled = 1; >+ filters[idx].filter[0] = 0x82; >+ filters[idx].mask[0] = 0xFF; >+ filters[idx].filter[1] = 0xFA; >+ filters[idx].mask[1] = 0x07; >+ memcpy(&filters[idx].filter[2], &prid[1], 2); >+ memset(&filters[idx].mask[2], 0xFF, 2); >+ idx++; >+ } >+ >+ *filter_count = idx; >+ } >+ >+ return CS_OK; >+} >+ >+static int32_t emu_get_pvu_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid), uint16_t srvid) >+{ >+ uint8_t hexserials[16][4]; >+ int32_t i, count = 0; >+ >+ if(!GetPowervuHexserials(srvid, hexserials, 16, &count)) >+ { return CS_ERROR; } >+ >+ if(*emm_filters == NULL) >+ { >+ const unsigned int max_filter_count = count; >+ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) >+ { return CS_ERROR; } >+ >+ struct s_csystem_emm_filter *filters = *emm_filters; >+ *filter_count = 0; >+ >+ int32_t idx = 0; >+ >+ for(i=0; i<count; i++) >+ { >+ filters[idx].type = EMM_UNIQUE; >+ filters[idx].enabled = 1; >+ filters[idx].filter[0] = 0x82; >+ filters[idx].filter[10] = hexserials[i][0]; >+ filters[idx].filter[11] = hexserials[i][1]; >+ filters[idx].filter[12] = hexserials[i][2]; >+ filters[idx].filter[13] = hexserials[i][3]; >+ filters[idx].mask[0] = 0xFF; >+ filters[idx].mask[10] = 0xFF; >+ filters[idx].mask[11] = 0xFF; >+ filters[idx].mask[12] = 0xFF; >+ filters[idx].mask[13] = 0xFF; >+ idx++; >+ } >+ >+ *filter_count = idx; >+ } >+ >+ return CS_OK; >+} >+ >+static int32_t emu_get_dre2_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t caid, uint32_t provid) >+{ >+ uint8_t hexserials[16]; >+ int32_t i, count = 0; >+ >+ if(!GetDrecryptHexserials(caid, provid, hexserials, 16, &count)) >+ { count = 0; } >+ >+ if(*emm_filters == NULL) >+ { >+ const unsigned int max_filter_count = 1 + count + 1; >+ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) >+ { return CS_ERROR; } >+ >+ struct s_csystem_emm_filter *filters = *emm_filters; >+ *filter_count = 0; >+ >+ int32_t idx = 0; >+ >+ if(provid == 0xFE) >+ { >+ filters[idx].type = EMM_GLOBAL; >+ filters[idx].enabled = 1; >+ filters[idx].filter[0] = 0x91; >+ filters[idx].mask[0] = 0xFF; >+ idx++; >+ } >+ >+ for(i=0; i<count; i++) >+ { >+ filters[idx].type = EMM_SHARED; >+ filters[idx].enabled = 1; >+ filters[idx].filter[0] = 0x86; >+ filters[idx].filter[1] = hexserials[i]; >+ filters[idx].mask[0] = 0xFF; >+ filters[idx].mask[1] = 0xFF; >+ idx++; >+ } >+ >+ //filters[idx].type = EMM_UNIQUE; >+ //filters[idx].enabled = 1; >+ //filters[idx].filter[0] = 0x87; >+ //filters[idx].mask[0] = 0xFF; >+ //idx++; >+ >+ filters[idx].type = EMM_UNIQUE; >+ filters[idx].enabled = 1; >+ filters[idx].filter[0] = 0x88; >+ filters[idx].mask[0] = 0xFF; >+ idx++; >+ >+ *filter_count = idx; >+ } >+ >+ return CS_OK; >+} >+ >+static int32_t emu_get_tan_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid)) >+{ >+ if(*emm_filters == NULL) >+ { >+ const unsigned int max_filter_count = 2; >+ uint8_t buf[8]; >+ >+ if(!FindKey('T', 0x40, 0, "MK", buf, 8, 0, 0, 0, NULL) && !FindKey('T', 0x40, 0, "MK01", buf, 8, 0, 0, 0, NULL)) >+ { return CS_ERROR; } >+ >+ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) >+ { return CS_ERROR; } >+ >+ struct s_csystem_emm_filter *filters = *emm_filters; >+ *filter_count = 0; >+ >+ int32_t idx = 0; >+ >+ filters[idx].type = EMM_GLOBAL; >+ filters[idx].enabled = 1; >+ filters[idx].filter[0] = 0x82; >+ filters[idx].mask[0] = 0xFF; >+ idx++; >+ >+ filters[idx].type = EMM_GLOBAL; >+ filters[idx].enabled = 1; >+ filters[idx].filter[0] = 0x83; >+ filters[idx].mask[0] = 0xFF; >+ idx++; >+ >+ *filter_count = idx; >+ } >+ >+ return CS_OK; >+} >+ >+static int32_t emu_get_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **UNUSED(emm_filters), unsigned int *UNUSED(filter_count)) >+{ >+ return CS_ERROR; >+} >+ >+static int32_t emu_get_emm_filter_adv(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t caid, uint32_t provid, uint16_t srvid) >+{ >+ switch(caid>>8) >+ { >+ case 0x05: >+ return emu_get_via3_emm_filter(rdr, emm_filters, filter_count, caid, provid); >+ >+ case 0x06: >+ return emu_get_ird2_emm_filter(rdr, emm_filters, filter_count, caid, provid); >+ >+ case 0x0E: >+ return emu_get_pvu_emm_filter(rdr, emm_filters, filter_count, caid, provid, srvid); >+ >+ case 0x4A: >+ return emu_get_dre2_emm_filter(rdr, emm_filters, filter_count, caid, provid); >+ >+ case 0x10: >+ return emu_get_tan_emm_filter(rdr, emm_filters, filter_count, caid, provid); >+ >+ default: >+ break; >+ } >+ >+ return CS_ERROR; >+} >+ >+const struct s_cardsystem reader_emu = >+{ >+ .desc = "emu", >+ .caids = (uint16_t[]){ 0x0D, 0x09, 0x0500, 0x18, 0x06, 0x26, 0xFFFF, 0x0E, 0x4A, 0x10, 0 }, >+ .do_ecm = emu_do_ecm, >+ .do_emm = emu_do_emm, >+ .card_info = emu_card_info, >+ //.card_init = emu_card_init, // apparently this is not needed at all >+ .get_emm_type = emu_get_emm_type, >+ .get_emm_filter = emu_get_emm_filter, // needed to pass checks >+ .get_emm_filter_adv = emu_get_emm_filter_adv, >+}; >+ >+/* >+ * Create the Emu virtual "device" part. This is of type s_cardreader. >+ * Similar structures are found in the csctapi (Card System Card Terminal API) >+ * folder for every IFD (InterFace Device), aka smart card reader. >+ * Since we have no hardware to initialize, we start our Stream Relay server >+ * with the emu_reader_init() function. >+ * At Emu shutdown, we remove keys from memory with the emu_close() function. >+*/ >+ >+#define CR_OK 0 >+#define CR_ERROR 1 >+ >+static int32_t emu_reader_init(struct s_reader *UNUSED(reader)) >+{ >+ int32_t i; >+ char authtmp[128]; >+ >+ if (cfg.emu_stream_relay_enabled && (stream_server_thread_init == 0)) >+ { >+ stream_server_thread_init = 1; >+ SAFE_MUTEX_INIT(&emu_fixed_key_srvid_mutex, NULL); >+ >+ for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++) >+ { >+ SAFE_MUTEX_INIT(&emu_fixed_key_data_mutex[i], NULL); >+ ll_emu_stream_delayed_keys[i] = ll_create("ll_emu_stream_delayed_keys"); >+ memset(&emu_fixed_key_data[i], 0, sizeof(emu_stream_client_key_data)); >+ } >+ >+ start_thread("stream_key_delayer", stream_key_delayer, NULL, NULL, 1, 1); >+ cs_log("Stream key delayer initialized"); >+ >+ cs_strncpy(emu_stream_source_host, cfg.emu_stream_source_host, sizeof(emu_stream_source_host)); >+ emu_stream_source_port = cfg.emu_stream_source_port; >+ emu_stream_relay_port = cfg.emu_stream_relay_port; >+ emu_stream_emm_enabled = cfg.emu_stream_emm_enabled; >+ >+ if (cfg.emu_stream_source_auth_user && cfg.emu_stream_source_auth_password) >+ { >+ snprintf(authtmp, sizeof(authtmp), "%s:%s", cfg.emu_stream_source_auth_user, cfg.emu_stream_source_auth_password); >+ b64encode(authtmp, strlen(authtmp), &emu_stream_source_auth); >+ } >+ else >+ { >+ NULLFREE(emu_stream_source_auth); >+ } >+ >+ start_thread("stream_server", stream_server, NULL, NULL, 1, 1); >+ cs_log("Stream relay server initialized"); >+ } >+ >+ return CR_OK; >+} >+ >+static int32_t emu_close(struct s_reader *UNUSED(reader)) >+{ >+ cs_log("Reader is shutting down"); >+ >+ // Delete keys from Emu's memory >+ clear_emu_keydata(); >+ >+ return CR_OK; >+} >+ >+static int32_t emu_get_status(struct s_reader *UNUSED(reader), int32_t *in) { *in = 1; return CR_OK; } >+static int32_t emu_activate(struct s_reader *UNUSED(reader), struct s_ATR *UNUSED(atr)) { return CR_OK; } >+static int32_t emu_transmit(struct s_reader *UNUSED(reader), uint8_t *UNUSED(buffer), uint32_t UNUSED(size), uint32_t UNUSED(expectedlen), uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { return CR_OK; } >+static int32_t emu_receive(struct s_reader *UNUSED(reader), uint8_t *UNUSED(buffer), uint32_t UNUSED(size), uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { return CR_OK; } >+static int32_t emu_write_settings(struct s_reader *UNUSED(reader), struct s_cardreader_settings *UNUSED(s)) { return CR_OK; } >+static int32_t emu_card_write(struct s_reader *UNUSED(pcsc_reader),const uchar *UNUSED(buf) ,uint8_t *UNUSED(cta_res), uint16_t *UNUSED(cta_lr),int32_t UNUSED(l)) { return CR_OK; } >+static int32_t emu_set_protocol(struct s_reader *UNUSED(rdr),uint8_t *UNUSED(params),uint32_t *UNUSED(length), uint32_t UNUSED(len_request)) { return CR_OK; } >+ >+const struct s_cardreader cardreader_emu = >+{ >+ .desc = "emu", >+ .typ = R_EMU, >+ .skip_extra_atr_parsing = 1, >+ .reader_init = emu_reader_init, >+ .get_status = emu_get_status, >+ .activate = emu_activate, >+ .transmit = emu_transmit, >+ .receive = emu_receive, >+ .close = emu_close, >+ .write_settings = emu_write_settings, >+ .card_write = emu_card_write, >+ .set_protocol = emu_set_protocol, >+}; >+ >+void add_emu_reader(void) >+{ >+ // This function is called inside oscam.c and creates an emu [reader] with default >+ // settings in oscam.server file. If an emu [reader] already exists, it uses that. >+ >+ LL_ITER itr; >+ struct s_reader *rdr; >+ int8_t haveEmuReader = 0; >+ char *emuName = "emulator"; >+ char *ctab, *ftab, *emu_auproviders; >+ >+ // Check if emu [reader] entry already exists in oscam.server file and get it >+ itr = ll_iter_create(configured_readers); >+ while ((rdr = ll_iter_next(&itr))) >+ { >+ if (rdr->typ == R_EMU) >+ { >+ haveEmuReader = 1; >+ break; >+ } >+ } >+ >+ rdr = NULL; >+ >+ // If there's no emu [reader] in oscam.server, create one with default settings >+ if (!haveEmuReader) >+ { >+ if (!cs_malloc(&rdr, sizeof(struct s_reader))) >+ { >+ return; >+ } >+ >+ reader_set_defaults(rdr); >+ >+ rdr->enable = 1; >+ rdr->typ = R_EMU; >+ strncpy(rdr->label, emuName, strlen(emuName)); >+ strncpy(rdr->device, emuName, strlen(emuName)); >+ >+ // CAIDs >+ ctab = strdup("090F,0500,1801,0604,2600,FFFF,0E00,4AE1,1010"); >+ chk_caidtab(ctab, &rdr->ctab); >+ NULLFREE(ctab); >+ >+ // Idents >+ ftab = strdup("090F:000000;" >+ "0500:000000,023800,021110,007400,007800;" >+ "1801:000000,007301,001101,002111;" >+ "0604:000000;" >+ "2600:000000;" >+ "FFFF:000000;" >+ "0E00:000000;" >+ "4AE1:000011,000014,0000FE;" >+ "1010:000000;" >+ ); >+ chk_ftab(ftab, &rdr->ftab); >+ NULLFREE(ftab); >+ >+ // AU providers >+ emu_auproviders = strdup("0604:010200;0E00:000000;4AE1:000011,000014,0000FE;1010:000000;"); >+ chk_ftab(emu_auproviders, &rdr->emu_auproviders); >+ NULLFREE(emu_auproviders); >+ >+ // EMM cache >+ rdr->cachemm = 2; >+ rdr->rewritemm = 1; >+ rdr->logemm = 2; >+ rdr->deviceemm = 1; >+ >+ // User group >+ rdr->grp = 0x1ULL; >+ >+ // Add the "device" part to our emu reader >+ rdr->crdr = &cardreader_emu; >+ >+ reader_fixups_fn(rdr); >+ ll_append(configured_readers, rdr); >+ } >+ >+ // Set DVB Api delayer option >+#ifdef HAVE_DVBAPI >+ if (cfg.dvbapi_enabled && cfg.dvbapi_delayer < 60) >+ { >+ cfg.dvbapi_delayer = 60; >+ } >+#endif >+ >+ cs_log("OSCam-Emu version %d", GetOSemuVersion()); >+} >Index: module-newcamd-des.c >=================================================================== >--- module-newcamd-des.c (revision 11398) >+++ module-newcamd-des.c (working copy) >@@ -5,10 +5,7 @@ > #define DES_IP 1 > #define DES_IP_1 2 > #define DES_RIGHT 4 >-#define DES_HASH 8 > >-#define DES_ECM_CRYPT 0 >-#define DES_ECM_HASH DES_HASH > #define DES_ECS2_DECRYPT (DES_IP | DES_IP_1 | DES_RIGHT) > #define DES_ECS2_CRYPT (DES_IP | DES_IP_1) > >@@ -356,7 +353,7 @@ > swap(data - 4, data); > } > >-static void nc_des(unsigned char key[], unsigned char mode, unsigned char data[]) >+void nc_des(unsigned char key[], unsigned char mode, unsigned char data[]) > { > unsigned char i; > unsigned char left[8]; >Index: module-newcamd-des.h >=================================================================== >--- module-newcamd-des.h (revision 11398) >+++ module-newcamd-des.h (working copy) >@@ -1,8 +1,15 @@ > #ifndef MODULE_NEWCAMD_DES_H_ > #define MODULE_NEWCAMD_DES_H_ > >+#define DES_HASH 8 >+ >+#define DES_ECM_CRYPT 0 >+#define DES_ECM_HASH DES_HASH >+ > int nc_des_encrypt(unsigned char *buffer, int len, unsigned char *deskey); > int nc_des_decrypt(unsigned char *buffer, int len, unsigned char *deskey); > unsigned char *nc_des_login_key_get(unsigned char *key1, unsigned char *key2, int len, unsigned char *des16); > >+ void nc_des(unsigned char key[], unsigned char mode, unsigned char data[]); >+ > #endif >Index: module-newcamd.c >=================================================================== >--- module-newcamd.c (revision 11398) >+++ module-newcamd.c (working copy) >@@ -919,6 +919,13 @@ > // set userfilter for au enabled clients > if(aureader) > { >+#ifdef WITH_EMU >+ if(aureader->typ == R_EMU) >+ { >+ usr_filter = * get_emu_prids_for_caid(aureader, cfg.ncd_ptab.ports[cl->port_idx].ncd->ncd_ftab.filts[0].caid); >+ } >+ else >+#endif > mk_user_au_ftab(aureader, &usr_filter); > } > >@@ -948,6 +955,13 @@ > else > { memset(&mbuf[8], 0, 6); } //mbuf[8] - mbuf[13] > >+#ifdef WITH_EMU >+ if(aureader && aureader->typ == R_EMU && caid_is_dre(pufilt->caid)) >+ { >+ mbuf[10] = aureader->dre36_force_group; >+ } >+#endif >+ > mbuf[14] = pufilt->nprids; > for(j = 0; j < pufilt->nprids; j++) > { >@@ -973,7 +987,7 @@ > int32_t k, found; > uint32_t rprid; > found = 0; >- if(pufilt->caid == aureader->caid) >+ if(pufilt->caid == aureader->caid && aureader->typ != R_EMU) > { > for(k = 0; (k < aureader->nprov); k++) > { >@@ -999,6 +1013,32 @@ > } > } > } >+#ifdef WITH_EMU >+ else if(aureader->typ == R_EMU) >+ { >+ if(caid_is_dre(pufilt->caid)) >+ { >+ found = 1; >+ memset(&mbuf[22 + 11 * j] ,0 ,4); >+ switch((uchar)(pufilt->prids[j])) >+ { >+ case 0x11: >+ mbuf[22 + 11 * j] = aureader->dre36_force_group; >+ break; >+ case 0x14: >+ mbuf[22 + 11 * j] = aureader->dre56_force_group; >+ break; >+ case 0xfe: >+ mbuf[22 + 11 * j] = 0xED; >+ mbuf[25 + 11 * j] = 0x02; >+ break; >+ default: >+ found = 0; >+ } >+ } >+ } >+#endif >+ > if(!found) > { > mbuf[22 + 11 * j] = 0x00; >Index: module-stat.c >=================================================================== >--- module-stat.c (revision 11398) >+++ module-stat.c (working copy) >@@ -903,7 +903,7 @@ > > uint16_t get_rdr_caid(struct s_reader *rdr) > { >- if(is_network_reader(rdr)) >+ if(is_network_reader(rdr) || rdr->typ == R_EMU) > { > return 0; //reader caid is not real caid > } >@@ -1301,7 +1301,7 @@ > for(ea = er->matching_rdr; ea; ea = ea->next) > { > rdr = ea->reader; >- if(is_network_reader(rdr)) //reader caid is not real caid >+ if(is_network_reader(rdr) || rdr->typ == R_EMU) //reader caid is not real caid > { > prv = ea; > continue; // proxy can convert or reject >Index: module-webif-tpl.c >=================================================================== >--- module-webif-tpl.c (revision 11398) >+++ module-webif-tpl.c (working copy) >@@ -457,6 +457,7 @@ > check_conf(WITH_SSL, ptr2); > check_conf(WITH_STAPI, ptr2); > check_conf(WITH_STAPI5, ptr2); >+ check_conf(WITH_EMU, ptr2); > } // for > if(ok == 0) > { >Index: module-webif.c >=================================================================== >--- module-webif.c (revision 11398) >+++ module-webif.c (working copy) >@@ -101,6 +101,7 @@ > #define MNU_CFG_LCD 14 > #define MNU_CFG_MONITOR 15 > #define MNU_CFG_WEBIF 16 >+#define MNU_CFG_STREAMRELAY 17 > > /* constants for files.html submenuactivating */ > #define MNU_CFG_FVERSION 0 >@@ -134,8 +135,9 @@ > #define MNU_GBX_FSTAINF 27 > #define MNU_GBX_FEXPINF 28 > #define MNU_GBX_INFOLOG 29 >+#define MNU_CFG_FSOFTCAMKEY 30 > >-#define MNU_CFG_TOTAL_ITEMS 30 // sum of items above. Use it for "All inactive" in function calls too. >+#define MNU_CFG_TOTAL_ITEMS 31 // sum of config or files items above. Use it for "All inactive" in function calls too. > > static void set_status_info_var(struct templatevars *vars, char *varname, int no_data, char *fmt, double value) { > if (no_data) >@@ -1216,6 +1218,34 @@ > } > #endif > >+#ifdef WITH_EMU >+#include "module-emulator-stream.h" >+ >+static char *send_oscam_config_streamrelay(struct templatevars *vars, struct uriparams *params) >+{ >+ setActiveSubMenu(vars, MNU_CFG_STREAMRELAY); >+ >+ webif_save_config("streamrelay", vars, params); >+ >+ tpl_printf(vars, TPLADD, "STREAM_SOURCE_HOST", "%s", cfg.emu_stream_source_host); >+ tpl_printf(vars, TPLADD, "STREAM_SOURCE_PORT", "%d", cfg.emu_stream_source_port); >+ if(cfg.emu_stream_source_auth_user) >+ { tpl_printf(vars, TPLADD, "STREAM_SOURCE_AUTH_USER", "%s", cfg.emu_stream_source_auth_user); } >+ if(cfg.emu_stream_source_auth_password) >+ { tpl_printf(vars, TPLADD, "STREAM_SOURCE_AUTH_PASSWORD", "%s", cfg.emu_stream_source_auth_password); } >+ tpl_printf(vars, TPLADD, "STREAM_RELAY_PORT", "%d", cfg.emu_stream_relay_port); >+ tpl_printf(vars, TPLADD, "STREAM_ECM_DELAY", "%d", cfg.emu_stream_ecm_delay); >+ >+ tpl_printf(vars, TPLADD, "TMP", "STREAMRELAYENABLEDSELECTED%d", cfg.emu_stream_relay_enabled); >+ tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); >+ >+ tpl_printf(vars, TPLADD, "TMP", "STREAMEMMENABLEDSELECTED%d", cfg.emu_stream_emm_enabled); >+ tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); >+ >+ return tpl_getTpl(vars, "CONFIGSTREAMRELAY"); >+} >+#endif >+ > #ifdef MODULE_CCCAM > static char *send_oscam_config_cccam(struct templatevars *vars, struct uriparams *params) > { >@@ -1554,6 +1584,10 @@ > tpl_printf(vars, TPLADD, "TMP", "EXTENDEDCWAPISELECTED%d", cfg.dvbapi_extended_cw_api); > tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); > >+ //extended_cw_pids (pid limiter) >+ tpl_printf(vars, TPLADD, "TMP", "EXTENDEDCWPIDSSELECTED%d", cfg.dvbapi_extended_cw_pids); >+ tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); >+ > //write_sdt_prov > if(cfg.dvbapi_write_sdt_prov > 0) > { tpl_addVar(vars, TPLADD, "WRITESDTPROVCHECKED", "checked"); } >@@ -1631,6 +1665,9 @@ > #ifdef MODULE_SCAM > else if(!strcmp(part, "scam")) { return send_oscam_config_scam(vars, params); } > #endif >+#ifdef WITH_EMU >+ else if(!strcmp(part, "streamrelay")) { return send_oscam_config_streamrelay(vars, params); } >+#endif > #ifdef MODULE_CCCAM > else if(!strcmp(part, "cccam")) { return send_oscam_config_cccam(vars, params); } > #endif >@@ -2093,7 +2130,7 @@ > chk_reader("services", servicelabels, rdr); > chk_reader("lb_whitelist_services", servicelabelslb, rdr); > >- if(is_network_reader(rdr)) //physical readers make trouble if re-started >+ if(is_network_reader(rdr) || rdr->typ == R_EMU) //physical readers make trouble if re-started > { > restart_cardreader(rdr, 1); > } >@@ -2671,6 +2708,31 @@ > tpl_addVar(vars, TPLADD, "USERSCRIPT", rdr->userscript); > #endif > >+#ifdef WITH_EMU >+ //emu_auproviders >+ value = mk_t_ftab(&rdr->emu_auproviders); >+ tpl_addVar(vars, TPLADD, "EMUAUPROVIDERS", value); >+ free_mk_t(value); >+ >+ // Date-coded BISS keys >+ if(!apicall) >+ { >+ tpl_addVar(vars, TPLADD, "EMUDATECODEDENABLED", (rdr->emu_datecodedenabled == 1) ? "checked" : ""); >+ } >+ else >+ { >+ tpl_addVar(vars, TPLADD, "EMUDATECODEDENABLED", (rdr->emu_datecodedenabled == 1) ? "1" : "0"); >+ } >+ >+ //extee >+ tpl_addVar(vars, TPLADD, "EXTEE36", rdr->extee36); >+ tpl_addVar(vars, TPLADD, "EXTEE56", rdr->extee56); >+ >+ //dre force group >+ tpl_printf(vars, TPLADD, "DRE36FORCEGROUP","%02X", rdr->dre36_force_group); >+ tpl_printf(vars, TPLADD, "DRE56FORCEGROUP","%02X", rdr->dre56_force_group); >+#endif >+ > tpl_addVar(vars, TPLADD, "PROTOCOL", reader_get_type_desc(rdr, 0)); > > // Show only parameters which needed for the reader >@@ -2692,6 +2754,9 @@ > case R_CAMD35 : > tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGCAMD35BIT")); > break; >+ case R_EMU : >+ tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGEMUBIT")); >+ break; > case R_CS378X : > tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGCS378XBIT")); > break; >@@ -4414,9 +4479,38 @@ > > tpl_addVar(vars, TPLAPPEND, "LOGHISTORY", "<BR><BR>New Structure:<BR>"); > char tbuffer[83]; >+#ifdef WITH_EMU >+ char keyBuffer[1024]; >+#endif > int jsondelimiter = 0; > while((item = ll_iter_next(&itr))) > { >+#ifdef WITH_EMU >+ if(item->isKey) { >+ tpl_addVar(vars, TPLADD, "ENTSTARTDATE", ""); >+ tpl_addVar(vars, TPLADD, "ENTENDDATE", ""); >+ cs_hexdump(0, item->key, item->keyLength, keyBuffer, sizeof(keyBuffer)); >+ tpl_addVar(vars, TPLADD, "ENTEXPIERED", "e_valid"); >+ tpl_printf(vars, TPLADD, "ENTCAID", "%04X", item->caid); >+ if(item->caid == 0x2600) { >+ tpl_printf(vars, TPLADD, "ENTPROVID", "%08X", item->provid); >+ } >+ else { >+ tpl_printf(vars, TPLADD, "ENTPROVID", "%06X", item->provid); >+ } >+ tpl_addVar(vars, TPLADD, "ENTID", item->name); >+ tpl_addVar(vars, TPLADD, "ENTCLASS", keyBuffer); >+ if(item->isData) { tpl_addVar(vars, TPLADD, "ENTTYPE", "data"); } >+ else { tpl_addVar(vars, TPLADD, "ENTTYPE", "key"); } >+ tpl_addVar(vars, TPLADD, "ENTRESNAME", ""); >+ >+ if((strcmp(getParam(params, "hideexpired"), "1") != 0) || (item->end > now)) >+ { tpl_addVar(vars, TPLAPPEND, "READERENTENTRY", tpl_getTpl(vars, "ENTITLEMENTITEMBIT")); } >+ >+ continue; >+ } >+#endif >+ > localtime_r(&item->start, &start_t); > localtime_r(&item->end, &end_t); > >@@ -4892,6 +4986,9 @@ > #else > filtered = (type == cl->typ); > #endif >+#ifdef WITH_EMU >+ if(type == 'e' && cl->typ == 'r' && cl->reader->typ == R_EMU) filtered = 1; >+#endif > } > } > >@@ -6336,6 +6433,9 @@ > { "expired.info", MNU_GBX_FEXPINF, FTYPE_GBOX }, // id 28 > { "info.log", MNU_GBX_INFOLOG, FTYPE_GBOX }, // id 29 > #endif >+#ifdef WITH_EMU >+ { "SoftCam.Key", MNU_CFG_FSOFTCAMKEY,FTYPE_CONFIG }, // id 30 >+#endif > { NULL, 0, 0 }, > }; > >@@ -6806,7 +6906,7 @@ > else if(!proxy && rdr->csystem_active) // local active reader > { > csystem = rdr->csystem; >- caid = rdr->caid; >+ if(rdr->typ != R_EMU) caid = rdr->caid; > } > > if(csystem) >@@ -7813,8 +7913,8 @@ > memcpy(*result + bufsize, buf2, n); > bufsize += n; > >- //max request size 100kb >- if(bufsize > 102400) >+ //max request size 200kb >+ if(bufsize > 204800) > { > cs_log("error: too much data received from %s", cs_inet_ntoa(in)); > NULLFREE(*result); >Index: oscam-aes.c >=================================================================== >--- oscam-aes.c (revision 11398) >+++ oscam-aes.c (working copy) >@@ -37,6 +37,16 @@ > } > } > >+void aes_cbc_encrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv) >+{ >+ AES_cbc_encrypt(buf, buf, n, &aes->aeskey_encrypt, iv, AES_ENCRYPT); >+} >+ >+void aes_cbc_decrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv) >+{ >+ AES_cbc_encrypt(buf, buf, n, &aes->aeskey_decrypt, iv, AES_DECRYPT); >+} >+ > /* Creates an AES_ENTRY and adds it to the given linked list. */ > void add_aes_entry(AES_ENTRY **list, uint16_t caid, uint32_t ident, int32_t keyid, uchar *aesKey) > { >Index: oscam-aes.h >=================================================================== >--- oscam-aes.h (revision 11398) >+++ oscam-aes.h (working copy) >@@ -5,6 +5,8 @@ > bool aes_set_key_alloc(struct aes_keys **aes, char *key); > void aes_decrypt(struct aes_keys *aes, uchar *buf, int32_t n); > void aes_encrypt_idx(struct aes_keys *aes, uchar *buf, int32_t n); >+void aes_cbc_encrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv); >+void aes_cbc_decrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv); > > void add_aes_entry(AES_ENTRY **list, uint16_t caid, uint32_t ident, int32_t keyid, uchar *aesKey); > void parse_aes_entry(AES_ENTRY **list, char *label, char *value); >Index: oscam-chk.c >=================================================================== >--- oscam-chk.c (revision 11398) >+++ oscam-chk.c (working copy) >@@ -758,7 +758,7 @@ > return 0; > } > >- if(!is_network_reader(rdr) && ((rdr->caid >> 8) != ((er->caid >> 8) & 0xFF) && (rdr->caid >> 8) != ((er->ocaid >> 8) & 0xFF))) >+ if(!(rdr->typ == R_EMU) && !is_network_reader(rdr) && ((rdr->caid >> 8) != ((er->caid >> 8) & 0xFF) && (rdr->caid >> 8) != ((er->ocaid >> 8) & 0xFF))) > { > if (!rdr->csystem) > return 0; >@@ -794,7 +794,7 @@ > } > > //Checking ident: >- if(!chk_rfilter(er, rdr)) >+ if(!(rdr->typ == R_EMU && (er->caid>>8 == 0x26 || er->caid == 0xFFFF)) && !chk_rfilter(er, rdr)) > { > cs_log_dbg(D_TRACE, "r-filter reader %s", rdr->label); > return (0); >@@ -853,7 +853,7 @@ > } > > //Checking entitlements: >- if(ll_count(rdr->ll_entitlements) > 0) >+ if(ll_count(rdr->ll_entitlements) > 0 && !(rdr->typ == R_EMU)) > { > LL_ITER itr = ll_iter_create(rdr->ll_entitlements); > S_ENTITLEMENT *item; >@@ -1024,7 +1024,7 @@ > > int32_t chk_caid_rdr(struct s_reader *rdr, uint16_t caid) > { >- if(is_network_reader(rdr)) >+ if(is_network_reader(rdr) || rdr->typ == R_EMU) > { > return 1; //reader caid is not real caid > } >Index: oscam-config-global.c >=================================================================== >--- oscam-config-global.c (revision 11398) >+++ oscam-config-global.c (working copy) >@@ -854,6 +854,30 @@ > #else > static const struct config_list scam_opts[] = { DEF_LAST_OPT }; > #endif >+ >+#ifdef WITH_EMU >+static bool streamrelay_should_save_fn(void *UNUSED(var)) >+{ >+ return 1; >+} >+static const struct config_list streamrelay_opts[] = >+{ >+ DEF_OPT_SAVE_FUNC(streamrelay_should_save_fn), >+ DEF_OPT_STR("stream_source_host" , OFS(emu_stream_source_host), "127.0.0.1"), >+ DEF_OPT_INT32("stream_source_port" , OFS(emu_stream_source_port), 8001), >+ DEF_OPT_STR("stream_source_auth_user" , OFS(emu_stream_source_auth_user), NULL), >+ DEF_OPT_STR("stream_source_auth_password" , OFS(emu_stream_source_auth_password), NULL), >+ DEF_OPT_INT32("stream_relay_port" , OFS(emu_stream_relay_port), 17999), >+ DEF_OPT_UINT32("stream_ecm_delay" , OFS(emu_stream_ecm_delay), 600), >+ DEF_OPT_INT8("stream_relay_enabled" , OFS(emu_stream_relay_enabled), 1), >+ DEF_OPT_INT8("stream_emm_enabled" , OFS(emu_stream_emm_enabled), 1), >+ DEF_LAST_OPT >+}; >+#else >+static const struct config_list streamrelay_opts[] = { DEF_LAST_OPT }; >+#endif >+ >+ > #ifdef MODULE_RADEGAST > static bool radegast_should_save_fn(void *UNUSED(var)) > { >@@ -1236,6 +1260,7 @@ > DEF_OPT_INT8("read_sdt" , OFS(dvbapi_read_sdt), 0), > DEF_OPT_INT8("write_sdt_prov", OFS(dvbapi_write_sdt_prov), 0), > DEF_OPT_INT8("extended_cw_api", OFS(dvbapi_extended_cw_api), 0), >+ DEF_OPT_INT8("extended_cw_pids", OFS(dvbapi_extended_cw_pids), 64), // pid limiter > DEF_OPT_FUNC("boxtype" , OFS(dvbapi_boxtype), dvbapi_boxtype_fn), > DEF_OPT_FUNC("services" , OFS(dvbapi_sidtabs.ok), dvbapi_services_fn), > // OBSOLETE OPTIONS >@@ -1289,6 +1314,7 @@ > { "cccam", cccam_opts }, > { "pandora", pandora_opts }, > { "scam", scam_opts }, >+ { "streamrelay", streamrelay_opts }, > { "dvbapi", dvbapi_opts }, > { "monitor", monitor_opts }, > { "webif", webif_opts }, >Index: oscam-config-reader.c >=================================================================== >--- oscam-config-reader.c (revision 11398) >+++ oscam-config-reader.c (working copy) >@@ -109,6 +109,7 @@ > { "newcamd525", R_NEWCAMD }, > { "newcamd524", R_NEWCAMD }, > { "drecas", R_DRECAS }, >+ { "emu", R_EMU }, > { NULL , 0 } > }, *p; > int i; >@@ -448,6 +449,9 @@ > if(ftab_type & FTAB_FBPCAID) { rdr = container_of(setting, struct s_reader, fallback_percaid); } > if(ftab_type & FTAB_LOCALCARDS) { rdr = container_of(setting, struct s_reader, localcards); } > if(ftab_type & FTAB_IGNCHKSMCAID){ rdr = container_of(setting, struct s_reader, disablecrccws_only_for); } >+#ifdef WITH_EMU >+ if(ftab_type & FTAB_EMUAU) { rdr = container_of(setting, struct s_reader, emu_auproviders); } >+#endif > if(rdr) > { rdr->changes_since_shareupdate = 1; } > } >@@ -779,7 +783,7 @@ > } > > >-static void reader_fixups_fn(void *var) >+void reader_fixups_fn(void *var) > { > struct s_reader *rdr = var; > #ifdef WITH_LB >@@ -923,6 +927,14 @@ > #ifdef READER_DRECAS > DEF_OPT_STR("stmkeys" , OFS(stmkeys), NULL), > #endif >+#ifdef WITH_EMU >+ DEF_OPT_FUNC_X("emu_auproviders" , OFS(emu_auproviders), ftab_fn, FTAB_READER | FTAB_EMUAU), >+ DEF_OPT_INT8("emu_datecodedenabled" , OFS(emu_datecodedenabled), 0), >+ DEF_OPT_STR("extee36" , OFS(extee36), NULL), >+ DEF_OPT_STR("extee56" , OFS(extee56), NULL), >+ DEF_OPT_HEX("dre36_force_group" , OFS(dre36_force_group), 1), >+ DEF_OPT_HEX("dre56_force_group" , OFS(dre56_force_group), 1), >+#endif > DEF_OPT_INT8("deprecated" , OFS(deprecated), 0), > DEF_OPT_INT8("audisabled" , OFS(audisabled), 0), > DEF_OPT_FUNC("auprovid" , 0, auprovid_fn), >Index: oscam-config.h >=================================================================== >--- oscam-config.h (revision 11398) >+++ oscam-config.h (working copy) >@@ -22,6 +22,7 @@ > int32_t free_readerdb(void); > int32_t write_server(void); > void reload_readerdb(void); >+void reader_fixups_fn(void *var); > > void chk_sidtab(char *token, char *value, struct s_sidtab *sidtab); > int32_t init_sidtab(void); >@@ -63,7 +64,8 @@ > FTAB_FBPCAID = 0x10, > FTAB_LOCALCARDS = 0x20, > FTAB_IGNCHKSMCAID = 0x40, >- FTAB_IGNCRCCEX4USERONLYFOR = 0x80 >+ FTAB_IGNCRCCEX4USERONLYFOR = 0x80, >+ FTAB_EMUAU = 0x100 > }; > > void ftab_fn(const char *token, char *value, void *setting, long ftab_type, FILE *f); >Index: oscam-ecm.c >=================================================================== >--- oscam-ecm.c (revision 11398) >+++ oscam-ecm.c (working copy) >@@ -1584,7 +1584,7 @@ > > if(reader && cw && rc < E_NOTFOUND) > { >- if(cfg.disablecrccws == 0 && reader->disablecrccws == 0) >+ if(cfg.disablecrccws == 0 && reader->disablecrccws == 0 && ((er->caid >> 8) != 0x0E)) > { > uint8_t selectedForIgnChecksum = chk_if_ignore_checksum(er, cfg.disablecrccws, &cfg.disablecrccws_only_for) > + chk_if_ignore_checksum(er, reader->disablecrccws, &reader->disablecrccws_only_for); >Index: oscam-emm.c >=================================================================== >--- oscam-emm.c (revision 11398) >+++ oscam-emm.c (working copy) >@@ -50,7 +50,14 @@ > unsigned int j, filter_count = 0; > > // Call cardsystems emm filter >- csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); >+ if(rdr->typ == R_EMU) >+ { >+ return 1; //valid emm >+ } >+ else >+ { >+ csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); >+ } > > // Only check matching emmtypes: > uint8_t org_emmtype; >@@ -209,6 +216,24 @@ > rdr_log_dbg(reader, D_EMM, "reader auprovid = %06X fixup to %06X (ignoring last digit)", reader->auprovid, prid); > } > >+#ifdef WITH_EMU >+ if(reader->typ == R_EMU) >+ { >+ FILTER* emu_provids = get_emu_prids_for_caid(reader, caid); >+ if(emu_provids != NULL) >+ { >+ for(i = 0; i < emu_provids->nprids; i++) >+ { >+ if(provid == emu_provids->prids[i]) >+ { >+ return 1; >+ } >+ } >+ } >+ return 0; >+ } >+#endif >+ > if(prid == provid) > { > rdr_log_dbg(reader, D_EMM, "reader auprovid = %06X matching with emm provid = %06X -> SEND!", prid, provid); >Index: oscam-string.c >=================================================================== >--- oscam-string.c (revision 11398) >+++ oscam-string.c (working copy) >@@ -510,6 +510,62 @@ > return crc ^ 0xffffffffL; > } > >+static uint32_t fletcher_crc_table[256] = { >+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, >+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, >+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, >+ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, >+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, >+ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, >+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, >+ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, >+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, >+ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, >+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, >+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, >+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, >+ 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, >+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, >+ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, >+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, >+ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, >+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, >+ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, >+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, >+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, >+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, >+ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, >+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, >+ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, >+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, >+ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, >+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, >+ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, >+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, >+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, >+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, >+ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, >+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, >+ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, >+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, >+ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, >+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, >+ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, >+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, >+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, >+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; >+ >+uint32_t fletcher_crc32(uint8_t *data, uint32_t len) >+{ >+ uint32_t i; >+ uint32_t crc = 0xffffffff; >+ >+ for (i=0; i<len; i++) >+ crc = (crc << 8) ^ fletcher_crc_table[((crc >> 24) ^ *data++) & 0xff]; >+ >+ return crc; >+} >+ > static uint16_t ccitt_crc_table [256] = > { > 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, >Index: oscam-string.h >=================================================================== >--- oscam-string.h (revision 11398) >+++ oscam-string.h (working copy) >@@ -37,6 +37,7 @@ > void get_random_bytes(uint8_t *dst, uint32_t dst_len); > > uint32_t crc32(uint32_t crc, const uint8_t *buf, uint32_t len); >+uint32_t fletcher_crc32(uint8_t *data, uint32_t len); > uint16_t ccitt_crc(uint8_t *data, size_t length, uint16_t seed, uint16_t final); > uint32_t jhash(const char *key, size_t len); > >Index: oscam.c >=================================================================== >--- oscam.c (revision 11398) >+++ oscam.c (working copy) >@@ -41,6 +41,11 @@ > #include "reader-common.h" > #include "module-gbox.h" > >+#ifdef WITH_EMU >+ void add_emu_reader(void); >+ void stop_stream_server(void); >+#endif >+ > #ifdef WITH_SSL > #include <openssl/crypto.h> > #include <openssl/ssl.h> >@@ -421,6 +426,7 @@ > write_conf(CW_CYCLE_CHECK, "CW Cycle Check support"); > write_conf(LCDSUPPORT, "LCD support"); > write_conf(LEDSUPPORT, "LED support"); >+ write_conf(WITH_EMU, "Emulator support"); > switch (cs_getclocktype()) { > case CLOCK_TYPE_UNKNOWN : write_conf(CLOCKFIX, "Clockfix with UNKNOWN clock"); break; > case CLOCK_TYPE_REALTIME : write_conf(CLOCKFIX, "Clockfix with realtime clock"); break; >@@ -1639,6 +1645,9 @@ > #ifdef CARDREADER_STINGER > &cardreader_stinger, > #endif >+#ifdef WITH_EMU >+ &cardreader_emu, >+#endif > NULL > }; > >@@ -1810,6 +1819,9 @@ > > init_sidtab(); > init_readerdb(); >+#ifdef WITH_EMU >+ add_emu_reader(); >+#endif > cfg.account = init_userdb(); > init_signal(); > init_provid(); >@@ -1897,6 +1909,9 @@ > if(!cfg.gsms_dis) > { stop_sms_sender(); } > #endif >+#ifdef WITH_EMU >+ stop_stream_server(); >+#endif > webif_close(); > azbox_close(); > coolapi_close_all(); >Index: reader-common.c >=================================================================== >--- reader-common.c (revision 11398) >+++ reader-common.c (working copy) >@@ -15,6 +15,7 @@ > #include "reader-common.h" > //#include "csctapi/atr.h" > #include "csctapi/icc_async.h" >+#include "readers.h" > > extern const struct s_cardsystem *cardsystems[]; > extern char *RDR_CD_TXT[]; >@@ -142,6 +143,19 @@ > static int32_t reader_get_cardsystem(struct s_reader *reader, ATR *atr) > { > int32_t i; >+ >+#ifdef WITH_EMU >+ if(reader->typ == R_EMU) >+ { >+ NULLFREE(reader->csystem_data); >+ rdr_log(reader, "found card system %s", reader_emu.desc); >+ reader->csystem = &reader_emu; >+ reader->csystem_active = true; >+ led_status_found_cardsystem(); >+ return (reader->csystem_active); >+ } >+#endif >+ > for(i = 0; cardsystems[i]; i++) > { > NULLFREE(reader->csystem_data); >Index: readers.h >=================================================================== >--- readers.h (revision 11398) >+++ readers.h (working copy) >@@ -16,5 +16,6 @@ > extern const struct s_cardsystem reader_bulcrypt; > extern const struct s_cardsystem reader_griffin; > extern const struct s_cardsystem reader_dgcrypt; >+extern const struct s_cardsystem reader_emu; > > #endif >Index: webif/config/dvbapi.html >=================================================================== >--- webif/config/dvbapi.html (revision 11398) >+++ webif/config/dvbapi.html (working copy) >@@ -53,7 +53,7 @@ > </TD> > </TR> > <TR><TD><A>Write detected prov name to srvid:</A></TD><TD><input name="write_sdt_prov" type="checkbox" value="1" ##WRITESDTPROVCHECKED##><label></label> >- <!-- <TR><TD><A>API for extended CWs</A></TD> >+ <TR><TD><A>API for extended CWs</A></TD> > <TD> > <select name="extended_cw_api"> > <option value="0" ##EXTENDEDCWAPISELECTED0##>0 - none (disabled)</option> >@@ -61,4 +61,19 @@ > <option value="2" ##EXTENDEDCWAPISELECTED2##>2 - OE2.0</option> > </select> > </TD> >- </TR> --> >\ No newline at end of file >+ </TR> >+ </TR> >+ <TR><TD><A>Max pids for extended CWs</A></TD> >+ <TD> >+ <select name="extended_cw_pids"> >+ <option value="2" ##EXTENDEDCWPIDSSELECTED2##>2</option> >+ <option value="3" ##EXTENDEDCWPIDSSELECTED3##>3</option> >+ <option value="4" ##EXTENDEDCWPIDSSELECTED4##>4</option> >+ <option value="5" ##EXTENDEDCWPIDSSELECTED5##>5</option> >+ <option value="6" ##EXTENDEDCWPIDSSELECTED6##>6</option> >+ <option value="7" ##EXTENDEDCWPIDSSELECTED7##>7</option> >+ <option value="8" ##EXTENDEDCWPIDSSELECTED8##>8</option> >+ <option value="64" ##EXTENDEDCWPIDSSELECTED64##>64</option> >+ </select> >+ </TD> >+ </TR> >\ No newline at end of file >Index: webif/config/menu.html >=================================================================== >--- webif/config/menu.html (revision 11398) >+++ webif/config/menu.html (working copy) >@@ -16,6 +16,7 @@ > ##TPLCONFIGMENUDVBAPI## <!-- CMENUACTIVE13 --> > ##TPLCONFIGMENULCD## <!-- CMENUACTIVE14 --> > ##TPLCONFIGMENUMONITOR## <!-- CMENUACTIVE15 --> >+##TPLCONFIGMENUSTREAMRELAY## <!-- CMENUACTIVE17 --> > <LI CLASS="##CMENUACTIVE16##"><A HREF="config.html?part=webif">WebIf</A></LI> > </UL> > </DIV> >Index: webif/config/menu_streamrelay.html >=================================================================== >--- webif/config/menu_streamrelay.html (revision 0) >+++ webif/config/menu_streamrelay.html (working copy) >@@ -0,0 +1 @@ >+ <LI CLASS="##CMENUACTIVE17##"><A HREF="config.html?part=streamrelay">Stream Relay</A></LI> >Index: webif/config/streamrelay.html >=================================================================== >--- webif/config/streamrelay.html (revision 0) >+++ webif/config/streamrelay.html (working copy) >@@ -0,0 +1,25 @@ >+ <input name="part" type="hidden" value="streamrelay"> >+ <TABLE CLASS="config"> >+ <TR><TH COLSPAN="2">Edit Stream Relay Config</TH></TR> >+ <TR><TD><A>Mode (requires OSCam restart)</A></TD> >+ <TD> >+ <select name="stream_relay_enabled"> >+ <option value="0" ##STREAMRELAYENABLEDSELECTED0##>0 - disabled (use direct DVBAPI decryption)</option> >+ <option value="1" ##STREAMRELAYENABLEDSELECTED1##>1 - enabled (use Stream Relay)</option> >+ </select> >+ </TD> >+ </TR> >+ <TR><TD><A>Source Stream Host:</A></TD><TD><input name="stream_source_host" type="text" maxlength="15" value="##STREAM_SOURCE_HOST##"></TD></TR> >+ <TR><TD><A>Source Stream Port:</A></TD><TD><input name="stream_source_port" class="short" type="text" maxlength="5" value="##STREAM_SOURCE_PORT##"></TD></TR> >+ <TR><TD><A>Source Stream User:</A></TD><TD><input name="stream_source_auth_user" type="text" value="##STREAM_SOURCE_AUTH_USER##"></TD></TR> >+ <TR><TD><A>Source Stream Password:</A></TD><TD><input name="stream_source_auth_password" type="text" value="##STREAM_SOURCE_AUTH_PASSWORD##"></TD></TR> >+ <TR><TD><A>Relay Port:</A></TD><TD><input name="stream_relay_port" class="short" type="text" maxlength="5" value="##STREAM_RELAY_PORT##"></TD></TR> >+ <TR><TD><A>ECM fix delay:</A></TD><TD><input name="stream_ecm_delay" class="short" type="text" maxlength="5" value="##STREAM_ECM_DELAY##"></TD></TR> >+ <TR><TD><A>Process EMM from stream:</A></TD> >+ <TD> >+ <select name="stream_emm_enabled"> >+ <option value="0" ##STREAMEMMENABLEDSELECTED0##>0 - disabled </option> >+ <option value="1" ##STREAMEMMENABLEDSELECTED1##>1 - enabled </option> >+ </select> >+ </TD> >+ </TR> >\ No newline at end of file >Index: webif/files/menu.html >=================================================================== >--- webif/files/menu.html (revision 11398) >+++ webif/files/menu.html (working copy) >@@ -10,7 +10,7 @@ > <LI CLASS="##CMENUACTIVE7##"><A HREF="files.html?file=logfile">logfile</A></LI> > <LI CLASS="##CMENUACTIVE8##"><A HREF="files.html?file=userfile">userfile</A></LI> > ##TPLFILEMENUGBOX## <!-- CMENUACTIVE19-29 --> >- <LI CLASS="##CMENUACTIVE9## ##CMENUACTIVE10## ##CMENUACTIVE11## ##CMENUACTIVE12## ##CMENUACTIVE13## ##CMENUACTIVE14## ##CMENUACTIVE15## ##CMENUACTIVE16## ##CMENUACTIVE17## ##CMENUACTIVE18##"><A HREF="#" class="drop">other files<b class="subcaret"></b></A> >+ <LI CLASS="##CMENUACTIVE9## ##CMENUACTIVE10## ##CMENUACTIVE11## ##CMENUACTIVE12## ##CMENUACTIVE13## ##CMENUACTIVE14## ##CMENUACTIVE15## ##CMENUACTIVE16## ##CMENUACTIVE17## ##CMENUACTIVE18## ##CMENUACTIVE30##"><A HREF="#" class="drop">other files<b class="subcaret"></b></A> > <UL CLASS="dropdown_nav"> > <LI CLASS="##CMENUACTIVE9##"><A HREF="files.html?file=oscam.services">oscam.services</A></LI> > <LI CLASS="##CMENUACTIVE10##"><A HREF="files.html?file=oscam.provid">oscam.provid</A></LI> >@@ -22,6 +22,7 @@ > ##VIEW_FILEMENUCSS## <!-- CMENUACTIVE16 --> > ##TPLFILEMENUTWIN## <!-- CMENUACTIVE17 --> > ##TPLFILEMENUCONSTCW## <!-- CMENUACTIVE18 --> >+##TPLFILEMENUSOFTCAMKEY## <!-- CMENUACTIVE30 --> > </UL> > </LI> > </UL> >Index: webif/files/menu_softcamkey.html >=================================================================== >--- webif/files/menu_softcamkey.html (revision 0) >+++ webif/files/menu_softcamkey.html (working copy) >@@ -0,0 +1 @@ >+ <LI CLASS="##CMENUACTIVE30##"><A HREF="files.html?file=SoftCam.Key">SoftCam.Key</A></LI> >Index: webif/pages_index.txt >=================================================================== >--- webif/pages_index.txt (revision 11398) >+++ webif/pages_index.txt (working copy) >@@ -80,11 +80,13 @@ > CONFIGMENUNEWCAMD config/menu_newcamd.html MODULE_NEWCAMD > CONFIGMENURADEGAST config/menu_radegast.html MODULE_RADEGAST > CONFIGMENUSCAM config/menu_scam.html MODULE_SCAM >+CONFIGMENUSTREAMRELAY config/menu_streamrelay.html WITH_EMU > CONFIGMENUSERIAL config/menu_serial.html MODULE_SERIAL > CONFIGMONITOR config/monitor.html MODULE_MONITOR > CONFIGNEWCAMD config/newcamd.html MODULE_NEWCAMD > CONFIGRADEGAST config/radegast.html MODULE_RADEGAST > CONFIGSCAM config/scam.html MODULE_SCAM >+CONFIGSTREAMRELAY config/streamrelay.html WITH_EMU > CONFIGSERIAL config/serial.html MODULE_SERIAL > CONFIGSERIALDEVICEBIT config/serial_devices.html MODULE_SERIAL > CONFIGWEBIF config/webif.html >@@ -118,6 +120,7 @@ > FILEMENUFAKECWS files/menu_fakecws.html CS_CACHEEX > FILEMENUGBOX files/menu_gbox.html MODULE_GBOX > FILEMENUTWIN files/menu_twin.html MODULE_SERIAL >+FILEMENUSOFTCAMKEY files/menu_softcamkey.html WITH_EMU > > AUTOCONF ghttp/autoconf.html MODULE_GHTTP > PREAUTOCONF ghttp/pre_autoconf.html MODULE_GHTTP >@@ -182,6 +185,7 @@ > READEREDITCACHEEXBIT readerconfig/readerconfig_cacheexbit.html CS_CACHEEX > READERCONFIGCAMD35BIT readerconfig/readerconfig_camd35bit.html MODULE_CAMD35 > READERCONFIGCCCAMBIT readerconfig/readerconfig_cccambit.html MODULE_CCCAM >+READERCONFIGEMUBIT readerconfig/readerconfig_emubit.html WITH_EMU > READERCONFIGCS378XBIT readerconfig/readerconfig_cs378xbit.html MODULE_CAMD35_TCP > READERCONFIGGBOXBIT readerconfig/readerconfig_gboxbit.html MODULE_GBOX > READERCONFIGGHTTPBIT readerconfig/readerconfig_ghttpbit.html MODULE_GHTTP >Index: webif/readerconfig/readerconfig_emubit.html >=================================================================== >--- webif/readerconfig/readerconfig_emubit.html (revision 0) >+++ webif/readerconfig/readerconfig_emubit.html (working copy) >@@ -0,0 +1,6 @@ >+ <TR><TD><A>AU providers:</A></TD><TD><textarea name="emu_auproviders" rows="3" class="bt">##EMUAUPROVIDERS##</textarea></TD></TR> >+ <TR><TD><A>[BISS] Enable date-coded keys:</A></TD><TD><input name="emu_datecodedenabled" type="hidden" value="0"><input name="emu_datecodedenabled" type="checkbox" value="1" ##EMUDATECODEDENABLED##><label></label></TD></TR> >+ <TR><TD><A>[Drecrypt] Path to ee36.bin:</A></TD><TD><input name="extee36" type="text" maxlength="150" value="##EXTEE36##"></TD></TR> >+ <TR><TD><A>[Drecrypt] Path to ee56.bin:</A></TD><TD><input name="extee56" type="text" maxlength="150" value="##EXTEE56##"></TD></TR> >+ <TR><TD><A>[Drecrypt] Center force group:</A></TD><TD><input name="dre36_force_group" class="medium" type="text" maxlength="2" value="##DRE36FORCEGROUP##"></TD></TR> >+ <TR><TD><A>[Drecrypt] Siberia force group:</A></TD><TD><input name="dre56_force_group" class="medium" type="text" maxlength="2" value="##DRE56FORCEGROUP##"></TD></TR>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 426518
:
318116
|
329610
|
329612
|
329614
|
337900
|
337902
|
516320
|
516322
| 516324 |
516326
|
516328