Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Index: CMakeLists.txt
- ===================================================================
- --- CMakeLists.txt (revision 11209)
- +++ CMakeLists.txt (working copy)
- @@ -99,6 +99,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}
- @@ -108,6 +109,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")
- @@ -415,6 +417,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})
- @@ -444,6 +453,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)
- @@ -493,7 +503,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")
- @@ -642,6 +652,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)
- @@ -726,6 +741,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.*")
- @@ -814,4 +845,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 11209)
- +++ Makefile (working copy)
- @@ -65,6 +65,13 @@
- LDFLAGS = -Wl,--gc-sections
- +TARGETHELP := $(shell $(CC) --target-help)
- +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:
- @@ -267,6 +274,23 @@
- 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) += module-emulator-st20.c
- +SRC-$(CONFIG_WITH_EMU) += module-emulator-dre2overcrypt.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
- @@ -359,7 +383,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 11209)
- +++ 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 11209)
- +++ 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"
- @@ -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
- @@ -288,12 +289,14 @@
- 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 MODULE_NEWCAMD >/dev/null
- }
- list_config() {
- @@ -343,9 +346,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() {
- @@ -456,6 +459,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 11209)
- +++ 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 11209)
- +++ 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 11209)
- +++ csctapi/cardreaders.h (working copy)
- @@ -13,5 +13,6 @@
- extern const struct s_cardreader cardreader_smartreader;
- extern const struct s_cardreader cardreader_stapi;
- extern const struct s_cardreader cardreader_stinger;
- +extern const struct s_cardreader cardreader_emu;
- #endif
- Index: ffdecsa/CMakeLists.txt
- ===================================================================
- --- ffdecsa/CMakeLists.txt (revision 0)
- +++ ffdecsa/CMakeLists.txt (working copy)
- @@ -0,0 +1,8 @@
- +project (ffdecsa)
- +
- +file (GLOB ffdecsa_srcs "ffdecsa.c")
- +file (GLOB ffdecsa_hdrs "*.h")
- +
- +set (lib_name "ffdecsa")
- +
- +add_library (${lib_name} STATIC ${ffdecsa_srcs} ${ffdecsa_hdrs})
- Index: ffdecsa/COPYING
- ===================================================================
- --- ffdecsa/COPYING (revision 0)
- +++ ffdecsa/COPYING (working copy)
- @@ -0,0 +1,339 @@
- + GNU GENERAL PUBLIC LICENSE
- + Version 2, June 1991
- +
- + Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- + 675 Mass Ave, Cambridge, MA 02139, USA
- + Everyone is permitted to copy and distribute verbatim copies
- + of this license document, but changing it is not allowed.
- +
- + Preamble
- +
- + The licenses for most software are designed to take away your
- +freedom to share and change it. By contrast, the GNU General Public
- +License is intended to guarantee your freedom to share and change free
- +software--to make sure the software is free for all its users. This
- +General Public License applies to most of the Free Software
- +Foundation's software and to any other program whose authors commit to
- +using it. (Some other Free Software Foundation software is covered by
- +the GNU Library General Public License instead.) You can apply it to
- +your programs, too.
- +
- + When we speak of free software, we are referring to freedom, not
- +price. Our General Public Licenses are designed to make sure that you
- +have the freedom to distribute copies of free software (and charge for
- +this service if you wish), that you receive source code or can get it
- +if you want it, that you can change the software or use pieces of it
- +in new free programs; and that you know you can do these things.
- +
- + To protect your rights, we need to make restrictions that forbid
- +anyone to deny you these rights or to ask you to surrender the rights.
- +These restrictions translate to certain responsibilities for you if you
- +distribute copies of the software, or if you modify it.
- +
- + For example, if you distribute copies of such a program, whether
- +gratis or for a fee, you must give the recipients all the rights that
- +you have. You must make sure that they, too, receive or can get the
- +source code. And you must show them these terms so they know their
- +rights.
- +
- + We protect your rights with two steps: (1) copyright the software, and
- +(2) offer you this license which gives you legal permission to copy,
- +distribute and/or modify the software.
- +
- + Also, for each author's protection and ours, we want to make certain
- +that everyone understands that there is no warranty for this free
- +software. If the software is modified by someone else and passed on, we
- +want its recipients to know that what they have is not the original, so
- +that any problems introduced by others will not reflect on the original
- +authors' reputations.
- +
- + Finally, any free program is threatened constantly by software
- +patents. We wish to avoid the danger that redistributors of a free
- +program will individually obtain patent licenses, in effect making the
- +program proprietary. To prevent this, we have made it clear that any
- +patent must be licensed for everyone's free use or not licensed at all.
- +
- + The precise terms and conditions for copying, distribution and
- +modification follow.
- +
- + GNU GENERAL PUBLIC LICENSE
- + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- +
- + 0. This License applies to any program or other work which contains
- +a notice placed by the copyright holder saying it may be distributed
- +under the terms of this General Public License. The "Program", below,
- +refers to any such program or work, and a "work based on the Program"
- +means either the Program or any derivative work under copyright law:
- +that is to say, a work containing the Program or a portion of it,
- +either verbatim or with modifications and/or translated into another
- +language. (Hereinafter, translation is included without limitation in
- +the term "modification".) Each licensee is addressed as "you".
- +
- +Activities other than copying, distribution and modification are not
- +covered by this License; they are outside its scope. The act of
- +running the Program is not restricted, and the output from the Program
- +is covered only if its contents constitute a work based on the
- +Program (independent of having been made by running the Program).
- +Whether that is true depends on what the Program does.
- +
- + 1. You may copy and distribute verbatim copies of the Program's
- +source code as you receive it, in any medium, provided that you
- +conspicuously and appropriately publish on each copy an appropriate
- +copyright notice and disclaimer of warranty; keep intact all the
- +notices that refer to this License and to the absence of any warranty;
- +and give any other recipients of the Program a copy of this License
- +along with the Program.
- +
- +You may charge a fee for the physical act of transferring a copy, and
- +you may at your option offer warranty protection in exchange for a fee.
- +
- + 2. You may modify your copy or copies of the Program or any portion
- +of it, thus forming a work based on the Program, and copy and
- +distribute such modifications or work under the terms of Section 1
- +above, provided that you also meet all of these conditions:
- +
- + a) You must cause the modified files to carry prominent notices
- + stating that you changed the files and the date of any change.
- +
- + b) You must cause any work that you distribute or publish, that in
- + whole or in part contains or is derived from the Program or any
- + part thereof, to be licensed as a whole at no charge to all third
- + parties under the terms of this License.
- +
- + c) If the modified program normally reads commands interactively
- + when run, you must cause it, when started running for such
- + interactive use in the most ordinary way, to print or display an
- + announcement including an appropriate copyright notice and a
- + notice that there is no warranty (or else, saying that you provide
- + a warranty) and that users may redistribute the program under
- + these conditions, and telling the user how to view a copy of this
- + License. (Exception: if the Program itself is interactive but
- + does not normally print such an announcement, your work based on
- + the Program is not required to print an announcement.)
- +
- +These requirements apply to the modified work as a whole. If
- +identifiable sections of that work are not derived from the Program,
- +and can be reasonably considered independent and separate works in
- +themselves, then this License, and its terms, do not apply to those
- +sections when you distribute them as separate works. But when you
- +distribute the same sections as part of a whole which is a work based
- +on the Program, the distribution of the whole must be on the terms of
- +this License, whose permissions for other licensees extend to the
- +entire whole, and thus to each and every part regardless of who wrote it.
- +
- +Thus, it is not the intent of this section to claim rights or contest
- +your rights to work written entirely by you; rather, the intent is to
- +exercise the right to control the distribution of derivative or
- +collective works based on the Program.
- +
- +In addition, mere aggregation of another work not based on the Program
- +with the Program (or with a work based on the Program) on a volume of
- +a storage or distribution medium does not bring the other work under
- +the scope of this License.
- +
- + 3. You may copy and distribute the Program (or a work based on it,
- +under Section 2) in object code or executable form under the terms of
- +Sections 1 and 2 above provided that you also do one of the following:
- +
- + a) Accompany it with the complete corresponding machine-readable
- + source code, which must be distributed under the terms of Sections
- + 1 and 2 above on a medium customarily used for software interchange; or,
- +
- + b) Accompany it with a written offer, valid for at least three
- + years, to give any third party, for a charge no more than your
- + cost of physically performing source distribution, a complete
- + machine-readable copy of the corresponding source code, to be
- + distributed under the terms of Sections 1 and 2 above on a medium
- + customarily used for software interchange; or,
- +
- + c) Accompany it with the information you received as to the offer
- + to distribute corresponding source code. (This alternative is
- + allowed only for noncommercial distribution and only if you
- + received the program in object code or executable form with such
- + an offer, in accord with Subsection b above.)
- +
- +The source code for a work means the preferred form of the work for
- +making modifications to it. For an executable work, complete source
- +code means all the source code for all modules it contains, plus any
- +associated interface definition files, plus the scripts used to
- +control compilation and installation of the executable. However, as a
- +special exception, the source code distributed need not include
- +anything that is normally distributed (in either source or binary
- +form) with the major components (compiler, kernel, and so on) of the
- +operating system on which the executable runs, unless that component
- +itself accompanies the executable.
- +
- +If distribution of executable or object code is made by offering
- +access to copy from a designated place, then offering equivalent
- +access to copy the source code from the same place counts as
- +distribution of the source code, even though third parties are not
- +compelled to copy the source along with the object code.
- +
- + 4. You may not copy, modify, sublicense, or distribute the Program
- +except as expressly provided under this License. Any attempt
- +otherwise to copy, modify, sublicense or distribute the Program is
- +void, and will automatically terminate your rights under this License.
- +However, parties who have received copies, or rights, from you under
- +this License will not have their licenses terminated so long as such
- +parties remain in full compliance.
- +
- + 5. You are not required to accept this License, since you have not
- +signed it. However, nothing else grants you permission to modify or
- +distribute the Program or its derivative works. These actions are
- +prohibited by law if you do not accept this License. Therefore, by
- +modifying or distributing the Program (or any work based on the
- +Program), you indicate your acceptance of this License to do so, and
- +all its terms and conditions for copying, distributing or modifying
- +the Program or works based on it.
- +
- + 6. Each time you redistribute the Program (or any work based on the
- +Program), the recipient automatically receives a license from the
- +original licensor to copy, distribute or modify the Program subject to
- +these terms and conditions. You may not impose any further
- +restrictions on the recipients' exercise of the rights granted herein.
- +You are not responsible for enforcing compliance by third parties to
- +this License.
- +
- + 7. If, as a consequence of a court judgment or allegation of patent
- +infringement or for any other reason (not limited to patent issues),
- +conditions are imposed on you (whether by court order, agreement or
- +otherwise) that contradict the conditions of this License, they do not
- +excuse you from the conditions of this License. If you cannot
- +distribute so as to satisfy simultaneously your obligations under this
- +License and any other pertinent obligations, then as a consequence you
- +may not distribute the Program at all. For example, if a patent
- +license would not permit royalty-free redistribution of the Program by
- +all those who receive copies directly or indirectly through you, then
- +the only way you could satisfy both it and this License would be to
- +refrain entirely from distribution of the Program.
- +
- +If any portion of this section is held invalid or unenforceable under
- +any particular circumstance, the balance of the section is intended to
- +apply and the section as a whole is intended to apply in other
- +circumstances.
- +
- +It is not the purpose of this section to induce you to infringe any
- +patents or other property right claims or to contest validity of any
- +such claims; this section has the sole purpose of protecting the
- +integrity of the free software distribution system, which is
- +implemented by public license practices. Many people have made
- +generous contributions to the wide range of software distributed
- +through that system in reliance on consistent application of that
- +system; it is up to the author/donor to decide if he or she is willing
- +to distribute software through any other system and a licensee cannot
- +impose that choice.
- +
- +This section is intended to make thoroughly clear what is believed to
- +be a consequence of the rest of this License.
- +
- + 8. If the distribution and/or use of the Program is restricted in
- +certain countries either by patents or by copyrighted interfaces, the
- +original copyright holder who places the Program under this License
- +may add an explicit geographical distribution limitation excluding
- +those countries, so that distribution is permitted only in or among
- +countries not thus excluded. In such case, this License incorporates
- +the limitation as if written in the body of this License.
- +
- + 9. The Free Software Foundation may publish revised and/or new versions
- +of the General Public License from time to time. Such new versions will
- +be similar in spirit to the present version, but may differ in detail to
- +address new problems or concerns.
- +
- +Each version is given a distinguishing version number. If the Program
- +specifies a version number of this License which applies to it and "any
- +later version", you have the option of following the terms and conditions
- +either of that version or of any later version published by the Free
- +Software Foundation. If the Program does not specify a version number of
- +this License, you may choose any version ever published by the Free Software
- +Foundation.
- +
- + 10. If you wish to incorporate parts of the Program into other free
- +programs whose distribution conditions are different, write to the author
- +to ask for permission. For software which is copyrighted by the Free
- +Software Foundation, write to the Free Software Foundation; we sometimes
- +make exceptions for this. Our decision will be guided by the two goals
- +of preserving the free status of all derivatives of our free software and
- +of promoting the sharing and reuse of software generally.
- +
- + NO WARRANTY
- +
- + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
- +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
- +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
- +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
- +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
- +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
- +REPAIR OR CORRECTION.
- +
- + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
- +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
- +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
- +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
- +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
- +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
- +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
- +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
- +POSSIBILITY OF SUCH DAMAGES.
- +
- + END OF TERMS AND CONDITIONS
- +
- + Appendix: How to Apply These Terms to Your New Programs
- +
- + If you develop a new program, and you want it to be of the greatest
- +possible use to the public, the best way to achieve this is to make it
- +free software which everyone can redistribute and change under these terms.
- +
- + To do so, attach the following notices to the program. It is safest
- +to attach them to the start of each source file to most effectively
- +convey the exclusion of warranty; and each file should have at least
- +the "copyright" line and a pointer to where the full notice is found.
- +
- + <one line to give the program's name and a brief idea of what it does.>
- + Copyright (C) 19yy <name of author>
- +
- + This program is free software; you can redistribute it and/or modify
- + it under the terms of the GNU General Public License as published by
- + the Free Software Foundation; either version 2 of the License, or
- + (at your option) any later version.
- +
- + This program is distributed in the hope that it will be useful,
- + but WITHOUT ANY WARRANTY; without even the implied warranty of
- + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + GNU General Public License for more details.
- +
- + You should have received a copy of the GNU General Public License
- + along with this program; if not, write to the Free Software
- + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- +
- +Also add information on how to contact you by electronic and paper mail.
- +
- +If the program is interactive, make it output a short notice like this
- +when it starts in an interactive mode:
- +
- + Gnomovision version 69, Copyright (C) 19yy name of author
- + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- + This is free software, and you are welcome to redistribute it
- + under certain conditions; type `show c' for details.
- +
- +The hypothetical commands `show w' and `show c' should show the appropriate
- +parts of the General Public License. Of course, the commands you use may
- +be called something other than `show w' and `show c'; they could even be
- +mouse-clicks or menu items--whatever suits your program.
- +
- +You should also get your employer (if you work as a programmer) or your
- +school, if any, to sign a "copyright disclaimer" for the program, if
- +necessary. Here is a sample; alter the names:
- +
- + Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- + `Gnomovision' (which makes passes at compilers) written by James Hacker.
- +
- + <signature of Ty Coon>, 1 April 1989
- + Ty Coon, President of Vice
- +
- +This General Public License does not permit incorporating your program into
- +proprietary programs. If your program is a subroutine library, you may
- +consider it more useful to permit linking proprietary applications with the
- +library. If this is what you want to do, use the GNU Library General
- +Public License instead of this License.
- Index: ffdecsa/Makefile
- ===================================================================
- --- ffdecsa/Makefile (revision 0)
- +++ ffdecsa/Makefile (working copy)
- @@ -0,0 +1,2 @@
- +parent:
- + @$(MAKE) --no-print-directory -C ..
- Index: ffdecsa/ffdecsa.c
- ===================================================================
- --- ffdecsa/ffdecsa.c (revision 0)
- +++ ffdecsa/ffdecsa.c (working copy)
- @@ -0,0 +1,926 @@
- +/* FFdecsa -- fast decsa algorithm
- + *
- + * Copyright (C) 2003-2004 fatih89r
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- + */
- +
- +
- +#include <sys/types.h>
- +#include <string.h>
- +#include <stdio.h>
- +#include <stdlib.h>
- +
- +#include "ffdecsa.h"
- +
- +#ifndef NULL
- +#define NULL 0
- +#endif
- +
- +//#define DEBUG
- +#ifdef DEBUG
- +#define DBG(a) a
- +#else
- +#define DBG(a)
- +#endif
- +
- +//// parallelization stuff, large speed differences are possible
- +// possible choices
- +#define PARALLEL_32_4CHAR 320
- +#define PARALLEL_32_4CHARA 321
- +#define PARALLEL_32_INT 322
- +#define PARALLEL_64_8CHAR 640
- +#define PARALLEL_64_8CHARA 641
- +#define PARALLEL_64_2INT 642
- +#define PARALLEL_64_LONG 643
- +#define PARALLEL_64_MMX 644
- +#define PARALLEL_128_16CHAR 1280
- +#define PARALLEL_128_16CHARA 1281
- +#define PARALLEL_128_4INT 1282
- +#define PARALLEL_128_2LONG 1283
- +#define PARALLEL_128_2MMX 1284
- +#define PARALLEL_128_SSE 1285
- +#define PARALLEL_128_SSE2 1286
- +
- +//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice ////////
- +#ifndef PARALLEL_MODE
- +
- +#if defined(__x86_64__) || defined(_M_X64)
- +#define PARALLEL_MODE PARALLEL_128_SSE2
- +
- +#elif defined(__mips__) || defined(__mips) || defined(__MIPS__)
- +#define PARALLEL_MODE PARALLEL_64_LONG
- +
- +#elif defined(__sh__) || defined(__SH4__)
- +#define PARALLEL_MODE PARALLEL_32_INT
- +#define COPY_UNALIGNED_PKT
- +#define MEMALIGN_VAL 4
- +
- +#else
- +#define PARALLEL_MODE PARALLEL_32_INT
- +#endif
- +
- +#endif
- +//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice ////////
- +
- +#include "parallel_generic.h"
- +//// conditionals
- +#if PARALLEL_MODE==PARALLEL_32_4CHAR
- +#include "parallel_032_4char.h"
- +#elif PARALLEL_MODE==PARALLEL_32_4CHARA
- +#include "parallel_032_4charA.h"
- +#elif PARALLEL_MODE==PARALLEL_32_INT
- +#include "parallel_032_int.h"
- +#elif PARALLEL_MODE==PARALLEL_64_8CHAR
- +#include "parallel_064_8char.h"
- +#elif PARALLEL_MODE==PARALLEL_64_8CHARA
- +#include "parallel_064_8charA.h"
- +#elif PARALLEL_MODE==PARALLEL_64_2INT
- +#include "parallel_064_2int.h"
- +#elif PARALLEL_MODE==PARALLEL_64_LONG
- +#include "parallel_064_long.h"
- +#elif PARALLEL_MODE==PARALLEL_64_MMX
- +#include "parallel_064_mmx.h"
- +#elif PARALLEL_MODE==PARALLEL_128_16CHAR
- +#include "parallel_128_16char.h"
- +#elif PARALLEL_MODE==PARALLEL_128_16CHARA
- +#include "parallel_128_16charA.h"
- +#elif PARALLEL_MODE==PARALLEL_128_4INT
- +#include "parallel_128_4int.h"
- +#elif PARALLEL_MODE==PARALLEL_128_2LONG
- +#include "parallel_128_2long.h"
- +#elif PARALLEL_MODE==PARALLEL_128_2MMX
- +#include "parallel_128_2mmx.h"
- +#elif PARALLEL_MODE==PARALLEL_128_SSE
- +#include "parallel_128_sse.h"
- +#elif PARALLEL_MODE==PARALLEL_128_SSE2
- +#include "parallel_128_sse2.h"
- +#else
- +#error "unknown/undefined parallel mode"
- +#endif
- +
- +// stuff depending on conditionals
- +
- +#define BYTES_PER_GROUP (GROUP_PARALLELISM/8)
- +#define BYPG BYTES_PER_GROUP
- +#define BITS_PER_GROUP GROUP_PARALLELISM
- +#define BIPG BITS_PER_GROUP
- +
- +// platform specific
- +
- +#ifdef __arm__
- +#if !defined(MEMALIGN_VAL) || MEMALIGN_VAL<4
- +#undef MEMALIGN_VAL
- +#define MEMALIGN_VAL 4
- +#endif
- +#define COPY_UNALIGNED_PKT
- +#endif
- +
- +//
- +
- +#ifndef MALLOC
- +#define MALLOC(X) malloc(X)
- +#endif
- +#ifndef FREE
- +#define FREE(X) free(X)
- +#endif
- +#ifdef MEMALIGN_VAL
- +#define MEMALIGN __attribute__((aligned(MEMALIGN_VAL)))
- +#else
- +#define MEMALIGN
- +#endif
- +
- +//// debug tool
- +
- +#ifdef DEBUG
- +static void dump_mem(const char *string, const unsigned char *p, int len, int linelen){
- + int i;
- + for(i=0;i<len;i++){
- + if(i%linelen==0&&i) fprintf(stderr,"\n");
- + if(i%linelen==0) fprintf(stderr,"%s %08x:",string,i);
- + else{
- + if(i%8==0) fprintf(stderr," ");
- + if(i%4==0) fprintf(stderr," ");
- + }
- + fprintf(stderr," %02x",p[i]);
- + }
- + if(i%linelen==0) fprintf(stderr,"\n");
- +}
- +#endif
- +
- +//////////////////////////////////////////////////////////////////////////////////
- +
- +struct csa_key_t{
- + unsigned char ck[8];
- +// used by stream
- + int iA[8]; // iA[0] is for A1, iA[7] is for A8
- + int iB[8]; // iB[0] is for B1, iB[7] is for B8
- +// used by stream (group)
- + MEMALIGN group ck_g[8][8]; // [byte][bit:0=LSB,7=MSB]
- + MEMALIGN group iA_g[8][4]; // [0 for A1][0 for LSB]
- + MEMALIGN group iB_g[8][4]; // [0 for B1][0 for LSB]
- +// used by block
- + unsigned char kk[56];
- +// used by block (group)
- + MEMALIGN batch kkmulti[56]; // many times the same byte in every batch
- +};
- +
- +struct csa_keys_t{
- + struct csa_key_t even;
- + struct csa_key_t odd;
- +};
- +
- +//-----stream cypher
- +
- +//-----key schedule for stream decypher
- +static void key_schedule_stream(
- + unsigned char *ck, // [In] ck[0]-ck[7] 8 bytes | Key.
- + int *iA, // [Out] iA[0]-iA[7] 8 nibbles | Key schedule.
- + int *iB) // [Out] iB[0]-iB[7] 8 nibbles | Key schedule.
- +{
- + iA[0]=(ck[0]>>4)&0xf;
- + iA[1]=(ck[0] )&0xf;
- + iA[2]=(ck[1]>>4)&0xf;
- + iA[3]=(ck[1] )&0xf;
- + iA[4]=(ck[2]>>4)&0xf;
- + iA[5]=(ck[2] )&0xf;
- + iA[6]=(ck[3]>>4)&0xf;
- + iA[7]=(ck[3] )&0xf;
- + iB[0]=(ck[4]>>4)&0xf;
- + iB[1]=(ck[4] )&0xf;
- + iB[2]=(ck[5]>>4)&0xf;
- + iB[3]=(ck[5] )&0xf;
- + iB[4]=(ck[6]>>4)&0xf;
- + iB[5]=(ck[6] )&0xf;
- + iB[6]=(ck[7]>>4)&0xf;
- + iB[7]=(ck[7] )&0xf;
- +}
- +
- +//----- stream main function
- +
- +#define STREAM_INIT
- +#include "stream.c"
- +#undef STREAM_INIT
- +
- +#define STREAM_NORMAL
- +#include "stream.c"
- +#undef STREAM_NORMAL
- +
- +
- +//-----block decypher
- +
- +//-----key schedule for block decypher
- +
- +static void key_schedule_block(
- + unsigned char *ck, // [In] ck[0]-ck[7] 8 bytes | Key.
- + unsigned char *kk) // [Out] kk[0]-kk[55] 56 bytes | Key schedule.
- +{
- + static const unsigned char key_perm[0x40] = {
- + 0x12,0x24,0x09,0x07,0x2A,0x31,0x1D,0x15, 0x1C,0x36,0x3E,0x32,0x13,0x21,0x3B,0x40,
- + 0x18,0x14,0x25,0x27,0x02,0x35,0x1B,0x01, 0x22,0x04,0x0D,0x0E,0x39,0x28,0x1A,0x29,
- + 0x33,0x23,0x34,0x0C,0x16,0x30,0x1E,0x3A, 0x2D,0x1F,0x08,0x19,0x17,0x2F,0x3D,0x11,
- + 0x3C,0x05,0x38,0x2B,0x0B,0x06,0x0A,0x2C, 0x20,0x3F,0x2E,0x0F,0x03,0x26,0x10,0x37,
- + };
- +
- + int i,j,k;
- + int bit[64];
- + int newbit[64];
- + int kb[7][8];
- +
- + // 56 steps
- + // 56 key bytes kk(55)..kk(0) by key schedule from ck
- +
- + // kb(6,0) .. kb(6,7) = ck(0) .. ck(7)
- + kb[6][0] = ck[0];
- + kb[6][1] = ck[1];
- + kb[6][2] = ck[2];
- + kb[6][3] = ck[3];
- + kb[6][4] = ck[4];
- + kb[6][5] = ck[5];
- + kb[6][6] = ck[6];
- + kb[6][7] = ck[7];
- +
- + // calculate kb[5] .. kb[0]
- + for(i=5; i>=0; i--){
- + // 64 bit perm on kb
- + for(j=0; j<8; j++){
- + for(k=0; k<8; k++){
- + bit[j*8+k] = (kb[i+1][j] >> (7-k)) & 1;
- + newbit[key_perm[j*8+k]-1] = bit[j*8+k];
- + }
- + }
- + for(j=0; j<8; j++){
- + kb[i][j] = 0;
- + for(k=0; k<8; k++){
- + kb[i][j] |= newbit[j*8+k] << (7-k);
- + }
- + }
- + }
- +
- + // xor to give kk
- + for(i=0; i<7; i++){
- + for(j=0; j<8; j++){
- + kk[i*8+j] = kb[i][j] ^ i;
- + }
- + }
- +
- +}
- +
- +//-----block utils
- +
- +static inline __attribute__((always_inline)) void trasp_N_8 (unsigned char *in,unsigned char* out,int count){
- + int *ri=(int *)in;
- + int *ibi=(int *)out;
- + int j,i,k,g;
- + // copy and first step
- + for(g=0;g<count;g++){
- + ri[g]=ibi[2*g];
- + ri[GROUP_PARALLELISM+g]=ibi[2*g+1];
- + }
- +//dump_mem("NE1 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
- +// now 01230123
- +#define INTS_PER_ROW (GROUP_PARALLELISM/8*2)
- + for(j=0;j<8;j+=4){
- + for(i=0;i<2;i++){
- + for(k=0;k<INTS_PER_ROW;k++){
- + unsigned int t,b;
- + t=ri[INTS_PER_ROW*(j+i)+k];
- + b=ri[INTS_PER_ROW*(j+i+2)+k];
- + ri[INTS_PER_ROW*(j+i)+k]= (t&0x0000ffff) | ((b )<<16);
- + ri[INTS_PER_ROW*(j+i+2)+k]= ((t )>>16) | (b&0xffff0000) ;
- + }
- + }
- + }
- +//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
- +// now 01010101
- + for(j=0;j<8;j+=2){
- + for(i=0;i<1;i++){
- + for(k=0;k<INTS_PER_ROW;k++){
- + unsigned int t,b;
- + t=ri[INTS_PER_ROW*(j+i)+k];
- + b=ri[INTS_PER_ROW*(j+i+1)+k];
- + ri[INTS_PER_ROW*(j+i)+k]= (t&0x00ff00ff) | ((b&0x00ff00ff)<<8);
- + ri[INTS_PER_ROW*(j+i+1)+k]= ((t&0xff00ff00)>>8) | (b&0xff00ff00);
- + }
- + }
- + }
- +//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
- +// now 00000000
- +}
- +
- +static inline __attribute__((always_inline)) void trasp_8_N (unsigned char *in,unsigned char* out,int count){
- + int *ri=(int *)in;
- + int *bdi=(int *)out;
- + int j,i,k,g;
- +#define INTS_PER_ROW (GROUP_PARALLELISM/8*2)
- +//dump_mem("NE1 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
- +// now 00000000
- + for(j=0;j<8;j+=2){
- + for(i=0;i<1;i++){
- + for(k=0;k<INTS_PER_ROW;k++){
- + unsigned int t,b;
- + t=ri[INTS_PER_ROW*(j+i)+k];
- + b=ri[INTS_PER_ROW*(j+i+1)+k];
- + ri[INTS_PER_ROW*(j+i)+k]= (t&0x00ff00ff) | ((b&0x00ff00ff)<<8);
- + ri[INTS_PER_ROW*(j+i+1)+k]= ((t&0xff00ff00)>>8) | (b&0xff00ff00);
- + }
- + }
- + }
- +//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
- +// now 01010101
- + for(j=0;j<8;j+=4){
- + for(i=0;i<2;i++){
- + for(k=0;k<INTS_PER_ROW;k++){
- + unsigned int t,b;
- + t=ri[INTS_PER_ROW*(j+i)+k];
- + b=ri[INTS_PER_ROW*(j+i+2)+k];
- + ri[INTS_PER_ROW*(j+i)+k]= (t&0x0000ffff) | ((b )<<16);
- + ri[INTS_PER_ROW*(j+i+2)+k]= ((t )>>16) | (b&0xffff0000) ;
- + }
- + }
- + }
- +//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
- +// now 01230123
- + for(g=0;g<count;g++){
- + bdi[2*g]=ri[g];
- + bdi[2*g+1]=ri[GROUP_PARALLELISM+g];
- + }
- +}
- +
- +//-----block main function
- +
- +// block group
- +static void block_decypher_group(
- + batch *kkmulti, // [In] kkmulti[0]-kkmulti[55] 56 batches | Key schedule (each batch has repeated equal bytes).
- + unsigned char *ib, // [In] (ib0,ib1,...ib7)...x32 32*8 bytes | Initialization vector.
- + unsigned char *bd, // [Out] (bd0,bd1,...bd7)...x32 32*8 bytes | Block decipher.
- + int count)
- +{
- + // int is faster than unsigned char. apparently not
- + static const unsigned char block_sbox[0x100] = {
- + 0x3A,0xEA,0x68,0xFE,0x33,0xE9,0x88,0x1A, 0x83,0xCF,0xE1,0x7F,0xBA,0xE2,0x38,0x12,
- + 0xE8,0x27,0x61,0x95,0x0C,0x36,0xE5,0x70, 0xA2,0x06,0x82,0x7C,0x17,0xA3,0x26,0x49,
- + 0xBE,0x7A,0x6D,0x47,0xC1,0x51,0x8F,0xF3, 0xCC,0x5B,0x67,0xBD,0xCD,0x18,0x08,0xC9,
- + 0xFF,0x69,0xEF,0x03,0x4E,0x48,0x4A,0x84, 0x3F,0xB4,0x10,0x04,0xDC,0xF5,0x5C,0xC6,
- + 0x16,0xAB,0xAC,0x4C,0xF1,0x6A,0x2F,0x3C, 0x3B,0xD4,0xD5,0x94,0xD0,0xC4,0x63,0x62,
- + 0x71,0xA1,0xF9,0x4F,0x2E,0xAA,0xC5,0x56, 0xE3,0x39,0x93,0xCE,0x65,0x64,0xE4,0x58,
- + 0x6C,0x19,0x42,0x79,0xDD,0xEE,0x96,0xF6, 0x8A,0xEC,0x1E,0x85,0x53,0x45,0xDE,0xBB,
- + 0x7E,0x0A,0x9A,0x13,0x2A,0x9D,0xC2,0x5E, 0x5A,0x1F,0x32,0x35,0x9C,0xA8,0x73,0x30,
- +
- + 0x29,0x3D,0xE7,0x92,0x87,0x1B,0x2B,0x4B, 0xA5,0x57,0x97,0x40,0x15,0xE6,0xBC,0x0E,
- + 0xEB,0xC3,0x34,0x2D,0xB8,0x44,0x25,0xA4, 0x1C,0xC7,0x23,0xED,0x90,0x6E,0x50,0x00,
- + 0x99,0x9E,0x4D,0xD9,0xDA,0x8D,0x6F,0x5F, 0x3E,0xD7,0x21,0x74,0x86,0xDF,0x6B,0x05,
- + 0x8E,0x5D,0x37,0x11,0xD2,0x28,0x75,0xD6, 0xA7,0x77,0x24,0xBF,0xF0,0xB0,0x02,0xB7,
- + 0xF8,0xFC,0x81,0x09,0xB1,0x01,0x76,0x91, 0x7D,0x0F,0xC8,0xA0,0xF2,0xCB,0x78,0x60,
- + 0xD1,0xF7,0xE0,0xB5,0x98,0x22,0xB3,0x20, 0x1D,0xA6,0xDB,0x7B,0x59,0x9F,0xAE,0x31,
- + 0xFB,0xD3,0xB6,0xCA,0x43,0x72,0x07,0xF4, 0xD8,0x41,0x14,0x55,0x0D,0x54,0x8B,0xB9,
- + 0xAD,0x46,0x0B,0xAF,0x80,0x52,0x2C,0xFA, 0x8C,0x89,0x66,0xFD,0xB2,0xA9,0x9B,0xC0,
- + };
- + MEMALIGN unsigned char r[GROUP_PARALLELISM*(8+56)]; /* 56 because we will move back in memory while looping */
- + MEMALIGN unsigned char sbox_in[GROUP_PARALLELISM],sbox_out[GROUP_PARALLELISM],perm_out[GROUP_PARALLELISM];
- + int roff;
- + int i,g,count_all=GROUP_PARALLELISM;
- +
- + roff=GROUP_PARALLELISM*56;
- +
- +#define FASTTRASP1
- +#ifndef FASTTRASP1
- + for(g=0;g<count;g++){
- + // Init registers
- + int j;
- + for(j=0;j<8;j++){
- + r[roff+GROUP_PARALLELISM*j+g]=ib[8*g+j];
- + }
- + }
- +#else
- + trasp_N_8((unsigned char *)&r[roff],(unsigned char *)ib,count);
- +#endif
- +//dump_mem("OLD r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
- +
- + // loop over kk[55]..kk[0]
- + for(i=55;i>=0;i--){
- + {
- + MEMALIGN batch tkkmulti=kkmulti[i];
- + batch *si=(batch *)sbox_in;
- + batch *r6_N=(batch *)(r+roff+GROUP_PARALLELISM*6);
- + for(g=0;g<count_all/BYTES_PER_BATCH;g++){
- + si[g]=B_FFXOR(tkkmulti,r6_N[g]); //FIXME: introduce FASTBATCH?
- + }
- + }
- +
- + // table lookup, this works on only one byte at a time
- + // most difficult part of all
- + // - can't be parallelized
- + // - can't be synthetized through boolean terms (8 input bits are too many)
- + for(g=0;g<count_all;g++){
- + sbox_out[g]=block_sbox[sbox_in[g]];
- + }
- +
- + // bit permutation
- + {
- + unsigned char *po=(unsigned char *)perm_out;
- + unsigned char *so=(unsigned char *)sbox_out;
- +//dump_mem("pre perm ",(unsigned char *)so,GROUP_PARALLELISM,GROUP_PARALLELISM);
- + for(g=0;g<count_all;g+=BYTES_PER_BATCH){
- + MEMALIGN batch in,out;
- + in=*(batch *)&so[g];
- +
- + out=B_FFOR(
- + B_FFOR(
- + B_FFOR(
- + B_FFOR(
- + B_FFOR(
- + B_FFSH8L(B_FFAND(in,B_FFN_ALL_29()),1),
- + B_FFSH8L(B_FFAND(in,B_FFN_ALL_02()),6)),
- + B_FFSH8L(B_FFAND(in,B_FFN_ALL_04()),3)),
- + B_FFSH8R(B_FFAND(in,B_FFN_ALL_10()),2)),
- + B_FFSH8R(B_FFAND(in,B_FFN_ALL_40()),6)),
- + B_FFSH8R(B_FFAND(in,B_FFN_ALL_80()),4));
- +
- + *(batch *)&po[g]=out;
- + }
- +//dump_mem("post perm",(unsigned char *)po,GROUP_PARALLELISM,GROUP_PARALLELISM);
- + }
- +
- + roff-=GROUP_PARALLELISM; /* virtual shift of registers */
- +
- +#if 0
- +/* one by one */
- + for(g=0;g<count_all;g++){
- + r[roff+GROUP_PARALLELISM*0+g]=r[roff+GROUP_PARALLELISM*8+g]^sbox_out[g];
- + r[roff+GROUP_PARALLELISM*6+g]^=perm_out[g];
- + r[roff+GROUP_PARALLELISM*4+g]^=r[roff+GROUP_PARALLELISM*0+g];
- + r[roff+GROUP_PARALLELISM*3+g]^=r[roff+GROUP_PARALLELISM*0+g];
- + r[roff+GROUP_PARALLELISM*2+g]^=r[roff+GROUP_PARALLELISM*0+g];
- + }
- +#else
- + for(g=0;g<count_all;g+=BEST_SPAN){
- + XOR_BEST_BY(&r[roff+GROUP_PARALLELISM*0+g],&r[roff+GROUP_PARALLELISM*8+g],&sbox_out[g]);
- + XOREQ_BEST_BY(&r[roff+GROUP_PARALLELISM*6+g],&perm_out[g]);
- + XOREQ_BEST_BY(&r[roff+GROUP_PARALLELISM*4+g],&r[roff+GROUP_PARALLELISM*0+g]);
- + XOREQ_BEST_BY(&r[roff+GROUP_PARALLELISM*3+g],&r[roff+GROUP_PARALLELISM*0+g]);
- + XOREQ_BEST_BY(&r[roff+GROUP_PARALLELISM*2+g],&r[roff+GROUP_PARALLELISM*0+g]);
- + }
- +#endif
- + }
- +
- +#define FASTTRASP2
- +#ifndef FASTTRASP2
- + for(g=0;g<count;g++){
- + // Copy results
- + int j;
- + for(j=0;j<8;j++){
- + bd[8*g+j]=r[roff+GROUP_PARALLELISM*j+g];
- + }
- + }
- +#else
- + trasp_8_N((unsigned char *)&r[roff],(unsigned char *)bd,count);
- +#endif
- +}
- +
- +//-----------------------------------EXTERNAL INTERFACE
- +
- +//-----get internal parallelism
- +
- +int get_internal_parallelism(void){
- + return GROUP_PARALLELISM;
- +}
- +
- +//-----get suggested cluster size
- +
- +int get_suggested_cluster_size(void){
- + int r;
- + r=GROUP_PARALLELISM+GROUP_PARALLELISM/10;
- + if(r<GROUP_PARALLELISM+5) r=GROUP_PARALLELISM+5;
- + return r;
- +}
- +
- +//-----key structure
- +
- +void *get_key_struct(void){
- + struct csa_keys_t *keys=(struct csa_keys_t *)MALLOC(sizeof(struct csa_keys_t));
- + if(keys) {
- + static const unsigned char pk[8] = { 0,0,0,0,0,0,0,0 };
- + set_control_words(keys,pk,pk);
- + }
- + return keys;
- +}
- +
- +void free_key_struct(void *keys){
- + return FREE(keys);
- +}
- +
- +//-----set control words
- +
- +static void schedule_key(struct csa_key_t *key, const unsigned char *pk){
- + // could be made faster, but is not run often
- + int bi,by;
- + int i,j;
- +// key
- + memcpy(key->ck,pk,8);
- +// precalculations for stream
- + key_schedule_stream(key->ck,key->iA,key->iB);
- + for(by=0;by<8;by++){
- + for(bi=0;bi<8;bi++){
- + key->ck_g[by][bi]=(key->ck[by]&(1<<bi))?FF1():FF0();
- + }
- + }
- + for(by=0;by<8;by++){
- + for(bi=0;bi<4;bi++){
- + key->iA_g[by][bi]=(key->iA[by]&(1<<bi))?FF1():FF0();
- + key->iB_g[by][bi]=(key->iB[by]&(1<<bi))?FF1():FF0();
- + }
- + }
- +// precalculations for block
- + key_schedule_block(key->ck,key->kk);
- + for(i=0;i<56;i++){
- + for(j=0;j<BYTES_PER_BATCH;j++){
- + *(((unsigned char *)&key->kkmulti[i])+j)=key->kk[i];
- + }
- + }
- +}
- +
- +void set_control_words(void *keys, const unsigned char *ev, const unsigned char *od){
- + schedule_key(&((struct csa_keys_t *)keys)->even,ev);
- + schedule_key(&((struct csa_keys_t *)keys)->odd,od);
- +}
- +
- +void set_even_control_word(void *keys, const unsigned char *pk){
- + schedule_key(&((struct csa_keys_t *)keys)->even,pk);
- +}
- +
- +void set_odd_control_word(void *keys, const unsigned char *pk){
- + schedule_key(&((struct csa_keys_t *)keys)->odd,pk);
- +}
- +
- +//-----get control words
- +
- +void get_control_words(void *keys, unsigned char *even, unsigned char *odd){
- + memcpy(even,&((struct csa_keys_t *)keys)->even.ck,8);
- + memcpy(odd,&((struct csa_keys_t *)keys)->odd.ck,8);
- +}
- +
- +//----- decrypt
- +
- +int decrypt_packets(void *keys, unsigned char **cluster){
- + // statistics, currently unused
- + int stat_no_scramble=0;
- + int stat_reserved=0;
- + int stat_decrypted[2]={0,0};
- + int stat_decrypted_mini=0;
- + unsigned char **clst;
- + unsigned char **clst2;
- + int grouped;
- + int group_ev_od;
- + int advanced;
- + int can_advance;
- + unsigned char *g_pkt[GROUP_PARALLELISM];
- + int g_len[GROUP_PARALLELISM];
- + int g_offset[GROUP_PARALLELISM];
- + int g_n[GROUP_PARALLELISM];
- + int g_residue[GROUP_PARALLELISM];
- + unsigned char *pkt;
- + int xc0,ev_od,len,offset,n,residue;
- + struct csa_key_t* k;
- + int i,j,iter,g;
- + int t23,tsmall;
- + int alive[24];
- +//icc craziness int pad1=0; //////////align! FIXME
- + unsigned char *encp[GROUP_PARALLELISM];
- + MEMALIGN unsigned char stream_in[GROUP_PARALLELISM*8];
- + MEMALIGN unsigned char stream_out[GROUP_PARALLELISM*8];
- + MEMALIGN unsigned char ib[GROUP_PARALLELISM*8];
- + MEMALIGN unsigned char block_out[GROUP_PARALLELISM*8];
- +#ifdef COPY_UNALIGNED_PKT
- + unsigned char *unaligned[GROUP_PARALLELISM];
- + MEMALIGN unsigned char alignedBuff[GROUP_PARALLELISM][188];
- +#endif
- + struct stream_regs regs;
- +
- +//icc craziness i=(int)&pad1;//////////align!!! FIXME
- +
- + // build a list of packets to be processed
- + clst=cluster;
- + grouped=0;
- + advanced=0;
- + can_advance=1;
- + group_ev_od=-1; // silence incorrect compiler warning
- + pkt=*clst;
- + do{ // find a new packet
- + if(grouped==GROUP_PARALLELISM){
- + // full
- + break;
- + }
- + if(pkt==NULL){
- + // no more ranges
- + break;
- + }
- + if(pkt>=*(clst+1)){
- + // out of this range, try next
- + clst++;clst++;
- + pkt=*clst;
- + continue;
- + }
- +
- + do{ // handle this packet
- + xc0=pkt[3]&0xc0;
- + DBG(fprintf(stderr," exam pkt=%p, xc0=%02x, can_adv=%i\n",pkt,xc0,can_advance));
- + if(xc0==0x00){
- + DBG(fprintf(stderr,"skip clear pkt %p (can_advance is %i)\n",pkt,can_advance));
- + advanced+=can_advance;
- + stat_no_scramble++;
- + break;
- + }
- + if(xc0==0x40){
- + DBG(fprintf(stderr,"skip reserved pkt %p (can_advance is %i)\n",pkt,can_advance));
- + advanced+=can_advance;
- + stat_reserved++;
- + break;
- + }
- + if(xc0==0x80||xc0==0xc0){ // encrypted
- + ev_od=(xc0&0x40)>>6; // 0 even, 1 odd
- + if(grouped==0) group_ev_od=ev_od; // this group will be all even (or odd)
- + if(group_ev_od==ev_od){ // could be added to group
- + pkt[3]&=0x3f; // consider it decrypted now
- + if(pkt[3]&0x20){ // incomplete packet
- + offset=4+pkt[4]+1;
- + len=188-offset;
- + n=len>>3;
- + residue=len-(n<<3);
- + if(n==0){ // decrypted==encrypted!
- + DBG(fprintf(stderr,"DECRYPTED MINI! (can_advance is %i)\n",can_advance));
- + advanced+=can_advance;
- + stat_decrypted_mini++;
- + break; // this doesn't need more processing
- + }
- + }else{
- + len=184;
- + offset=4;
- + n=23;
- + residue=0;
- + }
- + g_pkt[grouped]=pkt;
- + g_len[grouped]=len;
- + g_offset[grouped]=offset;
- + g_n[grouped]=n;
- + g_residue[grouped]=residue;
- + DBG(fprintf(stderr,"%2i: eo=%i pkt=%p len=%03i n=%2i residue=%i\n",grouped,ev_od,pkt,len,n,residue));
- + grouped++;
- + advanced+=can_advance;
- + stat_decrypted[ev_od]++;
- + }
- + else{
- + can_advance=0;
- + DBG(fprintf(stderr,"skip pkt %p and can_advance set to 0\n",pkt));
- + break; // skip and go on
- + }
- + }
- + } while(0);
- +
- + if(can_advance){
- + // move range start forward
- + *clst+=188;
- + }
- + // next packet, if there is one
- + pkt+=188;
- + } while(1);
- + DBG(fprintf(stderr,"-- result: grouped %i pkts, advanced %i pkts\n",grouped,advanced));
- +
- + // delete empty ranges and compact list
- + clst2=cluster;
- + for(clst=cluster;*clst!=NULL;clst+=2){
- + // if not empty
- + if(*clst<*(clst+1)){
- + // it will remain
- + *clst2=*clst;
- + *(clst2+1)=*(clst+1);
- + clst2+=2;
- + }
- + }
- + *clst2=NULL;
- +
- + if(grouped==0){
- + // no processing needed
- + return advanced;
- + }
- +
- + // sort them, longest payload first
- + // we expect many n=23 packets and a few n<23
- + DBG(fprintf(stderr,"PRESORTING\n"));
- + for(i=0;i<grouped;i++){
- + DBG(fprintf(stderr,"%2i of %2i: pkt=%p len=%03i n=%2i residue=%i\n",i,grouped,g_pkt[i],g_len[i],g_n[i],g_residue[i]));
- + }
- + // grouped is always <= GROUP_PARALLELISM
- +
- +#define g_swap(a,b) \
- + pkt=g_pkt[a]; \
- + g_pkt[a]=g_pkt[b]; \
- + g_pkt[b]=pkt; \
- +\
- + len=g_len[a]; \
- + g_len[a]=g_len[b]; \
- + g_len[b]=len; \
- +\
- + offset=g_offset[a]; \
- + g_offset[a]=g_offset[b]; \
- + g_offset[b]=offset; \
- +\
- + n=g_n[a]; \
- + g_n[a]=g_n[b]; \
- + g_n[b]=n; \
- +\
- + residue=g_residue[a]; \
- + g_residue[a]=g_residue[b]; \
- + g_residue[b]=residue;
- +
- + // step 1: move n=23 packets before small packets
- + t23=0;
- + tsmall=grouped-1;
- + for(;;){
- + for(;t23<grouped;t23++){
- + if(g_n[t23]!=23) break;
- + }
- +DBG(fprintf(stderr,"t23 after for =%i\n",t23));
- +
- + for(;tsmall>=0;tsmall--){
- + if(g_n[tsmall]==23) break;
- + }
- +DBG(fprintf(stderr,"tsmall after for =%i\n",tsmall));
- +
- + if(tsmall-t23<1) break;
- +
- +DBG(fprintf(stderr,"swap t23=%i,tsmall=%i\n",t23,tsmall));
- +
- + g_swap(t23,tsmall);
- +
- + t23++;
- + tsmall--;
- +DBG(fprintf(stderr,"new t23=%i,tsmall=%i\n\n",t23,tsmall));
- + }
- + DBG(fprintf(stderr,"packets with n=23, t23=%i grouped=%i\n",t23,grouped));
- + DBG(fprintf(stderr,"MIDSORTING\n"));
- + for(i=0;i<grouped;i++){
- + DBG(fprintf(stderr,"%2i of %2i: pkt=%p len=%03i n=%2i residue=%i\n",i,grouped,g_pkt[i],g_len[i],g_n[i],g_residue[i]));
- + }
- +
- + // step 2: sort small packets in decreasing order of n (bubble sort is enough)
- + for(i=t23;i<grouped;i++){
- + for(j=i+1;j<grouped;j++){
- + if(g_n[j]>g_n[i]){
- + g_swap(i,j);
- + }
- + }
- + }
- + DBG(fprintf(stderr,"POSTSORTING\n"));
- + for(i=0;i<grouped;i++){
- + DBG(fprintf(stderr,"%2i of %2i: pkt=%p len=%03i n=%2i residue=%i\n",i,grouped,g_pkt[i],g_len[i],g_n[i],g_residue[i]));
- + }
- +
- + // we need to know how many packets need 23 iterations, how many 22...
- + for(i=0;i<=23;i++){
- + alive[i]=0;
- + }
- + // count
- + alive[23-1]=t23;
- + for(i=t23;i<grouped;i++){
- + alive[g_n[i]-1]++;
- + }
- + // integrate
- + for(i=22;i>=0;i--){
- + alive[i]+=alive[i+1];
- + }
- + DBG(fprintf(stderr,"ALIVE\n"));
- + for(i=0;i<=23;i++){
- + DBG(fprintf(stderr,"alive%2i=%i\n",i,alive[i]));
- + }
- +
- + // choose key
- + if(group_ev_od==0){
- + k=&((struct csa_keys_t *)keys)->even;
- + }
- + else{
- + k=&((struct csa_keys_t *)keys)->odd;
- + }
- +
- + //INIT
- +//#define INITIALIZE_UNUSED_INPUT
- +#ifdef INITIALIZE_UNUSED_INPUT
- +// unnecessary zeroing.
- +// without this, we operate on uninitialized memory
- +// when grouped<GROUP_PARALLELISM, but it's not a problem,
- +// as final results will be discarded.
- +// random data makes debugging sessions difficult.
- + for(j=0;j<GROUP_PARALLELISM*8;j++) stream_in[j]=0;
- +DBG(fprintf(stderr,"--- WARNING: you could gain speed by not initializing unused memory ---\n"));
- +#else
- +DBG(fprintf(stderr,"--- WARNING: DEBUGGING IS MORE DIFFICULT WHEN PROCESSING RANDOM DATA CHANGING AT EVERY RUN! ---\n"));
- +#endif
- +
- + for(g=0;g<grouped;g++){
- + encp[g]=g_pkt[g];
- + DBG(fprintf(stderr,"header[%i]=%p (%02x)\n",g,encp[g],*(encp[g])));
- + encp[g]+=g_offset[g]; // skip header
- +#ifdef COPY_UNALIGNED_PKT
- + if(((int)encp[g])&0x03) {
- + memcpy(alignedBuff[g],encp[g],g_len[g]);
- + unaligned[g]=encp[g];
- + encp[g]=alignedBuff[g];
- + }
- + else unaligned[g]=0;
- +#endif
- + FFTABLEIN(stream_in,g,encp[g]);
- + }
- +//dump_mem("stream_in",stream_in,GROUP_PARALLELISM*8,BYPG);
- +
- +
- + // ITER 0
- +DBG(fprintf(stderr,">>>>>ITER 0\n"));
- + iter=0;
- + stream_cypher_group_init(®s,k->iA_g,k->iB_g,stream_in);
- + // fill first ib
- + for(g=0;g<alive[iter];g++){
- + COPY_8_BY(ib+8*g,encp[g]);
- + }
- +DBG(dump_mem("IB ",ib,8*alive[iter],8));
- + // ITER 1..N-1
- + for (iter=1;iter<23&&alive[iter-1]>0;iter++){
- +DBG(fprintf(stderr,">>>>>ITER %i\n",iter));
- + // alive and just dead packets: calc block
- + block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]);
- +DBG(dump_mem("BLO_ib ",block_out,8*alive[iter-1],8));
- + // all packets (dead too): calc stream
- + stream_cypher_group_normal(®s,stream_out);
- +//dump_mem("stream_out",stream_out,GROUP_PARALLELISM*8,BYPG);
- +
- + // alive packets: calc ib
- + for(g=0;g<alive[iter];g++){
- + FFTABLEOUT(ib+8*g,stream_out,g);
- +DBG(dump_mem("stream_out_ib ",ib+8*g,8,8));
- +// XOREQ8BY gcc bug? 2x4 ok, 8 ko UPDATE: result ok but speed 1-2% slower (!!!???)
- +#if 1
- + XOREQ_4_BY(ib+8*g,encp[g]+8);
- + XOREQ_4_BY(ib+8*g+4,encp[g]+8+4);
- +#else
- + XOREQ_8_BY(ib+8*g,encp[g]+8);
- +#endif
- +DBG(dump_mem("after_stream_xor_ib ",ib+8*g,8,8));
- + }
- + // alive packets: decrypt data
- + for(g=0;g<alive[iter];g++){
- +DBG(dump_mem("before_ib_decrypt_data ",encp[g],8,8));
- + XOR_8_BY(encp[g],ib+8*g,block_out+8*g);
- +DBG(dump_mem("after_ib_decrypt_data ",encp[g],8,8));
- + }
- + // just dead packets: write decrypted data
- + for(g=alive[iter];g<alive[iter-1];g++){
- +DBG(dump_mem("jd_before_ib_decrypt_data ",encp[g],8,8));
- + COPY_8_BY(encp[g],block_out+8*g);
- +DBG(dump_mem("jd_after_ib_decrypt_data ",encp[g],8,8));
- + }
- + // just dead packets: decrypt residue
- + for(g=alive[iter];g<alive[iter-1];g++){
- +DBG(dump_mem("jd_before_decrypt_residue ",encp[g]+8,g_residue[g],g_residue[g]));
- + FFTABLEOUTXORNBY(g_residue[g],encp[g]+8,stream_out,g);
- +DBG(dump_mem("jd_after_decrypt_residue ",encp[g]+8,g_residue[g],g_residue[g]));
- + }
- + // alive packets: pointers++
- + for(g=0;g<alive[iter];g++) encp[g]+=8;
- + };
- + // ITER N
- +DBG(fprintf(stderr,">>>>>ITER 23\n"));
- + iter=23;
- + // calc block
- + block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]);
- +DBG(dump_mem("23BLO_ib ",block_out,8*alive[iter-1],8));
- + // just dead packets: write decrypted data
- + for(g=alive[iter];g<alive[iter-1];g++){
- +DBG(dump_mem("23jd_before_ib_decrypt_data ",encp[g],8,8));
- + COPY_8_BY(encp[g],block_out+8*g);
- +DBG(dump_mem("23jd_after_ib_decrypt_data ",encp[g],8,8));
- + }
- + // no residue possible
- + // so do nothing
- +
- + DBG(fprintf(stderr,"returning advanced=%i\n",advanced));
- +
- +#ifdef COPY_UNALIGNED_PKT
- + for(g=0;g<grouped;g++)
- + if(unaligned[g]) memcpy(unaligned[g],alignedBuff[g],g_len[g]);
- +#endif
- +
- + M_EMPTY(); // restore CPU multimedia state
- +
- + return advanced;
- +}
- Index: ffdecsa/ffdecsa.h
- ===================================================================
- --- ffdecsa/ffdecsa.h (revision 0)
- +++ ffdecsa/ffdecsa.h (working copy)
- @@ -0,0 +1,62 @@
- +/* FFdecsa -- fast decsa algorithm
- + *
- + * Copyright (C) 2003-2004 fatih89r
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- + */
- +
- +
- +#ifndef FFDECSA_H
- +#define FFDECSA_H
- +
- +//----- public interface
- +
- +// -- how many packets can be decrypted at the same time
- +// This is an info about internal decryption parallelism.
- +// You should try to call decrypt_packets with more packets than the number
- +// returned here for performance reasons (use get_suggested_cluster_size to know
- +// how many).
- +int get_internal_parallelism(void);
- +
- +// -- how many packets you should have in a cluster when calling decrypt_packets
- +// This is a suggestion to achieve optimal performance; typically a little
- +// higher than what get_internal_parallelism returns.
- +// Passing less packets could slow down the decryption.
- +// Passing more packets is never bad (if you don't spend a lot of time building
- +// the list).
- +int get_suggested_cluster_size(void);
- +
- +// -- alloc & free the key structure
- +void *get_key_struct(void);
- +void free_key_struct(void *keys);
- +
- +// -- set control words, 8 bytes each
- +void set_control_words(void *keys, const unsigned char *even, const unsigned char *odd);
- +
- +// -- set even control word, 8 bytes
- +void set_even_control_word(void *keys, const unsigned char *even);
- +
- +// -- set odd control word, 8 bytes
- +void set_odd_control_word(void *keys, const unsigned char *odd);
- +
- +// -- get control words, 8 bytes each
- +//void get_control_words(void *keys, unsigned char *even, unsigned char *odd);
- +
- +// -- decrypt many TS packets
- +// This interface is a bit complicated because it is designed for maximum speed.
- +// Please read doc/how_to_use.txt.
- +int decrypt_packets(void *keys, unsigned char **cluster);
- +
- +#endif
- Index: ffdecsa/fftable.h
- ===================================================================
- --- ffdecsa/fftable.h (revision 0)
- +++ ffdecsa/fftable.h (working copy)
- @@ -0,0 +1,56 @@
- +/* FFdecsa -- fast decsa algorithm
- + *
- + * Copyright (C) 2007 Dark Avenger
- + * 2003-2004 fatih89r
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- + */
- +
- +#ifndef FFTABLE_H
- +#define FFTABLE_H
- +
- +inline static void FFTABLEIN(unsigned char *tab, int g, unsigned char *data)
- +{
- +#if 0
- + *(((int *)tab)+2*g)=*((int *)data);
- + *(((int *)tab)+2*g+1)=*(((int *)data)+1);
- +#else
- + *(((long long *)tab)+g)=*((long long *)data);
- +#endif
- +}
- +
- +inline static void FFTABLEOUT(unsigned char *data, unsigned char *tab, int g)
- +{
- +#if 1
- + *((int *)data)=*(((int *)tab)+2*g);
- + *(((int *)data)+1)=*(((int *)tab)+2*g+1);
- +#else
- + *((long long *)data)=*(((long long *)tab)+g);
- +#endif
- +}
- +
- +inline static void FFTABLEOUTXORNBY(int n, unsigned char *data, unsigned char *tab, int g)
- +{
- + int j;
- + for(j=0;j<n;j++) *(data+j)^=*(tab+8*g+j);
- +}
- +
- +#undef XOREQ_BEST_BY
- +inline static void XOREQ_BEST_BY(unsigned char *d, unsigned char *s)
- +{
- + XOR_BEST_BY(d, d, s);
- +}
- +
- +#endif //FFTABLE_H
- Index: ffdecsa/parallel_032_int.h
- ===================================================================
- --- ffdecsa/parallel_032_int.h (revision 0)
- +++ ffdecsa/parallel_032_int.h (working copy)
- @@ -0,0 +1,55 @@
- +/* FFdecsa -- fast decsa algorithm
- + *
- + * Copyright (C) 2003-2004 fatih89r
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- + */
- +
- +#include "parallel_std_def.h"
- +
- +typedef unsigned int group;
- +#define GROUP_PARALLELISM 32
- +#define FF0() 0x0
- +#define FF1() 0xffffffff
- +
- +/* 64 rows of 32 bits */
- +
- +inline static void FFTABLEIN(unsigned char *tab, int g, unsigned char *data){
- + *(((int *)tab)+g)=*((int *)data);
- + *(((int *)tab)+32+g)=*(((int *)data)+1);
- +}
- +
- +inline static void FFTABLEOUT(unsigned char *data, unsigned char *tab, int g){
- + *((int *)data)=*(((int *)tab)+g);
- + *(((int *)data)+1)=*(((int *)tab)+32+g);
- +}
- +
- +inline static void FFTABLEOUTXORNBY(int n, unsigned char *data, unsigned char *tab, int g){
- + int j;
- + for(j=0;j<n;j++){
- + *(data+j)^=*(tab+4*(g+(j>=4?32-1:0))+j);
- + }
- +}
- +
- +typedef unsigned int batch;
- +#define BYTES_PER_BATCH 4
- +#define B_FFN_ALL_29() 0x29292929
- +#define B_FFN_ALL_02() 0x02020202
- +#define B_FFN_ALL_04() 0x04040404
- +#define B_FFN_ALL_10() 0x10101010
- +#define B_FFN_ALL_40() 0x40404040
- +#define B_FFN_ALL_80() 0x80808080
- +
- +#define M_EMPTY()
- Index: ffdecsa/parallel_064_long.h
- ===================================================================
- --- ffdecsa/parallel_064_long.h (revision 0)
- +++ ffdecsa/parallel_064_long.h (working copy)
- @@ -0,0 +1,39 @@
- +/* FFdecsa -- fast decsa algorithm
- + *
- + * Copyright (C) 2007 Dark Avenger
- + * 2003-2004 fatih89r
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- + */
- +
- +#include "parallel_std_def.h"
- +
- +typedef unsigned long long group;
- +#define GROUP_PARALLELISM 64
- +#define FF0() 0x0ULL
- +#define FF1() 0xffffffffffffffffULL
- +
- +typedef unsigned long long batch;
- +#define BYTES_PER_BATCH 8
- +#define B_FFN_ALL_29() 0x2929292929292929ULL
- +#define B_FFN_ALL_02() 0x0202020202020202ULL
- +#define B_FFN_ALL_04() 0x0404040404040404ULL
- +#define B_FFN_ALL_10() 0x1010101010101010ULL
- +#define B_FFN_ALL_40() 0x4040404040404040ULL
- +#define B_FFN_ALL_80() 0x8080808080808080ULL
- +
- +#define M_EMPTY()
- +
- +#include "fftable.h"
- Index: ffdecsa/parallel_128_sse2.h
- ===================================================================
- --- ffdecsa/parallel_128_sse2.h (revision 0)
- +++ ffdecsa/parallel_128_sse2.h (working copy)
- @@ -0,0 +1,82 @@
- +/* FFdecsa -- fast decsa algorithm
- + *
- + * Copyright (C) 2007 Dark Avenger
- + * 2003-2004 fatih89r
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- + */
- +
- +#include <emmintrin.h>
- +
- +#define MEMALIGN_VAL 16
- +
- +union __u128i {
- + unsigned int u[4];
- + __m128i v;
- +};
- +
- +static const union __u128i ff0 = {{0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}};
- +static const union __u128i ff1 = {{0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU}};
- +
- +typedef __m128i group;
- +#define GROUP_PARALLELISM 128
- +#define FF0() ff0.v
- +#define FF1() ff1.v
- +#define FFAND(a,b) _mm_and_si128((a),(b))
- +#define FFOR(a,b) _mm_or_si128((a),(b))
- +#define FFXOR(a,b) _mm_xor_si128((a),(b))
- +#define FFNOT(a) _mm_xor_si128((a),FF1())
- +#define MALLOC(X) _mm_malloc(X,16)
- +#define FREE(X) _mm_free(X)
- +
- +/* BATCH */
- +
- +static const union __u128i ff29 = {{0x29292929U, 0x29292929U, 0x29292929U, 0x29292929U}};
- +static const union __u128i ff02 = {{0x02020202U, 0x02020202U, 0x02020202U, 0x02020202U}};
- +static const union __u128i ff04 = {{0x04040404U, 0x04040404U, 0x04040404U, 0x04040404U}};
- +static const union __u128i ff10 = {{0x10101010U, 0x10101010U, 0x10101010U, 0x10101010U}};
- +static const union __u128i ff40 = {{0x40404040U, 0x40404040U, 0x40404040U, 0x40404040U}};
- +static const union __u128i ff80 = {{0x80808080U, 0x80808080U, 0x80808080U, 0x80808080U}};
- +
- +typedef __m128i batch;
- +#define BYTES_PER_BATCH 16
- +#define B_FFN_ALL_29() ff29.v
- +#define B_FFN_ALL_02() ff02.v
- +#define B_FFN_ALL_04() ff04.v
- +#define B_FFN_ALL_10() ff10.v
- +#define B_FFN_ALL_40() ff40.v
- +#define B_FFN_ALL_80() ff80.v
- +
- +#define B_FFAND(a,b) FFAND(a,b)
- +#define B_FFOR(a,b) FFOR(a,b)
- +#define B_FFXOR(a,b) FFXOR(a,b)
- +#define B_FFSH8L(a,n) _mm_slli_epi64((a),(n))
- +#define B_FFSH8R(a,n) _mm_srli_epi64((a),(n))
- +
- +#define M_EMPTY()
- +
- +#undef BEST_SPAN
- +#define BEST_SPAN 16
- +
- +#undef XOR_BEST_BY
- +inline static void XOR_BEST_BY(unsigned char *d, unsigned char *s1, unsigned char *s2)
- +{
- + __m128i vs1 = _mm_load_si128((__m128i*)s1);
- + __m128i vs2 = _mm_load_si128((__m128i*)s2);
- + vs1 = _mm_xor_si128(vs1, vs2);
- + _mm_store_si128((__m128i*)d, vs1);
- +}
- +
- +#include "fftable.h"
- Index: ffdecsa/parallel_generic.h
- ===================================================================
- --- ffdecsa/parallel_generic.h (revision 0)
- +++ ffdecsa/parallel_generic.h (working copy)
- @@ -0,0 +1,102 @@
- +/* FFdecsa -- fast decsa algorithm
- + *
- + * Copyright (C) 2003-2004 fatih89r
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- + */
- +
- +
- +
- +#if 0
- +//// generics
- +#define COPY4BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \
- + *pd = *ps; }while(0)
- +#define COPY8BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \
- + *pd = *ps; }while(0)
- +#define COPY16BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \
- + *pd = *ps; \
- + *(pd+1) = *(ps+1); }while(0)
- +#define COPY32BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \
- + *pd = *ps; \
- + *(pd+1) = *(ps+1) \
- + *(pd+2) = *(ps+2) \
- + *(pd+3) = *(ps+3); }while(0)
- +#define XOR4BY(d,s1,s2) do{ int *pd=(int *)(d), *ps1=(int *)(s1), *ps2=(int *)(s2); \
- + *pd = *ps1 ^ *ps2; }while(0)
- +#define XOR8BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \
- + *pd = *ps1 ^ *ps2; }while(0)
- +#define XOR16BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \
- + *pd = *ps1 ^ *ps2; \
- + *(pd+8) = *(ps1+8) ^ *(ps2+8); }while(0)
- +#define XOR32BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \
- + *pd = *ps1 ^ *ps2; \
- + *(pd+1) = *(ps1+1) ^ *(ps2+1); \
- + *(pd+2) = *(ps1+2) ^ *(ps2+2); \
- + *(pd+3) = *(ps1+3) ^ *(ps2+3); }while(0)
- +#define XOR32BV(d,s1,s2) do{ int *const pd=(int *const)(d), *ps1=(const int *const)(s1), *ps2=(const int *const)(s2); \
- + int z; \
- + for(z=0;z<8;z++){ \
- + pd[z]=ps1[z]^ps2[z]; \
- + } \
- + }while(0)
- +#define XOREQ4BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \
- + *pd ^= *ps; }while(0)
- +#define XOREQ8BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \
- + *pd ^= *ps; }while(0)
- +#define XOREQ16BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \
- + *pd ^= *ps; \
- + *(pd+1) ^=*(ps+1); }while(0)
- +#define XOREQ32BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \
- + *pd ^= *ps; \
- + *(pd+1) ^=*(ps+1); \
- + *(pd+2) ^=*(ps+2); \
- + *(pd+3) ^=*(ps+3); }while(0)
- +#define XOREQ32BY4(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \
- + *pd ^= *ps; \
- + *(pd+1) ^=*(ps+1); \
- + *(pd+2) ^=*(ps+2); \
- + *(pd+3) ^=*(ps+3); \
- + *(pd+4) ^=*(ps+4); \
- + *(pd+5) ^=*(ps+5); \
- + *(pd+6) ^=*(ps+6); \
- + *(pd+7) ^=*(ps+7); }while(0)
- +#define XOREQ32BV(d,s) do{ unsigned char *pd=(unsigned char *)(d), *ps=(unsigned char *)(s); \
- + int z; \
- + for(z=0;z<32;z++){ \
- + pd[z]^=ps[z]; \
- + } \
- + }while(0)
- +
- +#else
- +#define XOR_4_BY(d,s1,s2) do{ int *pd=(int *)(d), *ps1=(int *)(s1), *ps2=(int *)(s2); \
- + *pd = *ps1 ^ *ps2; }while(0)
- +#define XOR_8_BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \
- + *pd = *ps1 ^ *ps2; }while(0)
- +#define XOREQ_4_BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \
- + *pd ^= *ps; }while(0)
- +#define XOREQ_8_BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \
- + *pd ^= *ps; }while(0)
- +#define COPY_4_BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \
- + *pd = *ps; }while(0)
- +#define COPY_8_BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \
- + *pd = *ps; }while(0)
- +
- +#define BEST_SPAN 8
- +#define XOR_BEST_BY(d,s1,s2) do{ XOR_8_BY(d,s1,s2); }while(0);
- +#define XOREQ_BEST_BY(d,s) do{ XOREQ_8_BY(d,s); }while(0);
- +#define COPY_BEST_BY(d,s) do{ COPY_8_BY(d,s); }while(0);
- +
- +#define END_MM do{ }while(0);
- +#endif
- Index: ffdecsa/parallel_std_def.h
- ===================================================================
- --- ffdecsa/parallel_std_def.h (revision 0)
- +++ ffdecsa/parallel_std_def.h (working copy)
- @@ -0,0 +1,29 @@
- +/* FFdecsa -- fast decsa algorithm
- + *
- + * Copyright (C) 2003-2004 fatih89r
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- + */
- +
- +#define FFXOR(a,b) ((a)^(b))
- +#define FFAND(a,b) ((a)&(b))
- +#define FFOR(a,b) ((a)|(b))
- +#define FFNOT(a) (~(a))
- +
- +#define B_FFAND(a,b) ((a)&(b))
- +#define B_FFOR(a,b) ((a)|(b))
- +#define B_FFXOR(a,b) ((a)^(b))
- +#define B_FFSH8L(a,n) ((a)<<(n))
- +#define B_FFSH8R(a,n) ((a)>>(n))
- Index: ffdecsa/stream.c
- ===================================================================
- --- ffdecsa/stream.c (revision 0)
- +++ ffdecsa/stream.c (working copy)
- @@ -0,0 +1,906 @@
- +/* FFdecsa -- fast decsa algorithm
- + *
- + * Copyright (C) 2003-2004 fatih89r
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- + */
- +
- +
- +
- +// define statics only once, when STREAM_INIT
- +#ifdef STREAM_INIT
- +struct stream_regs {
- + group A[32+10][4]; // 32 because we will move back (virtual shift register)
- + group B[32+10][4]; // 32 because we will move back (virtual shift register)
- + group X[4];
- + group Y[4];
- + group Z[4];
- + group D[4];
- + group E[4];
- + group F[4];
- + group p;
- + group q;
- + group r;
- + };
- +
- +static inline void trasp64_32_88ccw(unsigned char *data){
- +/* 64 rows of 32 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/
- +#define row ((unsigned int *)data)
- + int i,j;
- + for(j=0;j<64;j+=32){
- + unsigned int t,b;
- + for(i=0;i<16;i++){
- + t=row[j+i];
- + b=row[j+16+i];
- + row[j+i] = (t&0x0000ffff) | ((b )<<16);
- + row[j+16+i]=((t )>>16) | (b&0xffff0000) ;
- + }
- + }
- + for(j=0;j<64;j+=16){
- + unsigned int t,b;
- + for(i=0;i<8;i++){
- + t=row[j+i];
- + b=row[j+8+i];
- + row[j+i] = (t&0x00ff00ff) | ((b&0x00ff00ff)<<8);
- + row[j+8+i] =((t&0xff00ff00)>>8) | (b&0xff00ff00);
- + }
- + }
- + for(j=0;j<64;j+=8){
- + unsigned int t,b;
- + for(i=0;i<4;i++){
- + t=row[j+i];
- + b=row[j+4+i];
- + row[j+i] =((t&0x0f0f0f0f)<<4) | (b&0x0f0f0f0f);
- + row[j+4+i] = (t&0xf0f0f0f0) | ((b&0xf0f0f0f0)>>4);
- + }
- + }
- + for(j=0;j<64;j+=4){
- + unsigned int t,b;
- + for(i=0;i<2;i++){
- + t=row[j+i];
- + b=row[j+2+i];
- + row[j+i] =((t&0x33333333)<<2) | (b&0x33333333);
- + row[j+2+i] = (t&0xcccccccc) | ((b&0xcccccccc)>>2);
- + }
- + }
- + for(j=0;j<64;j+=2){
- + unsigned int t,b;
- + for(i=0;i<1;i++){
- + t=row[j+i];
- + b=row[j+1+i];
- + row[j+i] =((t&0x55555555)<<1) | (b&0x55555555);
- + row[j+1+i] = (t&0xaaaaaaaa) | ((b&0xaaaaaaaa)>>1);
- + }
- + }
- +#undef row
- +}
- +
- +static inline void trasp64_32_88cw(unsigned char *data){
- +/* 64 rows of 32 bits transposition (bytes transp. - 8x8 rotate clockwise)*/
- +#define row ((unsigned int *)data)
- + int i,j;
- + for(j=0;j<64;j+=32){
- + unsigned int t,b;
- + for(i=0;i<16;i++){
- + t=row[j+i];
- + b=row[j+16+i];
- + row[j+i] = (t&0x0000ffff) | ((b )<<16);
- + row[j+16+i]=((t )>>16) | (b&0xffff0000) ;
- + }
- + }
- + for(j=0;j<64;j+=16){
- + unsigned int t,b;
- + for(i=0;i<8;i++){
- + t=row[j+i];
- + b=row[j+8+i];
- + row[j+i] = (t&0x00ff00ff) | ((b&0x00ff00ff)<<8);
- + row[j+8+i] =((t&0xff00ff00)>>8) | (b&0xff00ff00);
- + }
- + }
- + for(j=0;j<64;j+=8){
- + unsigned int t,b;
- + for(i=0;i<4;i++){
- + t=row[j+i];
- + b=row[j+4+i];
- + row[j+i] =((t&0xf0f0f0f0)>>4) | (b&0xf0f0f0f0);
- + row[j+4+i]= (t&0x0f0f0f0f) | ((b&0x0f0f0f0f)<<4);
- + }
- + }
- + for(j=0;j<64;j+=4){
- + unsigned int t,b;
- + for(i=0;i<2;i++){
- + t=row[j+i];
- + b=row[j+2+i];
- + row[j+i] =((t&0xcccccccc)>>2) | (b&0xcccccccc);
- + row[j+2+i]= (t&0x33333333) | ((b&0x33333333)<<2);
- + }
- + }
- + for(j=0;j<64;j+=2){
- + unsigned int t,b;
- + for(i=0;i<1;i++){
- + t=row[j+i];
- + b=row[j+1+i];
- + row[j+i] =((t&0xaaaaaaaa)>>1) | (b&0xaaaaaaaa);
- + row[j+1+i]= (t&0x55555555) | ((b&0x55555555)<<1);
- + }
- + }
- +#undef row
- +}
- +
- +//64-64----------------------------------------------------------
- +static inline void trasp64_64_88ccw(unsigned char *data){
- +/* 64 rows of 64 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/
- +#define row ((unsigned long long int *)data)
- + int i,j;
- + for(j=0;j<64;j+=64){
- + unsigned long long int t,b;
- + for(i=0;i<32;i++){
- + t=row[j+i];
- + b=row[j+32+i];
- + row[j+i] = (t&0x00000000ffffffffULL) | ((b )<<32);
- + row[j+32+i]=((t )>>32) | (b&0xffffffff00000000ULL) ;
- + }
- + }
- + for(j=0;j<64;j+=32){
- + unsigned long long int t,b;
- + for(i=0;i<16;i++){
- + t=row[j+i];
- + b=row[j+16+i];
- + row[j+i] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16);
- + row[j+16+i]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ;
- + }
- + }
- + for(j=0;j<64;j+=16){
- + unsigned long long int t,b;
- + for(i=0;i<8;i++){
- + t=row[j+i];
- + b=row[j+8+i];
- + row[j+i] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8);
- + row[j+8+i] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL);
- + }
- + }
- + for(j=0;j<64;j+=8){
- + unsigned long long int t,b;
- + for(i=0;i<4;i++){
- + t=row[j+i];
- + b=row[j+4+i];
- + row[j+i] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL);
- + row[j+4+i] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4);
- + }
- + }
- + for(j=0;j<64;j+=4){
- + unsigned long long int t,b;
- + for(i=0;i<2;i++){
- + t=row[j+i];
- + b=row[j+2+i];
- + row[j+i] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL);
- + row[j+2+i] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2);
- + }
- + }
- + for(j=0;j<64;j+=2){
- + unsigned long long int t,b;
- + for(i=0;i<1;i++){
- + t=row[j+i];
- + b=row[j+1+i];
- + row[j+i] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL);
- + row[j+1+i] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1);
- + }
- + }
- +#undef row
- +}
- +
- +static inline void trasp64_64_88cw(unsigned char *data){
- +/* 64 rows of 64 bits transposition (bytes transp. - 8x8 rotate clockwise)*/
- +#define row ((unsigned long long int *)data)
- + int i,j;
- + for(j=0;j<64;j+=64){
- + unsigned long long int t,b;
- + for(i=0;i<32;i++){
- + t=row[j+i];
- + b=row[j+32+i];
- + row[j+i] = (t&0x00000000ffffffffULL) | ((b )<<32);
- + row[j+32+i]=((t )>>32) | (b&0xffffffff00000000ULL) ;
- + }
- + }
- + for(j=0;j<64;j+=32){
- + unsigned long long int t,b;
- + for(i=0;i<16;i++){
- + t=row[j+i];
- + b=row[j+16+i];
- + row[j+i] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16);
- + row[j+16+i]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ;
- + }
- + }
- + for(j=0;j<64;j+=16){
- + unsigned long long int t,b;
- + for(i=0;i<8;i++){
- + t=row[j+i];
- + b=row[j+8+i];
- + row[j+i] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8);
- + row[j+8+i] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL);
- + }
- + }
- + for(j=0;j<64;j+=8){
- + unsigned long long int t,b;
- + for(i=0;i<4;i++){
- + t=row[j+i];
- + b=row[j+4+i];
- + row[j+i] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL);
- + row[j+4+i] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4);
- + }
- + }
- + for(j=0;j<64;j+=4){
- + unsigned long long int t,b;
- + for(i=0;i<2;i++){
- + t=row[j+i];
- + b=row[j+2+i];
- + row[j+i] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL);
- + row[j+2+i] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2);
- + }
- + }
- + for(j=0;j<64;j+=2){
- + unsigned long long int t,b;
- + for(i=0;i<1;i++){
- + t=row[j+i];
- + b=row[j+1+i];
- + row[j+i] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL);
- + row[j+1+i] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1);
- + }
- + }
- +#undef row
- +}
- +
- +//64-128----------------------------------------------------------
- +static inline void trasp64_128_88ccw(unsigned char *data){
- +/* 64 rows of 128 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/
- +#define halfrow ((unsigned long long int *)data)
- + int i,j;
- + for(j=0;j<64;j+=64){
- + unsigned long long int t,b;
- + for(i=0;i<32;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+32+i)];
- + halfrow[2*(j+i)] = (t&0x00000000ffffffffULL) | ((b )<<32);
- + halfrow[2*(j+32+i)]=((t )>>32) | (b&0xffffffff00000000ULL) ;
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+32+i)+1];
- + halfrow[2*(j+i)+1] = (t&0x00000000ffffffffULL) | ((b )<<32);
- + halfrow[2*(j+32+i)+1]=((t )>>32) | (b&0xffffffff00000000ULL) ;
- + }
- + }
- + for(j=0;j<64;j+=32){
- + unsigned long long int t,b;
- + for(i=0;i<16;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+16+i)];
- + halfrow[2*(j+i)] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16);
- + halfrow[2*(j+16+i)]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ;
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+16+i)+1];
- + halfrow[2*(j+i)+1] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16);
- + halfrow[2*(j+16+i)+1]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ;
- + }
- + }
- + for(j=0;j<64;j+=16){
- + unsigned long long int t,b;
- + for(i=0;i<8;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+8+i)];
- + halfrow[2*(j+i)] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8);
- + halfrow[2*(j+8+i)] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL);
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+8+i)+1];
- + halfrow[2*(j+i)+1] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8);
- + halfrow[2*(j+8+i)+1] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL);
- + }
- + }
- + for(j=0;j<64;j+=8){
- + unsigned long long int t,b;
- + for(i=0;i<4;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+4+i)];
- + halfrow[2*(j+i)] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL);
- + halfrow[2*(j+4+i)] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4);
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+4+i)+1];
- + halfrow[2*(j+i)+1] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL);
- + halfrow[2*(j+4+i)+1] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4);
- + }
- + }
- + for(j=0;j<64;j+=4){
- + unsigned long long int t,b;
- + for(i=0;i<2;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+2+i)];
- + halfrow[2*(j+i)] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL);
- + halfrow[2*(j+2+i)] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2);
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+2+i)+1];
- + halfrow[2*(j+i)+1] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL);
- + halfrow[2*(j+2+i)+1] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2);
- + }
- + }
- + for(j=0;j<64;j+=2){
- + unsigned long long int t,b;
- + for(i=0;i<1;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+1+i)];
- + halfrow[2*(j+i)] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL);
- + halfrow[2*(j+1+i)] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1);
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+1+i)+1];
- + halfrow[2*(j+i)+1] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL);
- + halfrow[2*(j+1+i)+1] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1);
- + }
- + }
- +#undef halfrow
- +}
- +
- +static inline void trasp64_128_88cw(unsigned char *data){
- +/* 64 rows of 128 bits transposition (bytes transp. - 8x8 rotate clockwise)*/
- +#define halfrow ((unsigned long long int *)data)
- + int i,j;
- + for(j=0;j<64;j+=64){
- + unsigned long long int t,b;
- + for(i=0;i<32;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+32+i)];
- + halfrow[2*(j+i)] = (t&0x00000000ffffffffULL) | ((b )<<32);
- + halfrow[2*(j+32+i)]=((t )>>32) | (b&0xffffffff00000000ULL) ;
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+32+i)+1];
- + halfrow[2*(j+i)+1] = (t&0x00000000ffffffffULL) | ((b )<<32);
- + halfrow[2*(j+32+i)+1]=((t )>>32) | (b&0xffffffff00000000ULL) ;
- + }
- + }
- + for(j=0;j<64;j+=32){
- + unsigned long long int t,b;
- + for(i=0;i<16;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+16+i)];
- + halfrow[2*(j+i)] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16);
- + halfrow[2*(j+16+i)]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ;
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+16+i)+1];
- + halfrow[2*(j+i)+1] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16);
- + halfrow[2*(j+16+i)+1]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ;
- + }
- + }
- + for(j=0;j<64;j+=16){
- + unsigned long long int t,b;
- + for(i=0;i<8;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+8+i)];
- + halfrow[2*(j+i)] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8);
- + halfrow[2*(j+8+i)] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL);
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+8+i)+1];
- + halfrow[2*(j+i)+1] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8);
- + halfrow[2*(j+8+i)+1] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL);
- + }
- + }
- + for(j=0;j<64;j+=8){
- + unsigned long long int t,b;
- + for(i=0;i<4;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+4+i)];
- + halfrow[2*(j+i)] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL);
- + halfrow[2*(j+4+i)] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4);
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+4+i)+1];
- + halfrow[2*(j+i)+1] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL);
- + halfrow[2*(j+4+i)+1] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4);
- + }
- + }
- + for(j=0;j<64;j+=4){
- + unsigned long long int t,b;
- + for(i=0;i<2;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+2+i)];
- + halfrow[2*(j+i)] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL);
- + halfrow[2*(j+2+i)] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2);
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+2+i)+1];
- + halfrow[2*(j+i)+1] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL);
- + halfrow[2*(j+2+i)+1] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2);
- + }
- + }
- + for(j=0;j<64;j+=2){
- + unsigned long long int t,b;
- + for(i=0;i<1;i++){
- + t=halfrow[2*(j+i)];
- + b=halfrow[2*(j+1+i)];
- + halfrow[2*(j+i)] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL);
- + halfrow[2*(j+1+i)] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1);
- + t=halfrow[2*(j+i)+1];
- + b=halfrow[2*(j+1+i)+1];
- + halfrow[2*(j+i)+1] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL);
- + halfrow[2*(j+1+i)+1] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1);
- + }
- + }
- +#undef halfrow
- +}
- +#endif
- +
- +
- +#ifdef STREAM_INIT
- +void stream_cypher_group_init(
- + struct stream_regs *regs,
- + group iA[8][4], // [In] iA00,iA01,...iA73 32 groups | Derived from key.
- + group iB[8][4], // [In] iB00,iB01,...iB73 32 groups | Derived from key.
- + unsigned char *sb) // [In] (SB0,SB1,...SB7)...x32 32*8 bytes | Extra input.
- +#endif
- +#ifdef STREAM_NORMAL
- +void stream_cypher_group_normal(
- + struct stream_regs *regs,
- + unsigned char *cb) // [Out] (CB0,CB1,...CB7)...x32 32*8 bytes | Output.
- +#endif
- +{
- +#ifdef STREAM_INIT
- + group in1[4];
- + group in2[4];
- +#endif
- + group extra_B[4];
- + group fa,fb,fc,fd,fe;
- + group s1a,s1b,s2a,s2b,s3a,s3b,s4a,s4b,s5a,s5b,s6a,s6b,s7a,s7b;
- + group next_E[4];
- + group tmp0,tmp1,tmp2,tmp3,tmp4;
- +#ifdef STREAM_INIT
- + group *sb_g=(group *)sb;
- +#endif
- +#ifdef STREAM_NORMAL
- + group *cb_g=(group *)cb;
- +#endif
- + int aboff;
- + int i,j,k,b;
- + int dbg;
- +
- +#ifdef STREAM_INIT
- + DBG(fprintf(stderr,":::::::::: BEGIN STREAM INIT\n"));
- +#endif
- +#ifdef STREAM_NORMAL
- + DBG(fprintf(stderr,":::::::::: BEGIN STREAM NORMAL\n"));
- +#endif
- +#ifdef STREAM_INIT
- +for(j=0;j<64;j++){
- + DBG(fprintf(stderr,"precall prerot stream_in[%2i]=",j));
- + DBG(dump_mem("",sb+BYPG*j,BYPG,BYPG));
- +}
- +
- +DBG(dump_mem("stream_prerot ",sb,GROUP_PARALLELISM*8,BYPG));
- +#if GROUP_PARALLELISM==32
- +trasp64_32_88ccw(sb);
- +#endif
- +#if GROUP_PARALLELISM==64
- +trasp64_64_88ccw(sb);
- +#endif
- +#if GROUP_PARALLELISM==128
- +trasp64_128_88ccw(sb);
- +#endif
- +DBG(dump_mem("stream_postrot",sb,GROUP_PARALLELISM*8,BYPG));
- +
- +for(j=0;j<64;j++){
- + DBG(fprintf(stderr,"precall stream_in[%2i]=",j));
- + DBG(dump_mem("",sb+BYPG*j,BYPG,BYPG));
- +}
- +#endif
- +
- + aboff=32;
- +
- +#ifdef STREAM_INIT
- + // load first 32 bits of ck into A[aboff+0]..A[aboff+7]
- + // load last 32 bits of ck into B[aboff+0]..B[aboff+7]
- + // all other regs = 0
- + for(i=0;i<8;i++){
- + for(b=0;b<4;b++){
- +DBG(fprintf(stderr,"dbg from iA A[%i][%i]=",i,b));
- +DBG(dump_mem("",(unsigned char *)&iA[i][b],BYPG,BYPG));
- +DBG(fprintf(stderr," dbg from iB B[%i][%i]=",i,b));
- +DBG(dump_mem("",(unsigned char *)&iB[i][b],BYPG,BYPG));
- + regs->A[aboff+i][b]=iA[i][b];
- + regs->B[aboff+i][b]=iB[i][b];
- + }
- + }
- + for(b=0;b<4;b++){
- + regs->A[aboff+8][b]=FF0();
- + regs->A[aboff+9][b]=FF0();
- + regs->B[aboff+8][b]=FF0();
- + regs->B[aboff+9][b]=FF0();
- + }
- + for(b=0;b<4;b++){
- + regs->X[b]=FF0();
- + regs->Y[b]=FF0();
- + regs->Z[b]=FF0();
- + regs->D[b]=FF0();
- + regs->E[b]=FF0();
- + regs->F[b]=FF0();
- + }
- + regs->p=FF0();
- + regs->q=FF0();
- + regs->r=FF0();
- +#endif
- +
- +for(dbg=0;dbg<4;dbg++){
- + DBG(fprintf(stderr,"dbg A0[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)®s->A[aboff+0][dbg],BYPG,BYPG));
- + DBG(fprintf(stderr,"dbg B0[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)®s->B[aboff+0][dbg],BYPG,BYPG));
- +}
- +
- +////////////////////////////////////////////////////////////////////////////////
- +
- + // EXTERNAL LOOP - 8 bytes per operation
- + for(i=0;i<8;i++){
- +
- + DBG(fprintf(stderr,"--BEGIN EXTERNAL LOOP %i\n",i));
- +
- +#ifdef STREAM_INIT
- + for(b=0;b<4;b++){
- + in1[b]=sb_g[8*i+4+b];
- + in2[b]=sb_g[8*i+b];
- + }
- +#endif
- +
- + // INTERNAL LOOP - 2 bits per iteration
- + for(j=0; j<4; j++){
- +
- + DBG(fprintf(stderr,"---BEGIN INTERNAL LOOP %i (EXT %i, INT %i)\n",j,i,j));
- +
- + // from A0..A9, 35 bits are selected as inputs to 7 s-boxes
- + // 5 bits input per s-box, 2 bits output per s-box
- +
- + // we can select bits with zero masking and shifting operations
- + // and synthetize s-boxes with optimized boolean functions.
- + // this is the actual reason we do all the crazy transposition
- + // stuff to switch between normal and bit slice representations.
- + // this code really flies.
- +
- + fe=regs->A[aboff+3][0];fa=regs->A[aboff+0][2];fb=regs->A[aboff+5][1];fc=regs->A[aboff+6][3];fd=regs->A[aboff+8][0];
- +/* 1000 1110 1110 0001 : lev 7: */ //tmp0=( fa^( fb^( ( ( ( fa|fb )^fc )|( fc^fd ) )^ALL_ONES ) ) );
- +/* 1110 0010 0011 0011 : lev 6: */ //tmp1=( ( fa|fb )^( ( fc&( fa|( fb^fd ) ) )^ALL_ONES ) );
- +/* 0011 0110 1000 1101 : lev 5: */ //tmp2=( fa^( ( fb&fd )^( ( fa&fd )|fc ) ) );
- +/* 0101 0101 1001 0011 : lev 5: */ //tmp3=( ( fa&fc )^( fa^( ( fa&fb )|fd ) ) );
- +/* 1000 1110 1110 0001 : lev 7: */ tmp0=FFXOR(fa,FFXOR(fb,FFXOR(FFOR(FFXOR(FFOR(fa,fb),fc),FFXOR(fc,fd)),FF1())));
- +/* 1110 0010 0011 0011 : lev 6: */ tmp1=FFXOR(FFOR(fa,fb),FFXOR(FFAND(fc,FFOR(fa,FFXOR(fb,fd))),FF1()));
- +/* 0011 0110 1000 1101 : lev 5: */ tmp2=FFXOR(fa,FFXOR(FFAND(fb,fd),FFOR(FFAND(fa,fd),fc)));
- +/* 0101 0101 1001 0011 : lev 5: */ tmp3=FFXOR(FFAND(fa,fc),FFXOR(fa,FFOR(FFAND(fa,fb),fd)));
- + s1a=FFXOR(tmp0,FFAND(fe,tmp1));
- + s1b=FFXOR(tmp2,FFAND(fe,tmp3));
- +//dump_mem("s1as1b-fe",&fe,BYPG,BYPG);
- +//dump_mem("s1as1b-fa",&fa,BYPG,BYPG);
- +//dump_mem("s1as1b-fb",&fb,BYPG,BYPG);
- +//dump_mem("s1as1b-fc",&fc,BYPG,BYPG);
- +//dump_mem("s1as1b-fd",&fd,BYPG,BYPG);
- +
- + fe=regs->A[aboff+1][1];fa=regs->A[aboff+2][2];fb=regs->A[aboff+5][3];fc=regs->A[aboff+6][0];fd=regs->A[aboff+8][1];
- +/* 1001 1110 0110 0001 : lev 6: */ //tmp0=( fa^( ( fb&( fc|fd ) )^( fc^( fd^ALL_ONES ) ) ) );
- +/* 0000 0011 0111 1011 : lev 5: */ //tmp1=( ( fa&( fb^fd ) )|( ( fa|fb )&fc ) );
- +/* 1100 0110 1101 0010 : lev 6: */ //tmp2=( ( fb&fd )^( ( fa&fd )|( fb^( fc^ALL_ONES ) ) ) );
- +/* 0001 1110 1111 0101 : lev 5: */ //tmp3=( ( fa&fd )|( fa^( fb^( fc&fd ) ) ) );
- +/* 1001 1110 0110 0001 : lev 6: */ tmp0=FFXOR(fa,FFXOR(FFAND(fb,FFOR(fc,fd)),FFXOR(fc,FFXOR(fd,FF1()))));
- +/* 0000 0011 0111 1011 : lev 5: */ tmp1=FFOR(FFAND(fa,FFXOR(fb,fd)),FFAND(FFOR(fa,fb),fc));
- +/* 1100 0110 1101 0010 : lev 6: */ tmp2=FFXOR(FFAND(fb,fd),FFOR(FFAND(fa,fd),FFXOR(fb,FFXOR(fc,FF1()))));
- +/* 0001 1110 1111 0101 : lev 5: */ tmp3=FFOR(FFAND(fa,fd),FFXOR(fa,FFXOR(fb,FFAND(fc,fd))));
- + s2a=FFXOR(tmp0,FFAND(fe,tmp1));
- + s2b=FFXOR(tmp2,FFAND(fe,tmp3));
- +
- + fe=regs->A[aboff+0][3];fa=regs->A[aboff+1][0];fb=regs->A[aboff+4][1];fc=regs->A[aboff+4][3];fd=regs->A[aboff+5][2];
- +/* 0100 1011 1001 0110 : lev 5: */ //tmp0=( fa^( fb^( ( fc&( fa|fd ) )^fd ) ) );
- +/* 1101 0101 1000 1100 : lev 7: */ //tmp1=( ( fa&fc )^( ( fa^fd )|( ( fb|fc )^( fd^ALL_ONES ) ) ) );
- +/* 0010 0111 1101 1000 : lev 4: */ //tmp2=( fa^( ( ( fb^fc )&fd )^fc ) );
- +/* 1111 1111 1111 1111 : lev 0: */ //tmp3=ALL_ONES;
- +/* 0100 1011 1001 0110 : lev 5: */ tmp0=FFXOR(fa,FFXOR(fb,FFXOR(FFAND(fc,FFOR(fa,fd)),fd)));
- +/* 1101 0101 1000 1100 : lev 7: */ tmp1=FFXOR(FFAND(fa,fc),FFOR(FFXOR(fa,fd),FFXOR(FFOR(fb,fc),FFXOR(fd,FF1()))));
- +/* 0010 0111 1101 1000 : lev 4: */ tmp2=FFXOR(fa,FFXOR(FFAND(FFXOR(fb,fc),fd),fc));
- +/* 1111 1111 1111 1111 : lev 0: */ tmp3=FF1();
- + s3a=FFXOR(tmp0,FFAND(FFNOT(fe),tmp1));
- + s3b=FFXOR(tmp2,FFAND(fe,tmp3));
- +
- + fe=regs->A[aboff+2][3];fa=regs->A[aboff+0][1];fb=regs->A[aboff+1][3];fc=regs->A[aboff+3][2];fd=regs->A[aboff+7][0];
- +/* 1011 0101 0100 1001 : lev 7: */ //tmp0=( fa^( ( fc&( fa^fd ) )|( fb^( fc|( fd^ALL_ONES ) ) ) ) );
- +/* 0010 1101 0110 0110 : lev 6: */ //tmp1=( ( fa&fb )^( fb^( ( ( fa|fc )&fd )^fc ) ) );
- +/* 0110 0111 1101 0000 : lev 7: */ //tmp2=( fa^( ( fb&fc )|( ( ( fa&( fb^fd ) )|fc )^fd ) ) );
- +/* 1111 1111 1111 1111 : lev 0: */ //tmp3=ALL_ONES;
- +/* 1011 0101 0100 1001 : lev 7: */ tmp0=FFXOR(fa,FFOR(FFAND(fc,FFXOR(fa,fd)),FFXOR(fb,FFOR(fc,FFXOR(fd,FF1())))));
- +/* 0010 1101 0110 0110 : lev 6: */ tmp1=FFXOR(FFAND(fa,fb),FFXOR(fb,FFXOR(FFAND(FFOR(fa,fc),fd),fc)));
- +/* 0110 0111 1101 0000 : lev 7: */ tmp2=FFXOR(fa,FFOR(FFAND(fb,fc),FFXOR(FFOR(FFAND(fa,FFXOR(fb,fd)),fc),fd)));
- +/* 1111 1111 1111 1111 : lev 0: */ tmp3=FF1();
- + s4a=FFXOR(tmp0,FFAND(fe,FFXOR(tmp1,tmp0)));
- + s4b=FFXOR(FFXOR(s4a,tmp2),FFAND(fe,tmp3));
- +
- + fe=regs->A[aboff+4][2];fa=regs->A[aboff+3][3];fb=regs->A[aboff+5][0];fc=regs->A[aboff+7][1];fd=regs->A[aboff+8][2];
- +/* 1000 1111 0011 0010 : lev 7: */ //tmp0=( ( ( fa&( fb|fc ) )^fb )|( ( ( fa^fc )|fd )^ALL_ONES ) );
- +/* 0110 1011 0000 1011 : lev 6: */ //tmp1=( fb^( ( fc^fd )&( fc^( fb|( fa^fd ) ) ) ) );
- +/* 0001 1010 0111 1001 : lev 6: */ //tmp2=( ( fa&fc )^( fb^( ( fb|( fa^fc ) )&fd ) ) );
- +/* 0101 1101 1101 0101 : lev 4: */ //tmp3=( ( ( fa^fb )&( fc^ALL_ONES ) )|fd );
- +/* 1000 1111 0011 0010 : lev 7: */ tmp0=FFOR(FFXOR(FFAND(fa,FFOR(fb,fc)),fb),FFXOR(FFOR(FFXOR(fa,fc),fd),FF1()));
- +/* 0110 1011 0000 1011 : lev 6: */ tmp1=FFXOR(fb,FFAND(FFXOR(fc,fd),FFXOR(fc,FFOR(fb,FFXOR(fa,fd)))));
- +/* 0001 1010 0111 1001 : lev 6: */ tmp2=FFXOR(FFAND(fa,fc),FFXOR(fb,FFAND(FFOR(fb,FFXOR(fa,fc)),fd)));
- +/* 0101 1101 1101 0101 : lev 4: */ tmp3=FFOR(FFAND(FFXOR(fa,fb),FFXOR(fc,FF1())),fd);
- + s5a=FFXOR(tmp0,FFAND(fe,tmp1));
- + s5b=FFXOR(tmp2,FFAND(fe,tmp3));
- +
- + fe=regs->A[aboff+2][1];fa=regs->A[aboff+3][1];fb=regs->A[aboff+4][0];fc=regs->A[aboff+6][2];fd=regs->A[aboff+8][3];
- +/* 0011 0110 0010 1101 : lev 6: */ //tmp0=( ( ( fa&fc )&fd )^( ( fb&( fa|fd ) )^fc ) );
- +/* 1110 1110 1011 1011 : lev 3: */ //tmp1=( ( ( fa^fc )&fd )^ALL_ONES );
- +/* 0101 1000 0110 0111 : lev 6: */ //tmp2=( ( fa&( fb|fc ) )^( fb^( ( fb&fc )|fd ) ) );
- +/* 0001 0011 0000 0001 : lev 5: */ //tmp3=( fc&( ( fa&( fb^fd ) )^( fb|fd ) ) );
- +/* 0011 0110 0010 1101 : lev 6: */ tmp0=FFXOR(FFAND(FFAND(fa,fc),fd),FFXOR(FFAND(fb,FFOR(fa,fd)),fc));
- +/* 1110 1110 1011 1011 : lev 3: */ tmp1=FFXOR(FFAND(FFXOR(fa,fc),fd),FF1());
- +/* 0101 1000 0110 0111 : lev 6: */ tmp2=FFXOR(FFAND(fa,FFOR(fb,fc)),FFXOR(fb,FFOR(FFAND(fb,fc),fd)));
- +/* 0001 0011 0000 0001 : lev 5: */ tmp3=FFAND(fc,FFXOR(FFAND(fa,FFXOR(fb,fd)),FFOR(fb,fd)));
- + s6a=FFXOR(tmp0,FFAND(fe,tmp1));
- + s6b=FFXOR(tmp2,FFAND(fe,tmp3));
- +
- + fe=regs->A[aboff+1][2];fa=regs->A[aboff+2][0];fb=regs->A[aboff+6][1];fc=regs->A[aboff+7][2];fd=regs->A[aboff+7][3];
- +/* 0111 1000 1001 0110 : lev 5: */ //tmp0=( fb^( ( fc&fd )|( fa^( fc^fd ) ) ) );
- +/* 0100 1001 0101 1011 : lev 6: */ //tmp1=( ( fb|fd )&( ( fa&fc )|( fb^( fc^fd ) ) ) );
- +/* 0100 1001 1011 1001 : lev 5: */ //tmp2=( ( fa|fb )^( ( fc&( fb|fd ) )^fd ) );
- +/* 1111 1111 1101 1101 : lev 3: */ //tmp3=( fd|( ( fa&fc )^ALL_ONES ) );
- +/* 0111 1000 1001 0110 : lev 5: */ tmp0=FFXOR(fb,FFOR(FFAND(fc,fd),FFXOR(fa,FFXOR(fc,fd))));
- +/* 0100 1001 0101 1011 : lev 6: */ tmp1=FFAND(FFOR(fb,fd),FFOR(FFAND(fa,fc),FFXOR(fb,FFXOR(fc,fd))));
- +/* 0100 1001 1011 1001 : lev 5: */ tmp2=FFXOR(FFOR(fa,fb),FFXOR(FFAND(fc,FFOR(fb,fd)),fd));
- +/* 1111 1111 1101 1101 : lev 3: */ tmp3=FFOR(fd,FFXOR(FFAND(fa,fc),FF1()));
- + s7a=FFXOR(tmp0,FFAND(fe,tmp1));
- + s7b=FFXOR(tmp2,FFAND(fe,tmp3));
- +
- +
- +/*
- + we have just done this:
- +
- + int sbox1[0x20] = {2,0,1,1,2,3,3,0, 3,2,2,0,1,1,0,3, 0,3,3,0,2,2,1,1, 2,2,0,3,1,1,3,0};
- + int sbox2[0x20] = {3,1,0,2,2,3,3,0, 1,3,2,1,0,0,1,2, 3,1,0,3,3,2,0,2, 0,0,1,2,2,1,3,1};
- + int sbox3[0x20] = {2,0,1,2,2,3,3,1, 1,1,0,3,3,0,2,0, 1,3,0,1,3,0,2,2, 2,0,1,2,0,3,3,1};
- + int sbox4[0x20] = {3,1,2,3,0,2,1,2, 1,2,0,1,3,0,0,3, 1,0,3,1,2,3,0,3, 0,3,2,0,1,2,2,1};
- + int sbox5[0x20] = {2,0,0,1,3,2,3,2, 0,1,3,3,1,0,2,1, 2,3,2,0,0,3,1,1, 1,0,3,2,3,1,0,2};
- + int sbox6[0x20] = {0,1,2,3,1,2,2,0, 0,1,3,0,2,3,1,3, 2,3,0,2,3,0,1,1, 2,1,1,2,0,3,3,0};
- + int sbox7[0x20] = {0,3,2,2,3,0,0,1, 3,0,1,3,1,2,2,1, 1,0,3,3,0,1,1,2, 2,3,1,0,2,3,0,2};
- +
- + s12 = sbox1[ (((A3>>0)&1)<<4) | (((A0>>2)&1)<<3) | (((A5>>1)&1)<<2) | (((A6>>3)&1)<<1) | (((A8>>0)&1)<<0) ]
- + |sbox2[ (((A1>>1)&1)<<4) | (((A2>>2)&1)<<3) | (((A5>>3)&1)<<2) | (((A6>>0)&1)<<1) | (((A8>>1)&1)<<0) ];
- + s34 = sbox3[ (((A0>>3)&1)<<4) | (((A1>>0)&1)<<3) | (((A4>>1)&1)<<2) | (((A4>>3)&1)<<1) | (((A5>>2)&1)<<0) ]
- + |sbox4[ (((A2>>3)&1)<<4) | (((A0>>1)&1)<<3) | (((A1>>3)&1)<<2) | (((A3>>2)&1)<<1) | (((A7>>0)&1)<<0) ];
- + s56 = sbox5[ (((A4>>2)&1)<<4) | (((A3>>3)&1)<<3) | (((A5>>0)&1)<<2) | (((A7>>1)&1)<<1) | (((A8>>2)&1)<<0) ]
- + |sbox6[ (((A2>>1)&1)<<4) | (((A3>>1)&1)<<3) | (((A4>>0)&1)<<2) | (((A6>>2)&1)<<1) | (((A8>>3)&1)<<0) ];
- + s7 = sbox7[ (((A1>>2)&1)<<4) | (((A2>>0)&1)<<3) | (((A6>>1)&1)<<2) | (((A7>>2)&1)<<1) | (((A7>>3)&1)<<0) ];
- +*/
- +
- + // use 4x4 xor to produce extra nibble for T3
- +
- + extra_B[3]=FFXOR(FFXOR(FFXOR(regs->B[aboff+2][0],regs->B[aboff+5][1]),regs->B[aboff+6][2]),regs->B[aboff+8][3]);
- + extra_B[2]=FFXOR(FFXOR(FFXOR(regs->B[aboff+5][0],regs->B[aboff+7][1]),regs->B[aboff+2][3]),regs->B[aboff+3][2]);
- + extra_B[1]=FFXOR(FFXOR(FFXOR(regs->B[aboff+4][3],regs->B[aboff+7][2]),regs->B[aboff+3][0]),regs->B[aboff+4][1]);
- + extra_B[0]=FFXOR(FFXOR(FFXOR(regs->B[aboff+8][2],regs->B[aboff+5][3]),regs->B[aboff+2][1]),regs->B[aboff+7][0]);
- +for(dbg=0;dbg<4;dbg++){
- + DBG(fprintf(stderr,"extra_B[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)&extra_B[dbg],BYPG,BYPG));
- +}
- +
- + // T1 = xor all inputs
- + // in1, in2, D are only used in T1 during initialisation, not generation
- + for(b=0;b<4;b++){
- + regs->A[aboff-1][b]=FFXOR(regs->A[aboff+9][b],regs->X[b]);
- + }
- +
- +#ifdef STREAM_INIT
- + for(b=0;b<4;b++){
- + regs->A[aboff-1][b]=FFXOR(FFXOR(regs->A[aboff-1][b],regs->D[b]),((j % 2) ? in2[b] : in1[b]));
- + }
- +#endif
- +
- +for(dbg=0;dbg<4;dbg++){
- + DBG(fprintf(stderr,"next_A0[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)®s->A[aboff-1][dbg],BYPG,BYPG));
- +}
- +
- + // T2 = xor all inputs
- + // in1, in2 are only used in T1 during initialisation, not generation
- + // if p=0, use this, if p=1, rotate the result left
- + for(b=0;b<4;b++){
- + regs->B[aboff-1][b]=FFXOR(FFXOR(regs->B[aboff+6][b],regs->B[aboff+9][b]),regs->Y[b]);
- + }
- +
- +#ifdef STREAM_INIT
- + for(b=0;b<4;b++){
- + regs->B[aboff-1][b]=FFXOR(regs->B[aboff-1][b],((j % 2) ? in1[b] : in2[b]));
- + }
- +#endif
- +
- +for(dbg=0;dbg<4;dbg++){
- + DBG(fprintf(stderr,"next_B0[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)®s->B[aboff-1][dbg],BYPG,BYPG));
- +}
- +
- + // if p=1, rotate left (yes, this is what we're doing)
- + tmp3=regs->B[aboff-1][3];
- + regs->B[aboff-1][3]=FFXOR(regs->B[aboff-1][3],FFAND(FFXOR(regs->B[aboff-1][3],regs->B[aboff-1][2]),regs->p));
- + regs->B[aboff-1][2]=FFXOR(regs->B[aboff-1][2],FFAND(FFXOR(regs->B[aboff-1][2],regs->B[aboff-1][1]),regs->p));
- + regs->B[aboff-1][1]=FFXOR(regs->B[aboff-1][1],FFAND(FFXOR(regs->B[aboff-1][1],regs->B[aboff-1][0]),regs->p));
- + regs->B[aboff-1][0]=FFXOR(regs->B[aboff-1][0],FFAND(FFXOR(regs->B[aboff-1][0],tmp3),regs->p));
- +
- +for(dbg=0;dbg<4;dbg++){
- + DBG(fprintf(stderr,"next_B0[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)®s->B[aboff-1][dbg],BYPG,BYPG));
- +}
- +
- + // T3 = xor all inputs
- + for(b=0;b<4;b++){
- + regs->D[b]=FFXOR(FFXOR(regs->E[b],regs->Z[b]),extra_B[b]);
- + }
- +
- +for(dbg=0;dbg<4;dbg++){
- + DBG(fprintf(stderr,"D[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)®s->D[dbg],BYPG,BYPG));
- +}
- +
- + // T4 = sum, carry of Z + E + r
- + for(b=0;b<4;b++){
- + next_E[b]=regs->F[b];
- + }
- +
- + tmp0=FFXOR(regs->Z[0],regs->E[0]);
- + tmp1=FFAND(regs->Z[0],regs->E[0]);
- + regs->F[0]=FFXOR(regs->E[0],FFAND(regs->q,FFXOR(regs->Z[0],regs->r)));
- + tmp3=FFAND(tmp0,regs->r);
- + tmp4=FFOR(tmp1,tmp3);
- +
- + tmp0=FFXOR(regs->Z[1],regs->E[1]);
- + tmp1=FFAND(regs->Z[1],regs->E[1]);
- + regs->F[1]=FFXOR(regs->E[1],FFAND(regs->q,FFXOR(regs->Z[1],tmp4)));
- + tmp3=FFAND(tmp0,tmp4);
- + tmp4=FFOR(tmp1,tmp3);
- +
- + tmp0=FFXOR(regs->Z[2],regs->E[2]);
- + tmp1=FFAND(regs->Z[2],regs->E[2]);
- + regs->F[2]=FFXOR(regs->E[2],FFAND(regs->q,FFXOR(regs->Z[2],tmp4)));
- + tmp3=FFAND(tmp0,tmp4);
- + tmp4=FFOR(tmp1,tmp3);
- +
- + tmp0=FFXOR(regs->Z[3],regs->E[3]);
- + tmp1=FFAND(regs->Z[3],regs->E[3]);
- + regs->F[3]=FFXOR(regs->E[3],FFAND(regs->q,FFXOR(regs->Z[3],tmp4)));
- + tmp3=FFAND(tmp0,tmp4);
- + regs->r=FFXOR(regs->r,FFAND(regs->q,FFXOR(FFOR(tmp1,tmp3),regs->r))); // ultimate carry
- +
- +/*
- + we have just done this: (believe it or not)
- +
- + if (q) {
- + F = Z + E + r;
- + r = (F >> 4) & 1;
- + F = F & 0x0f;
- + }
- + else {
- + F = E;
- + }
- +*/
- + for(b=0;b<4;b++){
- + regs->E[b]=next_E[b];
- + }
- +for(dbg=0;dbg<4;dbg++){
- + DBG(fprintf(stderr,"F[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)®s->F[dbg],BYPG,BYPG));
- +}
- +DBG(fprintf(stderr,"r="));
- +DBG(dump_mem("",(unsigned char *)®s->r,BYPG,BYPG));
- +for(dbg=0;dbg<4;dbg++){
- + DBG(fprintf(stderr,"E[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)®s->E[dbg],BYPG,BYPG));
- +}
- +
- + // this simple instruction is virtually shifting all the shift registers
- + aboff--;
- +
- +/*
- + we've just done this:
- +
- + A9=A8;A8=A7;A7=A6;A6=A5;A5=A4;A4=A3;A3=A2;A2=A1;A1=A0;A0=next_A0;
- + B9=B8;B8=B7;B7=B6;B6=B5;B5=B4;B4=B3;B3=B2;B2=B1;B1=B0;B0=next_B0;
- +*/
- +
- + regs->X[0]=s1a;
- + regs->X[1]=s2a;
- + regs->X[2]=s3b;
- + regs->X[3]=s4b;
- + regs->Y[0]=s3a;
- + regs->Y[1]=s4a;
- + regs->Y[2]=s5b;
- + regs->Y[3]=s6b;
- + regs->Z[0]=s5a;
- + regs->Z[1]=s6a;
- + regs->Z[2]=s1b;
- + regs->Z[3]=s2b;
- + regs->p=s7a;
- + regs->q=s7b;
- +for(dbg=0;dbg<4;dbg++){
- + DBG(fprintf(stderr,"X[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)®s->X[dbg],BYPG,BYPG));
- +}
- +for(dbg=0;dbg<4;dbg++){
- + DBG(fprintf(stderr,"Y[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)®s->Y[dbg],BYPG,BYPG));
- +}
- +for(dbg=0;dbg<4;dbg++){
- + DBG(fprintf(stderr,"Z[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)®s->Z[dbg],BYPG,BYPG));
- +}
- +DBG(fprintf(stderr,"p="));
- +DBG(dump_mem("",(unsigned char *)®s->p,BYPG,BYPG));
- +DBG(fprintf(stderr,"q="));
- +DBG(dump_mem("",(unsigned char *)®s->q,BYPG,BYPG));
- +
- +#ifdef STREAM_NORMAL
- + // require 4 loops per output byte
- + // 2 output bits are a function of the 4 bits of D
- + // xor 2 by 2
- + cb_g[8*i+7-2*j]=FFXOR(regs->D[2],regs->D[3]);
- + cb_g[8*i+6-2*j]=FFXOR(regs->D[0],regs->D[1]);
- +for(dbg=0;dbg<8;dbg++){
- + DBG(fprintf(stderr,"op[%i]=",dbg));
- + DBG(dump_mem("",(unsigned char *)&cb_g[8*i+dbg],BYPG,BYPG));
- +}
- +#endif
- +
- +DBG(fprintf(stderr,"---END INTERNAL LOOP\n"));
- +
- + } // INTERNAL LOOP
- +
- +DBG(fprintf(stderr,"--END EXTERNAL LOOP\n"));
- +
- + } // EXTERNAL LOOP
- +
- + // move 32 steps forward, ready for next call
- + for(k=0;k<10;k++){
- + for(b=0;b<4;b++){
- +DBG(fprintf(stderr,"moving forward AB k=%i b=%i\n",k,b));
- + regs->A[32+k][b]=regs->A[k][b];
- + regs->B[32+k][b]=regs->B[k][b];
- + }
- + }
- +
- +
- +////////////////////////////////////////////////////////////////////////////////
- +
- +#ifdef STREAM_NORMAL
- +for(j=0;j<64;j++){
- + DBG(fprintf(stderr,"postcall prerot cb[%2i]=",j));
- + DBG(dump_mem("",(unsigned char *)(cb+BYPG*j),BYPG,BYPG));
- +}
- +
- +#if GROUP_PARALLELISM==32
- +trasp64_32_88cw(cb);
- +#endif
- +#if GROUP_PARALLELISM==64
- +trasp64_64_88cw(cb);
- +#endif
- +#if GROUP_PARALLELISM==128
- +trasp64_128_88cw(cb);
- +#endif
- +
- +for(j=0;j<64;j++){
- + DBG(fprintf(stderr,"postcall postrot cb[%2i]=",j));
- + DBG(dump_mem("",(unsigned char *)(cb+BYPG*j),BYPG,BYPG));
- +}
- +#endif
- +
- +#ifdef STREAM_INIT
- + DBG(fprintf(stderr,":::::::::: END STREAM INIT\n"));
- +#endif
- +#ifdef STREAM_NORMAL
- + DBG(fprintf(stderr,":::::::::: END STREAM NORMAL\n"));
- +#endif
- +
- +}
- +
- Index: globals.h
- ===================================================================
- --- globals.h (revision 11209)
- +++ globals.h (working copy)
- @@ -387,12 +387,12 @@
- #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
- #define MAX_ECM_SIZE 596
- -#define MAX_EMM_SIZE 512
- +#define MAX_EMM_SIZE 1024
- -#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
- @@ -423,6 +423,7 @@
- /////////////////// readers that do not reed baudrate setting and timings are guarded by reader itself (large buffer built in): AFTER R_SMART
- #define R_SMART 0x7 // Smartreader+
- #define R_PCSC 0x8 // PCSC
- +#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
- @@ -847,6 +848,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 ;
- @@ -970,6 +978,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 *);
- };
- @@ -1674,6 +1683,7 @@
- #ifdef MODULE_GHTTP
- uint8_t ghttp_use_ssl;
- #endif
- + FTAB emu_auproviders;
- 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;
- @@ -2141,6 +2151,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)
- @@ -2313,4 +2335,6 @@
- static inline bool caid_is_dre(uint16_t caid) { return caid == 0x4AE0 || caid == 0x4AE1;}
- const char *get_cardsystem_desc_by_caid(uint16_t caid);
- +FILTER* get_emu_prids_for_caid(struct s_reader *rdr, uint16_t caid);
- +
- #endif
- Index: module-dvbapi.c
- ===================================================================
- --- module-dvbapi.c (revision 11209)
- +++ module-dvbapi.c (working copy)
- @@ -1440,7 +1440,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)
- @@ -1459,7 +1467,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
- @@ -1560,7 +1575,7 @@
- demux[demux_id].ECMpids[demux[demux_id].ECMpidcount].table = 0;
- cs_log("Demuxer %d ecmpid %d CAID: %04X ECM_PID: %04X PROVID: %06X %s", demux_id, demux[demux_id].ECMpidcount, caid, ecmpid, provid, txt);
- - if(caid_is_irdeto(caid)) { demux[demux_id].emmstart.time = 1; } // marker to fetch emms early irdeto needs them!
- + if(caid_is_irdeto(caid) || caid_is_dre(caid)) { demux[demux_id].emmstart.time = 1; } // marker to fetch emms early irdeto needs them!
- demux[demux_id].ECMpidcount++;
- }
- @@ -3038,7 +3053,7 @@
- openxcas_set_ecm_pid(demux[demux_id].ECMpids[found].ECM_PID);
- // fixup for cas that need emm first!
- - if(caid_is_irdeto(demux[demux_id].ECMpids[found].CAID)) { demux[demux_id].emmstart.time = 0; }
- + if(caid_is_irdeto(demux[demux_id].ECMpids[found].CAID) || caid_is_dre(demux[demux_id].ECMpids[found].CAID)) { demux[demux_id].emmstart.time = 0; }
- started = dvbapi_start_descrambling(demux_id, found, checked);
- if(cfg.dvbapi_requestmode == 0 && started == 1) { return; } // in requestmode 0 we only start 1 ecm request at the time
- }
- @@ -4287,6 +4302,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!
- @@ -4313,9 +4329,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;
- @@ -6088,6 +6119,7 @@
- delayer(er, delay);
- + if(er->caid>>8 != 0x0E || !cfg.emu_stream_relay_enabled)
- switch(selected_api)
- {
- #if defined(WITH_STAPI) || defined(WITH_STAPI5)
- Index: module-dvbapi.h
- ===================================================================
- --- module-dvbapi.h (revision 11209)
- +++ module-dvbapi.h (working copy)
- @@ -135,6 +135,7 @@
- ca_index_t index[MAX_STREAM_INDICES];
- int8_t useMultipleIndices;
- uint32_t streams;
- + int16_t pvu_counter;
- };
- typedef struct filter_s
- Index: module-emulator-dre2overcrypt.c
- ===================================================================
- --- module-emulator-dre2overcrypt.c (revision 0)
- +++ module-emulator-dre2overcrypt.c (working copy)
- @@ -0,0 +1,637 @@
- +#include "globals.h"
- +#ifdef WITH_EMU
- +#include "oscam-string.h"
- +#endif
- +#include "module-emulator-st20.h"
- +#include "module-emulator-dre2overcrypt.h"
- +
- +static uint16_t gId = 0xFFFF;
- +static uint32_t gDecryptAddr;
- +static uint32_t gRawSec = 0;
- +static uint8_t gVersion = 0xFF;
- +
- +typedef struct data_block_t
- +{
- + uint8_t *data;
- + uint32_t size;
- + uint32_t used;
- +} data_block;
- +
- +typedef struct memory_block_t
- +{
- + uint8_t *pos;
- + uint8_t *end;
- +} memory_block;
- +
- +static data_block raw_buffer = { NULL, 0, 0 };
- +static data_block code_buffer = { NULL, 0, 0 };
- +
- +uint8_t initial_snippet[3694] =
- +{
- + 0x6F, 0xF0, 0x0E, 0x0D, 0x00, 0x00, 0x18, 0x75, 0xFF, 0x75, 0x63, 0x72, 0x2E, 0x2C, 0x17, 0x00,
- + 0x00, 0x3F, 0x3D, 0x15, 0x00, 0x00, 0x9C, 0x00, 0xFB, 0xF7, 0xFA, 0xF5, 0x85, 0x4C, 0xFB, 0xF0,
- + 0x04, 0xFB, 0xF8, 0xFB, 0xF1, 0xF7, 0xF0, 0x24, 0x0E, 0x42, 0xFF, 0x22, 0xF0, 0x41, 0x22, 0xF0,
- + 0x60, 0xBF, 0x73, 0xFF, 0x24, 0x4B, 0x72, 0x9D, 0xD0, 0x70, 0x42, 0xF4, 0xBF, 0xA4, 0x70, 0xB1,
- + 0x22, 0xF0, 0x40, 0x49, 0x00, 0x64, 0xFF, 0xB0, 0x25, 0x73, 0xD0, 0x24, 0x4C, 0x25, 0x72, 0xFF,
- + 0x25, 0xFF, 0x21, 0x22, 0x29, 0xA2, 0x25, 0x72, 0xFF, 0x42, 0x21, 0xFB, 0xFA, 0xF6, 0x22, 0x26,
- + 0x03, 0xFF, 0x80, 0x26, 0x2A, 0x0E, 0x80, 0x22, 0x2B, 0x07, 0xFF, 0x80, 0x22, 0x28, 0x05, 0x80,
- + 0x26, 0x2C, 0x07, 0xFF, 0x80, 0x2C, 0x24, 0x05, 0x80, 0x27, 0x20, 0x09, 0xBF, 0x80, 0x26, 0x2E,
- + 0x00, 0x80, 0x23, 0x73, 0x00, 0x22, 0xFF, 0x2C, 0x09, 0x80, 0x25, 0x22, 0x0B, 0x80, 0x25, 0xFF,
- + 0x2C, 0x04, 0x80, 0x21, 0x21, 0x2F, 0x03, 0x2A, 0xFF, 0x24, 0x08, 0x80, 0x2A, 0x27, 0x0F, 0x80,
- + 0x23, 0x7D, 0x2F, 0x8C, 0x00, 0x2D, 0x05, 0x80, 0x23, 0x2C, 0x84, 0x01, 0xFA, 0x90, 0x00, 0x2F,
- + 0x78, 0x00, 0x26, 0x08, 0x80, 0x2E, 0x0A, 0xFF, 0x80, 0x80, 0x27, 0x24, 0x09, 0x80, 0x27, 0x2C,
- + 0xCF, 0x06, 0x80, 0x27, 0x29, 0x78, 0x00, 0x6F, 0x00, 0x2A, 0x2F, 0xFF, 0x0D, 0x80, 0x28, 0x23,
- + 0x05, 0x80, 0x2B, 0x28, 0xF7, 0x08, 0x80, 0x28, 0xB7, 0x00, 0x26, 0x2F, 0x0E, 0x80, 0xFF, 0x27,
- + 0x25, 0x00, 0x80, 0x2B, 0x21, 0x06, 0x80, 0xFF, 0x2A, 0x25, 0x01, 0x80, 0x21, 0x28, 0x00, 0x80,
- + 0xCB, 0x22, 0x2E, 0xB0, 0x01, 0x0D, 0x6D, 0x00, 0x88, 0x00, 0x28, 0x03, 0xFE, 0x91, 0x00, 0x0C,
- + 0x80, 0x2C, 0x2D, 0x0E, 0x80, 0x2A, 0xB5, 0x04, 0xBC, 0x00, 0x2A, 0xD4, 0x00, 0x27, 0x0C, 0xE5,
- + 0x00, 0x07, 0xFF, 0x80, 0x23, 0x2D, 0x0D, 0x80, 0x25, 0x21, 0x00, 0xFF, 0x80, 0x24, 0x24, 0x0D,
- + 0x80, 0x24, 0x2B, 0x08, 0xFF, 0x80, 0x24, 0x2D, 0x0C, 0x80, 0x2D, 0x21, 0x0A, 0xFE, 0x0D, 0x10,
- + 0x0C, 0x80, 0x28, 0x28, 0x02, 0x80, 0x26, 0xDF, 0x27, 0x0A, 0x80, 0x2A, 0x21, 0x24, 0x10, 0x20,
- + 0x08, 0xEA, 0x85, 0x00, 0x03, 0x21, 0x10, 0x0A, 0x19, 0x10, 0x07, 0x80, 0x2F, 0xFE, 0xCF, 0x01,
- + 0x2D, 0x0B, 0x80, 0x2A, 0x24, 0x00, 0x80, 0xFF, 0x29, 0x20, 0x0E, 0x80, 0x26, 0x22, 0x0A, 0x80,
- + 0xFF, 0x21, 0x20, 0x25, 0x01, 0x2A, 0x21, 0x01, 0x80, 0xD3, 0x2A, 0x03, 0xBC, 0x00, 0x6F, 0x10,
- + 0x24, 0x6F, 0x10, 0x21, 0x22, 0xEF, 0x03, 0x80, 0x2C, 0x02, 0x78, 0x10, 0x20, 0x29, 0x0E, 0xFF,
- + 0x28, 0x27, 0x00, 0x80, 0x27, 0x2F, 0x03, 0x80, 0xFB, 0x29, 0x21, 0x8C, 0x00, 0x73, 0x45, 0x25,
- + 0x71, 0x61, 0xFB, 0x2B, 0x96, 0x43, 0x01, 0x2D, 0x20, 0xAE, 0x70, 0x25, 0xFF, 0xB0, 0x22, 0xF0,
- + 0x70, 0xF1, 0x41, 0x24, 0xF6, 0xF5, 0xC0, 0xA2, 0x12, 0x81, 0xA7, 0x17, 0x21, 0x1D, 0x42, 0x24,
- + 0x7F, 0xFA, 0x21, 0x7D, 0x4C, 0x27, 0xF8, 0xD1, 0xC1, 0x10, 0xEF, 0x24, 0xF0, 0x21, 0xDD, 0xC7,
- + 0x11, 0xF1, 0x21, 0xDD, 0xDF, 0x71, 0x21, 0x7D, 0x23, 0xF3, 0xCC, 0x10, 0x1D, 0x70, 0x6A, 0xBE,
- + 0x10, 0x42, 0xB7, 0x13, 0x1F, 0xBE, 0x11, 0x7F, 0x43, 0xC4, 0x11, 0xEB, 0x7F, 0x43, 0xCA, 0x10,
- + 0xDF, 0xF3, 0x11, 0xF1, 0x21, 0xDF, 0x77, 0x71, 0x21, 0x7F, 0xD8, 0x10, 0xDF, 0x21, 0x1F, 0xDE,
- + 0x18, 0x3B, 0x1E, 0x44, 0xBF, 0x10, 0x7E, 0x21, 0x45, 0xC4, 0x11, 0x1A, 0x20, 0xFA, 0xCA, 0x10,
- + 0xDE, 0x20, 0x22, 0xF1, 0x21, 0xDE, 0x71, 0x21, 0x3D, 0x7E, 0xD8, 0x10, 0xDE, 0x21, 0x1E, 0x70,
- + 0x16, 0x20, 0xE2, 0x13, 0x7B, 0x22, 0x14, 0x16, 0x20, 0x22, 0x74, 0x21, 0x47, 0xC4, 0x10, 0xDE,
- + 0x48, 0x21, 0x24, 0xF0, 0x22, 0xD4, 0x4F, 0x22, 0xF1, 0x22, 0xBF, 0xD4, 0x71, 0x22, 0x74, 0x23,
- + 0xF3, 0x55, 0x20, 0x14, 0x3A, 0x39, 0x28, 0x18, 0x45, 0x21, 0x78, 0x21, 0x4E, 0x4C, 0x21, 0x78,
- + 0x20, 0xFA, 0x53, 0x20, 0xD8, 0x7E, 0x22, 0xF1, 0x22, 0xD8, 0x71, 0x22, 0x5D, 0x78, 0x62, 0x20,
- + 0xD8, 0x22, 0x18, 0x39, 0x28, 0x1A, 0x45, 0x21, 0x5B, 0x7A, 0x49, 0x4C, 0x21, 0x7A, 0x49, 0x53,
- + 0x20, 0xDA, 0xAC, 0x21, 0xBF, 0xF1, 0x22, 0xDA, 0x71, 0x22, 0x7A, 0x62, 0x20, 0xDA, 0x7B, 0x22,
- + 0x1A, 0x39, 0x27, 0x81, 0x21, 0x1A, 0x43, 0xBF, 0x10, 0xD1, 0x7A, 0x4B, 0x21, 0xD3, 0x20, 0xCA,
- + 0x10, 0xDA, 0xD9, 0x21, 0xF1, 0x21, 0xE7, 0xDA, 0x71, 0x21, 0xBC, 0x20, 0xDE, 0x20, 0x1A, 0x70,
- + 0x81, 0xAC, 0xD0, 0x20, 0xC7, 0x24, 0x22, 0x19, 0x45, 0x21, 0x79, 0x7A, 0x22, 0x79, 0xFA, 0x81,
- + 0x21, 0xD9, 0x07, 0x31, 0xF1, 0x22, 0xD9, 0x71, 0x22, 0x7D, 0x79, 0x62, 0x20, 0xD9, 0x22, 0x19,
- + 0x70, 0x81, 0xC4, 0x27, 0xAB, 0x22, 0x1B, 0x45, 0x21, 0x7B, 0x4B, 0x22, 0x7B, 0x52, 0x21, 0xDB,
- + 0x7E, 0x35, 0x31, 0xF1, 0x22, 0xDB, 0x71, 0x22, 0x7B, 0x62, 0x20, 0x57, 0xDB, 0x22, 0x1B, 0x1E,
- + 0x3A, 0x17, 0x45, 0x21, 0x77, 0xA8, 0x22, 0xF5, 0x77, 0xAE, 0x21, 0xD7, 0x63, 0x31, 0xF1, 0x22,
- + 0xD7, 0x71, 0xBB, 0x22, 0x77, 0x62, 0x20, 0xD7, 0x22, 0x17, 0x1E, 0x38, 0x82, 0x1B, 0x22, 0x13,
- + 0xD0, 0x20, 0x22, 0x73, 0xEF, 0x11, 0x8B, 0x30, 0x53, 0x20, 0xFD, 0xD3, 0x91, 0x31, 0xF1, 0x22,
- + 0xD3, 0x71, 0x22, 0x73, 0xBE, 0x62, 0x20, 0xD3, 0x22, 0x13, 0x70, 0x82, 0xF2, 0x26, 0x82, 0xDB,
- + 0x22, 0x12, 0x88, 0x31, 0x72, 0x44, 0x4C, 0x21, 0x72, 0x44, 0xFA, 0x53, 0x20, 0xD2, 0xBF, 0x31,
- + 0xF1, 0x22, 0xD2, 0x71, 0x22, 0x5D, 0x72, 0x62, 0x20, 0xD2, 0x22, 0x12, 0xA8, 0x3A, 0x15, 0x88,
- + 0x31, 0x5B, 0x75, 0x46, 0x4C, 0x21, 0x75, 0x46, 0x53, 0x20, 0xD5, 0xED, 0x31, 0xBF, 0xF1, 0x22,
- + 0xD5, 0x71, 0x22, 0x75, 0x62, 0x20, 0xD5, 0x6B, 0x22, 0x15, 0xA8, 0x3A, 0x11, 0x45, 0x21, 0x71,
- + 0x4F, 0x4C, 0x21, 0xF3, 0x71, 0x4F, 0x53, 0x20, 0x1A, 0x42, 0xF1, 0x22, 0xD1, 0x71, 0xFB, 0x22,
- + 0x71, 0x62, 0x20, 0xD1, 0x22, 0x11, 0x70, 0x82, 0x16, 0x7C, 0x37, 0x21, 0x1C, 0x16, 0x21, 0x7C,
- + 0x1B, 0x23, 0x44, 0x40, 0xCA, 0x10, 0xFD, 0xDC, 0x4A, 0x42, 0xF1, 0x21, 0xDC, 0x71, 0x21, 0x7C,
- + 0x6E, 0xD8, 0x10, 0xDC, 0x21, 0x1C, 0x32, 0x49, 0x22, 0x10, 0x45, 0x21, 0x47, 0x70, 0x21, 0x4A,
- + 0x4C, 0x21, 0x75, 0x40, 0x53, 0x20, 0xD0, 0x7B, 0x42, 0xBF, 0xF1, 0x22, 0xD0, 0x71, 0x22, 0x70,
- + 0x62, 0x20, 0xD0, 0xB3, 0x22, 0x10, 0x32, 0x4A, 0x2B, 0x31, 0x21, 0x7B, 0xEF, 0x12, 0x7B, 0xFA,
- + 0xF5, 0x11, 0xDB, 0xAB, 0x41, 0xF1, 0x21, 0xDB, 0x71, 0x21, 0x74, 0x45, 0x30, 0xB0, 0x40, 0x1B,
- + 0x32, 0x48, 0x51, 0x21, 0x11, 0xBE, 0x11, 0xE5, 0x71, 0xC3, 0x12, 0x71, 0xC9, 0x11, 0xD8, 0x42,
- + 0xF1, 0x21, 0xD1, 0x73, 0x71, 0x21, 0x2B, 0x40, 0xDE, 0x40, 0x11, 0x70, 0x51, 0xDF, 0x16, 0x57,
- + 0x51, 0x21, 0x10, 0xBE, 0x11, 0x70, 0xD5, 0x22, 0x70, 0xDB, 0x21, 0x7D, 0xD0, 0x07, 0x51, 0xF1,
- + 0x21, 0xD0, 0x71, 0x21, 0x8D, 0x40, 0xAA, 0x0C, 0x50, 0x10, 0xF0, 0x49, 0x1E, 0xBE, 0x10, 0x7E,
- + 0xA8, 0x21, 0x7E, 0xBA, 0xAE, 0x20, 0xDE, 0x33, 0x50, 0xF1, 0xDE, 0x71, 0x32, 0x20, 0xDE, 0xD9,
- + 0x1E, 0xF0, 0x49, 0xE3, 0x31, 0x75, 0x4D, 0xC4, 0x10, 0x75, 0x4D, 0x77, 0x24, 0xF0, 0xD5, 0x58,
- + 0x50, 0xF1, 0xD5, 0x71, 0xFD, 0x30, 0xAF, 0xD5, 0x15, 0x70, 0x51, 0xF2, 0x26, 0x51, 0xB5, 0x31,
- + 0x72, 0xEA, 0xE9, 0x31, 0x72, 0xEF, 0x30, 0xD2, 0x7D, 0x50, 0xF1, 0xD2, 0x71, 0xA6, 0xCF, 0x30,
- + 0xD2, 0x12, 0x68, 0x59, 0x87, 0x31, 0x73, 0xA8, 0x21, 0x73, 0xBA, 0xAE, 0x20, 0xD3, 0xA2, 0x50,
- + 0xF1, 0xD3, 0x71, 0xA1, 0x30, 0xD3, 0xD9, 0x13, 0x68, 0x59, 0x44, 0x21, 0x74, 0x4B, 0xC4, 0x10,
- + 0x74, 0x4B, 0x77, 0x24, 0xF0, 0xD4, 0xC7, 0x50, 0xF1, 0xD4, 0x71, 0x61, 0x20, 0xCF, 0xD4, 0x14,
- + 0x70, 0x51, 0xC4, 0x47, 0x11, 0x41, 0x71, 0x21, 0x9A, 0xA8, 0x20, 0xD2, 0xE7, 0x50, 0x24, 0xF0,
- + 0xE6, 0x40, 0xB5, 0x20, 0xD1, 0xA5, 0x72, 0x2B, 0x40, 0xD1, 0xEF, 0x40, 0xC4, 0x47, 0x16, 0x16,
- + 0x20, 0x76, 0xB9, 0x21, 0xC3, 0x51, 0x0F, 0x60, 0x24, 0xF0, 0xD6, 0x15, 0x61, 0xF1, 0x7F, 0xD6,
- + 0x71, 0x76, 0x23, 0xF3, 0xD6, 0x16, 0xD7, 0x59, 0x72, 0x59, 0x31, 0x77, 0x79, 0x22, 0x37, 0x60,
- + 0x24, 0xF0, 0xD7, 0x3D, 0x61, 0xB7, 0xF1, 0xD7, 0x71, 0x73, 0x30, 0xD7, 0x17, 0xD7, 0x58, 0x85,
- + 0x55, 0x1F, 0xD0, 0x20, 0x7F, 0xBB, 0x31, 0x7F, 0xC1, 0x30, 0xDF, 0x64, 0x60, 0xF7, 0xF1, 0xDF,
- + 0x71, 0x03, 0x20, 0xDF, 0x1F, 0x70, 0x85, 0x6E, 0xF2, 0x26, 0x86, 0x22, 0x16, 0xBE, 0x10, 0x22,
- + 0x76, 0x77, 0x42, 0xF5, 0x76, 0x7E, 0x41, 0xD6, 0x8B, 0x61, 0xF1, 0x22, 0xD6, 0x71, 0xB9, 0x22,
- + 0x22, 0x60, 0x90, 0x60, 0x16, 0x70, 0x86, 0xDF, 0x16, 0x86, 0x55, 0x19, 0xBE, 0x10, 0x79, 0xEF,
- + 0x11, 0x79, 0xF5, 0x10, 0xD9, 0xB7, 0x60, 0xB7, 0xF1, 0xD9, 0x71, 0x17, 0x30, 0xD9, 0x19, 0xA2,
- + 0x69, 0x1A, 0xF6, 0xBE, 0x10, 0x7A, 0x48, 0xC4, 0x10, 0x7A, 0x48, 0x24, 0xF0, 0xDD, 0xDA, 0xDC,
- + 0x60, 0xF1, 0xDA, 0x71, 0xBC, 0x20, 0xDA, 0x1A, 0xAA, 0xA2, 0x69, 0x18, 0xBE, 0x10, 0x78, 0xA8,
- + 0x21, 0x78, 0xAE, 0x20, 0xD8, 0x6E, 0x01, 0x70, 0xF1, 0xD8, 0x71, 0x90, 0x20, 0xD8, 0x18, 0xA2,
- + 0x68, 0x9F, 0x87, 0x1B, 0x41, 0x24, 0xFA, 0xA6, 0x42, 0xAC, 0x41, 0xDB, 0xF6, 0xB3, 0x41, 0xDB,
- + 0x71, 0x45, 0x30, 0xDB, 0x1B, 0x70, 0x87, 0x54, 0x1E, 0x70, 0x16, 0x74, 0x1C, 0x1E, 0x70, 0x7C,
- + 0xBB, 0x31, 0x7C, 0xC1, 0x30, 0xDD, 0xDC, 0x4B, 0x70, 0xF1, 0xDC, 0x71, 0x5C, 0x40, 0xDC, 0x1C,
- + 0xAA, 0x36, 0x79, 0x1D, 0x1E, 0x70, 0x7D, 0x1C, 0x21, 0x7D, 0x23, 0x20, 0xDD, 0x6E, 0x70, 0x70,
- + 0xF1, 0xDD, 0x71, 0xD7, 0x10, 0xDD, 0x1D, 0x36, 0x77, 0xFE, 0xE2, 0x12, 0x40, 0xD1, 0x70, 0x71,
- + 0xF2, 0xF1, 0xD2, 0xBF, 0x70, 0x41, 0x71, 0xFC, 0xF2, 0xF1, 0x91, 0x70, 0x23, 0xEB, 0xFB, 0x72,
- + 0x97, 0x70, 0x70, 0x9E, 0x70, 0x71, 0x81, 0xD1, 0xBF, 0x41, 0x71, 0xF9, 0xA2, 0x62, 0x0F, 0x8A,
- + 0x7A, 0x42, 0x50, 0x98, 0x77, 0xBF, 0x70, 0xA5, 0x7F, 0x8F, 0x71, 0x85, 0x93, 0x71, 0x47, 0x98,
- + 0x73, 0xF1, 0x85, 0x9E, 0x71, 0xE8, 0x70, 0xCD, 0x77, 0xA3, 0x80, 0x62, 0x0C, 0x4A, 0x8A, 0x76,
- + 0x86, 0xE4, 0x78, 0x86, 0xF0, 0x7F, 0x02, 0x89, 0x81, 0x93, 0x71, 0x45, 0x44, 0x98, 0x73, 0x81,
- + 0x9E, 0x71, 0x3E, 0x80, 0xCD, 0x74, 0x42, 0xFF, 0x7C, 0x05, 0x83, 0xE4, 0x78, 0x83, 0x1B, 0x8B,
- + 0x54, 0x8D, 0x39, 0x82, 0xE8, 0x74, 0x45, 0x82, 0x2A, 0x1F, 0x87, 0x43, 0xFF, 0x7C, 0x82, 0xE4,
- + 0x78, 0x82, 0x9C, 0x8F, 0x02, 0x89, 0xD4, 0xE4, 0x78, 0x1B, 0x8B, 0x44, 0xFF, 0x72, 0x0E, 0xE2,
- + 0x12, 0x2A, 0x23, 0xFF, 0x4F, 0x21, 0xFB, 0x23, 0x1C, 0x21, 0x40, 0x24, 0xFF, 0xFA, 0x40, 0xD1,
- + 0x23, 0x1C, 0x71, 0x70, 0xF2, 0xE9, 0xF1, 0xC1, 0x30, 0x1B, 0x91, 0xF1, 0x19, 0x91, 0x4F, 0x24,
- + 0xF6, 0x3F, 0x23, 0x1C, 0xF2, 0xF1, 0x24, 0xFB, 0x19, 0x90, 0xCF, 0x72, 0xB5, 0x48, 0xAD, 0x71,
- + 0x07, 0x05, 0x93, 0x21, 0x44, 0x0D, 0x90, 0x18, 0x3A, 0x11, 0x94, 0x18, 0x19, 0x9F, 0xF6, 0x23,
- + 0x18, 0x2E, 0x9F, 0xE2, 0x12, 0x7F, 0x29, 0x2E, 0x49, 0x21, 0xFB, 0x24, 0x10, 0x11, 0x93, 0x3B,
- + 0x24, 0x10, 0x54, 0x9F, 0xF6, 0x24, 0x10, 0x69, 0x9F, 0x7B, 0x93, 0x33, 0x2B, 0x4E, 0x0D, 0x90,
- + 0x86, 0x94, 0x23, 0x10, 0x62, 0x82, 0x1D, 0x95, 0xA0, 0x62, 0x82, 0x29, 0x91, 0xA3, 0x92, 0x6E,
- + 0x83, 0xD1, 0x70, 0x45, 0xAD, 0x71, 0x04, 0x56, 0x7B, 0x93, 0x29, 0x40, 0x0D, 0x90, 0x14, 0x11,
- + 0x94, 0x14, 0x8F, 0x9F, 0x67, 0xF6, 0x23, 0x14, 0xA4, 0x9F, 0x7B, 0x93, 0x26, 0x45, 0x83, 0x90,
- + 0xC2, 0x4B, 0x94, 0x24, 0x53, 0x9F, 0xA0, 0x90, 0x68, 0x9F, 0x7A, 0x94, 0x23, 0x4A, 0xD7, 0x21,
- + 0xFB, 0x22, 0x10, 0x94, 0x22, 0x18, 0x9F, 0x24, 0xF6, 0xA9, 0x22, 0x2D, 0x9F, 0x7A, 0x94, 0x20,
- + 0x0C, 0x90, 0x24, 0xFF, 0x94, 0x24, 0xB0, 0x07, 0xAF, 0xA0, 0x90, 0x1C, 0xAF, 0x3F, 0x93, 0x28,
- + 0x2E, 0x47, 0x90, 0x24, 0x82, 0x10, 0x94, 0x24, 0x7D, 0xAF, 0xA0, 0x90, 0x92, 0xAA, 0xAC, 0x72,
- + 0x3F, 0x93, 0x4C, 0xDF, 0x21, 0xD4, 0x4D, 0x21, 0xD5, 0x52, 0x00, 0x42, 0x21, 0xFF, 0x14, 0x25,
- + 0x71, 0x28, 0x2B, 0x95, 0xD0, 0x70, 0xF9, 0xA5, 0xA1, 0x12, 0xE2, 0x12, 0x21, 0x4E, 0x21, 0xD8,
- + 0x22, 0x57, 0x40, 0x21, 0xD9, 0x26, 0xB2, 0x18, 0x2C, 0xB0, 0x29, 0x30, 0xBB, 0xFF, 0x23, 0x44,
- + 0x21, 0xD6, 0x23, 0x45, 0x21, 0xD7, 0xEA, 0x26, 0xB2, 0x16, 0x2C, 0xB0, 0x27, 0x30, 0xBB, 0x46,
- + 0x21, 0xD2, 0xAF, 0x24, 0x40, 0x21, 0xD3, 0x26, 0xB2, 0x12, 0x2C, 0xB0, 0x25, 0xDC, 0x99, 0x10,
- + 0x33, 0xB8, 0x25, 0x73, 0x21, 0x94, 0x10, 0x6B, 0x2A, 0xBF, 0x9A, 0xD0, 0x70, 0x41, 0xF4, 0xA7,
- + 0x32, 0xB4, 0x70, 0x5F, 0xC1, 0xC0, 0xA2, 0x21, 0x01, 0x9D, 0xB0, 0x47, 0xA1, 0xB0, 0x7B, 0x28,
- + 0x9F, 0x90, 0xBF, 0x71, 0x6B, 0x27, 0x99, 0xA6, 0xBF, 0xDA, 0x9D, 0xB0, 0x49, 0xA1, 0xB0, 0x25,
- + 0x9E, 0xC1, 0xBF, 0x71, 0x6B, 0x53, 0x24, 0x98, 0xD7, 0xBF, 0x9D, 0xB0, 0x4F, 0xA1, 0xB0, 0x22,
- + 0x42, 0x00, 0xF6, 0xF4, 0xBF, 0x21, 0x97, 0x08, 0xCF, 0x25, 0x73, 0x22, 0x4B, 0xDF, 0x25, 0x71,
- + 0x6C, 0x2F, 0x9C, 0x23, 0xCF, 0x71, 0x6C, 0x79, 0x2E, 0x99, 0x10, 0x3B, 0xCC, 0x00, 0x25, 0x73,
- + 0x46, 0x4F, 0xC0, 0x95, 0x2C, 0x53, 0xCD, 0x22, 0xEC, 0xB0, 0x6C, 0x98, 0x11, 0x3B, 0xCF, 0x22,
- + 0xAD, 0x4A, 0x4F, 0xC0, 0x29, 0x9B, 0x54, 0xCC, 0x40, 0x4F, 0xC0, 0x28, 0xDC, 0x99, 0x12, 0x33,
- + 0xB3, 0x25, 0x73, 0x41, 0x4F, 0xC0, 0x27, 0x94, 0x5A, 0xCA, 0xC9, 0x42, 0x4F, 0xC0, 0x26, 0x92,
- + 0xCA, 0xC9, 0x43, 0x4F, 0xC0, 0x2B, 0x25, 0x90, 0xCA, 0xC9, 0x44, 0x4F, 0xC0, 0x23, 0xF1, 0xB0,
- + 0xCC, 0xC5, 0x4C, 0x98, 0xB4, 0x1D, 0xC0, 0x6C, 0x22, 0x38, 0xC0, 0xCC, 0xC7, 0x21, 0xC4, 0xC1,
- + 0x35, 0x21, 0xDB, 0xCA, 0x21, 0xD6, 0xC1, 0x20, 0x91, 0x29, 0xDA, 0xE8, 0xC0, 0x63, 0x6D, 0x2E,
- + 0x11, 0xD8, 0x9D, 0xB0, 0xFA, 0xC0, 0x6D, 0x2D, 0xB4, 0xC0, 0x3A, 0x14, 0xDC, 0x21, 0x7E, 0xC0,
- + 0x6D, 0x2C, 0x93, 0x29, 0xDA, 0xBB, 0xB0, 0x53, 0x6D, 0x2B, 0xFF, 0xCA, 0x87, 0xD1, 0x29, 0x61,
- + 0xDB, 0x48, 0x5D, 0xD0, 0x49, 0x28, 0x74, 0xD8, 0x97, 0xD4, 0x27, 0x07, 0xC0, 0x14, 0xDC, 0x22,
- + 0x6F, 0xD1, 0x35, 0x26, 0xFF, 0xCA, 0x22, 0x0C, 0xD0, 0x6D, 0x24, 0x42, 0x02, 0xF4, 0xD6, 0x86,
- + 0x94, 0x10, 0x6D, 0x23, 0xA5, 0xB0, 0xF2, 0xD8, 0x87, 0xD1, 0x27, 0xDB, 0x22, 0x78, 0x9A, 0xD1,
- + 0x3A, 0xD9, 0x8C, 0xC5, 0x4D, 0x25, 0x71, 0x6E, 0x52, 0xC1, 0x8A, 0xF2, 0xD8, 0x4E, 0x4F, 0xE0,
- + 0x2E, 0xD6, 0xB0, 0xF2, 0xD8, 0x1D, 0xC0, 0x6E, 0x55, 0x2D, 0xC9, 0xCA, 0x23, 0xC4, 0xC0, 0x6E,
- + 0x8B, 0xDB, 0x23, 0xD6, 0xC0, 0x31, 0x6E, 0x9E, 0xD9, 0x98, 0xB4, 0x7E, 0xC0, 0x6E, 0x29, 0x66,
- + 0xEA, 0x61, 0xE1, 0x09, 0x28, 0x28, 0xDB, 0x0C, 0xD0, 0x6E, 0xDA, 0xCB, 0xB1, 0xE1, 0xEC, 0xCB,
- + 0xB1, 0xE1, 0x60, 0xFE, 0xCB, 0xB1, 0xE1, 0x10, 0xD9, 0x9D, 0xB0, 0xAF, 0xC0, 0x6E, 0x22, 0xC4,
- + 0xDB, 0xA6, 0x4E, 0xC0, 0x6E, 0x21, 0xD7, 0xD8, 0xAF, 0xE3, 0x20, 0xC9, 0xCA, 0x21, 0x9F, 0x4C,
- + 0x25, 0x71, 0x6F, 0x2F, 0x8C, 0xDB, 0x4E, 0xE0, 0x6F, 0x99, 0x2E, 0xEF, 0xDB, 0xD6, 0xC0, 0x6F,
- + 0x2C, 0x02, 0xEB, 0xE8, 0xC0, 0x6F, 0x99, 0x2B, 0x15, 0xEB, 0xBF, 0xD0, 0x6F, 0x2A, 0x28, 0xDA,
- + 0x7E, 0xC0, 0x6F, 0x68, 0x4F, 0xB1, 0xF2, 0xD8, 0x57, 0xF1, 0x28, 0xED, 0xED, 0x6F, 0x27, 0xFF,
- + 0xCA, 0xD5, 0x23, 0x90, 0xF1, 0x25, 0x02, 0xEA, 0x23, 0xFA, 0xC0, 0x6F, 0x24, 0x4A, 0x15, 0xEA,
- + 0x23, 0xB5, 0xF1, 0x23, 0x28, 0xDA, 0xFF, 0xF2, 0x22, 0xDB, 0xCA, 0xEA, 0xFF, 0xF2, 0x21, 0x4E,
- + 0xDA, 0x23, 0x4E, 0xC0, 0x61, 0x2F, 0x2F, 0xAC, 0xF2, 0xFB, 0x57, 0xF0, 0x61, 0x2F, 0x65, 0xEB,
- + 0x23, 0x4E, 0xE0, 0x61, 0x73, 0x2F, 0x2D, 0xBA, 0xFA, 0xFF, 0xF1, 0x61, 0x2F, 0x2C, 0x3E, 0x0B,
- + 0x6E, 0x61, 0xE0, 0x61, 0x2F, 0x2A, 0xF2, 0xFE, 0x61, 0x2F, 0xB5, 0xEB, 0x5D, 0x24, 0xD6, 0xC0,
- + 0x61, 0x2F, 0x28, 0xBA, 0xFA, 0x24, 0xBB, 0xB0, 0xD7, 0x61, 0x2F, 0x27, 0x4E, 0xDA, 0x24, 0xBF,
- + 0xD0, 0x61, 0x2F, 0x9C, 0xF1, 0xFB, 0x56, 0xF1, 0x61, 0x2F, 0x24, 0x66, 0xEB, 0xE8, 0xC0, 0x61,
- + 0x73, 0x2F, 0x23, 0xCA, 0x0B, 0xEC, 0xB0, 0x61, 0x2F, 0x22, 0xDE, 0x0B, 0x4E, 0xAF, 0xC0, 0x61,
- + 0x2F, 0x20, 0x02, 0xE8, 0x98, 0xB4, 0x23, 0xD8, 0x01, 0xB3, 0x2E, 0x2F, 0xDB, 0xCA, 0x73, 0xE1,
- + 0x61, 0x2E, 0x6E, 0xFB, 0x23, 0x62, 0xEC, 0x01, 0x2E, 0x82, 0xC1, 0x7C, 0xE8, 0x28, 0x11, 0x2E,
- + 0x2B, 0x37, 0xFA, 0x2D, 0x23, 0x3C, 0x11, 0x2E, 0x2A, 0x3B, 0xEF, 0x23, 0x69, 0x12, 0xC3, 0xDB,
- + 0x92, 0xBD, 0x13, 0x27, 0x18, 0x0B, 0x69, 0x12, 0x26, 0x8C, 0xEB, 0x69, 0x12, 0x24, 0xD4, 0xC0,
- + 0xB0, 0xC7, 0x1D, 0x23, 0x74, 0xDF, 0x24, 0x14, 0x11, 0x2E, 0x22, 0x5A, 0xED, 0xCA, 0x24, 0x88,
- + 0x01, 0x2E, 0x20, 0x61, 0xDA, 0x24, 0x0C, 0xD0, 0xD7, 0x61, 0x2D, 0x2F, 0x15, 0xEA, 0x24, 0xA0,
- + 0xB0, 0x61, 0x2D, 0x38, 0x68, 0xC1, 0xB9, 0x08, 0x7E, 0xC0, 0x61, 0x2D, 0x2D, 0xED, 0xC8, 0x98,
- + 0xB4, 0x92, 0xD8, 0x01, 0x2D, 0x94, 0xFB, 0xEC, 0x01, 0x2D, 0xA7, 0xFB, 0x28, 0x11, 0x2D, 0x99,
- + 0x29, 0xDB, 0xCA, 0x3C, 0x11, 0x2D, 0x28, 0x4E, 0xDA, 0x4C, 0x01, 0x2D, 0xF5, 0x26, 0x11, 0xDD,
- + 0x43, 0x24, 0x31, 0x60, 0xBD, 0x40, 0xD0, 0xFF, 0x75, 0x21, 0xA0, 0x41, 0x60, 0x8F, 0xD2, 0x75,
- + 0xFF, 0x74, 0x61, 0x2D, 0x23, 0x95, 0xD1, 0x71, 0xA9, 0x7F, 0x71, 0xD0, 0x06, 0x21, 0x20, 0x46,
- + 0xB3, 0xDF, 0x81, 0xFF, 0x72, 0xC0, 0xA2, 0x41, 0xD1, 0x71, 0xC0, 0xA4, 0xDF, 0x21, 0x20, 0x41,
- + 0xD0, 0x70, 0x10, 0x30, 0x41, 0x71, 0xFF, 0xE0, 0x71, 0x30, 0x60, 0x8F, 0x71, 0xE0, 0x40, 0xFE,
- + 0xF4, 0x20, 0xBF, 0x40, 0xD0, 0x72, 0x30, 0xC0, 0xA7, 0xDF, 0x72, 0x30, 0x81, 0x72, 0xE0, 0x1F,
- + 0x30, 0xA4, 0x40, 0xED, 0xB1, 0x3C, 0xB0, 0x20, 0x41, 0x43, 0x30, 0x20, 0x20, 0x00, 0xFF, 0x0D,
- + 0x0B, 0x0A, 0x08, 0x02, 0x09, 0x01, 0x05, 0xFF, 0x0C, 0x0E, 0x03, 0x07, 0x04, 0x0F, 0x06, 0x0B,
- + 0xFF, 0x0C, 0x08, 0x09, 0x0F, 0x04, 0x03, 0x00, 0x0D, 0x7F, 0x01, 0x0A, 0x0E, 0x06, 0x02, 0x07,
- + 0x05, 0x62, 0x30, 0xFF, 0x0B, 0x06, 0x09, 0x00, 0x01, 0x0A, 0x05, 0x0E, 0xFF, 0x0D, 0x0C, 0x02,
- + 0x08, 0x07, 0x0F, 0x05, 0x03, 0xFF, 0x0B, 0x04, 0x0A, 0x09, 0x01, 0x0C, 0x06, 0x0E, 0xFF, 0x08,
- + 0x00, 0x07, 0x02, 0x0D, 0x02, 0x04, 0x0A, 0xFF, 0x0F, 0x0C, 0x01, 0x0E, 0x0B, 0x00, 0x09, 0x03,
- + 0xFF, 0x08, 0x0D, 0x07, 0x06, 0x05, 0x04, 0x03, 0x05, 0xFB, 0x0A, 0x06, 0x95, 0x30, 0x0E, 0x02,
- + 0x0C, 0x0F, 0x0D, 0xFF, 0x07, 0x08, 0x01, 0x05, 0x0A, 0x03, 0x02, 0x07, 0xFF, 0x04, 0x0D, 0x0E,
- + 0x01, 0x08, 0x00, 0x0F, 0x0C, 0xFF, 0x09, 0x06, 0x0B, 0x05, 0x0C, 0x09, 0x03, 0x01, 0xFF, 0x0D,
- + 0x07, 0x04, 0x06, 0x08, 0x0B, 0x02, 0x0A, 0xFF, 0x00, 0x0F, 0x0E, 0x05, 0x0D, 0x09, 0x01, 0x08,
- + 0xFF, 0x06, 0x04, 0x03, 0x0A, 0x07, 0x02, 0x0E, 0x00, 0xFF, 0x0B, 0x0C, 0x0F, 0x71, 0x51, 0x25,
- + 0xFA, 0x31, 0x5F, 0xD1, 0x32, 0xF6, 0x71, 0x54, 0xE0, 0x34, 0x57, 0xE0, 0x34, 0xF5, 0x5A, 0xE0,
- + 0x34, 0x5D, 0xE0, 0x33, 0x70, 0x72, 0x69, 0x6E, 0xFF, 0x74, 0x66, 0x00, 0x69, 0x63, 0x67, 0x5F,
- + 0x72, 0xFF, 0x75, 0x6E, 0x5F, 0x69, 0x6E, 0x5F, 0x74, 0x68, 0xFF, 0x72, 0x65, 0x61, 0x64, 0x73,
- + 0x00, 0x6D, 0x61, 0xFF, 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x66, 0x72, 0x65, 0xFF, 0x65, 0x00, 0x65,
- + 0x78, 0x69, 0x74, 0x00, 0x73, 0xFF, 0x6E, 0x69, 0x70, 0x70, 0x65, 0x74, 0x5F, 0x64, 0xFF, 0x65,
- + 0x69, 0x6E, 0x69, 0x74, 0x69, 0x61, 0x6C, 0xC7, 0x69, 0x7A, 0x65, 0x30, 0x46, 0x3B, 0x4F, 0x17,
- + 0x44, 0x5F, 0x63, 0x57, 0x6F, 0x75, 0x6E, 0x37, 0x41, 0x63, 0x45, 0x47, 0x64, 0x6D, 0x4A, 0xFF,
- + 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x5F, 0xBF, 0x61, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x30,
- + 0x48, 0x63, 0x7F, 0x72, 0x79, 0x70, 0x74, 0x00, 0x20, 0x20, 0x82, 0x90, 0xFF, 0x71, 0x21, 0x29,
- + 0x9D, 0x20, 0x21, 0x28, 0x09, 0xFF, 0x20, 0x69, 0x6D, 0x70, 0x6F, 0x72, 0x74, 0x20, 0xB7, 0x66,
- + 0x75, 0x6E, 0x92, 0x42, 0x20, 0x63, 0x21, 0x40, 0x20, 0xFF, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x0A,
- + 0x00, 0x60, 0xFF, 0xBB, 0x40, 0xD4, 0x77, 0x30, 0x40, 0xF9, 0x24, 0xEF, 0xA6, 0x40, 0xD0, 0x78,
- + 0xD7, 0x40, 0x23, 0xA4, 0x74, 0xFF, 0x43, 0xF8, 0xD3, 0x70, 0x43, 0xF8, 0x78, 0x31, 0xFF, 0xFA,
- + 0xD1, 0x73, 0x77, 0x31, 0xFA, 0xD2, 0x71, 0xFF, 0x30, 0x72, 0x30, 0x76, 0x2E, 0x9B, 0xC0, 0x21,
- + 0x5F, 0xA0, 0x71, 0x32, 0x72, 0xE2, 0xE8, 0x43, 0x31, 0xEF, 0x41, 0xD7, 0xE1, 0x70, 0x81, 0xDD,
- + 0x40, 0x70, 0xAE, 0x70, 0x00, 0x74, 0xFD, 0x81, 0xD5, 0x40, 0x74, 0xF9, 0xA2, 0x64, 0x0A, 0xB5,
- + 0xEE, 0xF4, 0x20, 0xBB, 0x40, 0xD3, 0xD6, 0x42, 0xA1, 0x68, 0x47, 0xF7, 0x21, 0xFB, 0xD4, 0xDC,
- + 0x43, 0x22, 0xAA, 0x73, 0x43, 0xD7, 0xF8, 0xD2, 0x72, 0xF0, 0x40, 0xD1, 0xE8, 0x43, 0x30, 0x71,
- + 0xFF, 0x30, 0x76, 0x29, 0x95, 0xC0, 0xA9, 0x74, 0x71, 0x73, 0xE2, 0x76, 0x40, 0x51, 0x0D, 0x57,
- + 0x0A, 0x73, 0x81, 0x28, 0x50, 0xDF, 0x73, 0xF9, 0xA2, 0x63, 0x04, 0x22, 0x50, 0x71, 0x21, 0xFF,
- + 0x30, 0x72, 0xE0, 0x71, 0x21, 0x31, 0x72, 0xE1, 0xFF, 0x71, 0x22, 0x34, 0x73, 0xE0, 0x71, 0x22,
- + 0x35, 0x5B, 0x73, 0xE1, 0x71, 0x50, 0x22, 0x54, 0x71, 0x51, 0x50, 0xF4, 0x20, 0xD5, 0xBC, 0xF8,
- + 0x20, 0x22, 0xE7, 0x30, 0xD1, 0xD7, 0x40, 0x21, 0xA2, 0xD5, 0x75, 0xE8, 0x40, 0x71, 0x0B, 0x53,
- + 0x71, 0x12, 0x51, 0x61, 0x0E, 0xDE, 0xF8, 0x21, 0x50, 0x25, 0xFA, 0xD2, 0x37, 0x51, 0xA2, 0x61,
- + 0x7E, 0xE6, 0xA1, 0xD3, 0x40, 0xD1, 0x75, 0x71, 0x72, 0x0B, 0x50, 0xF5, 0x73, 0xCA, 0x51, 0xE2,
- + 0xAA, 0x51, 0x43, 0xF2, 0xD1, 0x72, 0xF6, 0xAE, 0x52, 0x06, 0xB4, 0xF4, 0x21, 0x75, 0x76, 0x24,
- + 0xFB, 0x7F, 0x43, 0x24, 0xF6, 0xC0, 0x22, 0xAE, 0x24, 0xE7, 0xA0, 0xFD, 0x30, 0x9A, 0x50, 0x47,
- + 0x24, 0xF1, 0xD2, 0x06, 0x75, 0xBF, 0x51, 0xD5, 0x76, 0x51, 0xD6, 0x75, 0xF6, 0x50, 0xD0, 0xF7,
- + 0x76, 0x30, 0xF4, 0xFB, 0x40, 0x70, 0x71, 0xF4, 0x70, 0x9F, 0x23, 0xF2, 0x24, 0xF6, 0x72, 0xED,
- + 0x50, 0x01, 0x80, 0x0F, 0xFB, 0x75, 0xF1, 0x07, 0x61, 0xF1, 0xF4, 0x25, 0xFA, 0xC0, 0xFF, 0xAA,
- + 0x70, 0xA9, 0x75, 0x81, 0xD5, 0x76, 0x81, 0xAF, 0xD6, 0x61, 0x0A, 0xF0, 0x10, 0x30, 0x01, 0x3A,
- + 0x60, 0x71, 0xFF, 0x28, 0x9D, 0xA6, 0x21, 0x23, 0x29, 0xFA, 0x22, 0xFB, 0xF0, 0x00, 0x4A, 0x31,
- + 0x20, 0x60, 0xB0, 0x4A, 0xD6, 0xFF, 0x21, 0x72, 0x21, 0x71, 0x28, 0x9A, 0x41, 0xF2, 0xFF, 0xD7,
- + 0x21, 0x72, 0xD8, 0x10, 0x21, 0x71, 0x23, 0xFF, 0x93, 0x7B, 0x22, 0xC2, 0xC0, 0x21, 0xAB, 0x7B,
- + 0xFF, 0x60, 0xCE, 0xC0, 0x21, 0xAA, 0x7B, 0x60, 0xCD, 0xFE, 0x6C, 0x60, 0x21, 0x71, 0x2E, 0x91,
- + 0x23, 0x2E, 0x4D, 0x9F, 0xF0, 0xE0, 0x60, 0x4F, 0x21, 0x8C, 0x71, 0x80, 0x61, 0x60, 0xF5, 0x4E,
- + 0x85, 0x62, 0x4D, 0x80, 0x61, 0x20, 0x71, 0x21, 0x9D, 0xDF, 0xAE, 0x24, 0xF2, 0x21, 0x32, 0xF6,
- + 0x51, 0xAB, 0x72, 0xDB, 0x42, 0x9E, 0x8D, 0x61, 0x72, 0xEB, 0xA6, 0x65, 0x75, 0xF6, 0xFB, 0x42,
- + 0xD2, 0x9A, 0x65, 0xA4, 0x40, 0x45, 0x95, 0xD2, 0xF3, 0x72, 0xC1, 0xB2, 0x61, 0x4B, 0x61, 0xBF,
- + 0x68, 0xFC, 0xD0, 0xF1, 0x70, 0x30, 0x50, 0x0B, 0x60, 0x49, 0x31, 0x11, 0x00, 0x20, 0x05, 0xBF,
- + 0x60, 0xBF, 0x73, 0x81, 0xD2, 0x73, 0xEC, 0x50, 0x21, 0xFF, 0xA4, 0x73, 0x25, 0xFA, 0x81, 0xD3,
- + 0xF1, 0xA7, 0x7E, 0xE7, 0x61, 0xA8, 0x60, 0x02, 0x73, 0x72, 0xFC, 0x43, 0x30, 0xFD, 0x24, 0x82,
- + 0x90, 0xD4, 0x03, 0x73, 0x51, 0xD3, 0x73, 0xB6, 0x06, 0x61, 0x74, 0x30, 0x12, 0x63, 0x74, 0x31,
- + 0x19, 0x62, 0x61, 0xF7, 0x07, 0x70, 0x2F, 0x29, 0x90, 0x21, 0xAE, 0x70, 0x2F, 0xF7, 0x2F, 0x20,
- + 0x40, 0xE9, 0x60, 0xA0, 0x70, 0x74, 0x32, 0xEF, 0x24, 0xF6, 0xA5, 0x80, 0x07, 0x70, 0x0D, 0x73,
- + 0x83, 0xFF, 0xD3, 0x09, 0x80, 0x73, 0x82, 0xD3, 0x04, 0x80, 0xE8, 0x66, 0x50, 0xFB, 0x63, 0x3A,
- + 0x61, 0x80, 0x52, 0x70, 0x00, 0x00, 0xFF, 0xAF, 0x00, 0x71, 0x22, 0x56, 0x49, 0x62, 0x00, 0x62,
- + 0x70, 0xD0, 0xA9, 0x13, 0x62, 0x71, 0x68, 0x73, 0xD7, 0x67, 0x78, 0xEA, 0x67, 0x78, 0xF1, 0xAA,
- + 0x67, 0x78, 0xF6, 0x67, 0x78, 0x05, 0x62, 0x70, 0x04, 0x62, 0x70, 0xFB, 0x7E, 0x67, 0x74, 0xFB,
- + 0x12, 0x00, 0x00, 0x10, 0x14, 0x68, 0x73, 0xA5, 0xEF, 0xB3, 0x70, 0x23, 0xB7, 0x74, 0x62, 0x71,
- + 0x3C, 0xB7, 0x74, 0x03, 0xAA, 0x62, 0x70, 0x4B, 0xB7, 0x74, 0x1A, 0x62, 0x70, 0x62, 0xB7, 0x74,
- + 0xC0, 0xAA, 0xB3, 0x70, 0x06, 0x62, 0x70, 0x48, 0x9B, 0x78, 0x11, 0x62, 0x70, 0x1D, 0xAA, 0x62,
- + 0x70, 0x29, 0x62, 0x70, 0x35, 0x62, 0x70, 0x44, 0x62, 0x70, 0x49, 0xAA, 0x62, 0x70, 0x51, 0x62,
- + 0x70, 0x55, 0x62, 0x70, 0x5D, 0x62, 0x70, 0x61, 0xAA, 0x62, 0x70, 0x69, 0x62, 0x70, 0x6D, 0x62,
- + 0x70, 0x75, 0x62, 0x70, 0x79, 0xAA, 0x62, 0x70, 0x81, 0x62, 0x70, 0x85, 0x62, 0x70, 0x8D, 0x62,
- + 0x70, 0x94, 0xFE, 0x1F, 0x81, 0x15, 0x00, 0x00, 0x2E, 0x2E, 0x2F, 0x67, 0xFF, 0x65, 0x6E, 0x65,
- + 0x72, 0x61, 0x74, 0x6F, 0x72, 0x7D, 0x2F, 0x6E, 0x40, 0x2E, 0x64, 0x62, 0x67, 0x00
- +};
- +
- +static int32_t offtin(uint8_t *buf)
- +{
- + int32_t y;
- + y = buf[7] & 0x7F;
- + y = y * 256; y += buf[6];
- + y = y * 256; y += buf[5];
- + y = y * 256; y += buf[4];
- + y = y * 256; y += buf[3];
- + y = y * 256; y += buf[2];
- + y = y * 256; y += buf[1];
- + y = y * 256; y += buf[0];
- + if(buf[7] & 0x80) y =- y;
- + return y;
- +}
- +
- +static int32_t bspatch(uint8_t *dest, uint8_t *src, int32_t src_len, uint8_t *patch)
- +{
- + int32_t i, newsize, bzctrllen, bzdatalen, oldpos, newpos, ctrl[3];
- + uint8_t *cstream, *dstream, *estream;
- +
- + if(memcmp(patch, "BSDIFF40", 8)) return -1;
- +
- + bzctrllen = offtin(patch + 8);
- + bzdatalen = offtin(patch + 16);
- + newsize = offtin(patch + 24);
- + if((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0)) return -1;
- +
- + oldpos = 0;
- + newpos = 0;
- + cstream = patch + 32;
- + dstream = cstream + bzctrllen;
- + estream = dstream + bzdatalen;
- +
- + while(newpos < newsize)
- + {
- + /* Read control data */
- + for(i = 0; i < 3; i++)
- + {
- + ctrl[i] = offtin(cstream);
- + cstream += 8;
- + }
- + /* Sanity-check */
- + if((newpos + ctrl[0]) > newsize) return -1;
- + /* Read diff string */
- + memcpy(dest + newpos, dstream, ctrl[0]);
- + dstream += ctrl[0];
- + /* Add old data to diff string */
- + for(i = 0; i < ctrl[0]; i++)
- + {
- + if(((oldpos + i) >= 0) && ((oldpos + i) < src_len)) dest[newpos + i] += src[oldpos + i];
- + }
- + /* Adjust pointers */
- + newpos += ctrl[0];
- + oldpos += ctrl[0];
- + /* Sanity-check */
- + if((newpos + ctrl[1]) > newsize) return -1;
- + /* Read extra string */
- + memcpy(dest + newpos, estream, ctrl[1]);
- + estream += ctrl[1];
- + /* Adjust pointers */
- + newpos += ctrl[1];
- + oldpos += ctrl[2];
- + }
- + return newsize;
- +}
- +
- +static int32_t dre_unpack(uint8_t *dest, uint8_t *src, int32_t len)
- +{
- + uint8_t dbuf[0x1000], mask;
- + int32_t i, soffs, doffs, dbidx, boffs, n;
- +
- + dbidx = 4078;
- + memset(dbuf, 32, 4078);
- + for(soffs = 0, doffs = 0; soffs < len; )
- + {
- + mask = src[soffs++];
- + for(i = 0; i < 8 && soffs < len; i++, mask >>= 1)
- + {
- + if(mask & 1)
- + {
- + dest[doffs++] = dbuf[dbidx] = src[soffs++];
- + dbidx = (dbidx + 1) & 0xfff;
- + }
- + else
- + {
- + boffs = src[soffs++];
- + n = src[soffs++];
- + boffs |= (n & 0xf0) << 4;
- + n &= 0xf;
- + n += 3;
- + while(n--)
- + {
- + boffs &= 0xfff;
- + dest[doffs++] = dbuf[dbidx] = dbuf[boffs++];
- + dbidx = (dbidx + 1) & 0xfff;
- + }
- + }
- + }
- + }
- + return doffs;
- +}
- +
- +typedef struct
- +{
- + int32_t magic_number; /* magic number - value . */
- + int32_t codesize; /* size of code in the rcu. */
- + int32_t entrypointoffset; /* entrypoint offset into the code. */
- + int32_t datasize; /* size of data region. */
- + int32_t datalocationoffset; /* offset to place data at. */
- + int32_t bsssize; /* size of bss region. */
- + int32_t bsslocationoffset; /* offset to place bss at. */
- + int32_t staticlinkoffset; /* offset to staticlink in data. */
- + int32_t relsize; /* size of relocation table. */
- + int32_t conssize; /* size of constructor table. */
- + int32_t dessize; /* size of destructor table. */
- + int32_t stacksize; /* size of stack this rcu needs. */
- + int32_t heapsize; /* size of heap this rcu needs. */
- + int32_t dbgfilenamesize; /* size of .dbg filename. */
- + int32_t slot0; /* 4 words space for user use. */
- + int32_t slot1;
- + int32_t slot2;
- + int32_t slot3;
- +} rcu_header_t;
- +
- +static void rcu_load_offs(uint32_t *offs, uint8_t *buf, int32_t size)
- +{
- + uint32_t i;
- + for(i = 0; i < size / sizeof(int32_t); i++)
- + {
- + offs[i] = (uint32_t)(buf[3 + i * 4] << 24) | (buf[2 + i * 4] << 16) | (buf[1 + i * 4] << 8) | buf[0 + i * 4];
- + }
- +}
- +
- +static void rcu_load(uint8_t *rcu)
- +{
- + int32_t rcu_data_size;
- + uint32_t i;
- + uint32_t nexports, nimports;
- + rcu_header_t rcuh;
- + uint8_t *ptr, *rcu_code, *rcu_data;
- +// char *dbgfilename;
- +
- + rcu_load_offs((uint32_t *)&rcuh, rcu, sizeof(rcu_header_t));
- + ptr = rcu + sizeof(rcu_header_t);
- + rcu_code = ptr;
- + ptr += rcuh.codesize;
- + rcu_data_size = rcuh.datasize + rcuh.bsssize;
- + rcu_data = ptr;
- + ptr += rcuh.datasize;
- +
- + if(rcuh.relsize)
- + {
- + uint32_t relocations[rcuh.relsize / sizeof(int32_t)];
- + rcu_load_offs(relocations, ptr, rcuh.relsize);
- + ptr += rcuh.relsize;
- + }
- + if(rcuh.conssize)
- + {
- + uint32_t constructors[rcuh.conssize / sizeof(int32_t)];
- + rcu_load_offs(constructors, ptr, rcuh.conssize);
- + ptr += rcuh.conssize;
- + }
- + if(rcuh.dessize)
- + {
- + uint32_t destructors[rcuh.dessize / sizeof(int32_t)];
- + rcu_load_offs(destructors, ptr, rcuh.dessize);
- + ptr += rcuh.dessize;
- + }
- +// if(rcuh.dbgfilenamesize)
- +// {
- +// dbgfilename = (char *) ptr;
- +// }
- +
- + ptr = rcu_data + rcu_data_size - 16 + 4;
- + rcu_load_offs(&nexports, ptr, sizeof(int32_t));
- + if(nexports)
- + {
- + uint32_t exports[nexports * 3];
- + rcu_load_offs(exports, ptr - nexports * sizeof(int32_t) * 3, nexports * sizeof(int32_t) * 3);
- + for(i = 0; i < nexports; i++)
- + {
- + char *symbol = (char *) (rcu_code + exports[0 + i * 3]);
- + uint32_t faddr = exports[2 + i * 3];
- + if(strcmp(symbol, "snippet_decrypt") == 0) gDecryptAddr = faddr;
- + }
- + }
- + ptr -= nexports * 3 * sizeof(int32_t) + 8;
- + rcu_load_offs(&nimports, ptr, sizeof(int32_t));
- + if(nimports)
- + {
- + uint32_t imports[nimports * 3];
- + rcu_load_offs(imports, ptr - nimports * sizeof(int32_t) * 3, nimports * sizeof(int32_t) * 3);
- + }
- +}
- +
- +static int32_t load_sections(uint8_t *body)
- +{
- + uint8_t section[4096];
- + //uint8_t version;
- + uint16_t sect_len, sect_no, last_sect_no, curr_sect_no = 0;
- + //uint16_t table_id_extension;
- + int32_t body_len, total_body_len = 0;
- + //int32_t current_next_indicator;
- + uint32_t i=0;
- +
- + while((i+3)<raw_buffer.used)
- + {
- + memcpy(section, raw_buffer.data+i, 3);
- + i+=3;
- + memcpy(§_len, section + 1, 2);
- + sect_len = ntohs(sect_len) & 0xfff;
- +
- + memcpy(section + 3, raw_buffer.data+i, sect_len);
- + i+=sect_len;
- +
- + if(section[0] != 0x91 || sect_len < (4 + 5)) continue;
- +
- + uint32_t crc = crc32(-1, section, sect_len + 3 - 4);
- + uint32_t sect_crc = (uint32_t) section[sect_len - 1 + 3] << 24 | section[sect_len - 2 + 3] << 16 | section[sect_len - 3 + 3] << 8 | section[sect_len - 4 + 3];
- + if(crc != sect_crc)
- + {
- + continue;
- + }
- +
- + //table_id_extension = (section[3] << 8) | section[4];
- + //version = (section[5] & 0x3e) >> 1;
- + //current_next_indicator = section[5] & 1;
- + sect_no = section[6];
- + last_sect_no = section[7];
- +
- + if(curr_sect_no == 0)
- + {
- + gId = (section[13] << 8) | section[14];
- + gVersion = (section[5] & 0x3e) >> 1;
- + }
- +
- + if(curr_sect_no == sect_no)
- + {
- + body_len = sect_len - 5 - 4;
- + memcpy(body, section + 8, body_len);
- + total_body_len += body_len;
- + body += body_len;
- + curr_sect_no++;
- + }
- + if(curr_sect_no > last_sect_no) break;
- + }
- +
- + return total_body_len;
- +}
- +
- +static int32_t allocate_data_block(data_block *buff, uint32_t size)
- +{
- + if (buff->data == NULL)
- + {
- + buff->data = malloc(size);
- + if (buff->data == NULL) { return -1; }
- + buff->size = size;
- + buff->used = 0;
- + }
- + if (buff->size < size)
- + {
- + uint8_t *new_buff;
- +
- + new_buff = malloc(size);
- + if (new_buff == NULL) { return -1; }
- + memcpy(new_buff, buff->data, buff->used);
- +
- + free(buff->data);
- +
- + buff->data = new_buff;
- + buff->size = size;
- + }
- + return 0;
- +}
- +
- +void Drecrypt2OverCW(uint16_t overcryptId, uint8_t *cw)
- +{
- + if(overcryptId == gId)
- + {
- + st20_run(code_buffer.data, code_buffer.used, gDecryptAddr, cw, overcryptId);
- + }
- + else
- + {
- + cs_log("[icg] ICG algo %04X not found", overcryptId);
- + }
- +}
- +
- +void Drecrypt2OverEMM(uint8_t *emm)
- +{
- + uint32_t dataLen;
- +
- + if(gVersion == (emm[5] & 0x3e) >> 1)
- + {
- + return;
- + }
- +
- + if (gRawSec == 0)
- + {
- + if(emm[6] != 0)
- + {
- + return;
- + }
- + }
- +
- + if (emm[6] != gRawSec)
- + {
- + gRawSec = 0;
- + return;
- + }
- +
- + dataLen = ((emm[1] & 0xF) << 8) | emm[2];
- + dataLen += 3;
- + if(dataLen < 4)
- + {
- + return;
- + }
- +
- + if (gRawSec == 0)
- + {
- + raw_buffer.used = 0;
- + }
- +
- + if (allocate_data_block(&raw_buffer, raw_buffer.used + dataLen))
- + {
- + return;
- + }
- +
- + memcpy(raw_buffer.data + raw_buffer.used, emm, dataLen);
- + raw_buffer.used += dataLen;
- +
- + if (emm[6] != emm[7])
- + {
- + gRawSec++;
- + return;
- + }
- +
- + gRawSec = 0;
- +
- + int32_t patch_len, rcu_len, len, snip_len;
- + uint8_t *buf = malloc(0x1000), *snip = malloc(0x10000), *rcu = malloc(0x10000), *patch = malloc(0x10000);
- +
- + if(buf == NULL || snip == NULL || rcu == NULL || patch == NULL) {printf("can't allocate memory\n"); return;}
- +
- + snip_len = (initial_snippet[4] << 24) | (initial_snippet[5] << 16) | (initial_snippet[6] << 8) | initial_snippet[7];
- +
- + if(dre_unpack(snip, initial_snippet + 8, sizeof(initial_snippet) - 8) >= snip_len)
- + {
- + len = load_sections(buf);
- +
- + patch_len = (buf[14] << 24) | (buf[15] << 16) | (buf[16] << 8) | buf[17];
- + if(dre_unpack(patch, buf + 18, len - 18) >= patch_len)
- + {
- + rcu_len = bspatch(rcu, snip, snip_len, patch);
- + if(rcu_len > 0)
- + {
- + rcu_load(rcu);
- + allocate_data_block(&code_buffer,rcu_len);
- + memcpy(code_buffer.data, rcu, rcu_len);
- + code_buffer.used = (uint32_t) rcu_len;
- + }
- + }
- + }
- +
- + //gId = (raw_buffer.data[13] << 8) | raw_buffer.data[14];
- + //gVersion = (emm[5] & 0x3e) >> 1;
- +
- + free(buf);
- + free(snip);
- + free(rcu);
- + free(patch);
- +
- + cs_log("[icg] snippet patch created. ICG algo %04X", gId);
- +}
- +
- Index: module-emulator-dre2overcrypt.h
- ===================================================================
- --- module-emulator-dre2overcrypt.h (revision 0)
- +++ module-emulator-dre2overcrypt.h (working copy)
- @@ -0,0 +1,7 @@
- +#ifndef DRE2_OVERCRYPT_H_
- +#define DRE2_OVERCRYPT_H_
- +
- + void Drecrypt2OverCW(uint16_t overcryptId, uint8_t *cw);
- + void Drecrypt2OverEMM(uint8_t *emm);
- +
- +#endif
- Index: module-emulator-osemu.c
- ===================================================================
- --- module-emulator-osemu.c (revision 0)
- +++ module-emulator-osemu.c (working copy)
- @@ -0,0 +1,4291 @@
- +#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"
- +// 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"
- +#endif
- +
- +#include "module-emulator-osemu.h"
- +#include "module-emulator-stream.h"
- +#include "module-emulator-dre2overcrypt.h"
- +
- +// Version info
- +uint32_t GetOSemuVersion(void)
- +{
- + return atoi("$Version: 728 $"+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<inLen/2; i++) {
- + if(sscanf(in + i*2, "%02X", &tmp) != 1) {
- + return 0;
- + }
- + out[i] = (uint8_t)tmp;
- + }
- + return 1;
- +}
- +
- +
- +KeyDataContainer CwKeys = { NULL, 0, 0 };
- +KeyDataContainer ViKeys = { NULL, 0, 0 };
- +KeyDataContainer NagraKeys = { NULL, 0, 0 };
- +KeyDataContainer IrdetoKeys = { NULL, 0, 0 };
- +KeyDataContainer NDSKeys = { NULL, 0, 0 };
- +KeyDataContainer BissKeys = { NULL, 0, 0 };
- +KeyDataContainer PowervuKeys = { NULL, 0, 0 };
- +KeyDataContainer DreKeys = { NULL, 0, 0 };
- +
- +static KeyDataContainer *GetKeyContainer(char identifier)
- +{
- + switch(identifier) {
- + case 'W':
- + return &CwKeys;
- + case 'V':
- + return &ViKeys;
- + case 'N':
- + return &NagraKeys;
- + case 'I':
- + return &IrdetoKeys;
- + case 'S':
- + return &NDSKeys;
- + case 'F':
- + return &BissKeys;
- + case 'P':
- + return &PowervuKeys;
- + case 'D':
- + return &DreKeys;
- + default:
- + return NULL;
- + }
- +}
- +
- +static void WriteKeyToFile(char identifier, uint32_t provider, const char *keyName, uint8_t *key, uint32_t keyLength, char* comment)
- +{
- + char line[1200], dateText[100];
- + uint32_t pathLength;
- + struct dirent *pDirent;
- + DIR *pDir;
- + char *path, *filepath, filename[EMU_KEY_FILENAME_MAX_LEN+1], *keyValue;
- + FILE *file = NULL;
- + uint8_t fileNameLen = strlen(EMU_KEY_FILENAME);
- + time_t now;
- + struct tm t;
- +
- + pathLength = strlen(emu_keyfile_path);
- + path = (char*)malloc(pathLength+1);
- + if(path == NULL) {
- + return;
- + }
- + strncpy(path, emu_keyfile_path, pathLength+1);
- +
- + pathLength = strlen(path);
- + if(pathLength >= fileNameLen && strcasecmp(path+pathLength-fileNameLen, EMU_KEY_FILENAME) == 0) {
- + // cut file name
- + path[pathLength-fileNameLen] = '\0';
- + }
- +
- + pathLength = strlen(path);
- + if(path[pathLength-1] == '/' || path[pathLength-1] == '\\') {
- + // cut trailing /
- + path[pathLength-1] = '\0';
- + }
- +
- + pDir = opendir(path);
- + if (pDir == NULL) {
- + cs_log("cannot open key file path: %s", path);
- + free(path);
- + return;
- + }
- +
- + while((pDirent = readdir(pDir)) != NULL) {
- + if(strcasecmp(pDirent->d_name, EMU_KEY_FILENAME) == 0) {
- + strncpy(filename, pDirent->d_name, sizeof(filename));
- + break;
- + }
- + }
- + closedir(pDir);
- +
- + if(pDirent == NULL) {
- + strncpy(filename, EMU_KEY_FILENAME, sizeof(filename));
- + }
- +
- + pathLength = strlen(path)+1+strlen(filename)+1;
- + filepath = (char*)malloc(pathLength);
- + if(filepath == NULL) {
- + free(path);
- + return;
- + }
- + snprintf(filepath, pathLength, "%s/%s", path, filename);
- + free(path);
- +
- + cs_log("writing key file: %s", filepath);
- +
- + file = fopen(filepath, "a");
- + free(filepath);
- + if(file == NULL) {
- + return;
- + }
- +
- + 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 %08X %s %s ; added by OSEmu %s %s\n", identifier, provider, keyName, keyValue, dateText, comment);
- + }
- + else
- + {
- + snprintf(line, sizeof(line), "\n%c %04X %s %s ; added by OSEmu %s\n", identifier, provider, keyName, keyValue, dateText);
- + }
- + cs_log("[Emu] Key written: %c %08X %s %s", identifier, provider, keyName, keyValue);
- + free(keyValue);
- +
- + fwrite(line, strlen(line), 1, file);
- + fclose(file);
- +}
- +
- +// key must come from malloc() !
- +static int32_t SetKey(char identifier, uint32_t provider, const char *keyName, uint8_t *key,
- + uint32_t keyLength, uint8_t writeKey, char *comment)
- +{
- + uint32_t i, j;
- + uint8_t *tmpKey = NULL, *orgKey = NULL;
- + KeyDataContainer *KeyDB;
- + KeyData *tmpKeyData, *newKeyData;
- + identifier = (char)toupper((int)identifier);
- + uint8_t key_exists = 0;
- +
- + KeyDB = GetKeyContainer(identifier);
- + if(KeyDB == NULL) {
- + return 0;
- + }
- +
- + // fix patched mgcamd format for Irdeto
- + if(identifier == 'I' && provider < 0xFFFF) {
- + provider = provider<<8;
- + }
- +
- + // 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] = key[0];
- + tmpKey[1] = key[1];
- + tmpKey[2] = key[2];
- + tmpKey[3] = ((key[0] + key[1] + key[2]) & 0xff);
- + tmpKey[4] = key[3];
- + tmpKey[5] = key[4];
- + tmpKey[6] = key[5];
- + tmpKey[7] = ((key[3] + key[4] + key[5]) & 0xff);
- +
- + orgKey = key;
- + key = tmpKey;
- + keyLength = 8;
- + }
- +
- + for(i=0; i<KeyDB->keyCount; i++) {
- + if(strcmp(KeyDB->EmuKeys[i].keyName, keyName)) {
- + continue;
- + }
- +
- + if( identifier == 'P' ) {
- + if(writeKey) {
- + if( (KeyDB->EmuKeys[i].provider & 0xFFFF0000) != (provider & 0xFFFF0000) ) { // mask out srvid, only compare group
- + continue;
- + }
- + tmpKeyData = &KeyDB->EmuKeys[i];
- + if(memcmp(tmpKeyData->key, key, tmpKeyData->keyLength < keyLength ? tmpKeyData->keyLength : keyLength) == 0) {
- + key_exists = 1;
- + continue;
- + }
- + provider = KeyDB->EmuKeys[i].provider; // set to matched full provider ( group + srvid )
- + }
- + else {
- + if( KeyDB->EmuKeys[i].provider != provider ) {
- + continue;
- + }
- + }
- + }
- + else {
- + if(KeyDB->EmuKeys[i].provider != provider) {
- + continue;
- + }
- + }
- + key_exists = 1;
- +
- + // allow multiple keys for Irdeto and Powervu
- + if(identifier == 'I')
- + {
- + // reject duplicates
- + tmpKeyData = &KeyDB->EmuKeys[i];
- + do {
- + if(memcmp(tmpKeyData->key, key, tmpKeyData->keyLength < keyLength ? tmpKeyData->keyLength : keyLength) == 0) {
- + if(tmpKey != NULL) {
- + free(tmpKey);
- + }
- + return 0;
- + }
- + tmpKeyData = tmpKeyData->nextKey;
- + }
- + while(tmpKeyData != NULL);
- +
- + // add new key
- + newKeyData = (KeyData*)malloc(sizeof(KeyData));
- + if(newKeyData == NULL) {
- + if(tmpKey != 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 = key;
- + 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, key, keyLength, comment);
- + }
- + }
- + else // identifier != 'I'
- + {
- + free(KeyDB->EmuKeys[i].key);
- + KeyDB->EmuKeys[i].key = key;
- + KeyDB->EmuKeys[i].keyLength = keyLength;
- +
- + if(writeKey) {
- + WriteKeyToFile(identifier, provider, keyName, key, keyLength, comment);
- + }
- + }
- +
- + if(tmpKey != NULL) {
- + free(orgKey);
- + }
- + if((identifier != 'P') | !writeKey){ // on pvu update continue loop to find others in group
- + return 1;
- + }
- + }
- +
- + if(key_exists) {
- + 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) {
- + if(tmpKey != NULL) {
- + free(tmpKey);
- + }
- + return 0;
- + }
- + KeyDB->keyMax+=64;
- + }
- + else {
- + tmpKeyData = (KeyData*)realloc(KeyDB->EmuKeys, sizeof(KeyData)*(KeyDB->keyMax+16));
- + if(tmpKeyData == NULL) {
- + if(tmpKey != 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 = key;
- + KeyDB->EmuKeys[KeyDB->keyCount].keyLength = keyLength;
- + KeyDB->EmuKeys[KeyDB->keyCount].nextKey = NULL;
- + KeyDB->keyCount++;
- +
- + if(writeKey) {
- + WriteKeyToFile(identifier, provider, keyName, key, keyLength, comment);
- + }
- +
- + if(tmpKey != NULL) {
- + free(orgKey);
- + }
- + return 1;
- +}
- +
- +static int32_t FindKey(char identifier, uint32_t provider, const char *keyName, uint8_t *key, uint32_t maxKeyLength,
- + uint8_t isCriticalKey, uint8_t keyRef, uint8_t matchLength, uint32_t *getProvider)
- +{
- + uint32_t i;
- + uint16_t j;
- + uint8_t k;
- + KeyDataContainer *KeyDB;
- + KeyData *tmpKeyData;
- +
- + KeyDB = GetKeyContainer(identifier);
- + if(KeyDB == NULL) {
- + return 0;
- + }
- +
- + k = 0;
- + for(i=0; i<KeyDB->keyCount; i++) {
- + if(identifier == 'P') {
- + if( getProvider == NULL && (KeyDB->EmuKeys[i].provider & 0x0000FFFF) != provider ) { // mask out group, only compare srvid
- + continue;
- + }
- + //provider = KeyDB->EmuKeys[i].provider; // set to matched full provider ( group + srvid )
- + }
- + else {
- + if(getProvider == NULL && KeyDB->EmuKeys[i].provider != 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(identifier == 'P') {
- + if(k < keyRef) {
- + k++;
- + continue;
- + }
- + else {
- + keyRef = 0;
- + }
- + }
- +
- + tmpKeyData = &KeyDB->EmuKeys[i];
- +
- + j = 0;
- + while(j<keyRef && tmpKeyData->nextKey != NULL) {
- + j++;
- + tmpKeyData = tmpKeyData->nextKey;
- + }
- +
- + if(j == keyRef) {
- + memcpy(key, tmpKeyData->key, tmpKeyData->keyLength > maxKeyLength ? maxKeyLength : tmpKeyData->keyLength);
- + if(tmpKeyData->keyLength < maxKeyLength) {
- + memset(key+tmpKeyData->keyLength, 0, maxKeyLength - tmpKeyData->keyLength);
- + }
- + if(getProvider != NULL) {
- + (*getProvider) = tmpKeyData->provider;
- + }
- + return 1;
- + }
- + else {
- + break;
- + }
- + }
- +
- + if(isCriticalKey) {
- + cs_log("[Emu] Key not found: %c %X %s", identifier, provider, keyName);
- + }
- + return 0;
- +}
- +
- +// key must come from malloc() !
- +static int32_t UpdateKey(char identifier, uint32_t provider, char *keyName, uint8_t *key, uint32_t keyLength, char *comment)
- +{
- + uint8_t keyRef = 0;
- + uint8_t *tmpKey = (uint8_t*)malloc(sizeof(uint8_t)*keyLength);
- + if(tmpKey == NULL)
- + {
- + return 0;
- + }
- +
- + while(FindKey(identifier, provider, keyName, tmpKey, keyLength, 0, keyRef, 0, NULL))
- + {
- + if(memcmp(tmpKey, key, keyLength) == 0)
- + {
- + free(tmpKey);
- + return 0;
- + }
- + if(keyRef == 0xFF)
- + {
- + break;
- + }
- + keyRef++;
- + }
- +
- + free(tmpKey);
- +
- + return SetKey(identifier, provider, keyName, key, keyLength, 1, comment);
- +}
- +
- +
- +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));
- + if(!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));
- + if(!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<n) {
- + int32_t l=n-s;
- + memset(out,0,l);
- + BN_bn2bin(r,out+l);
- + }
- + else {
- + BN_bn2bin(r,out);
- + }
- + if(le) {
- + ReverseMem(out,n);
- + }
- + return s;
- +}
- +
- +static int32_t EmuRSA(uint8_t *out, const uint8_t *in, int32_t n, BIGNUM *exp, BIGNUM *mod, int8_t le)
- +{
- + BN_CTX *ctx;
- + BIGNUM *r, *d;
- + int32_t result = 0;
- +
- + ctx = BN_CTX_new();
- + r = BN_new();
- + d = BN_new();
- +
- + if(EmuRSAInput(d,in,n,le) && BN_mod_exp(r,d,exp,mod,ctx)) {
- + result = EmuRSAOutput(out,n,r,le);
- + }
- +
- + BN_free(d);
- + BN_free(r);
- + BN_CTX_free(ctx);
- + return result;
- +}
- +
- +static inline void xxor(uint8_t *data, int32_t len, const uint8_t *v1, const uint8_t *v2)
- +{
- + uint32_t i;
- + switch(len)
- + {
- + case 16:
- + for(i = 8; i < 16; ++i)
- + {
- + data[i] = v1[i] ^ v2[i];
- + }
- + case 8:
- + for(i = 4; i < 8; ++i)
- + {
- + data[i] = v1[i] ^ v2[i];
- + }
- + case 4:
- + for(i = 0; i < 4; ++i)
- + {
- + data[i] = v1[i] ^ v2[i];
- + }
- + break;
- + default:
- + while(len--) { *data++ = *v1++ ^ *v2++; }
- + break;
- + }
- +}
- +
- +static int8_t isValidDCW(uint8_t *dw)
- +{
- + if (((dw[0]+dw[1]+dw[2]) & 0xFF) != dw[3]) {
- + return 0;
- + }
- + if (((dw[4]+dw[5]+dw[6]) & 0xFF) != dw[7]) {
- + return 0;
- + }
- + if (((dw[8]+dw[9]+dw[10]) & 0xFF) != dw[11]) {
- + return 0;
- + }
- + if (((dw[12]+dw[13]+dw[14]) & 0xFF) != dw[15]) {
- + return 0;
- + }
- + return 1;
- +}
- +
- +static inline uint8_t GetBit(uint8_t byte, uint8_t bitnb)
- +{
- + return ((byte&(1<<bitnb)) ? 1: 0);
- +}
- +
- +static inline uint8_t SetBit(uint8_t val, uint8_t bitnb, uint8_t biton)
- +{
- + return (biton ? (val | (1<<bitnb)) : (val & ~(1<<bitnb)));
- +}
- +
- +static void ExpandDesKey(unsigned char *key)
- +{
- + uint8_t i, j, parity;
- + uint8_t tmpKey[7];
- +
- + memcpy(tmpKey, key, 7);
- +
- + key[0] = (tmpKey[0] & 0xFE);
- + key[1] = ((tmpKey[0] << 7) | ((tmpKey[1] >> 1) & 0xFE));
- + key[2] = ((tmpKey[1] << 6) | ((tmpKey[2] >> 2) & 0xFE));
- + key[3] = ((tmpKey[2] << 5) | ((tmpKey[3] >> 3) & 0xFE));
- + key[4] = ((tmpKey[3] << 4) | ((tmpKey[4] >> 4) & 0xFE));
- + key[5] = ((tmpKey[4] << 3) | ((tmpKey[5] >> 5) & 0xFE));
- + key[6] = ((tmpKey[5] << 2) | ((tmpKey[6] >> 6) & 0xFE));
- + key[7] = (tmpKey[6] << 1);
- +
- + for (i = 0; i < 8; i++)
- + {
- + parity = 1;
- + for (j = 1; j < 8; j++) if ((key[i] >> j) & 0x1) { parity = ~parity & 0x01; }
- + key[i] |= parity;
- + }
- +}
- +
- +// Cryptoworks EMU
- +static int8_t GetCwKey(uint8_t *buf,uint32_t ident, uint8_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey)
- +{
- +
- + char keyName[EMU_MAX_CHAR_KEYNAME];
- + uint32_t tmp;
- +
- + if((ident>>4)== 0xD02A) {
- + keyIndex &=0xFE; // map to even number key indexes
- + }
- + if((ident>>4)== 0xD00C) {
- + ident = 0x0D00C0; // map provider C? to C0
- + }
- + else if(keyIndex==6 && ((ident>>8) == 0x0D05)) {
- + ident = 0x0D0504; // always use provider 04 system key
- + }
- +
- + tmp = keyIndex;
- + snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", tmp);
- + if(FindKey('W', ident, keyName, buf, keyLength, isCriticalKey, 0, 0, NULL)) {
- + return 1;
- + }
- +
- + return 0;
- +}
- +
- +static const uint8_t cw_sbox1[64] = {
- + 0xD8,0xD7,0x83,0x3D,0x1C,0x8A,0xF0,0xCF,0x72,0x4C,0x4D,0xF2,0xED,0x33,0x16,0xE0,
- + 0x8F,0x28,0x7C,0x82,0x62,0x37,0xAF,0x59,0xB7,0xE0,0x00,0x3F,0x09,0x4D,0xF3,0x94,
- + 0x16,0xA5,0x58,0x83,0xF2,0x4F,0x67,0x30,0x49,0x72,0xBF,0xCD,0xBE,0x98,0x81,0x7F,
- + 0xA5,0xDA,0xA7,0x7F,0x89,0xC8,0x78,0xA7,0x8C,0x05,0x72,0x84,0x52,0x72,0x4D,0x38
- +};
- +static const uint8_t cw_sbox2[64] = {
- + 0xD8,0x35,0x06,0xAB,0xEC,0x40,0x79,0x34,0x17,0xFE,0xEA,0x47,0xA3,0x8F,0xD5,0x48,
- + 0x0A,0xBC,0xD5,0x40,0x23,0xD7,0x9F,0xBB,0x7C,0x81,0xA1,0x7A,0x14,0x69,0x6A,0x96,
- + 0x47,0xDA,0x7B,0xE8,0xA1,0xBF,0x98,0x46,0xB8,0x41,0x45,0x9E,0x5E,0x20,0xB2,0x35,
- + 0xE4,0x2F,0x9A,0xB5,0xDE,0x01,0x65,0xF8,0x0F,0xB2,0xD2,0x45,0x21,0x4E,0x2D,0xDB
- +};
- +static const uint8_t cw_sbox3[64] = {
- + 0xDB,0x59,0xF4,0xEA,0x95,0x8E,0x25,0xD5,0x26,0xF2,0xDA,0x1A,0x4B,0xA8,0x08,0x25,
- + 0x46,0x16,0x6B,0xBF,0xAB,0xE0,0xD4,0x1B,0x89,0x05,0x34,0xE5,0x74,0x7B,0xBB,0x44,
- + 0xA9,0xC6,0x18,0xBD,0xE6,0x01,0x69,0x5A,0x99,0xE0,0x87,0x61,0x56,0x35,0x76,0x8E,
- + 0xF7,0xE8,0x84,0x13,0x04,0x7B,0x9B,0xA6,0x7A,0x1F,0x6B,0x5C,0xA9,0x86,0x54,0xF9
- +};
- +static const uint8_t cw_sbox4[64] = {
- + 0xBC,0xC1,0x41,0xFE,0x42,0xFB,0x3F,0x10,0xB5,0x1C,0xA6,0xC9,0xCF,0x26,0xD1,0x3F,
- + 0x02,0x3D,0x19,0x20,0xC1,0xA8,0xBC,0xCF,0x7E,0x92,0x4B,0x67,0xBC,0x47,0x62,0xD0,
- + 0x60,0x9A,0x9E,0x45,0x79,0x21,0x89,0xA9,0xC3,0x64,0x74,0x9A,0xBC,0xDB,0x43,0x66,
- + 0xDF,0xE3,0x21,0xBE,0x1E,0x16,0x73,0x5D,0xA2,0xCD,0x8C,0x30,0x67,0x34,0x9C,0xCB
- +};
- +static const uint8_t AND_bit1[8] = {0x00,0x40,0x04,0x80,0x21,0x10,0x02,0x08};
- +static const uint8_t AND_bit2[8] = {0x80,0x08,0x01,0x40,0x04,0x20,0x10,0x02};
- +static const uint8_t AND_bit3[8] = {0x82,0x40,0x01,0x10,0x00,0x20,0x04,0x08};
- +static const uint8_t AND_bit4[8] = {0x02,0x10,0x04,0x40,0x80,0x08,0x01,0x20};
- +
- +static void CW_SWAP_KEY(uint8_t *key)
- +{
- + uint8_t k[8];
- + memcpy(k, key, 8);
- + memcpy(key, key + 8, 8);
- + memcpy(key + 8, k, 8);
- +}
- +
- +static void CW_SWAP_DATA(uint8_t *k)
- +{
- + uint8_t d[4];
- + memcpy(d, k + 4, 4);
- + memcpy(k + 4 ,k ,4);
- + memcpy(k, d, 4);
- +}
- +
- +static void CW_DES_ROUND(uint8_t *d, uint8_t *k)
- +{
- + uint8_t aa[44] = {1,0,3,1,2,2,3,2,1,3,1,1,3,0,1,2,3,1,3,2,2,0,7,6,5,4,7,6,5,7,6,5,6,7,5,7,5,7,6,6,7,5,4,4};
- + uint8_t bb[44] = {0x80,0x08,0x10,0x02,0x08,0x40,0x01,0x20,0x40,0x80,0x04,0x10,0x04,0x01,0x01,0x02,0x20,0x20,0x02,0x01,
- + 0x80,0x04,0x02,0x02,0x08,0x02,0x10,0x80,0x01,0x20,0x08,0x80,0x01,0x08,0x40,0x01,0x02,0x80,0x10,0x40,0x40,0x10,0x08,0x01
- + };
- + uint8_t ff[4] = {0x02,0x10,0x04,0x04};
- + uint8_t l[24] = {0,2,4,6,7,5,3,1,4,5,6,7,7,6,5,4,7,4,5,6,4,7,6,5};
- +
- + uint8_t des_td[8], i, o, n, c = 1, m = 0, r = 0, *a = aa, *b = bb, *f = ff, *p1 = l, *p2 = l+8, *p3 = l+16;
- +
- + for (m = 0; m < 2; m++) {
- + for(i = 0; i < 4; i++) {
- + des_td[*p1++] =
- + (m) ? ((d[*p2++]*2) & 0x3F) | ((d[*p3++] & 0x80) ? 0x01 : 0x00): (d[*p2++]/2) | ((d[*p3++] & 0x01) ? 0x80 : 0x00);
- + }
- + }
- +
- + for (i = 0; i < 8; i++) {
- + c = (c) ? 0 : 1;
- + r = (c) ? 6 : 7;
- + n = (i) ? i-1 : 1;
- + o = (c) ? ((k[n] & *f++) ? 1 : 0) : des_td[n];
- + for (m = 1; m < r; m++) {
- + o = (c) ? (o*2) | ((k[*a++] & *b++) ? 0x01 : 0x00) : (o/2) | ((k[*a++] & *b++) ? 0x80 : 0x00);
- + }
- + n = (i) ? n+1 : 0;
- + des_td[n] = (c) ? des_td[n] ^ o : (o ^ des_td[n] )/4;
- + }
- +
- + for( i = 0; i < 8; i++) {
- + d[0] ^= (AND_bit1[i] & cw_sbox1[des_td[i]]);
- + d[1] ^= (AND_bit2[i] & cw_sbox2[des_td[i]]);
- + d[2] ^= (AND_bit3[i] & cw_sbox3[des_td[i]]);
- + d[3] ^= (AND_bit4[i] & cw_sbox4[des_td[i]]);
- + }
- +
- + CW_SWAP_DATA(d);
- +}
- +
- +static void CW_48_Key(uint8_t *inkey, uint8_t *outkey, uint8_t algotype)
- +{
- + uint8_t Round_Counter, i = 8, *key128 = inkey, *key48 = inkey + 0x10;
- + Round_Counter = 7 - (algotype & 7);
- +
- + memset(outkey, 0, 16);
- + memcpy(outkey, key48, 6);
- +
- + for( ; i > Round_Counter; i--) {
- + if (i > 1) {
- + outkey[i-2] = key128[i];
- + }
- + }
- +}
- +
- +static void CW_LS_DES_KEY(uint8_t *key,uint8_t Rotate_Counter)
- +{
- + uint8_t round[] = {1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,1};
- + uint8_t i, n;
- + uint16_t k[8];
- +
- + n = round[Rotate_Counter];
- +
- + for (i = 0; i < 8; i++) {
- + k[i] = key[i];
- + }
- +
- + for (i = 1; i < n + 1; i++) {
- + k[7] = (k[7]*2) | ((k[4] & 0x008) ? 1 : 0);
- + k[6] = (k[6]*2) | ((k[7] & 0xF00) ? 1 : 0);
- + k[7] &=0xff;
- + k[5] = (k[5]*2) | ((k[6] & 0xF00) ? 1 : 0);
- + k[6] &=0xff;
- + k[4] = ((k[4]*2) | ((k[5] & 0xF00) ? 1 : 0)) & 0xFF;
- + k[5] &= 0xff;
- + k[3] = (k[3]*2) | ((k[0] & 0x008) ? 1 : 0);
- + k[2] = (k[2]*2) | ((k[3] & 0xF00) ? 1 : 0);
- + k[3] &= 0xff;
- + k[1] = (k[1]*2) | ((k[2] & 0xF00) ? 1 : 0);
- + k[2] &= 0xff;
- + k[0] = ((k[0]*2) | ((k[1] & 0xF00) ? 1 : 0)) & 0xFF;
- + k[1] &= 0xff;
- + }
- + for (i = 0; i < 8; i++) {
- + key[i] = (uint8_t) k[i];
- + }
- +}
- +
- +static void CW_RS_DES_KEY(uint8_t *k, uint8_t Rotate_Counter)
- +{
- + uint8_t i,c;
- + for (i = 1; i < Rotate_Counter+1; i++) {
- + c = (k[3] & 0x10) ? 0x80 : 0;
- + k[3] /= 2;
- + if (k[2] & 1) {
- + k[3] |= 0x80;
- + }
- + k[2] /= 2;
- + if (k[1] & 1) {
- + k[2] |= 0x80;
- + }
- + k[1] /= 2;
- + if (k[0] & 1) {
- + k[1] |= 0x80;
- + }
- + k[0] /= 2;
- + k[0] |= c ;
- + c = (k[7] & 0x10) ? 0x80 : 0;
- + k[7] /= 2;
- + if (k[6] & 1) {
- + k[7] |= 0x80;
- + }
- + k[6] /= 2;
- + if (k[5] & 1) {
- + k[6] |= 0x80;
- + }
- + k[5] /= 2;
- + if (k[4] & 1) {
- + k[5] |= 0x80;
- + }
- + k[4] /= 2;
- + k[4] |= c;
- + }
- +}
- +
- +static void CW_RS_DES_SUBKEY(uint8_t *k, uint8_t Rotate_Counter)
- +{
- + uint8_t round[] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
- + CW_RS_DES_KEY(k, round[Rotate_Counter]);
- +}
- +
- +static void CW_PREP_KEY(uint8_t *key )
- +{
- + uint8_t DES_key[8],j;
- + int32_t Round_Counter = 6,i,a;
- + key[7] = 6;
- + memset(DES_key, 0 , 8);
- + do {
- + a = 7;
- + i = key[7];
- + j = key[Round_Counter];
- + do {
- + DES_key[i] = ( (DES_key[i] * 2) | ((j & 1) ? 1: 0) ) & 0xFF;
- + j /=2;
- + i--;
- + if (i < 0) {
- + i = 6;
- + }
- + a--;
- + }
- + while (a >= 0);
- + key[7] = i;
- + Round_Counter--;
- + }
- + while ( Round_Counter >= 0 );
- + a = DES_key[4];
- + DES_key[4] = DES_key[6];
- + DES_key[6] = a;
- + DES_key[7] = (DES_key[3] * 16) & 0xFF;
- + memcpy(key,DES_key,8);
- + CW_RS_DES_KEY(key,4);
- +}
- +
- +static void CW_L2DES(uint8_t *data, uint8_t *key, uint8_t algo)
- +{
- + uint8_t i, k0[22], k1[22];
- + memcpy(k0,key,22);
- + memcpy(k1,key,22);
- + CW_48_Key(k0, k1,algo);
- + CW_PREP_KEY(k1);
- + for (i = 0; i< 2; i++) {
- + CW_LS_DES_KEY( k1,15);
- + CW_DES_ROUND( data ,k1);
- + }
- +}
- +
- +static void CW_R2DES(uint8_t *data, uint8_t *key, uint8_t algo)
- +{
- + uint8_t i, k0[22],k1[22];
- + memcpy(k0,key,22);
- + memcpy(k1,key,22);
- + CW_48_Key(k0, k1, algo);
- + CW_PREP_KEY(k1);
- + for (i = 0; i< 2; i++) {
- + CW_LS_DES_KEY(k1,15);
- + }
- + for (i = 0; i< 2; i++) {
- + CW_DES_ROUND( data ,k1);
- + CW_RS_DES_SUBKEY(k1,1);
- + }
- + CW_SWAP_DATA(data);
- +}
- +
- +static void CW_DES(uint8_t *data, uint8_t *inkey, uint8_t m)
- +{
- + uint8_t key[22], i;
- + memcpy(key, inkey + 9, 8);
- + CW_PREP_KEY( key );
- + for (i = 16; i > 0; i--) {
- + if (m == 1) {
- + CW_LS_DES_KEY(key, (uint8_t) (i-1));
- + }
- + CW_DES_ROUND( data ,key);
- + if (m == 0) {
- + CW_RS_DES_SUBKEY(key, (uint8_t) (i-1));
- + }
- + }
- +}
- +
- +static void CW_DEC_ENC(uint8_t *d, uint8_t *k, uint8_t a,uint8_t m)
- +{
- + uint8_t n = m & 1;
- + CW_L2DES(d , k, a);
- + CW_DES (d , k, n);
- + CW_R2DES(d , k, a);
- + if (m & 2) {
- + CW_SWAP_KEY(k);
- + }
- +}
- +
- +static void Cryptoworks3DES(uint8_t *data, uint8_t *key)
- +{
- + uint32_t ks1[32], ks2[32];
- +
- + des_set_key(key, ks1);
- + des_set_key(key+8, ks2);
- +
- + des(data, ks1, 0);
- + des(data, ks2, 1);
- + des(data, ks1, 0);
- +}
- +
- +static uint8_t CryptoworksProcessNano80(uint8_t *data, uint32_t caid, int32_t provider, uint8_t *opKey, uint8_t nanoLength, uint8_t nano80Algo)
- +{
- + int32_t i, j;
- + uint8_t key[16], desKey[16], t[8], dat1[8], dat2[8], k0D00C000[16];
- + if(nanoLength < 11) {
- + return 0;
- + }
- + if(caid == 0x0D00 && provider != 0xA0 && !GetCwKey(k0D00C000, 0x0D00C0, 0, 16, 1)) {
- + return 0;
- + }
- +
- + if(nano80Algo > 1) {
- + return 0;
- + }
- +
- + memset(t, 0, 8);
- + memcpy(dat1, data, 8);
- +
- + if(caid == 0x0D00 && provider != 0xA0) {
- + memcpy(key, k0D00C000, 16);
- + }
- + else {
- + memcpy(key, opKey, 16);
- + }
- + Cryptoworks3DES(data, key);
- + memcpy(desKey, data, 8);
- +
- + memcpy(data, dat1, 8);
- + if(caid == 0x0D00 && provider != 0xA0) {
- + memcpy(key, &k0D00C000[8], 8);
- + memcpy(&key[8], k0D00C000, 8);
- + }
- + else {
- + memcpy(key, &opKey[8], 8);
- + memcpy(&key[8], opKey, 8);
- + }
- + Cryptoworks3DES(data, key);
- + memcpy(&desKey[8], data, 8);
- +
- + for(i=8; i+7<nanoLength; i+=8) {
- + memcpy(dat1, &data[i], 8);
- + memcpy(dat2, dat1, 8);
- + memcpy(key, desKey, 16);
- + Cryptoworks3DES(dat1, key);
- + for(j=0; j<8; j++) {
- + dat1[j] ^= t[j];
- + }
- + memcpy(&data[i], dat1, 8);
- + memcpy(t, dat2, 8);
- + }
- +
- + return data[10] + 5;
- +}
- +
- +static void CryptoworksSignature(const uint8_t *data, uint32_t length, uint8_t *key, uint8_t *signature)
- +{
- + uint32_t i, sigPos;
- + int8_t algo, first;
- +
- + algo = data[0] & 7;
- + if(algo == 7) {
- + algo = 6;
- + }
- + memset(signature, 0, 8);
- + first = 1;
- + sigPos = 0;
- + for(i=0; i<length; i++) {
- + signature[sigPos] ^= data[i];
- + sigPos++;
- +
- + if(sigPos > 7) {
- + if (first) {
- + CW_L2DES(signature, key, algo);
- + }
- + CW_DES(signature, key, 1);
- +
- + sigPos = 0;
- + first = 0;
- + }
- + }
- + if(sigPos > 0) {
- + CW_DES(signature, key, 1);
- + }
- + CW_R2DES(signature, key, algo);
- +}
- +
- +static void CryptoworksDecryptDes(uint8_t *data, uint8_t algo, uint8_t *key)
- +{
- + int32_t i;
- + uint8_t k[22], t[8];
- +
- + algo &= 7;
- + if(algo<7) {
- + CW_DEC_ENC(data, key, algo, 0);
- + }
- + else {
- + memcpy(k, key, 22);
- + for(i=0; i<3; i++) {
- + CW_DEC_ENC(data, k, algo, i&1);
- + memcpy(t,k,8);
- + memcpy(k,k+8,8);
- + memcpy(k+8,t,8);
- + }
- + }
- +}
- +
- +static int8_t CryptoworksECM(uint32_t caid, uint8_t *ecm, uint8_t *cw)
- +{
- + uint32_t ident;
- + uint8_t keyIndex = 0, nanoLength, newEcmLength, key[22], signature[8], nano80Algo = 1;
- + int32_t provider = -1;
- + uint16_t i, j, ecmLen = GetEcmLen(ecm);
- +
- + if(ecmLen < 8) {
- + return 1;
- + }
- + if(ecm[7] != ecmLen - 8) {
- + return 1;
- + }
- +
- + memset(key, 0, 22);
- +
- + for(i = 8; i+1 < ecmLen; i += ecm[i+1] + 2) {
- + if(ecm[i] == 0x83 && i+2 < ecmLen) {
- + provider = ecm[i+2] & 0xFC;
- + keyIndex = ecm[i+2] & 3;
- + keyIndex = keyIndex ? 1 : 0;
- + }
- + else if(ecm[i] == 0x84 && i+3 < ecmLen) {
- + //nano80Provider = ecm[i+2] & 0xFC;
- + //nano80KeyIndex = ecm[i+2] & 3;
- + //nano80KeyIndex = nano80KeyIndex ? 1 : 0;
- + nano80Algo = ecm[i+3];
- + }
- + }
- +
- + if(provider < 0) {
- + switch(caid) {
- + case 0x0D00:
- + provider = 0xC0;
- + break;
- + case 0x0D02:
- + provider = 0xA0;
- + break;
- + case 0x0D03:
- + provider = 0x04;
- + break;
- + case 0x0D05:
- + provider = 0x04;
- + break;
- + default:
- + return 1;
- + }
- + }
- +
- + ident = (caid << 8) | provider;
- + if(!GetCwKey(key, ident, keyIndex, 16, 1)) {
- + return 2;
- + }
- + if(!GetCwKey(&key[16], ident, 6, 6, 1)) {
- + return 2;
- + }
- +
- + for(i = 8; i+1 < ecmLen; i += ecm[i+1] + 2) {
- + if(ecm[i] == 0x80 && i+2+7 < ecmLen && i+2+ecm[i+1] <= ecmLen
- + && (provider == 0xA0 || provider == 0xC0 || provider == 0xC4 || provider == 0xC8)) {
- + nanoLength = ecm[i+1];
- + newEcmLength = CryptoworksProcessNano80(ecm+i+2, caid, provider, key, nanoLength, nano80Algo);
- + if(newEcmLength == 0 || newEcmLength > ecmLen-(i+2+3)) {
- + return 1;
- + }
- + ecm[i+2+3] = 0x81;
- + ecm[i+2+4] = 0x70;
- + ecm[i+2+5] = newEcmLength;
- + ecm[i+2+6] = 0x81;
- + ecm[i+2+7] = 0xFF;
- + return CryptoworksECM(caid, ecm+i+2+3, cw);
- + }
- + }
- +
- + if(ecmLen - 15 < 1) {
- + return 1;
- + }
- + CryptoworksSignature(ecm + 5, ecmLen - 15, key, signature);
- + for(i = 8; i+1 < ecmLen; i += ecm[i+1]+2) {
- + switch(ecm[i]) {
- + case 0xDA:
- + case 0xDB:
- + case 0xDC:
- + if(i+2+ecm[i+1] > ecmLen) {
- + break;
- + }
- + for(j=0; j+7<ecm[i+1]; j+=8) {
- + CryptoworksDecryptDes(&ecm[i+2+j], ecm[5], key);
- + }
- + break;
- + case 0xDF:
- + if(i+2+8 > ecmLen) {
- + break;
- + }
- + if(memcmp(&ecm[i+2], signature, 8)) {
- + return 6;
- + }
- + break;
- + }
- + }
- +
- + for(i = 8; i+1 < ecmLen; i += ecm[i+1]+2) {
- + switch(ecm[i]) {
- + case 0xDB:
- + if(i+2+ecm[i+1] <= ecmLen && ecm[i+1]==16) {
- + memcpy(cw, &ecm[i+2], 16);
- + return 0;
- + }
- + break;
- + }
- + }
- +
- + return 5;
- +}
- +
- +// SoftNDS EMU
- +static const uint8_t nds_const[]= {0x0F,0x1E,0x2D,0x3C,0x4B,0x5A,0x69,0x78,0x87,0x96,0xA5,0xB4,0xC3,0xD2,0xE1,0xF0};
- +
- +uint8_t viasat_const[]= {
- + 0x15,0x85,0xC5,0xE4,0xB8,0x52,0xEC,0xF7,0xC3,0xD9,0x08,0xBA,0x22,0x4A,0x66,0xF2,
- + 0x82,0x15,0x4F,0xB2,0x18,0x48,0x63,0x97,0xDC,0x19,0xD8,0x51,0x9A,0x39,0xFC,0xCA,
- + 0x1C,0x24,0xD0,0x65,0xA9,0x66,0x2D,0xD6,0x53,0x3B,0x86,0xBA,0x40,0xEA,0x4C,0x6D,
- + 0xD9,0x1E,0x41,0x14,0xFE,0x15,0xAF,0xC3,0x18,0xC5,0xF8,0xA7,0xA8,0x01,0x00,0x01,
- +};
- +
- +static int8_t SoftNDSECM(uint16_t caid, uint8_t *ecm, uint8_t *dw)
- +{
- + int32_t i;
- + uint8_t *tDW, irdEcmLen, offsetCw = 0, offsetP2 = 0;
- + uint8_t digest[16], md5_const[64];
- + MD5_CTX mdContext;
- + uint16_t ecmLen = GetEcmLen(ecm);
- +
- + if(ecmLen < 7) {
- + return 1;
- + }
- +
- + if(ecm[3] != 0x00 || ecm[4] != 0x00 || ecm[5] != 0x01) {
- + return 1;
- + }
- +
- + irdEcmLen = ecm[6];
- + if(irdEcmLen < (10+3+8+4) || irdEcmLen+6 >= ecmLen) {
- + return 1;
- + }
- +
- + for(i=0; 10+i+2 < irdEcmLen; i++) {
- + if(ecm[17+i] == 0x0F && ecm[17+i+1] == 0x40 && ecm[17+i+2] == 0x00) {
- + offsetCw = 17+i+3;
- + offsetP2 = offsetCw+9;
- + }
- + }
- +
- + if(offsetCw == 0 || offsetP2 == 0) {
- + return 1;
- + }
- +
- + if(offsetP2-7+4 > irdEcmLen) {
- + return 1;
- + }
- +
- + if(caid == 0x090F || caid == 0x093E) {
- + memcpy(md5_const, viasat_const, 64);
- + }
- + else if(!FindKey('S', caid, "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, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) {
- + return 1;
- + }
- +
- + if(ident == 0xD00040 && FindKey('V', 0x030B00, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) {
- + return 1;
- + }
- +
- + return 0;
- +}
- +
- +static void Via1Mod(const uint8_t* key2, uint8_t* data)
- +{
- + int32_t kb, db;
- + for (db=7; db>=0; db--) {
- + for (kb=7; kb>3; kb--) {
- + int32_t a0=kb^db;
- + int32_t pos=7;
- + if (a0&4) {
- + a0^=7;
- + pos^=7;
- + }
- + a0=(a0^(kb&3)) + (kb&3);
- + if (!(a0&4)) {
- + data[db]^=(key2[kb] ^ ((data[kb^pos]*key2[kb^4]) & 0xFF));
- + }
- + }
- + }
- + for (db=0; db<8; db++) {
- + for (kb=0; kb<4; kb++) {
- + int32_t a0=kb^db;
- + int32_t pos=7;
- + if (a0&4) {
- + a0^=7;
- + pos^=7;
- + }
- + a0=(a0^(kb&3)) + (kb&3);
- + if (!(a0&4)) {
- + data[db]^=(key2[kb] ^ ((data[kb^pos]*key2[kb^4]) & 0xFF));
- + }
- + }
- + }
- +}
- +
- +static void Via1Decode(uint8_t *data, uint8_t *key)
- +{
- + Via1Mod(key+8, data);
- + nc_des(key, DES_ECM_CRYPT, data);
- + Via1Mod(key+8, data);
- +}
- +
- +static void Via1Hash(uint8_t *data, uint8_t *key)
- +{
- + Via1Mod(key+8, data);
- + nc_des(key, DES_ECM_HASH, data);
- + Via1Mod(key+8, data);
- +}
- +
- +static inline void Via1DoHash(uint8_t *hashbuffer, uint8_t *pH, uint8_t data, uint8_t *hashkey)
- +{
- + hashbuffer[*pH] ^= data;
- + (*pH)++;
- +
- + if(*pH == 8) {
- + Via1Hash(hashbuffer, hashkey);
- + *pH = 0;
- + }
- +}
- +
- +static int8_t Via1Decrypt(uint8_t* ecm, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex)
- +{
- + uint8_t work_key[16];
- + uint8_t *data, *des_data1, *des_data2;
- + uint16_t ecmLen = GetEcmLen(ecm);
- + int32_t msg_pos;
- + int32_t encStart = 0, hash_start, i;
- + uint8_t signature[8], hashbuffer[8], prepared_key[16], hashkey[16];
- + uint8_t tmp, k, pH, foundData = 0;
- +
- + if (ident == 0) {
- + return 4;
- + }
- + memset(work_key, 0, 16);
- + if(!GetViaKey(work_key, ident, '0', desKeyIndex, 8, 1)) {
- + return 2;
- + }
- +
- + if(ecmLen < 11) {
- + return 1;
- + }
- + data = ecm+9;
- + des_data1 = dw;
- + des_data2 = dw+8;
- +
- + msg_pos = 0;
- + pH = 0;
- + memset(hashbuffer, 0, sizeof(hashbuffer));
- + memcpy(hashkey, work_key, sizeof(hashkey));
- + memset(signature, 0, 8);
- +
- + while(9+msg_pos+2 < ecmLen) {
- + switch (data[msg_pos]) {
- + case 0xea:
- + if(9+msg_pos+2+15 < ecmLen) {
- + encStart = msg_pos + 2;
- + memcpy(des_data1, &data[msg_pos+2], 8);
- + memcpy(des_data2, &data[msg_pos+2+8], 8);
- + foundData |= 1;
- + }
- + break;
- + case 0xf0:
- + if(9+msg_pos+2+7 < ecmLen) {
- + memcpy(signature, &data[msg_pos+2], 8);
- + foundData |= 2;
- + }
- + break;
- + }
- + msg_pos += data[msg_pos+1]+2;
- + }
- +
- + if(foundData != 3) {
- + return 1;
- + }
- +
- + pH=i=0;
- +
- + if(data[0] == 0x9f && 10+data[1] <= ecmLen) {
- + Via1DoHash(hashbuffer, &pH, data[i++], hashkey);
- + Via1DoHash(hashbuffer, &pH, data[i++], hashkey);
- +
- + for (hash_start=0; hash_start < data[1]; hash_start++) {
- + Via1DoHash(hashbuffer, &pH, data[i++], hashkey);
- + }
- +
- + while (pH != 0) {
- + Via1DoHash(hashbuffer, &pH, 0, hashkey);
- + }
- + }
- +
- + if (work_key[7] == 0) {
- + for (; i < encStart + 16; i++) {
- + Via1DoHash(hashbuffer, &pH, data[i], hashkey);
- + }
- + memcpy(prepared_key, work_key, 8);
- + }
- + else {
- + prepared_key[0] = work_key[2];
- + prepared_key[1] = work_key[3];
- + prepared_key[2] = work_key[4];
- + prepared_key[3] = work_key[5];
- + prepared_key[4] = work_key[6];
- + prepared_key[5] = work_key[0];
- + prepared_key[6] = work_key[1];
- + prepared_key[7] = work_key[7];
- + memcpy(prepared_key+8, work_key+8, 8);
- +
- + if (work_key[7] & 1) {
- + for (; i < encStart; i++) {
- + Via1DoHash(hashbuffer, &pH, data[i], hashkey);
- + }
- +
- + k = ((work_key[7] & 0xf0) == 0) ? 0x5a : 0xa5;
- +
- + for (i=0; i<8; i++) {
- + tmp = des_data1[i];
- + des_data1[i] = (k & hashbuffer[pH] ) ^ tmp;
- + Via1DoHash(hashbuffer, &pH, tmp, hashkey);
- + }
- +
- + for (i = 0; i < 8; i++) {
- + tmp = des_data2[i];
- + des_data2[i] = (k & hashbuffer[pH] ) ^ tmp;
- + Via1DoHash(hashbuffer, &pH, tmp, hashkey);
- + }
- + }
- + else {
- + for (; i < encStart + 16; i++) {
- + Via1DoHash(hashbuffer, &pH, data[i], hashkey);
- + }
- + }
- + }
- + Via1Decode(des_data1, prepared_key);
- + Via1Decode(des_data2, prepared_key);
- + Via1Hash(hashbuffer, hashkey);
- + if(memcmp(signature, hashbuffer, 8)) {
- + return 6;
- + }
- + return 0;
- +}
- +
- +static int8_t Via26ProcessDw(uint8_t *indata, uint32_t ident, uint8_t desKeyIndex)
- +{
- + uint8_t pv1,pv2, i;
- + uint8_t Tmp[8], T1Key[300], P1Key[8], KeyDes1[16], KeyDes2[16], XorKey[8];
- + uint32_t ks1[32], ks2[32];
- +
- + if(!GetViaKey(T1Key, ident, 'T', 1, 300, 1)) {
- + return 2;
- + }
- + if(!GetViaKey(P1Key, ident, 'P', 1, 8, 1)) {
- + return 2;
- + }
- + if(!GetViaKey(KeyDes1, ident, 'D', 1, 16, 1)) {
- + return 2;
- + }
- + if(!GetViaKey(KeyDes2, ident, '0', desKeyIndex, 16, 1)) {
- + return 2;
- + }
- + if(!GetViaKey(XorKey, ident, 'X', 1, 8, 1)) {
- + return 2;
- + }
- +
- + for (i=0; i<8; i++) {
- + pv1 = indata[i];
- + Tmp[i] = T1Key[pv1];
- + }
- + for (i=0; i<8; i++) {
- + pv1 = P1Key[i];
- + pv2 = Tmp[pv1];
- + indata[i]=pv2;
- + }
- +
- + des_set_key(KeyDes1, ks1);
- + des(indata, ks1, 1);
- +
- + for (i=0; i<8; i++) {
- + indata[i] ^= XorKey[i];
- + }
- +
- + des_set_key(KeyDes2, ks1);
- + des_set_key(KeyDes2+8, ks2);
- + des(indata, ks1, 0);
- + des(indata, ks2, 1);
- + des(indata, ks1, 0);
- +
- + for (i=0; i<8; i++) {
- + indata[i] ^= XorKey[i];
- + }
- +
- + des_set_key(KeyDes1, ks1);
- + des(indata, ks1, 0);
- +
- + for (i=0; i<8; i++) {
- + pv1 = indata[i];
- + pv2 = P1Key[i];
- + Tmp[pv2] = pv1;
- + }
- + for (i=0; i<8; i++) {
- + pv1 = Tmp[i];
- + pv2 = T1Key[pv1];
- + indata[i] = pv2;
- + }
- + return 0;
- +}
- +
- +static int8_t Via26Decrypt(uint8_t* source, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex)
- +{
- + uint8_t tmpData[8], C1[8];
- + uint8_t *pXorVector;
- + int32_t i,j;
- +
- + if (ident == 0) {
- + return 4;
- + }
- + if(!GetViaKey(C1, ident, 'C', 1, 8, 1)) {
- + return 2;
- + }
- +
- + for (i=0; i<2; i++) {
- + memcpy(tmpData, source+ i*8, 8);
- + Via26ProcessDw(tmpData, ident, desKeyIndex);
- + if (i!=0) {
- + pXorVector = source;
- + }
- + else {
- + pXorVector = &C1[0];
- + }
- + for (j=0; j<8; j++) {
- + dw[i*8+j] = tmpData[j]^pXorVector[j];
- + }
- + }
- + return 0;
- +}
- +
- +static void Via3Core(uint8_t *data, uint8_t Off, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key)
- +{
- + uint8_t i;
- + uint32_t lR2, lR3, lR4, lR6, lR7;
- +
- + switch (ident) {
- + case 0x032820: {
- + for (i=0; i<4; i++) {
- + data[i]^= XorKey[(Off+i) & 0x07];
- + }
- + lR2 = (data[0]^0xBD)+data[0];
- + lR3 = (data[3]^0xEB)+data[3];
- + lR2 = (lR2-lR3)^data[2];
- + lR3 = ((0x39*data[1])<<2);
- + data[4] = (lR2|lR3)+data[2];
- + lR3 = ((((data[0]+6)^data[0]) | (data[2]<<1))^0x65)+data[0];
- + lR2 = (data[1]^0xED)+data[1];
- + lR7 = ((data[3]+0x29)^data[3])*lR2;
- + data[5] = lR7+lR3;
- + lR2 = ((data[2]^0x33)+data[2]) & 0x0A;
- + lR3 = (data[0]+0xAD)^data[0];
- + lR3 = lR3+lR2;
- + lR2 = data[3]*data[3];
- + lR7 = (lR2 | 1) + data[1];
- + data[6] = (lR3|lR7)+data[1];
- + lR3 = data[1] & 0x07;
- + lR2 = (lR3-data[2]) & (data[0] | lR2 |0x01);
- + data[7] = lR2+data[3];
- + for (i=0; i<4; i++) {
- + data[i+4] = T1Key[data[i+4]];
- + }
- + }
- + break;
- + case 0x030B00: {
- + for (i=0; i<4; i++) {
- + data[i]^= XorKey[(Off+i) & 0x07];
- + }
- + lR6 = (data[3] + 0x6E) ^ data[3];
- + lR6 = (lR6*(data[2] << 1)) + 0x17;
- + lR3 = (data[1] + 0x77) ^ data[1];
- + lR4 = (data[0] + 0xD7) ^ data[0];
- + data[4] = ((lR4 & lR3) | lR6) + data[0];
- + lR4 = ((data[3] + 0x71) ^ data[3]) ^ 0x90;
- + lR6 = (data[1] + 0x1B) ^ data[1];
- + lR4 = (lR4*lR6) ^ data[0];
- + data[5] = (lR4 ^ (data[2] << 1)) + data[1];
- + lR3 = (data[3] * data[3])| 0x01;
- + lR4 = (((data[2] ^ 0x35) + data[2]) | lR3) + data[2];
- + lR6 = data[1] ^ (data[0] + 0x4A);
- + data[6] = lR6 + lR4;
- + lR3 = (data[0] * (data[2] << 1)) | data[1];
- + lR4 = 0xFE - data[3];
- + lR3 = lR4 ^ lR3;
- + data[7] = lR3 + data[3];
- + for (i=0; i<4; i++) {
- + data[4+i] = T1Key[data[4+i]];
- + }
- + }
- + break;
- + default:
- + break;
- + }
- +}
- +
- +static void Via3Fct1(uint8_t *data, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key)
- +{
- + uint8_t t;
- + Via3Core(data, 0, ident, XorKey, T1Key);
- +
- + switch (ident) {
- + case 0x032820: {
- + t = data[4];
- + data[4] = data[7];
- + data[7] = t;
- + }
- + break;
- + case 0x030B00: {
- + t = data[5];
- + data[5] = data[7];
- + data[7] = t;
- + }
- + break;
- + default:
- + break;
- + }
- +}
- +
- +static void Via3Fct2(uint8_t *data, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key)
- +{
- + uint8_t t;
- + Via3Core(data, 4, ident, XorKey, T1Key);
- +
- + switch (ident) {
- + case 0x032820: {
- + t = data[4];
- + data[4] = data[7];
- + data[7] = data[5];
- + data[5] = data[6];
- + data[6] = t;
- + }
- + break;
- + case 0x030B00: {
- + t = data[6];
- + data[6] = data[7];
- + data[7] = t;
- + }
- + break;
- + default:
- + break;
- + }
- +}
- +
- +static int8_t Via3ProcessDw(uint8_t *data, uint32_t ident, uint8_t desKeyIndex)
- +{
- + uint8_t i;
- + uint8_t tmp[8], T1Key[300], P1Key[8], KeyDes[16], XorKey[8];
- + uint32_t ks1[32], ks2[32];
- +
- + if(!GetViaKey(T1Key, ident, 'T', 1, 300, 1)) {
- + return 2;
- + }
- + if(!GetViaKey(P1Key, ident, 'P', 1, 8, 1)) {
- + return 2;
- + }
- + if(!GetViaKey(KeyDes, ident, '0', desKeyIndex, 16, 1)) {
- + return 2;
- + }
- + if(!GetViaKey(XorKey, ident, 'X', 1, 8, 1)) {
- + return 2;
- + }
- +
- + for (i=0; i<4; i++) {
- + tmp[i] = data[i+4];
- + }
- + Via3Fct1(tmp, ident, XorKey, T1Key);
- + for (i=0; i<4; i++) {
- + tmp[i] = data[i]^tmp[i+4];
- + }
- + Via3Fct2(tmp, ident, XorKey, T1Key);
- + for (i=0; i<4; i++) {
- + tmp[i]^= XorKey[i+4];
- + }
- + for (i=0; i<4; i++) {
- + data[i] = data[i+4]^tmp[i+4];
- + data[i+4] = tmp[i];
- + }
- +
- + des_set_key(KeyDes, ks1);
- + des_set_key(KeyDes+8, ks2);
- +
- + des(data, ks1, 0);
- + des(data, ks2, 1);
- + des(data, ks1, 0);
- +
- + for (i=0; i<4; i++) {
- + tmp[i] = data[i+4];
- + }
- + Via3Fct2(tmp, ident, XorKey, T1Key);
- + for (i=0; i<4; i++) {
- + tmp[i] = data[i]^tmp[i+4];
- + }
- + Via3Fct1(tmp, ident, XorKey, T1Key);
- + for (i=0; i<4; i++) {
- + tmp[i]^= XorKey[i];
- + }
- + for (i=0; i<4; i++) {
- + data[i] = data[i+4]^tmp[i+4];
- + data[i+4] = tmp[i];
- + }
- + return 0;
- +}
- +
- +static void Via3FinalMix(uint8_t *dw)
- +{
- + uint8_t tmp[4];
- +
- + memcpy(tmp, dw, 4);
- + memcpy(dw, dw + 4, 4);
- + memcpy(dw + 4, tmp, 4);
- +
- + memcpy(tmp, dw + 8, 4);
- + memcpy(dw + 8, dw + 12, 4);
- + memcpy(dw + 12, tmp, 4);
- +}
- +
- +static int8_t Via3Decrypt(uint8_t* source, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex, uint8_t aesKeyIndex, uint8_t aesMode, int8_t doFinalMix)
- +{
- + int8_t aesAfterCore = 0;
- + int8_t needsAES = (aesKeyIndex != 0xFF);
- + uint8_t tmpData[8], C1[8];
- + uint8_t *pXorVector;
- + char aesKey[16];
- + int32_t i, j;
- +
- + if(ident == 0) {
- + return 4;
- + }
- + if(!GetViaKey(C1, ident, 'C', 1, 8, 1)) {
- + return 2;
- + }
- + if(needsAES && !GetViaKey((uint8_t*)aesKey, ident, 'E', aesKeyIndex, 16, 1)) {
- + return 2;
- + }
- + if(aesMode==0x0D || aesMode==0x11 || aesMode==0x15) {
- + aesAfterCore = 1;
- + }
- +
- + if(needsAES && !aesAfterCore) {
- + if(aesMode == 0x0F) {
- + hdSurEncPhase1_D2_0F_11(source);
- + hdSurEncPhase2_D2_0F_11(source);
- + }
- + else if(aesMode == 0x13) {
- + hdSurEncPhase1_D2_13_15(source);
- + }
- + struct aes_keys aes;
- + aes_set_key(&aes, aesKey);
- + aes_decrypt(&aes, source, 16);
- + if(aesMode == 0x0F) {
- + hdSurEncPhase1_D2_0F_11(source);
- + }
- + else if(aesMode == 0x13) {
- + hdSurEncPhase2_D2_13_15(source);
- + }
- + }
- +
- + for(i=0; i<2; i++) {
- + memcpy(tmpData, source+i*8, 8);
- + Via3ProcessDw(tmpData, ident, desKeyIndex);
- + if (i!=0) {
- + pXorVector = source;
- + }
- + else {
- + pXorVector = &C1[0];
- + }
- + for (j=0; j<8; j++) {
- + dw[i*8+j] = tmpData[j]^pXorVector[j];
- + }
- + }
- +
- + if(needsAES && aesAfterCore) {
- + if(aesMode == 0x11) {
- + hdSurEncPhase1_D2_0F_11(dw);
- + hdSurEncPhase2_D2_0F_11(dw);
- + }
- + else if(aesMode == 0x15) {
- + hdSurEncPhase1_D2_13_15(dw);
- + }
- + struct aes_keys aes;
- + aes_set_key(&aes, aesKey);
- + aes_decrypt(&aes, dw, 16);
- + if(aesMode == 0x11) {
- + hdSurEncPhase1_D2_0F_11(dw);
- + }
- + if(aesMode == 0x15) {
- + hdSurEncPhase2_D2_13_15(dw);
- + }
- + }
- +
- + if(ident == 0x030B00) {
- + if(doFinalMix) {
- + Via3FinalMix(dw);
- + }
- + if(!isValidDCW(dw)) {
- + return 6;
- + }
- + }
- + return 0;
- +}
- +
- +static int8_t ViaccessECM(uint8_t *ecm, uint8_t *dw)
- +{
- + uint32_t currentIdent = 0;
- + uint8_t nanoCmd = 0, nanoLen = 0, version = 0, providerKeyLen = 0, desKeyIndex = 0, aesMode = 0, aesKeyIndex = 0xFF;
- + int8_t doFinalMix = 0, result = 1;
- + uint16_t i = 0, keySelectPos = 0, ecmLen = GetEcmLen(ecm);
- +
- + for (i=4; i+2<ecmLen; ) {
- + nanoCmd = ecm[i++];
- + nanoLen = ecm[i++];
- + if(i+nanoLen > ecmLen) {
- + return 1;
- + }
- +
- + switch (nanoCmd) {
- + case 0x40:
- + if (nanoLen < 0x03) {
- + break;
- + }
- + version = ecm[i];
- + if (nanoLen == 3) {
- + currentIdent=((ecm[i]<<16)|(ecm[i+1]<<8))|(ecm[i+2]&0xF0);
- + desKeyIndex = ecm[i+2]&0x0F;
- + keySelectPos = i+3;
- + }
- + else {
- + currentIdent =(ecm[i]<<16)|(ecm[i+1]<<8)|((ecm[i+2]>>4)&0x0F);
- + desKeyIndex = ecm[i+3];
- + keySelectPos = i+4;
- + }
- + providerKeyLen = nanoLen;
- + break;
- + case 0x90:
- + if (nanoLen < 0x03) {
- + break;
- + }
- + version = ecm[i];
- + currentIdent= ((ecm[i]<<16)|(ecm[i+1]<<8))|(ecm[i+2]&0xF0);
- + desKeyIndex = ecm[i+2]&0x0F;
- + keySelectPos = i+4;
- + if((version == 3) && (nanoLen > 3)) {
- + desKeyIndex = ecm[i+(nanoLen-4)]&0x0F;
- + }
- + providerKeyLen = nanoLen;
- + break;
- + case 0x80:
- + nanoLen = 0;
- + break;
- + case 0xD2:
- + if (nanoLen < 0x02) {
- + break;
- + }
- + aesMode = ecm[i];
- + aesKeyIndex = ecm[i+1];
- + break;
- + case 0xDD:
- + nanoLen = 0;
- + break;
- + case 0xEA:
- + if (nanoLen < 0x10) {
- + break;
- + }
- +
- + if (version < 2) {
- + return Via1Decrypt(ecm, dw, currentIdent, desKeyIndex);
- + }
- + else if (version == 2) {
- + return Via26Decrypt(ecm + i, dw, currentIdent, desKeyIndex);
- + }
- + else if (version == 3) {
- + doFinalMix = 0;
- + if (currentIdent == 0x030B00 && providerKeyLen>3) {
- + if(keySelectPos+2 >= ecmLen) {
- + break;
- + }
- + if (ecm[keySelectPos]==0x05 && ecm[keySelectPos+1]==0x67 && (ecm[keySelectPos+2]==0x00 || ecm[keySelectPos+2]==0x01)) {
- + if(ecm[keySelectPos+2]==0x01) {
- + doFinalMix = 1;
- + }
- + }
- + else {
- + break;
- + }
- + }
- + return Via3Decrypt(ecm + i, dw, currentIdent, desKeyIndex, aesKeyIndex, aesMode, doFinalMix);
- + }
- + break;
- + default:
- + break;
- + }
- + i += nanoLen;
- + }
- + return result;
- +}
- +
- +// Nagra EMU
- +static int8_t GetNagraKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint8_t isCriticalKey)
- +{
- + char keyStr[EMU_MAX_CHAR_KEYNAME];
- + snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex);
- + if(FindKey('N', ident, keyStr, buf, keyName == 'M' ? 64 : 16, isCriticalKey, 0, 0, NULL)) {
- + return 1;
- + }
- +
- + return 0;
- +}
- +
- +static int8_t Nagra2Signature(const uint8_t *vkey, const uint8_t *sig, const uint8_t *msg, int32_t len)
- +{
- + uint8_t buff[16];
- + uint8_t iv[8];
- + int32_t i,j;
- +
- + memcpy(buff,vkey,sizeof(buff));
- + for(i=0; i+7<len; i+=8) {
- + IDEA_KEY_SCHEDULE ek;
- + idea_set_encrypt_key(buff, &ek);
- + memcpy(buff,buff+8,8);
- + memset(iv,0,sizeof(iv));
- + idea_cbc_encrypt(msg+i,buff+8,8,&ek,iv,IDEA_ENCRYPT);
- + for(j=7; j>=0; j--) {
- + buff[j+8]^=msg[i+j];
- + }
- + }
- + buff[8]&=0x7F;
- + return (memcmp(sig,buff+8,8)==0);
- +}
- +
- +static int8_t DecryptNagra2ECM(uint8_t *in, uint8_t *out, const uint8_t *key, int32_t len, const uint8_t *vkey, uint8_t *keyM)
- +{
- + BIGNUM *exp, *mod;
- + uint8_t iv[8];
- + int32_t i = 0, sign = in[0] & 0x80;
- + uint8_t binExp = 3;
- + int8_t result = 1;
- +
- + exp = BN_new();
- + mod = BN_new();
- + BN_bin2bn(&binExp, 1, exp);
- + BN_bin2bn(keyM, 64, mod);
- +
- + if(EmuRSA(out,in+1,64,exp,mod,1)<=0) {
- + BN_free(exp);
- + BN_free(mod);
- + return 0;
- + }
- + out[63]|=sign;
- + if(len>64) {
- + memcpy(out+64,in+65,len-64);
- + }
- +
- + memset(iv,0,sizeof(iv));
- + if(in[0]&0x04) {
- + uint8_t key1[8], key2[8];
- + ReverseMemInOut(key1,&key[0],8);
- + ReverseMemInOut(key2,&key[8],8);
- +
- + for(i=7; i>=0; i--) {
- + ReverseMem(out+8*i,8);
- + }
- + des_ede2_cbc_decrypt(out, iv, key1, key2, len);
- + for(i=7; i>=0; i--) {
- + ReverseMem(out+8*i,8);
- + }
- + }
- + else {
- + IDEA_KEY_SCHEDULE ek;
- + idea_set_encrypt_key(key, &ek);
- + idea_cbc_encrypt(out, out, len&~7, &ek, iv, IDEA_DECRYPT);
- + }
- +
- + ReverseMem(out,64);
- + if(result && EmuRSA(out,out,64,exp,mod,0)<=0) {
- + result = 0;
- + }
- + if(result && vkey && !Nagra2Signature(vkey,out,out+8,len-8)) {
- + result = 0;
- + }
- +
- + BN_free(exp);
- + BN_free(mod);
- + return result;
- +}
- +
- +static int8_t Nagra2ECM(uint8_t *ecm, uint8_t *dw)
- +{
- + uint32_t ident, identMask, tmp1, tmp2, tmp3;
- + uint8_t cmdLen, ideaKeyNr, *dec, ideaKey[16], vKey[16], m1Key[64], mecmAlgo = 0;
- + int8_t useVerifyKey = 0;
- + int32_t l=0, s;
- + uint16_t i = 0, ecmLen = GetEcmLen(ecm);
- +
- + if(ecmLen < 8) {
- + return 1;
- + }
- + cmdLen = ecm[4] - 5;
- + ident = (ecm[5] << 8) + ecm[6];
- + ideaKeyNr = (ecm[7]&0x10)>>4;
- + if(ideaKeyNr) {
- + ideaKeyNr = 1;
- + }
- + if(ident == 1283 || ident == 1285 || ident == 1297) {
- + ident = 1281;
- + }
- + if(cmdLen <= 63 || ecmLen < cmdLen + 10) {
- + return 1;
- + }
- +
- + if(!GetNagraKey(ideaKey, ident, '0', ideaKeyNr, 1)) {
- + return 2;
- + }
- + if(GetNagraKey(vKey, ident, 'V', 0, 0)) {
- + useVerifyKey = 1;
- + }
- + if(!GetNagraKey(m1Key, ident, 'M', 1, 1)) {
- + return 2;
- + }
- + ReverseMem(m1Key, 64);
- +
- + dec = (uint8_t*)malloc(sizeof(uint8_t)*cmdLen);
- + if(dec == NULL) {
- + return 7;
- + }
- + if(!DecryptNagra2ECM(ecm+9, dec, ideaKey, cmdLen, useVerifyKey?vKey:0, m1Key)) {
- + free(dec);
- + return 1;
- + }
- +
- + for(i=(dec[14]&0x10)?16:20; i<cmdLen && l!=3; ) {
- + switch(dec[i]) {
- + case 0x10:
- + case 0x11:
- + if(i+10 < cmdLen && dec[i+1]==0x09) {
- + s = (~dec[i])&1;
- + mecmAlgo = dec[i+2]&0x60;
- + memcpy(dw+(s<<3),&dec[i+3],8);
- + i+=11;
- + l|=(s+1);
- + }
- + else {
- + i++;
- + }
- + break;
- + case 0x00:
- + i+=2;
- + break;
- + case 0x30:
- + case 0x31:
- + case 0x32:
- + case 0x33:
- + case 0x34:
- + case 0x35:
- + case 0x36:
- + case 0xB0:
- + if(i+1 < cmdLen) {
- + i+=dec[i+1]+2;
- + }
- + else {
- + i++;
- + }
- + break;
- + default:
- + i++;
- + continue;
- + }
- + }
- +
- + free(dec);
- +
- + if(l!=3) {
- + return 1;
- + }
- + if(mecmAlgo>0) {
- + return 1;
- + }
- +
- + identMask = ident & 0xFF00;
- + if (identMask == 0x1100 || identMask == 0x500 || identMask == 0x3100) {
- + memcpy(&tmp1, dw, 4);
- + memcpy(&tmp2, dw + 4, 4);
- + memcpy(&tmp3, dw + 12, 4);
- + memcpy(dw, dw + 8, 4);
- + memcpy(dw + 4, &tmp3, 4);
- + memcpy(dw + 8, &tmp1, 4);
- + memcpy(dw + 12, &tmp2, 4);
- + }
- + return 0;
- +}
- +
- +// Irdeto EMU
- +static int8_t GetIrdetoKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint8_t isCriticalKey, uint16_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, keyStr, buf, 16, *keyRef > 0 ? 0 : isCriticalKey, (uint8_t)*keyRef, 0, NULL)) {
- + (*keyRef)++;
- + return 1;
- + }
- +
- + return 0;
- +}
- +
- +static void Irdeto2Encrypt(uint8_t *data, const uint8_t *seed, const uint8_t *key, int32_t len)
- +{
- + const uint8_t *tmp = seed;;
- + int32_t i;
- + uint32_t ks1[32], ks2[32];
- +
- + des_set_key(key, ks1);
- + des_set_key(key+8, ks2);
- +
- + len&=~7;
- +
- + for(i=0; i+7<len; i+=8) {
- + xxor(&data[i],8,&data[i],tmp);
- + tmp=&data[i];
- + des(&data[i], ks1, 1);
- + des(&data[i], ks2, 0);
- + des(&data[i], ks1, 1);
- + }
- +}
- +
- +static void Irdeto2Decrypt(uint8_t *data, const uint8_t *seed, const uint8_t *key, int32_t len)
- +{
- + uint8_t buf[2][8];
- + int32_t i, n=0;
- + uint32_t ks1[32], ks2[32];
- +
- + des_set_key(key, ks1);
- + des_set_key(key+8, ks2);
- +
- + len&=~7;
- +
- + memcpy(buf[n],seed,8);
- + for(i=0; i+7<len; i+=8,data+=8,n^=1) {
- + memcpy(buf[1-n],data,8);
- + des(data, ks1, 0);
- + des(data, ks2, 1);
- + des(data, ks1, 0);
- + xxor(data,8,data,buf[n]);
- + }
- +}
- +
- +static int8_t Irdeto2CalculateHash(const uint8_t *key, const uint8_t *iv, const uint8_t *data, int32_t len)
- +{
- + uint8_t cbuff[8];
- + int32_t l, y;
- + uint32_t ks1[32], ks2[32];
- +
- + des_set_key(key, ks1);
- + des_set_key(key+8, ks2);
- +
- + memset(cbuff,0,sizeof(cbuff));
- + len-=8;
- +
- + for(y=0; y<len; y+=8) {
- + if(y<len-8) {
- + xxor(cbuff,8,cbuff,&data[y]);
- + }
- + else {
- + l=len-y;
- + xxor(cbuff,l,cbuff,&data[y]);
- + xxor(cbuff+l,8-l,cbuff+l,iv+8);
- + }
- +
- + des(cbuff, ks1, 1);
- + des(cbuff, ks2, 0);
- + des(cbuff, ks1, 1);
- + }
- +
- + return memcmp(cbuff,&data[len],8)==0;
- +}
- +
- +static int8_t Irdeto2ECM(uint16_t caid, uint8_t *oecm, uint8_t *dw)
- +{
- + uint8_t keyNr=0, length, end, key[16], okeySeed[16], keySeed[16], keyIV[16], tmp[16];
- + uint32_t i, l, ident;
- + uint16_t key0Ref, keySeedRef, keyIVRef;
- + uint8_t ecmCopy[EMU_MAX_ECM_LEN], *ecm = oecm;
- + uint16_t ecmLen = GetEcmLen(ecm);
- +
- + if(ecmLen < 12) {
- + return 1;
- + }
- +
- + length = ecm[11];
- + keyNr = ecm[9];
- + ident = ecm[8] | caid << 8;
- +
- + if(ecmLen < length+12) {
- + return 1;
- + }
- +
- + key0Ref = 0;
- + while(GetIrdetoKey(key, ident, '0', keyNr, 1, &key0Ref)) {
- + keySeedRef = 0;
- + while(GetIrdetoKey(okeySeed, ident, 'M', 1, 1, &keySeedRef)) {
- + keyIVRef = 0;
- + while(GetIrdetoKey(keyIV, ident, 'M', 2, 1, &keyIVRef)) {
- +
- + memcpy(keySeed, okeySeed, 16);
- + memcpy(ecmCopy, oecm, ecmLen);
- + ecm = ecmCopy;
- +
- + memset(tmp, 0, 16);
- + Irdeto2Encrypt(keySeed, tmp, key, 16);
- + ecm+=12;
- + Irdeto2Decrypt(ecm, keyIV, keySeed, length);
- + i=(ecm[0]&7)+1;
- + end = length-8 < 0 ? 0 : length-8;
- +
- + while(i<end) {
- + l = ecm[i+1] ? (ecm[i+1]&0x3F)+2 : 1;
- + switch(ecm[i]) {
- + case 0x10:
- + case 0x50:
- + if(l==0x13 && i<=length-8-l) {
- + Irdeto2Decrypt(&ecm[i+3], keyIV, key, 16);
- + }
- + break;
- + case 0x78:
- + if(l==0x14 && i<=length-8-l) {
- + Irdeto2Decrypt(&ecm[i+4], keyIV, key, 16);
- + }
- + break;
- + }
- + i+=l;
- + }
- +
- + i=(ecm[0]&7)+1;
- + if(Irdeto2CalculateHash(keySeed, keyIV, ecm-6, length+6)) {
- + while(i<end) {
- + l = ecm[i+1] ? (ecm[i+1]&0x3F)+2 : 1;
- + switch(ecm[i]) {
- + case 0x78:
- + if(l==0x14 && i<=length-8-l) {
- + memcpy(dw, &ecm[i+4], 16);
- + return 0;
- + }
- + }
- + i+=l;
- + }
- + }
- + }
- + if(keyIVRef == 0) {
- + return 2;
- + }
- + }
- + if(keySeedRef == 0) {
- + return 2;
- + }
- + }
- + if(key0Ref == 0) {
- + return 2;
- + }
- +
- + return 1;
- +}
- +
- +// BISS Emu
- +static int8_t BissECM(uint16_t UNUSED(caid), const uint8_t *ecm, int16_t ecmDataLen,
- + uint8_t *dw, uint16_t srvid, uint16_t ecmpid)
- +{
- + uint8_t haveKey1 = 0, haveKey2 = 0;
- + uint16_t ecmLen = 0, pid = 0;
- + uint32_t i;
- +
- + //try using ecmpid if it seems to be valid
- + if(ecmpid != 0) {
- + haveKey1 = FindKey('F', (srvid<<16)|ecmpid, "00", dw, 8, 1, 0, 0, NULL);
- + haveKey2 = FindKey('F', (srvid<<16)|ecmpid, "01", &dw[8], 8, 1, 0, 0, NULL);
- +
- + if(haveKey1 && haveKey2) {return 0;}
- + else if(haveKey1 && !haveKey2) {memcpy(&dw[8], dw, 8); return 0;}
- + else if(!haveKey1 && haveKey2) {memcpy(dw, &dw[8], 8); return 0;}
- + }
- +
- + //try to get the pid from oscam's fake ecm ([sid] ([pid1] [pid2] ... [pidx])
- + if(ecmDataLen >= 3) {
- + ecmLen = GetEcmLen(ecm);
- +
- + if(ecmLen > 7 && ecmLen <= ecmDataLen) {
- + for(i=5; i+1<ecmLen; i+=2) {
- + pid = b2i(2, ecm+i);
- + haveKey1 = FindKey('F', (srvid<<16)|pid, "00", dw, 8, 1, 0, 0, NULL);
- + haveKey2 = FindKey('F', (srvid<<16)|pid, "01", &dw[8], 8, 1, 0, 0, NULL);
- +
- + if(haveKey1 && haveKey2) {return 0;}
- + else if(haveKey1 && !haveKey2) {memcpy(&dw[8], dw, 8); return 0;}
- + else if(!haveKey1 && haveKey2) {memcpy(dw, &dw[8], 8); return 0;}
- + }
- + }
- + }
- +
- + //fallback to default pid
- + haveKey1 = FindKey('F', (srvid<<16)|0x1FFF, "00", dw, 8, 1, 0, 0, NULL);
- + haveKey2 = FindKey('F', (srvid<<16)|0x1FFF, "01", &dw[8], 8, 1, 0, 0, NULL);
- +
- + if(haveKey1 && haveKey2) {return 0;}
- + else if(haveKey1 && !haveKey2) {memcpy(&dw[8], dw, 8); return 0;}
- + else if(!haveKey1 && haveKey2) {memcpy(dw, &dw[8], 8); return 0;}
- +
- + return 2;
- +}
- +
- +//PowerVu Emu
- +static int8_t GetPowervuKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey, uint16_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('P', ident, keyStr, buf, keyLength, isCriticalKey, (uint8_t)keyRef, 0, NULL)) {
- + return 1;
- + }
- +
- + return 0;
- +}
- +
- +static int8_t GetPowervuEmmKey(uint8_t *buf, uint32_t ident, char *keyName, uint32_t keyLength, uint8_t isCriticalKey, uint32_t *getProvider)
- +{
- + if(FindKey('P', ident, keyName, buf, keyLength, isCriticalKey, 0, 0, getProvider)) {
- + return 1;
- + }
- +
- + return 0;
- +}
- +
- +static const uint8_t PowerVu_A0_S_1[16] = {0x33, 0xA4, 0x44, 0x3C, 0xCA, 0x2E, 0x75, 0x7B, 0xBC, 0xE6, 0xE5, 0x35, 0xA0, 0x55, 0xC9, 0xA2};
- +static const uint8_t PowerVu_A0_S_2[16] = {0x5A, 0xB0, 0x2C, 0xBC, 0xDA, 0x32, 0xE6, 0x92, 0x40, 0x53, 0x6E, 0xF9, 0x69, 0x11, 0x1E, 0xFB};
- +static const uint8_t PowerVu_A0_S_3[16] = {0x4E, 0x18, 0x9B, 0x19, 0x79, 0xFB, 0x01, 0xFA, 0xE3, 0xE1, 0x28, 0x3D, 0x32, 0xE4, 0x92, 0xEA};
- +static const uint8_t PowerVu_A0_S_4[16] = {0x05, 0x6F, 0x37, 0x66, 0x35, 0xE1, 0x58, 0xD0, 0xB4, 0x6A, 0x97, 0xAE, 0xD8, 0x91, 0x27, 0x56};
- +static const uint8_t PowerVu_A0_S_5[16] = {0x7B, 0x26, 0xAD, 0x34, 0x3D, 0x77, 0x39, 0x51, 0xE0, 0xE0, 0x48, 0x8C, 0x39, 0xF5, 0xE8, 0x47};
- +static const uint8_t PowerVu_A0_S_6[16] = {0x74, 0xFA, 0x4D, 0x79, 0x42, 0x39, 0xD1, 0xA4, 0x99, 0xA3, 0x97, 0x07, 0xDF, 0x14, 0x3A, 0xC4};
- +static const uint8_t PowerVu_A0_S_7[16] = {0xC6, 0x1E, 0x3C, 0x24, 0x11, 0x08, 0x5D, 0x6A, 0xEB, 0x97, 0xB9, 0x25, 0xA7, 0xFA, 0xE9, 0x1A};
- +static const uint8_t PowerVu_A0_S_8[16] = {0x9A, 0xAD, 0x72, 0xD7, 0x7C, 0x68, 0x3B, 0x55, 0x1D, 0x4A, 0xA2, 0xB0, 0x38, 0xB9, 0x56, 0xD0};
- +static const uint8_t PowerVu_A0_S_9[32] = {0x61, 0xDA, 0x5F, 0xB7, 0xEB, 0xC6, 0x3F, 0x6C, 0x09, 0xF3, 0x64, 0x38, 0x33, 0x08, 0xAA, 0x15,
- + 0xCC, 0xEF, 0x22, 0x64, 0x01, 0x2C, 0x12, 0xDE, 0xF4, 0x6E, 0x3C, 0xCD, 0x1A, 0x64, 0x63, 0x7C
- + };
- +
- +static const uint8_t PowerVu_00_S_1[16] = {0x97, 0x13, 0xEB, 0x6B, 0x04, 0x5E, 0x60, 0x3A, 0xD9, 0xCC, 0x91, 0xC2, 0x5A, 0xFD, 0xBA, 0x0C};
- +static const uint8_t PowerVu_00_S_2[16] = {0x61, 0x3C, 0x03, 0xB0, 0xB5, 0x6F, 0xF8, 0x01, 0xED, 0xE0, 0xE5, 0xF3, 0x78, 0x0F, 0x0A, 0x73};
- +static const uint8_t PowerVu_00_S_3[16] = {0xFD, 0xDF, 0xD2, 0x97, 0x06, 0x14, 0x91, 0xB5, 0x36, 0xAD, 0xBC, 0xE1, 0xB3, 0x00, 0x66, 0x41};
- +static const uint8_t PowerVu_00_S_4[16] = {0x8B, 0xD9, 0x18, 0x0A, 0xED, 0xEE, 0x61, 0x34, 0x1A, 0x79, 0x80, 0x8C, 0x1E, 0x7F, 0xC5, 0x9F};
- +static const uint8_t PowerVu_00_S_5[16] = {0xB0, 0xA1, 0xF2, 0xB8, 0xEA, 0x72, 0xDD, 0xD3, 0x30, 0x65, 0x2B, 0x1E, 0xE9, 0xE1, 0x45, 0x29};
- +static const uint8_t PowerVu_00_S_6[16] = {0x5D, 0xCA, 0x53, 0x75, 0xB2, 0x24, 0xCE, 0xAF, 0x21, 0x54, 0x9E, 0xBE, 0x02, 0xA9, 0x4C, 0x5D};
- +static const uint8_t PowerVu_00_S_7[16] = {0x42, 0x66, 0x72, 0x83, 0x1B, 0x2D, 0x22, 0xC9, 0xF8, 0x4D, 0xBA, 0xCD, 0xBB, 0x20, 0xBD, 0x6B};
- +static const uint8_t PowerVu_00_S_8[16] = {0xC4, 0x0C, 0x6B, 0xD3, 0x6D, 0x94, 0x7E, 0x53, 0xCE, 0x96, 0xAC, 0x40, 0x2C, 0x7A, 0xD3, 0xA9};
- +static const uint8_t PowerVu_00_S_9[32] = {0x31, 0x82, 0x4F, 0x9B, 0xCB, 0x6F, 0x9D, 0xB7, 0xAE, 0x68, 0x0B, 0xA0, 0x93, 0x15, 0x32, 0xE2,
- + 0xED, 0xE9, 0x47, 0x29, 0xC2, 0xA8, 0x92, 0xEF, 0xBA, 0x27, 0x22, 0x57, 0x76, 0x54, 0xC0, 0x59,
- + };
- +
- +static uint8_t PowervuSbox(uint8_t *input, uint8_t mode)
- +{
- + uint8_t s_index, bit, last_index, last_bit;
- + uint8_t const *Sbox1, *Sbox2, *Sbox3, *Sbox4, *Sbox5, *Sbox6, *Sbox7, *Sbox8, *Sbox9;
- +
- + if(mode)
- + {
- + Sbox1 = PowerVu_A0_S_1;
- + Sbox2 = PowerVu_A0_S_2;
- + Sbox3 = PowerVu_A0_S_3;
- + Sbox4 = PowerVu_A0_S_4;
- + Sbox5 = PowerVu_A0_S_5;
- + Sbox6 = PowerVu_A0_S_6;
- + Sbox7 = PowerVu_A0_S_7;
- + Sbox8 = PowerVu_A0_S_8;
- + Sbox9 = PowerVu_A0_S_9;
- + }
- + else
- + {
- + Sbox1 = PowerVu_00_S_1;
- + Sbox2 = PowerVu_00_S_2;
- + Sbox3 = PowerVu_00_S_3;
- + Sbox4 = PowerVu_00_S_4;
- + Sbox5 = PowerVu_00_S_5;
- + Sbox6 = PowerVu_00_S_6;
- + Sbox7 = PowerVu_00_S_7;
- + Sbox8 = PowerVu_00_S_8;
- + Sbox9 = PowerVu_00_S_9;
- + }
- +
- + bit = (GetBit(input[2],0)<<2) | (GetBit(input[3],4)<<1) | (GetBit(input[5],3));
- + s_index = (GetBit(input[0],0)<<3) | (GetBit(input[2],6)<<2) | (GetBit(input[2],4)<<1) | (GetBit(input[5],7));
- + last_bit = GetBit(Sbox1[s_index],7-bit);
- +
- + bit = (GetBit(input[5],0)<<2) | (GetBit(input[4],0)<<1) | (GetBit(input[6],2));
- + s_index = (GetBit(input[2],1)<<3) | (GetBit(input[2],2)<<2) | (GetBit(input[5],5)<<1) | (GetBit(input[5],1));
- + last_bit = last_bit | (GetBit(Sbox2[s_index],7-bit)<<1);
- +
- + bit = (GetBit(input[6],0)<<2) | (GetBit(input[1],7)<<1) | (GetBit(input[6],7));
- + s_index = (GetBit(input[1],3)<<3) | (GetBit(input[3],7)<<2) | (GetBit(input[1],5)<<1) | (GetBit(input[5],2));
- + last_bit = last_bit | (GetBit(Sbox3[s_index], 7-bit)<<2);
- +
- + bit = (GetBit(input[1],0)<<2) | (GetBit(input[2],7)<<1) | (GetBit(input[2],5));
- + s_index = (GetBit(input[6],3)<<3) | (GetBit(input[6],4)<<2) | (GetBit(input[6],6)<<1) | (GetBit(input[3],5));
- + last_index = GetBit(Sbox4[s_index], 7-bit);
- +
- + bit = (GetBit(input[3],3)<<2) | (GetBit(input[4],6)<<1) | (GetBit(input[3],2));
- + s_index = (GetBit(input[3],1)<<3) | (GetBit(input[4],5)<<2) | (GetBit(input[3],0)<<1) | (GetBit(input[4],7));
- + last_index = last_index | (GetBit(Sbox5[s_index], 7-bit)<<1);
- +
- + bit = (GetBit(input[5],4)<<2) | (GetBit(input[4],4)<<1) | (GetBit(input[1],2));
- + s_index = (GetBit(input[2],3)<<3) | (GetBit(input[6],5)<<2) | (GetBit(input[1],4)<<1) | (GetBit(input[4],1));
- + last_index = last_index | (GetBit(Sbox6[s_index], 7-bit)<<2);
- +
- + bit = (GetBit(input[0],6)<<2) | (GetBit(input[0],7)<<1) | (GetBit(input[0],4));
- + s_index = (GetBit(input[0],5)<<3) | (GetBit(input[0],3)<<2) | (GetBit(input[0],1)<<1) | (GetBit(input[0],2));
- + last_index = last_index | (GetBit(Sbox7[s_index], 7-bit)<<3);
- +
- + bit = (GetBit(input[4],2)<<2) | (GetBit(input[4],3)<<1) | (GetBit(input[1],1));
- + s_index = (GetBit(input[1],6)<<3) | (GetBit(input[6],1)<<2) | (GetBit(input[5],6)<<1) | (GetBit(input[3],6));
- + last_index = last_index | (GetBit(Sbox8[s_index], 7-bit)<<4);
- +
- + return (GetBit(Sbox9[last_index&0x1f],7-last_bit)&1) ? 1: 0;
- +}
- +
- +static void PowervuDecrypt(uint8_t *data, uint32_t length, uint8_t *key, uint8_t sbox)
- +{
- + uint32_t i;
- + int32_t j, k;
- + uint8_t curByte, tmpBit;
- +
- + for(i=0; i<length; i++)
- + {
- + curByte = data[i];
- +
- + for(j=7; j>=0; j--)
- + {
- + data[i] = SetBit(data[i], j,(GetBit(curByte,j)^PowervuSbox(key, sbox))^GetBit(key[0],7));
- +
- + tmpBit = GetBit(data[i],j)^(GetBit(key[6],0));
- + if (tmpBit)
- + {
- + key[3] ^= 0x10;
- + }
- +
- + for (k = 6; k > 0; k--)
- + {
- + key[k] = (key[k]>>1) | (key[k-1]<<7);
- + }
- + key[0] = (key[0]>>1);
- +
- + key[0] = SetBit(key[0], 7, tmpBit);
- + }
- + }
- +}
- +
- +#define PVU_CW_VID 0 // VIDeo
- +#define PVU_CW_HSD 1 // High Speed Data
- +#define PVU_CW_A1 2 // Audio 1
- +#define PVU_CW_A2 3 // Audio 2
- +#define PVU_CW_A3 4 // Audio 3
- +#define PVU_CW_A4 5 // Audio 4
- +#define PVU_CW_UTL 6 // UTiLity
- +#define PVU_CW_VBI 7 // Vertical Blanking Interval
- +
- +#define PVU_CONVCW_VID_ECM 0x80 // VIDeo
- +#define PVU_CONVCW_HSD_ECM 0x40 // High Speed Data
- +#define PVU_CONVCW_A1_ECM 0x20 // Audio 1
- +#define PVU_CONVCW_A2_ECM 0x10 // Audio 2
- +#define PVU_CONVCW_A3_ECM 0x08 // Audio 3
- +#define PVU_CONVCW_A4_ECM 0x04 // Audio 4
- +#define PVU_CONVCW_UTL_ECM 0x02 // UTiLity
- +#define PVU_CONVCW_VBI_ECM 0x01 // Vertical Blanking Interval
- +
- +static uint8_t PowervuGetConvcwIndex(uint8_t ecmTag)
- +{
- + switch(ecmTag)
- + {
- + case PVU_CONVCW_VID_ECM:
- + return PVU_CW_VID;
- +
- + case PVU_CONVCW_HSD_ECM:
- + return PVU_CW_HSD;
- +
- + case PVU_CONVCW_A1_ECM:
- + return PVU_CW_A1;
- +
- + case PVU_CONVCW_A2_ECM:
- + return PVU_CW_A2;
- +
- + case PVU_CONVCW_A3_ECM:
- + return PVU_CW_A3;
- +
- + case PVU_CONVCW_A4_ECM:
- + return PVU_CW_A4;
- +
- + case PVU_CONVCW_UTL_ECM:
- + return PVU_CW_UTL;
- +
- + case PVU_CONVCW_VBI_ECM:
- + return PVU_CW_VBI;
- +
- + default:
- + return PVU_CW_VBI;
- + }
- +}
- +
- +static uint16_t PowervuGetSeedIV(uint8_t seedType, uint8_t *ecm)
- +{
- + switch(seedType)
- + {
- + case PVU_CW_VID:
- + return ((ecm[0x10] & 0x1F) <<3) | 0;
- + case PVU_CW_HSD:
- + return ((ecm[0x12] & 0x1F) <<3) | 2;
- + case PVU_CW_A1:
- + return ((ecm[0x11] & 0x3F) <<3) | 1;
- + case PVU_CW_A2:
- + return ((ecm[0x13] & 0x3F) <<3) | 1;
- + case PVU_CW_A3:
- + return ((ecm[0x19] & 0x3F) <<3) | 1;
- + case PVU_CW_A4:
- + return ((ecm[0x1A] & 0x3F) <<3) | 1;;
- + case PVU_CW_UTL:
- + return ((ecm[0x14] & 0x0F) <<3) | 4;
- + case PVU_CW_VBI:
- + return (((ecm[0x15] & 0xF8)>>3)<<3) | 5;
- + default:
- + return 0;
- + }
- +}
- +
- +static 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;
- + uint16_t keyRef1, keyRef2;
- +#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("[Emu] 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
- + if(cdata != NULL || update_global_key || cw_ex != NULL)
- +#else
- + if(cdata != NULL)
- +#endif
- + {
- + // 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
- +
- +static int8_t GetDrecryptKey(uint8_t *buf, uint32_t keyIdent, uint16_t keyName, uint8_t isCriticalKey, uint8_t *keyRef)
- +{
- + char keyStr[EMU_MAX_CHAR_KEYNAME];
- + snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%X", keyName);
- + if(FindKey('D', keyIdent, keyStr, buf, 32, *keyRef > 0 ? 0 : isCriticalKey, *keyRef, 0, NULL)) {
- + (*keyRef)++;
- + return 1;
- + }
- +
- + return 0;
- +}
- +
- +static void DrecryptOver(const unsigned char *ECMdata, unsigned char *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, 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 DrecryptGostDec(uint32_t inData)
- +{
- + static const uint8_t DrecryptSbox[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) | (DrecryptSbox[i*16 + j] & 0x0F);
- + }
- +
- + inData= (inData << 11) | (inData >> 21);
- +
- + return (inData);
- +}
- +
- +static void DrecryptDecrypt(uint8_t *Data, uint8_t *Key)
- +{
- + int32_t 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^= DrecryptGostDec(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^= DrecryptGostDec(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^= DrecryptGostDec(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^= DrecryptGostDec(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(uint16_t caid, uint32_t provId, uint8_t *ecm, uint8_t *dw)
- +{
- + uint8_t keyType, keyIndex, keyRef, ccw[16], key[32];
- + uint16_t keyName, overcryptId;
- + uint32_t keyIdent;
- +
- + uint16_t ecmLen = GetEcmLen(ecm);
- + if(ecmLen < 30 || caid != 0x4AE1) {
- + return 1;
- + }
- +
- + switch(provId & 0xFF)
- + {
- + case 0x11:
- + case 0x14:
- + break;
- + default:
- + return 1;
- + }
- +
- + keyType = ecm[6];
- + keyIndex = ecm[5];
- +
- + keyIdent = caid<<8 | provId;
- + keyName = keyType<<8 | keyIndex;
- +
- + keyRef = 0;
- + while(GetDrecryptKey(key, keyIdent, keyName, 1, &keyRef))
- + {
- + memcpy(ccw, ecm+13, 16);
- + DrecryptPostCw(key);
- + DrecryptPostCw(key+16);
- + DrecryptDecrypt(ccw, key);
- + DrecryptDecrypt(ccw+8, key);
- +
- + if(ecmLen >= 46 && ecm[43] == 1)
- + {
- + DrecryptSwap(ccw);
- + overcryptId = b2i(2, &ecm[44]);
- + Drecrypt2OverCW(overcryptId, ccw);
- + memcpy(dw, ccw, 16);
- + return 0;
- + }
- +
- + DrecryptOver(ecm, ccw);
- +
- + if(isValidDCW(ccw)) {
- + DrecryptSwap(ccw);
- + memcpy(dw, ccw, 16);
- + return 0;
- + }
- + }
- + if(keyRef == 0) {
- + return 2;
- + }
- +
- + 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";
- + 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)
- +#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)
- +#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) {
- + result = Drecrypt2ECM(caid,provider,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("[Emu] 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, *newKeyD0, *newEcmKey;
- + uint16_t i = 0, j = 0, k = 0, emmLen = GetEcmLen(emm);
- + uint8_t ecmKeys[6][16], keyD0[2], emmKey[16], emmXorKey[16], provName[17];
- + uint8_t ecmKeyCount = 0, emmKeyIndex = 0, aesMode = 0x0D;
- + uint8_t nanoLen = 0, subNanoLen = 0, haveEmmXorKey = 0, haveNewD0 = 0;
- + uint32_t ui1, ui2, ui3, ecmKeyIndex[6], provider = 0, ecmProvider = 0;
- + char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36];
- + struct aes_keys aes;
- +
- + memset(keyD0, 0, 2);
- + memset(ecmKeyIndex, 0, sizeof(uint32_t)*6);
- +
- + for(i=3; i+2<emmLen; ) {
- + nanoCmd = emm[i++];
- + nanoLen = emm[i++];
- + if(i+nanoLen > emmLen) {
- + return 1;
- + }
- +
- + switch(nanoCmd) {
- + case 0x90: {
- + if(nanoLen < 3) {
- + break;
- + }
- + ui1 = emm[i+2];
- + ui2 = emm[i+1];
- + ui3 = emm[i];
- + provider = (ui1 | (ui2 << 8) | (ui3 << 16));
- + if(provider == 0x00D00040) {
- + ecmProvider = 0x030B00;
- + }
- + else {
- + return 1;
- + }
- + break;
- + }
- + case 0xD2: {
- + if(nanoLen < 2) {
- + break;
- + }
- + emmKeyIndex = emm[i+1];
- + break;
- + }
- + case 0x41: {
- + if(nanoLen < 1) {
- + break;
- + }
- + if(!GetViaKey(emmKey, provider, 'M', emmKeyIndex, 16, 1)) {
- + return 2;
- + }
- + memset(provName, 0, 17);
- + memset(emmXorKey, 0, 16);
- + k = nanoLen < 16 ? nanoLen : 16;
- + memcpy(provName, &emm[i], k);
- + aes_set_key(&aes, (char*)emmKey);
- + aes_decrypt(&aes, emmXorKey, 16);
- + for(j=0; j<16; j++) {
- + provName[j] ^= emmXorKey[j];
- + }
- + provName[k] = 0;
- +
- + if(strcmp((char*)provName, "TNTSAT") != 0 && strcmp((char*)provName, "TNTSATPRO") != 0
- + &&strcmp((char*)provName, "CSAT V") != 0) {
- + return 1;
- + }
- + break;
- + }
- + case 0xBA: {
- + if(nanoLen < 2) {
- + break;
- + }
- + GetViaKey(keyD0, ecmProvider, 'D', 0, 2, 0);
- + ui1 = (emm[i] << 8) | emm[i+1];
- + if( (uint32_t)((keyD0[0] << 8) | keyD0[1]) < ui1 || (keyD0[0] == 0x00 && keyD0[1] == 0x00)) {
- + keyD0[0] = emm[i];
- + keyD0[1] = emm[i+1];
- + haveNewD0 = 1;
- + break;
- + }
- + return 0;
- + }
- + case 0xBC: {
- + break;
- + }
- + case 0x43: {
- + if(nanoLen < 16) {
- + break;
- + }
- + memcpy(emmXorKey, &emm[i], 16);
- + haveEmmXorKey = 1;
- + break;
- + }
- + case 0x44: {
- + if(nanoLen < 3) {
- + break;
- + }
- + if (!haveEmmXorKey) {
- + memset(emmXorKey, 0, 16);
- + }
- + tmp = (uint8_t*)malloc(((nanoLen/16)+1)*16*sizeof(uint8_t));
- + if(tmp == NULL) {
- + return 7;
- + }
- + memcpy(tmp, &emm[i], nanoLen);
- + aes_set_key(&aes, (char*)emmKey);
- + for(j=0; j<nanoLen; j+=16) {
- + aes_decrypt(&aes, emmXorKey, 16);
- + for(k=0; k<16; k++) {
- + tmp[j+k] ^= emmXorKey[k];
- + }
- + }
- + memcpy(&emm[i-2], tmp, nanoLen);
- + free(tmp);
- + nanoLen = 0;
- + i -= 2;
- + break;
- + }
- + case 0x68: {
- + if(ecmKeyCount > 5) {
- + break;
- + }
- + for(j=i; j+2<i+nanoLen; ) {
- + subNanoCmd = emm[j++];
- + subNanoLen = emm[j++];
- + if(j+subNanoLen > i+nanoLen) {
- + break;
- + }
- + switch(subNanoCmd) {
- + case 0xD2: {
- + if(nanoLen < 2) {
- + break;
- + }
- + aesMode = emm[j];
- + emmKeyIndex = emm[j+1];
- + break;
- + }
- + case 0x01: {
- + if(nanoLen < 17) {
- + break;
- + }
- + ecmKeyIndex[ecmKeyCount] = emm[j];
- + memcpy(&ecmKeys[ecmKeyCount], &emm[j+1], 16);
- + if(!GetViaKey(emmKey, provider, 'M', emmKeyIndex, 16, 1)) {
- + break;
- + }
- +
- + if(aesMode == 0x0F || aesMode == 0x11) {
- + hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]);
- + hdSurEncPhase2_D2_0F_11(ecmKeys[ecmKeyCount]);
- + }
- + else if(aesMode == 0x13 || aesMode == 0x15) {
- + hdSurEncPhase1_D2_13_15(ecmKeys[ecmKeyCount]);
- + }
- + aes_set_key(&aes, (char*)emmKey);
- + aes_decrypt(&aes, ecmKeys[ecmKeyCount], 16);
- + if(aesMode == 0x0F || aesMode == 0x11) {
- + hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]);
- + }
- + else if(aesMode == 0x13 || aesMode == 0x15) {
- + hdSurEncPhase2_D2_13_15(ecmKeys[ecmKeyCount]);
- + }
- +
- + ecmKeyCount++;
- + break;
- + }
- + default:
- + break;
- + }
- + j += subNanoLen;
- + }
- + break;
- + }
- + case 0xF0: {
- + if(nanoLen != 4) {
- + break;
- + }
- + ui1 = ((emm[i+2] << 8) | (emm[i+1] << 16) | (emm[i] << 24) | emm[i+3]);
- + if(fletcher_crc32(emm + 3, emmLen - 11) != ui1) {
- + return 4;
- + }
- +
- + if(haveNewD0) {
- + newKeyD0 = (uint8_t*)malloc(sizeof(uint8_t)*2);
- + if(newKeyD0 == NULL) {
- + return 7;
- + }
- + memcpy(newKeyD0, keyD0, 2);
- + if(!SetKey('V', ecmProvider, "D0", newKeyD0, 2, 1, NULL)) {
- + free(newKeyD0);
- + }
- + for(j=0; j<ecmKeyCount; j++) {
- + newEcmKey = (uint8_t*)malloc(sizeof(uint8_t)*16);
- + if(newEcmKey == NULL) {
- + return 7;
- + }
- + memcpy(newEcmKey, ecmKeys[j], 16);
- + snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "E%X", ecmKeyIndex[j]);
- + if(!SetKey('V', ecmProvider, keyName, newEcmKey, 16, 1, NULL)) {
- + free(newEcmKey);
- + }
- + (*keysAdded)++;
- + cs_hexdump(0, ecmKeys[j], 16, keyValue, sizeof(keyValue));
- + cs_log("[Emu] Key found in EMM: V %06X %s %s", ecmProvider, keyName, keyValue);
- + }
- + }
- + break;
- + }
- + default:
- + break;
- + }
- + i += nanoLen;
- + }
- + return 0;
- +}
- +
- +// Irdeto2 EMM EMU
- +static int8_t Irdeto2DoEMMTypeOP(uint32_t ident, uint8_t *emm, uint8_t *keySeed, uint8_t *keyIV, uint8_t *keyPMK,
- + uint16_t emmLen, uint8_t startOffset, uint8_t length, uint32_t *keysAdded)
- +{
- + uint32_t end, i, l;
- + uint8_t tmp[16], *newOpKey;
- + char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36];
- +
- + memset(tmp, 0, 16);
- + Irdeto2Encrypt(keySeed, tmp, keyPMK, 16);
- + Irdeto2Decrypt(&emm[startOffset], keyIV, keySeed, length);
- +
- + i = 16;
- + end = startOffset + (length-8 < 0 ? 0 : length-8);
- +
- + while(i<end) {
- + l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1;
- + switch(emm[i]) {
- + case 0x10:
- + case 0x50:
- + if(l==0x13 && i<=startOffset+length-8-l) {
- + Irdeto2Decrypt(&emm[i+3], keyIV, keyPMK, 16);
- + }
- + break;
- + case 0x78:
- + if(l==0x14 && i<=startOffset+length-8-l) {
- + Irdeto2Decrypt(&emm[i+4], keyIV, keyPMK, 16);
- + }
- + break;
- + }
- + i+=l;
- + }
- +
- + memmove(emm+6, emm+7, emmLen-7);
- +
- + i = 15;
- + end = startOffset + (length-9 < 0 ? 0 : length-9);
- +
- + if(Irdeto2CalculateHash(keySeed, keyIV, emm+3, emmLen-4)) {
- + while(i<end) {
- + l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1;
- + switch(emm[i]) {
- + case 0x10:
- + case 0x50:
- + if(l==0x13 && i<=startOffset+length-9-l) {
- + newOpKey = (uint8_t*)malloc(sizeof(uint8_t)*16);
- + if(newOpKey == NULL) {
- + return 7;
- + }
- + memcpy(newOpKey, &emm[i+3], 16);
- + snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X", emm[i+2]>>2);
- + if(!SetKey('I', ident, keyName, newOpKey, 16, 1, NULL)) {
- + free(newOpKey);
- + }
- + (*keysAdded)++;
- + cs_hexdump(0, &emm[i+3], 16, keyValue, sizeof(keyValue));
- + cs_log("[Emu] 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;
- + uint8_t *newPmkKey;
- + char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36];
- +
- + Irdeto2Decrypt(&emm[startOffset], keyIV, keySeed, length);
- +
- + i = 13;
- + end = startOffset + (length-8 < 0 ? 0 : length-8);
- +
- + while(i<end) {
- + l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1;
- + switch(emm[i]) {
- + case 0x10:
- + case 0x50:
- + if(l==0x13 && i<=startOffset+length-8-l) {
- + Irdeto2Decrypt(&emm[i+3], keyIV, keyPMK, 16);
- + }
- + break;
- + case 0x78:
- + if(l==0x14 && i<=startOffset+length-8-l) {
- + Irdeto2Decrypt(&emm[i+4], keyIV, keyPMK, 16);
- + }
- + break;
- + case 0x68:
- + if(l==0x26 && i<=startOffset+length-8-l) {
- + Irdeto2Decrypt(&emm[i+3], keyIV, keyPMK, 16*2);
- + }
- + break;
- + }
- + i+=l;
- + }
- +
- + memmove(emm+7, emm+9, emmLen-9);
- +
- + i = 11;
- + end = startOffset + (length-10 < 0 ? 0 : length-10);
- +
- + if(Irdeto2CalculateHash(keySeed, keyIV, emm+3, emmLen-5)) {
- + while(i<end) {
- + l = emm[i+1] ? (emm[i+1]&0x3F)+2 : 1;
- + switch(emm[i]) {
- + case 0x68:
- + if(l==0x26 && i<=startOffset+length-10-l) {
- + for(j=0; j<2; j++) {
- + newPmkKey = (uint8_t*)malloc(sizeof(uint8_t)*16);
- + if(newPmkKey == NULL) {
- + return 7;
- + }
- + memcpy(newPmkKey, &emm[i+3+j*16], 16);
- + snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "M%01X", 3+j);
- + if(!SetKey('I', ident, keyName, newPmkKey, 16, 1, NULL)) {
- + free(newPmkKey);
- + }
- + (*keysAdded)++;
- + cs_hexdump(0, &emm[i+3+j*16], 16, keyValue, sizeof(keyValue));
- + cs_log("[Emu] Key found in EMM: I %06X %s %s", ident, keyName, keyValue);
- + }
- + }
- + }
- + i+=l;
- + }
- +
- + if(*keysAdded > 0) {
- + return 0;
- + }
- + }
- +
- + return 1;
- +}
- +
- +static const uint8_t fausto_xor[16] = { 0x22, 0x58, 0xBD, 0x85, 0x2E, 0x8E, 0x52, 0x80, 0xA3, 0x79, 0x98, 0x69, 0x68, 0xE2, 0xD8, 0x4D };
- +
- +static int8_t Irdeto2EMM(uint16_t caid, uint8_t *oemm, uint32_t *keysAdded)
- +{
- + uint8_t length, okeySeed[16], keySeed[16], keyIV[16], keyPMK[16], startOffset, emmType;
- + uint32_t ident;
- + uint16_t keySeedRef, keyIVRef, keyPMK0Ref, keyPMK1Ref, keyPMK0ERef, keyPMK1ERef;
- + uint8_t emmCopy[EMU_MAX_EMM_LEN], *emm = oemm;
- + uint16_t emmLen = GetEcmLen(emm);
- +
- + if(emmLen < 11) {
- + return 1;
- + }
- +
- + if(emm[3] == 0xC3 || emm[3] == 0xCB) {
- + emmType = 2;
- + startOffset = 11;
- + }
- + else {
- + emmType = 1;
- + startOffset = 10;
- + }
- +
- + ident = emm[startOffset-2] | caid << 8;
- + length = emm[startOffset-1];
- +
- +
- + if(emmLen < length+startOffset) {
- + return 1;
- + }
- +
- + keySeedRef = 0;
- + while(GetIrdetoKey(okeySeed, ident, 'M', emmType == 1 ? 0 : 0xA, 1, &keySeedRef)) {
- + keyIVRef = 0;
- + while(GetIrdetoKey(keyIV, ident, 'M', 2, 1, &keyIVRef)) {
- +
- + keyPMK0Ref = 0;
- + keyPMK1Ref = 0;
- + keyPMK0ERef = 0;
- + keyPMK1ERef = 0;
- +
- + while(GetIrdetoKey(keyPMK, ident, 'M', emmType == 1 ? 3 : 0xB, 1, &keyPMK0Ref)) {
- + memcpy(keySeed, okeySeed, 16);
- + memcpy(emmCopy, oemm, emmLen);
- + emm = emmCopy;
- + if(emmType == 1) {
- + if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) {
- + return 0;
- + }
- + }
- + else {
- + if(Irdeto2DoEMMTypePMK(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) {
- + return 0;
- + }
- + }
- + }
- +
- + if(emmType == 1) {
- + while(GetIrdetoKey(keyPMK, ident, 'M', 4, 1, &keyPMK1Ref)) {
- + memcpy(keySeed, okeySeed, 16);
- + memcpy(emmCopy, oemm, emmLen);
- + emm = emmCopy;
- + if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) {
- + return 0;
- + }
- + }
- +
- + while(GetIrdetoKey(keyPMK, ident, 'M', 5, 1, &keyPMK0ERef)) {
- + xxor(keyPMK, 16, keyPMK, fausto_xor);
- + memcpy(keySeed, okeySeed, 16);
- + memcpy(emmCopy, oemm, emmLen);
- + emm = emmCopy;
- + if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) {
- + return 0;
- + }
- + }
- +
- + while(GetIrdetoKey(keyPMK, ident, 'M', 6, 1, &keyPMK1ERef)) {
- + xxor(keyPMK, 16, keyPMK, fausto_xor);
- + memcpy(keySeed, okeySeed, 16);
- + memcpy(emmCopy, oemm, emmLen);
- + emm = emmCopy;
- + if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) {
- + return 0;
- + }
- + }
- + }
- +
- + if(keyPMK0Ref == 0 && keyPMK1Ref == 0 && keyPMK0ERef == 0 && keyPMK1ERef == 0) {
- + return 2;
- + }
- + }
- + if(keyIVRef == 0) {
- + return 2;
- + }
- + }
- + if(keySeedRef == 0) {
- + return 2;
- + }
- +
- + return 1;
- +}
- +
- +int32_t GetIrdeto2Hexserial(uint16_t caid, uint8_t *hexserial)
- +{
- + uint32_t i, len;
- + KeyDataContainer *KeyDB;
- + KeyData *tmpKeyData;
- +
- + KeyDB = GetKeyContainer('I');
- + if(KeyDB == NULL) {
- + return 0;
- + }
- +
- + for(i=0; i<KeyDB->keyCount; i++) {
- +
- + if(KeyDB->EmuKeys[i].provider>>8 != caid) {
- + continue;
- + }
- + if(strcmp(KeyDB->EmuKeys[i].keyName, "MC")) {
- + continue;
- + }
- +
- + tmpKeyData = &KeyDB->EmuKeys[i];
- +
- + len = tmpKeyData->keyLength;
- + if(len > 3)
- + { len = 3; }
- +
- + memcpy(hexserial+(3-len), tmpKeyData->key, len);
- + return 1;
- + }
- +
- + return 0;
- +}
- +
- +
- +// PowerVu EMM EMU
- +static int8_t PowervuEMM(uint8_t *emm, uint32_t *keysAdded)
- +{
- + uint8_t emmInfo, emmType, *newEcmKey;
- + uint16_t emmLen = GetEcmLen(emm);
- + uint32_t i, uniqueAddress, channelId;
- + //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);
- + if(!GetPowervuEmmKey(emmKey, 0, keyName, 7, 0, &channelId))
- + {
- + cs_log_dbg(D_EMM,"[Emu] 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]))
- + {
- + continue;
- + }
- + }
- +
- + 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("[Emu] Key found in EMM: P %.4X %s %s -> REJECTED (looks invalid) UA: %X", channelId, keyName, keyValue, uniqueAddress);
- + continue;
- + }
- +
- + newEcmKey = (uint8_t*)malloc(sizeof(uint8_t)*7);
- + if(newEcmKey == NULL) {
- + return 7;
- + }
- + memcpy(newEcmKey, &emm[i+3], 7);
- + snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", emmType);
- + snprintf(uaInfo, sizeof(uaInfo), "UA: %08X", uniqueAddress);
- + if(!SetKey('P', channelId<<16, keyName, newEcmKey, 7, 1, uaInfo)) {
- + free(newEcmKey);
- + }
- + (*keysAdded)++;
- + cs_hexdump(0, &emm[i+3], 7, keyValue, sizeof(keyValue));
- + cs_log("[Emu] Key found in EMM: P %.4X %s %s ; UA: %X", channelId, keyName, keyValue, uniqueAddress);
- + }
- +
- + return 0;
- +}
- +
- +int32_t GetPowervuHexserials(uint16_t srvid, uint8_t hexserials[][4], int32_t length, int32_t* count)
- +{
- + uint32_t i,j;
- + uint32_t groupid;
- + int32_t len;
- + KeyDataContainer *KeyDB;
- +
- + KeyDB = GetKeyContainer('P');
- + if(KeyDB == NULL)
- + { return 0; }
- +
- + (*count) = 0;
- +
- + for(i=0; i<KeyDB->keyCount && (*count)<length ; i++) {
- +
- + if(srvid != 0xFFFF && (KeyDB->EmuKeys[i].provider & 0x0000FFFF) != srvid)
- + { continue; }
- +
- + groupid = KeyDB->EmuKeys[i].provider>>16;
- +
- + for(j=0; j<KeyDB->keyCount && (*count)<length ; j++) {
- +
- + if(srvid != 0xFFFF && KeyDB->EmuKeys[j].provider != groupid)
- + { continue; }
- +
- + len = strlen(KeyDB->EmuKeys[j].keyName);
- +
- + if(len < 3)
- + { continue;}
- +
- + if(len > 8)
- + { len = 8; }
- +
- + memset(hexserials[*count], 0, 4);
- + CharToBin(hexserials[(*count)]+(4-(len/2)), KeyDB->EmuKeys[j].keyName, len);
- +
- + (*count)++;
- + }
- + if(srvid == 0xFFFF) {
- + return ((*count)>0);
- + }
- + }
- +
- + 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%X", keyName);
- + return FindKey('D', keyIdent, keyStr, buf, 32, isCriticalKey, 0, 0, NULL);
- +}
- +
- +static int8_t Drecrypt2EMM(uint16_t caid, uint32_t provId, uint8_t *emm, uint32_t *keysAdded)
- +{
- + uint16_t emmLen = GetEcmLen(emm);
- + uint32_t keyIdent;
- + uint16_t keyName;
- + uint8_t emmKey[32];
- + int32_t i;
- + uint8_t *newEcmKey;
- + uint8_t keynum, keyidx, keyclass, key1offset, key2offset;
- + char newKeyName[EMU_MAX_CHAR_KEYNAME], keyValue[100];
- +
- + if(emmLen < 5 || caid != 0x4AE1) {
- + return 1;
- + }
- +
- + if(emm[0] == 0x91) {
- + Drecrypt2OverEMM(emm);
- + return 0;
- + }
- +
- + switch(provId & 0xFF)
- + {
- + case 0x11:
- + if (emmLen < (0x8B + 32)) return 0;
- + if (emm[0] != 0x86 && emm[4] != 0x4D) return 0;
- + keynum = 0x61; keyidx = 0x60; keyclass = 0x05; key1offset = 0x62; key2offset = 0x8B;
- + break;
- + case 0x14:
- + if (emmLen < (0x6D + 32)) return 0;
- + if (emm[0] != 0x86 && emm[4] != 0x02) return 0;
- + keynum = 0x2C; keyidx = 0x30; keyclass = 0x26; key1offset = 0x35; key2offset = 0x6D;
- + break;
- + default:
- + return 0;
- + }
- +
- + 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];
- + newEcmKey = (uint8_t*)malloc(sizeof(uint8_t)*32);
- + if(newEcmKey == NULL) {
- + return 7;
- + }
- + memcpy(newEcmKey, &emm[key1offset], 32);
- + snprintf(newKeyName, EMU_MAX_CHAR_KEYNAME, "%.4X", keyName);
- + if(!UpdateKey('D', keyIdent, newKeyName, newEcmKey, 32, NULL)) {
- + free(newEcmKey);
- + }
- + (*keysAdded)++;
- + cs_hexdump(0, &emm[key1offset], 32, keyValue, sizeof(keyValue));
- + cs_log("[Emu] Key found in EMM: D %.6X %s %s", keyIdent, newKeyName, keyValue);
- +
- + //key #2
- + keyName = (emm[keyidx] == 0x56 ? 0x3B00 : 0x5600) | emm[keyclass];
- + newEcmKey = (uint8_t*)malloc(sizeof(uint8_t)*32);
- + if(newEcmKey == NULL) {
- + return 7;
- + }
- + memcpy(newEcmKey, &emm[key2offset], 32);
- + snprintf(newKeyName, EMU_MAX_CHAR_KEYNAME, "%.4X", keyName);
- + if(!UpdateKey('D', keyIdent, newKeyName, newEcmKey, 32, NULL)) {
- + free(newEcmKey);
- + }
- + (*keysAdded)++;
- + cs_hexdump(0, &emm[key2offset], 32, keyValue, sizeof(keyValue));
- + cs_log("[Emu] Key found in EMM: D %.6X %s %s", keyIdent, newKeyName, keyValue);
- +
- + return 0;
- +}
- +
- +int32_t GetDrecryptHexserials(uint16_t caid, 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; i<KeyDB->keyCount && (*count)<length ; i++) {
- +
- + if(KeyDB->EmuKeys[i].provider>>8 != caid)
- + { 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;
- +}
- +
- +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";
- + default:
- + return "Unknown";
- + }
- +}
- +
- +/* 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, 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);
- + if(result == 2) { // missing key already logged
- + return 2;
- + }
- + }
- + else if(caid==0x4AE1) {
- + result = Drecrypt2EMM(caid, provider, emmCopy, keysAdded);
- + }
- +
- + if(result != 0) {
- + cs_log_dbg(D_EMM,"[Emu] 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,114 @@
- +#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 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);
- +
- + /* 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);
- +#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);
- +#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, 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, uint8_t* hexserials, int32_t length, int32_t* count);
- +
- +
- +#define PVU_CW_VID 0 // VIDeo
- +#define PVU_CW_HSD 1 // High Speed Data
- +#define PVU_CW_A1 2 // Audio 1
- +#define PVU_CW_A2 3 // Audio 2
- +#define PVU_CW_A3 4 // Audio 3
- +#define PVU_CW_A4 5 // Audio 4
- +#define PVU_CW_UTL 6 // UTiLity
- +#define PVU_CW_VBI 7 // Vertical Blanking Interval
- +
- +#ifdef WITH_EMU
- + int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, uint16_t srvid, emu_stream_client_key_data *cdata, EXTENDED_CW* cw_ex);
- +#else
- + int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, emu_stream_client_key_data *cdata);
- +#endif
- +
- +#endif
- Index: module-emulator-st20.c
- ===================================================================
- --- module-emulator-st20.c (revision 0)
- +++ module-emulator-st20.c (working copy)
- @@ -0,0 +1,393 @@
- +#include "globals.h"
- +#include "module-emulator-st20.h"
- +
- +#define IPTR 0
- +#define WPTR 1
- +#define AREG 2
- +#define BREG 3
- +#define CREG 4
- +
- +#define FLASHS 0x7FE00000
- +#define FLASHE 0x7FFFFFFF
- +#define RAMS 0x40000000
- +#define RAME 0x401FFFFF
- +#define IRAMS 0x80000000
- +#define IRAME 0x800017FF
- +
- +#define ERR_ILL_OP -1
- +#define ERR_CNT -2
- +
- +// ----------------------------------------------------------------
- +
- +#define STACKMAX 16
- +#define STACKMASK (STACKMAX-1)
- +
- +typedef struct
- +{
- + uint32_t Iptr, Wptr;
- + uint8_t *flash, *ram;
- + uint32_t flashSize, ramSize;
- + int32_t sptr, stack[STACKMAX];
- + uint8_t iram[0x1800];
- + int32_t invalid;
- + int32_t verbose;
- +} st20_context_t;
- +
- +
- +void st20_set_flash(st20_context_t *ctx, uint8_t *m, int32_t len);
- +void st20_set_ram(st20_context_t *ctx, uint8_t *m, int32_t len);
- +void st20_init(st20_context_t *ctx, uint32_t IPtr, uint32_t WPtr, int32_t verbose);
- +void st20_free(st20_context_t *ctx);
- +
- +void st20_set_call_frame(st20_context_t *ctx, uint32_t raddr, int32_t p1, int32_t p2, int32_t p3);
- +
- +
- +uint32_t st20_get_reg(st20_context_t *ctx, int32_t reg);
- +void st20_set_reg(st20_context_t *ctx, int32_t reg, uint32_t val);
- +uint8_t st20_rbyte(st20_context_t *ctx, uint32_t off);
- +void st20_wbyte(st20_context_t *ctx, uint32_t off, uint8_t val);
- +
- +#define get_misalign(_a) *(_a)
- +#define put_misalign(_b,_a) *(_a)=(_b)
- +
- +#define UINT32_LE(a) get_misalign((uint32_t *)(a))
- +#define UINT16_LE(a) get_misalign((uint16_t *)(a))
- +#define UINT8_LE(a) *((uint8_t *)a)
- +#define BYTE4_LE(a,b) put_misalign(b,(uint32_t *)(a))
- +#define BYTE2_LE(a,b) put_misalign(b,(uint16_t *)(a))
- +#define BYTE1_LE(a,b) *(uint8_t *)(a)=(b)
- +
- +#define INVALID_VALUE 0xCCCCCCCC
- +#define ERRORVAL 0xDEADBEEF
- +
- +#define MININT 0x7FFFFFFF
- +#define MOSTPOS 0x7FFFFFFF
- +#define MOSTNEG 0x80000000
- +
- +#define POP() ctx->stack[(ctx->sptr++)&STACKMASK]
- +
- +#define PUSH(v) do { int32_t __v=(v); ctx->stack[(--ctx->sptr)&STACKMASK]=__v; } while(0)
- +#define DROP(n) ctx->sptr+=n
- +
- +#define AAA ctx->stack[ctx->sptr&STACKMASK]
- +#define BBB ctx->stack[(ctx->sptr+1)&STACKMASK]
- +#define CCC ctx->stack[(ctx->sptr+2)&STACKMASK]
- +
- +#define GET_OP() operand|=op1&0x0F
- +#define CLEAR_OP() operand=0
- +#define JUMP(x) ctx->Iptr+=(x)
- +#define POP64() ({ uint32_t __b=POP(); ((uint64_t)POP()<<32)|__b; })
- +#define PUSHPOP(op,val) do { int32_t __a=val; AAA op##= (__a); } while(0)
- +
- +#define RB(off) UINT8_LE(st20_addr(ctx, off))
- +#define RW(off) UINT32_LE(st20_addr(ctx, off))
- +#define WW(off,val) BYTE4_LE(st20_addr(ctx, off),val)
- +
- +uint32_t st20_get_reg(st20_context_t *ctx, int32_t reg)
- +{
- + switch(reg)
- + {
- + case IPTR:
- + return ctx->Iptr;
- + case WPTR:
- + return ctx->Wptr;
- + case AREG:
- + return AAA;
- + case BREG:
- + return BBB;
- + case CREG:
- + return CCC;
- + }
- + return 0;
- +}
- +
- +void st20_set_reg(st20_context_t *ctx, int32_t reg, uint32_t val)
- +{
- + switch(reg)
- + {
- + case IPTR: ctx->Iptr = val; return;
- + case WPTR: ctx->Wptr = val; return;
- + case AREG: AAA=val; return;
- + case BREG: BBB=val; return;
- + case CREG: CCC=val; return;
- + }
- +}
- +
- +uint8_t *st20_addr(st20_context_t *ctx, uint32_t off)
- +{
- + if(off >= FLASHS && off <= FLASHE) return &ctx->flash[off - FLASHS];
- +
- + else if(off >= RAMS && off <= RAME) return &ctx->ram[off - RAMS];
- +
- + else if(off >= IRAMS && off <= IRAME) return &ctx->iram[off - IRAMS];
- +
- + ctx->invalid = ERRORVAL;
- + return (uint8_t *)&ctx->invalid;
- +
- +}
- +
- +uint32_t st20_rword(st20_context_t *ctx, uint32_t off)
- +{
- + return UINT32_LE(st20_addr(ctx, off));
- +}
- +
- +uint16_t st20_rshort(st20_context_t *ctx, uint32_t off)
- +{
- + return UINT16_LE(st20_addr(ctx, off));
- +}
- +
- +uint8_t st20_rbyte(st20_context_t *ctx, uint32_t off)
- +{
- + return UINT8_LE(st20_addr(ctx, off));
- +}
- +
- +void st20_wword(st20_context_t *ctx, uint32_t off, uint32_t val)
- +{
- + BYTE4_LE(st20_addr(ctx, off), val);
- +}
- +
- +void st20_wshort(st20_context_t *ctx, uint32_t off, uint16_t val)
- +{
- + BYTE2_LE(st20_addr(ctx, off), val);
- +}
- +
- +void st20_wbyte(st20_context_t *ctx, uint32_t off, uint8_t val)
- +{
- + BYTE1_LE(st20_addr(ctx, off), val);
- +}
- +
- +#define OP_COL 20
- +#define LOG_OP(op) //printf("%s\n",op);
- +
- +int32_t st20_decode(st20_context_t *ctx, int32_t count)
- +{
- + int32_t operand = 0;
- +
- + CLEAR_OP();
- + while(ctx->Iptr != 0)
- + {
- + int32_t a, op1 = RB(ctx->Iptr++);
- + GET_OP();
- + switch(op1 >> 4)
- + {
- + case 0x0: // j / jump
- + LOG_OP("j");
- + JUMP(operand);
- + CLEAR_OP();
- + break;
- + case 0x1: // ldlp
- + LOG_OP("ldlp");
- + PUSH(ctx->Wptr + (operand * 4));
- + CLEAR_OP();
- + break;
- + case 0x2: // positive prefix
- + LOG_OP("pfix");
- + operand <<= 4;
- + break;
- + case 0x3: // ldnl
- + LOG_OP("ldnl");
- + AAA=RW(AAA + (operand * 4));
- + CLEAR_OP();
- + break;
- + case 0x4: // ldc
- + LOG_OP("ldc");
- + PUSH(operand);
- + CLEAR_OP();
- + break;
- + case 0x5: // ldnlp
- + LOG_OP("ldnlp");
- + PUSHPOP(+, operand * 4);
- + CLEAR_OP();
- + break;
- + case 0x6: // negative prefix
- + LOG_OP("nfix");
- + operand = (~operand) << 4;
- + break;
- + case 0x7: // ldl
- + LOG_OP("ldl");
- + PUSH(RW(ctx->Wptr + (operand * 4)));
- + CLEAR_OP();
- + break;
- + case 0x8: // adc
- + LOG_OP("adc");
- + PUSHPOP(+, operand);
- + CLEAR_OP();
- + break;
- + case 0x9: // call
- + LOG_OP("call");
- + ctx->Wptr -= 16;
- + WW(ctx->Wptr, ctx->Iptr); WW(ctx->Wptr + 4, POP()); WW(ctx->Wptr + 8, POP()); WW(ctx->Wptr + 12, POP());
- + PUSH(ctx->Iptr);
- + JUMP(operand);
- + CLEAR_OP();
- + break;
- + case 0xA: // cj / conditional jump
- + LOG_OP("cj");
- + if(AAA) { DROP(1); } else { JUMP(operand); }
- + CLEAR_OP();
- + break;
- + case 0xB: // ajw / adjust workspace
- + LOG_OP("ajw");
- + ctx->Wptr += operand * 4;
- + CLEAR_OP();
- + break;
- + case 0xC: // eqc / equals constant
- + LOG_OP("eqc");
- + AAA = (operand == AAA ? 1 : 0);
- + CLEAR_OP();
- + break;
- + case 0xD: // stl
- + LOG_OP("stl");
- + WW(ctx->Wptr + (operand * 4), POP());
- + CLEAR_OP();
- + break;
- + case 0xE: // stnl
- + LOG_OP("stnl");
- + a = POP(); WW(a + (operand * 4), POP());
- + CLEAR_OP();
- + break;
- + case 0xF: // opr (secondary ins)
- + switch(operand)
- + {
- + case 0x00: LOG_OP("rev"); a = AAA; AAA = BBB; BBB = a; break;
- + case 0x01: LOG_OP("lb"); AAA = RB(AAA); break;
- + case 0x02: LOG_OP("bsub"); PUSHPOP(+, POP()); break;
- + case 0x04: LOG_OP("diff"); PUSHPOP(-, POP()); break;
- + case 0x05: LOG_OP("add"); PUSHPOP(+, POP()); break;
- + case 0x06: LOG_OP("gcall"); a = AAA; AAA = ctx->Iptr; ctx->Iptr = a; break;
- + case 0x08: LOG_OP("prod"); PUSHPOP(*, POP()); break;
- + case 0x09: LOG_OP("gt"); a=POP(); AAA = (AAA > a); break;
- + case 0x0A: LOG_OP("wsub"); a=POP(); AAA = a + (AAA * 4); break;
- + case 0x0C: LOG_OP("sub"); PUSHPOP(-, POP()); break;
- + case 0x1A: LOG_OP("ldiv"); { a = POP(); uint64_t ll = POP64(); PUSH(ll % (uint32_t)a); PUSH(ll / (uint32_t)a); } break;
- + case 0x1B: LOG_OP("ldpi"); PUSHPOP(+, ctx->Iptr); break;
- + case 0x1D: LOG_OP("xdble"); CCC = BBB; BBB = (AAA >= 0 ? 0 : -1); break;
- + case 0x1F: LOG_OP("rem"); PUSHPOP(%, POP()); break;
- + case 0x20: LOG_OP("ret"); ctx->Iptr = RW(ctx->Wptr); ctx->Wptr = ctx->Wptr + 16; break;
- + case 0x2C:
- + LOG_OP("div");
- + PUSHPOP( /, POP());
- + break;
- + case 0x30: LOG_OP("nop"); break;
- + case 0x32: LOG_OP("not"); AAA =~ AAA; break;
- + case 0x33: LOG_OP("xor"); PUSHPOP(^, POP()); break;
- + case 0x34: LOG_OP("bcnt"); PUSHPOP(*, 4); break;
- + case 0x35: LOG_OP("lshr"); { a = POP(); uint64_t ll = POP64() >> a; PUSH((ll >> 32) & 0xFFFFFFFF); PUSH(ll & 0xFFFFFFFF); } break;
- + case 0x36: LOG_OP("lshl"); { a = POP(); uint64_t ll = POP64() << a; PUSH((ll >> 32) & 0xFFFFFFFF); PUSH(ll & 0xFFFFFFFF); } break;
- + case 0x3B: LOG_OP("sb"); a = POP(); st20_wbyte(ctx, a, POP()); break;
- + case 0x3F: LOG_OP("wcnt"); a = POP(); PUSH(a & 3); PUSH((uint32_t)a >> 2); break;
- + case 0x40: LOG_OP("shr"); a = POP(); AAA = (uint32_t)AAA >> a; break;
- + case 0x41: LOG_OP("shl"); a = POP(); AAA = (uint32_t)AAA << a; break;
- + case 0x42: LOG_OP("mint"); PUSH(MOSTNEG); break;
- + case 0x46: LOG_OP("and"); PUSHPOP(&, POP()); break;
- + case 0x4A: LOG_OP("move"); { a = POP(); int32_t b = POP(); int32_t c = POP(); while(a--) st20_wbyte(ctx, b++, st20_rbyte(ctx, c++)); } break;
- + case 0x4B: LOG_OP("or"); PUSHPOP(|, POP()); break;
- + case 0x53: LOG_OP("mul"); PUSHPOP(*, POP()); break;
- + case 0x5A: LOG_OP("dup"); PUSH(AAA); break;
- + case 0x5F: LOG_OP("gtu"); a = POP(); AAA = ((uint32_t)AAA > (uint32_t)a); break;
- + case 0x78: LOG_OP("bitrevnbits"); { a = POP(); int32_t b = POP(); int32_t bb = 0; while(a--){bb <<= 1; bb |= b & 1; b >>= 1;} PUSH(bb);} break;
- + case 0xCA: LOG_OP("ls"); AAA = st20_rshort(ctx, AAA); break;
- + default:
- + //printf("unknown opcode %X\n", operand);
- + cs_log("[icg] unknown opcode %X", operand);
- + return ERR_ILL_OP;
- + }
- + CLEAR_OP();
- + break;
- + }
- +
- + if(--count <= 0 && operand == 0)
- + {
- + return ERR_CNT;
- + }
- +}
- + return 0;
- +}
- +
- +void st20_set_flash(st20_context_t *ctx, uint8_t *m, int32_t len)
- +{
- + if(ctx->flash) free(ctx->flash);
- + ctx->flash = malloc(len);
- + if(ctx->flash && m) memcpy(ctx->flash, m, len);
- + else memset(ctx->flash, 0, len);
- + ctx->flashSize = len;
- +}
- +
- +void st20_set_ram(st20_context_t *ctx, uint8_t *m, int32_t len)
- +{
- + if(ctx->ram) free(ctx->ram);
- + ctx->ram = malloc(len);
- + if(ctx->ram && m) memcpy(ctx->ram, m, len);
- + else memset(ctx->ram, 0, len);
- + ctx->ramSize = len;
- +}
- +
- +void st20_init(st20_context_t *ctx, uint32_t IPtr, uint32_t WPtr, int32_t verbose)
- +{
- + ctx->Wptr = WPtr; ctx->Iptr = IPtr;
- + memset(ctx->stack, INVALID_VALUE, sizeof(ctx->stack)); ctx->sptr = STACKMAX - 3;
- + memset(ctx->iram, 0, sizeof(ctx->iram));
- + ctx->verbose = verbose;
- +}
- +
- +void st20_free(st20_context_t *ctx)
- +{
- + if(ctx->flash) free(ctx->flash);
- + if(ctx->ram) free(ctx->ram);
- + ctx->flash = NULL;
- + ctx->ram = NULL;
- +}
- +
- +void st20_set_call_frame(st20_context_t *ctx, uint32_t raddr, int32_t p1, int32_t p2, int32_t p3)
- +{
- + ctx->Wptr -= 16;
- + st20_wword(ctx, ctx->Wptr, raddr); // RET
- + st20_wword(ctx, ctx->Wptr + 4, p1); //Areg
- + st20_wword(ctx, ctx->Wptr + 8, p1); //Breg
- + st20_wword(ctx, ctx->Wptr + 12, p1); //Creg
- + st20_wword(ctx, ctx->Wptr + 16, p2);
- + st20_wword(ctx, ctx->Wptr + 20, p3);
- + st20_set_reg(ctx, AREG, raddr); // RET
- +}
- +
- +int32_t st20_run(uint8_t* snip, uint32_t snip_len, int32_t addr, uint8_t *data, uint16_t overcryptId)
- +{
- + int32_t error, i, n;
- + st20_context_t ctx;
- +
- + //printf("exec_snip addr = 0x%X\n", addr);
- + cs_log("[icg] decrypt address = 0x%X, id = %04X", addr, overcryptId);
- +
- + //printf("CW: "); for(i = 0; i < 16; i++) printf("%02X ", data[i]); printf("\n");
- + cs_log("[icg] CW: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X "
- + ,data[0], data[1], data[2] , data[3] , data[4] , data[5] , data[6] , data[7]
- + ,data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]);
- + for(n=0;n<2;n++)
- + {
- + memset(&ctx, 0, sizeof(st20_context_t));
- + st20_set_ram(&ctx, NULL, 0x1000);
- + st20_set_flash(&ctx, snip + 0x48, (int) (snip_len - 0x48));
- + st20_init(&ctx, FLASHS + addr, RAMS + 0x100, 1);
- + st20_set_call_frame(&ctx, 0, RAMS, RAMS, RAMS);
- + for(i = 0; i < 8; i++) st20_wbyte(&ctx, RAMS + i, data[i+n*8]);
- + error = st20_decode(&ctx, 800000);
- + //printf("ret = %d, AREG = %X\n", error, st20_get_reg(&ctx, AREG));
- + cs_log("[icg] ret = %d, AREG = %X", error, st20_get_reg(&ctx, AREG));
- + for(i = 0; i < 8; i++) data[i+n*8] = st20_rbyte(&ctx, RAMS + i);
- + st20_free(&ctx);
- + }
- +
- + //printf("DW: "); for(i = 0; i < 16; i++) printf("%02X ", data[i]); printf("\n");
- + cs_log("[icg] DW: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X "
- + ,data[0], data[1], data[2] , data[3] , data[4] , data[5] , data[6] , data[7]
- + ,data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]);
- +
- +
- + if(error < 0)
- + {
- + cs_log("[icg] st20 processing failed with error %d", error);
- + return 0;
- + }
- +
- + return 1;
- +}
- Index: module-emulator-st20.h
- ===================================================================
- --- module-emulator-st20.h (revision 0)
- +++ module-emulator-st20.h (working copy)
- @@ -0,0 +1,6 @@
- +#ifndef ST20_H_
- +#define ST20_H_
- +
- + int32_t st20_run(uint8_t* snip, uint32_t snip_len, int32_t addr, uint8_t *data, uint16_t overcryptId);
- +
- +#endif
- Index: module-emulator-stream.c
- ===================================================================
- --- module-emulator-stream.c (revision 0)
- +++ module-emulator-stream.c (working copy)
- @@ -0,0 +1,1071 @@
- +#include "globals.h"
- +#include "cscrypt/des.h"
- +
- +#ifdef WITH_EMU
- +#include "oscam-string.h"
- +#include "oscam-config.h"
- +#include "oscam-time.h"
- +#include "oscam-net.h"
- +
- +extern int32_t exit_oscam;
- +#endif
- +
- +#include "ffdecsa/ffdecsa.h"
- +#include "module-emulator-osemu.h"
- +#include "module-emulator-stream.h"
- +
- +typedef struct
- +{
- + int32_t connfd;
- + int32_t connid;
- +} emu_stream_client_conn_data;
- +
- +int8_t stream_server_thread_init = 0;
- +char emu_stream_source_host[256] = {"127.0.0.1"};
- +int32_t emu_stream_source_port = 8001;
- +char *emu_stream_source_auth = NULL;
- +int32_t emu_stream_relay_port = 17999;
- +int8_t emu_stream_emm_enabled = 0;
- +uint32_t cluster_size = 50;
- +
- +static uint8_t emu_stream_server_mutex_init = 0;
- +static pthread_mutex_t emu_stream_server_mutex;
- +static int32_t glistenfd, gconncount = 0, gconnfd[EMU_STREAM_SERVER_MAX_CONNECTIONS];
- +
- +#ifdef WITH_EMU
- +pthread_mutex_t emu_fixed_key_srvid_mutex;
- +uint16_t emu_stream_cur_srvid[EMU_STREAM_SERVER_MAX_CONNECTIONS];
- +int8_t stream_server_has_ecm[EMU_STREAM_SERVER_MAX_CONNECTIONS];
- +
- +pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
- +emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS];
- +LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS];
- +#endif
- +
- +static void SearchTsPackets(uint8_t *buf, uint32_t bufLength, uint16_t *packetSize, uint16_t *startOffset)
- +{
- + uint32_t i;
- +
- + (*packetSize) = 0;
- + (*startOffset) = 0;
- +
- + for(i=0; i<bufLength; i++) {
- + if(buf[i] == 0x47) {
- + if((buf[i+188] == 0x47) & (buf[i+376] == 0x47)) { //if three packets align, probably safe to assume correct size.
- + (*packetSize) = 188;
- + (*startOffset) = i;
- + return;
- + }
- + else if((buf[i+204] == 0x47) & (buf[i+408] == 0x47)) {
- + (*packetSize) = 204;
- + (*startOffset) = i;
- + return;
- + }
- + else if((buf[i+208] == 0x47) & (buf[i+416] == 0x47)) {
- + (*packetSize) = 208;
- + (*startOffset) = i;
- + return;
- + }
- + }
- + }
- +}
- +
- +typedef void (*ts_data_callback)(emu_stream_client_data *cdata);
- +
- +static void ParseTSData(uint8_t table_id, uint8_t table_mask, uint8_t min_table_length, int8_t* flag, uint8_t* data,
- + uint16_t data_length, uint16_t* data_pos, int8_t payloadStart, uint8_t* buf, int32_t len,
- + ts_data_callback func, emu_stream_client_data *cdata)
- +{
- + uint16_t section_length;
- + int32_t i;
- + int8_t found_start = 0;
- + uint16_t offset = 0;
- + int32_t free_data_length;
- + int32_t copySize;
- +
- + if(len < 1)
- + { return; }
- +
- + if(*flag == 0 && !payloadStart)
- + { return; }
- +
- + if(*flag == 0)
- + {
- + *data_pos = 0;
- + offset = 1 + buf[0];
- + }
- + else if(payloadStart)
- + {
- + offset = 1;
- + }
- +
- + if(len-offset < 1)
- + { return; }
- +
- + free_data_length = data_length - *data_pos;
- + copySize = (len-offset) > free_data_length ? free_data_length : (len-offset);
- +
- + memcpy(data+(*data_pos), buf+offset, copySize);
- + (*data_pos) += copySize;
- +
- + found_start = 0;
- + for(i=0; i < *data_pos; i++)
- + {
- + if((data[i] & table_mask) == table_id)
- + {
- + if(i != 0)
- + {
- + if((*data_pos)-i > i)
- + { memmove(data, &data[i], (*data_pos)-i); }
- + else
- + { memcpy(data, &data[i], (*data_pos)-i); }
- +
- + *data_pos -= i;
- + }
- + found_start = 1;
- + break;
- + }
- + }
- + if(!found_start)
- + { *flag = 0; return; }
- +
- + *flag = 2;
- +
- + if(*data_pos < 3)
- + { return; }
- +
- + section_length = SCT_LEN(data);
- +
- + if(section_length > data_length || section_length < min_table_length)
- + { *flag = 0; return; }
- +
- + if((*data_pos) < section_length)
- + { return; }
- +
- + func(cdata);
- +
- + found_start = 0;
- + for(i=section_length; i < *data_pos; i++)
- + {
- + if((data[i] & table_mask) == table_id)
- + {
- + if((*data_pos)-i > i)
- + { memmove(data, &data[i], (*data_pos)-i); }
- + else
- + { memcpy(data, &data[i], (*data_pos)-i); }
- +
- + *data_pos -= i;
- + found_start = 1;
- + break;
- + }
- + }
- + if(!found_start)
- + { *data_pos = 0; }
- +
- + *flag = 1;
- +}
- +
- +static void ParsePATData(emu_stream_client_data *cdata)
- +{
- + uint8_t* data = cdata->data;
- + uint16_t section_length = SCT_LEN(data);
- + uint16_t srvid;
- + int32_t i;
- +
- + for(i=8; i+7<section_length; i+=4)
- + {
- + srvid = b2i(2, data+i);
- +
- + if(srvid == 0)
- + { continue; }
- +
- + if(cdata->srvid == srvid)
- + {
- + cdata->pmt_pid = b2i(2, data+i+2) & 0x1FFF;
- + cs_log_dbg(D_READER, "[Emu] 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->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;
- +
- + 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, "[Emu] stream %i found ecm pid : 0x%04X (%i)",cdata->connid, cdata->ecm_pid, cdata->ecm_pid);
- + break;
- + }
- + }
- + }
- +
- + for(i=12+program_info_length; i+4<section_length; i+=5+es_info_length)
- + {
- + stream_type = data[i];
- + stream_pid = b2i(2, data+i+1) &0x1FFF;
- + es_info_length = b2i(2, data+i+3) &0xFFF;
- +
- + if(stream_type == 0x01 || stream_type == 0x02 || stream_type == 0x10 || stream_type == 0x1B
- + || stream_type == 0x24 || stream_type == 0x42 || stream_type == 0x80 || stream_type == 0xD1
- + || stream_type == 0xEA)
- + {
- + cdata->video_pid = stream_pid;
- + cs_log_dbg(D_READER, "[Emu] 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)
- + {
- + 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, "[Emu] stream %i found audio pid: 0x%04X (%i)", cdata->connid, stream_pid, stream_pid);
- + }
- + }
- +}
- +
- +static void ParseECMData(emu_stream_client_data *cdata)
- +{
- + uint8_t* data = cdata->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
- + }
- +}
- +
- +//#ifdef WITH_EMU
- +//static void ParseTSPackets(emu_stream_client_conn_data *conndata, emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
- +//#else
- +static void ParseTSPackets(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
- +//#endif
- +{
- + 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
- + uint32_t keysAdded = 0;
- + uint8_t *cptr;
- +
- + for(i=0; i<bufLength; i+=packetSize)
- + {
- + tsHeader = b2i(4, stream_buf+i);
- + pid = (tsHeader & 0x1fff00) >> 8;
- + scramblingControl = tsHeader & 0xc0;
- + payloadStart = (tsHeader & 0x400000) >> 22;
- +
- + if(tsHeader & 0x20)
- + { offset = 4 + stream_buf[i+4] + 1; }
- + else
- + { offset = 4; }
- +
- + if(packetSize-offset < 1)
- + { continue; }
- +
- + if( pid == 0x01 && emu_stream_emm_enabled && !data->emm_pid ) // CAT
- + {
- + cptr = stream_buf+i+offset;
- + j = 0;
- + while (cptr != NULL)
- + {
- + cptr = memchr (stream_buf+i+offset+j, 0x0E,100);
- + if (cptr != NULL)
- + {
- + if (*(cptr+1) == 00)
- + {
- + data->emm_pid = (b2i(2,cptr+2) & 0x1FFF);
- + cs_log_dbg(D_READER|D_EMM, "[Emu] stream %i found emm pid : 0x%04X (%i)",data->connid, data->emm_pid, data->emm_pid);
- + break;
- + }
- + j = cptr - stream_buf +i + 1;
- + }
- + }
- + }
- +
- + if(pid == data->emm_pid && data->emm_pid)
- + {
- + ProcessEMM(0x0E00,0x0,stream_buf+i+offset+1, &keysAdded);
- + if(keysAdded)
- + {
- + cs_log("[Emu] stream %i found %i keys.",data->connid, keysAdded);
- + }
- +
- + }
- +
- + if(data->have_pat_data != 1)
- + {
- + if(pid == 0)
- + {
- + ParseTSData(0x00, 0xFF, 16, &data->have_pat_data, data->data, sizeof(data->data), &data->data_pos, payloadStart,
- + stream_buf+i+offset, packetSize-offset, ParsePATData, data);
- + }
- +
- + continue;
- + }
- +
- + if(!data->pmt_pid)
- + {
- + data->have_pat_data = 0;
- + continue;
- + }
- +
- + if(data->have_pmt_data != 1)
- + {
- + if(pid == data->pmt_pid)
- + {
- + ParseTSData(0x02, 0xFF, 21, &data->have_pmt_data, data->data, sizeof(data->data), &data->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
- +
- + ParseTSData(0x80, 0xFE, 10, &data->have_ecm_data, data->data, sizeof(data->data), &data->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)
- + {
- + 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("[Emu] error: setsockopt() failed for SO_RCVTIMEO");
- + return -1;
- + }
- +
- + bzero(&cservaddr, sizeof(cservaddr));
- + cservaddr.sin_family = AF_INET;
- + cs_resolve(emu_stream_source_host, &in_addr, NULL, NULL);
- + SIN_GET_ADDR(cservaddr) = in_addr;
- + cservaddr.sin_port = htons(emu_stream_source_port);
- +
- + if(connect(streamfd, (struct sockaddr *)&cservaddr, sizeof(cservaddr)) == -1)
- + { return -1; }
- + if(emu_stream_source_auth)
- + {
- + snprintf(http_buf, http_buf_len, "GET %s HTTP/1.1\nHost: %s:%u\n"
- + "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0\n"
- + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n"
- + "Accept-Language: en-US\n"
- + "Authorization: Basic %s\n"
- + "Connection: keep-alive\n\n", stream_path, emu_stream_source_host, emu_stream_source_port, emu_stream_source_auth);
- + }
- + else
- + {
- + snprintf(http_buf, http_buf_len, "GET %s HTTP/1.1\nHost: %s:%u\n"
- + "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0\n"
- + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n"
- + "Accept-Language: en-US\n"
- + "Connection: keep-alive\n\n", stream_path, emu_stream_source_host, emu_stream_source_port);
- + }
- +
- + if(send(streamfd, http_buf, strlen(http_buf), 0) == -1)
- + { return -1; }
- +
- + return streamfd;
- +}
- +
- +static void stream_client_disconnect(emu_stream_client_conn_data *conndata)
- +{
- + int32_t i;
- +
- +#ifdef WITH_EMU
- + SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex);
- + emu_stream_cur_srvid[conndata->connid] = NO_SRVID_VALUE;
- + stream_server_has_ecm[conndata->connid] = 0;
- + SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex);
- +#endif
- +
- + SAFE_MUTEX_LOCK(&emu_stream_server_mutex);
- + for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
- + {
- + if(gconnfd[i] == conndata->connfd)
- + {
- + gconnfd[i] = -1;
- + gconncount--;
- + }
- + }
- + SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex);
- +
- + shutdown(conndata->connfd, 2);
- + close(conndata->connfd);
- +
- + cs_log("[Emu] 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("[Emu] 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("[Emu] 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("[Emu] 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 == -1)
- + {
- + streamDataErrorCount++;
- + break;
- + }
- +
- + if(streamStatus == 0)
- + {
- + cs_log("[Emu] 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;
- + }
- +
- + 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("[Emu] 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, "[Emu] warning: stream client %i non-full buffer from stream source", conndata->connid);
- + }
- + }
- +
- + streamConnectErrorCount = 0;
- + streamDataErrorCount = 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);
- +
- +//#ifdef WITH_EMU
- +// ParseTSPackets(conndata, data, stream_buf+startOffset, packetCount*packetSize, packetSize);
- +//#else
- + ParseTSPackets(data, stream_buf+startOffset, packetCount*packetSize, packetSize);
- +//#endif
- + 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("[Emu] info: FFDecsa parallel mode = %d", cluster_size);
- +
- + if(!emu_stream_server_mutex_init)
- + {
- + SAFE_MUTEX_INIT(&emu_stream_server_mutex, NULL);
- + emu_stream_server_mutex_init = 1;
- + }
- +
- +#ifdef WITH_EMU
- + SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex);
- + for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
- + {
- + emu_stream_cur_srvid[i] = NO_SRVID_VALUE;
- + stream_server_has_ecm[i] = 0;
- + }
- + SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex);
- +#endif
- +
- + for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
- + {
- + gconnfd[i] = -1;
- + }
- +
- + glistenfd = socket(AF_INET, SOCK_STREAM, 0);
- + if(glistenfd == -1)
- + {
- + cs_log("[Emu] error: cannot create stream server socket");
- + return NULL;
- + }
- +
- + bzero(&servaddr,sizeof(servaddr));
- + servaddr.sin_family = AF_INET;
- + servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- + servaddr.sin_port = htons(emu_stream_relay_port);
- + setsockopt(glistenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
- +
- + if(bind(glistenfd,(struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
- + {
- + cs_log("[Emu] error: cannot bind to stream server socket");
- + close(glistenfd);
- + return NULL;
- + }
- +
- + if(listen(glistenfd, 3) == -1)
- + {
- + cs_log("[Emu] error: cannot listen to stream server socket");
- + close(glistenfd);
- + return NULL;
- + }
- +
- + while(!exit_oscam)
- + {
- + clilen = sizeof(cliaddr);
- + connfd = accept(glistenfd,(struct sockaddr *)&cliaddr, &clilen);
- +
- + if(connfd == -1)
- + {
- + cs_log("[Emu] error: accept() failed");
- + break;
- + }
- +
- + connaccepted = 0;
- +
- + if(cs_malloc(&conndata, sizeof(emu_stream_client_conn_data)))
- + {
- + SAFE_MUTEX_LOCK(&emu_stream_server_mutex);
- + if(gconncount < EMU_STREAM_SERVER_MAX_CONNECTIONS)
- + {
- + for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
- + {
- + if(gconnfd[i] == -1)
- + {
- + gconnfd[i] = connfd;
- + gconncount++;
- + connaccepted = 1;
- +
- + conndata->connfd = connfd;
- + conndata->connid = i;
- +
- + break;
- + }
- + }
- + }
- + SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex);
- + }
- +
- + if(connaccepted)
- + {
- + int on = 1;
- + if (setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on))<0)
- + {
- + cs_log("[Emu] 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("[Emu] error: stream server client dropped because of too many connections (%i)", EMU_STREAM_SERVER_MAX_CONNECTIONS);
- + }
- +
- + cs_sleepms(20);
- + }
- +
- + close(glistenfd);
- +
- + return NULL;
- +}
- +
- +#ifdef WITH_EMU
- +void *stream_key_delayer(void *UNUSED(arg))
- +{
- + int32_t i, j;
- + emu_stream_client_key_data* cdata;
- + LL_ITER it;
- + emu_stream_cw_item *item;
- + struct timeb t_now;
- +
- + while(!exit_oscam)
- + {
- + cs_ftime(&t_now);
- +
- + for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
- + {
- + it = ll_iter_create(ll_emu_stream_delayed_keys[i]);
- + while((item = ll_iter_next(&it)))
- + {
- + if(comp_timeb(&t_now, &item->write_time) < 0)
- + {
- + break;
- + }
- +
- + SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[i]);
- +
- + cdata = &emu_fixed_key_data[i];
- +
- + for(j=0; j<8; j++)
- + {
- + if(item->csa_used)
- + {
- + if(cdata->pvu_csa_ks[j] == NULL)
- + { cdata->pvu_csa_ks[j] = get_key_struct(); }
- +
- + if(item->is_even)
- + { set_even_control_word(cdata->pvu_csa_ks[j], item->cw[j]); }
- + else
- + { set_odd_control_word(cdata->pvu_csa_ks[j], item->cw[j]); }
- +
- + cdata->pvu_csa_used = 1;
- + }
- + else
- + {
- + if(item->is_even)
- + { des_set_key(item->cw[j], cdata->pvu_des_ks[j][0]); }
- + else
- + { des_set_key(item->cw[j], cdata->pvu_des_ks[j][1]); }
- +
- + cdata->pvu_csa_used = 0;
- + }
- + }
- +
- + SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[i]);
- +
- + ll_iter_remove_data(&it);
- + }
- + }
- +
- + cs_sleepms(25);
- + }
- +
- + return NULL;
- +}
- +#endif
- +
- +void stop_stream_server(void)
- +{
- + int32_t i;
- +
- + SAFE_MUTEX_LOCK(&emu_stream_server_mutex);
- + for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
- + {
- + if(gconnfd[i] != -1)
- + {
- + shutdown(gconnfd[i], 2);
- + close(gconnfd[i]);
- + gconnfd[i] = -1;
- + }
- + }
- +
- + gconncount = 0;
- + SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex);
- +
- + shutdown(glistenfd, 2);
- + close(glistenfd);
- +}
- Index: module-emulator-stream.h
- ===================================================================
- --- module-emulator-stream.h (revision 0)
- +++ module-emulator-stream.h (working copy)
- @@ -0,0 +1,64 @@
- +#ifndef EMU_STREAM_SERVER_H_
- +#define EMU_STREAM_SERVER_H_
- +
- +#define EMU_STREAM_SERVER_MAX_CONNECTIONS 8
- +#define EMU_STREAM_MAX_AUDIO_SUB_TRACKS 16
- +
- + typedef struct
- + {
- + uint32_t pvu_des_ks[8][2][32];
- + int8_t pvu_csa_used;
- + void* pvu_csa_ks[8];
- + } emu_stream_client_key_data;
- +
- + typedef struct
- + {
- + int32_t connid;
- + int8_t have_pat_data;
- + int8_t have_pmt_data;
- + int8_t have_ecm_data;
- + uint8_t data[1024+208];
- + uint16_t data_pos;
- + uint16_t srvid;
- + uint16_t pmt_pid;
- + uint16_t ecm_pid;
- + uint16_t emm_pid;
- + uint16_t video_pid;
- + uint16_t audio_pids[EMU_STREAM_MAX_AUDIO_SUB_TRACKS];
- + uint8_t audio_pid_count;
- + int16_t ecm_nb;
- + emu_stream_client_key_data key;
- + } emu_stream_client_data;
- +
- + extern char emu_stream_source_host[256];
- + extern int32_t emu_stream_source_port;
- + extern char *emu_stream_source_auth;
- + extern int32_t emu_stream_relay_port;
- + extern int8_t emu_stream_emm_enabled;
- +
- + extern int8_t stream_server_thread_init;
- +
- + void *stream_server(void *a);
- + void stop_stream_server(void);
- +
- +#ifdef WITH_EMU
- + typedef struct
- + {
- + struct timeb write_time;
- + int8_t csa_used;
- + int8_t is_even;
- + uint8_t cw[8][8];
- + } emu_stream_cw_item;
- +
- + extern pthread_mutex_t emu_fixed_key_srvid_mutex;
- + extern uint16_t emu_stream_cur_srvid[EMU_STREAM_SERVER_MAX_CONNECTIONS];
- + extern int8_t stream_server_has_ecm[EMU_STREAM_SERVER_MAX_CONNECTIONS];
- +
- + extern pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
- + extern emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS];
- + extern LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS];
- +
- + void *stream_key_delayer(void *arg);
- +#endif
- +
- +#endif
- Index: module-emulator.c
- ===================================================================
- --- module-emulator.c (revision 0)
- +++ module-emulator.c (working copy)
- @@ -0,0 +1,715 @@
- +#include "globals.h"
- +#include "oscam-string.h"
- +#include "oscam-config.h"
- +#include "oscam-conf-chk.h"
- +#include "oscam-time.h"
- +#include "module-emulator-osemu.h"
- +#include "module-emulator-stream.h"
- +
- +// oscam virtual emu card reader
- +#define CS_OK 1
- +#define CS_ERROR 0
- +
- +static int32_t emu_do_ecm(struct s_reader *UNUSED(rdr), const struct ecm_request_t *er, struct s_ecm_answer *ea)
- +{
- + if (!ProcessECM(er->ecmlen, er->caid, er->prid, er->ecm, ea->cw, er->srvid, er->pid, &ea->cw_ex)) {
- + 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;
- + }
- +
- + if(!ProcessEMM(b2i(2, emm->caid), b2i(4, emm->provid), emm->emm, &keysAdded)) {
- + if(keysAdded > 0) { refresh_entitlements(rdr); }
- + return CS_OK;
- + }
- +
- + return CS_ERROR;
- +}
- +
- +static int32_t EMU_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 *rdr)
- +{
- + if(ep->emm[0] == 0x91)
- + {
- + ep->type = GLOBAL;
- + rdr_log_dbg(rdr, D_EMM, "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;;
- +
- + default:
- + ep->type = 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);
- +
- + 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 && i<emu_provids->nprids; i++)
- + {
- + i2b_buf(4, emu_provids->prids[i], prid);
- +
- + filters[idx].type = EMM_UNIQUE;
- + filters[idx].enabled = 1;
- + filters[idx].filter[0] = 0x82;
- + filters[idx].mask[0] = 0xFF;
- + filters[idx].filter[1] = 0xFB;
- + filters[idx].mask[1] = 0x07;
- + memcpy(&filters[idx].filter[2], &prid[1], 3);
- + memset(&filters[idx].mask[2], 0xFF, 3);
- + idx++;
- +
- + filters[idx].type = EMM_SHARED;
- + filters[idx].enabled = 1;
- + filters[idx].filter[0] = 0x82;
- + filters[idx].mask[0] = 0xFF;
- + filters[idx].filter[1] = 0xFA;
- + filters[idx].mask[1] = 0x07;
- + memcpy(&filters[idx].filter[2], &prid[1], 2);
- + memset(&filters[idx].mask[2], 0xFF, 2);
- + idx++;
- + }
- +
- + *filter_count = idx;
- + }
- +
- + return CS_OK;
- +}
- +
- +static int32_t emu_get_pvu_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid), uint16_t srvid)
- +{
- + uint8_t hexserials[16][4];
- + int32_t i, count = 0;
- +
- + if(!GetPowervuHexserials(srvid, hexserials, 16, &count))
- + { return CS_ERROR; }
- +
- + if(*emm_filters == NULL)
- + {
- + const unsigned int max_filter_count = count;
- + if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
- + { return CS_ERROR; }
- +
- + struct s_csystem_emm_filter *filters = *emm_filters;
- + *filter_count = 0;
- +
- + int32_t idx = 0;
- +
- + for(i=0; i<count; i++)
- + {
- + filters[idx].type = EMM_UNIQUE;
- + filters[idx].enabled = 1;
- + filters[idx].filter[0] = 0x82;
- + filters[idx].filter[10] = hexserials[i][0];
- + filters[idx].filter[11] = hexserials[i][1];
- + filters[idx].filter[12] = hexserials[i][2];
- + filters[idx].filter[13] = hexserials[i][3];
- + filters[idx].mask[0] = 0xFF;
- + filters[idx].mask[10] = 0xFF;
- + filters[idx].mask[11] = 0xFF;
- + filters[idx].mask[12] = 0xFF;
- + filters[idx].mask[13] = 0xFF;
- + idx++;
- + }
- +
- + *filter_count = idx;
- + }
- +
- + return CS_OK;
- +}
- +
- +static int32_t emu_get_dre2_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t caid, uint32_t UNUSED(provid))
- +{
- + uint8_t hexserials[8];
- + int32_t i, count = 0;
- +
- + if(!GetDrecryptHexserials(caid, hexserials, 8, &count))
- + { count = 0; }
- +
- + if(*emm_filters == NULL)
- + {
- + const unsigned int max_filter_count = 1 + 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;
- +
- + filters[idx].type = EMM_GLOBAL;
- + filters[idx].enabled = 1;
- + filters[idx].filter[0] = 0x91;
- + filters[idx].mask[0] = 0xFF;
- + idx++;
- +
- + for(i=0; i<count; i++)
- + {
- + filters[idx].type = EMM_SHARED;
- + filters[idx].enabled = 1;
- + filters[idx].filter[0] = 0x86;
- + filters[idx].filter[1] = hexserials[i];
- + filters[idx].mask[0] = 0xFF;
- + filters[idx].mask[1] = 0xFF;
- + idx++;
- + }
- +
- + *filter_count = idx;
- + }
- +
- + return CS_OK;
- +}
- +
- +static int32_t emu_get_emm_filter_adv(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t caid, uint32_t provid, uint16_t srvid)
- +{
- + switch(caid>>8)
- + {
- + case 0x05:
- + return emu_get_via3_emm_filter(rdr, emm_filters, filter_count, caid, provid);
- +
- + case 0x06:
- + return emu_get_ird2_emm_filter(rdr, emm_filters, filter_count, caid, provid);
- +
- + case 0x0E:
- + return emu_get_pvu_emm_filter(rdr, emm_filters, filter_count, caid, provid, srvid);
- +
- + case 0x4A:
- + return emu_get_dre2_emm_filter(rdr, emm_filters, filter_count, caid, provid);
- +
- + 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, 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<CwKeys.keyCount; i++)
- + emu_add_entitlement(reader, CwKeys.EmuKeys[i].provider>>8, CwKeys.EmuKeys[i].provider&0xFF,
- + CwKeys.EmuKeys[i].key, CwKeys.EmuKeys[i].keyName, CwKeys.EmuKeys[i].keyLength, 0);
- +
- + for(i=0; i<ViKeys.keyCount; i++)
- + emu_add_entitlement(reader, 0x500, ViKeys.EmuKeys[i].provider, ViKeys.EmuKeys[i].key, ViKeys.EmuKeys[i].keyName,
- + ViKeys.EmuKeys[i].keyLength, 0);
- +
- + for(i=0; i<NagraKeys.keyCount; i++)
- + emu_add_entitlement(reader, 0x1801, NagraKeys.EmuKeys[i].provider, NagraKeys.EmuKeys[i].key, NagraKeys.EmuKeys[i].keyName,
- + NagraKeys.EmuKeys[i].keyLength, 0);
- +
- + for(i=0; i<IrdetoKeys.keyCount; i++) {
- + tmpKeyData = &IrdetoKeys.EmuKeys[i];
- + do {
- + emu_add_entitlement(reader, tmpKeyData->provider>>8, tmpKeyData->provider&0xFF, tmpKeyData->key, tmpKeyData->keyName, tmpKeyData->keyLength, 0);
- + tmpKeyData = tmpKeyData->nextKey;
- + }
- + while(tmpKeyData!= NULL);
- + }
- +
- + for(i=0; i<NDSKeys.keyCount; i++)
- + { emu_add_entitlement(reader, NDSKeys.EmuKeys[i].provider, 0, NDSKeys.EmuKeys[i].key, NDSKeys.EmuKeys[i].keyName, NDSKeys.EmuKeys[i].keyLength, 0); }
- +
- + emu_add_entitlement(reader, 0x090F, 0, viasat_const, "00", 64, 1);
- + emu_add_entitlement(reader, 0x093E, 0, viasat_const, "00", 64, 1);
- +
- + for(i=0; i<BissKeys.keyCount; i++)
- + { emu_add_entitlement(reader, 0x2600, BissKeys.EmuKeys[i].provider, BissKeys.EmuKeys[i].key, BissKeys.EmuKeys[i].keyName, BissKeys.EmuKeys[i].keyLength, 0); }
- +
- + emu_add_entitlement(reader, 0xFFFF, 0, &oneByte, "00", 1, 1);
- +
- + for(i=0; i<PowervuKeys.keyCount; i++)
- + emu_add_entitlement(reader, 0x0E00, PowervuKeys.EmuKeys[i].provider, PowervuKeys.EmuKeys[i].key, PowervuKeys.EmuKeys[i].keyName,
- + PowervuKeys.EmuKeys[i].keyLength, 0);
- +
- + for(i=0; i<DreKeys.keyCount; i++)
- + emu_add_entitlement(reader, 0x4AE1, DreKeys.EmuKeys[i].provider, DreKeys.EmuKeys[i].key, DreKeys.EmuKeys[i].keyName,
- + DreKeys.EmuKeys[i].keyLength, 0);
- +}
- +
- +extern char cs_confdir[128];
- +
- +static void set_hexserial_to_version(struct s_reader *rdr)
- +{
- + char cVersion[32];
- +
- + uint32_t version = GetOSemuVersion();
- + uint8_t hversion[2];
- + memset(hversion, 0, 2);
- + snprintf(cVersion, sizeof(cVersion), "%04d", version);
- + CharToBin(hversion, cVersion, 4);
- + rdr->hexserial[3] = hversion[0];
- + rdr->hexserial[4] = hversion[1];
- +}
- +
- +static void set_prids(struct s_reader *rdr)
- +{
- + int32_t i, j;
- +
- + rdr->nprov = 0;
- +
- + for(i = 0; (i < rdr->emu_auproviders.nfilts) && (rdr->nprov < CS_MAXPROV); i++)
- + {
- + for(j = 0; (j < rdr->emu_auproviders.filts[i].nprids) && (rdr->nprov < CS_MAXPROV); j++)
- + {
- + i2b_buf(4, rdr->emu_auproviders.filts[i].prids[j], rdr->prid[i]);
- + rdr->nprov++;
- + }
- + }
- +}
- +
- +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];
- +
- + if(stream_server_thread_init == 0)
- + {
- + stream_server_thread_init = 1;
- +
- + SAFE_MUTEX_INIT(&emu_fixed_key_srvid_mutex, NULL);
- +
- + for(i=0; i<EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
- + {
- + SAFE_MUTEX_INIT(&emu_fixed_key_data_mutex[i], NULL);
- + ll_emu_stream_delayed_keys[i] = ll_create("ll_emu_stream_delayed_keys");
- + memset(&emu_fixed_key_data[i], 0, sizeof(emu_stream_client_key_data));
- + }
- +
- + start_thread("stream_key_delayer", stream_key_delayer, NULL, NULL, 1, 1);
- +
- + cs_strncpy(emu_stream_source_host, cfg.emu_stream_source_host, sizeof(emu_stream_source_host));
- + emu_stream_source_port = cfg.emu_stream_source_port;
- + emu_stream_relay_port = cfg.emu_stream_relay_port;
- + emu_stream_emm_enabled = cfg.emu_stream_emm_enabled;
- +
- + if(cfg.emu_stream_source_auth_user && cfg.emu_stream_source_auth_password)
- + {
- + snprintf(authtmp, sizeof(authtmp), "%s:%s", cfg.emu_stream_source_auth_user, cfg.emu_stream_source_auth_password);
- + b64encode(authtmp, strlen(authtmp), &emu_stream_source_auth);
- + }
- + else
- + {
- + NULLFREE(emu_stream_source_auth);
- + }
- +
- + start_thread("stream_server", stream_server, NULL, NULL, 1, 1);
- + }
- +
- + set_hexserial_to_version(reader);
- +
- +#if !defined(__APPLE__) && !defined(__ANDROID__)
- + read_emu_keymemory();
- +#endif
- +
- + set_emu_keyfile_path(cs_confdir);
- +
- + if(!read_emu_keyfile(cs_confdir)) {
- + read_emu_keyfile("/var/keys/");
- + }
- +
- + 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("0D00,0D02,090F,0500,1801,0604,2600,FFFF,0E00,4AE1");
- + chk_caidtab(ctab, &rdr->ctab);
- + NULLFREE(ctab);
- +
- + ftab = strdup( "0D00:000000,000004,000010,000014,000020,0000C0,0000C4,0000C8,0000CC;"
- + "0D02:000000,00008C,0000A0,0000A4,0000A8;"
- + "090F:000000;"
- + "0500:000000,030B00,023800,021110,007400,007800;"
- + "1801:000000,007301,001101;"
- + "0604:000000;"
- + "2600:000000;"
- + "FFFF:000000;"
- + "0E00:000000;"
- + "4AE1:000011,000014,0000FE;" );
- +
- + chk_ftab(ftab, &rdr->ftab);
- + NULLFREE(ftab);
- +
- + emu_auproviders = strdup("0500:030B00;0604:010200;0E00:000000;4AE1:000011,000014,0000FE;");
- + 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("[Emu] oscam-emu version %d", GetOSemuVersion());
- +}
- Index: module-newcamd-des.c
- ===================================================================
- --- module-newcamd-des.c (revision 11209)
- +++ 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 11209)
- +++ 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-stat.c
- ===================================================================
- --- module-stat.c (revision 11209)
- +++ module-stat.c (working copy)
- @@ -886,7 +886,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
- }
- @@ -1284,7 +1284,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 11209)
- +++ module-webif-tpl.c (working copy)
- @@ -456,6 +456,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 11209)
- +++ module-webif.c (working copy)
- @@ -98,6 +98,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
- @@ -119,8 +120,9 @@
- #define MNU_CFG_FCSS 16
- #define MNU_CFG_FTWIN 17
- #define MNU_CFG_FKEYCW 18
- +#define MNU_CFG_FSOFTCAMKEY 19
- -#define MNU_CFG_TOTAL_ITEMS 19 // sum of config or files submenuactivating above. Use it for "All inactive" in function calls too.
- +#define MNU_CFG_TOTAL_ITEMS 20 // sum of config or files submenuactivating 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)
- @@ -942,6 +944,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)
- {
- @@ -1355,6 +1385,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
- @@ -1793,7 +1826,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);
- }
- @@ -2350,6 +2383,13 @@
- tpl_printf(vars, TPLADD, "GBOXRESHARE", "%d", rdr->gbox_reshare);
- #endif
- +#ifdef WITH_EMU
- + //emu_auproviders
- + value = mk_t_ftab(&rdr->emu_auproviders);
- + tpl_addVar(vars, TPLADD, "EMUAUPROVIDERS", value);
- + free_mk_t(value);
- +#endif
- +
- tpl_addVar(vars, TPLADD, "PROTOCOL", reader_get_type_desc(rdr, 0));
- // Show only parameters which needed for the reader
- @@ -2370,6 +2410,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;
- @@ -4047,9 +4090,38 @@
- tpl_addVar(vars, TPLAPPEND, "LOGHISTORY", "<BR><BR>New Structure:<BR>");
- char tbuffer[83];
- +#ifdef WITH_EMU
- + char keyBuffer[1024];
- +#endif
- int jsondelimiter = 0;
- while((item = ll_iter_next(&itr)))
- {
- +#ifdef WITH_EMU
- + if(item->isKey) {
- + tpl_addVar(vars, TPLADD, "ENTSTARTDATE", "");
- + tpl_addVar(vars, TPLADD, "ENTENDDATE", "");
- + cs_hexdump(0, item->key, item->keyLength, keyBuffer, sizeof(keyBuffer));
- + tpl_addVar(vars, TPLADD, "ENTEXPIERED", "e_valid");
- + tpl_printf(vars, TPLADD, "ENTCAID", "%04X", item->caid);
- + if(item->caid == 0x2600) {
- + tpl_printf(vars, TPLADD, "ENTPROVID", "%08X", item->provid);
- + }
- + else {
- + tpl_printf(vars, TPLADD, "ENTPROVID", "%06X", item->provid);
- + }
- + tpl_addVar(vars, TPLADD, "ENTID", item->name);
- + tpl_addVar(vars, TPLADD, "ENTCLASS", keyBuffer);
- + if(item->isData) { tpl_addVar(vars, TPLADD, "ENTTYPE", "data"); }
- + else { tpl_addVar(vars, TPLADD, "ENTTYPE", "key"); }
- + tpl_addVar(vars, TPLADD, "ENTRESNAME", "");
- +
- + if((strcmp(getParam(params, "hideexpired"), "1") != 0) || (item->end > now))
- + { tpl_addVar(vars, TPLAPPEND, "READERENTENTRY", tpl_getTpl(vars, "ENTITLEMENTITEMBIT")); }
- +
- + continue;
- + }
- +#endif
- +
- localtime_r(&item->start, &start_t);
- localtime_r(&item->end, &end_t);
- @@ -4516,6 +4588,9 @@
- #else
- filtered = (type == cl->typ);
- #endif
- +#ifdef WITH_EMU
- + if(type == 'e' && cl->typ == 'r' && cl->reader->typ == R_EMU) filtered = 1;
- +#endif
- }
- }
- @@ -5923,6 +5998,9 @@
- #ifdef MODULE_CONSTCW
- { "constant.cw", MNU_CFG_FKEYCW, FTYPE_CONFIG }, // id 18
- #endif
- +#ifdef WITH_EMU
- + { "SoftCam.Key", MNU_CFG_FSOFTCAMKEY,FTYPE_CONFIG }, // id 19
- +#endif
- { NULL, 0, 0 },
- };
- @@ -6388,7 +6466,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)
- @@ -7393,8 +7471,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 11209)
- +++ oscam-chk.c (working copy)
- @@ -706,7 +706,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;
- @@ -742,7 +742,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);
- @@ -977,7 +977,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 11209)
- +++ oscam-config-global.c (working copy)
- @@ -803,6 +803,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_UINT8("stream_relay_enabled" , OFS(emu_stream_relay_enabled), 1),
- + DEF_OPT_UINT8("stream_emm_enabled" , OFS(emu_stream_emm_enabled), 0),
- + 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))
- {
- @@ -1008,7 +1032,7 @@
- DEF_OPT_STR("user" , OFS(dvbapi_usr), NULL),
- DEF_OPT_INT8("read_sdt" , OFS(dvbapi_read_sdt), 0),
- DEF_OPT_INT8("write_sdt_prov", OFS(dvbapi_write_sdt_prov), 0),
- - DEF_OPT_INT8("extended_cw_api", OFS(dvbapi_extended_cw_api), 0),
- + DEF_OPT_INT8("extended_cw_api", OFS(dvbapi_extended_cw_api), 1),
- DEF_OPT_FUNC("boxtype" , OFS(dvbapi_boxtype), dvbapi_boxtype_fn),
- DEF_OPT_FUNC("services" , OFS(dvbapi_sidtabs.ok), dvbapi_services_fn),
- // OBSOLETE OPTIONS
- @@ -1062,6 +1086,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 11209)
- +++ oscam-config-reader.c (working copy)
- @@ -107,6 +107,7 @@
- { "newcamd", R_NEWCAMD },
- { "newcamd525", R_NEWCAMD },
- { "newcamd524", R_NEWCAMD },
- + { "emu", R_EMU },
- { NULL , 0 }
- }, *p;
- int i;
- @@ -445,6 +446,7 @@
- if(ftab_type & FTAB_CHID) { rdr = container_of(setting, struct s_reader, fchid); }
- 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_EMUAU) { rdr = container_of(setting, struct s_reader, emu_auproviders); }
- if(rdr)
- { rdr->changes_since_shareupdate = 1; }
- }
- @@ -752,7 +754,7 @@
- }
- -static void reader_fixups_fn(void *var)
- +void reader_fixups_fn(void *var)
- {
- struct s_reader *rdr = var;
- #ifdef WITH_LB
- @@ -887,6 +889,9 @@
- #ifdef MODULE_GHTTP
- DEF_OPT_UINT8("use_ssl" , OFS(ghttp_use_ssl), 0),
- #endif
- +#ifdef WITH_EMU
- + DEF_OPT_FUNC_X("emu_auproviders" , OFS(emu_auproviders), ftab_fn, FTAB_READER | FTAB_EMUAU),
- +#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 11209)
- +++ 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);
- @@ -60,7 +61,8 @@
- FTAB_PROVID = 0x04,
- FTAB_CHID = 0x08,
- FTAB_FBPCAID = 0x10,
- - FTAB_LOCALCARDS = 0x20
- + FTAB_LOCALCARDS = 0x20,
- + FTAB_EMUAU = 0x40
- };
- void ftab_fn(const char *token, char *value, void *setting, long ftab_type, FILE *f);
- Index: oscam-ecm.c
- ===================================================================
- --- oscam-ecm.c (revision 11209)
- +++ oscam-ecm.c (working copy)
- @@ -1578,7 +1578,7 @@
- if(reader && cw && rc < E_NOTFOUND)
- {
- - if(reader->disablecrccws == 0)
- + if(reader->disablecrccws == 0 && ((er->caid>>8)!=0x0E))
- {
- for(i = 0; i < 16; i += 4)
- {
- Index: oscam-emm.c
- ===================================================================
- --- oscam-emm.c (revision 11209)
- +++ 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;
- @@ -205,6 +212,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 11209)
- +++ oscam-string.c (working copy)
- @@ -494,6 +494,62 @@
- return crc ^ 0xffffffffL;
- }
- +static uint32_t fletcher_crc_table[256] = {
- + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
- + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
- + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
- + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
- + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
- + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
- + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
- + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
- + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
- + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
- + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
- + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
- + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
- + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
- + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
- + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
- + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
- + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
- + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
- + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
- + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
- + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
- + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
- + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
- + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
- + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
- + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
- + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
- + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
- + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
- + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
- + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
- + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
- + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
- + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
- + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
- + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
- + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
- + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
- + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
- + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
- + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
- + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
- +
- +uint32_t fletcher_crc32(uint8_t *data, uint32_t len)
- +{
- + uint32_t i;
- + uint32_t crc = 0xffffffff;
- +
- + for (i=0; i<len; i++)
- + crc = (crc << 8) ^ fletcher_crc_table[((crc >> 24) ^ *data++) & 0xff];
- +
- + return crc;
- +}
- +
- static uint16_t ccitt_crc_table [256] =
- {
- 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5,
- Index: oscam-string.h
- ===================================================================
- --- oscam-string.h (revision 11209)
- +++ oscam-string.h (working copy)
- @@ -35,6 +35,7 @@
- void get_random_bytes_init(void);
- void get_random_bytes(uint8_t *dst, uint32_t dst_len);
- +uint32_t fletcher_crc32(uint8_t *data, uint32_t len);
- unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int 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 11209)
- +++ oscam.c (working copy)
- @@ -41,6 +41,11 @@
- #include "reader-common.h"
- #include "module-gbox.h"
- +#ifdef WITH_EMU
- + void add_emu_reader(void);
- + void stop_stream_server(void);
- +#endif
- +
- #ifdef WITH_SSL
- #include <openssl/crypto.h>
- #include <openssl/ssl.h>
- @@ -408,6 +413,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;
- @@ -1588,6 +1594,9 @@
- #ifdef CARDREADER_STINGER
- &cardreader_stinger,
- #endif
- +#ifdef WITH_EMU
- + &cardreader_emu,
- +#endif
- NULL
- };
- @@ -1759,6 +1768,9 @@
- init_sidtab();
- init_readerdb();
- +#ifdef WITH_EMU
- + add_emu_reader();
- +#endif
- cfg.account = init_userdb();
- init_signal();
- init_provid();
- @@ -1842,6 +1854,9 @@
- SAFE_COND_SIGNAL(&reader_check_sleep_cond); // Stop reader_check thread
- // Cleanup
- +#ifdef WITH_EMU
- + stop_stream_server();
- +#endif
- #ifdef MODULE_GBOX
- stop_sms_sender();
- #endif
- Index: reader-common.c
- ===================================================================
- --- reader-common.c (revision 11209)
- +++ reader-common.c (working copy)
- @@ -14,6 +14,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[];
- @@ -141,6 +142,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: reader-dre.c
- ===================================================================
- --- reader-dre.c (revision 11209)
- +++ reader-dre.c (working copy)
- @@ -2,6 +2,7 @@
- #ifdef READER_DRE
- #include "cscrypt/des.h"
- #include "reader-common.h"
- +#include "module-emulator-dre2overcrypt.h"
- struct dre_data
- {
- @@ -20,6 +21,23 @@
- return checksum;
- }
- +static int8_t isValidDCW(uint8_t *dw)
- +{
- + if (((dw[0]+dw[1]+dw[2]) & 0xFF) != dw[3]) {
- + return 0;
- + }
- + if (((dw[4]+dw[5]+dw[6]) & 0xFF) != dw[7]) {
- + return 0;
- + }
- + if (((dw[8]+dw[9]+dw[10]) & 0xFF) != dw[11]) {
- + return 0;
- + }
- + if (((dw[12]+dw[13]+dw[14]) & 0xFF) != dw[15]) {
- + return 0;
- + }
- + return 1;
- +}
- +
- static int32_t dre_command(struct s_reader *reader, const uchar *cmd, int32_t cmdlen, unsigned char *cta_res, uint16_t *p_cta_lr) //attention: inputcommand will be changed!!!! answer will be in cta_res, length cta_lr ; returning 1 = no error, return ERROR = err
- {
- uchar startcmd[] = { 0x80, 0xFF, 0x10, 0x01, 0x05 }; //any command starts with this,
- @@ -146,7 +164,7 @@
- int32_t endday = temp.tm_mday;
- rdr_log(reader, "active package %i valid from %04i/%02i/%02i to %04i/%02i/%02i", i, startyear, startmonth, startday,
- endyear, endmonth, endday);
- - cs_add_entitlement(reader, reader->caid, b2ll(4, reader->prid[0]), 0, 0, start, end, 1, 1);
- + cs_add_entitlement(reader, reader->caid, b2ll(4, reader->prid[0]), 0, i, start, end, 1, 1);
- }
- }
- return OK;
- @@ -203,6 +221,7 @@
- }
- memset(reader->prid, 0x00, 8);
- + reader->prid[0][3] = atr[6];
- static const uchar cmd30[] =
- {
- @@ -269,9 +288,17 @@
- reader->sa[0][3], cs_hexdump(0, reader->hexserial + 2, 4, tmp, sizeof(tmp)));
- reader->nprov = 1;
- -
- +
- + if(csystem_data->provider == 0x11)
- + {
- + memset(reader->prid[1], 0x00, 8);
- + reader->prid[1][3] = 0xFE;
- + reader->nprov = 2;
- + }
- +
- if(!dre_set_provider_info(reader))
- { return ERROR; } //fatal error
- +
- rdr_log(reader, "ready for requests");
- return OK;
- @@ -312,6 +339,8 @@
- static int32_t dre_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea)
- {
- def_resp;
- + uint16_t overcryptId;
- + uint8_t tmp[16];
- char tmp_dbg[256];
- struct dre_data *csystem_data = reader->csystem_data;
- if(reader->caid == 0x4ae0)
- @@ -352,14 +381,33 @@
- rdr_log_dbg(reader, D_READER, "unused ECM info front:%s", cs_hexdump(0, er->ecm, 5, tmp_dbg, sizeof(tmp_dbg)));
- rdr_log_dbg(reader, D_READER, "unused ECM info back:%s", cs_hexdump(0, er->ecm + 37, 4, tmp_dbg, sizeof(tmp_dbg)));
- ecmcmd51[33] = csystem_data->provider; //no part of sig
- +
- if((dre_cmd(ecmcmd51))) //ecm request
- {
- if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00))
- { return ERROR; } //exit if response is not 90 00
- +
- + if(er->ecm[2] >= 46 && er->ecm[43] == 1)
- + {
- + memcpy(tmp, cta_res + 11, 8);
- + memcpy(tmp + 8, cta_res + 3, 8);
- + overcryptId = b2i(2, &er->ecm[44]);
- + rdr_log_dbg(reader, D_READER, "ICG ID: %04X", overcryptId);
- + Drecrypt2OverCW(overcryptId,tmp);
- + memcpy(ea->cw, tmp, 16);
- + return OK;
- + }
- +
- DREover(er->ecm, cta_res + 3);
- - memcpy(ea->cw, cta_res + 11, 8);
- - memcpy(ea->cw + 8, cta_res + 3, 8);
- - return OK;
- +
- + if(isValidDCW(cta_res + 3))
- + {
- +
- +
- + memcpy(ea->cw, cta_res + 11, 8);
- + memcpy(ea->cw + 8, cta_res + 3, 8);
- + return OK;
- + }
- }
- }
- return ERROR;
- @@ -394,6 +442,10 @@
- memset(ep->hexserial, 0, 8);
- ep->hexserial[0] = ep->emm[3];
- return ep->hexserial[0] == rdr->sa[0][0];
- +
- + case 0x91:
- + ep->type = GLOBAL;
- + return 1;
- default:
- ep->type = UNKNOWN;
- @@ -405,7 +457,7 @@
- {
- if(*emm_filters == NULL)
- {
- - const unsigned int max_filter_count = 7;
- + const unsigned int max_filter_count = 8;
- if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
- { return ERROR; }
- @@ -477,6 +529,12 @@
- filters[idx].mask[0] = 0xFF;
- //FIXME: No filter for hexserial
- idx++;
- +
- + filters[idx].type = EMM_GLOBAL;
- + filters[idx].enabled = 1;
- + filters[idx].filter[0] = 0x91;
- + filters[idx].mask[0] = 0xFF;
- + idx++;
- *filter_count = idx;
- }
- @@ -491,6 +549,8 @@
- if(reader->caid == 0x4ae1)
- {
- + if(reader->caid != b2i(2, ep->caid)) return ERROR;
- +
- if(ep->type == UNIQUE && ep->emm[39] == 0x3d)
- {
- /* For new package activation. */
- @@ -502,7 +562,7 @@
- if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00))
- { return ERROR; }
- }
- - else
- + else if(ep->emm[4] == 0x02 && csystem_data->provider != 0x11)
- {
- uchar emmcmd52[0x3a];
- emmcmd52[0] = 0x52;
- @@ -519,6 +579,45 @@
- { return ERROR; } //exit if response is not 90 00
- }
- }
- + else if(ep->emm[0] == 0x86 && ep->emm[4] == 0x4D && csystem_data->provider == 0x11)
- + {
- + uchar emmcmd52[0x3a];
- + emmcmd52[0] = 0x52;
- + emmcmd52[1] = 0x01;
- + emmcmd52[2] = ep->emm[5];
- + emmcmd52[3] = 0x01;
- + emmcmd52[4] = ep->emm[3];
- + emmcmd52[5] = 0;
- + emmcmd52[6] = 0;
- + emmcmd52[7] = 0;
- + emmcmd52[9] = 0x01;
- + emmcmd52[10] = 0x01;
- + emmcmd52[11] = 0;
- + memcpy(emmcmd52 + 13, ep->emm + 0x5C, 4);
- + int32_t i;
- + for(i = 0; i < 2; i++)
- + {
- + //memcpy(emmcmd52 + 1, ep->emm + 5 + 32 + i * 56, 56);
- + emmcmd52[8] = ep->emm[0x61+i*0x29];
- + if(i == 0) emmcmd52[12] = ep->emm[0x60] == 0x56 ? 0x56:0x3B;
- + else emmcmd52[12] = ep->emm[0x60] == 0x56 ? 0x3B:0x56;
- + memcpy(emmcmd52 + 0x11, ep->emm + 0x62 + i * 0x29, 40);
- +
- + // check for shared address
- + if(ep->emm[3] != reader->sa[0][0])
- + { return OK; } // ignore, wrong address
- + emmcmd52[0x39] = csystem_data->provider;
- + if((dre_cmd(emmcmd52)))
- + if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00))
- + { return ERROR; } //exit if response is not 90 00
- + }
- + }
- + else if(ep->type == GLOBAL && ep->emm[0] == 0x91)
- + {
- + Drecrypt2OverEMM(ep->emm);
- + return OK;
- + }
- + else return ERROR;
- }
- else
- {
- Index: readers.h
- ===================================================================
- --- readers.h (revision 11209)
- +++ readers.h (working copy)
- @@ -15,5 +15,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 11209)
- +++ webif/config/dvbapi.html (working copy)
- @@ -53,7 +53,7 @@
- </TD>
- </TR>
- <TR><TD><A>Write detected prov name to srvid:</A></TD><TD><input name="write_sdt_prov" type="checkbox" value="1" ##WRITESDTPROVCHECKED##><label></label>
- - <!-- <TR><TD><A>API for extended CWs</A></TD>
- + <TR><TD><A>API for extended CWs</A></TD>
- <TD>
- <select name="extended_cw_api">
- <option value="0" ##EXTENDEDCWAPISELECTED0##>0 - none (disabled)</option>
- @@ -61,4 +61,4 @@
- <option value="2" ##EXTENDEDCWAPISELECTED2##>2 - OE2.0</option>
- </select>
- </TD>
- - </TR> -->
- \ No newline at end of file
- + </TR>
- \ No newline at end of file
- Index: webif/config/menu.html
- ===================================================================
- --- webif/config/menu.html (revision 11209)
- +++ webif/config/menu.html (working copy)
- @@ -16,6 +16,7 @@
- ##TPLCONFIGMENUDVBAPI## <!-- CMENUACTIVE13 -->
- ##TPLCONFIGMENULCD## <!-- CMENUACTIVE14 -->
- ##TPLCONFIGMENUMONITOR## <!-- CMENUACTIVE15 -->
- +##TPLCONFIGMENUSTREAMRELAY##<!-- CMENUACTIVE17 -->
- <LI CLASS="##CMENUACTIVE16##"><A HREF="config.html?part=webif">WebIf</A></LI>
- </UL>
- </DIV>
- \ No newline at end of file
- Index: webif/config/menu_streamrelay.html
- ===================================================================
- --- webif/config/menu_streamrelay.html (revision 0)
- +++ webif/config/menu_streamrelay.html (working copy)
- @@ -0,0 +1 @@
- + <LI CLASS="##CMENUACTIVE17##"><A HREF="config.html?part=streamrelay">Stream Relay</A></LI>
- Index: webif/config/streamrelay.html
- ===================================================================
- --- webif/config/streamrelay.html (revision 0)
- +++ webif/config/streamrelay.html (working copy)
- @@ -0,0 +1,26 @@
- + <input name="part" type="hidden" value="streamrelay">
- + <TABLE CLASS="config">
- + <TR><TH COLSPAN="2">Edit Stream Relay Config</TH></TR>
- + <TR><TD><A>Mode (disable to use direct dvbapi decryption)</A></TD>
- + <TD>
- + <select name="stream_relay_enabled">
- + <option value="0" ##STREAMRELAYENABLEDSELECTED0##>0 - disabled (use DVBAPI)</option>
- + <option value="1" ##STREAMRELAYENABLEDSELECTED1##>1 - enabled (use Stream Relay)</option>
- + </select>
- + </TD>
- + </TR>
- + <TR><TD><A>Process EMM from stream </A></TD>
- + <TD>
- + <select name="stream_emm_enabled">
- + <option value="0" ##STREAMEMMENABLEDSELECTED0##>0 - disabled </option>
- + <option value="1" ##STREAMEMMENABLEDSELECTED1##>1 - enabled </option>
- + </select>
- + </TD>
- + </TR>
- + <TR><TD><A>Source Stream Host:</A></TD><TD><input name="stream_source_host" type="text" maxlength="15" value="##STREAM_SOURCE_HOST##"></TD></TR>
- + <TR><TD><A>Source Stream Port:</A></TD><TD><input name="stream_source_port" class="short" type="text" maxlength="5" value="##STREAM_SOURCE_PORT##"></TD></TR>
- + <TR><TD><A>Source Stream User:</A></TD><TD><input name="stream_source_auth_user" type="text" value="##STREAM_SOURCE_AUTH_USER##"></TD></TR>
- + <TR><TD><A>Source Stream Password:</A></TD><TD><input name="stream_source_auth_password" type="text" value="##STREAM_SOURCE_AUTH_PASSWORD##"></TD></TR>
- + <TR><TD><A>Relay Port:</A></TD><TD><input name="stream_relay_port" class="short" type="text" maxlength="5" value="##STREAM_RELAY_PORT##"></TD></TR>
- + <TR><TD><A>ECM fix delay:</A></TD><TD><input name="stream_ecm_delay" class="short" type="text" maxlength="5" value="##STREAM_ECM_DELAY##"></TD></TR>
- +
- Index: webif/files/menu.html
- ===================================================================
- --- webif/files/menu.html (revision 11209)
- +++ webif/files/menu.html (working copy)
- @@ -9,7 +9,7 @@
- ##TPLFILEMENUANTICASC## <!-- CMENUACTIVE6 -->
- <LI CLASS="##CMENUACTIVE7##"><A HREF="files.html?file=logfile">logfile</A></LI>
- <LI CLASS="##CMENUACTIVE8##"><A HREF="files.html?file=userfile">userfile</A></LI>
- - <LI CLASS="##CMENUACTIVE9## ##CMENUACTIVE10## ##CMENUACTIVE11## ##CMENUACTIVE12## ##CMENUACTIVE13## ##CMENUACTIVE14## ##CMENUACTIVE15## ##CMENUACTIVE16## ##CMENUACTIVE17## ##CMENUACTIVE18##"><A HREF="#" class="drop">other file<b class="subcaret"></b></A>
- + <LI CLASS="##CMENUACTIVE9## ##CMENUACTIVE10## ##CMENUACTIVE11## ##CMENUACTIVE12## ##CMENUACTIVE13## ##CMENUACTIVE14## ##CMENUACTIVE15## ##CMENUACTIVE16## ##CMENUACTIVE17## ##CMENUACTIVE18## ##CMENUACTIVE19##"><A HREF="#" class="drop">other file<b class="subcaret"></b></A>
- <UL CLASS="dropdown_nav">
- <LI CLASS="##CMENUACTIVE9##"><A HREF="files.html?file=oscam.services">oscam.services</A></LI>
- <LI CLASS="##CMENUACTIVE10##"><A HREF="files.html?file=oscam.provid">oscam.provid</A></LI>
- @@ -21,6 +21,7 @@
- ##VIEW_FILEMENUCSS## <!-- CMENUACTIVE16 -->
- ##TPLFILEMENUTWIN## <!-- CMENUACTIVE17 -->
- ##TPLFILEMENUCONSTCW## <!-- CMENUACTIVE18 -->
- +##TPLFILEMENUSOFTCAMKEY## <!-- CMENUACTIVE19 -->
- </UL>
- </LI>
- </UL>
- Index: webif/files/menu_softcamkey.html
- ===================================================================
- --- webif/files/menu_softcamkey.html (revision 0)
- +++ webif/files/menu_softcamkey.html (working copy)
- @@ -0,0 +1 @@
- + <LI CLASS="##CMENUACTIVE19##"><A HREF="files.html?file=SoftCam.Key">SoftCam.Key</A></LI>
- Index: webif/pages_index.txt
- ===================================================================
- --- webif/pages_index.txt (revision 11209)
- +++ 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
- @@ -117,6 +119,7 @@
- FILEMENUDVBAPI files/menu_dvbapi.html HAVE_DVBAPI
- FILEMENUFAKECWS files/menu_fakecws.html CS_CACHEEX
- 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
- @@ -181,6 +184,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 @@
- + <TR><TD><A>AU providers:</A></TD><TD><textarea name="emu_auproviders" rows="3" class="bt">##EMUAUPROVIDERS##</textarea></TD></TR>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement