Index: CMakeLists.txt =================================================================== --- CMakeLists.txt (revision 11384) +++ 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 11384) +++ 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 11384) +++ 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 11384) +++ 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/md5.c =================================================================== --- cscrypt/md5.c (revision 11384) +++ 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 11384) +++ 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 11384) +++ 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. + + + Copyright (C) 19yy + + 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. + + , 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 +#include +#include +#include + +#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>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>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>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>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>16) | (b&0xffff0000) ; + } + } + } +//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); +// now 01230123 + for(g=0;g=0;i--){ + { + MEMALIGN batch tkkmulti=kkmulti[i]; + batch *si=(batch *)sbox_in; + batch *r6_N=(batch *)(r+roff+GROUP_PARALLELISM*6); + for(g=0;gck,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<iA_g[by][bi]=(key->iA[by]&(1<iB_g[by][bi]=(key->iB[by]&(1<ck,key->kk); + for(i=0;i<56;i++){ + for(j=0;jkkmulti[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=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;ig_n[i]){ + g_swap(i,j); + } + } + } + DBG(fprintf(stderr,"POSTSORTING\n")); + for(i=0;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>>>>ITER 0\n")); + iter=0; + stream_cypher_group_init(®s,k->iA_g,k->iB_g,stream_in); + // fill first ib + for(g=0;g0;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>>>>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=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 + +#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 11384) +++ 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 *); }; @@ -1455,6 +1464,14 @@ int16_t max; }; +#ifdef WITH_EMU +typedef struct opkeys +{ + uint8_t key3b[32][32]; + uint8_t key56[32][32]; +} opkeys_t; +#endif + struct s_reader //contains device info, reader info and card info { uint8_t keepalive; @@ -1714,6 +1731,15 @@ #ifdef MODULE_GHTTP uint8_t ghttp_use_ssl; #endif +#ifdef WITH_EMU + FTAB emu_auproviders; + char *extee36; + char *extee56; + opkeys_t *ee36; + opkeys_t *ee56; + 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; @@ -2207,6 +2233,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 +2426,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 11384) +++ module-dvbapi.c (working copy) @@ -1458,7 +1458,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) @@ -1477,7 +1485,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 @@ -4361,6 +4376,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! @@ -4387,9 +4403,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 > 0xb) + { + if(buffer[0xb] > curpid->pvu_counter || (curpid->pvu_counter == 255 && buffer[0xb] == 0) + || ((curpid->pvu_counter - buffer[0xb]) > 5)) + { + curpid->pvu_counter = buffer[0xb]; + 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; @@ -4669,6 +4700,40 @@ dvbapi_stop_filternum(demux_id, filter_num); 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+2caid>>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 11384) +++ 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,4899 @@ +#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: 735 $"+10); +} + +// Key DB +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= 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; + } + + now = time(NULL); + localtime_r(&now, &t); + strftime(dateText, sizeof(dateText)-1, "%c", &t); + + 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) +{ + 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); + + // 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 + { + 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; + } + + for(i=0; ikeyCount; i++) { + + if(KeyDB->EmuKeys[i].provider != provider) { + continue; + } + + if(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(writeKey) { + WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); + } + } + + return 1; + } + + if(KeyDB->keyCount+1 > KeyDB->keyMax) { + if(KeyDB->EmuKeys == NULL) { + KeyDB->EmuKeys = (KeyData*)malloc(sizeof(KeyData)*(KeyDB->keyMax+64)); + if(KeyDB->EmuKeys == NULL) { + free(tmpKey); + return 0; + } + KeyDB->keyMax+=64; + } + else { + 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, const 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; ikeyCount; i++) { + + if((KeyDB->EmuKeys[i].provider & ~providerIgnoreMask) != provider) { + continue; + } + + if(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(jnextKey != 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(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); +} + +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)) + { + ret = 1; + } + } + + free(tmpKey); + return ret; +} + +uint8_t read_emu_keyfile(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; + } + + CharToBin(key, keyString, strlen(keyString)); + SetKey(identifier, provider, keyName, key, keyLength, 0, NULL); + 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(void) +{ + 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; + } + + CharToBin(key, keyString, strlen(keyString)); + SetKey(identifier, provider, keyName, key, keyLength, 0, NULL); + free(key); + line = strtok_r(NULL, "\n", &saveptr); + } + free(keyData); +} +#endif + +// 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> 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 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 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) { + 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=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; i0) { + 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= 3) { + ecmLen = GetEcmLen(ecm); + + if(ecmLen > 7 && ecmLen <= ecmDataLen) { + for(i=5; i+1= 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 void PowervuExpandSeed(uint8_t seedType, uint8_t *seed) +{ + uint8_t seedLength, 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; + } + + for(i=seedLength; i<7; i++) + { + seed[i] = seed[i%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) +{ + int32_t k; + + PowervuExpandSeed(seedType, seed); + + if(csaUsed) + { + 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 + { + for(k = 0; k < 7; k++) + { + cw[k] = seed[k] ^ baseCw[k]; + } + ExpandDesKey(cw); + } +} + +#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; +#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; + } + + 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; + } + + csaUsed = GetBit(ecm[i+7], 7); + fixedKey = !GetBit(ecm[i+6], 5); + oddKey = GetBit(ecm[i+6], 4); + 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); + + 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); + } + + 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 +void DrecryptSetEmuExtee(ReaderInstanceData* idata) +{ + FILE *file = NULL; + + if(idata->ee36 != NULL) + { + //need add md5 check + free(idata->ee36); + } + + if(idata->ee56 != NULL) + { + //need add md5 check + free(idata->ee56); + } + + idata->ee36 = malloc(sizeof(opkeys_t)); + idata->ee56 = malloc(sizeof(opkeys_t)); + + if(idata->ee36 == NULL || idata->ee56 == NULL) return; + + memset(idata->ee36, 0, sizeof(opkeys_t)); + memset(idata->ee56, 0, sizeof(opkeys_t)); + + if(idata->extee36 == NULL) + { + idata->extee36 = malloc(256); + snprintf(idata->extee36, 256, "%see36.bin", emu_keyfile_path); + } + else if(strchr(idata->extee36, '/') == NULL) + { + char *temp = malloc(256); + snprintf(temp, 256, "%s%s" ,emu_keyfile_path, idata->extee36); + free(idata->extee36); + idata->extee36 = malloc(strlen(temp)+1); + strncpy(idata->extee36, temp, strlen(temp)); + free(temp); + } + + if(idata->extee56 == NULL) + { + idata->extee56 = malloc(256); + snprintf(idata->extee56, 256, "%see56.bin", emu_keyfile_path); + } + else if(strchr(idata->extee56, '/') == NULL) + { + char *temp = malloc(256); + snprintf(temp, 256, "%s%s", emu_keyfile_path, idata->extee56); + free(idata->extee56); + idata->extee56 = malloc(strlen(temp)+1); + strncpy(idata->extee56, temp, strlen(temp)); + free(temp); + } + + if((file = fopen(idata->extee36,"rb")) != NULL) + { + if(fread(idata->ee36, 1, sizeof(opkeys_t), file) != sizeof(opkeys_t)) + { + memset(idata->ee36, 0, sizeof(opkeys_t)); + } + fclose(file); + } + //else cs_log("Cannot open key file: %s", idata->extee36); + + if((file = fopen(idata->extee56, "rb")) != NULL) + { + if(fread(idata->ee56, 1, sizeof(opkeys_t),file) != sizeof(opkeys_t)) + { + memset(idata->ee56, 0, sizeof(opkeys_t)); + } + fclose(file); + } + //else cs_log("Cannot open key file: %s", idata->extee56); +} + +static void DREover(const uint8_t *ECMdata, uint8_t *DW) +{ + uint8_t key[8]; + char keyStr[EMU_MAX_CHAR_KEYNAME]; + uint32_t key_schedule[32]; + + if(ECMdata[2] >= (43 + 4) && ECMdata[40] == 0x3A && ECMdata[41] == 0x4B) + { + snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%X", (ECMdata[42] & 0x0F)); + + if(!FindKey('D', 0, 0, keyStr, 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(ReaderInstanceData* idata, uint16_t caid, uint32_t provId, uint8_t *ecm, uint8_t *dw) +{ + uint8_t keyClass = ecm[5], keyIndex = ecm[6], ccw[16], key[32], dummy[2][32]; + + uint16_t overcryptId; + + uint16_t ecmLen = GetEcmLen(ecm); + + cs_log_dbg(D_READER, "CAID %04X IDENT %06X", caid, provId); + + if(ecmLen < 30 || caid != 0x4AE1) + { + return 1; + } + + switch(provId & 0xFF) + { + case 0x11: + memcpy(key, keyIndex == 0x3B ? idata->ee36->key3b[keyClass] : idata->ee36->key56[keyClass], 32); + if(ecm[3] != 0x56) memcpy(key, keyIndex == 0x3B ? idata->ee36->key3b[ecm[3]] : idata->ee36->key56[ecm[3]], 32); + break; + case 0x14: + memcpy(key, keyIndex == 0x3B ? idata->ee56->key3b[keyClass] : idata->ee56->key56[keyClass], 32); + break; + default: + return 4; + } + + memset(dummy[0], 0x00, 32); + memset(dummy[1], 0xFF, 32); + + if(memcmp(dummy[0], key, 32) == 0 || memcmp(dummy[1], key, 32) == 0) + { + DrecryptSetEmuExtee(idata); + cs_log("ERROR: ee%s.bin keys missing", ((provId & 0xFF) == 0x11) ? "36" : "56"); + return 2; + } + + memcpy(ccw, ecm+13, 16); + + DrecryptPostCw(key); DrecryptPostCw(key+16); + DrecryptDecrypt(ccw, key); DrecryptDecrypt(ccw+8, key); + + if(ecmLen >= 46 && ecm[43] == 1 && provId == 0x11) + { + DrecryptSwap(ccw); + overcryptId = b2i(2, &ecm[44]); + if(Drecrypt2OverCW(overcryptId, ccw) == 2) DrecryptSetEmuExtee(idata); + + if(isValidDCW(ccw)) + { + memcpy(dw, ccw, 16); + return 0; + } + return 9; + } + + DREover(ecm, ccw); + + if(isValidDCW(ccw)) + { + DrecryptSwap(ccw); + memcpy(dw, ccw, 16); + return 0; + } + + DrecryptSetEmuExtee(idata); + + return 1; +} + +//Tandberg EMU +static int8_t GetTandbergKey(uint8_t *buf, uint32_t entitlementId) +{ + if(FindKey('T', entitlementId, 0, "00", buf, 8, 0, 0, 0, NULL)) + { + return 1; + } + + if(FindKey('T', entitlementId, 0, "01", buf, 8, 1, 0, 0, NULL)) + { + return 1; + } + + return 0; +} + +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; + + switch(nanoType) + { + 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(ecmKey, entitlementId)) + { + 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(ecmKey, entitlementId)) + { + 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 +*/ +#ifdef WITH_EMU +int8_t ProcessECM(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, ReaderInstanceData* idata) +#else +int8_t ProcessECM(int16_t ecmDataLen, uint16_t caid, uint32_t provider, const uint8_t *ecm, + uint8_t *dw, uint16_t srvid, uint16_t ecmpid, ReaderInstanceData* idata) +#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(caid, 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 && idata) { + result = Drecrypt2ECM(idata, caid, 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) { + 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 5) { + break; + } + for(j=i; j+2 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); + + for(j=0; j>2); + SetKey('I', ident, keyName, &emm[i+3], 16, 1, 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 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; ikeyCount; 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 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; + } + + // 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; + } + + 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 %08X %s %s -> REJECTED (looks invalid) UA: %X", groupId, keyName, keyValue, uniqueAddress); + continue; + } + + snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", emmType); + snprintf(uaInfo, sizeof(uaInfo), "UA: %08X", uniqueAddress); + + 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 %08X %s %s ; UA: %X", 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; ikeyCount && (*count)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; jkeyCount && (*count)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 GetDrecryptEMMKey(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 DrecryptWriteEEToFile(ReaderInstanceData* idata, uint8_t ident) +{ + FILE *file = NULL; + opkeys_t *ee = ident == 0x11 ? idata->ee36 : idata->ee56; + char *path = ident == 0x11 ? idata->extee36 : idata->extee56; + + if(ee == NULL) return; + + if((file = fopen(path,"wb")) == NULL) return; + fwrite(ee,1,sizeof(opkeys_t),file); + fclose(file); +} + +static int8_t DrecryptProcessEMM(uint16_t caid, uint32_t provId, uint8_t *emm, ReaderInstanceData* idata, uint32_t *keysAdded) +{ + uint16_t emmLen = ((emm[1] & 0xF) << 8) | emm[2]; + uint32_t keyIdent; + uint16_t keyName; + uint8_t emmKey[32]; + int32_t i; + uint8_t *curECMkey3B, *curECMkey56; + uint8_t keynum, keyidx, keyclass, key1offset, key2offset; + char newKeyName[EMU_MAX_CHAR_KEYNAME], keyValue[100]; + + if(emmLen < 1 || caid != 0x4AE1) + { + return 1; + } + + if(emm[0] == 0x91) + { + Drecrypt2OverEMM(emm); + return 0; + } + else if(emm[0] == 0x82) + { + ReasmEMM82(emm); + return 0; + } + else if(emm[0] != 0x86) + { + return 1; + } + + 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; + } + + switch(provId & 0xFF) + { + case 0x11: + if (idata->ee36 == NULL) return 7; + curECMkey3B = idata->ee36->key3b[emm[keyclass]]; + curECMkey56 = idata->ee36->key56[emm[keyclass]]; + break; + case 0x14: + if (idata->ee56 == NULL) return 7; + curECMkey3B = idata->ee56->key3b[emm[keyclass]]; + curECMkey56 = idata->ee56->key56[emm[keyclass]]; + break; + default: + return 9; + } + + keyIdent = caid<<8 | provId; + keyName = emm[0x3]<<8 | emm[keynum]; + + if(!GetDrecryptEMMKey(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); + (*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); + (*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) DrecryptWriteEEToFile(idata, (provId & 0xFF)); + + return 0; +} + +static int8_t Drecrypt2EMM(uint16_t caid, uint32_t provId, uint8_t *emm, ReaderInstanceData* idata, uint32_t *keysAdded) +{ + int8_t result = DrecryptProcessEMM(caid, provId, emm, idata, keysAdded); + + if(result == 2) + { + uint8_t keynum = 0, emmkey; + uint32_t i, len; + KeyDataContainer *KeyDB; + + emmkey = emm[4] == 0x4D ? emm[0x61] : emm[0x2c]; + + if((KeyDB = GetKeyContainer('D')) != NULL) + { + for(i=0; ikeyCount; i++) + { + if(KeyDB->EmuKeys[i].provider != ((caid << 8) | provId)) + { continue; } + + len = strlen(KeyDB->EmuKeys[i].keyName); + + if(len < 6) + { continue; } + + if(memcmp(KeyDB->EmuKeys[i].keyName, "MK", 2)) + { continue; } + + CharToBin(&keynum, KeyDB->EmuKeys[i].keyName+4, 2); + if(keynum == emmkey) + { + if(provId == 0x11) CharToBin(&idata->dre36_force_group, KeyDB->EmuKeys[i].keyName+2, 2); + else CharToBin(&idata->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; + int32_t len; + KeyDataContainer *KeyDB; + + KeyDB = GetKeyContainer('D'); + if(KeyDB == NULL) + { return 0; } + + (*count) = 0; + + for(i=0; ikeyCount && (*count)EmuKeys[i].provider != ((caid << 8) | provid)) + { continue; } + + len = strlen(KeyDB->EmuKeys[i].keyName); + + if(len < 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 GetTandbergEMMKey(uint8_t *buf, uint16_t keyIndex, uint8_t isCriticalKey, const char *keySet) +{ + return FindKey('T', keyIndex, 0, keySet, buf, 8, isCriticalKey, 0, 0, NULL); +} + +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(!GetTandbergEMMKey(emmKey, keyIndex, 1, "MK01")) + { + 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); + } + } + 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(!GetTandbergEMMKey(emmKey, keyIndex, 1, "MK")) + { + 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); + } + } + 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(!GetTandbergEMMKey(emmKey, keyIndex, 1, "MK")) + { + 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(!GetTandbergEMMKey(emmKey, keyIndex, 1, "MK01")) + { + 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]; + 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(uint16_t caid, uint32_t provider, const uint8_t *emm, ReaderInstanceData* idata, 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 && idata) { + result = Drecrypt2EMM(caid, provider, emmCopy, idata, 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,141 @@ +#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); + uint8_t read_emu_keyfile(const char *path); + +#if !defined(__APPLE__) && !defined(__ANDROID__) + void read_emu_keymemory(void); +#endif + + int32_t CharToBin(uint8_t *out, const char *in, uint32_t inLen); + +#ifndef WITH_EMU + typedef struct opkeys + { + uint8_t key3b[32][32]; + uint8_t key56[32][32]; + } opkeys_t; +#endif + + typedef struct { + char *extee36; + char *extee56; + opkeys_t *ee36; + opkeys_t *ee56; + uint8_t dre36_force_group; + uint8_t dre56_force_group; + } ReaderInstanceData; + + + /* 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 + */ +#ifdef WITH_EMU + int8_t ProcessECM(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, ReaderInstanceData* idata); +#else + int8_t ProcessECM(int16_t ecmDataLen, uint16_t caid, uint32_t provider, const uint8_t *ecm, + uint8_t *dw, uint16_t srvid, uint16_t ecmpid, ReaderInstanceData* idata); +#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(uint16_t caid, uint32_t provider, const uint8_t *emm, ReaderInstanceData* idata, 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); + + void DrecryptSetEmuExtee(ReaderInstanceData* idata); + +#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 SetKey(char identifier, uint32_t provider, char *keyName, uint8_t *orgKey, uint32_t keyLength, uint8_t writeKey, char *comment); + + int32_t FindKey(char identifier, uint32_t provider, uint32_t providerIgnoreMask, const 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 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+7srvid == 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+4video_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(0x0E00, 0, data, NULL, &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> 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; iconnfd) + { + 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; iconnfd = 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; iwrite_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; iextee36; + idata.extee56 = rdr->extee56; + idata.ee36 = rdr->ee36; + idata.ee56 = rdr->ee56; + idata.dre36_force_group = rdr->dre36_force_group; + idata.dre56_force_group = rdr->dre56_force_group; + + if (!ProcessECM(er->ecmlen, er->caid, er->prid, er->ecm, ea->cw, er->srvid, er->pid, &ea->cw_ex, &idata)) { + return CS_OK; + } + + return CS_ERROR; +} + +static void refresh_entitlements(struct s_reader *reader); + +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; + } + + ReaderInstanceData idata; + idata.extee36 = rdr->extee36; + idata.extee56 = rdr->extee56; + idata.ee36 = rdr->ee36; + idata.ee56 = rdr->ee56; + idata.dre36_force_group = rdr->dre36_force_group; + idata.dre56_force_group = rdr->dre56_force_group; + + if(!ProcessEMM(b2i(2, emm->caid), b2i(4, emm->provid), emm->emm, &idata, &keysAdded)) { + if(keysAdded > 0) { refresh_entitlements(rdr); } + return CS_OK; + } + + return CS_ERROR; +} + +static int32_t EMU_Init(struct s_reader *reader); + +static int32_t emu_card_info(struct s_reader *rdr) { + EMU_Init(rdr); + return CS_OK; +} + +static int32_t emu_card_init(struct s_reader *UNUSED(rdr), struct s_ATR *UNUSED(atr)) +{return CS_ERROR;} + +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;} + + +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)) +{ + if(ep->emm[0] == 0x91) + { + ep->type = GLOBAL; + return 1; + } + else if(ep->emm[0] == 0x82) + { + ep->type = GLOBAL; + return 1; + } + else + { + switch(ep->emm[0]) + { + 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 + + 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; +} + +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 && inprids; 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>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, + .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, +}; + + +#define CR_OK 0 +#define CR_ERROR 1 + +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 uint8_t oneByte = 0x01; + +static void refresh_entitlements(struct s_reader *reader) +{ + uint32_t i; + KeyData *tmpKeyData; + + if(reader->ll_entitlements) + { ll_clear_data(reader->ll_entitlements); } + + for(i=0; i>8, CwKeys.EmuKeys[i].provider&0xFF, + CwKeys.EmuKeys[i].key, CwKeys.EmuKeys[i].keyName, CwKeys.EmuKeys[i].keyLength, 0); + + for(i=0; iprovider>>8, tmpKeyData->provider&0xFF, tmpKeyData->key, tmpKeyData->keyName, tmpKeyData->keyLength, 0); + tmpKeyData = tmpKeyData->nextKey; + } + while(tmpKeyData!= NULL); + } + + for(i=0; ihexserial[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++; + } + } +} + +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_Init(struct s_reader *reader) +{ + int32_t i; + char authtmp[128]; + char keyStr[EMU_MAX_CHAR_KEYNAME]; + + if(stream_server_thread_init == 0) + { + stream_server_thread_init = 1; + + SAFE_MUTEX_INIT(&emu_fixed_key_srvid_mutex, NULL); + + for(i=0; ides_key_length >= 128) + { + for(i=0; i<16; i++) + { + snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%X", i); + + SetKey('D', 0, keyStr, reader->des_key + (i*8), 8, 0, NULL); + } + } + + ReaderInstanceData idata; + idata.extee36 = reader->extee36; + idata.extee56 = reader->extee56; + idata.ee36 = reader->ee36; + idata.ee56 = reader->ee56; + idata.dre36_force_group = reader->dre36_force_group; + idata.dre56_force_group = reader->dre56_force_group; + + DrecryptSetEmuExtee(&idata); + + refresh_entitlements(reader); + + set_prids(reader); + + return CR_OK; +} + +static int32_t EMU_GetStatus(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_Close(struct s_reader *UNUSED(reader)) { 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_Init, + .get_status = EMU_GetStatus, + .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) +{ + LL_ITER itr; + struct s_reader *rdr; + int8_t haveEmuReader = 0; + char *emuName = "emulator"; + char *ctab, *ftab, *emu_auproviders; + + itr = ll_iter_create(configured_readers); + while((rdr = ll_iter_next(&itr))) + { + if(rdr->typ == R_EMU) { + haveEmuReader = 1; + break; + } + } + + rdr = NULL; + + 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)); + + ctab = strdup("090F,0500,1801,0604,2600,FFFF,0E00,4AE1,1010"); + chk_caidtab(ctab, &rdr->ctab); + NULLFREE(ctab); + + 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); + + emu_auproviders = strdup("0604:010200;0E00:000000;4AE1:000011,000014,0000FE;1010:000000;"); + chk_ftab(emu_auproviders, &rdr->emu_auproviders); + NULLFREE(emu_auproviders); + + rdr->cachemm = 2; + rdr->rewritemm = 1; + rdr->logemm = 2; + rdr->deviceemm = 1; + + rdr->grp = 0x1ULL; + + rdr->crdr = &cardreader_emu; + + reader_fixups_fn(rdr); + ll_append(configured_readers, rdr); + } + +#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 11384) +++ 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 11384) +++ 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 11384) +++ 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 11384) +++ 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 11384) +++ 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 11384) +++ 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 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) { @@ -1631,6 +1661,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 +2126,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 +2704,21 @@ 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); + + //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 +2740,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 +4465,38 @@ tpl_addVar(vars, TPLAPPEND, "LOGHISTORY", "

New Structure:
"); 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 +4972,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 +6419,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 29 +#endif { NULL, 0, 0 }, }; @@ -6806,7 +6892,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 +7899,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-chk.c =================================================================== --- oscam-chk.c (revision 11384) +++ 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 11384) +++ 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)) { @@ -1289,6 +1313,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 11384) +++ 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,13 @@ #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_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 11384) +++ 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 11384) +++ 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 11384) +++ 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 11384) +++ 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> 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 11384) +++ 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 11384) +++ 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 #include @@ -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(); @@ -1896,6 +1908,9 @@ #ifdef MODULE_GBOX 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 11384) +++ 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 11384) +++ 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 11384) +++ webif/config/dvbapi.html (working copy) @@ -53,7 +53,7 @@ Write detected prov name to srvid: - \ No newline at end of file + \ No newline at end of file Index: webif/config/menu.html =================================================================== --- webif/config/menu.html (revision 11384) +++ webif/config/menu.html (working copy) @@ -16,6 +16,7 @@ ##TPLCONFIGMENUDVBAPI## ##TPLCONFIGMENULCD## ##TPLCONFIGMENUMONITOR## +##TPLCONFIGMENUSTREAMRELAY##
  • WebIf
  • Index: webif/config/menu_streamrelay.html =================================================================== --- webif/config/menu_streamrelay.html (revision 0) +++ webif/config/menu_streamrelay.html (working copy) @@ -0,0 +1 @@ +
  • Stream Relay
  • Index: webif/config/streamrelay.html =================================================================== --- webif/config/streamrelay.html (revision 0) +++ webif/config/streamrelay.html (working copy) @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + \ No newline at end of file Index: webif/files/menu.html =================================================================== --- webif/files/menu.html (revision 11384) +++ webif/files/menu.html (working copy) @@ -9,8 +9,8 @@ ##TPLFILEMENUANTICASC##
  • logfile
  • userfile
  • -##TPLFILEMENUGBOX## -
  • other files +##TPLFILEMENUGBOX## +
  • other files
  • Index: webif/files/menu_softcamkey.html =================================================================== --- webif/files/menu_softcamkey.html (revision 0) +++ webif/files/menu_softcamkey.html (working copy) @@ -0,0 +1 @@ +
  • SoftCam.Key
  • Index: webif/pages_index.txt =================================================================== --- webif/pages_index.txt (revision 11384) +++ 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,5 @@ + + + + +
    Edit Stream Relay Config
    Mode (disable to use direct dvbapi decryption) + +
    Source Stream Host:
    Source Stream Port:
    Source Stream User:
    Source Stream Password:
    Relay Port:
    ECM fix delay:
    Process EMM from stream: + +
    AU providers:
    DRE extee36:
    DRE extee56:
    DRE center force group:
    DRE siberia force group: