diff --git a/CMakeLists.txt b/CMakeLists.txt
index dc19535f8..4603c4dd0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -101,7 +101,6 @@ if (OSCamOperatingSystem MATCHES "Windows/Cygwin")
${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}
@@ -111,7 +110,6 @@ else (OSCamOperatingSystem MATCHES "Windows/Cygwin")
${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")
@@ -419,6 +417,39 @@ else (HAVE_PCSC)
endif (OSCamOperatingSystem MATCHES "Windows/Cygwin")
endif (HAVE_PCSC)
+execute_process (COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/config.sh --enabled MODULE_STREAMRELAY OUTPUT_VARIABLE CONFIG_STREAMRELAY OUTPUT_STRIP_TRAILING_WHITESPACE)
+if (CONFIG_STREAMRELAY MATCHES "Y" AND NOT MODULE_STREAMRELAY EQUAL 1)
+ if (LIBDVBCSADIR)
+ check_include_file ("${LIBDVBCSADIR}/include/dvbcsa/dvbcsa.h" FOUND_LIBDVBCSA)
+ set (LIBADVBCSA_LIBRARY "${LIBDVBCSADIR}/libdvbcsa.a")
+ set (LIBDVBCSA_LIBRARY "${LIBDVBCSADIR}/libdvbcsa.so")
+ else (LIBDVBCSADIR)
+ check_include_file ("dvbcsa/dvbcsa.h" FOUND_LIBDVBCSA)
+ find_library (LIBADVBCSA_LIBRARY NAMES libdvbcsa.a)
+ find_library (LIBDVBCSA_LIBRARY NAMES dvbcsa)
+ endif (LIBDVBCSADIR)
+
+ if (HAVE_LIBDVBCSA)
+ if (STATIC_LIBDVBCSA AND FOUND_LIBDVBCSA AND EXISTS ${LIBADVBCSA_LIBRARY})
+ message(STATUS " static libdvbcsa found (libdvbcsa.a).")
+ add_library(imp_libdvbcsa STATIC IMPORTED)
+ set_property(TARGET imp_libdvbcsa PROPERTY IMPORTED_LOCATION ${LIBADVBCSA_LIBRARY})
+ set (dvbcsa_link "imp_libdvbcsa")
+ set (STATICLIBDVBCSA True)
+ elseif ((NOT STATIC_LIBDVBCSA OR STATIC_LIBDVBCSA EQUAL 0) AND FOUND_LIBDVBCSA AND EXISTS ${LIBDVBCSA_LIBRARY})
+ message(STATUS " libdvbcsa found (libdvbcsa.so).")
+ add_library(imp_libdvbcsa SHARED IMPORTED)
+ set_property(TARGET imp_libdvbcsa PROPERTY IMPORTED_LOCATION ${LIBDVBCSA_LIBRARY} )
+ set(dvbcsa_link dvbcsa)
+ set (STATICLIBDVBCSA False)
+ else (STATIC_LIBDVBCSA AND FOUND_LIBDVBCSA AND EXISTS ${LIBADVBCSA_LIBRARY})
+ message(FATAL_ERROR " no libdvbcsa found!")
+ endif (STATIC_LIBDVBCSA AND FOUND_LIBDVBCSA AND EXISTS ${LIBADVBCSA_LIBRARY})
+ else (HAVE_LIBDVBCSA)
+ message(FATAL_ERROR " HAVE_LIBDVBCSA disabled!")
+ endif (HAVE_LIBDVBCSA)
+endif (CONFIG_STREAMRELAY MATCHES "Y" AND NOT MODULE_STREAMRELAY EQUAL 1)
+
# Manage config.h based on command line parameters
# Manipulate config file based on given parameters and read unset parameters
@@ -467,7 +498,6 @@ execute_process (COMMAND make --no-print-directory --quiet -C ${CMAKE_CURRENT_SO
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)
@@ -517,7 +547,7 @@ add_library (${csoscam} STATIC ${csoscam_srcs} ${csoscam_hdrs})
set (exe_name "oscam")
add_executable (${exe_name} ${exe_srcs} ${exe_hdrs})
-target_link_libraries (${exe_name} ${csoscam} ${csmodules} ${csreaders} csctapi cscrypt minilzo ffdecsa)
+target_link_libraries (${exe_name} ${csoscam} ${csmodules} ${csreaders} csctapi cscrypt minilzo)
if(HAVE_LIBRT AND HAVE_LIBUSB)
if (LIBUSBDIR)
set (libusb_link "imp_libusb")
@@ -645,7 +675,7 @@ elseif (OSCamOperatingSystem MATCHES "SU980")
target_link_libraries (${exe_name} rt entropic)
endif (OSCamOperatingSystem MATCHES "Linux")
-target_link_libraries (${exe_name} ${libusb_link} ${rt_link} ${setupapi_link} ${ole32_link} ${shell32_link} ${pthread_link} ${dl_link} ${xcas_link})
+target_link_libraries (${exe_name} ${libusb_link} ${rt_link} ${setupapi_link} ${ole32_link} ${shell32_link} ${pthread_link} ${dl_link} ${xcas_link} ${dvbcsa_link})
#----------------------- put svnversion in the build ------------------------------
# at every target rebuild, we re-build the oscam.c compilation...
@@ -671,10 +701,26 @@ add_definitions ("-D'CS_SVN_VERSION=\"${CS_SVN_VERSION}\"'")
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpmachine COMMAND tr -d '\n' OUTPUT_VARIABLE CS_TARGET)
add_definitions ("-D'CS_TARGET=\"${CS_TARGET}\"'")
+
+execute_process (COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/config.sh --enabled WITH_ARM_NEON OUTPUT_VARIABLE CONFIG_WITH_ARM_NEON OUTPUT_STRIP_TRAILING_WHITESPACE)
+if (CONFIG_WITH_ARM_NEON MATCHES "Y" AND NOT WITH_ARM_NEON EQUAL 0)
+ add_definitions ("-DWITH_ARM_NEON")
+ set (WITH_ARM_NEON "1")
+elseif (CONFIG_WITH_ARM_NEON MATCHES "Y" AND NOT WITH_ARM_NEON EQUAL 0)
+ message (status " The config file has WITH_ARM_NEON enabled, but You disabled it by you cmake command COMPILING WHITOUT arm neon optimization")
+endif (CONFIG_WITH_ARM_NEON MATCHES "Y" AND NOT WITH_ARM_NEON EQUAL 0)
#----------------------- global compile and link options ------------------------------
-#enable sse2 on x86
+#enable sse2 on x86, neon on arm
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse -msse2 -msse3")
+elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "(arm)|(ARM)")
+ if (WITH_ARM_NEON EQUAL 1)
+ message(status " ARM NEON is enabled, compiling with neon optimization")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=neon")
+ set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -mfpu=neon")
+ else (WITH_ARM_NEON EQUAL 1)
+ message(status " ARM NEON is disabled, compiling without neon optimization")
+ endif (WITH_ARM_NEON EQUAL 1)
endif (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
# disable warning about unused but set variables in gcc 4.6+
@@ -684,7 +730,7 @@ if (CMAKE_COMPILER_IS_GNUCC)
list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR)
list(GET GCC_VERSION_COMPONENTS 0 GCC_MINOR)
add_definitions ("-W -Wall ")
- set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O2")
+ set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O2 -pipe -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-schedule-insns")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O2")
set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0 -ggdb")
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -ggdb")
@@ -846,9 +892,9 @@ if (HAVE_PTHREAD)
message (STATUS " use system pthread functions")
endif (HAVE_PTHREAD)
if (HAVE_LIBUSB)
-if(STATIC_LIBUSB EQUAL 1)
- message (STATUS " You selected to enable static libusb")
-endif(STATIC_LIBUSB EQUAL 1)
+ if(STATIC_LIBUSB EQUAL 1)
+ message (STATUS " You selected to enable static libusb")
+ endif(STATIC_LIBUSB EQUAL 1)
if(STATICLIBUSB AND NOT LIBUSBDIR)
message (STATUS " use static libusb functions")
else(STATICLIBUSB AND NOT LIBUSBDIR)
@@ -863,6 +909,24 @@ endif(STATIC_LIBUSB EQUAL 1)
endif(LIBUSBDIR AND STATIC_LIBUSB EQUAL 0)
endif(STATICLIBUSB AND NOT LIBUSBDIR)
endif (HAVE_LIBUSB)
+if (HAVE_LIBDVBCSA)
+ if(STATIC_LIBDVBCSA EQUAL 1)
+ message (STATUS " You selected to enable static libdvbcsa")
+ endif(STATIC_LIBDVBCSA EQUAL 1)
+ if(STATICLIBDVBCSA AND NOT LIBDVBCSADIR)
+ message (STATUS " use static libdvbcsa functions")
+ else(STATICLIBDVBCSA AND NOT LIBDVBCSADIR)
+ if (LIBDVBCSADIR AND STATIC_LIBDVBCSA EQUAL 0)
+ message(STATUS " use system libdvbcsa from selected LIBDVBCSADIR functions")
+ elseif (LIBDVBCSADIR AND STATIC_LIBDVBCSA EQUAL 1)
+ message(STATUS " use static libdvbcsa from selected LIBDVBCSADIR functions")
+ elseif(LIBDVBCSADIR)
+ message(STATUS " use system libdvbcsa from selected LIBDVBCSADIR functions")
+ elseif(NOT LIBDVBCSADIR AND NOT STATIC_LIBDVBCSA)
+ message (STATUS " use system libdvbcsa functions")
+ endif(LIBDVBCSADIR AND STATIC_LIBDVBCSA EQUAL 0)
+ endif(STATICLIBDVBCSA AND NOT LIBDVBCSADIR)
+endif (HAVE_LIBDVBCSA)
if (WITH_EMU)
message (STATUS " Compile with EMU support")
diff --git a/Distribution/doc/html/oscam.conf.5.html b/Distribution/doc/html/oscam.conf.5.html
index 898183c09..6a8c40d21 100644
--- a/Distribution/doc/html/oscam.conf.5.html
+++ b/Distribution/doc/html/oscam.conf.5.html
@@ -1634,6 +1634,16 @@
The [dvbapi] section
+demuxer_fix = 0|1
+
-
+try fixing audio/video sync errors:
+
+
0 = disabled (default)
+
1 = enabled
+
+
+
+
cw_delay = milli-seconds
-
delay of CW writing, default:none
diff --git a/Distribution/doc/man/oscam.conf.5 b/Distribution/doc/man/oscam.conf.5
index 4eef81544..ec5794425 100644
--- a/Distribution/doc/man/oscam.conf.5
+++ b/Distribution/doc/man/oscam.conf.5
@@ -1234,6 +1234,14 @@ mode writing provider name into \fBoscam.srvid2\fR file:
\fB1\fP = enabled
.RE
.PP
+\fBdemuxer_fix\fP = \fB0\fP|\fB1\fP
+.RS 3n
+try fixing audio/video sync errors:
+
+ \fB0\fP = disabled (default)
+ \fB1\fP = enabled
+.RE
+.PP
\fBcw_delay\fP = \fBmilli-seconds\fP
.RS 3n
delay of CW writing, default:none
diff --git a/Distribution/doc/txt/oscam.conf.txt b/Distribution/doc/txt/oscam.conf.txt
index 0c7e2a756..4d9e1651e 100644
--- a/Distribution/doc/txt/oscam.conf.txt
+++ b/Distribution/doc/txt/oscam.conf.txt
@@ -864,6 +864,12 @@ DESCRIPTIONS
0 = disabled (default)
1 = enabled
+ demuxer_fix = 0|1
+ try fixing audio/video sync errors:
+
+ 0 = disabled (default)
+ 1 = enabled
+
cw_delay = milli-seconds
delay of CW writing, default:none
diff --git a/Makefile b/Makefile
index 4782cc6bf..f01a0c167 100644
--- a/Makefile
+++ b/Makefile
@@ -50,6 +50,10 @@ ifeq ($(uname_S),FreeBSD)
LIB_DL :=
endif
+ifeq "$(shell ./config.sh --enabled MODULE_STREAMRELAY)" "Y"
+ override USE_LIBDVBCSA=1
+endif
+
override STD_LIBS := -lm $(LIB_PTHREAD) $(LIB_DL) $(LIB_RT)
override STD_DEFS := -D'CS_SVN_VERSION="$(SVN_REV)"'
override STD_DEFS += -D'CS_CONFDIR="$(CONF_DIR)"'
@@ -58,18 +62,25 @@ override STD_DEFS += -D'CS_CONFDIR="$(CONF_DIR)"'
CC_WARN = -W -Wall -Wshadow -Wredundant-decls -Wstrict-prototypes -Wold-style-definition
# Compiler optimizations
-CC_OPTS = -O2 -ggdb -pipe -ffunction-sections -fdata-sections
+ifeq ($(HOSTCC),clang)
+ CC_OPTS = -O2 -ggdb -pipe -ffunction-sections -fdata-sections -fomit-frame-pointer
+else
+ CC_OPTS = -O2 -ggdb -pipe -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-schedule-insns
+endif
CC = $(CROSS_DIR)$(CROSS)gcc
STRIP = $(CROSS_DIR)$(CROSS)strip
LDFLAGS = -Wl,--gc-sections
+#enable sse2 on x86, neon on arm
TARGETHELP := $(shell $(CC) --target-help 2>&1)
ifneq (,$(findstring sse2,$(TARGETHELP)))
-override CFLAGS += -fexpensive-optimizations -mmmx -msse -msse2 -msse3
-else
-override CFLAGS += -fexpensive-optimizations
+override CFLAGS += -mmmx -msse -msse2 -msse3
+else ifneq (,$(findstring neon,$(TARGETHELP)))
+ ifeq "$(shell ./config.sh --enabled WITH_ARM_NEON)" "Y"
+ override CFLAGS += -mfpu=neon
+ endif
endif
# The linker for powerpc have bug that prevents --gc-sections from working
@@ -106,6 +117,7 @@ DEFAULT_SU980_LIB = -lentropic -lrt
DEFAULT_AZBOX_LIB = -Lextapi/openxcas -lOpenXCASAPI
DEFAULT_LIBCRYPTO_LIB = -lcrypto
DEFAULT_SSL_LIB = -lssl
+DEFAULT_LIBDVBCSA_LIB = -ldvbcsa
ifeq ($(uname_S),Linux)
DEFAULT_LIBUSB_LIB = -lusb-1.0 -lrt
else
@@ -117,15 +129,13 @@ ifeq ($(uname_S),FreeBSD)
DEFAULT_LIBUSB_LIB = -lusb
endif
ifeq ($(uname_S),Darwin)
- FIX_OPENSSL_FLAGS_DIR := $(shell ln -sf /usr/local/opt/openssl@1.1/include/openssl /usr/local/include)
- FIX_OPENSSL_LIB_DIR := $(shell ln -sf /usr/local/opt/openssl@1.1/lib/libssl.1.1.dylib /usr/local/lib)
- FIX_OPENSSL_LIBCRYPTO_DIR := $(shell ln -sf /usr/local/opt/openssl@1.1/lib/libcrypto.1.1.dylib /usr/local/lib)
- DEFAULT_LIBCRYPTO_LIB = -L/usr/local/opt/openssl@1.1/lib -lcrypto
- DEFAULT_SSL_LIB = -L/usr/local/opt/openssl@1.1/lib -lssl
+ DEFAULT_SSL_LIB = -L/usr/local/opt/openssl/lib -lssl
+ DEFAULT_LIBCRYPTO_LIB = -L/usr/local/opt/openssl/lib -lcrypto
+ DEFAULT_LIBDVBCSA_LIB = -L/usr/local/opt/libdvbcsa/lib -ldvbcsa
DEFAULT_LIBUSB_FLAGS = -I/usr/local/opt/libusb/include
- DEFAULT_LIBUSB_LIB = -L/usr/local/opt/libusb/lib -lusb-1.0 -framework IOKit -framework CoreFoundation -framework Security
+ DEFAULT_LIBUSB_LIB = -L/usr/local/opt/libusb/lib -lusb-1.0 -lobjc -framework IOKit -framework CoreFoundation -framework Security
DEFAULT_PCSC_FLAGS = -I/usr/local/opt/pcsc-lite/include/PCSC
- DEFAULT_PCSC_LIB = -L/usr/local/opt/pcsc-lite/lib -framework IOKit -framework CoreFoundation -framework PCSC
+ DEFAULT_PCSC_LIB = -L/usr/local/opt/pcsc-lite/lib -lpcsclite -lobjc -framework IOKit -framework CoreFoundation -framework PCSC
else
# Get the compiler's last include PATHs. Basicaly it is /usr/include
# but in case of cross compilation it might be something else.
@@ -180,6 +190,7 @@ $(eval $(call prepare_use_flags,SSL,ssl))
$(eval $(call prepare_use_flags,LIBCRYPTO,))
$(eval $(call prepare_use_flags,LIBUSB,libusb))
$(eval $(call prepare_use_flags,PCSC,pcsc))
+$(eval $(call prepare_use_flags,LIBDVBCSA,libdvbcsa))
$(eval $(call prepare_use_flags,UTF8))
# Add PLUS_TARGET and EXTRA_TARGET to TARGET
@@ -285,7 +296,6 @@ 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-streamserver.c
SRC-$(CONFIG_WITH_EMU) += module-emulator-biss.c
SRC-$(CONFIG_WITH_EMU) += module-emulator-cryptoworks.c
SRC-$(CONFIG_WITH_EMU) += module-emulator-director.c
@@ -293,7 +303,6 @@ SRC-$(CONFIG_WITH_EMU) += module-emulator-irdeto.c
SRC-$(CONFIG_WITH_EMU) += module-emulator-nagravision.c
SRC-$(CONFIG_WITH_EMU) += module-emulator-powervu.c
SRC-$(CONFIG_WITH_EMU) += module-emulator-viaccess.c
-SRC-$(CONFIG_WITH_EMU) += ffdecsa/ffdecsa.c
ifeq "$(CONFIG_WITH_EMU)" "y"
ifeq "$(CONFIG_WITH_SOFTCAM)" "y"
UNAME := $(shell uname -s)
@@ -325,7 +334,6 @@ SRC-$(CONFIG_MODULE_GBOX) += module-gbox-sms.c
SRC-$(CONFIG_MODULE_GBOX) += module-gbox-remm.c
SRC-$(CONFIG_MODULE_GBOX) += module-gbox-cards.c
SRC-$(CONFIG_MODULE_GBOX) += module-gbox.c
-SRC-$(CONFIG_IRDETO_GUESSING) += module-ird-guess.c
SRC-$(CONFIG_LCDSUPPORT) += module-lcd.c
SRC-$(CONFIG_LEDSUPPORT) += module-led.c
SRC-$(CONFIG_MODULE_MONITOR) += module-monitor.c
@@ -336,6 +344,7 @@ SRC-$(CONFIG_MODULE_GHTTP) += module-ghttp.c
SRC-$(CONFIG_MODULE_RADEGAST) += module-radegast.c
SRC-$(CONFIG_MODULE_SCAM) += module-scam.c
SRC-$(CONFIG_MODULE_SERIAL) += module-serial.c
+SRC-$(CONFIG_MODULE_STREAMRELAY) += module-streamrelay.c
SRC-$(CONFIG_WITH_LB) += module-stat.c
SRC-$(CONFIG_WEBIF) += module-webif-lib.c
SRC-$(CONFIG_WEBIF) += module-webif-tpl.c
@@ -407,7 +416,7 @@ SRC := $(subst config.c,$(OBJDIR)/config.c,$(SRC))
# starts the compilation.
all:
@./config.sh --use-flags "$(USE_FLAGS)" --objdir "$(OBJDIR)" --make-config.mak
- @-mkdir -p $(OBJDIR)/cscrypt $(OBJDIR)/csctapi $(OBJDIR)/minilzo $(OBJDIR)/ffdecsa $(OBJDIR)/webif
+ @-mkdir -p $(OBJDIR)/cscrypt $(OBJDIR)/csctapi $(OBJDIR)/minilzo $(OBJDIR)/webif
@-printf "\
+-------------------------------------------------------------------------------\n\
| OSCam ver: $(VER) rev: $(SVN_REV) target: $(TARGET)\n\
@@ -454,7 +463,7 @@ $(OBJDIR)/config.o: $(OBJDIR)/config.c
$(Q)$(CC) $(STD_DEFS) $(CC_OPTS) $(CC_WARN) $(CFLAGS) -c $< -o $@
$(OBJDIR)/%.o: %.c Makefile
- @$(CC) -MP -MM -MT $@ -o $(subst .o,.d,$@) $<
+ @$(CC) $(CFLAGS) -MP -MM -MT $@ -o $(subst .o,.d,$@) $<
$(SAY) "CC $<"
$(Q)$(CC) $(STD_DEFS) $(CC_OPTS) $(CC_WARN) $(CFLAGS) -c $< -o $@
@@ -697,6 +706,13 @@ OSCam build system documentation\n\
SSL_LDFLAGS='$(DEFAULT_SSL_FLAGS)'\n\
SSL_LIB='$(DEFAULT_SSL_LIB)'\n\
Using USE_SSL=1 adds to '-ssl' to PLUS_TARGET.\n\
+\n\
+ USE_LIBDVBCSA=1 - Request linking with libdvbcsa. USE_LIBDVBCSA is automatically\n\
+ The variables that control USE_LIBDVBCSA=1 build are:\n\
+ LIBDVBCSA_FLAGS='$(DEFAULT_LIBDVBCSA_FLAGS)'\n\
+ LIBDVBCSA_CFLAGS='$(DEFAULT_LIBDVBCSA_FLAGS)'\n\
+ LIBDVBCSA_LDFLAGS='$(DEFAULT_LIBDVBCSA_FLAGS)'\n\
+ LIBDVBCSA_LIB='$(DEFAULT_LIBDVBCSA_LIB)'\n\
\n\
USE_UTF8=1 - Request UTF-8 enabled webif by default.\n\
\n\
@@ -815,6 +831,8 @@ OSCam build system documentation\n\
make USE_LIBCRYPTO=1 LIBCRYPTO_LIB=\"/usr/lib/libcrypto.a\"\n\n\
Build OSCam with static libssl and libcrypto:\n\
make USE_SSL=1 SSL_LIB=\"/usr/lib/libssl.a\" LIBCRYPTO_LIB=\"/usr/lib/libcrypto.a\"\n\n\
+ Build OSCam with static libdvbcsa:\n\
+ make USE_LIBDVBCSA=1 LIBDVBCSA_LIB=\"/usr/lib/libdvbcsa.a\"\n\n\
Build with verbose messages and size optimizations:\n\
make V=1 CC_OPTS=-Os\n\n\
Build and set oscam file name:\n\
diff --git a/README b/README
index ba2dea4fd..a2af8b975 100644
--- a/README
+++ b/README
@@ -6,7 +6,7 @@ License
=======
OSCam: Open Source CAM
-Copyright (C) 2009-2020 OSCam developers
+Copyright (C) 2009-2024 OSCam developers
OSCam is based on the Streamboard mp-cardserver 0.9d by dukat and
has been extended and worked on by many more since then.
diff --git a/config.h b/config.h
index 8995af7a3..833378383 100644
--- a/config.h
+++ b/config.h
@@ -10,11 +10,11 @@
//#define WITH_SSL 1
#if defined(__linux__) || defined(__CYGWIN__)
#define HAVE_DVBAPI 1
+//#define WITH_EXTENDED_CW 1
#endif
//#define WITH_NEUTRINO 1
#define READ_SDT_CHARSETS 1
//#define CLOCKFIX 1
-#define IRDETO_GUESSING 1
//#define CS_ANTICASC 1
#define WITH_DEBUG 1
#define WITH_LB 1
@@ -24,6 +24,7 @@
//#define LCDSUPPORT 1
//#define LEDSUPPORT 1
//#define IPV6SUPPORT 1
+//#define WITH_ARM_NEON 1
#define MODULE_MONITOR 1
//#define MODULE_CAMD33 1
@@ -38,7 +39,8 @@
//#define MODULE_CONSTCW 1
//#define MODULE_PANDORA 1
//#define MODULE_GHTTP 1
-#define MODULE_SCAM 1
+//#define MODULE_SCAM 1
+//#define MODULE_STREAMRELAY 1
#define WITH_CARDREADER 1
@@ -64,7 +66,7 @@
//#define CARDREADER_SC8IN1 1
//#define CARDREADER_SMARGO 1
//#define CARDREADER_DB2COM 1
-#define CARDREADER_STINGER 1
+//#define CARDREADER_STINGER 1
//#define CARDREADER_DRECAS 1
#ifdef WITH_PCSC
diff --git a/config.sh b/config.sh
index fd5bb0f35..582c94032 100755
--- a/config.sh
+++ b/config.sh
@@ -1,7 +1,7 @@
#!/bin/sh
-addons="WEBIF WEBIF_LIVELOG WEBIF_JQUERY TOUCH WITH_SSL HAVE_DVBAPI WITH_NEUTRINO READ_SDT_CHARSETS IRDETO_GUESSING CS_ANTICASC WITH_DEBUG MODULE_MONITOR WITH_LB CS_CACHEEX CS_CACHEEX_AIO CW_CYCLE_CHECK LCDSUPPORT LEDSUPPORT CLOCKFIX IPV6SUPPORT WITH_EMU WITH_SOFTCAM"
-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"
+addons="WEBIF WEBIF_LIVELOG WEBIF_JQUERY TOUCH WITH_SSL HAVE_DVBAPI WITH_EXTENDED_CW WITH_NEUTRINO READ_SDT_CHARSETS CS_ANTICASC WITH_DEBUG MODULE_MONITOR WITH_LB CS_CACHEEX CS_CACHEEX_AIO CW_CYCLE_CHECK LCDSUPPORT LEDSUPPORT CLOCKFIX IPV6SUPPORT WITH_ARM_NEON WITH_EMU WITH_SOFTCAM"
+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 MODULE_STREAMRELAY"
readers="READER_NAGRA READER_NAGRA_MERLIN READER_IRDETO READER_CONAX READER_CRYPTOWORKS READER_SECA READER_VIACCESS READER_VIDEOGUARD READER_DRE READER_TONGFANG READER_BULCRYPT READER_GRIFFIN READER_DGCRYPT"
card_readers="CARDREADER_PHOENIX CARDREADER_INTERNAL CARDREADER_SC8IN1 CARDREADER_MP35 CARDREADER_SMARGO CARDREADER_DB2COM CARDREADER_STAPI CARDREADER_STAPI5 CARDREADER_STINGER CARDREADER_DRECAS"
@@ -12,9 +12,9 @@ CONFIG_WEBIF_JQUERY=y
# CONFIG_TOUCH=n
# CONFIG_WITH_SSL=n
CONFIG_HAVE_DVBAPI=y
+# CONFIG_WITH_EXTENDED_CW=n
# CONFIG_WITH_NEUTRINO=n
CONFIG_READ_SDT_CHARSETS=y
-CONFIG_IRDETO_GUESSING=y
# CONFIG_CS_ANTICASC=n
CONFIG_WITH_DEBUG=y
CONFIG_MODULE_MONITOR=y
@@ -26,6 +26,7 @@ CONFIG_WITH_LB=y
# CONFIG_LEDSUPPORT=n
# CONFIG_CLOCKFIX=n
# CONFIG_IPV6SUPPORT=n
+# CONFIG_WITH_ARM_NEON=n
CONFIG_WITH_EMU=y
CONFIG_WITH_SOFTCAM=y
# CONFIG_MODULE_CAMD33=n
@@ -39,8 +40,9 @@ CONFIG_MODULE_GBOX=y
# CONFIG_MODULE_SERIAL=n
# CONFIG_MODULE_CONSTCW=n
# CONFIG_MODULE_PANDORA=n
-CONFIG_MODULE_SCAM=y
+# CONFIG_MODULE_SCAM=n
# CONFIG_MODULE_GHTTP=n
+# CONFIG_MODULE_STREAMRELAY=n
CONFIG_WITH_CARDREADER=y
CONFIG_READER_NAGRA_COMMON=y
CONFIG_READER_NAGRA=y
@@ -65,7 +67,7 @@ CARDREADER_INTERNAL=y
# CARDREADER_DB2COM=n
# CARDREADER_STAPI=n
# CARDREADER_STAPI5=n
-CARDREADER_STINGER=y
+# CARDREADER_STINGER=n
"
usage() {
@@ -459,20 +461,21 @@ menu_addons() {
TOUCH "Touch Web Interface" $(check_test "TOUCH") \
WITH_SSL "OpenSSL support" $(check_test "WITH_SSL") \
HAVE_DVBAPI "DVB API" $(check_test "HAVE_DVBAPI") \
+ WITH_EXTENDED_CW "DVB API EXTENDED CW API" $(check_test "WITH_EXTENDED_CW") \
WITH_NEUTRINO "Neutrino support" $(check_test "WITH_NEUTRINO") \
READ_SDT_CHARSETS "DVB API read-sdt charsets" $(check_test "READ_SDT_CHARSETS") \
- IRDETO_GUESSING "Irdeto guessing" $(check_test "IRDETO_GUESSING") \
CS_ANTICASC "Anti cascading" $(check_test "CS_ANTICASC") \
WITH_DEBUG "Debug messages" $(check_test "WITH_DEBUG") \
MODULE_MONITOR "Monitor" $(check_test "MODULE_MONITOR") \
WITH_LB "Loadbalancing" $(check_test "WITH_LB") \
CS_CACHEEX "Cache exchange" $(check_test "CS_CACHEEX") \
- CS_CACHEEX_AIO "Cache exchange aio (depend on Cache exchange)" $(check_test "CS_CACHEEX_AIO") \
+ CS_CACHEEX_AIO "Cache exchange aio (depend on Cache exchange)" $(check_test "CS_CACHEEX_AIO") \
CW_CYCLE_CHECK "CW Cycle Check" $(check_test "CW_CYCLE_CHECK") \
LCDSUPPORT "LCD support" $(check_test "LCDSUPPORT") \
LEDSUPPORT "LED support" $(check_test "LEDSUPPORT") \
CLOCKFIX "Clockfix (disable on old systems!)" $(check_test "CLOCKFIX") \
IPV6SUPPORT "IPv6 support (experimental)" $(check_test "IPV6SUPPORT") \
+ WITH_ARM_NEON "ARM NEON (SIMD/MPE) support" $(check_test "WITH_ARM_NEON") \
WITH_EMU "Emulator support" $(check_test "WITH_EMU") \
WITH_SOFTCAM "Built-in SoftCam.Key" $(check_test "WITH_SOFTCAM") \
2> ${tempfile}
@@ -499,6 +502,7 @@ menu_protocols() {
MODULE_PANDORA "Pandora" $(check_test "MODULE_PANDORA") \
MODULE_GHTTP "Ghttp" $(check_test "MODULE_GHTTP") \
MODULE_SCAM "scam" $(check_test "MODULE_SCAM") \
+ MODULE_STREAMRELAY "Stream Relay" $(check_test "MODULE_STREAMRELAY") \
2> ${tempfile}
opt=${?}
diff --git a/cscrypt/bn_exp.c b/cscrypt/bn_exp.c
index ec1d43f98..6c5d58518 100644
--- a/cscrypt/bn_exp.c
+++ b/cscrypt/bn_exp.c
@@ -268,4 +268,262 @@ int BN_mod_exp_simple(BIGNUM *r, BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
return (ret);
}
+int
+BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx)
+{
+ /* like BN_mod, but returns non-negative remainder
+ * (i.e., 0 <= r < |d| always holds)
+ */
+
+ if (!(BN_mod(r, m, d, ctx)))
+ return 0;
+ if (!r->neg)
+ return 1;
+ /* now -|d| < r < 0, so we have to set r : = r + |d| */
+ return (d->neg ? BN_sub : BN_add)(r, r, d);
+}
+
+/* solves ax == 1 (mod n) */
+BIGNUM *
+BN_mod_inverse(BIGNUM *ret, BIGNUM *a, const BIGNUM *n, BN_CTX *ctx)
+{
+ BIGNUM *A, *B, *X, *Y, *M, *D, *T = NULL;
+ int sign;
+
+ bn_check_top(a);
+ bn_check_top(n);
+
+ BN_CTX_start(ctx);
+ A = BN_CTX_get(ctx);
+ B = BN_CTX_get(ctx);
+ X = BN_CTX_get(ctx);
+ D = BN_CTX_get(ctx);
+ M = BN_CTX_get(ctx);
+ Y = BN_CTX_get(ctx);
+ T = BN_CTX_get(ctx);
+ if (T == NULL) goto err;
+
+ if (ret == NULL) goto err;
+
+ BN_one(X);
+ BN_zero(Y);
+ if (BN_copy(B, a) == NULL) goto err;
+ if (BN_copy(A, n) == NULL) goto err;
+ A->neg = 0;
+ if (B->neg || (BN_ucmp(B, A) >= 0)) {
+ if (!BN_nnmod(B, B, A, ctx)) goto err;
+ }
+ sign = -1;
+ /* From B = a mod |n|, A = |n| it follows that
+ *
+ * 0 <= B < A,
+ * -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|).
+ */
+
+ if (BN_is_odd(n) && (BN_num_bits(n) <= (BN_BITS <= 32 ? 450 : 2048))) {
+ /* Binary inversion algorithm; requires odd modulus.
+ * This is faster than the general algorithm if the modulus
+ * is sufficiently small (about 400 .. 500 bits on 32-bit
+ * sytems, but much more on 64-bit systems)
+ */
+ int shift;
+
+ while (!BN_is_zero(B)) {
+ /*
+ * 0 < B < |n|,
+ * 0 < A <= |n|,
+ * (1) -sign*X*a == B (mod |n|),
+ * (2) sign*Y*a == A (mod |n|)
+ */
+
+ /* Now divide B by the maximum possible power of two in the integers,
+ * and divide X by the same value mod |n|.
+ * When we're done, (1) still holds.
+ */
+ shift = 0;
+ while (!BN_is_bit_set(B, shift)) /* note that 0 < B */ {
+ shift++;
+
+ if (BN_is_odd(X)) {
+ if (!BN_uadd(X, X, n)) goto err;
+ }
+ /* now X is even, so we can easily divide it by two */
+ if (!BN_rshift1(X, X)) goto err;
+ }
+ if (shift > 0) {
+ if (!BN_rshift(B, B, shift)) goto err;
+ }
+
+
+ /* Same for A and Y. Afterwards, (2) still holds. */
+ shift = 0;
+ while (!BN_is_bit_set(A, shift)) /* note that 0 < A */ {
+ shift++;
+
+ if (BN_is_odd(Y)) {
+ if (!BN_uadd(Y, Y, n)) goto err;
+ }
+ /* now Y is even */
+ if (!BN_rshift1(Y, Y)) goto err;
+ }
+ if (shift > 0) {
+ if (!BN_rshift(A, A, shift)) goto err;
+ }
+
+ /* We still have (1) and (2).
+ * Both A and B are odd.
+ * The following computations ensure that
+ *
+ * 0 <= B < |n|,
+ * 0 < A < |n|,
+ * (1) -sign*X*a == B (mod |n|),
+ * (2) sign*Y*a == A (mod |n|),
+ *
+ * and that either A or B is even in the next iteration.
+ */
+ if (BN_ucmp(B, A) >= 0) {
+ /* -sign*(X + Y)*a == B - A (mod |n|) */
+ if (!BN_uadd(X, X, Y)) goto err;
+ /* NB: we could use BN_mod_add_quick(X, X, Y, n), but that
+ * actually makes the algorithm slower
+ */
+ if (!BN_usub(B, B, A)) goto err;
+ } else {
+ /* sign*(X + Y)*a == A - B (mod |n|) */
+ if (!BN_uadd(Y, Y, X)) goto err;
+ /* as above, BN_mod_add_quick(Y, Y, X, n) would slow things down */
+ if (!BN_usub(A, A, B)) goto err;
+ }
+ }
+ } else {
+ /* general inversion algorithm */
+
+ while (!BN_is_zero(B)) {
+ BIGNUM *tmp;
+
+ /*
+ * 0 < B < A,
+ * (*) -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|)
+ */
+
+ /* (D, M) : = (A/B, A%B) ... */
+ if (BN_num_bits(A) == BN_num_bits(B)) {
+ if (!BN_one(D)) goto err;
+ if (!BN_sub(M, A, B)) goto err;
+ } else if (BN_num_bits(A) == BN_num_bits(B) + 1) {
+ /* A/B is 1, 2, or 3 */
+ if (!BN_lshift1(T, B)) goto err;
+ if (BN_ucmp(A, T) < 0) {
+ /* A < 2*B, so D = 1 */
+ if (!BN_one(D)) goto err;
+ if (!BN_sub(M, A, B)) goto err;
+ } else {
+ /* A >= 2*B, so D = 2 or D = 3 */
+ if (!BN_sub(M, A, T)) goto err;
+ if (!BN_add(D, T, B)) goto err;
+ /* use D ( := 3 * B) as temp */
+ if (BN_ucmp(A, D) < 0) {
+ /* A < 3*B, so D = 2 */
+ if (!BN_set_word(D, 2)) goto err;
+ /* M ( = A - 2*B) already has the correct value */
+ } else {
+ /* only D = 3 remains */
+ if (!BN_set_word(D, 3)) goto err;
+ /* currently M = A - 2 * B,
+ * but we need M = A - 3 * B
+ */
+ if (!BN_sub(M, M, B)) goto err;
+ }
+ }
+ } else {
+ if (!BN_div(D, M, A, B, ctx)) goto err;
+ }
+
+ /* Now
+ * A = D*B + M;
+ * thus we have
+ * (**) sign*Y*a == D*B + M (mod |n|).
+ */
+
+ tmp = A; /* keep the BIGNUM object, the value does not matter */
+
+ /* (A, B) : = (B, A mod B) ... */
+ A = B;
+ B = M;
+ /* ... so we have 0 <= B < A again */
+
+ /* Since the former M is now B and the former B is now A,
+ * (**) translates into
+ * sign*Y*a == D*A + B (mod |n|),
+ * i.e.
+ * sign*Y*a - D*A == B (mod |n|).
+ * Similarly, (*) translates into
+ * -sign*X*a == A (mod |n|).
+ *
+ * Thus,
+ * sign*Y*a + D*sign*X*a == B (mod |n|),
+ * i.e.
+ * sign*(Y + D*X)*a == B (mod |n|).
+ *
+ * So if we set (X, Y, sign) : = (Y + D*X, X, -sign), we arrive back at
+ * -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|).
+ * Note that X and Y stay non-negative all the time.
+ */
+
+ /* most of the time D is very small, so we can optimize tmp : = D*X+Y */
+ if (BN_is_one(D)) {
+ if (!BN_add(tmp, X, Y)) goto err;
+ } else {
+ if (BN_is_word(D, 2)) {
+ if (!BN_lshift1(tmp, X)) goto err;
+ } else if (BN_is_word(D, 4)) {
+ if (!BN_lshift(tmp, X, 2)) goto err;
+ } else if (D->top == 1) {
+ if (!BN_copy(tmp, X)) goto err;
+ if (!BN_mul_word(tmp, D->d[0])) goto err;
+ } else {
+ if (!BN_mul(tmp, D, X, ctx)) goto err;
+ }
+ if (!BN_add(tmp, tmp, Y)) goto err;
+ }
+
+ M = Y; /* keep the BIGNUM object, the value does not matter */
+ Y = X;
+ X = tmp;
+ sign = -sign;
+ }
+ }
+
+ /*
+ * The while loop (Euclid's algorithm) ends when
+ * A == gcd(a, n);
+ * we have
+ * sign*Y*a == A (mod |n|),
+ * where Y is non-negative.
+ */
+
+ if (sign < 0) {
+ if (!BN_sub(Y, n, Y)) goto err;
+ }
+ /* Now Y*a == A (mod |n|). */
+
+
+ if (BN_is_one(A)) {
+ /* Y*a == 1 (mod |n|) */
+ if (!Y->neg && BN_ucmp(Y, n) < 0) {
+ if (!BN_copy(ret, Y)) goto err;
+ } else {
+ if (!BN_nnmod(ret, Y, n, ctx)) goto err;
+ }
+ } else {
+ goto err;
+ }
+err:
+ BN_CTX_end(ctx);
+ return (ret);
+}
+
#endif
diff --git a/cscrypt/mdc2.c b/cscrypt/mdc2.c
index 269a8fbc2..d889e8ab6 100644
--- a/cscrypt/mdc2.c
+++ b/cscrypt/mdc2.c
@@ -1,35 +1,31 @@
#include "../globals.h"
#include "mdc2.h"
-/* To everybody who want to fix this external openssl dependency bug
- * read this starting at page 5 https://board.streamboard.tv/forum/thread/47678-oscam-bug-report/?pageNo=5
- * Don't touch this if you have no real fix. Right now resolution is can't fix
- */
#undef c2l
#define c2l(c,l) (l =((DES_LONG)(*((c)++))) , \
- l|=((DES_LONG)(*((c)++)))<< 8L, \
- l|=((DES_LONG)(*((c)++)))<<16L, \
- l|=((DES_LONG)(*((c)++)))<<24L)
+ l|=((DES_LONG)(*((c)++)))<< 8L, \
+ l|=((DES_LONG)(*((c)++)))<<16L, \
+ l|=((DES_LONG)(*((c)++)))<<24L)
#undef l2c
#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
- *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
- *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
- *((c)++)=(unsigned char)(((l)>>24L)&0xff))
+ *((c)++)=(unsigned char)(((l)>> 8L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16L)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24L)&0xff))
# define FP(l,r) \
- { \
- register DES_LONG tt; \
- PERM_OP(l,r,tt, 1,0x55555555L); \
- PERM_OP(r,l,tt, 8,0x00ff00ffL); \
- PERM_OP(l,r,tt, 2,0x33333333L); \
- PERM_OP(r,l,tt,16,0x0000ffffL); \
- PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \
- }
-
-//OPENSSL_GLOBAL const DES_LONG DES_SPtrans[8][64] =
-const DES_LONG DES_SPtrans_Oscam[8][64] =
+ { \
+ register DES_LONG tt; \
+ PERM_OP(l,r,tt, 1,0x55555555L); \
+ PERM_OP(r,l,tt, 8,0x00ff00ffL); \
+ PERM_OP(l,r,tt, 2,0x33333333L); \
+ PERM_OP(r,l,tt,16,0x0000ffffL); \
+ PERM_OP(l,r,tt, 4,0x0f0f0f0fL); \
+ }
+
+#if !defined(WITH_SSL) || !defined(WITH_LIBCRYPTO)
+const DES_LONG DES_SPtrans[8][64] =
{
{
/* nibble 0 */
@@ -184,42 +180,42 @@ const DES_LONG DES_SPtrans_Oscam[8][64] =
0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L,
}
};
+#endif
-
-# define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g)
-# define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
- u=R^s[S ]; \
- t=R^s[S+1]
-
-# define D_ENCRYPT(LL,R,S) { \
- LOAD_DATA_tmp(R,S,u,t,E0,E1); \
- t=ROTATE(t,4); \
- LL^= \
- DES_SPtrans_Oscam[0][(u>> 2L)&0x3f]^ \
- DES_SPtrans_Oscam[2][(u>>10L)&0x3f]^ \
- DES_SPtrans_Oscam[4][(u>>18L)&0x3f]^ \
- DES_SPtrans_Oscam[6][(u>>26L)&0x3f]^ \
- DES_SPtrans_Oscam[1][(t>> 2L)&0x3f]^ \
- DES_SPtrans_Oscam[3][(t>>10L)&0x3f]^ \
- DES_SPtrans_Oscam[5][(t>>18L)&0x3f]^ \
- DES_SPtrans_Oscam[7][(t>>26L)&0x3f]; }
+#define LOAD_DATA_tmp(a,b,c,d,e,f) LOAD_DATA(a,b,c,d,e,f,g)
+#define LOAD_DATA(R,S,u,t,E0,E1,tmp) \
+ u=R^s[S ]; \
+ t=R^s[S+1]
+
+#define D_ENCRYPT(LL,R,S) { \
+ LOAD_DATA_tmp(R,S,u,t,E0,E1); \
+ t=ROTATE(t,4); \
+ LL^= \
+ DES_SPtrans[0][(u>> 2L)&0x3f]^ \
+ DES_SPtrans[2][(u>>10L)&0x3f]^ \
+ DES_SPtrans[4][(u>>18L)&0x3f]^ \
+ DES_SPtrans[6][(u>>26L)&0x3f]^ \
+ DES_SPtrans[1][(t>> 2L)&0x3f]^ \
+ DES_SPtrans[3][(t>>10L)&0x3f]^ \
+ DES_SPtrans[5][(t>>18L)&0x3f]^ \
+ DES_SPtrans[7][(t>>26L)&0x3f]; }
#define IP(l,r) \
- { \
- register DES_LONG tt; \
- PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \
- PERM_OP(l,r,tt,16,0x0000ffffL); \
- PERM_OP(r,l,tt, 2,0x33333333L); \
- PERM_OP(l,r,tt, 8,0x00ff00ffL); \
- PERM_OP(r,l,tt, 1,0x55555555L); \
- }
+ { \
+ register DES_LONG tt; \
+ PERM_OP(r,l,tt, 4,0x0f0f0f0fL); \
+ PERM_OP(l,r,tt,16,0x0000ffffL); \
+ PERM_OP(r,l,tt, 2,0x33333333L); \
+ PERM_OP(l,r,tt, 8,0x00ff00ffL); \
+ PERM_OP(r,l,tt, 1,0x55555555L); \
+ }
-# define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
- (b)^=(t),\
- (a)^=((t)<<(n)))
+#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\
+ (b)^=(t),\
+ (a)^=((t)<<(n)))
-# define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n))))
+#define ROTATE(a,n) (((a)>>(n))+((a)<<(32-(n))))
@@ -254,7 +250,7 @@ static const unsigned char odd_parity[256] =
};
#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\
- (a)=(a)^(t)^(t>>(16-(n))))
+ (a)=(a)^(t)^(t>>(16-(n))))
# define ITERATIONS 16
# define HALF_ITERATIONS 8
@@ -494,7 +490,8 @@ void DES_set_odd_parity(DES_cblock *key)
}
-void DES_encrypt1_Oscam(DES_LONG *data, DES_key_schedule *ks, int enc)
+#if !defined(WITH_SSL) || !defined(WITH_LIBCRYPTO)
+void DES_encrypt1(DES_LONG *data, DES_key_schedule *ks, int enc)
{
register DES_LONG l=0, r=0, t=0, u=0;
//l = r = t = u = 0;
@@ -569,7 +566,7 @@ void DES_encrypt1_Oscam(DES_LONG *data, DES_key_schedule *ks, int enc)
data[0] = l;
data[1] = r;
}
-
+#endif
static void mdc2_body(MDC2_CTX *c, const unsigned char *in, size_t len);
@@ -639,11 +636,11 @@ static void mdc2_body(MDC2_CTX *c, const unsigned char *in, size_t len)
DES_set_odd_parity(&c->h);
DES_set_key_unchecked(&c->h, &k);
- DES_encrypt1_Oscam(d, &k, 1);
+ DES_encrypt1(d, &k, 1);
DES_set_odd_parity(&c->hh);
DES_set_key_unchecked(&c->hh, &k);
- DES_encrypt1_Oscam(dd, &k, 1);
+ DES_encrypt1(dd, &k, 1);
ttin0 = tin0 ^ dd[0];
ttin1 = tin1 ^ dd[1];
diff --git a/cscrypt/mdc2.h b/cscrypt/mdc2.h
index 8476b376d..e57c3ed35 100644
--- a/cscrypt/mdc2.h
+++ b/cscrypt/mdc2.h
@@ -59,12 +59,20 @@
#ifndef HEADER_MDC2_H
#define HEADER_MDC2_H
-/* To everybody who want to fix this external openssl dependency bug
- * read this starting at page 5 https://board.streamboard.tv/forum/thread/47678-oscam-bug-report/?pageNo=5
- * Don't touch this if you have no real fix. Right now resolution is can't fix
- */
-
+#if defined(WITH_SSL) || defined(WITH_LIBCRYPTO)
#include
+#else
+#define DES_KEY_SZ (sizeof(DES_cblock))
+typedef unsigned int DES_LONG;
+typedef unsigned char DES_cblock[8];
+typedef unsigned char const_DES_cblock[8];
+typedef struct DES_ks {
+ union {
+ DES_cblock cblock;
+ DES_LONG deslong[2];
+ } ks[16];
+} DES_key_schedule;
+#endif
#ifdef __cplusplus
extern "C" {
diff --git a/csctapi/icc_async.c b/csctapi/icc_async.c
index 34d6c83b3..c4a7e9e9a 100644
--- a/csctapi/icc_async.c
+++ b/csctapi/icc_async.c
@@ -54,6 +54,8 @@ static void calculate_cak7_vars(struct s_reader *reader, const ATR *atr)
mbedtls_sha256_free(&ctx_sha256);
memcpy(reader->cak7_aes_key,aes_key,32);
memcpy(reader->cak7_aes_iv,aes_iv,16);
+ char tmp[128];
+ rdr_log(reader, "Initial AES: %s", cs_hexdump(1, reader->cak7_aes_key + 16, 16, tmp, sizeof(tmp)));
}
void calculate_cak7_cmd(struct s_reader *reader, uint8_t *cmdin,uint8_t cmdlen,uint8_t *cmdout)
@@ -74,18 +76,101 @@ void do_cak7_cmd(struct s_reader *reader,unsigned char *cta_res, uint16_t *p_cta
// head
req[0]=0x80;
req[1]=0xCA;
- // len
- req[4]=inlen;
+ if(reader->protocol_type == ATR_PROTOCOL_TYPE_T0)
+ {
+ req[4]=inlen + 1;
+ }
+ else
+ {
+ req[4]=inlen;
+ }
req[sizeof(req)-1]=resplen;
data[4]=(reader->cak7_seq>>16)&0xFF;
data[5]=(reader->cak7_seq>>8)&0xFF;
data[6]=(reader->cak7_seq)&0xFF;
+ rdr_log_dump_dbg(reader, D_READER, data, inlen, "preparing data for writing to cardreader");
calculate_cak7_cmd(reader,data,inlen,&req[5]);
+ rdr_log_dump_dbg(reader, D_READER, req, sizeof(req), "write to cardreader");
if(!ICC_Async_CardWrite(reader, req, sizeof(req), cta_res, p_cta_lr))
{
- AesCtx ctx;
- AesCtxIni(&ctx, reader->cak7_aes_iv, &reader->cak7_aes_key[16], KEY128, CBC);
- AesDecrypt(&ctx, cta_res, cta_res, *p_cta_lr-2);
+ if(reader->protocol_type == ATR_PROTOCOL_TYPE_T0)
+ {
+ if(cta_res[*p_cta_lr - 2] == 0x61)
+ {
+ uint8_t resp[] = {0x00,0xC0,0x00,0x00,0x00};
+ memcpy(resp + 4,&cta_res[*p_cta_lr - 1],1);
+ if(!ICC_Async_CardWrite(reader, resp, sizeof(resp), cta_res, p_cta_lr))
+ {
+ AesCtx ctx;
+ AesCtxIni(&ctx, reader->cak7_aes_iv, &reader->cak7_aes_key[16], KEY128, CBC);
+ AesDecrypt(&ctx, cta_res, cta_res, *p_cta_lr-2);
+ }
+ else
+ {
+ *p_cta_lr=0;
+ }
+ }
+ else if(cta_res[*p_cta_lr - 2] == 0x6F && cta_res[*p_cta_lr - 1] == 0x01)
+ {
+ rdr_log(reader, "card answered 6F01 - trying one more time");
+ if(!ICC_Async_CardWrite(reader, req, sizeof(req), cta_res, p_cta_lr))
+ {
+ if(cta_res[*p_cta_lr - 2] == 0x61)
+ {
+ uint8_t resp[] = {0x00,0xC0,0x00,0x00,0x00};
+ memcpy(resp + 4,&cta_res[*p_cta_lr - 1],1);
+ if(!ICC_Async_CardWrite(reader, resp, sizeof(resp), cta_res, p_cta_lr))
+ {
+ AesCtx ctx;
+ AesCtxIni(&ctx, reader->cak7_aes_iv, &reader->cak7_aes_key[16], KEY128, CBC);
+ AesDecrypt(&ctx, cta_res, cta_res, *p_cta_lr-2);
+ }
+ else
+ {
+ *p_cta_lr=0;
+ }
+ }
+ else if(cta_res[*p_cta_lr - 2] == 0x6F && cta_res[*p_cta_lr - 1] == 0x01)
+ {
+ rdr_log(reader, "card needs reinit");
+ }
+ }
+ else
+ {
+ *p_cta_lr=0;
+ }
+ }
+ }
+ else
+ {
+ if(cta_res[*p_cta_lr - 2] == 0x6F && cta_res[*p_cta_lr - 1] == 0x01)
+ {
+ rdr_log(reader, "card answered 6F01 - trying one more time");
+ if(!ICC_Async_CardWrite(reader, req, sizeof(req), cta_res, p_cta_lr))
+ {
+ if(cta_res[*p_cta_lr - 2] == 0x6F && cta_res[*p_cta_lr - 1] == 0x01)
+ {
+ rdr_log(reader, "card needs reinit");
+ }
+ else
+ {
+ AesCtx ctx;
+ AesCtxIni(&ctx, reader->cak7_aes_iv, &reader->cak7_aes_key[16], KEY128, CBC);
+ AesDecrypt(&ctx, cta_res, cta_res, *p_cta_lr-2);
+ }
+ }
+ else
+ {
+ *p_cta_lr=0;
+ }
+ }
+ else
+ {
+ AesCtx ctx;
+ AesCtxIni(&ctx, reader->cak7_aes_iv, &reader->cak7_aes_key[16], KEY128, CBC);
+ AesDecrypt(&ctx, cta_res, cta_res, *p_cta_lr-2);
+ }
+ }
}
else
{
@@ -245,29 +330,46 @@ int32_t ICC_Async_Activate(struct s_reader *reader, ATR *atr, uint16_t deprecate
return ERROR;
}
+ reader->cak7type = 0;
#ifdef READER_NAGRA_MERLIN
- bool need_nagra_layer_switch = false;
- bool is_cak7 = false;
-
- static const uint8_t hd03atr [] = {0x3F,0xFF,0x95,0x00,0xFF,0x91,0x81,0x71,0xA0,0x47,0x00,0x44,0x4E,0x41,0x53,0x50,0x31,0x39,0x30,0x20,0x4D,0x65,0x72,0x51,0x32,0x35,0x4F}; //HD03, HD03A (CAK6.3 Mode)
- static const uint8_t hd03atr2[] = {0x3F,0xFF,0x95,0x00,0xFF,0x91,0x81,0x71,0xFE,0x57,0x00,0x44,0x4E,0x41,0x53,0x50,0x34,0x31,0x30,0x20,0x52,0x65,0x76,0x51,0x32,0x35,0x17}; //HD03, HD03A (CAK7 Mode)
- static const uint8_t hd04atr [] = {0x3F,0xFF,0x95,0x00,0xFF,0x91,0x81,0x71,0xFE,0x57,0x00,0x44,0x4E,0x41,0x53,0x50,0x34,0x32,0x30,0x20,0x52,0x65,0x76,0x53,0x36,0x30,0x17}; //HD04, HD04A, HD04B (CAK7 only)
- static const uint8_t hd04hatr[] = {0x3F,0xFF,0x95,0x00,0xFF,0x91,0x81,0x71,0xFE,0x57,0x00,0x44,0x4E,0x41,0x53,0x50,0x34,0x32,0x30,0x20,0x52,0x65,0x76,0x53,0x36,0x34,0x13}; //HD04H (CAK7 only)
- static const uint8_t hd05atr [] = {0x3F,0xFF,0x95,0x00,0xFF,0x91,0x81,0x71,0xFE,0x57,0x00,0x44,0x4E,0x41,0x53,0x50,0x34,0x35,0x30,0x20,0x52,0x65,0x76,0x57,0x36,0x30,0x14}; //HD05, HD05A (CAK7 only)
ATR_GetRaw(atr, atrarr, &atr_size);
- if(!memcmp(hd03atr, atrarr, atr_size)) need_nagra_layer_switch = true;
- if(!memcmp(hd03atr2, atrarr, atr_size) || !memcmp(hd04atr, atrarr, atr_size) || !memcmp(hd04hatr, atrarr, atr_size) || !memcmp(hd05atr, atrarr, atr_size)) is_cak7 = true;
- if(is_cak7)
+ if((memcmp(atrarr + 8, "DNASP40", 7) == 0) || (memcmp(atrarr + 11, "DNASP41", 7) == 0) || (memcmp(atrarr + 11, "DNASP48", 7) == 0))
+ {
+ rdr_log(reader, "card needs reset before init");
+ memset(atr, 0, 1);
+ call(crdr_ops->activate(reader, atr)); //try to read the atr of this layer
+ ATR_GetRaw(atr, atrarr, &atr_size);
+ rdr_log(reader,"ATR: %s", cs_hexdump(1, atrarr, atr_size, tmp, sizeof(tmp)));
+ // Parse_ATR and InitCard need to be included in lock because they change parity of serial port
+ if(crdr_ops->lock)
+ {
+ crdr_ops->lock(reader);
+ }
+ int32_t ret1 = Parse_ATR(reader, atr, deprecated);
+ if(crdr_ops->unlock)
+ {
+ crdr_ops->unlock(reader);
+ }
+ if(ret1)
+ {
+ rdr_log(reader, "ERROR: Parse_ATR returned error");
+ return ERROR;
+ }
+ }
+
+ if((memcmp(atrarr + 8, "DNASP4", 6) == 0) || (memcmp(atrarr + 11, "DNASP4", 6) == 0))
{
- rdr_log(reader, "detected nagra merlin card in CAK7 mode");
+ rdr_log(reader, "detected card in CAK7 mode");
calculate_cak7_vars(reader, atr);
+ reader->cak7type = 1;
}
- else if(need_nagra_layer_switch)
+ else if(((memcmp(atrarr + 7, "pp", 2) == 0 && ((atrarr[9]&0x0F) >= 10)) || (memcmp(atrarr + 11, "DNASP18", 7) == 0) || (memcmp(atrarr + 11, "DNASP19", 7) == 0) || (memcmp(atrarr + 11, "DNASP1A", 7) == 0)) && reader->cak7_mode)
{
- rdr_log(reader, "detected nagra merlin card in legacy mode -> try switch nagra layer to CAK7");
- uint8_t changerom_handshake[] = { 0x80, 0xCA, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 };
+ rdr_log(reader, "detected card in CAK6/Seca mode -> try switch to Nagra CAK7");
+ uint8_t changerom_handshake[22];
+ memset(changerom_handshake, 0x00, 22);
calculate_changerom_cmd(reader, atr, &changerom_handshake[5]);
memset(reader->rom, 0, 15);
@@ -275,6 +377,8 @@ int32_t ICC_Async_Activate(struct s_reader *reader, ATR *atr, uint16_t deprecate
memset(cta_res, 0, CTA_RES_LEN);
uint16_t cta_lr;
+ changerom_handshake[0] = 0x80;
+ changerom_handshake[1] = 0xCA;
changerom_handshake[4] = 0x11; // 0x11: length of data we will send
uint8_t cta_res1_ok = 0x61;
uint8_t cta_res2_ok = 0x10;
@@ -287,6 +391,9 @@ int32_t ICC_Async_Activate(struct s_reader *reader, ATR *atr, uint16_t deprecate
cta_res2_ok = 0x00;
}
+ changerom_handshake[21] = 0x10;
+
+ reader->cak7type = 1;
if(!ICC_Async_CardWrite(reader, changerom_handshake, sizeof(changerom_handshake), cta_res, &cta_lr))
{
if(cta_res[cta_lr-2] == cta_res1_ok && cta_res[cta_lr-1] == cta_res2_ok)
@@ -295,17 +402,31 @@ int32_t ICC_Async_Activate(struct s_reader *reader, ATR *atr, uint16_t deprecate
memset(atr, 0, 1);
call(crdr_ops->activate(reader, atr)); //try to read the atr of this layer
ATR_GetRaw(atr, atrarr, &atr_size);
- rdr_log(reader,"Nagra layer ATR: %s", cs_hexdump(1, atrarr, atr_size, tmp, sizeof(tmp)));
+ rdr_log(reader,"ATR: %s", cs_hexdump(1, atrarr, atr_size, tmp, sizeof(tmp)));
calculate_cak7_vars(reader, atr);
+ if(reader->protocol_type == ATR_PROTOCOL_TYPE_T0)
+ {
+ reader->cak7type = 3;
+ }
+ else
+ {
+ reader->cak7type = 1;
+ }
+
if(crdr_ops->lock)
{
crdr_ops->lock(reader);
}
- Parse_ATR(reader, atr, deprecated);
+ int32_t ret2 = Parse_ATR(reader, atr, deprecated);
if(crdr_ops->unlock)
{
crdr_ops->unlock(reader);
}
+ if(ret2)
+ {
+ rdr_log(reader, "ERROR: Parse_ATR returned error");
+ return ERROR;
+ }
}
else
{
@@ -362,7 +483,7 @@ int32_t ICC_Async_CardWrite(struct s_reader *reader, unsigned char *command, uin
case ATR_PROTOCOL_TYPE_T1:
ret = Protocol_T1_Command(reader, command, command_len, rsp, lr);
type = 1;
- if(ret != OK && !crdr_ops->skip_t1_command_retries)
+ if(ret != OK && !crdr_ops->skip_t1_command_retries && reader->cak7type == 0)
{
//try to resync
rdr_log(reader, "Resync error: readtimeouts %d/%d (max/min) us, writetimeouts %d/%d (max/min) us", reader->maxreadtimeout, reader->minreadtimeout, reader->maxwritetimeout, reader->minwritetimeout);
@@ -398,7 +519,7 @@ int32_t ICC_Async_CardWrite(struct s_reader *reader, unsigned char *command, uin
}
try++;
}
- while((try < 3) && (ret != OK)); // always do one retry when failing
+ while((try < 3) && (ret != OK) && (((type == 0 || type == 1) && reader->cak7type == 0) || type == 14)); // always do one retry when failing
if(crdr_ops->unlock)
{
crdr_ops->unlock(reader);
diff --git a/ffdecsa/CMakeLists.txt b/ffdecsa/CMakeLists.txt
deleted file mode 100644
index d5be555f8..000000000
--- a/ffdecsa/CMakeLists.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-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})
diff --git a/ffdecsa/COPYING b/ffdecsa/COPYING
deleted file mode 100644
index a43ea2126..000000000
--- a/ffdecsa/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 675 Mass Ave, Cambridge, MA 02139, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- Appendix: How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C) 19yy
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- , 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/ffdecsa/Makefile b/ffdecsa/Makefile
deleted file mode 100644
index b03684a08..000000000
--- a/ffdecsa/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-parent:
- @$(MAKE) --no-print-directory -C ..
diff --git a/ffdecsa/ffdecsa.c b/ffdecsa/ffdecsa.c
deleted file mode 100644
index 2c7169a79..000000000
--- a/ffdecsa/ffdecsa.c
+++ /dev/null
@@ -1,926 +0,0 @@
-/* FFdecsa -- fast decsa algorithm
- *
- * Copyright (C) 2003-2004 fatih89r
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-#include
-#include
-#include
-#include
-
-#include "ffdecsa.h"
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-//#define DEBUG
-#ifdef DEBUG
-#define DBG(a) a
-#else
-#define DBG(a)
-#endif
-
-//// parallelization stuff, large speed differences are possible
-// possible choices
-#define PARALLEL_32_4CHAR 320
-#define PARALLEL_32_4CHARA 321
-#define PARALLEL_32_INT 322
-#define PARALLEL_64_8CHAR 640
-#define PARALLEL_64_8CHARA 641
-#define PARALLEL_64_2INT 642
-#define PARALLEL_64_LONG 643
-#define PARALLEL_64_MMX 644
-#define PARALLEL_128_16CHAR 1280
-#define PARALLEL_128_16CHARA 1281
-#define PARALLEL_128_4INT 1282
-#define PARALLEL_128_2LONG 1283
-#define PARALLEL_128_2MMX 1284
-#define PARALLEL_128_SSE 1285
-#define PARALLEL_128_SSE2 1286
-
-//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice ////////
-#ifndef PARALLEL_MODE
-
-#if defined(__x86_64__) || defined(_M_X64)
-#define PARALLEL_MODE PARALLEL_128_SSE2
-
-#elif defined(__mips__) || defined(__mips) || defined(__MIPS__)
-#define PARALLEL_MODE PARALLEL_64_LONG
-
-#elif defined(__sh__) || defined(__SH4__)
-#define PARALLEL_MODE PARALLEL_32_INT
-#define COPY_UNALIGNED_PKT
-#define MEMALIGN_VAL 4
-
-#else
-#define PARALLEL_MODE PARALLEL_32_INT
-#endif
-
-#endif
-//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice ////////
-
-#include "parallel_generic.h"
-//// conditionals
-#if PARALLEL_MODE==PARALLEL_32_4CHAR
-#include "parallel_032_4char.h"
-#elif PARALLEL_MODE==PARALLEL_32_4CHARA
-#include "parallel_032_4charA.h"
-#elif PARALLEL_MODE==PARALLEL_32_INT
-#include "parallel_032_int.h"
-#elif PARALLEL_MODE==PARALLEL_64_8CHAR
-#include "parallel_064_8char.h"
-#elif PARALLEL_MODE==PARALLEL_64_8CHARA
-#include "parallel_064_8charA.h"
-#elif PARALLEL_MODE==PARALLEL_64_2INT
-#include "parallel_064_2int.h"
-#elif PARALLEL_MODE==PARALLEL_64_LONG
-#include "parallel_064_long.h"
-#elif PARALLEL_MODE==PARALLEL_64_MMX
-#include "parallel_064_mmx.h"
-#elif PARALLEL_MODE==PARALLEL_128_16CHAR
-#include "parallel_128_16char.h"
-#elif PARALLEL_MODE==PARALLEL_128_16CHARA
-#include "parallel_128_16charA.h"
-#elif PARALLEL_MODE==PARALLEL_128_4INT
-#include "parallel_128_4int.h"
-#elif PARALLEL_MODE==PARALLEL_128_2LONG
-#include "parallel_128_2long.h"
-#elif PARALLEL_MODE==PARALLEL_128_2MMX
-#include "parallel_128_2mmx.h"
-#elif PARALLEL_MODE==PARALLEL_128_SSE
-#include "parallel_128_sse.h"
-#elif PARALLEL_MODE==PARALLEL_128_SSE2
-#include "parallel_128_sse2.h"
-#else
-#error "unknown/undefined parallel mode"
-#endif
-
-// stuff depending on conditionals
-
-#define BYTES_PER_GROUP (GROUP_PARALLELISM/8)
-#define BYPG BYTES_PER_GROUP
-#define BITS_PER_GROUP GROUP_PARALLELISM
-#define BIPG BITS_PER_GROUP
-
-// platform specific
-
-#ifdef __arm__
-#if !defined(MEMALIGN_VAL) || MEMALIGN_VAL<4
-#undef MEMALIGN_VAL
-#define MEMALIGN_VAL 4
-#endif
-#define COPY_UNALIGNED_PKT
-#endif
-
-//
-
-#ifndef MALLOC
-#define MALLOC(X) malloc(X)
-#endif
-#ifndef FREE
-#define FREE(X) free(X)
-#endif
-#ifdef MEMALIGN_VAL
-#define MEMALIGN __attribute__((aligned(MEMALIGN_VAL)))
-#else
-#define MEMALIGN
-#endif
-
-//// debug tool
-
-#ifdef DEBUG
-static void dump_mem(const char *string, const unsigned char *p, int len, int linelen){
- int i;
- for(i=0;i>4)&0xf;
- iA[1]=(ck[0] )&0xf;
- iA[2]=(ck[1]>>4)&0xf;
- iA[3]=(ck[1] )&0xf;
- iA[4]=(ck[2]>>4)&0xf;
- iA[5]=(ck[2] )&0xf;
- iA[6]=(ck[3]>>4)&0xf;
- iA[7]=(ck[3] )&0xf;
- iB[0]=(ck[4]>>4)&0xf;
- iB[1]=(ck[4] )&0xf;
- iB[2]=(ck[5]>>4)&0xf;
- iB[3]=(ck[5] )&0xf;
- iB[4]=(ck[6]>>4)&0xf;
- iB[5]=(ck[6] )&0xf;
- iB[6]=(ck[7]>>4)&0xf;
- iB[7]=(ck[7] )&0xf;
-}
-
-//----- stream main function
-
-#define STREAM_INIT
-#include "stream.c"
-#undef STREAM_INIT
-
-#define STREAM_NORMAL
-#include "stream.c"
-#undef STREAM_NORMAL
-
-
-//-----block decypher
-
-//-----key schedule for block decypher
-
-static void key_schedule_block(
- unsigned char *ck, // [In] ck[0]-ck[7] 8 bytes | Key.
- unsigned char *kk) // [Out] kk[0]-kk[55] 56 bytes | Key schedule.
-{
- static const unsigned char key_perm[0x40] = {
- 0x12,0x24,0x09,0x07,0x2A,0x31,0x1D,0x15, 0x1C,0x36,0x3E,0x32,0x13,0x21,0x3B,0x40,
- 0x18,0x14,0x25,0x27,0x02,0x35,0x1B,0x01, 0x22,0x04,0x0D,0x0E,0x39,0x28,0x1A,0x29,
- 0x33,0x23,0x34,0x0C,0x16,0x30,0x1E,0x3A, 0x2D,0x1F,0x08,0x19,0x17,0x2F,0x3D,0x11,
- 0x3C,0x05,0x38,0x2B,0x0B,0x06,0x0A,0x2C, 0x20,0x3F,0x2E,0x0F,0x03,0x26,0x10,0x37,
- };
-
- int i,j,k;
- int bit[64];
- int newbit[64];
- int kb[7][8];
-
- // 56 steps
- // 56 key bytes kk(55)..kk(0) by key schedule from ck
-
- // kb(6,0) .. kb(6,7) = ck(0) .. ck(7)
- kb[6][0] = ck[0];
- kb[6][1] = ck[1];
- kb[6][2] = ck[2];
- kb[6][3] = ck[3];
- kb[6][4] = ck[4];
- kb[6][5] = ck[5];
- kb[6][6] = ck[6];
- kb[6][7] = ck[7];
-
- // calculate kb[5] .. kb[0]
- for(i=5; i>=0; i--){
- // 64 bit perm on kb
- for(j=0; j<8; j++){
- for(k=0; k<8; k++){
- bit[j*8+k] = (kb[i+1][j] >> (7-k)) & 1;
- newbit[key_perm[j*8+k]-1] = bit[j*8+k];
- }
- }
- for(j=0; j<8; j++){
- kb[i][j] = 0;
- for(k=0; k<8; k++){
- kb[i][j] |= newbit[j*8+k] << (7-k);
- }
- }
- }
-
- // xor to give kk
- for(i=0; i<7; i++){
- for(j=0; j<8; j++){
- kk[i*8+j] = kb[i][j] ^ i;
- }
- }
-
-}
-
-//-----block utils
-
-static inline __attribute__((always_inline)) void trasp_N_8 (unsigned char *in,unsigned char* out,int count){
- int *ri=(int *)in;
- int *ibi=(int *)out;
- int j,i,k,g;
- // copy and first step
- for(g=0;g>16) | (b&0xffff0000) ;
- }
- }
- }
-//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
-// now 01010101
- for(j=0;j<8;j+=2){
- for(i=0;i<1;i++){
- for(k=0;k>8) | (b&0xff00ff00);
- }
- }
- }
-//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
-// now 00000000
-}
-
-static inline __attribute__((always_inline)) void trasp_8_N (unsigned char *in,unsigned char* out,int count){
- int *ri=(int *)in;
- int *bdi=(int *)out;
- int j,i,k,g;
-#define INTS_PER_ROW (GROUP_PARALLELISM/8*2)
-//dump_mem("NE1 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
-// now 00000000
- for(j=0;j<8;j+=2){
- for(i=0;i<1;i++){
- for(k=0;k>8) | (b&0xff00ff00);
- }
- }
- }
-//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
-// now 01010101
- for(j=0;j<8;j+=4){
- for(i=0;i<2;i++){
- for(k=0;k>16) | (b&0xffff0000) ;
- }
- }
- }
-//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM);
-// now 01230123
- for(g=0;g=0;i--){
- {
- MEMALIGN batch tkkmulti=kkmulti[i];
- batch *si=(batch *)sbox_in;
- batch *r6_N=(batch *)(r+roff+GROUP_PARALLELISM*6);
- for(g=0;gck,pk,8);
-// precalculations for stream
- key_schedule_stream(key->ck,key->iA,key->iB);
- for(by=0;by<8;by++){
- for(bi=0;bi<8;bi++){
- key->ck_g[by][bi]=(key->ck[by]&(1<iA_g[by][bi]=(key->iA[by]&(1<iB_g[by][bi]=(key->iB[by]&(1<ck,key->kk);
- for(i=0;i<56;i++){
- for(j=0;jkkmulti[i])+j)=key->kk[i];
- }
- }
-}
-
-void set_control_words(void *keys, const unsigned char *ev, const unsigned char *od){
- schedule_key(&((struct csa_keys_t *)keys)->even,ev);
- schedule_key(&((struct csa_keys_t *)keys)->odd,od);
-}
-
-void set_even_control_word(void *keys, const unsigned char *pk){
- schedule_key(&((struct csa_keys_t *)keys)->even,pk);
-}
-
-void set_odd_control_word(void *keys, const unsigned char *pk){
- schedule_key(&((struct csa_keys_t *)keys)->odd,pk);
-}
-
-//-----get control words
-
-void get_control_words(void *keys, unsigned char *even, unsigned char *odd){
- memcpy(even,&((struct csa_keys_t *)keys)->even.ck,8);
- memcpy(odd,&((struct csa_keys_t *)keys)->odd.ck,8);
-}
-
-//----- decrypt
-
-int decrypt_packets(void *keys, unsigned char **cluster){
- // statistics, currently unused
- int stat_no_scramble=0;
- int stat_reserved=0;
- int stat_decrypted[2]={0,0};
- int stat_decrypted_mini=0;
- unsigned char **clst;
- unsigned char **clst2;
- int grouped;
- int group_ev_od;
- int advanced;
- int can_advance;
- unsigned char *g_pkt[GROUP_PARALLELISM];
- int g_len[GROUP_PARALLELISM];
- int g_offset[GROUP_PARALLELISM];
- int g_n[GROUP_PARALLELISM];
- int g_residue[GROUP_PARALLELISM];
- unsigned char *pkt;
- int xc0,ev_od,len,offset,n,residue;
- struct csa_key_t* k;
- int i,j,iter,g;
- int t23,tsmall;
- int alive[24];
-//icc craziness int pad1=0; //////////align! FIXME
- unsigned char *encp[GROUP_PARALLELISM];
- MEMALIGN unsigned char stream_in[GROUP_PARALLELISM*8];
- MEMALIGN unsigned char stream_out[GROUP_PARALLELISM*8];
- MEMALIGN unsigned char ib[GROUP_PARALLELISM*8];
- MEMALIGN unsigned char block_out[GROUP_PARALLELISM*8];
-#ifdef COPY_UNALIGNED_PKT
- unsigned char *unaligned[GROUP_PARALLELISM];
- MEMALIGN unsigned char alignedBuff[GROUP_PARALLELISM][188];
-#endif
- struct stream_regs regs;
-
-//icc craziness i=(int)&pad1;//////////align!!! FIXME
-
- // build a list of packets to be processed
- clst=cluster;
- grouped=0;
- advanced=0;
- can_advance=1;
- group_ev_od=-1; // silence incorrect compiler warning
- pkt=*clst;
- do{ // find a new packet
- if(grouped==GROUP_PARALLELISM){
- // full
- break;
- }
- if(pkt==NULL){
- // no more ranges
- break;
- }
- if(pkt>=*(clst+1)){
- // out of this range, try next
- clst++;clst++;
- pkt=*clst;
- continue;
- }
-
- do{ // handle this packet
- xc0=pkt[3]&0xc0;
- DBG(fprintf(stderr," exam pkt=%p, xc0=%02x, can_adv=%i\n",pkt,xc0,can_advance));
- if(xc0==0x00){
- DBG(fprintf(stderr,"skip clear pkt %p (can_advance is %i)\n",pkt,can_advance));
- advanced+=can_advance;
- stat_no_scramble++;
- break;
- }
- if(xc0==0x40){
- DBG(fprintf(stderr,"skip reserved pkt %p (can_advance is %i)\n",pkt,can_advance));
- advanced+=can_advance;
- stat_reserved++;
- break;
- }
- if(xc0==0x80||xc0==0xc0){ // encrypted
- ev_od=(xc0&0x40)>>6; // 0 even, 1 odd
- if(grouped==0) group_ev_od=ev_od; // this group will be all even (or odd)
- if(group_ev_od==ev_od){ // could be added to group
- pkt[3]&=0x3f; // consider it decrypted now
- if(pkt[3]&0x20){ // incomplete packet
- offset=4+pkt[4]+1;
- len=188-offset;
- n=len>>3;
- residue=len-(n<<3);
- if(n==0){ // decrypted==encrypted!
- DBG(fprintf(stderr,"DECRYPTED MINI! (can_advance is %i)\n",can_advance));
- advanced+=can_advance;
- stat_decrypted_mini++;
- break; // this doesn't need more processing
- }
- }else{
- len=184;
- offset=4;
- n=23;
- residue=0;
- }
- g_pkt[grouped]=pkt;
- g_len[grouped]=len;
- g_offset[grouped]=offset;
- g_n[grouped]=n;
- g_residue[grouped]=residue;
- DBG(fprintf(stderr,"%2i: eo=%i pkt=%p len=%03i n=%2i residue=%i\n",grouped,ev_od,pkt,len,n,residue));
- grouped++;
- advanced+=can_advance;
- stat_decrypted[ev_od]++;
- }
- else{
- can_advance=0;
- DBG(fprintf(stderr,"skip pkt %p and can_advance set to 0\n",pkt));
- break; // skip and go on
- }
- }
- } while(0);
-
- if(can_advance){
- // move range start forward
- *clst+=188;
- }
- // next packet, if there is one
- pkt+=188;
- } while(1);
- DBG(fprintf(stderr,"-- result: grouped %i pkts, advanced %i pkts\n",grouped,advanced));
-
- // delete empty ranges and compact list
- clst2=cluster;
- for(clst=cluster;*clst!=NULL;clst+=2){
- // if not empty
- if(*clst<*(clst+1)){
- // it will remain
- *clst2=*clst;
- *(clst2+1)=*(clst+1);
- clst2+=2;
- }
- }
- *clst2=NULL;
-
- if(grouped==0){
- // no processing needed
- return advanced;
- }
-
- // sort them, longest payload first
- // we expect many n=23 packets and a few n<23
- DBG(fprintf(stderr,"PRESORTING\n"));
- for(i=0;i=0;tsmall--){
- if(g_n[tsmall]==23) break;
- }
-DBG(fprintf(stderr,"tsmall after for =%i\n",tsmall));
-
- if(tsmall-t23<1) break;
-
-DBG(fprintf(stderr,"swap t23=%i,tsmall=%i\n",t23,tsmall));
-
- g_swap(t23,tsmall);
-
- t23++;
- tsmall--;
-DBG(fprintf(stderr,"new t23=%i,tsmall=%i\n\n",t23,tsmall));
- }
- DBG(fprintf(stderr,"packets with n=23, t23=%i grouped=%i\n",t23,grouped));
- DBG(fprintf(stderr,"MIDSORTING\n"));
- for(i=0;ig_n[i]){
- g_swap(i,j);
- }
- }
- }
- DBG(fprintf(stderr,"POSTSORTING\n"));
- for(i=0;i=0;i--){
- alive[i]+=alive[i+1];
- }
- DBG(fprintf(stderr,"ALIVE\n"));
- for(i=0;i<=23;i++){
- DBG(fprintf(stderr,"alive%2i=%i\n",i,alive[i]));
- }
-
- // choose key
- if(group_ev_od==0){
- k=&((struct csa_keys_t *)keys)->even;
- }
- else{
- k=&((struct csa_keys_t *)keys)->odd;
- }
-
- //INIT
-//#define INITIALIZE_UNUSED_INPUT
-#ifdef INITIALIZE_UNUSED_INPUT
-// unnecessary zeroing.
-// without this, we operate on uninitialized memory
-// when grouped>>>>ITER 0\n"));
- iter=0;
- stream_cypher_group_init(®s,k->iA_g,k->iB_g,stream_in);
- // fill first ib
- for(g=0;g0;iter++){
-DBG(fprintf(stderr,">>>>>ITER %i\n",iter));
- // alive and just dead packets: calc block
- block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]);
-DBG(dump_mem("BLO_ib ",block_out,8*alive[iter-1],8));
- // all packets (dead too): calc stream
- stream_cypher_group_normal(®s,stream_out);
-//dump_mem("stream_out",stream_out,GROUP_PARALLELISM*8,BYPG);
-
- // alive packets: calc ib
- for(g=0;g>>>>ITER 23\n"));
- iter=23;
- // calc block
- block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]);
-DBG(dump_mem("23BLO_ib ",block_out,8*alive[iter-1],8));
- // just dead packets: write decrypted data
- for(g=alive[iter];g=4?32-1:0))+j);
- }
-}
-
-typedef unsigned int batch;
-#define BYTES_PER_BATCH 4
-#define B_FFN_ALL_29() 0x29292929
-#define B_FFN_ALL_02() 0x02020202
-#define B_FFN_ALL_04() 0x04040404
-#define B_FFN_ALL_10() 0x10101010
-#define B_FFN_ALL_40() 0x40404040
-#define B_FFN_ALL_80() 0x80808080
-
-#define M_EMPTY()
diff --git a/ffdecsa/parallel_064_long.h b/ffdecsa/parallel_064_long.h
deleted file mode 100644
index 09f7b95dd..000000000
--- a/ffdecsa/parallel_064_long.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* 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"
diff --git a/ffdecsa/parallel_128_sse2.h b/ffdecsa/parallel_128_sse2.h
deleted file mode 100644
index c7bd72517..000000000
--- a/ffdecsa/parallel_128_sse2.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* FFdecsa -- fast decsa algorithm
- *
- * Copyright (C) 2007 Dark Avenger
- * 2003-2004 fatih89r
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include
-
-#define MEMALIGN_VAL 16
-
-union __u128i {
- unsigned int u[4];
- __m128i v;
-};
-
-static const union __u128i ff0 = {{0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}};
-static const union __u128i ff1 = {{0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU}};
-
-typedef __m128i group;
-#define GROUP_PARALLELISM 128
-#define FF0() ff0.v
-#define FF1() ff1.v
-#define FFAND(a,b) _mm_and_si128((a),(b))
-#define FFOR(a,b) _mm_or_si128((a),(b))
-#define FFXOR(a,b) _mm_xor_si128((a),(b))
-#define FFNOT(a) _mm_xor_si128((a),FF1())
-#define MALLOC(X) _mm_malloc(X,16)
-#define FREE(X) _mm_free(X)
-
-/* BATCH */
-
-static const union __u128i ff29 = {{0x29292929U, 0x29292929U, 0x29292929U, 0x29292929U}};
-static const union __u128i ff02 = {{0x02020202U, 0x02020202U, 0x02020202U, 0x02020202U}};
-static const union __u128i ff04 = {{0x04040404U, 0x04040404U, 0x04040404U, 0x04040404U}};
-static const union __u128i ff10 = {{0x10101010U, 0x10101010U, 0x10101010U, 0x10101010U}};
-static const union __u128i ff40 = {{0x40404040U, 0x40404040U, 0x40404040U, 0x40404040U}};
-static const union __u128i ff80 = {{0x80808080U, 0x80808080U, 0x80808080U, 0x80808080U}};
-
-typedef __m128i batch;
-#define BYTES_PER_BATCH 16
-#define B_FFN_ALL_29() ff29.v
-#define B_FFN_ALL_02() ff02.v
-#define B_FFN_ALL_04() ff04.v
-#define B_FFN_ALL_10() ff10.v
-#define B_FFN_ALL_40() ff40.v
-#define B_FFN_ALL_80() ff80.v
-
-#define B_FFAND(a,b) FFAND(a,b)
-#define B_FFOR(a,b) FFOR(a,b)
-#define B_FFXOR(a,b) FFXOR(a,b)
-#define B_FFSH8L(a,n) _mm_slli_epi64((a),(n))
-#define B_FFSH8R(a,n) _mm_srli_epi64((a),(n))
-
-#define M_EMPTY()
-
-#undef BEST_SPAN
-#define BEST_SPAN 16
-
-#undef XOR_BEST_BY
-inline static void XOR_BEST_BY(unsigned char *d, unsigned char *s1, unsigned char *s2)
-{
- __m128i vs1 = _mm_load_si128((__m128i*)s1);
- __m128i vs2 = _mm_load_si128((__m128i*)s2);
- vs1 = _mm_xor_si128(vs1, vs2);
- _mm_store_si128((__m128i*)d, vs1);
-}
-
-#include "fftable.h"
diff --git a/ffdecsa/parallel_generic.h b/ffdecsa/parallel_generic.h
deleted file mode 100644
index 2af4c1c32..000000000
--- a/ffdecsa/parallel_generic.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/* 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
diff --git a/ffdecsa/parallel_std_def.h b/ffdecsa/parallel_std_def.h
deleted file mode 100644
index 10517d483..000000000
--- a/ffdecsa/parallel_std_def.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* 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))
diff --git a/ffdecsa/stream.c b/ffdecsa/stream.c
deleted file mode 100644
index 1bda8521c..000000000
--- a/ffdecsa/stream.c
+++ /dev/null
@@ -1,906 +0,0 @@
-/* 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
-
-}
-
diff --git a/globals.h b/globals.h
index cc5690348..4d130e794 100644
--- a/globals.h
+++ b/globals.h
@@ -368,7 +368,7 @@
/* ===========================
* constants
* =========================== */
-#define CS_VERSION "1.20_svn"
+#define CS_VERSION "1.30_svn"
#ifndef CS_SVN_VERSION
# define CS_SVN_VERSION "test"
#endif
@@ -628,6 +628,7 @@ enum {E2_GLOBAL = 0, E2_GROUP, E2_CAID, E2_IDENT, E2_CLASS, E2_CHID, E2_QUEUE, E
#define CW_ALGO_CSA 0
#define CW_ALGO_DES 1
#define CW_ALGO_AES128 2
+#define CW_ALGO_CSA_ALT 3
#define CW_ALGO_MODE_ECB 0
#define CW_ALGO_MODE_CBC 1
@@ -1556,6 +1557,7 @@ struct s_reader // contains device info, reader info and card info
int32_t resetcounter; // actual count
uint32_t auprovid; // AU only for this provid
int8_t audisabled; // exclude reader from auto AU
+ int8_t autype;
int8_t needsemmfirst; // 0: reader descrambles without emm first, 1: reader needs emms before it can descramble
struct timeb emm_last; // time of last successfully written emm
int8_t smargopatch;
@@ -1574,27 +1576,56 @@ struct s_reader // contains device info, reader info and card info
#ifdef READER_CRYPTOWORKS
int8_t needsglobalfirst; // 0:Write one Global EMM for SHARED EMM disabled 1:Write one Global EMM for SHARED EMM enabled
#endif
-#if defined(READER_NAGRA_MERLIN) || defined(READER_NAGRA)
- uint8_t nuid[4];
- uint8_t nuid_length;
- uint8_t cwekey[16];
- uint8_t cwekey_length;
+#if defined(READER_NAGRA)
+ uint8_t cak63nuid[4];
+ uint8_t cak63nuid_length;
+ uint8_t cak63cwekey[16];
+ uint8_t cak63cwekey_length;
#endif
#ifdef READER_NAGRA_MERLIN
- uint8_t irdid[4];
- uint8_t irdid_length;
- uint8_t public_exponent[3];
- uint8_t public_exponent_length;
uint8_t mod1[112];
uint8_t mod1_length;
+ uint8_t cmd0eprov[2];
+ uint8_t cmd0eprov_length;
+ uint8_t mod2[112];
+ uint8_t mod2_length;
+ uint8_t tmprsa[112];
uint8_t data50[80];
uint8_t data50_length;
uint8_t mod50[80];
uint8_t mod50_length;
+ uint8_t key3588[136];
+ uint8_t key3588_length;
uint8_t key60[96];
- uint8_t key60_length;
uint8_t exp60[96];
- uint8_t exp60_length;
+ uint8_t key68[104];
+ uint8_t exp68[104];
+ uint8_t key3des[16];
+ uint8_t klucz68[24];
+ uint8_t pairtype;
+ uint8_t hasunique;
+ uint8_t key3460[96];
+ uint8_t key3460_length;
+ uint8_t key3310[16];
+ uint8_t key3310_length;
+ uint8_t cwekey0[16];
+ uint8_t cwekey0_length;
+ uint8_t cwekey1[16];
+ uint8_t cwekey1_length;
+ uint8_t cwekey2[16];
+ uint8_t cwekey2_length;
+ uint8_t cwekey3[16];
+ uint8_t cwekey3_length;
+ uint8_t cwekey4[16];
+ uint8_t cwekey4_length;
+ uint8_t cwekey5[16];
+ uint8_t cwekey5_length;
+ uint8_t cwekey6[16];
+ uint8_t cwekey6_length;
+ uint8_t cwekey7[16];
+ uint8_t cwekey7_length;
+ uint8_t idird[4];
+ uint8_t idird_length;
uint8_t kdt05_00[216];
uint8_t kdt05_10[208];
uint8_t cardid[8];
@@ -1605,7 +1636,12 @@ struct s_reader // contains device info, reader info and card info
uint8_t block3[8];
uint8_t v[8];
uint8_t iout[8];
+ uint32_t dword_83DBC;
uint8_t data2[4];
+ uint8_t ecmheader[4];
+ uint8_t timestmp1[4];
+ uint8_t timestmp2[4];
+ uint8_t cak7expo[0x11];
uint8_t data[0x80];
uint8_t step1[0x60];
uint8_t step2[0x68];
@@ -1614,12 +1650,22 @@ struct s_reader // contains device info, reader info and card info
uint8_t result[104];
uint8_t stillencrypted[0x50];
uint8_t resultrsa[0x50];
- uint32_t cak7_restart;
uint32_t cak7_seq;
+ uint32_t needrestart;
+ uint8_t otpcsc[2];
+ uint8_t otpcsc_length;
+ uint8_t otacsc[2];
+ uint8_t otacsc_length;
+ uint8_t forcepair[1];
+ uint8_t forcepair_length;
uint8_t cak7_camstate;
uint8_t cak7_aes_key[32];
uint8_t cak7_aes_iv[16];
- struct timeb last_refresh;
+ int8_t forcecwswap;
+ int8_t evensa;
+ int8_t forceemmg;
+ int8_t cwpkota;
+
#endif
#ifdef CS_CACHEEX
CECSP cacheex; // CacheEx Settings
@@ -1644,6 +1690,12 @@ struct s_reader // contains device info, reader info and card info
int32_t l_port;
CAIDTAB ctab;
uint32_t boxid;
+ int8_t cak7_mode;
+ uint8_t cak7type;
+ uint8_t cwpkcaid[2];
+ uint8_t cwpkcaid_length;
+ uint8_t nuid[4];
+ uint8_t nuid_length;
int8_t nagra_read; // read nagra ncmed records: 0 Disabled (default), 1 read all records, 2 read valid records only
int8_t detect_seca_nagra_tunneled_card;
int8_t force_irdeto;
@@ -1651,6 +1703,8 @@ struct s_reader // contains device info, reader info and card info
uint8_t boxkey_length;
uint8_t rsa_mod[120]; // rsa modulus for nagra cards.
uint8_t rsa_mod_length;
+ uint8_t cwpk_mod[16]; // cwpk modulus for conax cards.
+ uint8_t cwpk_mod_length;
uint8_t des_key[128]; // 3des key for Viaccess 16 bytes, des key for Dre 128 bytes
uint8_t des_key_length;
uint8_t atr[64];
@@ -1662,8 +1716,18 @@ struct s_reader // contains device info, reader info and card info
SIDTABS lb_sidtabs;
uint8_t hexserial[8];
int32_t nprov;
+ int32_t nsa;
+ int32_t nemm84;
+ int32_t nemm83u;
+ int32_t nemm83s;
+ int32_t nemm87;
uint8_t prid[CS_MAXPROV][8];
uint8_t sa[CS_MAXPROV][4]; // viaccess & seca
+ uint8_t emm84[CS_MAXPROV][3];
+ uint8_t emm83u[CS_MAXPROV][6];
+ uint8_t emm83s[CS_MAXPROV][6];
+ uint8_t emm87[CS_MAXPROV][6];
+ uint8_t emm82;
uint8_t read_old_classes; // viaccess
uint8_t maturity; // viaccess & seca maturity level
uint16_t caid;
@@ -2338,6 +2402,9 @@ struct s_config
int8_t dvbapi_read_sdt;
int8_t dvbapi_write_sdt_prov;
int8_t dvbapi_extended_cw_api;
+#ifdef MODULE_STREAMRELAY
+ int8_t dvbapi_demuxer_fix;
+#endif
#endif
#ifdef CS_ANTICASC
@@ -2386,16 +2453,23 @@ struct s_config
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;
- CAIDTAB emu_stream_relay_ctab; // use the stream server for these caids
+#ifdef MODULE_STREAMRELAY
+ char *stream_source_host;
+ int32_t stream_source_port;
+ char *stream_source_auth_user;
+ char *stream_source_auth_password;
+ int32_t stream_relay_port;
+#ifdef MODULE_RADEGAST
+ int8_t stream_client_source_host;
+#endif
+ int8_t stream_relay_enabled;
+ uint32_t stream_relay_buffer_time;
+ CAIDTAB stream_relay_ctab; // use the stream server for these caids
+#ifdef WITH_NEUTRINO
+#define DEFAULT_STREAM_SOURCE_PORT 31339 //Neutrino
+#else
+#define DEFAULT_STREAM_SOURCE_PORT 8001 //Enigma2
+#endif
#endif
int32_t max_cache_time; // seconds ecms are stored in ecmcwcache
diff --git a/module-dvbapi.c b/module-dvbapi.c
index 82a4f490b..ac48833e7 100644
--- a/module-dvbapi.c
+++ b/module-dvbapi.c
@@ -12,6 +12,7 @@
#include "module-dvbapi-stapi.h"
#include "module-dvbapi-chancache.h"
#include "module-stat.h"
+#include "module-streamrelay.h"
#include "oscam-chk.h"
#include "oscam-client.h"
#include "oscam-config.h"
@@ -1248,6 +1249,14 @@ static int32_t dvbapi_detect_api(void)
maxfilter = filtercount;
cs_log("Detected %s Api: %d, userconfig boxtype: %d maximum number of filters is %d (oscam limit is %d)",
device_path, selected_api, cfg.dvbapi_boxtype, filtercount, MAX_FILTER);
+
+#ifdef MODULE_STREAMRELAY
+ // Log enabled demuxer fix
+ if(cfg.dvbapi_demuxer_fix)
+ {
+ cs_log("Demuxer fix enabled, try fixing stream relay audio/video sync...");
+ }
+#endif
}
// try at least 8 adapters
@@ -6830,10 +6839,24 @@ static void *dvbapi_main_local(void *cli)
}
// count ecm filters to see if demuxing is possible anyway
- if(demux[i].demux_fd[g].type == TYPE_ECM)
+#ifdef MODULE_STREAMRELAY
+ if(cfg.dvbapi_demuxer_fix)
{
- ecmcounter++;
+ if(demux[i].demux_fd[g].type == TYPE_ECM || demux[i].demux_fd[g].type == 3 || demux[i].demux_fd[g].type == 6)
+ {
+ ecmcounter++;
+ }
}
+ else
+ {
+#endif
+ if(demux[i].demux_fd[g].type == TYPE_ECM)
+ {
+ ecmcounter++;
+ }
+#ifdef MODULE_STREAMRELAY
+ }
+#endif
// count emm filters also
if(demux[i].demux_fd[g].type == TYPE_EMM)
@@ -7502,6 +7525,25 @@ void delayer(ECM_REQUEST *er, uint32_t delay)
}
}
+#ifdef WITH_EXTENDED_CW
+bool caid_is_csa_alt(uint16_t caid)
+{
+ return caid == 0x09c4 || caid == 0x098c || caid==0x098d;
+}
+
+bool select_csa_alt(ECM_REQUEST *er)
+{
+ if(caid_is_csa_alt(er->caid))
+ {
+ if((er->ecm[2] - er->ecm[4]) == 4)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
void dvbapi_send_dcw(struct s_client *client, ECM_REQUEST *er)
{
int32_t i, j, k, handled = 0;
@@ -7849,8 +7891,14 @@ void dvbapi_send_dcw(struct s_client *client, ECM_REQUEST *er)
delayer(er, delay);
-#ifdef WITH_EMU
- if(!chk_ctab_ex(er->caid, &cfg.emu_stream_relay_ctab) || !cfg.emu_stream_relay_enabled)
+#ifdef MODULE_STREAMRELAY
+ bool set_dvbapi_cw = true;
+ if(chk_ctab_ex(er->caid, &cfg.stream_relay_ctab) && cfg.stream_relay_enabled)
+ {
+ // streamserver set cw
+ set_dvbapi_cw = !stream_write_cw(er);
+ }
+ if (set_dvbapi_cw)
#endif
switch(selected_api)
{
@@ -7920,6 +7968,14 @@ void dvbapi_send_dcw(struct s_client *client, ECM_REQUEST *er)
{
dvbapi_write_cw(i, j, 0, er->cw_ex.session_word, 16, er->cw_ex.data, 16, er->cw_ex.algo, er->cw_ex.algo_mode, er->msgid);
}
+ else if(er->cw_ex.algo == CW_ALGO_CSA)
+ {
+ if(select_csa_alt(er))
+ {
+ er->cw_ex.algo = CW_ALGO_CSA_ALT;
+ }
+ dvbapi_write_cw(i, j, 0, er->cw, 8, NULL, 0, er->cw_ex.algo, er->cw_ex.algo_mode, er->msgid);
+ }
else
{
dvbapi_write_cw(i, j, 0, er->cw, 8, NULL, 0, er->cw_ex.algo, er->cw_ex.algo_mode, er->msgid);
diff --git a/module-emulator-osemu.c b/module-emulator-osemu.c
index e063be06a..786bee270 100644
--- a/module-emulator-osemu.c
+++ b/module-emulator-osemu.c
@@ -5,8 +5,8 @@
#ifdef WITH_EMU
#include "oscam-string.h"
+#include "module-streamrelay.h"
#include "module-emulator-osemu.h"
-#include "module-emulator-streamserver.h"
#include "module-emulator-biss.h"
#include "module-emulator-cryptoworks.h"
#include "module-emulator-director.h"
@@ -929,7 +929,14 @@ int8_t emu_process_ecm(struct s_reader *rdr, const ECM_REQUEST *er, uint8_t *cw,
if (caid_is_viaccess(er->caid)) result = viaccess_ecm(ecmCopy, cw);
else if (caid_is_irdeto(er->caid)) result = irdeto2_ecm(er->caid, ecmCopy, cw);
else if (caid_is_cryptoworks(er->caid)) result = cryptoworks_ecm(er->caid, ecmCopy, cw);
- else if (caid_is_powervu(er->caid)) result = powervu_ecm(ecmCopy, cw, cw_ex, er->srvid, er->caid, er->tsid, er->onid, er->ens, NULL);
+ else if (caid_is_powervu(er->caid))
+ {
+#ifdef MODULE_STREAMRELAY
+ result = powervu_ecm(ecmCopy, cw, cw_ex, er->srvid, er->caid, er->tsid, er->onid, er->ens, NULL);
+#else
+ result = powervu_ecm(ecmCopy, cw, cw_ex, er->srvid, er->caid, er->tsid, er->onid, er->ens);
+#endif
+ }
else if (caid_is_director(er->caid)) result = director_ecm(ecmCopy, cw);
else if (caid_is_nagra(er->caid)) result = nagra2_ecm(ecmCopy, cw);
else if (caid_is_biss(er->caid)) result = biss_ecm(rdr, er->ecm, er->caid, er->pid, cw, cw_ex);
diff --git a/module-emulator-powervu.c b/module-emulator-powervu.c
index 53da749f7..478fdf4e0 100644
--- a/module-emulator-powervu.c
+++ b/module-emulator-powervu.c
@@ -5,9 +5,8 @@
#ifdef WITH_EMU
#include "cscrypt/des.h"
-#include "ffdecsa/ffdecsa.h"
+#include "module-streamrelay.h"
#include "module-emulator-osemu.h"
-#include "module-emulator-streamserver.h"
#include "module-emulator-powervu.h"
#include "oscam-string.h"
#include "oscam-time.h"
@@ -649,7 +648,7 @@ static void create_hash(uint8_t *data, int len, uint8_t *hash, int mode)
case 35:
hash_modes_19_to_27_tables_3(dataPadded, hash, table23);
break;
-
+
case 36:
hash_modes_19_to_27_tables_3(dataPadded, hash, table24);
break;
@@ -1866,8 +1865,11 @@ static void calculate_cw(uint8_t seedType, uint8_t *seed, uint8_t csaUsed, uint8
}
}
-int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid, uint16_t caid,
- uint16_t tsid, uint16_t onid, uint32_t ens, emu_stream_client_key_data *cdata)
+#ifdef MODULE_STREAMRELAY
+int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid, uint16_t caid, uint16_t tsid, uint16_t onid, uint32_t ens, emu_stream_client_key_data *cdata)
+#else
+int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid, uint16_t caid, uint16_t tsid, uint16_t onid, uint32_t ens)
+#endif
{
uint32_t i, j, k;
uint32_t ecmCrc32, keyRef0, keyRef1, keyRef2, channel_hash, group_id = 0;
@@ -1884,12 +1886,15 @@ int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid
//char tmpBuffer1[512];
char tmpBuffer2[17];
+#ifdef MODULE_STREAMRELAY
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));
-
+#else
+#define EMU_STREAM_MAX_AUDIO_SUB_TRACKS 4
+#endif
if (ecmLen < 7)
{
return EMU_NOT_SUPPORTED;
@@ -2068,7 +2073,7 @@ int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid
while (!decrypt_ok);
memcpy(seedBase, ecm + i + 6 + 2, 4);
-
+#ifdef MODULE_STREAMRELAY
if (cdata == NULL)
{
SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex);
@@ -2084,7 +2089,9 @@ int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid
}
calculateAll = cdata != NULL || update_global_key || cw_ex != NULL;
-
+#else
+ calculateAll = cw_ex != NULL;
+#endif
if (calculateAll) // Calculate all seeds
{
for (j = 0; j < 8; j++)
@@ -2123,7 +2130,7 @@ int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid
//cs_log_dbg(D_ATR, "csaUsed=%d, cw: %s cdata=%x, cw_ex=%x",
// csaUsed, cs_hexdump(3, cw[0], 8, tmpBuffer1, sizeof(tmpBuffer1)),
// (unsigned int)cdata, (unsigned int)cw_ex);
-
+#ifdef MODULE_STREAMRELAY
if (update_global_key)
{
for (j = 0; j < EMU_STREAM_SERVER_MAX_CONNECTIONS; j++)
@@ -2146,25 +2153,19 @@ int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid
if (cdata != NULL)
{
- for (j = 0; j < 8; j++)
+ for (j = 0; j < EMU_STREAM_MAX_AUDIO_SUB_TRACKS + 2; 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]);
- }
+ dvbcsa_bs_key_set(cw[j], key_data[cdata->connid].key[j][EVEN]); }
else
{
- set_odd_control_word(cdata->pvu_csa_ks[j], cw[j]);
+ dvbcsa_bs_key_set(cw[j], key_data[cdata->connid].key[j][ODD]);
}
- cdata->pvu_csa_used = 1;
+ cdata->csa_used = 1;
}
else
{
@@ -2177,11 +2178,11 @@ int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid
des_set_key(cw[j], cdata->pvu_des_ks[j][1]);
}
- cdata->pvu_csa_used = 0;
+ cdata->csa_used = 0;
}
}
}
-
+#endif
if (cw_ex != NULL)
{
cw_ex->mode = CW_MODE_MULTIPLE_CW;
@@ -2197,7 +2198,7 @@ int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid
cw_ex->algo_mode = CW_ALGO_MODE_ECB;
}
- for (j = 0; j < 4; j++)
+ for (j = 0; j < EMU_STREAM_MAX_AUDIO_SUB_TRACKS; j++)
{
memset(cw_ex->audio[j], 0, 16);
diff --git a/module-emulator-powervu.h b/module-emulator-powervu.h
index 369be5e1b..b50d20887 100644
--- a/module-emulator-powervu.h
+++ b/module-emulator-powervu.h
@@ -21,7 +21,11 @@
#define PVU_CONVCW_UTL_ECM 0x02 // UTiLity
#define PVU_CONVCW_VBI_ECM 0x01 // Vertical Blanking Interval
+#ifdef MODULE_STREAMRELAY
int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid, uint16_t caid, uint16_t tsid, uint16_t onid, uint32_t ens, emu_stream_client_key_data *cdata);
+#else
+int8_t powervu_ecm(uint8_t *ecm, uint8_t *dw, EXTENDED_CW *cw_ex, uint16_t srvid, uint16_t caid, uint16_t tsid, uint16_t onid, uint32_t ens);
+#endif
int8_t powervu_emm(uint8_t *emm, uint32_t *keysAdded);
/*
diff --git a/module-emulator-streamserver.c b/module-emulator-streamserver.c
deleted file mode 100644
index a828a4f49..000000000
--- a/module-emulator-streamserver.c
+++ /dev/null
@@ -1,1812 +0,0 @@
-#define MODULE_LOG_PREFIX "emu"
-
-#include "globals.h"
-
-#ifdef WITH_EMU
-
-#include "cscrypt/des.h"
-#include "ffdecsa/ffdecsa.h"
-#include "module-emulator-osemu.h"
-#include "module-emulator-streamserver.h"
-#include "module-emulator-powervu.h"
-#include "oscam-config.h"
-#include "oscam-net.h"
-#include "oscam-string.h"
-#include "oscam-time.h"
-#include "oscam-chk.h"
-
-#define STREAM_UNDEFINED 0x00
-#define STREAM_VIDEO 0x01
-#define STREAM_AUDIO 0x02
-#define STREAM_SUBTITLE 0x03
-#define STREAM_TELETEXT 0x04
-
-extern int32_t exit_oscam;
-
-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];
-
-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];
-
-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 three packets align, probably safe to assume correct size
- if ((buf[i + 188] == 0x47) & (buf[i + 376] == 0x47))
- {
- (*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)
-{
- int8_t found_start = 0;
- int32_t free_data_length, copySize, i;
- uint16_t section_length, offset = 0;
-
- 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)
-{
- int32_t i;
- uint8_t *data = cdata->pat_data;
- uint16_t srvid, section_length = SCT_LEN(data);
-
- for (i = 8; i + 7 < section_length; i += 4)
- {
- srvid = b2i(2, data + i);
- if (srvid == 0)
- {
- continue;
- }
-
- if (cdata->srvid == srvid)
- {
- cdata->pmt_pid = b2i(2, data + i + 2) & 0x1FFF;
- cs_log_dbg(D_READER, "Stream client %i found pmt pid: 0x%04X (%i)",
- cdata->connid, cdata->pmt_pid, cdata->pmt_pid);
- break;
- }
- }
-}
-
-static int8_t stream_client_get_caid(emu_stream_client_data *cdata)
-{
- uint32_t tmp1 = (cdata->srvid << 16) | cdata->pmt_pid;
- uint8_t tmp2[2];
-
- if (emu_find_key('A', tmp1, 0, "FAKE", tmp2, 2, 0, 0, 0, NULL))
- {
- cdata->caid = b2i(2, tmp2);
- return 1;
- }
- return 0;
-}
-
-static void ParseDescriptors(uint8_t *buffer, uint16_t info_length, uint8_t *type)
-{
- uint8_t descriptor_tag = buffer[0], descriptor_length = 0;
- uint32_t j, k;
-
- if (info_length < 1)
- {
- return;
- }
-
- for (j = 0; j + 1 < info_length; j += descriptor_length + 2)
- {
- descriptor_tag = buffer[j];
- descriptor_length = buffer[j + 1];
-
- switch (descriptor_tag)
- {
- case 0x05: // Registration descriptor
- {
- // "HDMV" format identifier is removed
- // OSCam does not need to know about Blu-ray
- const char format_identifiers_audio[10][5] =
- {
- "AC-3", "BSSD", "dmat", "DRA1", "DTS1",
- "DTS2", "DTS3", "EAC3", "mlpa", "Opus",
- };
-
- for (k = 0; k < 10; k++)
- {
- if (memcmp(buffer + j + 2, format_identifiers_audio[k], 4) == 0)
- {
- *type = STREAM_AUDIO;
- break;
- }
- }
- break;
- }
-
- //case 0x09: // CA descriptor
- //{
- // break;
- //}
-
- case 0x46: // VBI teletext descriptor (DVB)
- case 0x56: // teletext descriptor (DVB)
- {
- *type = STREAM_TELETEXT;
- break;
- }
-
- case 0x59: // subtitling descriptor (DVB)
- {
- *type = STREAM_SUBTITLE;
- break;
- }
-
- case 0x6A: // AC-3 descriptor (DVB)
- case 0x7A: // enhanced AC-3 descriptor (DVB)
- case 0x7B: // DTS descriptor (DVB)
- case 0x7C: // AAC descriptor (DVB)
- case 0x81: // AC-3 descriptor (ATSC)
- case 0xCC: // Enhanced AC-3 descriptor (ATSC)
- {
- *type = STREAM_AUDIO;
- break;
- }
-
- case 0x7F: // extension descriptor (DVB)
- {
- uint8_t extension_descriptor_tag = buffer[j + 2];
-
- switch (extension_descriptor_tag)
- {
- case 0x0E: // DTS-HD descriptor (DVB)
- case 0x0F: // DTS Neural descriptor (DVB)
- case 0x15: // AC-4 descriptor (DVB)
- *type = STREAM_AUDIO;
- break;
-
- case 0x20: // TTML subtitling descriptor (DVB)
- *type = STREAM_SUBTITLE;
- break;
-
- default:
- *type = STREAM_UNDEFINED;
- break;
- }
- break;
- }
-
- default:
- break;
- }
- }
-}
-
-static void ParsePmtData(emu_stream_client_data *cdata)
-{
- int32_t i;
- uint8_t *data = cdata->pmt_data;
- uint8_t descriptor_tag = 0, descriptor_length = 0, stream_type;
- uint16_t program_info_length = 0, es_info_length = 0, elementary_pid, caid;
- uint16_t section_length = SCT_LEN(data);
-
- cdata->pcr_pid = b2i(2, data + 8) & 0x1FFF;
- if (cdata->pcr_pid != 0x1FFF)
- {
- cs_log_dbg(D_READER, "Stream client %i found pcr pid: 0x%04X (%i)",
- cdata->connid, cdata->pcr_pid, cdata->pcr_pid);
- }
-
- program_info_length = b2i(2, data + 10) & 0xFFF;
-
- if (12 + program_info_length >= section_length)
- {
- return;
- }
-
- // parse program descriptors (we are looking only for CA descriptor here)
- 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_is_powervu(caid) || caid == 0xA101) // add all supported caids here
- {
- if (cdata->caid == NO_CAID_VALUE)
- {
- cdata->caid = caid;
- }
- cdata->ecm_pid = b2i(2, data + i + 4) & 0x1FFF;
- cs_log_dbg(D_READER, "Stream client %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];
- elementary_pid = b2i(2, data + i + 1) & 0x1FFF;
- es_info_length = b2i(2, data + i + 3) & 0xFFF;
-
- switch (stream_type)
- {
- case 0x01:
- case 0x02:
- case 0x10:
- case 0x1B:
- case 0x20:
- case 0x24:
- case 0x25:
- case 0x42:
- case 0xD1:
- case 0xEA:
- {
- cdata->video_pid = elementary_pid;
- cs_log_dbg(D_READER, "Stream client %i found video pid: 0x%04X (%i)",
- cdata->connid, elementary_pid, elementary_pid);
- break;
- }
-
- case 0x03:
- case 0x04:
- case 0x0F:
- case 0x11:
- case 0x1C:
- case 0x2D:
- case 0x2E:
- case 0x81:
- {
- if (cdata->audio_pid_count >= EMU_STREAM_MAX_AUDIO_SUB_TRACKS)
- {
- continue;
- }
-
- cdata->audio_pids[cdata->audio_pid_count] = elementary_pid;
- cdata->audio_pid_count++;
- cs_log_dbg(D_READER, "Stream client %i found audio pid: 0x%04X (%i)",
- cdata->connid, elementary_pid, elementary_pid);
- break;
- }
-
- case 0x06:
- //case 0x81: // some ATSC AC-3 streams do not contain the AC-3 descriptor!
- case 0x87:
- {
- uint8_t type = STREAM_UNDEFINED;
- ParseDescriptors(data + i + 5, es_info_length, &type);
-
- if (type == STREAM_AUDIO)
- {
- if (cdata->audio_pid_count >= EMU_STREAM_MAX_AUDIO_SUB_TRACKS)
- {
- continue;
- }
-
- cdata->audio_pids[cdata->audio_pid_count] = elementary_pid;
- cdata->audio_pid_count++;
- cs_log_dbg(D_READER, "Stream client %i found audio pid: 0x%04X (%i)",
- cdata->connid, elementary_pid, elementary_pid);
- }
- else if (type == STREAM_TELETEXT)
- {
- cdata->teletext_pid = elementary_pid;
- cs_log_dbg(D_READER, "Stream client %i found teletext pid: 0x%04X (%i)",
- cdata->connid, elementary_pid, elementary_pid);
- }
- break;
- }
- }
- }
-
- // If we haven't found a CAID for this service,
- // search the keyDB for a fake one
- if (cdata->caid == NO_CAID_VALUE && stream_client_get_caid(cdata) == 1)
- {
- cs_log_dbg(D_READER, "Stream client %i found fake caid: 0x%04X (%i)",
- cdata->connid, cdata->caid, cdata->caid);
- }
-}
-
-static void ParseCatData(emu_stream_client_data *cdata)
-{
- uint8_t *data = cdata->cat_data;
- uint32_t i;
-
- for (i = 8; i < (b2i(2, data + 1) & 0xFFF) - 1; i += data[i + 1] + 2)
- {
- if (data[i] != 0x09)
- {
- continue;
- }
-
- uint16_t caid = b2i(2, data + i + 2);
-
- if (caid_is_powervu(caid)) // add all supported caids here
- {
- if (cdata->caid == NO_CAID_VALUE)
- {
- cdata->caid = caid;
- }
- cdata->emm_pid = b2i(2, data + i + 4) & 0x1FFF;;
- cs_log_dbg(D_READER, "Stream client %i found emm pid: 0x%04X (%i)",
- cdata->connid, cdata->emm_pid, cdata->emm_pid);
- break;
- }
- }
-}
-
-static void ParseEmmData(emu_stream_client_data *cdata)
-{
- uint32_t keysAdded = 0;
-
- emu_process_emm(NULL, cdata->caid, cdata->emm_data, &keysAdded);
-
- if (keysAdded)
- {
- //refresh_entitlements(rdr);
- cs_log("Stream client %i found %i keys", cdata->connid, keysAdded);
- }
-}
-
-static void ParseEcmData(emu_stream_client_data *cdata)
-{
- uint8_t *data = cdata->ecm_data;
- uint8_t dcw[16];
- uint16_t section_length = SCT_LEN(data);
-
- if (section_length < 11)
- {
- return;
- }
-
- if (caid_is_powervu(cdata->caid))
- {
- if (data[11] > cdata->ecm_nb || (cdata->ecm_nb == 255 && data[11] == 0) || ((cdata->ecm_nb - data[11]) > 5))
- {
- cdata->ecm_nb = data[11];
- powervu_ecm(data, dcw, NULL, cdata->srvid, cdata->caid, cdata->tsid, cdata->onid, cdata->ens, &cdata->key);
- }
- }
- //else if () // All other caids
- //{
- //emu_process_ecm();
- //}
-}
-
-static void ParseTsPackets(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
-{
- uint8_t payloadStart;
- uint16_t pid, offset;
- uint32_t i, tsHeader;
-
- for (i = 0; i < bufLength; i += packetSize)
- {
- tsHeader = b2i(4, stream_buf + i);
- pid = (tsHeader & 0x1FFF00) >> 8;
- payloadStart = (tsHeader & 0x400000) >> 22;
-
- if (tsHeader & 0x20)
- {
- offset = 4 + stream_buf[i + 4] + 1;
- }
- else
- {
- offset = 4;
- }
-
- if (packetSize - offset < 1)
- {
- continue;
- }
-
- if (pid == 0x0000 && data->have_pat_data != 1) // Search the PAT for the PMT pid
- {
- ParseTsData(0x00, 0xFF, 16, &data->have_pat_data, data->pat_data, sizeof(data->pat_data),
- &data->pat_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParsePatData, data);
- continue;
- }
-
- if (pid == data->pmt_pid && data->have_pmt_data != 1) // Search the PMT for PCR, ECM, Video and Audio pids
- {
- ParseTsData(0x02, 0xFF, 21, &data->have_pmt_data, data->pmt_data, sizeof(data->pmt_data),
- &data->pmt_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParsePmtData, data);
- continue;
- }
-
- // We have bot PAT and PMT data - No need to search the rest of the packets
- if (data->have_pat_data == 1 && data->have_pmt_data == 1)
- {
- break;
- }
- }
-}
-
-static void DescrambleTsPacketsPowervu(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
-{
- int8_t oddKeyUsed;
-
- uint8_t scramblingControl, payloadStart, oddeven;
- uint8_t *pdata, *packetClusterV[256];
- uint8_t *packetClusterA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS][64]; // separate cluster arrays for video and each audio track
- uint16_t pid, offset;
- uint32_t i, j, k, tsHeader;
- uint32_t scrambled_packets = 0, scrambled_packetsA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS] = { 0 };
- uint32_t *deskey;
- 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
-
- void *csakeyA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS] = { 0 };
- void *csakeyV = 0;
- emu_stream_client_key_data *keydata;
-
- packetClusterV[0] = NULL;
-
- 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 (emu_stream_emm_enabled && pid == 0x0001 && data->have_cat_data != 1) // Search the CAT for EMM pids
- {
- // set to null pid
- stream_buf[i + 1] |= 0x1F;
- stream_buf[i + 2] = 0xFF;
-
- ParseTsData(0x01, 0xFF, 8, &data->have_cat_data, data->cat_data, sizeof(data->cat_data),
- &data->cat_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParseCatData, data);
- continue;
- }
-
- if (emu_stream_emm_enabled && data->emm_pid && pid == data->emm_pid) // Process the EMM data
- {
- // set to null pid
- stream_buf[i + 1] |= 0x1F;
- stream_buf[i + 2] = 0xFF;
-
- ParseTsData(0x80, 0xF0, 3, &data->have_emm_data, data->emm_data, sizeof(data->emm_data),
- &data->emm_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParseEmmData, data);
- continue;
- }
-
- if (data->ecm_pid && pid == data->ecm_pid) // Process the ECM data
- {
- stream_server_has_ecm[data->connid] = 1;
-
- // set to null pid
- stream_buf[i + 1] |= 0x1F;
- stream_buf[i + 2] = 0xFF;
-
- ParseTsData(0x80, 0xFE, 3, &data->have_ecm_data, data->ecm_data, sizeof(data->ecm_data),
- &data->ecm_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParseEcmData, data);
- continue;
- }
-
- if (scramblingControl == 0)
- {
- continue;
- }
-
- if (!(stream_buf[i + 3] & 0x10))
- {
- stream_buf[i + 3] &= 0x3F;
- continue;
- }
-
- oddKeyUsed = scramblingControl == 0xC0 ? 1 : 0;
-
- 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
- {
- keydata = &data->key;
- }
-
- 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;
-
- // Now iterate through the rest of the packets and create clusters for batch decryption
- for (j = i + packetSize; j < bufLength; j += packetSize)
- {
- 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;
- }
-
- // Check for audio tracks and create single packet clusters
- for (k = 0; k < data->audio_pid_count; k++)
- {
- 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
- {
- // last packet was a video packet, so set end of cluster to end of last packet
- if (scrambled_packets > 1)
- {
- 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 audio track has scrambled packets, set null to mark end and decrypt
- if (scrambled_packetsA[k])
- {
- csakeyA[k] = keydata->pvu_csa_ks[PVU_CW_A1 + k];
- packetClusterA[k][csa[k]] = NULL;
- decrypt_packets(csakeyA[k], packetClusterA[k]);
- csa[k] = 0;
- scrambled_packetsA[k] = 0;
- }
- }
- }
- }
- else
- {
- for (j = 0; j < data->audio_pid_count; j++)
- {
- if (pid == data->audio_pids[j])
- {
- csakeyA[0] = keydata->pvu_csa_ks[PVU_CW_A1 + j];
- }
- }
-
- if (csakeyA[0] != NULL)
- {
- packetClusterA[0][0] = stream_buf + i;
- packetClusterA[0][1] = stream_buf + i + packetSize - 1;
- packetClusterA[0][2] = NULL;
- decrypt_packets(csakeyA[0], packetClusterA[0]);
- }
- }
- }
- else
- {
- deskey = NULL;
-
- if (pid == data->video_pid)
- {
- deskey = keydata->pvu_des_ks[PVU_CW_VID][oddKeyUsed];
- }
- else
- {
- for (j = 0; j < data->audio_pid_count; j++)
- {
- if (pid == data->audio_pids[j])
- {
- deskey = keydata->pvu_des_ks[PVU_CW_A1 + j][oddKeyUsed];
- }
- }
- }
-
- if (deskey == NULL)
- {
- deskey = keydata->pvu_des_ks[PVU_CW_HSD][oddKeyUsed];
- }
-
- for (j = offset; j + 7 < 188; j += 8)
- {
- pdata = stream_buf + i + j;
- des(pdata, deskey, 0);
- }
-
- stream_buf[i + 3] &= 0x3F;
- }
-
- if (!stream_server_has_ecm[data->connid])
- {
- SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[data->connid]);
- }
- }
-}
-
-static void DescrambleTsPacketsRosscrypt1(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
-{
- int8_t is_av_pid;
- int32_t j;
-
- uint8_t scramblingControl;
- uint16_t pid, offset;
- uint32_t i, tsHeader;
-
- for (i = 0; i < bufLength; i += packetSize)
- {
- tsHeader = b2i(4, stream_buf + i);
- pid = (tsHeader & 0x1FFF00) >> 8;
- scramblingControl = tsHeader & 0xC0;
-
- if (tsHeader & 0x20)
- {
- offset = 4 + stream_buf[i + 4] + 1;
- }
- else
- {
- offset = 4;
- }
-
- if (packetSize - offset < 1)
- {
- continue;
- }
-
- if (scramblingControl == 0)
- {
- continue;
- }
-
- if (!(stream_buf[i + 3] & 0x10))
- {
- stream_buf[i + 3] &= 0x3F;
- continue;
- }
-
- is_av_pid = 0;
-
- if (pid == data->video_pid)
- {
- is_av_pid = 1;
- }
- else
- {
- for (j = 0; j < data->audio_pid_count; j++)
- {
- if (pid == data->audio_pids[j])
- {
- is_av_pid = 1;
- break;
- }
- }
- }
-
- if (is_av_pid)
- {
- static uint8_t dyn_key[184];
- static uint8_t last_packet[184];
-
- // Reset key on channel change
- if (data->reset_key_data == 1)
- {
- memset(dyn_key, 0x00, 184);
- memset(last_packet, 0x00, 184);
- data->reset_key_data = 0;
- }
-
- if (memcmp(last_packet, stream_buf + i + 4, 184) == 0)
- {
- if (memcmp(dyn_key, stream_buf + i + 4, 184) != 0)
- {
- memcpy(dyn_key, stream_buf + i + 4, 184);
- }
- }
- else
- {
- memcpy(last_packet, stream_buf + i + 4, 184);
- }
-
- for (j = 0; j < 184; j++)
- {
- stream_buf[i + 4 + j] ^= dyn_key[j];
- }
-
- stream_buf[i + 3] &= 0x3F;
- }
- }
-}
-
-static void DescrambleTsPacketsCompel(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
-{
- int8_t is_pes_pid; // any PES pid
- int32_t j;
- const int8_t limit = 4;
-
- uint8_t scramblingControl;
- uint16_t pid, offset;
- uint32_t i, tsHeader;
-
- for (i = 0; i < bufLength; i += packetSize)
- {
- tsHeader = b2i(4, stream_buf + i);
- pid = (tsHeader & 0x1FFF00) >> 8;
- scramblingControl = tsHeader & 0xC0;
-
- if (tsHeader & 0x20)
- {
- offset = 4 + stream_buf[i + 4] + 1;
- }
- else
- {
- offset = 4;
- }
-
- if (packetSize - offset < 1)
- {
- continue;
- }
-
- if (scramblingControl == 0)
- {
- continue;
- }
-
- if (!(stream_buf[i + 3] & 0x10))
- {
- stream_buf[i + 3] &= 0x3F;
- continue;
- }
-
- is_pes_pid = 0;
-
- if (pid == data->video_pid)
- {
- is_pes_pid = 1;
- }
- else if (pid == data->teletext_pid)
- {
- is_pes_pid = 1;
- }
- else
- {
- for (j = 0; j < data->audio_pid_count; j++)
- {
- if (pid == data->audio_pids[j])
- {
- is_pes_pid = 1;
- break;
- }
- }
- }
-
- if (is_pes_pid)
- {
- static uint8_t dyn_key[184];
- static uint8_t found_key_bytes[184];
- static uint8_t found_key_bytes_count = 8;
- static uint8_t lastScramblingControl = 0xFF;
-
- int8_t matches00 = 0;
- int8_t matchesFF = 0;
- int8_t last00_was_good = 0;
- int8_t lastFF_was_good = 0;
-
- // Reset key when scrambling control changes from odd to even
- // and vice versa (every ~53 seconds) or when we change channel
- if (lastScramblingControl != scramblingControl)
- {
- memset(dyn_key, 0x00, 184);
- memset(found_key_bytes, 0, 184);
- found_key_bytes_count = 8;
- lastScramblingControl = scramblingControl;
-
- //cs_log_dbg(D_READER, "resetting key data (scrambling control: %02X)", scramblingControl);
- }
-
- for (j = 8; j < 184; j++)
- {
- if (found_key_bytes_count == 184)
- {
- break;
- }
-
- if (stream_buf[i + 4 + j] == 0x00)
- {
- last00_was_good = 1;
- matches00++;
-
- if (matches00 > limit && found_key_bytes[j] == 0)
- {
- dyn_key[j] = 0x00;
- found_key_bytes[j] = 1;
- found_key_bytes_count++;
- }
- }
- else if (stream_buf[i + 4 + j] == 0x3F)
- {
- last00_was_good = 1;
- matches00++;
-
- if (matches00 > limit && found_key_bytes[j] == 0)
- {
- dyn_key[j] = 0x3F;
- found_key_bytes[j] = 1;
- found_key_bytes_count++;
- }
- }
- else
- {
- if (last00_was_good == 1)
- {
- last00_was_good = 0;
- matches00--;
- }
- else
- {
- matches00 -= 2;
- }
-
- if (matches00 < 0)
- {
- matches00 = 0;
- }
- }
-
- if (stream_buf[i + 4 + j] == 0xC0)
- {
- lastFF_was_good = 1;
- matchesFF++;
-
- if (matchesFF > limit && found_key_bytes[j] == 0)
- {
- dyn_key[j] = 0x3F;
- found_key_bytes[j] = 1;
- found_key_bytes_count++;
- }
- }
- else if (stream_buf[i + 4 + j] == 0xFF)
- {
- lastFF_was_good = 1;
- matchesFF++;
-
- if (matchesFF > limit && found_key_bytes[j] == 0)
- {
- dyn_key[j] = 0x00;
- found_key_bytes[j] = 1;
- found_key_bytes_count++;
- }
- }
- else
- {
- if (lastFF_was_good == 1)
- {
- lastFF_was_good = 0;
- matchesFF--;
- }
- else
- {
- matchesFF -= 2;
- }
-
- if (matchesFF < 0)
- {
- matchesFF = 0;
- }
- }
- }
-
- for (j = 183; j >= 8; j--)
- {
- if (found_key_bytes_count == 184)
- {
- break;
- }
-
- if (stream_buf[i + 4 + j] == 0x00)
- {
- last00_was_good = 1;
- matches00++;
-
- if (matches00 > limit && found_key_bytes[j] == 0)
- {
- dyn_key[j] = 0x00;
- found_key_bytes[j] = 1;
- found_key_bytes_count++;
- }
- }
- else if (stream_buf[i + 4 + j] == 0x3F)
- {
- last00_was_good = 1;
- matches00++;
-
- if (matches00 > limit && found_key_bytes[j] == 0)
- {
- dyn_key[j] = 0x3F;
- found_key_bytes[j] = 1;
- found_key_bytes_count++;
- }
- }
- else
- {
- if (last00_was_good == 1)
- {
- last00_was_good = 0;
- matches00--;
- }
- else
- {
- matches00 -= 2;
- }
-
- if (matches00 < 0)
- {
- matches00 = 0;
- }
- }
-
- if (stream_buf[i + 4 + j] == 0xC0)
- {
- lastFF_was_good = 1;
- matchesFF++;
-
- if (matchesFF > limit && found_key_bytes[j] == 0)
- {
- dyn_key[j] = 0x3F;
- found_key_bytes[j] = 1;
- found_key_bytes_count++;
- }
- }
- else if (stream_buf[i + 4 + j] == 0xFF)
- {
- lastFF_was_good = 1;
- matchesFF++;
-
- if (matchesFF > limit && found_key_bytes[j] == 0)
- {
- dyn_key[j] = 0x00;
- found_key_bytes[j] = 1;
- found_key_bytes_count++;
- }
- }
- else
- {
- if (lastFF_was_good == 1)
- {
- lastFF_was_good = 0;
- matchesFF--;
- }
- else
- {
- matchesFF -= 2;
- }
-
- if (matchesFF < 0)
- {
- matchesFF = 0;
- }
- }
- }
-
- for (j = 8; j < 184; j++)
- {
- stream_buf[i + 4 + j] ^= dyn_key[j];
- }
- }
-
- stream_buf[i + 3] &= 0x3F; // Clear scrambling bits
- }
-}
-
-static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *stream_path)
-{
- struct sockaddr_in cservaddr;
- IN_ADDR_T in_addr;
-
- int32_t streamfd = socket(AF_INET, SOCK_STREAM, 0);
- if (streamfd == -1)
- {
- return -1;
- }
-
- struct timeval tv;
- tv.tv_sec = 2;
- tv.tv_usec = 0;
- if (setsockopt(streamfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv))
- {
- cs_log("ERROR: setsockopt() failed for SO_RCVTIMEO");
- return -1;
- }
-
- bzero(&cservaddr, sizeof(cservaddr));
- cservaddr.sin_family = AF_INET;
- cs_resolve(emu_stream_source_host, &in_addr, NULL, NULL);
- SIN_GET_ADDR(cservaddr) = in_addr;
- cservaddr.sin_port = htons(emu_stream_source_port);
-
- if (connect(streamfd, (struct sockaddr *)&cservaddr, sizeof(cservaddr)) == -1)
- {
- return -1;
- }
-
- if (emu_stream_source_auth)
- {
- snprintf(http_buf, http_buf_len, "GET %s HTTP/1.1\nHost: %s:%u\n"
- "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0\n"
- "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n"
- "Accept-Language: en-US\n"
- "Authorization: Basic %s\n"
- "Connection: keep-alive\n\n", stream_path, emu_stream_source_host, emu_stream_source_port, emu_stream_source_auth);
- }
- else
- {
- snprintf(http_buf, http_buf_len, "GET %s HTTP/1.1\nHost: %s:%u\n"
- "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0\n"
- "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n"
- "Accept-Language: en-US\n"
- "Connection: keep-alive\n\n", stream_path, emu_stream_source_host, emu_stream_source_port);
- }
-
- if (send(streamfd, http_buf, cs_strlen(http_buf), 0) == -1)
- {
- return -1;
- }
-
- return streamfd;
-}
-
-static void stream_client_disconnect(emu_stream_client_conn_data *conndata)
-{
- int32_t i;
-
- 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);
-
- SAFE_MUTEX_LOCK(&emu_stream_server_mutex);
- for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
- {
- if (gconnfd[i] == conndata->connfd)
- {
- gconnfd[i] = -1;
- gconncount--;
- }
- }
- SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex);
-
- shutdown(conndata->connfd, 2);
- close(conndata->connfd);
-
- cs_log("Stream client %i disconnected",conndata->connid);
-
- NULLFREE(conndata);
-}
-
-static void *stream_client_handler(void *arg)
-{
- emu_stream_client_conn_data *conndata = (emu_stream_client_conn_data *)arg;
- emu_stream_client_data *data;
-
- char *http_buf, stream_path[255], stream_path_copy[255];
- char *saveptr, *token, http_version[4];
-
- int8_t streamConnectErrorCount = 0, streamDataErrorCount = 0;
- int32_t bytesRead = 0, http_status_code = 0;
- int32_t clientStatus, streamStatus, streamfd;
- int32_t cur_dvb_buffer_size, cur_dvb_buffer_wait, i;
-
- uint8_t *stream_buf;
- uint16_t packetCount = 0, packetSize = 0, startOffset = 0;
- uint32_t remainingDataPos, remainingDataLength, tmp_pids[4];
-
- cs_log("Stream client %i connected", conndata->connid);
-
- if (!cs_malloc(&http_buf, 1024))
- {
- stream_client_disconnect(conndata);
- return NULL;
- }
-
- if (!cs_malloc(&stream_buf, EMU_DVB_BUFFER_SIZE))
- {
- NULLFREE(http_buf);
- stream_client_disconnect(conndata);
- return NULL;
- }
-
- if (!cs_malloc(&data, sizeof(emu_stream_client_data)))
- {
- NULLFREE(http_buf);
- NULLFREE(stream_buf);
- stream_client_disconnect(conndata);
- return NULL;
- }
-
- clientStatus = recv(conndata->connfd, http_buf, 1024, 0);
- if (clientStatus < 1)
- {
- NULLFREE(http_buf);
- NULLFREE(stream_buf);
- NULLFREE(data);
- stream_client_disconnect(conndata);
- return NULL;
- }
-
- http_buf[1023] = '\0';
- if (sscanf(http_buf, "GET %254s ", stream_path) < 1)
- {
- NULLFREE(http_buf);
- NULLFREE(stream_buf);
- NULLFREE(data);
- stream_client_disconnect(conndata);
- return NULL;
- }
-
- cs_strncpy(stream_path_copy, stream_path, sizeof(stream_path));
-
- token = strtok_r(stream_path_copy, ":", &saveptr); // token 0
- for (i = 1; token != NULL && i < 7; i++) // tokens 1 to 6
- {
- token = strtok_r(NULL, ":", &saveptr);
- if (token == NULL)
- {
- break;
- }
-
- if (i >= 3) // We olny need token 3 (srvid), 4 (tsid), 5 (onid) and 6 (ens)
- {
- if (sscanf(token, "%x", &tmp_pids[i - 3]) != 1)
- {
- tmp_pids[i - 3] = 0;
- }
- }
- }
-
- data->srvid = tmp_pids[0] & 0xFFFF;
- data->tsid = tmp_pids[1] & 0xFFFF;
- data->onid = tmp_pids[2] & 0xFFFF;
- data->ens = tmp_pids[3];
-
- if (data->srvid == 0) // We didn't get a srvid - Exit
- {
- NULLFREE(http_buf);
- NULLFREE(stream_buf);
- NULLFREE(data);
- stream_client_disconnect(conndata);
- return NULL;
- }
-
- 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);
-
- cs_log("Stream client %i request %s", conndata->connid, stream_path);
-
- cs_log_dbg(D_READER, "Stream client %i received srvid: %04X tsid: %04X onid: %04X ens: %08X",
- conndata->connid, data->srvid, data->tsid, data->onid, data->ens);
-
- 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, cs_strlen(http_buf), 0);
-
- data->connid = conndata->connid;
- data->caid = NO_CAID_VALUE;
- data->have_pat_data = 0;
- data->have_pmt_data = 0;
- data->have_cat_data = 0;
- data->have_ecm_data = 0;
- data->have_emm_data = 0;
- data->reset_key_data = 1;
-
- while (!exit_oscam && clientStatus != -1 && streamConnectErrorCount < 3
- && streamDataErrorCount < 15)
- {
- streamfd = connect_to_stream(http_buf, 1024, stream_path);
- if (streamfd == -1)
- {
- cs_log("WARNING: stream client %i cannot connect to stream source", conndata->connid);
- streamConnectErrorCount++;
- cs_sleepms(500);
- continue;
- }
-
- streamStatus = 0;
- bytesRead = 0;
-
- while (!exit_oscam && clientStatus != -1 && streamStatus != -1
- && streamConnectErrorCount < 3 && streamDataErrorCount < 15)
- {
- if (data->key.pvu_csa_used)
- {
- cur_dvb_buffer_size = EMU_DVB_BUFFER_SIZE_CSA;
- cur_dvb_buffer_wait = EMU_DVB_BUFFER_WAIT_CSA;
- }
- else
- {
- cur_dvb_buffer_size = EMU_DVB_BUFFER_SIZE_DES;
- cur_dvb_buffer_wait = EMU_DVB_BUFFER_WAIT_DES;
- }
-
- streamStatus = recv(streamfd, stream_buf + bytesRead, cur_dvb_buffer_size - bytesRead, MSG_WAITALL);
- if (streamStatus == 0) // socket closed
- {
- cs_log("WARNING: stream client %i - stream source closed connection", conndata->connid);
- streamConnectErrorCount++;
- cs_sleepms(100);
- break;
- }
-
- if (streamStatus < 0) // error
- {
- if ((errno == EWOULDBLOCK) | (errno == EAGAIN))
- {
- cs_log("WARNING: stream client %i no data from stream source", conndata->connid);
- streamDataErrorCount++; // 2 sec timeout * 15 = 30 seconds no data -> close
- cs_sleepms(100);
- continue;
- }
-
- cs_log("WARNING: stream client %i error receiving data from stream source", conndata->connid);
- streamConnectErrorCount++;
- cs_sleepms(100);
- break;
- }
-
- if (streamStatus < cur_dvb_buffer_size - bytesRead) // probably just received header but no stream
- {
- if (!bytesRead && streamStatus > 13 &&
- sscanf((const char*)stream_buf, "HTTP/%3s %d ", http_version , &http_status_code) == 2 &&
- http_status_code != 200)
- {
- cs_log("ERROR: stream client %i got %d response from stream source", conndata->connid, http_status_code);
- streamConnectErrorCount++;
- cs_sleepms(100);
- break;
- }
- else
- {
- cs_log_dbg(0, "WARNING: stream client %i non-full buffer from stream source", conndata->connid);
- streamDataErrorCount++;
- cs_sleepms(100);
- }
- }
- else
- {
- streamDataErrorCount = 0;
- }
-
- streamConnectErrorCount = 0;
- bytesRead += streamStatus;
-
- if (bytesRead >= cur_dvb_buffer_wait)
- {
- startOffset = 0;
-
- // only search if not starting on ts packet or unknown packet size
- if (stream_buf[0] != 0x47 || packetSize == 0)
- {
- SearchTsPackets(stream_buf, bytesRead, &packetSize, &startOffset);
- }
-
- if (packetSize == 0)
- {
- bytesRead = 0;
- }
- else
- {
- packetCount = ((bytesRead - startOffset) / packetSize);
-
- // We have both PAT and PMT data - We can start descrambling
- if (data->have_pat_data == 1 && data->have_pmt_data == 1)
- {
- if (chk_ctab_ex(data->caid, &cfg.emu_stream_relay_ctab))
- {
- if (caid_is_powervu(data->caid))
- {
- DescrambleTsPacketsPowervu(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
- }
- else if (data->caid == 0xA101) // Rosscrypt1
- {
- DescrambleTsPacketsRosscrypt1(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
- }
- else if (data->caid == NO_CAID_VALUE) // Compel
- {
- DescrambleTsPacketsCompel(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
- }
- }
- else
- {
- cs_log_dbg(D_READER, "Stream client %i caid %04X not enabled in stream relay config",
- conndata->connid, data->caid);
- }
- }
- else // Search PAT and PMT packets for service information
- {
- ParseTsPackets(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
- }
-
- clientStatus = send(conndata->connfd, stream_buf + startOffset, packetCount * packetSize, 0);
-
- remainingDataPos = startOffset + (packetCount * packetSize);
- remainingDataLength = bytesRead - remainingDataPos;
-
- if (remainingDataPos < remainingDataLength)
- {
- memmove(stream_buf, stream_buf + remainingDataPos, remainingDataLength);
- }
- else
- {
- memcpy(stream_buf, stream_buf + remainingDataPos, remainingDataLength);
- }
-
- bytesRead = remainingDataLength;
- }
- }
- }
-
- close(streamfd);
- }
-
- NULLFREE(http_buf);
- NULLFREE(stream_buf);
-
- for (i = 0; i < 8; i++)
- {
- if (data->key.pvu_csa_ks[i])
- {
- free_key_struct(data->key.pvu_csa_ks[i]);
- }
- }
- NULLFREE(data);
-
- stream_client_disconnect(conndata);
- return NULL;
-}
-
-void *stream_server(void *UNUSED(a))
-{
- struct sockaddr_in servaddr, cliaddr;
- socklen_t clilen;
- int32_t connfd, reuse = 1, i;
- int8_t connaccepted;
- emu_stream_client_conn_data *conndata;
-
- cluster_size = get_internal_parallelism();
- cs_log("INFO: FFDecsa parallel mode = %d", cluster_size);
-
- if (!emu_stream_server_mutex_init)
- {
- SAFE_MUTEX_INIT(&emu_stream_server_mutex, NULL);
- emu_stream_server_mutex_init = 1;
- }
-
- 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);
-
- for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
- {
- gconnfd[i] = -1;
- }
-
- glistenfd = socket(AF_INET, SOCK_STREAM, 0);
- if (glistenfd == -1)
- {
- cs_log("ERROR: cannot create stream server socket");
- return NULL;
- }
-
- bzero(&servaddr,sizeof(servaddr));
- servaddr.sin_family = AF_INET;
- servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
- servaddr.sin_port = htons(emu_stream_relay_port);
- setsockopt(glistenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
-
- if (bind(glistenfd,(struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
- {
- cs_log("ERROR: cannot bind to stream server socket");
- close(glistenfd);
- return NULL;
- }
-
- if (listen(glistenfd, 3) == -1)
- {
- cs_log("ERROR: cannot listen to stream server socket");
- close(glistenfd);
- return NULL;
- }
-
- while (!exit_oscam)
- {
- clilen = sizeof(cliaddr);
- connfd = accept(glistenfd,(struct sockaddr *)&cliaddr, &clilen);
-
- if (connfd == -1)
- {
- cs_log("ERROR: accept() failed");
- break;
- }
-
- connaccepted = 0;
-
- if (cs_malloc(&conndata, sizeof(emu_stream_client_conn_data)))
- {
- SAFE_MUTEX_LOCK(&emu_stream_server_mutex);
- if (gconncount < EMU_STREAM_SERVER_MAX_CONNECTIONS)
- {
- for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
- {
- if (gconnfd[i] == -1)
- {
- gconnfd[i] = connfd;
- gconncount++;
- connaccepted = 1;
-
- conndata->connfd = connfd;
- conndata->connid = i;
-
- break;
- }
- }
- }
- SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex);
- }
-
- if (connaccepted)
- {
- int on = 1;
- if (setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
- {
- cs_log("ERROR: stream client %i setsockopt() failed for TCP_NODELAY", conndata->connid);
- }
-
- start_thread("emu stream client", stream_client_handler, (void*)conndata, NULL, 1, 0);
- }
- else
- {
- shutdown(connfd, 2);
- close(connfd);
- cs_log("ERROR: stream server client dropped because of too many connections (%i)", EMU_STREAM_SERVER_MAX_CONNECTIONS);
- }
-
- cs_sleepms(20);
- }
-
- close(glistenfd);
-
- return NULL;
-}
-
-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;
-}
-
-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);
-}
-
-#endif // WITH_EMU
diff --git a/module-emulator-streamserver.h b/module-emulator-streamserver.h
deleted file mode 100644
index 2b1c2ac73..000000000
--- a/module-emulator-streamserver.h
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef MODULE_EMULATOR_STREAMSERVER_H_
-#define MODULE_EMULATOR_STREAMSERVER_H_
-
-#ifdef WITH_EMU
-
-#define EMU_STREAM_SERVER_MAX_CONNECTIONS 8
-#define EMU_STREAM_MAX_AUDIO_SUB_TRACKS 16
-
-#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
-
-typedef struct
-{
- uint32_t pvu_des_ks[8][2][32];
- int8_t pvu_csa_used;
- void* pvu_csa_ks[8];
-} emu_stream_client_key_data;
-
-typedef struct
-{
- int32_t connid;
- int8_t have_cat_data;
- int8_t have_pat_data;
- int8_t have_pmt_data;
- int8_t have_ecm_data;
- int8_t have_emm_data;
- int8_t reset_key_data;
- uint8_t cat_data[1024+208];
- uint8_t pat_data[1024+208];
- uint8_t pmt_data[1024+208];
- uint8_t ecm_data[1024+208];
- uint8_t emm_data[1024+208];
- uint16_t cat_data_pos;
- uint16_t pat_data_pos;
- uint16_t pmt_data_pos;
- uint16_t ecm_data_pos;
- uint16_t emm_data_pos;
- uint16_t srvid;
- uint16_t caid;
- uint16_t tsid;
- uint16_t onid;
- uint32_t ens;
- uint16_t pmt_pid;
- uint16_t ecm_pid;
- uint16_t emm_pid;
- uint16_t video_pid;
- uint16_t teletext_pid;
- uint16_t pcr_pid;
- uint16_t audio_pids[EMU_STREAM_MAX_AUDIO_SUB_TRACKS];
- uint8_t audio_pid_count;
- int16_t ecm_nb;
- emu_stream_client_key_data key;
-} emu_stream_client_data;
-
-extern char emu_stream_source_host[256];
-extern int32_t emu_stream_source_port;
-extern char *emu_stream_source_auth;
-extern int32_t emu_stream_relay_port;
-extern int8_t emu_stream_emm_enabled;
-
-extern int8_t stream_server_thread_init;
-
-void *stream_server(void *a);
-void stop_stream_server(void);
-
-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 // WITH_EMU
-
-#endif // MODULE_EMULATOR_STREAMSERVER_H_
diff --git a/module-emulator.c b/module-emulator.c
index bb510747b..6417a9626 100644
--- a/module-emulator.c
+++ b/module-emulator.c
@@ -4,8 +4,8 @@
#ifdef WITH_EMU
+#include "module-streamrelay.h"
#include "module-emulator-osemu.h"
-#include "module-emulator-streamserver.h"
#include "module-emulator-biss.h"
#include "module-emulator-irdeto.h"
#include "module-emulator-powervu.h"
@@ -39,7 +39,9 @@
#define CS_ERROR 0
extern char cs_confdir[128];
+#ifdef MODULE_STREAMRELAY
static int8_t emu_key_data_mutex_init = 0;
+#endif
pthread_mutex_t emu_key_data_mutex;
static void set_hexserial_to_version(struct s_reader *rdr)
@@ -724,11 +726,10 @@ const struct s_cardsystem reader_emu =
static int32_t emu_reader_init(struct s_reader *UNUSED(reader))
{
- int32_t i;
- char authtmp[128];
-
- if (cfg.emu_stream_relay_enabled && (stream_server_thread_init == 0))
+#ifdef MODULE_STREAMRELAY
+ if (cfg.stream_relay_enabled && (stream_server_thread_init == 0))
{
+ int32_t i;
stream_server_thread_init = 1;
SAFE_MUTEX_INIT(&emu_fixed_key_srvid_mutex, NULL);
@@ -741,24 +742,6 @@ static int32_t emu_reader_init(struct s_reader *UNUSED(reader))
start_thread("stream_key_delayer", stream_key_delayer, NULL, NULL, 1, 1);
cs_log("Stream key delayer initialized");
-
- cs_strncpy(emu_stream_source_host, cfg.emu_stream_source_host, sizeof(emu_stream_source_host));
- emu_stream_source_port = cfg.emu_stream_source_port;
- emu_stream_relay_port = cfg.emu_stream_relay_port;
- emu_stream_emm_enabled = cfg.emu_stream_emm_enabled;
-
- if (cfg.emu_stream_source_auth_user && cfg.emu_stream_source_auth_password)
- {
- snprintf(authtmp, sizeof(authtmp), "%s:%s", cfg.emu_stream_source_auth_user, cfg.emu_stream_source_auth_password);
- b64encode(authtmp, cs_strlen(authtmp), &emu_stream_source_auth);
- }
- else
- {
- NULLFREE(emu_stream_source_auth);
- }
-
- start_thread("stream_server", stream_server, NULL, NULL, 1, 1);
- cs_log("Stream relay server initialized");
}
// Initialize mutex for exclusive access to key database and key file
@@ -767,7 +750,7 @@ static int32_t emu_reader_init(struct s_reader *UNUSED(reader))
SAFE_MUTEX_INIT(&emu_key_data_mutex, NULL);
emu_key_data_mutex_init = 1;
}
-
+#endif
return CR_OK;
}
diff --git a/module-gbox.c b/module-gbox.c
index bb28f3b5a..1b0697d00 100644
--- a/module-gbox.c
+++ b/module-gbox.c
@@ -1810,7 +1810,6 @@ static int8_t gbox_check_header_recvd(struct s_client *cli, struct s_client *pro
cs_log_dump_dbg(D_READER, data, n, "-> decrypted data (%d bytes) from %s:", n, cs_inet_ntoa(cli->ip));
peer_received_pw = b2i(4, data + 6);
- peer_recvd_id = gbox_convert_password_to_id(peer_received_pw);
my_received_pw = b2i(4, data + 2);
rcvd_header_cmd = b2i(2, data);
diff --git a/module-ird-guess.c b/module-ird-guess.c
deleted file mode 100644
index 5c998b9d0..000000000
--- a/module-ird-guess.c
+++ /dev/null
@@ -1,178 +0,0 @@
-#define MODULE_LOG_PREFIX "irdguess"
-
-#include "globals.h"
-
-#ifdef IRDETO_GUESSING
-#include "module-ird-guess.h"
-#include "oscam-string.h"
-#include "oscam-conf.h"
-
-struct s_irdeto_quess
-{
- int32_t b47;
- uint16_t caid;
- uint16_t sid;
- struct s_irdeto_quess *next;
-};
-
-static struct s_irdeto_quess **itab;
-
-int32_t init_irdeto_guess_tab(void)
-{
- FILE *fp = open_config_file("oscam.ird");
- if(!fp)
- { return 1; }
-
- int32_t i, j, skip;
- int32_t b47;
- char token[128], *ptr, *saveptr1 = NULL;
- char zSid[5];
- uint8_t b3;
- uint16_t caid, sid;
- struct s_irdeto_quess *ird_row, *head;
-
- if(!cs_malloc(&itab, sizeof(struct s_irdeto_quess *) * 0xff))
- {
- fclose(fp);
- return 0;
- }
-
- while(fgets(token, sizeof(token), fp))
- {
- if(cs_strlen(token) < 20) { continue; }
- for(i = b3 = b47 = caid = sid = skip = 0, ptr = strtok_r(token, ":", &saveptr1); (i < 4) && (ptr); ptr = strtok_r(NULL, ":", &saveptr1), i++)
- {
- trim(ptr);
- if(*ptr == ';' || *ptr == '#' || *ptr == '-')
- {
- skip = 1;
- break;
- }
-
- switch(i)
- {
- case 0:
- b3 = a2i(ptr, 2);
- break;
-
- case 1:
- b47 = a2i(ptr, 8);
- break;
-
- case 2:
- caid = a2i(ptr, 4);
- break;
-
- case 3:
- for(j = 0; j < 4; j++)
- {
- zSid[j] = ptr[j];
- }
- zSid[4] = 0;
- sid = a2i(zSid, 4);
- break;
- }
- }
-
- if(!skip)
- {
- if(!cs_malloc(&ird_row, sizeof(struct s_irdeto_quess)))
- {
- fclose(fp);
- return (1);
- }
-
- ird_row->b47 = b47;
- ird_row->caid = caid;
- ird_row->sid = sid;
-
- head = itab[b3];
- if(head)
- {
- while(head->next)
- { head = head->next; }
- head->next = ird_row;
- }
- else
- { itab[b3] = ird_row; }
- //cs_log_dbg(D_CLIENT, "%02X:%08X:%04X:%04X", b3, b47, caid, sid);
- }
- }
- fclose(fp);
-
- for(i = 0; i < 0xff; i++)
- {
- head = itab[i];
- while(head)
- {
- cs_log_dbg(D_CLIENT, "itab[%02X]: b47=%08X, caid=%04X, sid=%04X",
- i, head->b47, head->caid, head->sid);
- head = head->next;
- }
- }
- return (0);
-}
-
-void free_irdeto_guess_tab(void)
-{
- uint8_t i;
- if(!itab)
- { return; }
-
- for(i = 0; i < 0xff; i++)
- {
- struct s_irdeto_quess *head = itab[i];
- while(head)
- {
- void *next = head->next;
- NULLFREE(head);
- head = next;
- }
- }
- NULLFREE(itab);
-}
-
-void guess_irdeto(ECM_REQUEST *er)
-{
- uint8_t b3;
- int32_t b47;
- //uint16_t chid;
- struct s_irdeto_quess *ptr;
-
- if(!itab)
- { return; }
-
- b3 = er->ecm[3];
- ptr = itab[b3];
- if(!ptr)
- {
- cs_log_dbg(D_TRACE, "unknown irdeto byte 3: %02X", b3);
- return;
- }
-
- b47 = b2i(4, er->ecm + 4);
- //chid = b2i(2, er->ecm+6);
- //cs_log_dbg(D_TRACE, "ecm: b47=%08X, ptr->b47=%08X, ptr->caid=%04X", b47, ptr->b47, ptr->caid);
-
- while(ptr)
- {
- if(b47 == ptr->b47)
- {
- if(er->srvid && (er->srvid != ptr->sid))
- {
- cs_log_dbg(D_TRACE, "sid mismatched (ecm: %04X, guess: %04X), wrong oscam.ird file?",
- er->srvid, ptr->sid);
- return;
- }
- er->caid = ptr->caid;
- er->srvid = ptr->sid;
- er->chid = (uint16_t)ptr->b47;
- //cs_log_dbg(D_TRACE, "quess_irdeto() found caid=%04X, sid=%04X, chid=%04X",
- //er->caid, er->srvid, er->chid);
- return;
- }
- ptr = ptr->next;
- }
-}
-
-#endif
diff --git a/module-ird-guess.h b/module-ird-guess.h
deleted file mode 100644
index 75c1c246e..000000000
--- a/module-ird-guess.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef MODULE_IRD_GUESS_H
-#define MODULE_IRD_GUESS_H
-
-#ifdef IRDETO_GUESSING
-int32_t init_irdeto_guess_tab(void);
-void guess_irdeto(ECM_REQUEST *er);
-void free_irdeto_guess_tab(void);
-#else
-static inline int32_t init_irdeto_guess_tab(void)
-{
- return 0;
-}
-static inline void guess_irdeto(ECM_REQUEST *UNUSED(er)) { }
-static inline void free_irdeto_guess_tab(void) { }
-#endif
-
-#endif
diff --git a/module-radegast.c b/module-radegast.c
index b514203ef..da3265aef 100644
--- a/module-radegast.c
+++ b/module-radegast.c
@@ -7,6 +7,10 @@
#include "oscam-net.h"
#include "oscam-string.h"
#include "oscam-reader.h"
+#ifdef MODULE_STREAMRELAY
+#include "module-streamrelay.h"
+#include "oscam-chk.h"
+#endif
static int32_t radegast_connect(void);
@@ -86,6 +90,12 @@ static void radegast_send_dcw(struct s_client *client, ECM_REQUEST *er)
mbuf[0] = 0x02; // DCW
if(er->rc < E_NOTFOUND)
{
+#ifdef MODULE_STREAMRELAY
+ if(chk_ctab_ex(er->caid, &cfg.stream_relay_ctab) && cfg.stream_relay_enabled)
+ {
+ stream_write_cw(er);
+ }
+#endif
mbuf[1] = 0x12; // len (overall)
mbuf[2] = 0x05; // ACCESS
mbuf[3] = 0x10; // len
diff --git a/module-streamrelay.c b/module-streamrelay.c
new file mode 100644
index 000000000..dc19e2846
--- /dev/null
+++ b/module-streamrelay.c
@@ -0,0 +1,1247 @@
+#define MODULE_LOG_PREFIX "relay"
+
+#include "globals.h"
+
+#ifdef MODULE_STREAMRELAY
+
+#include "module-streamrelay.h"
+#include "oscam-config.h"
+#include "oscam-net.h"
+#include "oscam-string.h"
+#include "oscam-time.h"
+#include "oscam-chk.h"
+
+#define STREAM_UNDEFINED 0x00
+#define STREAM_VIDEO 0x01
+#define STREAM_AUDIO 0x02
+#define STREAM_SUBTITLE 0x03
+#define STREAM_TELETEXT 0x04
+
+extern int32_t exit_oscam;
+
+typedef struct
+{
+ int32_t connfd;
+ int32_t connid;
+} stream_client_conn_data;
+
+char stream_source_host[256];
+char *stream_source_auth = NULL;
+uint32_t cluster_size = 50;
+
+static uint8_t stream_server_mutex_init = 0;
+static pthread_mutex_t stream_server_mutex;
+static int32_t glistenfd, gconncount = 0, gconnfd[STREAM_SERVER_MAX_CONNECTIONS];
+
+static pthread_mutex_t fixed_key_srvid_mutex;
+static uint16_t stream_cur_srvid[STREAM_SERVER_MAX_CONNECTIONS];
+static stream_client_key_data key_data[STREAM_SERVER_MAX_CONNECTIONS];
+
+#ifdef MODULE_RADEGAST
+static int32_t gRadegastFd = 0;
+
+static bool connect_to_radegast(void)
+{
+ struct SOCKADDR cservaddr;
+
+ if (gRadegastFd == 0)
+ gRadegastFd = socket(DEFAULT_AF, SOCK_STREAM, 0);
+
+ if (gRadegastFd < 0)
+ {
+ gRadegastFd = 0;
+ return false;
+ }
+
+ int32_t flags = fcntl(gRadegastFd, F_GETFL);
+ fcntl(gRadegastFd, F_SETFL, flags | O_NONBLOCK);
+
+ bzero(&cservaddr, sizeof(cservaddr));
+ SIN_GET_FAMILY(cservaddr) = DEFAULT_AF;
+ SIN_GET_PORT(cservaddr) = htons(cfg.rad_port);
+ SIN_GET_ADDR(cservaddr) = cfg.rad_srvip;
+
+ if (connect(gRadegastFd, (struct sockaddr *)&cservaddr, sizeof(cservaddr)) == -1)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static void close_radegast_connection(void)
+{
+ close(gRadegastFd);
+ gRadegastFd = 0;
+}
+
+static bool send_to_radegast(uint8_t* data, int len)
+{
+ if (send(gRadegastFd, data, len, 0) < 0)
+ {
+ cs_log("send_to_radegast: Send failure");
+ return false;
+ }
+ return true;
+}
+
+static void radegast_client_ecm(stream_client_data *cdata)
+{
+ uint16_t section_length = SCT_LEN(cdata->ecm_data);
+ uint8_t md5tmp[MD5_DIGEST_LENGTH];
+ MD5(cdata->ecm_data, section_length, md5tmp);
+
+ if (!memcmp(cdata->ecm_md5, md5tmp, MD5_DIGEST_LENGTH)) { return; }
+ memcpy(cdata->ecm_md5, md5tmp, MD5_DIGEST_LENGTH);
+
+ uint16_t packet_len;
+ static uint8_t header_len = 2;
+ static uint8_t payload_static_len = 12;
+
+ if (gRadegastFd <= 0)
+ { connect_to_radegast(); }
+
+ packet_len = header_len + payload_static_len + section_length;
+ uint8_t outgoing_data[packet_len];
+ outgoing_data[0] = 1;
+ outgoing_data[1] = payload_static_len + section_length;
+ outgoing_data[2] = 10; // caid
+ outgoing_data[3] = 2;
+ outgoing_data[4] = cdata->caid >> 8;
+ outgoing_data[5] = cdata->caid & 0xFF;
+ outgoing_data[6] = 9; // srvid
+ outgoing_data[7] = 4;
+ outgoing_data[8] = cdata->srvid & 0xFF;
+ outgoing_data[10] = cdata->srvid >> 8;
+ outgoing_data[12] = 3;
+ outgoing_data[13] = section_length;
+
+ memcpy(outgoing_data + header_len + payload_static_len, cdata->ecm_data, section_length);
+
+ if (!send_to_radegast(outgoing_data, packet_len))
+ {
+ close_radegast_connection();
+ if (connect_to_radegast())
+ {
+ send_to_radegast(outgoing_data, packet_len);
+ }
+ }
+}
+
+void ParseEcmData(stream_client_data *cdata)
+{
+ uint8_t *data = cdata->ecm_data;
+ uint16_t section_length = SCT_LEN(data);
+
+ if (section_length < 11)
+ {
+ return;
+ }
+
+ radegast_client_ecm(cdata);
+}
+#endif // MODULE_RADEGAST
+
+static void write_cw(ECM_REQUEST *er, int32_t connid)
+{
+ const uint8_t ecm = (caid_is_videoguard(er->caid) && (er->ecm[4] != 0 && (er->ecm[2] - er->ecm[4]) == 4)) ? 4 : 0;
+ if (memcmp(er->cw, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0)
+ {
+ dvbcsa_bs_key_set(er->cw, key_data[connid].key[EVEN]);
+ }
+
+ if (memcmp(er->cw + 8, "\x00\x00\x00\x00\x00\x00\x00\x00", 8) != 0)
+ {
+ dvbcsa_bs_key_set(er->cw + 8, key_data[connid].key[ODD]);
+ }
+}
+
+bool stream_write_cw(ECM_REQUEST *er)
+{
+ int32_t i;
+ if (er->rc == E_FOUND)
+ {
+ bool cw_written = false;
+ //SAFE_MUTEX_LOCK(&fixed_key_srvid_mutex);
+ for (i = 0; i < STREAM_SERVER_MAX_CONNECTIONS; i++)
+ {
+ if (stream_cur_srvid[i] == er->srvid)
+ {
+ write_cw(er, i);
+ cw_written = true;
+ // don't return as there might be more connections for the same channel (e.g. recordings)
+ }
+ }
+ //SAFE_MUTEX_UNLOCK(&fixed_key_srvid_mutex);
+ return cw_written;
+ }
+ return true;
+}
+
+static void SearchTsPackets(const uint8_t *buf, const uint32_t bufLength, uint16_t *packetSize, uint16_t *startOffset)
+{
+ uint32_t i;
+
+ for (i = 0; i < bufLength; i++)
+ {
+ if (buf[i] == 0x47)
+ {
+ // if three packets align, probably safe to assume correct size
+ if ((buf[i + 188] == 0x47) & (buf[i + 376] == 0x47))
+ {
+ (*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;
+ }
+ }
+ }
+
+ (*packetSize) = 0;
+ (*startOffset) = 0;
+}
+
+typedef void (*ts_data_callback)(stream_client_data *cdata);
+
+static void ParseTsData(const uint8_t table_id, const uint8_t table_mask, const uint8_t min_table_length, int8_t *flag,
+ uint8_t *data, const uint16_t data_length, uint16_t *data_pos, const int8_t payloadStart,
+ const uint8_t *buf, const int32_t len, ts_data_callback func, stream_client_data *cdata)
+{
+ int32_t i;
+ uint16_t offset = 0;
+ bool found_start = 0;
+
+ 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;
+ }
+
+ const int32_t free_data_length = (data_length - *data_pos);
+ const int32_t copySize = (len - offset) > free_data_length ? free_data_length : (len - offset);
+
+ memcpy(data + *data_pos, buf + offset, copySize);
+ *data_pos += copySize;
+
+ 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;
+ }
+ }
+
+ const uint16_t section_length = SCT_LEN(data);
+
+ if (!found_start || (section_length > data_length) || (section_length < min_table_length))
+ {
+ *flag = 0;
+ return;
+ }
+
+ if ((*data_pos < section_length) || (*data_pos < 3))
+ {
+ *flag = 2;
+ 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_length < *data_pos + copySize + 1))
+ {
+ *data_pos = 0;
+ }
+
+ *flag = 1;
+}
+
+static void ParsePatData(stream_client_data *cdata)
+{
+ int32_t i;
+ uint16_t srvid;
+#ifdef __BISS__
+ cdata->STREAMpidcount = 0;
+#endif
+ for (i = 8; i + 7 < SCT_LEN(cdata->pat_data); i += 4)
+ {
+ srvid = b2i(2, cdata->pat_data + i);
+ if (srvid == 0)
+ {
+ continue;
+ }
+
+ if (cdata->srvid == srvid)
+ {
+ cdata->pmt_pid = b2i(2, cdata->pat_data + i + 2) & 0x1FFF;
+ cs_log_dbg(D_READER, "Stream client %i found pmt pid: 0x%04X (%i)",
+ cdata->connid, cdata->pmt_pid, cdata->pmt_pid);
+ break;
+ }
+ }
+}
+
+static void ParseDescriptors(const uint8_t *buffer, const uint16_t info_length, uint8_t *type)
+{
+ uint32_t i;
+ uint8_t j, descriptor_length = 0;
+
+ if (info_length < 1)
+ {
+ return;
+ }
+
+ for (i = 0; i + 1 < info_length; i += descriptor_length + 2)
+ {
+ descriptor_length = buffer[i + 1];
+ switch (buffer[i]) // descriptor tag
+ {
+ case 0x05: // Registration descriptor
+ {
+ // "HDMV" format identifier is removed
+ // Cam does not need to know about Blu-ray
+ const char format_identifiers_audio[10][5] =
+ {
+ "AC-3", "BSSD", "dmat", "DRA1", "DTS1",
+ "DTS2", "DTS3", "EAC3", "mlpa", "Opus",
+ };
+ for (j = 0; j < 10; j++)
+ {
+ if (memcmp(buffer + i + 2, format_identifiers_audio[j], 4) == 0)
+ {
+ *type = STREAM_AUDIO;
+ break;
+ }
+ }
+ break;
+ }
+ //case 0x09: // CA descriptor
+ //{
+ // break;
+ //}
+ case 0x46: // VBI teletext descriptor (DVB)
+ case 0x56: // teletext descriptor (DVB)
+ {
+ *type = STREAM_TELETEXT;
+ break;
+ }
+ case 0x59: // subtitling descriptor (DVB)
+ {
+ *type = STREAM_SUBTITLE;
+ break;
+ }
+ case 0x6A: // AC-3 descriptor (DVB)
+ case 0x7A: // enhanced AC-3 descriptor (DVB)
+ case 0x7B: // DTS descriptor (DVB)
+ case 0x7C: // AAC descriptor (DVB)
+ case 0x81: // AC-3 descriptor (ATSC)
+ case 0xCC: // Enhanced AC-3 descriptor (ATSC)
+ {
+ *type = STREAM_AUDIO;
+ break;
+ }
+ case 0x7F: // extension descriptor (DVB)
+ {
+ switch(buffer[i + 2]) // extension descriptor tag
+ {
+ case 0x0E: // DTS-HD descriptor (DVB)
+ case 0x0F: // DTS Neural descriptor (DVB)
+ case 0x15: // AC-4 descriptor (DVB)
+ *type = STREAM_AUDIO;
+ break;
+
+ case 0x20: // TTML subtitling descriptor (DVB)
+ *type = STREAM_SUBTITLE;
+ break;
+
+ default:
+ *type = STREAM_UNDEFINED;
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+static void stream_parse_pmt_ca_descriptor(const uint8_t *data, const int32_t data_pos, const int32_t offset, const uint16_t info_length, stream_client_data *cdata)
+{
+ if (cdata->ecm_pid)
+ {
+ return;
+ }
+
+ // parse program descriptors (we are looking only for CA descriptor here)
+ int32_t i;
+ uint16_t caid;
+ uint8_t descriptor_tag, descriptor_length = 0;
+
+ for (i = offset; i + 1 < offset + info_length; i += descriptor_length + 2)
+ {
+ descriptor_tag = data[i + data_pos];
+ descriptor_length = data[i + 1 + data_pos];
+ if (descriptor_length < 1)
+ {
+ break;
+ }
+
+ if (i + 1 + descriptor_length >= offset + info_length)
+ {
+ break;
+ }
+
+ if (descriptor_tag == 0x09 && descriptor_length >= 4)
+ {
+ caid = b2i(2, data + i + 2 + data_pos);
+ if (chk_ctab_ex(caid, &cfg.stream_relay_ctab))
+ {
+ if (cdata->caid == NO_CAID_VALUE)
+ {
+ cdata->caid = caid;
+ }
+
+ if (cdata->caid != caid)
+ {
+ continue;
+ }
+ cdata->ecm_pid = b2i(2, data + i + 4 + data_pos) & 0x1FFF;
+ cs_log_dbg(D_READER, "Stream client %i found ecm pid: 0x%04X (%i)",
+ cdata->connid, cdata->ecm_pid, cdata->ecm_pid);
+ }
+ }
+ }
+}
+
+static void ParsePmtData(stream_client_data *cdata)
+{
+ int32_t i;
+ uint16_t program_info_length = 0, es_info_length = 0, elementary_pid;
+ const uint16_t section_length = SCT_LEN(cdata->pmt_data);
+ uint8_t offset = 0;
+
+ cdata->ecm_pid = 0;
+ cdata->pcr_pid = b2i(2, cdata->pmt_data + 8) & 0x1FFF;
+
+ if (cdata->pcr_pid != 0x1FFF)
+ {
+ cs_log_dbg(D_READER, "Stream client %i found pcr pid: 0x%04X (%i)",
+ cdata->connid, cdata->pcr_pid, cdata->pcr_pid);
+ }
+ program_info_length = b2i(2, cdata->pmt_data + 10) & 0xFFF;
+ if (!program_info_length)
+ {
+ offset = 5;
+ program_info_length = (b2i(2, cdata->pmt_data + 10 + offset) & 0xFFF);
+ }
+ if (12 + offset + program_info_length >= section_length) { return; }
+ stream_parse_pmt_ca_descriptor(cdata->pmt_data, 0, 12 + offset, program_info_length, cdata);
+
+ offset = offset == 5 ? 0 : program_info_length;
+ for (i = 12 + offset; i + 4 < section_length; i += 5 + es_info_length)
+ {
+ elementary_pid = b2i(2, cdata->pmt_data + i + 1) & 0x1FFF;
+ es_info_length = b2i(2, cdata->pmt_data + i + 3) & 0xFFF;
+ switch (cdata->pmt_data[i]) // stream type
+ {
+ case 0x01:
+ case 0x02:
+ case 0x10:
+ case 0x1B:
+ case 0x20:
+ case 0x24:
+ case 0x25:
+ case 0x42:
+ case 0xD1:
+ case 0xEA:
+ {
+ cs_log_dbg(D_READER, "Stream client %i found video pid: 0x%04X (%i)",
+ cdata->connid, elementary_pid, elementary_pid);
+ stream_parse_pmt_ca_descriptor(cdata->pmt_data, i, 5, es_info_length, cdata);
+ break;
+ }
+ case 0x03:
+ case 0x04:
+ case 0x0F:
+ case 0x11:
+ case 0x1C:
+ case 0x2D:
+ case 0x2E:
+ case 0x81:
+ {
+ cs_log_dbg(D_READER, "Stream client %i found audio pid: 0x%04X (%i)",
+ cdata->connid, elementary_pid, elementary_pid);
+ break;
+ }
+ case 0x06:
+ //case 0x81: // some ATSC AC-3 streams do not contain the AC-3 descriptor!
+ case 0x87:
+ {
+ uint8_t type = STREAM_UNDEFINED;
+ ParseDescriptors(cdata->pmt_data + i + 5, es_info_length, &type);
+ if (type == STREAM_AUDIO)
+ {
+ cs_log_dbg(D_READER, "Stream client %i found audio pid: 0x%04X (%i)",
+ cdata->connid, elementary_pid, elementary_pid);
+ }
+ else if (type == STREAM_TELETEXT)
+ {
+ cs_log_dbg(D_READER, "Stream client %i found teletext pid: 0x%04X (%i)",
+ cdata->connid, elementary_pid, elementary_pid);
+ }
+ break;
+ }
+ }
+#ifdef __BISS__
+ cdata->STREAMpids[cdata->STREAMpidcount] = elementary_pid;
+ cdata->STREAMpidcount++;
+#endif
+ }
+}
+
+static void ParseTsPackets(stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
+{
+ uint8_t payloadStart;
+ uint16_t pid, offset;
+ uint32_t i, tsHeader;
+
+ for (i = 0; i < bufLength; i += packetSize)
+ {
+ tsHeader = b2i(4, stream_buf + i);
+ pid = (tsHeader & 0x1FFF00) >> 8;
+ payloadStart = (tsHeader & 0x400000) >> 22;
+
+ if (tsHeader & 0x20)
+ {
+ offset = 4 + stream_buf[i + 4] + 1;
+ }
+ else
+ {
+ offset = 4;
+ }
+
+ if (packetSize - offset < 1)
+ {
+ continue;
+ }
+
+ if (pid == 0x0000 && data->have_pat_data != 1) // Search the PAT for the PMT pid
+ {
+ ParseTsData(0x00, 0xFF, 16, &data->have_pat_data, data->pat_data, sizeof(data->pat_data),
+ &data->pat_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParsePatData, data);
+ continue;
+ }
+
+ if (pid == data->pmt_pid && data->have_pmt_data != 1) // Search the PMT for PCR, ECM, Video and Audio pids
+ {
+ ParseTsData(0x02, 0xFF, 21, &data->have_pmt_data, data->pmt_data, sizeof(data->pmt_data),
+ &data->pmt_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParsePmtData, data);
+ continue;
+ }
+
+ // We have bot PAT and PMT data - No need to search the rest of the packets
+ if (data->have_pat_data == 1 && data->have_pmt_data == 1)
+ {
+ break;
+ }
+ }
+}
+
+static void decrypt(struct dvbcsa_bs_batch_s *tsbbatch, uint16_t fill[2], const uint8_t oddeven, const int32_t connid)
+{
+ if (fill[oddeven] > 0)
+ {
+#if 0
+ uint16_t i;
+ for(i = fill[oddeven]; i <= cluster_size; i++)
+ {
+ tsbbatch[i].data = NULL;
+ tsbbatch[i].len = 0;
+ }
+#else
+ tsbbatch[fill[oddeven]].data = NULL;
+#endif
+ //cs_log_dbg(D_READER, "dvbcsa (%s), batch=%d", oddeven == ODD ? "odd" : "even", fill[oddeven]);
+
+ fill[oddeven] = 0;
+
+ dvbcsa_bs_decrypt(key_data[connid].key[oddeven], tsbbatch, 184);
+ }
+}
+#define decrypt(a) decrypt(tsbbatch, fill, a, data->connid)
+
+static void DescrambleTsPackets(stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize, struct dvbcsa_bs_batch_s *tsbbatch)
+{
+ uint32_t i, tsHeader;
+ uint16_t offset, fill[2] = {0,0};
+ uint8_t oddeven = 0;
+#ifdef MODULE_RADEGAST
+ uint16_t pid;
+ uint8_t payloadStart;
+#endif
+
+ for (i = 0; i < bufLength; i += packetSize)
+ {
+ tsHeader = b2i(4, stream_buf + i);
+#ifdef MODULE_RADEGAST
+ pid = (tsHeader & 0x1FFF00) >> 8;
+ payloadStart = (tsHeader & 0x400000) >> 22;
+#endif
+ offset = (tsHeader & 0x20) ? 4 + stream_buf[i + 4] + 1 : 4;
+ if (packetSize - offset < 1)
+ {
+ continue;
+ }
+#ifdef MODULE_RADEGAST
+#ifdef __BISS__
+ if(data->ecm_pid == 0x1FFF && caid_is_biss_fixed(data->caid))
+ {
+ uint32_t j, n;
+ uint16_t ecm_len = 7;
+ data->ecm_data[0] = 0x80; // to pass the cache check it must be 0x80 or 0x81
+ data->ecm_data[1] = 0x00;
+ data->ecm_data[2] = 0x04;
+ i2b_buf(2, data->srvid, data->ecm_data + 3);
+ i2b_buf(2, data->pmt_pid, data->ecm_data + 5);
+ for(j = 0, n = 7; j < data->STREAMpidcount; j++, n += 2)
+ {
+ i2b_buf(2, data->STREAMpids[j], data->ecm_data + n);
+ data->ecm_data[2] += 2;
+ ecm_len += 2;
+ }
+ data->ens &= 0x0FFFFFFF; // clear top 4 bits (in case of DVB-T/C or garbage), prepare for flagging
+ data->ens |= 0xA0000000; // flag to emu: this is the namespace, not a pid
+ i2b_buf(2, data->tsid, data->ecm_data + ecm_len); // place tsid after the last stream pid
+ i2b_buf(2, data->onid, data->ecm_data + ecm_len + 2); // place onid right after tsid
+ i2b_buf(4, data->ens, data->ecm_data + ecm_len + 4); // place namespace at the end of the ecm
+ data->ecm_data[2] += 8;
+ ParseEcmData(data);
+ } else
+#endif // __BISS__
+ if (data->ecm_pid && pid == data->ecm_pid) // Process the ECM data
+ {
+ // set to null pid
+ stream_buf[i + 1] |= 0x1F;
+ stream_buf[i + 2] = 0xFF;
+ ParseTsData(0x80, 0xFE, 3, &data->have_ecm_data, data->ecm_data, sizeof(data->ecm_data),
+ &data->ecm_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParseEcmData, data);
+ continue;
+ }
+#endif // MODULE_RADEGAST
+ if ((tsHeader & 0xC0) == 0)
+ {
+ continue;
+ }
+
+ stream_buf[i + 3] &= 0x3f; // consider it decrypted now
+ oddeven = (tsHeader & 0xC0) == 0xC0 ? ODD: EVEN;
+ decrypt(oddeven == ODD ? EVEN : ODD);
+ tsbbatch[fill[oddeven]].data = &stream_buf[i + offset];
+ tsbbatch[fill[oddeven]].len = packetSize - offset;
+ fill[oddeven]++;
+
+ if (fill[oddeven] > cluster_size - 1)
+ {
+ decrypt(oddeven);
+ }
+ }
+
+ decrypt(oddeven);
+}
+
+static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *stream_path)
+{
+ struct SOCKADDR cservaddr;
+ IN_ADDR_T in_addr;
+
+ int32_t streamfd = socket(DEFAULT_AF, SOCK_STREAM, 0);
+ if (streamfd == -1) { return -1; }
+
+ struct timeval tv;
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ if (setsockopt(streamfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv))
+ {
+ cs_log("ERROR: setsockopt() failed for SO_RCVTIMEO");
+ return -1;
+ }
+
+ bzero(&cservaddr, sizeof(cservaddr));
+ SIN_GET_FAMILY(cservaddr) = DEFAULT_AF;
+ SIN_GET_PORT(cservaddr) = htons(cfg.stream_source_port);
+ cs_resolve(stream_source_host, &in_addr, NULL, NULL);
+ SIN_GET_ADDR(cservaddr) = in_addr;
+
+ if (connect(streamfd, (struct sockaddr *)&cservaddr, sizeof(cservaddr)) == -1)
+ {
+ cs_log("WARNING: Connect to stream source port %d failed", cfg.stream_source_port);
+ return -1;
+ }
+
+ if (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, stream_source_host, cfg.stream_source_port, 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, stream_source_host, cfg.stream_source_port);
+ }
+
+ if (send(streamfd, http_buf, cs_strlen(http_buf), 0) == -1) { return -1; }
+ return streamfd;
+}
+
+static void stream_client_disconnect(stream_client_conn_data *conndata)
+{
+ int32_t i;
+
+ SAFE_MUTEX_LOCK(&fixed_key_srvid_mutex);
+ stream_cur_srvid[conndata->connid] = NO_SRVID_VALUE;
+ SAFE_MUTEX_UNLOCK(&fixed_key_srvid_mutex);
+
+ SAFE_MUTEX_LOCK(&stream_server_mutex);
+ for (i = 0; i < STREAM_SERVER_MAX_CONNECTIONS; i++)
+ {
+ if (gconnfd[i] == conndata->connfd)
+ {
+ gconnfd[i] = -1;
+ gconncount--;
+ }
+ }
+ SAFE_MUTEX_UNLOCK(&stream_server_mutex);
+
+ shutdown(conndata->connfd, 2);
+ close(conndata->connfd);
+
+ cs_log("Stream client %i disconnected",conndata->connid);
+
+ NULLFREE(conndata);
+}
+
+static void *stream_client_handler(void *arg)
+{
+ stream_client_conn_data *conndata = (stream_client_conn_data *)arg;
+ stream_client_data *data;
+
+ char *http_buf, stream_path[255], stream_path_copy[255];
+ char *saveptr, *token, http_version[4];
+
+ int8_t streamConnectErrorCount = 0, streamDataErrorCount = 0;
+ int32_t bytesRead = 0, http_status_code = 0;
+ int32_t i, clientStatus, streamStatus, streamfd;
+
+ uint8_t *stream_buf;
+ uint16_t packetCount = 0, packetSize = 0, startOffset = 0;
+ uint32_t remainingDataPos, remainingDataLength, tmp_pids[4];
+ uint8_t descrambling = 0;
+
+ const int32_t cur_dvb_buffer_size = DVB_BUFFER_SIZE_CSA;
+ const int32_t cur_dvb_buffer_wait = DVB_BUFFER_WAIT_CSA;
+
+ struct dvbcsa_bs_batch_s *tsbbatch;
+
+ cs_log("Stream client %i connected", conndata->connid);
+
+ if (!cs_malloc(&http_buf, 1024))
+ {
+ stream_client_disconnect(conndata);
+ return NULL;
+ }
+
+ if (!cs_malloc(&stream_buf, DVB_BUFFER_SIZE))
+ {
+ NULLFREE(http_buf);
+ stream_client_disconnect(conndata);
+ return NULL;
+ }
+
+ if (!cs_malloc(&data, sizeof(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); // token 0
+ for (i = 1; token != NULL && i < 7; i++) // tokens 1 to 6
+ {
+ token = strtok_r(NULL, ":", &saveptr);
+ if (token == NULL)
+ {
+ break;
+ }
+
+ if (i >= 3) // We olny need token 3 (srvid), 4 (tsid), 5 (onid) and 6 (ens)
+ {
+ if (sscanf(token, "%x", &tmp_pids[i - 3]) != 1)
+ {
+ tmp_pids[i - 3] = 0;
+ }
+ }
+ }
+
+ data->srvid = tmp_pids[0] & 0xFFFF;
+ data->tsid = tmp_pids[1] & 0xFFFF;
+ data->onid = tmp_pids[2] & 0xFFFF;
+ data->ens = tmp_pids[3];
+
+ if (data->srvid == 0) // We didn't get a srvid - Exit
+ {
+ NULLFREE(http_buf);
+ NULLFREE(stream_buf);
+ NULLFREE(data);
+ stream_client_disconnect(conndata);
+ return NULL;
+ }
+
+ key_data[conndata->connid].key[ODD] = dvbcsa_bs_key_alloc();
+ key_data[conndata->connid].key[EVEN] = dvbcsa_bs_key_alloc();
+
+ if (!cs_malloc(&tsbbatch, (cluster_size + 1) * sizeof(struct dvbcsa_bs_batch_s)))
+ {
+ NULLFREE(http_buf);
+ NULLFREE(stream_buf);
+ NULLFREE(data);
+ stream_client_disconnect(conndata);
+ return NULL;
+ }
+
+ SAFE_MUTEX_LOCK(&fixed_key_srvid_mutex);
+ stream_cur_srvid[conndata->connid] = data->srvid;
+ SAFE_MUTEX_UNLOCK(&fixed_key_srvid_mutex);
+
+ cs_log("Stream client %i request %s", conndata->connid, stream_path);
+
+ cs_log_dbg(D_READER, "Stream client %i received srvid: %04X tsid: %04X onid: %04X ens: %08X",
+ conndata->connid, data->srvid, data->tsid, data->onid, data->ens);
+
+ 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, cs_strlen(http_buf), 0);
+
+ data->connid = conndata->connid;
+ data->caid = NO_CAID_VALUE;
+ data->have_pat_data = 0;
+ data->have_pmt_data = 0;
+ data->have_cat_data = 0;
+ data->have_ecm_data = 0;
+ data->have_emm_data = 0;
+
+ while (!exit_oscam && clientStatus != -1 && streamConnectErrorCount < 3
+ && streamDataErrorCount < 15)
+ {
+ streamfd = connect_to_stream(http_buf, 1024, stream_path);
+ if (streamfd == -1)
+ {
+ cs_log("WARNING: stream client %i cannot connect to stream source", conndata->connid);
+ streamConnectErrorCount++;
+ cs_sleepms(500);
+ continue;
+ }
+ streamStatus = 0;
+ bytesRead = 0;
+ while (!exit_oscam && clientStatus != -1 && streamStatus != -1
+#if 0
+ && streamConnectErrorCount < 3 && streamDataErrorCount < 15)
+#else
+ && (streamConnectErrorCount < 3 || streamDataErrorCount < 15))
+#endif
+ {
+ streamStatus = recv(streamfd, stream_buf + bytesRead, cur_dvb_buffer_size - bytesRead, MSG_WAITALL);
+ if (streamStatus == 0) // socket closed
+ {
+ cs_log("WARNING: stream client %i - stream source closed connection", conndata->connid);
+ streamConnectErrorCount++;
+ cs_sleepms(100);
+ break;
+ }
+ if (streamStatus < 0) // error
+ {
+ if ((errno == EWOULDBLOCK) | (errno == EAGAIN))
+ {
+ cs_log("WARNING: stream client %i no data from stream source", conndata->connid);
+ streamDataErrorCount++; // 2 sec timeout * 15 = 30 seconds no data -> close
+ cs_sleepms(100);
+ continue;
+ }
+ cs_log("WARNING: stream client %i error receiving data from stream source", conndata->connid);
+ streamConnectErrorCount++;
+ cs_sleepms(100);
+ break;
+ }
+ if (streamStatus < cur_dvb_buffer_size - bytesRead) // probably just received header but no stream
+ {
+ if (!bytesRead && streamStatus > 13 &&
+ sscanf((const char*)stream_buf, "HTTP/%3s %d ", http_version , &http_status_code) == 2 &&
+ http_status_code != 200)
+ {
+ cs_log("ERROR: stream client %i got %d response from stream source", conndata->connid, http_status_code);
+ streamConnectErrorCount++;
+ cs_sleepms(100);
+ break;
+ }
+ else
+ {
+ cs_log_dbg(0, "WARNING: stream client %i non-full buffer from stream source", conndata->connid);
+ streamDataErrorCount++;
+ cs_sleepms(100);
+ }
+ }
+ else
+ {
+ streamDataErrorCount = 0;
+ }
+
+ streamConnectErrorCount = 0;
+ bytesRead += streamStatus;
+
+ if (bytesRead >= cur_dvb_buffer_wait)
+ {
+ startOffset = 0;
+
+ // only search if not starting on ts packet or unknown packet size
+ if (stream_buf[0] != 0x47 || packetSize == 0)
+ {
+ SearchTsPackets(stream_buf, bytesRead, &packetSize, &startOffset);
+ }
+
+ if (packetSize == 0)
+ {
+ bytesRead = 0;
+ }
+ else
+ {
+ packetCount = ((bytesRead - startOffset) / packetSize);
+
+ // We have both PAT and PMT data - We can start descrambling
+ if (data->have_pat_data == 1 && data->have_pmt_data == 1)
+ {
+ if (chk_ctab_ex(data->caid, &cfg.stream_relay_ctab) && (data->caid != 0xA101 || data->caid == NO_CAID_VALUE))
+ {
+ DescrambleTsPackets(data, stream_buf + startOffset, packetCount * packetSize, packetSize, tsbbatch);
+ if (!descrambling && cfg.stream_relay_buffer_time) {
+ cs_sleepms(cfg.stream_relay_buffer_time);
+ descrambling = 1;
+ }
+ }
+ else
+ {
+ cs_log_dbg(D_READER, "Stream client %i caid %04X not enabled in stream relay config",
+ conndata->connid, data->caid);
+ }
+ }
+ else // Search PAT and PMT packets for service information
+ {
+ ParseTsPackets(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
+ }
+
+ clientStatus = send(conndata->connfd, stream_buf + startOffset, packetCount * packetSize, 0);
+
+ remainingDataPos = startOffset + (packetCount * packetSize);
+ remainingDataLength = bytesRead - remainingDataPos;
+
+ if (remainingDataPos < remainingDataLength)
+ {
+ memmove(stream_buf, stream_buf + remainingDataPos, remainingDataLength);
+ }
+ else
+ {
+ memcpy(stream_buf, stream_buf + remainingDataPos, remainingDataLength);
+ }
+
+ bytesRead = remainingDataLength;
+ }
+ }
+ }
+
+ close(streamfd);
+ }
+
+ NULLFREE(http_buf);
+ NULLFREE(stream_buf);
+
+ dvbcsa_bs_key_free(key_data[conndata->connid].key[ODD]);
+ dvbcsa_bs_key_free(key_data[conndata->connid].key[EVEN]);
+ NULLFREE(tsbbatch);
+
+ 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;
+ stream_client_conn_data *conndata;
+
+ cluster_size = dvbcsa_bs_batch_size();
+ cs_log("INFO: "
+#if DVBCSA_KEY_ECM > 0
+ "(ecm) "
+#endif
+ "dvbcsa parallel mode = %d (relay buffer time: %d ms)", cluster_size, cfg.stream_relay_buffer_time);
+
+ if (!stream_server_mutex_init)
+ {
+ SAFE_MUTEX_INIT(&stream_server_mutex, NULL);
+ stream_server_mutex_init = 1;
+ }
+
+ SAFE_MUTEX_LOCK(&fixed_key_srvid_mutex);
+ for (i = 0; i < STREAM_SERVER_MAX_CONNECTIONS; i++)
+ {
+ stream_cur_srvid[i] = NO_SRVID_VALUE;
+ }
+ SAFE_MUTEX_UNLOCK(&fixed_key_srvid_mutex);
+
+ for (i = 0; i < STREAM_SERVER_MAX_CONNECTIONS; i++)
+ {
+ gconnfd[i] = -1;
+ }
+
+ glistenfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (glistenfd == -1)
+ {
+ cs_log("ERROR: cannot create stream server socket");
+ return NULL;
+ }
+
+ bzero(&servaddr,sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ servaddr.sin_port = htons(cfg.stream_relay_port);
+ setsockopt(glistenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
+
+ if (bind(glistenfd,(struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
+ {
+ cs_log("ERROR: cannot bind to stream server socket");
+ close(glistenfd);
+ return NULL;
+ }
+
+ if (listen(glistenfd, 3) == -1)
+ {
+ cs_log("ERROR: cannot listen to stream server socket");
+ close(glistenfd);
+ return NULL;
+ }
+
+ while (!exit_oscam)
+ {
+ clilen = sizeof(cliaddr);
+ connfd = accept(glistenfd,(struct sockaddr *)&cliaddr, &clilen);
+
+ if (connfd == -1)
+ {
+ cs_log("ERROR: accept() failed");
+ break;
+ }
+
+ connaccepted = 0;
+
+#ifdef MODULE_RADEGAST
+ if(cfg.stream_client_source_host)
+ {
+ // Read ip of client who wants to play the stream
+ unsigned char *ip = (unsigned char *)&cliaddr.sin_addr.s_addr;
+ cs_log("Stream Client ip is: %d.%d.%d.%d, will fetch stream there\n", ip[0], ip[1], ip[2], ip[3]);
+
+ // Store ip of client in stream_source_host variable
+ snprintf(stream_source_host, sizeof(stream_source_host), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+ }
+#endif
+
+ if (cs_malloc(&conndata, sizeof(stream_client_conn_data)))
+ {
+ SAFE_MUTEX_LOCK(&stream_server_mutex);
+ if (gconncount < STREAM_SERVER_MAX_CONNECTIONS)
+ {
+ for (i = 0; i < 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(&stream_server_mutex);
+ }
+
+ if (connaccepted)
+ {
+ int on = 1;
+ if (setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
+ {
+ cs_log("ERROR: stream client %i setsockopt() failed for TCP_NODELAY", conndata->connid);
+ }
+
+ start_thread("stream client", stream_client_handler, (void*)conndata, NULL, 1, 0);
+ }
+ else
+ {
+ shutdown(connfd, 2);
+ close(connfd);
+ cs_log("ERROR: stream server client dropped because of too many connections (%i)", STREAM_SERVER_MAX_CONNECTIONS);
+ }
+
+ cs_sleepms(20);
+ }
+
+ close(glistenfd);
+
+ return NULL;
+}
+
+void init_stream_server(void)
+{
+ char authtmp[128];
+
+ if (cfg.stream_relay_enabled)
+ {
+
+ cs_strncpy(stream_source_host, cfg.stream_source_host, sizeof(stream_source_host));
+
+ if (cfg.stream_source_auth_user && cfg.stream_source_auth_password)
+ {
+ snprintf(authtmp, sizeof(authtmp), "%s:%s", cfg.stream_source_auth_user, cfg.stream_source_auth_password);
+ b64encode(authtmp, cs_strlen(authtmp), &stream_source_auth);
+ }
+
+ start_thread("stream_server", stream_server, NULL, NULL, 1, 1);
+ cs_log("Stream Relay server initialized");
+ }
+}
+
+void stop_stream_server(void)
+{
+ int32_t i;
+
+ SAFE_MUTEX_LOCK(&stream_server_mutex);
+ for (i = 0; i < STREAM_SERVER_MAX_CONNECTIONS; i++)
+ {
+ if (gconnfd[i] != -1)
+ {
+ shutdown(gconnfd[i], 2);
+ close(gconnfd[i]);
+ gconnfd[i] = -1;
+ }
+ }
+
+ gconncount = 0;
+ SAFE_MUTEX_UNLOCK(&stream_server_mutex);
+
+#ifdef MODULE_RADEGAST
+ close_radegast_connection();
+#endif
+
+ shutdown(glistenfd, 2);
+ close(glistenfd);
+}
+
+#endif // MODULE_STREAMRELAY
diff --git a/module-streamrelay.h b/module-streamrelay.h
new file mode 100644
index 000000000..5b6785707
--- /dev/null
+++ b/module-streamrelay.h
@@ -0,0 +1,74 @@
+#ifndef MODULE_STREAMRELAY_H_
+#define MODULE_STREAMRELAY_H_
+
+#ifdef MODULE_STREAMRELAY
+
+#define STREAM_SERVER_MAX_CONNECTIONS 16
+
+#define DVB_MAX_TS_PACKETS 278
+#define DVB_BUFFER_SIZE_CSA 188*DVB_MAX_TS_PACKETS
+#define DVB_BUFFER_WAIT_CSA 188*(DVB_MAX_TS_PACKETS-128)
+#define DVB_BUFFER_SIZE DVB_BUFFER_SIZE_CSA
+
+//#define __BISS__
+#ifdef __BISS__
+#define MAX_STREAM_PIDS 32
+#endif
+
+#include "cscrypt/md5.h"
+#include
+#if DVBCSA_KEY_ECM > 0
+#define dvbcsa_bs_key_set(a,b) dvbcsa_bs_key_set_ecm(ecm,a,b)
+#endif
+
+#define EVEN 0
+#define ODD 1
+
+typedef struct
+{
+ struct dvbcsa_bs_key_s *key[2];
+} stream_client_key_data;
+
+typedef struct
+{
+ int32_t connid;
+ int8_t have_cat_data;
+ int8_t have_pat_data;
+ int8_t have_pmt_data;
+ int8_t have_ecm_data;
+ int8_t have_emm_data;
+ uint8_t cat_data[1024+208];
+ uint8_t pat_data[1024+208];
+ uint8_t pmt_data[1024+208];
+ uint8_t ecm_data[1024+208];
+ uint8_t emm_data[1024+208];
+ uint16_t cat_data_pos;
+ uint16_t pat_data_pos;
+ uint16_t pmt_data_pos;
+ uint16_t ecm_data_pos;
+ uint16_t emm_data_pos;
+ uint16_t srvid;
+ uint16_t caid;
+ uint16_t tsid;
+ uint16_t onid;
+ uint32_t ens;
+ uint16_t pmt_pid;
+ uint16_t ecm_pid;
+ uint16_t emm_pid;
+ uint16_t pcr_pid;
+#ifdef __BISS__
+ uint8_t STREAMpidcount;
+ uint16_t STREAMpids[MAX_STREAM_PIDS];
+#endif
+ uint8_t ecm_md5[MD5_DIGEST_LENGTH];
+} stream_client_data;
+
+void *stream_server(void *a);
+void init_stream_server(void);
+void stop_stream_server(void);
+
+bool stream_write_cw(ECM_REQUEST *er);
+
+#endif // MODULE_STREAMRELAY
+
+#endif // MODULE_STREAMRELAY_H_
diff --git a/module-webif-tpl.c b/module-webif-tpl.c
index e94d693b1..32e793f78 100644
--- a/module-webif-tpl.c
+++ b/module-webif-tpl.c
@@ -423,7 +423,6 @@ char *tpl_getUnparsedTpl(const char *name, int8_t removeHeader, const char *subd
check_conf(READ_SDT_CHARSETS, ptr2);
check_conf(CLOCKFIX, ptr2);
check_conf(IPV6SUPPORT, ptr2);
- check_conf(IRDETO_GUESSING, ptr2);
check_conf(LCDSUPPORT, ptr2);
check_conf(LEDSUPPORT, ptr2);
check_conf(MODULE_CAMD33, ptr2);
diff --git a/module-webif.c b/module-webif.c
index 29c96083b..66d237197 100644
--- a/module-webif.c
+++ b/module-webif.c
@@ -1298,7 +1298,7 @@ static char *send_oscam_config_scam(struct templatevars *vars, struct uriparams
}
#endif
-#ifdef WITH_EMU
+#ifdef MODULE_STREAMRELAY
static char *send_oscam_config_streamrelay(struct templatevars *vars, struct uriparams *params)
{
char *value;
@@ -1307,22 +1307,22 @@ static char *send_oscam_config_streamrelay(struct templatevars *vars, struct uri
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, "STREAM_SOURCE_HOST", "%s", cfg.stream_source_host);
+ tpl_printf(vars, TPLADD, "STREAM_SOURCE_PORT", "%d", cfg.stream_source_port);
+ if(cfg.stream_source_auth_user)
+ { tpl_printf(vars, TPLADD, "STREAM_SOURCE_AUTH_USER", "%s", cfg.stream_source_auth_user); }
+ if(cfg.stream_source_auth_password)
+ { tpl_printf(vars, TPLADD, "STREAM_SOURCE_AUTH_PASSWORD", "%s", cfg.stream_source_auth_password); }
+#ifdef MODULE_RADEGAST
+ tpl_addVar(vars, TPLADD, "STREAM_CLIENT_SOURCE_HOST", (cfg.stream_client_source_host == 1) ? "checked" : "");
+#endif
+ tpl_printf(vars, TPLADD, "STREAM_RELAY_PORT", "%d", cfg.stream_relay_port);
+ tpl_printf(vars, TPLADD, "STREAM_RELAY_BUFFER_TIME", "%d", cfg.stream_relay_buffer_time);
- tpl_printf(vars, TPLADD, "TMP", "STREAMEMMENABLEDSELECTED%d", cfg.emu_stream_emm_enabled);
+ tpl_printf(vars, TPLADD, "TMP", "STREAMRELAYENABLEDSELECTED%d", cfg.stream_relay_enabled);
tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected");
- value = mk_t_caidtab(&cfg.emu_stream_relay_ctab);
+ value = mk_t_caidtab(&cfg.stream_relay_ctab);
tpl_addVar(vars, TPLADD, "STREAM_RELAY_CTAB", value);
free_mk_t(value);
@@ -1684,6 +1684,12 @@ static char *send_oscam_config_dvbapi(struct templatevars *vars, struct uriparam
if(cfg.dvbapi_write_sdt_prov > 0)
{ tpl_addVar(vars, TPLADD, "WRITESDTPROVCHECKED", "checked"); }
+#ifdef MODULE_STREAMRELAY
+ //demuxer_fix
+ if(cfg.dvbapi_demuxer_fix > 0)
+ { tpl_addVar(vars, TPLADD, "DEMUXERFIXCHECKED", "checked"); }
+#endif
+
//TCP listen port
if(cfg.dvbapi_listenport > 0)
{ tpl_printf(vars, TPLADD, "LISTENPORT", "%d", cfg.dvbapi_listenport); }
@@ -1758,7 +1764,7 @@ static char *send_oscam_config(struct templatevars *vars, struct uriparams *para
#ifdef MODULE_SCAM
else if(!strcmp(part, "scam")) { return send_oscam_config_scam(vars, params); }
#endif
-#ifdef WITH_EMU
+#ifdef MODULE_STREAMRELAY
else if(!strcmp(part, "streamrelay")) { return send_oscam_config_streamrelay(vars, params); }
#endif
#ifdef MODULE_CCCAM
@@ -2025,6 +2031,10 @@ static char *send_oscam_reader(struct templatevars *vars, struct uriparams *para
tpl_addVar(vars, TPLADD, "LASTGSMS", rdr->last_gsms);
}
#endif
+ if(apicall)
+ {
+ tpl_printf(vars, TPLADD, "PICONENABLED", "%d", cfg.http_showpicons?1:0);
+ }
tpl_addVar(vars, TPLADD, "READERNAMEENC", urlencode(vars, rdr->label));
if(!existing_insert)
{
@@ -2048,6 +2058,15 @@ static char *send_oscam_reader(struct templatevars *vars, struct uriparams *para
{
tpl_addVar(vars, TPLADD, "CLIENTPROTOSORT", (const char*)new_proto);
tpl_addVar(vars, TPLADD, "CLIENTPROTO", (const char*)new_proto);
+ if(cfg.http_showpicons)
+ {
+ char picon_name[32];
+ snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", new_proto);
+ if(picon_exists(picon_name))
+ {
+ tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s",(char*)new_proto);
+ }
+ }
if(rdr->cacheex.feature_bitfield & 32)
tpl_addVar(vars, TPLADD, "CLIENTPROTOTITLE", rdr->cacheex.aio_version);
@@ -2058,10 +2077,28 @@ static char *send_oscam_reader(struct templatevars *vars, struct uriparams *para
{
tpl_addVar(vars, TPLADD, "CLIENTPROTOSORT", proto);
tpl_addVar(vars, TPLADD, "CLIENTPROTO", proto);
+ if(cfg.http_showpicons)
+ {
+ char picon_name[32];
+ snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", proto);
+ if(picon_exists(picon_name))
+ {
+ tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s",(char *)proto);
+ }
+ }
}
#else
tpl_addVar(vars, TPLADD, "CLIENTPROTO", reader_get_type_desc(rdr, 0));
tpl_addVar(vars, TPLADD, "CLIENTPROTOSORT", reader_get_type_desc(rdr, 0));
+ if(cfg.http_showpicons)
+ {
+ char picon_name[32];
+ snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", reader_get_type_desc(rdr, 0));
+ if(picon_exists(picon_name))
+ {
+ tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s", reader_get_type_desc(rdr, 0));
+ }
+ }
#endif
switch(rdr->card_status)
{
@@ -2119,6 +2156,15 @@ static char *send_oscam_reader(struct templatevars *vars, struct uriparams *para
tpl_addVar(vars, TPLADD, "CLIENTPROTO", reader_get_type_desc(rdr, 0));
tpl_addVar(vars, TPLADD, "CLIENTPROTOSORT", reader_get_type_desc(rdr, 0));
+ if(cfg.http_showpicons)
+ {
+ char picon_name[32];
+ snprintf(picon_name, sizeof(picon_name) / sizeof(char) - 1, "%s", reader_get_type_desc(rdr, 0));
+ if(picon_exists(picon_name))
+ {
+ tpl_printf(vars, TPLADDONCE, "PROTOICON", "%s", reader_get_type_desc(rdr, 0));
+ }
+ }
}
}
@@ -2620,6 +2666,9 @@ static char *send_oscam_reader_config(struct templatevars *vars, struct uriparam
tpl_addVar(vars, TPLADD, "AUDISABLEDVALUE", (rdr->audisabled == 1) ? "1" : "0");
}
+ tpl_printf(vars, TPLADD, "TMP", "AUTYPE%d", rdr->autype);
+ tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected");
+
// AUprovid
if(rdr->auprovid)
{ tpl_printf(vars, TPLADD, "AUPROVID", "%06X", rdr->auprovid); }
@@ -2682,7 +2731,50 @@ static char *send_oscam_reader_config(struct templatevars *vars, struct uriparam
{ tpl_printf(vars, TPLAPPEND, "BOXKEY", "%02X", rdr->boxkey[i]); }
}
+#ifdef READER_CONAX
+ // CWPK Key
+ len = rdr->cwpk_mod_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len; i++) { tpl_printf(vars, TPLAPPEND, "CWPKKEY", "%02X", rdr->cwpk_mod[i]); }
+ }
+#endif
+
+#ifdef READER_NAGRA
+ // nuid (CAK6.3)
+ len = rdr->cak63nuid_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CAK63NUID", "%02X", rdr->cak63nuid[i]); }
+ }
+
+ // cwekey (CAK6.3)
+ len = rdr->cak63cwekey_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CAK63CWEKEY", "%02X", rdr->cak63cwekey[i]); }
+ }
+#endif
+
#ifdef READER_NAGRA_MERLIN
+ // idird (CAK7)
+ len = rdr->idird_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "IDIRD", "%02X", rdr->idird[i]); }
+ }
+
+ // cmd0e_provider (CAK7)
+ len = rdr->cmd0eprov_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CMD0EPROV", "%02X", rdr->cmd0eprov[i]); }
+ }
+
// mod1 (CAK7)
len = rdr->mod1_length;
if(len > 0)
@@ -2691,6 +2783,38 @@ static char *send_oscam_reader_config(struct templatevars *vars, struct uriparam
{ tpl_printf(vars, TPLAPPEND, "MOD1", "%02X", rdr->mod1[i]); }
}
+ // mod2 (CAK7)
+ len = rdr->mod2_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "MOD2", "%02X", rdr->mod2[i]); }
+ }
+
+ // key3588 (CAK7)
+ len = rdr->key3588_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "KEY3588", "%02X", rdr->key3588[i]); }
+ }
+
+ // key3310 (CAK7)
+ len = rdr->key3310_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "KEY3310", "%02X", rdr->key3310[i]); }
+ }
+
+ // key3460 (CAK7)
+ len = rdr->key3460_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "KEY3460", "%02X", rdr->key3460[i]); }
+ }
+
// data50 (CAK7)
len = rdr->data50_length;
if(len > 0)
@@ -2707,39 +2831,131 @@ static char *send_oscam_reader_config(struct templatevars *vars, struct uriparam
{ tpl_printf(vars, TPLAPPEND, "MOD50", "%02X", rdr->mod50[i]); }
}
- // key60 (CAK7)
- len = rdr->key60_length;
+ // nuid (CAK7)
+ len = rdr->nuid_length;
if(len > 0)
{
for(i = 0; i < len ; i++)
- { tpl_printf(vars, TPLAPPEND, "KEY60", "%02X", rdr->key60[i]); }
+ { tpl_printf(vars, TPLAPPEND, "NUID", "%02X", rdr->nuid[i]); }
}
- // exp60 (CAK7)
- len = rdr->exp60_length;
+ // OTP CSC (CAK7)
+ len = rdr->otpcsc_length;
if(len > 0)
{
for(i = 0; i < len ; i++)
- { tpl_printf(vars, TPLAPPEND, "EXP60", "%02X", rdr->exp60[i]); }
+ { tpl_printf(vars, TPLAPPEND, "OTPCSC", "%02X", rdr->otpcsc[i]); }
}
- // nuid (CAK7)
- len = rdr->nuid_length;
+ // OTA CSC (CAK7)
+ len = rdr->otacsc_length;
if(len > 0)
{
for(i = 0; i < len ; i++)
- { tpl_printf(vars, TPLAPPEND, "NUID", "%02X", rdr->nuid[i]); }
+ { tpl_printf(vars, TPLAPPEND, "OTACSC", "%02X", rdr->otacsc[i]); }
}
- // cwekey (CAK7)
- len = rdr->cwekey_length;
+ // Force Pairing Type (CAK7)
+ len = rdr->forcepair_length;
if(len > 0)
{
for(i = 0; i < len ; i++)
- { tpl_printf(vars, TPLAPPEND, "CWEKEY", "%02X", rdr->cwekey[i]); }
+ { tpl_printf(vars, TPLAPPEND, "FORCEPAIR", "%02X", rdr->forcepair[i]); }
}
+
+ // cwekey0 (CAK7)
+ len = rdr->cwekey0_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CWEKEY0", "%02X", rdr->cwekey0[i]); }
+ }
+
+ // cwekey1 (CAK7)
+ len = rdr->cwekey1_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CWEKEY1", "%02X", rdr->cwekey1[i]); }
+ }
+
+ // cwekey2 (CAK7)
+ len = rdr->cwekey2_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CWEKEY2", "%02X", rdr->cwekey2[i]); }
+ }
+
+ // cwekey3 (CAK7)
+ len = rdr->cwekey3_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CWEKEY3", "%02X", rdr->cwekey3[i]); }
+ }
+
+ // cwekey4 (CAK7)
+ len = rdr->cwekey4_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CWEKEY4", "%02X", rdr->cwekey4[i]); }
+ }
+
+ // cwekey5 (CAK7)
+ len = rdr->cwekey5_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CWEKEY5", "%02X", rdr->cwekey5[i]); }
+ }
+
+ // cwekey6 (CAK7)
+ len = rdr->cwekey6_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CWEKEY6", "%02X", rdr->cwekey6[i]); }
+ }
+
+ // cwekey7 (CAK7)
+ len = rdr->cwekey7_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CWEKEY7", "%02X", rdr->cwekey7[i]); }
+ }
+
+ // force_cw_swap
+ if(rdr->forcecwswap)
+ { tpl_addVar(vars, TPLADD, "FORCECWSWAPCHECKED", "checked"); }
+
+ // only_even_SA
+ if(rdr->evensa)
+ { tpl_addVar(vars, TPLADD, "EVENSACHECKED", "checked"); }
+
+ // force_EMM_82
+ if(rdr->forceemmg)
+ { tpl_addVar(vars, TPLADD, "FORCEEMMGCHECKED", "checked"); }
+
+ // OTA_CWPKs
+ if(rdr->cwpkota)
+ { tpl_addVar(vars, TPLADD, "CWPKOTACHECKED", "checked"); }
#endif
+ // CWPK CaID (CAK7)
+ len = rdr->cwpkcaid_length;
+ if(len > 0)
+ {
+ for(i = 0; i < len ; i++)
+ { tpl_printf(vars, TPLAPPEND, "CWPKCAID", "%02X", rdr->cwpkcaid[i]); }
+ }
+
+ // cak7_mode
+ if(rdr->cak7_mode)
+ { tpl_addVar(vars, TPLADD, "NAGRACAK7MODECHECKED", "checked"); }
+
// ins7E
if(rdr->ins7E[0x1A])
{
@@ -8434,7 +8650,7 @@ static char *send_oscam_api(struct templatevars * vars, FILE * f, struct uripara
cmd_pack->client = webif_client;
cmd_pack->cmdlen = strlen(getParam(params, "cmd")) / 2;
- if(cmd_pack->cmdlen > 0 && abs(cmd_pack->cmdlen) <= sizeof(cmd_pack->cmd))
+ if(cmd_pack->cmdlen > 0 && (unsigned long)abs(cmd_pack->cmdlen) <= sizeof(cmd_pack->cmd))
{
if(key_atob_l(getParam(params, "cmd"), cmd_pack->cmd, cmd_pack->cmdlen*2))
{
diff --git a/oscam-config-global.c b/oscam-config-global.c
index 164601c3a..2721602f2 100644
--- a/oscam-config-global.c
+++ b/oscam-config-global.c
@@ -591,7 +591,7 @@ static const struct config_list webif_opts[] =
DEF_OPT_INT8("http_status_log" , OFS(http_status_log) , 1),
#endif
#ifndef WEBIF_JQUERY
- DEF_OPT_STR("http_extern_jquery" , OFS(http_extern_jquery) , "//code.jquery.com/jquery-1.12.4.min.js"),
+ DEF_OPT_STR("http_extern_jquery" , OFS(http_extern_jquery) , "//code.jquery.com/jquery-3.7.1.min.js"),
#endif
DEF_LAST_OPT
};
@@ -910,23 +910,25 @@ static const struct config_list scam_opts[] =
static const struct config_list scam_opts[] = { DEF_LAST_OPT };
#endif
-#ifdef WITH_EMU
+#ifdef MODULE_STREAMRELAY
static bool streamrelay_should_save_fn(void *UNUSED(var))
{
- return 1;
+ return cfg.stream_relay_enabled;
}
static const struct config_list streamrelay_opts[] =
{
DEF_OPT_SAVE_FUNC(streamrelay_should_save_fn),
- DEF_OPT_STR("stream_source_host" , OFS(emu_stream_source_host), "127.0.0.1"),
- DEF_OPT_INT32("stream_source_port" , OFS(emu_stream_source_port), 8001),
- DEF_OPT_STR("stream_source_auth_user" , OFS(emu_stream_source_auth_user), NULL),
- DEF_OPT_STR("stream_source_auth_password" , OFS(emu_stream_source_auth_password), NULL),
- DEF_OPT_INT32("stream_relay_port" , OFS(emu_stream_relay_port), 17999),
- DEF_OPT_UINT32("stream_ecm_delay" , OFS(emu_stream_ecm_delay), 600),
- DEF_OPT_INT8("stream_relay_enabled" , OFS(emu_stream_relay_enabled), 1),
- DEF_OPT_INT8("stream_emm_enabled" , OFS(emu_stream_emm_enabled), 1),
- DEF_OPT_FUNC("stream_relay_ctab" , OFS(emu_stream_relay_ctab), check_caidtab_fn),
+ DEF_OPT_STR("stream_source_host" , OFS(stream_source_host), "127.0.0.1"),
+ DEF_OPT_INT32("stream_source_port" , OFS(stream_source_port), DEFAULT_STREAM_SOURCE_PORT),
+ DEF_OPT_STR("stream_source_auth_user" , OFS(stream_source_auth_user), NULL),
+ DEF_OPT_STR("stream_source_auth_password" , OFS(stream_source_auth_password), NULL),
+#ifdef MODULE_RADEGAST
+ DEF_OPT_INT8("stream_client_source_host" , OFS(stream_client_source_host), 0),
+#endif
+ DEF_OPT_INT32("stream_relay_port" , OFS(stream_relay_port), 17999),
+ DEF_OPT_INT8("stream_relay_enabled" , OFS(stream_relay_enabled), 0),
+ DEF_OPT_UINT32("stream_relay_buffer_time" , OFS(stream_relay_buffer_time), 0),
+ DEF_OPT_FUNC("stream_relay_ctab" , OFS(stream_relay_ctab), check_caidtab_fn),
DEF_LAST_OPT
};
#else
@@ -1355,6 +1357,9 @@ static const struct config_list dvbapi_opts[] =
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),
+#ifdef MODULE_STREAMRELAY
+ DEF_OPT_INT8("demuxer_fix" , OFS(dvbapi_demuxer_fix) , 0),
+#endif
DEF_OPT_FUNC("boxtype" , OFS(dvbapi_boxtype) , dvbapi_boxtype_fn),
DEF_OPT_FUNC("services" , OFS(dvbapi_sidtabs.ok) , dvbapi_services_fn),
// OBSOLETE OPTIONS
diff --git a/oscam-config-reader.c b/oscam-config-reader.c
index c91ae93fa..61a15324f 100644
--- a/oscam-config-reader.c
+++ b/oscam-config-reader.c
@@ -230,6 +230,43 @@ static void boxid_fn(const char *token, char *value, void *setting, FILE *f)
{ fprintf_conf(f, token, "\n"); }
}
+static void cwpkkey_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ // rdr_log(rdr, "CWPK config key length: %16X", len);
+ if(len == 0 || len > 32)
+ {
+ rdr->cwpk_mod_length = 0;
+ memset(rdr->cwpk_mod, 0, sizeof(rdr->cwpk_mod));
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cwpk_mod, len))
+ {
+ fprintf(stderr, "reader cwpkkey parse error, %s=%s\n", token, value);
+ rdr->cwpk_mod_length = 0;
+ memset(rdr->cwpk_mod, 0, sizeof(rdr->cwpk_mod));
+ }
+ else
+ {
+ rdr->cwpk_mod_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cwpk_mod_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cwpkkey", "%s\n", cs_hexdump(0, rdr->cwpk_mod, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cwpkkey", "\n"); }
+}
+
static void rsakey_fn(const char *token, char *value, void *setting, FILE *f)
{
struct s_reader *rdr = setting;
@@ -375,6 +412,150 @@ static void mod1_fn(const char *token, char *value, void *setting, FILE *f)
{ fprintf_conf(f, "mod1", "\n"); }
}
+static void mod2_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 224)
+ {
+ rdr->mod2_length = 0;
+ memset(rdr->mod2, 0, 112);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->mod2, len))
+ {
+ fprintf(stderr, "reader mod2 parse error, %s=%s\n", token, value);
+ rdr->mod2_length = 0;
+ memset(rdr->mod2, 0, sizeof(rdr->mod2));
+ }
+ else
+ {
+ rdr->mod2_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->mod2_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "mod2", "%s\n", cs_hexdump(0, rdr->mod2, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "mod2", "\n"); }
+}
+
+static void idird_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 8)
+ {
+ rdr->idird_length = 0;
+ memset(rdr->idird, 0, 4);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->idird, len))
+ {
+ fprintf(stderr, "reader idird parse error, %s=%s\n", token, value);
+ rdr->idird_length = 0;
+ memset(rdr->idird, 0, sizeof(rdr->idird));
+ }
+ else
+ {
+ rdr->idird_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->idird_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "idird", "%s\n", cs_hexdump(0, rdr->idird, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "idird", "\n"); }
+}
+
+static void cmd0eprov_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 4)
+ {
+ rdr->cmd0eprov_length = 0;
+ memset(rdr->cmd0eprov, 0, 2);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cmd0eprov, len))
+ {
+ fprintf(stderr, "reader cmd0eprov parse error, %s=%s\n", token, value);
+ rdr->cmd0eprov_length = 0;
+ memset(rdr->cmd0eprov, 0, sizeof(rdr->cmd0eprov));
+ }
+ else
+ {
+ rdr->cmd0eprov_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cmd0eprov_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cmd0eprov", "%s\n", cs_hexdump(0, rdr->cmd0eprov, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cmd0eprov", "\n"); }
+}
+
+static void key3588_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 272)
+ {
+ rdr->key3588_length = 0;
+ memset(rdr->key3588, 0, 136);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->key3588, len))
+ {
+ fprintf(stderr, "reader key3588 parse error, %s=%s\n", token, value);
+ rdr->key3588_length = 0;
+ memset(rdr->key3588, 0, sizeof(rdr->key3588));
+ }
+ else
+ {
+ rdr->key3588_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->key3588_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "key3588", "%s\n", cs_hexdump(0, rdr->key3588, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "key3588", "\n"); }
+}
+
static void data50_fn(const char *token, char *value, void *setting, FILE *f)
{
struct s_reader *rdr = setting;
@@ -447,7 +628,7 @@ static void mod50_fn(const char *token, char *value, void *setting, FILE *f)
{ fprintf_conf(f, "mod50", "\n"); }
}
-static void key60_fn(const char *token, char *value, void *setting, FILE *f)
+static void key3460_fn(const char *token, char *value, void *setting, FILE *f)
{
struct s_reader *rdr = setting;
if(value)
@@ -455,72 +636,70 @@ static void key60_fn(const char *token, char *value, void *setting, FILE *f)
int32_t len = cs_strlen(value);
if(len != 192)
{
- rdr->key60_length = 0;
- memset(rdr->key60, 0, 96);
+ rdr->key3460_length = 0;
+ memset(rdr->key3460, 0, 96);
}
else
{
- if(key_atob_l(value, rdr->key60, len))
+ if(key_atob_l(value, rdr->key3460, len))
{
- fprintf(stderr, "reader key60 parse error, %s=%s\n", token, value);
- rdr->key60_length = 0;
- memset(rdr->key60, 0, sizeof(rdr->key60));
+ fprintf(stderr, "reader key3460 parse error, %s=%s\n", token, value);
+ rdr->key3460_length = 0;
+ memset(rdr->key3460, 0, sizeof(rdr->key3460));
}
else
{
- rdr->key60_length = len/2;
+ rdr->key3460_length = len/2;
}
}
return;
}
- int32_t len = rdr->key60_length;
+ int32_t len = rdr->key3460_length;
if(len > 0)
{
char tmp[len * 2 + 1];
- fprintf_conf(f, "key60", "%s\n", cs_hexdump(0, rdr->key60, len, tmp, sizeof(tmp)));
+ fprintf_conf(f, "key3460", "%s\n", cs_hexdump(0, rdr->key3460, len, tmp, sizeof(tmp)));
}
else if(cfg.http_full_cfg)
- { fprintf_conf(f, "key60", "\n"); }
+ { fprintf_conf(f, "key3460", "\n"); }
}
-static void exp60_fn(const char *token, char *value, void *setting, FILE *f)
+static void key3310_fn(const char *token, char *value, void *setting, FILE *f)
{
struct s_reader *rdr = setting;
if(value)
{
int32_t len = cs_strlen(value);
- if(len != 192)
+ if(len != 32)
{
- rdr->exp60_length = 0;
- memset(rdr->exp60, 0, 96);
+ rdr->key3310_length = 0;
+ memset(rdr->key3310, 0, 16);
}
else
{
- if(key_atob_l(value, rdr->exp60, len))
+ if(key_atob_l(value, rdr->key3310, len))
{
- fprintf(stderr, "reader exp60 parse error, %s=%s\n", token, value);
- rdr->exp60_length = 0;
- memset(rdr->exp60, 0, sizeof(rdr->exp60));
+ fprintf(stderr, "reader key3310 parse error, %s=%s\n", token, value);
+ rdr->key3310_length = 0;
+ memset(rdr->key3310, 0, sizeof(rdr->key3310));
}
else
{
- rdr->exp60_length = len/2;
+ rdr->key3310_length = len/2;
}
}
return;
}
- int32_t len = rdr->exp60_length;
+ int32_t len = rdr->key3310_length;
if(len > 0)
{
char tmp[len * 2 + 1];
- fprintf_conf(f, "exp60", "%s\n", cs_hexdump(0, rdr->exp60, len, tmp, sizeof(tmp)));
+ fprintf_conf(f, "key3310", "%s\n", cs_hexdump(0, rdr->key3310, len, tmp, sizeof(tmp)));
}
else if(cfg.http_full_cfg)
- { fprintf_conf(f, "exp60", "\n"); }
+ { fprintf_conf(f, "key3310", "\n"); }
}
-#endif
-#if defined(READER_NAGRA_MERLIN) || defined(READER_NAGRA)
static void nuid_fn(const char *token, char *value, void *setting, FILE *f)
{
struct s_reader *rdr = setting;
@@ -557,7 +736,477 @@ static void nuid_fn(const char *token, char *value, void *setting, FILE *f)
{ fprintf_conf(f, "nuid", "\n"); }
}
-static void cwekey_fn(const char *token, char *value, void *setting, FILE *f)
+static void forcepair_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = cs_strlen(value);
+ if(len != 2)
+ {
+ rdr->forcepair_length = 0;
+ memset(rdr->forcepair, 0, 1);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->forcepair, len))
+ {
+ fprintf(stderr, "reader forcepair parse error, %s=%s\n", token, value);
+ rdr->forcepair_length = 0;
+ memset(rdr->forcepair, 0, sizeof(rdr->forcepair));
+ }
+ else
+ {
+ rdr->forcepair_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->forcepair_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "forcepair", "%s\n", cs_hexdump(0, rdr->forcepair, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "forcepair", "\n"); }
+}
+
+static void otpcsc_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 4)
+ {
+ rdr->otpcsc_length = 0;
+ memset(rdr->otpcsc, 0, 2);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->otpcsc, len))
+ {
+ fprintf(stderr, "reader otpcsc parse error, %s=%s\n", token, value);
+ rdr->otpcsc_length = 0;
+ memset(rdr->otpcsc, 0, sizeof(rdr->otpcsc));
+ }
+ else
+ {
+ rdr->otpcsc_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->otpcsc_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "otpcsc", "%s\n", cs_hexdump(0, rdr->otpcsc, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "otpcsc", "\n"); }
+}
+
+static void otacsc_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 4)
+ {
+ rdr->otacsc_length = 0;
+ memset(rdr->otacsc, 0, 2);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->otacsc, len))
+ {
+ fprintf(stderr, "reader otacsc parse error, %s=%s\n", token, value);
+ rdr->otacsc_length = 0;
+ memset(rdr->otacsc, 0, sizeof(rdr->otacsc));
+ }
+ else
+ {
+ rdr->otacsc_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->otacsc_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "otacsc", "%s\n", cs_hexdump(0, rdr->otacsc, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "otacsc", "\n"); }
+}
+
+static void cwpkcaid_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 4)
+ {
+ rdr->cwpkcaid_length = 0;
+ memset(rdr->cwpkcaid, 0, 2);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cwpkcaid, len))
+ {
+ fprintf(stderr, "reader cwpkcaid parse error, %s=%s\n", token, value);
+ rdr->cwpkcaid_length = 0;
+ memset(rdr->cwpkcaid, 0, sizeof(rdr->cwpkcaid));
+ }
+ else
+ {
+ rdr->cwpkcaid_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cwpkcaid_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cwpkcaid", "%s\n", cs_hexdump(0, rdr->cwpkcaid, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cwpkcaid", "\n"); }
+}
+
+static void cwekey0_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 32)
+ {
+ rdr->cwekey0_length = 0;
+ memset(rdr->cwekey0, 0, 16);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cwekey0, len))
+ {
+ fprintf(stderr, "reader cwekey0 parse error, %s=%s\n", token, value);
+ rdr->cwekey0_length = 0;
+ memset(rdr->cwekey0, 0, sizeof(rdr->cwekey0));
+ }
+ else
+ {
+ rdr->cwekey0_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cwekey0_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cwekey0", "%s\n", cs_hexdump(0, rdr->cwekey0, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cwekey0", "\n"); }
+}
+
+static void cwekey1_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 32)
+ {
+ rdr->cwekey1_length = 0;
+ memset(rdr->cwekey1, 0, 16);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cwekey1, len))
+ {
+ fprintf(stderr, "reader cwekey1 parse error, %s=%s\n", token, value);
+ rdr->cwekey1_length = 0;
+ memset(rdr->cwekey1, 0, sizeof(rdr->cwekey1));
+ }
+ else
+ {
+ rdr->cwekey1_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cwekey1_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cwekey1", "%s\n", cs_hexdump(0, rdr->cwekey1, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cwekey1", "\n"); }
+}
+
+static void cwekey2_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 32)
+ {
+ rdr->cwekey2_length = 0;
+ memset(rdr->cwekey2, 0, 16);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cwekey2, len))
+ {
+ fprintf(stderr, "reader cwekey2 parse error, %s=%s\n", token, value);
+ rdr->cwekey2_length = 0;
+ memset(rdr->cwekey2, 0, sizeof(rdr->cwekey2));
+ }
+ else
+ {
+ rdr->cwekey2_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cwekey2_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cwekey2", "%s\n", cs_hexdump(0, rdr->cwekey2, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cwekey2", "\n"); }
+}
+
+static void cwekey3_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 32)
+ {
+ rdr->cwekey3_length = 0;
+ memset(rdr->cwekey3, 0, 16);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cwekey3, len))
+ {
+ fprintf(stderr, "reader cwekey3 parse error, %s=%s\n", token, value);
+ rdr->cwekey3_length = 0;
+ memset(rdr->cwekey3, 0, sizeof(rdr->cwekey3));
+ }
+ else
+ {
+ rdr->cwekey3_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cwekey3_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cwekey3", "%s\n", cs_hexdump(0, rdr->cwekey3, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cwekey3", "\n"); }
+}
+
+static void cwekey4_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 32)
+ {
+ rdr->cwekey4_length = 0;
+ memset(rdr->cwekey4, 0, 16);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cwekey4, len))
+ {
+ fprintf(stderr, "reader cwekey4 parse error, %s=%s\n", token, value);
+ rdr->cwekey4_length = 0;
+ memset(rdr->cwekey4, 0, sizeof(rdr->cwekey4));
+ }
+ else
+ {
+ rdr->cwekey4_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cwekey4_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cwekey4", "%s\n", cs_hexdump(0, rdr->cwekey4, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cwekey4", "\n"); }
+}
+
+static void cwekey5_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 32)
+ {
+ rdr->cwekey5_length = 0;
+ memset(rdr->cwekey5, 0, 16);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cwekey5, len))
+ {
+ fprintf(stderr, "reader cwekey5 parse error, %s=%s\n", token, value);
+ rdr->cwekey5_length = 0;
+ memset(rdr->cwekey5, 0, sizeof(rdr->cwekey5));
+ }
+ else
+ {
+ rdr->cwekey5_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cwekey5_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cwekey5", "%s\n", cs_hexdump(0, rdr->cwekey5, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cwekey5", "\n"); }
+}
+
+static void cwekey6_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 32)
+ {
+ rdr->cwekey6_length = 0;
+ memset(rdr->cwekey6, 0, 16);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cwekey6, len))
+ {
+ fprintf(stderr, "reader cwekey6 parse error, %s=%s\n", token, value);
+ rdr->cwekey6_length = 0;
+ memset(rdr->cwekey6, 0, sizeof(rdr->cwekey6));
+ }
+ else
+ {
+ rdr->cwekey6_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cwekey6_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cwekey6", "%s\n", cs_hexdump(0, rdr->cwekey6, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cwekey6", "\n"); }
+}
+
+static void cwekey7_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = strlen(value);
+ if(len != 32)
+ {
+ rdr->cwekey7_length = 0;
+ memset(rdr->cwekey7, 0, 16);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cwekey7, len))
+ {
+ fprintf(stderr, "reader cwekey7 parse error, %s=%s\n", token, value);
+ rdr->cwekey7_length = 0;
+ memset(rdr->cwekey7, 0, sizeof(rdr->cwekey7));
+ }
+ else
+ {
+ rdr->cwekey7_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cwekey7_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cwekey7", "%s\n", cs_hexdump(0, rdr->cwekey7, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cwekey7", "\n"); }
+}
+#endif
+
+#if defined(READER_NAGRA)
+static void cak63nuid_fn(const char *token, char *value, void *setting, FILE *f)
+{
+ struct s_reader *rdr = setting;
+ if(value)
+ {
+ int32_t len = cs_strlen(value);
+ if(len != 8)
+ {
+ rdr->cak63nuid_length = 0;
+ memset(rdr->cak63nuid, 0, 4);
+ }
+ else
+ {
+ if(key_atob_l(value, rdr->cak63nuid, len))
+ {
+ fprintf(stderr, "reader cak63nuid parse error, %s=%s\n", token, value);
+ rdr->cak63nuid_length = 0;
+ memset(rdr->cak63nuid, 0, sizeof(rdr->cak63nuid));
+ }
+ else
+ {
+ rdr->cak63nuid_length = len/2;
+ }
+ }
+ return;
+ }
+ int32_t len = rdr->cak63nuid_length;
+ if(len > 0)
+ {
+ char tmp[len * 2 + 1];
+ fprintf_conf(f, "cak63nuid", "%s\n", cs_hexdump(0, rdr->cak63nuid, len, tmp, sizeof(tmp)));
+ }
+ else if(cfg.http_full_cfg)
+ { fprintf_conf(f, "cak63nuid", "\n"); }
+}
+
+static void cak63cwekey_fn(const char *token, char *value, void *setting, FILE *f)
{
struct s_reader *rdr = setting;
if(value)
@@ -565,32 +1214,32 @@ static void cwekey_fn(const char *token, char *value, void *setting, FILE *f)
int32_t len = cs_strlen(value);
if(len != 32)
{
- rdr->cwekey_length = 0;
- memset(rdr->cwekey, 0, 16);
+ rdr->cak63cwekey_length = 0;
+ memset(rdr->cak63cwekey, 0, 16);
}
else
{
- if(key_atob_l(value, rdr->cwekey, len))
+ if(key_atob_l(value, rdr->cak63cwekey, len))
{
- fprintf(stderr, "reader cwekey parse error, %s=%s\n", token, value);
- rdr->cwekey_length = 0;
- memset(rdr->cwekey, 0, sizeof(rdr->cwekey));
+ fprintf(stderr, "reader cak63cwekey parse error, %s=%s\n", token, value);
+ rdr->cak63cwekey_length = 0;
+ memset(rdr->cak63cwekey, 0, sizeof(rdr->cak63cwekey));
}
else
{
- rdr->cwekey_length = len/2;
+ rdr->cak63cwekey_length = len/2;
}
}
return;
}
- int32_t len = rdr->cwekey_length;
+ int32_t len = rdr->cak63cwekey_length;
if(len > 0)
{
char tmp[len * 2 + 1];
- fprintf_conf(f, "cwekey", "%s\n", cs_hexdump(0, rdr->cwekey, len, tmp, sizeof(tmp)));
+ fprintf_conf(f, "cak63cwekey", "%s\n", cs_hexdump(0, rdr->cak63cwekey, len, tmp, sizeof(tmp)));
}
else if(cfg.http_full_cfg)
- { fprintf_conf(f, "cwekey", "\n"); }
+ { fprintf_conf(f, "cak63cwekey", "\n"); }
}
#endif
@@ -1205,18 +1854,42 @@ static const struct config_list reader_opts[] =
DEF_OPT_FUNC("boxid" , 0, boxid_fn),
DEF_OPT_FUNC("boxkey" , 0, boxkey_fn),
DEF_OPT_FUNC("rsakey" , 0, rsakey_fn),
+ DEF_OPT_FUNC("cwpkkey" , 0, cwpkkey_fn),
DEF_OPT_FUNC("deskey" , 0, deskey_fn),
#ifdef READER_NAGRA_MERLIN
DEF_OPT_FUNC("mod1" , 0, mod1_fn),
+ DEF_OPT_FUNC("idird" , 0, idird_fn),
+ DEF_OPT_FUNC("cmd0eprov" , 0, cmd0eprov_fn),
+ DEF_OPT_FUNC("mod2" , 0, mod2_fn),
+ DEF_OPT_FUNC("key3588" , 0, key3588_fn),
+ DEF_OPT_FUNC("key3460" , 0, key3460_fn),
+ DEF_OPT_FUNC("key3310" , 0, key3310_fn),
DEF_OPT_FUNC("data50" , 0, data50_fn),
DEF_OPT_FUNC("mod50" , 0, mod50_fn),
- DEF_OPT_FUNC("key60" , 0, key60_fn),
- DEF_OPT_FUNC("exp60" , 0, exp60_fn),
-#endif
-#if defined(READER_NAGRA_MERLIN) || defined(READER_NAGRA)
DEF_OPT_FUNC("nuid" , 0, nuid_fn),
- DEF_OPT_FUNC("cwekey" , 0, cwekey_fn),
+ DEF_OPT_FUNC("forcepair" , 0, forcepair_fn),
+ DEF_OPT_FUNC("otpcsc" , 0, otpcsc_fn),
+ DEF_OPT_FUNC("otacsc" , 0, otacsc_fn),
+ DEF_OPT_FUNC("cwpkcaid" , 0, cwpkcaid_fn),
+ DEF_OPT_FUNC("cwekey0" , 0, cwekey0_fn),
+ DEF_OPT_FUNC("cwekey1" , 0, cwekey1_fn),
+ DEF_OPT_FUNC("cwekey2" , 0, cwekey2_fn),
+ DEF_OPT_FUNC("cwekey3" , 0, cwekey3_fn),
+ DEF_OPT_FUNC("cwekey4" , 0, cwekey4_fn),
+ DEF_OPT_FUNC("cwekey5" , 0, cwekey5_fn),
+ DEF_OPT_FUNC("cwekey6" , 0, cwekey6_fn),
+ DEF_OPT_FUNC("cwekey7" , 0, cwekey7_fn),
+ DEF_OPT_INT8("forcecwswap" , OFS(forcecwswap), 0),
+ DEF_OPT_INT8("evensa" , OFS(evensa), 0),
+ DEF_OPT_INT8("forceemmg" , OFS(forceemmg), 0),
+ DEF_OPT_INT8("cwpkota" , OFS(cwpkota), 0),
#endif
+#if defined(READER_NAGRA)
+ DEF_OPT_FUNC("cak63nuid" , 0, cak63nuid_fn),
+ DEF_OPT_FUNC("cak63cwekey" , 0, cak63cwekey_fn),
+#endif
+
+ DEF_OPT_INT8("cak7_mode" , OFS(cak7_mode), 0),
DEF_OPT_FUNC_X("ins7e" , OFS(ins7E), ins7E_fn, SIZEOF(ins7E)),
DEF_OPT_FUNC_X("ins42" , OFS(ins42), ins42_fn, SIZEOF(ins42)),
DEF_OPT_FUNC_X("ins7e11" , OFS(ins7E11), ins7E_fn, SIZEOF(ins7E11)),
@@ -1295,6 +1968,7 @@ static const struct config_list reader_opts[] =
#endif
DEF_OPT_INT8("deprecated" , OFS(deprecated), 0),
DEF_OPT_INT8("audisabled" , OFS(audisabled), 0),
+ DEF_OPT_INT8("autype" , OFS(autype), 0),
DEF_OPT_FUNC("auprovid" , 0, auprovid_fn),
DEF_OPT_INT8("ndsversion" , OFS(ndsversion), 0),
DEF_OPT_FUNC("ratelimitecm" , 0, ratelimitecm_fn),
@@ -1329,14 +2003,17 @@ static bool reader_check_setting(const struct config_list *UNUSED(clist), void *
"fix9993", "rsakey", "deskey", "ins7e", "ins42", "ins7e11", "ins2e06", "k1_generic", "k1_unique", "force_irdeto", "needsemmfirst", "boxkey",
"atr", "detect", "nagra_read", "mhz", "cardmhz", "readtiers", "read_old_classes", "use_gpio", "needsglobalfirst",
#ifdef READER_NAGRA_MERLIN
- "mod1", "data50", "mod50", "key60", "exp60",
+ "mod1", "idird", "cmd0eprov", "mod2", "key3588", "key3460", "key3310", "data50", "mod50", "nuid", "forcepair", "otpcsc", "otacsc", "cwpkcaid", "cwekey0", "cwekey1", "cwekey2", "cwekey3", "cwekey4", "cwekey5", "cwekey6", "cwekey7",
#endif
-#if defined(READER_NAGRA_MERLIN) || defined(READER_NAGRA)
- "nuid", "cwekey",
+#if defined(READER_NAGRA)
+ "cak63nuid", "cak63cwekey",
#endif
#if defined(READER_DRE) || defined(READER_DRECAS)
"exec_cmd_file",
#endif
+#ifdef READER_CONAX
+ "cwpkkey",
+#endif
#ifdef WITH_AZBOX
"mode",
#endif
@@ -1346,7 +2023,7 @@ static bool reader_check_setting(const struct config_list *UNUSED(clist), void *
// These are written only when the reader is network reader
static const char *network_only_settings[] =
{
- "user", "inactivitytimeout", "reconnecttimeout",
+ "user", "inactivitytimeout", "reconnecttimeout", "autype",
0
};
if(is_network_reader(reader))
diff --git a/oscam-config.c b/oscam-config.c
index 530a7e629..f4bdfeb89 100644
--- a/oscam-config.c
+++ b/oscam-config.c
@@ -13,12 +13,9 @@
#include "oscam-string.h"
#include "oscam-time.h"
-extern uint16_t len4caid[256];
-
#define cs_srid "oscam.srvid"
#define cs_ratelimit "oscam.ratelimit"
#define cs_trid "oscam.tiers"
-#define cs_l4ca "oscam.guess"
#define cs_sidt "oscam.services"
#define cs_whitelist "oscam.whitelist"
#define cs_provid "oscam.provid"
@@ -1391,46 +1388,6 @@ void global_whitelist_read(void)
}
}
-void init_len4caid(void)
-{
- FILE *fp = open_config_file(cs_l4ca);
- if(!fp)
- { return; }
-
- int32_t nr;
- char *value, *token;
-
- if(!cs_malloc(&token, MAXLINESIZE))
- { return; }
-
- memset(len4caid, 0, sizeof(uint16_t) << 8);
- for(nr = 0; fgets(token, MAXLINESIZE, fp);)
- {
- int32_t i, c;
- char *ptr;
- if(!(value = strchr(token, ':')))
- { continue; }
- *value++ = '\0';
- if((ptr = strchr(value, '#')))
- { * ptr = '\0'; }
- if(cs_strlen(trim(token)) != 2)
- { continue; }
- if(cs_strlen(trim(value)) != 4)
- { continue; }
- if((i = byte_atob(token)) < 0)
- { continue; }
- if((c = word_atob(value)) < 0)
- { continue; }
- len4caid[i] = c;
- nr++;
- }
- NULLFREE(token);
- fclose(fp);
- if(nr)
- { cs_log("%d lengths for caid guessing loaded", nr); }
- return;
-}
-
#ifdef MODULE_SERIAL
static struct s_twin *twin_read_int(void)
{
diff --git a/oscam-config.h b/oscam-config.h
index a430ce360..e66a1aa1c 100644
--- a/oscam-config.h
+++ b/oscam-config.h
@@ -38,7 +38,6 @@ int32_t init_provid(void);
int32_t init_srvid(void);
int32_t init_tierid(void);
int32_t init_fakecws(void);
-void init_len4caid(void);
#ifdef MODULE_SERIAL
struct ecmtw get_twin(ECM_REQUEST *er); // get twin channel
diff --git a/oscam-ecm.c b/oscam-ecm.c
index 489fb380c..4bccafcff 100644
--- a/oscam-ecm.c
+++ b/oscam-ecm.c
@@ -7,7 +7,6 @@
#include "module-led.h"
#include "module-stat.h"
#include "module-webif.h"
-#include "module-ird-guess.h"
#include "module-cw-cycle-check.h"
#include "module-gbox.h"
#include "oscam-cache.h"
@@ -30,7 +29,6 @@
extern CS_MUTEX_LOCK ecmcache_lock;
extern struct ecm_request_t *ecmcwcache;
-extern uint16_t len4caid[256];
extern uint32_t ecmcwcache_size;
extern int32_t exit_oscam;
@@ -2142,41 +2140,6 @@ int32_t write_ecm_answer(struct s_reader *reader, ECM_REQUEST *er, int8_t rc, ui
return res;
}
-static void guess_cardsystem(ECM_REQUEST *er)
-{
- uint16_t last_hope = 0;
-
- // viaccess - check by provid-search
- if((er->prid = chk_provid(er->ecm, 0x500)))
- { er->caid = 0x500; }
-
- // nagra
- // is ecm[1] always 0x30 ?
- // is ecm[3] always 0x07 ?
- if((er->ecm[6] == 1) && (er->ecm[4] == er->ecm[2] - 2))
- { er->caid = 0x1801; }
-
- // seca2 - very poor
- if((er->ecm[8] == 0x10) && ((er->ecm[9] & 0xF1) == 1))
- { last_hope = 0x100; }
-
- // is cryptoworks, but which caid ?
- if((er->ecm[3] == 0x81) && (er->ecm[4] == 0xFF) &&
- (!er->ecm[5]) && (!er->ecm[6]) && (er->ecm[7] == er->ecm[2] - 5))
- {
- last_hope = 0xd00;
- }
-
- if(!er->caid && er->ecm[2] == 0x31 && er->ecm[0x0b] == 0x28)
- { guess_irdeto(er); }
-
- if(!er->caid) // guess by len...
- { er->caid = len4caid[er->ecm[2] + 3]; }
-
- if(!er->caid)
- { er->caid = last_hope; }
-}
-
// chid calculation from module stat to here
// to improve the quickfix concerning ecm chid info and extend it
// to all client requests wereby the chid is known in module stat
@@ -2474,27 +2437,9 @@ void get_cw(struct s_client *client, ECM_REQUEST *er)
snprintf(er->msglog, sizeof(er->msglog), "invalid user group %s", username(client));
}
- if(!er->caid)
- { guess_cardsystem(er); }
-
- /* Quickfix Area */
-
// add chid for all client requests as in module stat
update_chid(er);
- // quickfix for 0100:000065
- if(er->caid == 0x100 && er->prid == 0x65 && er->srvid == 0)
- { er->srvid = 0x0642; }
-
- // Quickfixes for Opticum/Globo HD9500
- // Quickfix for 0500:030300
- if(er->caid == 0x500 && er->prid == 0x030300)
- { er->prid = 0x030600; }
-
- // Quickfix for 0500:D20200
- if(er->caid == 0x500 && er->prid == 0xD20200)
- { er->prid = 0x030600; }
-
// betacrypt ecm with nagra header
if(chk_is_betatunnel_caid(er->caid) == 1 && (er->ecmlen == 0x89 || er->ecmlen == 0x4A) && er->ecm[3] == 0x07 && (er->ecm[4] == 0x84 || er->ecm[4] == 0x45))
{
diff --git a/oscam-emm.c b/oscam-emm.c
index fc75799c8..d0df4bab5 100644
--- a/oscam-emm.c
+++ b/oscam-emm.c
@@ -165,7 +165,31 @@ int32_t emm_reader_match(struct s_reader *reader, uint16_t caid, uint32_t provid
if(reader->audisabled)
{ return 0; }
- if(reader->caid != caid)
+ if(reader->cwpkcaid_length && reader->nuid_length)
+ {
+ uint8_t check[1];
+ check[0] = caid & 0xFF;
+ if(check[0] == reader->cwpkcaid[1])
+ {
+ return 1;
+ }
+ }
+
+ uint16_t emmcaid;
+ if(reader->caid == 0x186D)
+ {
+ emmcaid = reader->caid - 0x03;
+ }
+ else if (reader->caid == 0x1856)
+ {
+ emmcaid = reader->caid + 0x28;
+ }
+ else
+ {
+ emmcaid = reader->caid;
+ }
+
+ if(emmcaid != caid)
{
int caid_found = 0;
if (!reader->csystem)
@@ -173,13 +197,13 @@ int32_t emm_reader_match(struct s_reader *reader, uint16_t caid, uint32_t provid
for(i = 0; reader->csystem->caids[i]; i++)
{
uint16_t cs_caid = reader->csystem->caids[i];
- if (reader->caid && cs_caid == caid)
+ if (emmcaid && cs_caid == caid)
{
caid_found = 1;
break;
}
- if ((reader->caid == 0) && chk_ctab_ex(caid, &reader->ctab))
+ if ((emmcaid == 0) && chk_ctab_ex(caid, &reader->ctab))
{
caid_found = 1;
break;
@@ -188,7 +212,7 @@ int32_t emm_reader_match(struct s_reader *reader, uint16_t caid, uint32_t provid
}
if(!caid_found)
{
- rdr_log_dbg(reader, D_EMM, "reader_caid %04X != emmpid caid %04X -> SKIP!", reader->caid, caid);
+ rdr_log_dbg(reader, D_EMM, "reader_caid %04X != emmpid caid %04X -> SKIP!", emmcaid, caid);
return 0;
}
}
diff --git a/oscam-work.c b/oscam-work.c
index 148dc7dc4..bee981dc1 100644
--- a/oscam-work.c
+++ b/oscam-work.c
@@ -11,9 +11,6 @@
#include "oscam-string.h"
#include "oscam-work.h"
#include "reader-common.h"
-#ifdef READER_NAGRA_MERLIN
-#include "reader-nagracak7.h"
-#endif
#include "module-cccam.h"
#include "module-cccam-data.h"
#include "module-cccshare.h"
@@ -130,6 +127,7 @@ void *work_thread(void *ptr)
cl->work_mbuf = mbuf; // Track locally allocated data, because some callback may call cs_exit/cs_disconect_client/pthread_exit and then mbuf would be leaked
int32_t n = 0, rc = 0, i, idx, s, dblvl;
+ (void)dblvl;
uint8_t dcw[16];
int8_t restart_reader = 0;
@@ -305,6 +303,7 @@ void *work_thread(void *ptr)
break;
case ACTION_READER_SENDCMD:
+#ifdef WITH_CARDREADER
dblvl = cs_dblevel;
cs_dblevel = dblvl | D_READER;
rc = cardreader_do_rawcmd(reader, data->ptr);
@@ -323,6 +322,7 @@ void *work_thread(void *ptr)
}
}
cs_dblevel = dblvl;
+#endif
break;
case ACTION_READER_CARDINFO:
@@ -330,14 +330,10 @@ void *work_thread(void *ptr)
break;
case ACTION_READER_POLL_STATUS:
+#ifdef READER_VIDEOGUARD
cardreader_poll_status(reader);
- break;
-
-#ifdef READER_NAGRA_MERLIN
- case ACTION_READER_RENEW_SK:
- CAK7_getCamKey(reader);
- break;
#endif
+ break;
case ACTION_READER_INIT:
if(!cl->init_done)
diff --git a/oscam-work.h b/oscam-work.h
index 5fb9e75ea..ac8368957 100644
--- a/oscam-work.h
+++ b/oscam-work.h
@@ -16,10 +16,7 @@ enum actions
ACTION_READER_CHECK_HEALTH = 11, // wr11
ACTION_READER_CAPMT_NOTIFY = 12, // wr12
ACTION_READER_POLL_STATUS = 13, // wr13
-#ifdef READER_NAGRA_MERLIN
- ACTION_READER_RENEW_SK = 14, // wr14
-#endif
- ACTION_READER_SENDCMD = 15, // wr15
+ ACTION_READER_SENDCMD = 14, // wr14
// Client actions
ACTION_CLIENT_UDP = 22, // wc22
ACTION_CLIENT_TCP = 23, // wc23
diff --git a/oscam.c b/oscam.c
index 137a7ded3..93809669f 100644
--- a/oscam.c
+++ b/oscam.c
@@ -16,13 +16,13 @@
#include "module-dvbapi-mca.h"
#include "module-dvbapi-chancache.h"
#include "module-gbox-sms.h"
-#include "module-ird-guess.h"
#include "module-lcd.h"
#include "module-led.h"
#include "module-stat.h"
#include "module-webif.h"
#include "module-webif-tpl.h"
#include "module-cw-cycle-check.h"
+#include "module-streamrelay.h"
#include "oscam-chk.h"
#include "oscam-cache.h"
#include "oscam-client.h"
@@ -43,7 +43,6 @@
#ifdef WITH_EMU
void add_emu_reader(void);
- void stop_stream_server(void);
#endif
#ifdef WITH_SSL
@@ -90,7 +89,6 @@ struct s_client *first_client = NULL; // Pointer to clients list, first client i
struct s_reader *first_active_reader = NULL; // list of active readers (enable=1 deleted = 0)
LLIST *configured_readers = NULL; // list of all (configured) readers
-uint16_t len4caid[256]; // table for guessing caid (by len)
char cs_confdir[128];
uint16_t cs_dblevel = 0; // Debug Level
int32_t thread_pipe[2] = {0, 0};
@@ -149,7 +147,7 @@ static void show_usage(void)
"| |_| |___) | |_| (_| | | | | | |\n"
" \\___/|____/ \\___\\__,_|_| |_| |_|\n\n");
printf("OSCam Cardserver v%s, build r%s (%s)\n", CS_VERSION, CS_SVN_VERSION, CS_TARGET);
- printf("Copyright (C) 2009-2020 OSCam developers.\n");
+ printf("Copyright (C) 2009-2024 OSCam developers.\n");
printf("This program is distributed under GPLv3.\n");
printf("OSCam is based on Streamboard mp-cardserver v0.9d written by dukat\n");
printf("Visit https://board.streamboard.tv/ for more details.\n\n");
@@ -416,6 +414,10 @@ static void write_versionfile(bool use_stdout)
write_conf(HAVE_DVBAPI, "DVB API support");
if(config_enabled(HAVE_DVBAPI))
{
+ if(config_enabled(MODULE_STREAMRELAY))
+ {
+ write_conf(true, "DVB API with Stream Relay support");
+ }
write_conf(WITH_AZBOX, "DVB API with AZBOX support");
write_conf(WITH_MCA, "DVB API with MCA support");
write_conf(WITH_COOLAPI, "DVB API with COOLAPI support");
@@ -425,7 +427,6 @@ static void write_versionfile(bool use_stdout)
write_conf(WITH_NEUTRINO, "DVB API with NEUTRINO support");
write_conf(READ_SDT_CHARSETS, "DVB API read-sdt charsets");
}
- write_conf(IRDETO_GUESSING, "Irdeto guessing");
write_conf(CS_ANTICASC, "Anti-cascading support");
write_conf(WITH_DEBUG, "Debug mode");
write_conf(MODULE_MONITOR, "Monitor");
@@ -444,6 +445,9 @@ static void write_versionfile(bool use_stdout)
case CLOCK_TYPE_MONOTONIC: write_conf(CLOCKFIX, "Clockfix with monotonic clock"); break;
}
write_conf(IPV6SUPPORT, "IPv6 support");
+#if defined(__arm__) || defined(__aarch64__)
+ write_conf(WITH_ARM_NEON, "ARM NEON (SIMD/MPE) support");
+#endif
write_conf(WITH_EMU, "Emulator support");
write_conf(WITH_SOFTCAM, "Built-in SoftCam.Key");
@@ -461,6 +465,7 @@ static void write_versionfile(bool use_stdout)
write_conf(MODULE_CONSTCW, "constant CW");
write_conf(MODULE_PANDORA, "Pandora");
write_conf(MODULE_GHTTP, "ghttp");
+ write_conf(MODULE_STREAMRELAY, "Streamrelay");
fprintf(fp, "\n");
write_conf(WITH_CARDREADER, "Reader support");
@@ -1843,6 +1848,9 @@ int32_t main(int32_t argc, char *argv[])
init_sidtab();
init_readerdb();
+#ifdef MODULE_STREAMRELAY
+ init_stream_server();
+#endif
#ifdef WITH_EMU
add_emu_reader();
#endif
@@ -1857,9 +1865,6 @@ int32_t main(int32_t argc, char *argv[])
cacheex_init();
- init_len4caid();
- init_irdeto_guess_tab();
-
write_versionfile(false);
led_init();
@@ -1934,7 +1939,7 @@ int32_t main(int32_t argc, char *argv[])
#ifdef MODULE_GBOX
stop_gbx_ticker();
#endif
-#ifdef WITH_EMU
+#ifdef MODULE_STREAMRELAY
stop_stream_server();
#endif
webif_close();
@@ -1993,7 +1998,6 @@ int32_t main(int32_t argc, char *argv[])
cfg.account = NULL;
init_free_sidtab();
free_readerdb();
- free_irdeto_guess_tab();
config_free();
ssl_done();
diff --git a/reader-common.c b/reader-common.c
index 5df23a694..cb6753f7b 100644
--- a/reader-common.c
+++ b/reader-common.c
@@ -37,6 +37,11 @@ static void reader_nullcard(struct s_reader *reader)
reader->csystem = NULL;
memset(reader->hexserial, 0, sizeof(reader->hexserial));
memset(reader->prid, 0xFF, sizeof(reader->prid));
+ memset(reader->sa, 0, sizeof(reader->sa));
+ memset(reader->emm84, 0, sizeof(reader->emm84));
+ memset(reader->emm83s, 0, sizeof(reader->emm83s));
+ memset(reader->emm83u, 0, sizeof(reader->emm83u));
+ memset(reader->emm87, 0, sizeof(reader->emm87));
reader->caid = 0;
reader->nprov = 0;
cs_clear_entitlement(reader);
diff --git a/reader-conax.c b/reader-conax.c
index 00317be77..3b08ade26 100644
--- a/reader-conax.c
+++ b/reader-conax.c
@@ -2,6 +2,91 @@
#ifdef READER_CONAX
#include "cscrypt/bn.h"
#include "reader-common.h"
+#include "cscrypt/des.h"
+
+static int32_t CWPK_CNX(struct s_reader *reader,uint8_t *msg)
+{
+int32_t ret = 0;
+
+uint8_t CWp1[8];
+uint8_t CWp2[8];
+uint8_t CWs1[8];
+uint8_t CWs2[8];
+
+CWp1[0] = msg[7];
+CWp1[1] = msg[8];
+CWp1[2] = msg[9];
+CWp1[3] = msg[10];
+CWp1[4] = msg[11];
+CWp1[5] = msg[12];
+CWp1[6] = msg[13];
+CWp1[7] = msg[14];
+
+CWp2[0] = msg[22];
+CWp2[1] = msg[23];
+CWp2[2] = msg[24];
+CWp2[3] = msg[25];
+CWp2[4] = msg[26];
+CWp2[5] = msg[27];
+CWp2[6] = msg[28];
+CWp2[7] = msg[29];
+
+des_ecb3_decrypt(CWp1,reader->cwpk_mod);
+des_ecb3_decrypt(CWp2,reader->cwpk_mod);
+CWs1[0] = CWp1[4];
+CWs1[1] = CWp1[5];
+CWs1[2] = CWp1[6];
+CWs1[3] = CWp1[7];
+CWs1[4] = CWp1[0];
+CWs1[5] = CWp1[1];
+CWs1[6] = CWp1[2];
+CWs1[7] = CWp1[3];
+
+CWs2[0] = CWp2[4];
+CWs2[1] = CWp2[5];
+CWs2[2] = CWp2[6];
+CWs2[3] = CWp2[7];
+CWs2[4] = CWp2[0];
+CWs2[5] = CWp2[1];
+CWs2[6] = CWp2[2];
+CWs2[7] = CWp2[3];
+
+int chkok = 1;
+if(((CWs1[0] + CWs1[1] + CWs1[2]) & 0xFF) != CWs1[3])
+{
+ chkok = 0;
+ rdr_log(reader, "CW0 checksum error [0]");
+}
+if(((CWs1[4] + CWs1[5] + CWs1[6]) & 0xFF) != CWs1[7])
+{
+ chkok = 0;
+ rdr_log(reader, "CW0 checksum error [1]");
+}
+if(((CWs2[0] + CWs2[1] + CWs2[2]) & 0xFF) != CWs2[3])
+{
+ chkok = 0;
+ rdr_log(reader, "CW1 checksum error [0]");
+}
+if(((CWs2[4] + CWs2[5] + CWs2[6]) & 0xFF) != CWs2[7])
+{
+ chkok = 0;
+ rdr_log(reader, "CW1 checksum error [1]");
+}
+
+if(chkok == 1)
+{
+ memcpy(&msg[7],CWs1,0x08);
+ memcpy(&msg[22],CWs2,0x08);
+
+ ret = 0;
+}
+if(chkok != 1)
+{
+ ret = -8;
+}
+
+return ret;
+}
static int32_t RSA_CNX(struct s_reader *reader, uint8_t *msg, uint8_t *mod, uint8_t *exp, uint32_t cta_lr, uint32_t modbytes, uint32_t expbytes)
{
@@ -114,6 +199,26 @@ static int32_t read_record(struct s_reader *reader, const uint8_t *cmd, const ui
return (cta_lr - 2);
}
+static int32_t check_pairing(struct s_reader *reader, const uint8_t *cmd, const uint8_t *data, uint8_t *cta_res)
+{
+ uint16_t cta_lr;
+
+ if(reader->cwpk_mod_length)
+ {
+ write_cmd(cmd, data);
+ rdr_log(reader, "CWPK Pairing is active");
+ }
+ else if(reader->rsa_mod_length)
+ {
+ rdr_log(reader, "RSA Pairing is active");
+ }
+ else
+ {
+ rdr_log(reader, "Pairing is not active");
+ }
+ return OK;
+}
+
static uint8_t PairingECMRotation(struct s_reader *reader, const ECM_REQUEST *er, int32_t n)
{
uint8_t cta_res[CTA_RES_LEN] = { 0x00 };
@@ -147,6 +252,7 @@ static int32_t conax_card_init(struct s_reader *reader, ATR *newatr)
uint8_t cta_res[CTA_RES_LEN];
int32_t i, j, n;
static const uint8_t ins26[] = { 0xDD, 0x26, 0x00, 0x00, 0x03, 0x10, 0x01, 0x40 };
+ static const uint8_t inscp[] = { 0xDD, 0x26, 0x00, 0x00, 0x04, 0x6C, 0x02, 0x10,0x00 };
uint8_t ins82[] = { 0xDD, 0x82, 0x00, 0x00, 0x11, 0x11, 0x0f, 0x01, 0xb0, 0x0f, 0xff,
0xff, 0xfb, 0x00, 0x00, 0x09, 0x04, 0x0b, 0x00, 0xe0, 0x30, 0x2b };
@@ -213,6 +319,7 @@ static int32_t conax_card_init(struct s_reader *reader, ATR *newatr)
rdr_log(reader, "Provider: %d Provider-Id: %06X", j + 1, b2i(4, reader->prid[j]));
rdr_log_sensitive(reader, "Provider: %d SharedAddress: {%08X}", j + 1, b2i(4, reader->sa[j]));
}
+ check_pairing(reader, inscp, inscp + 5, cta_res);
return OK;
}
@@ -239,16 +346,37 @@ static int32_t conax_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, stru
uint8_t exp[] = { 0x01, 0x00, 0x01 };
uint8_t buf[256];
+ char ppp = 0x00;
+
if((n = check_sct_len(er->ecm, 3)) < 0)
{ return ERROR; }
buf[0] = 0x14;
buf[1] = n + 1;
- if(0x0 != PairingECMRotation(reader, er, n))
- { buf[2] = 2; } // card will answer with encrypted dw
+ if(reader->cwpk_mod_length)
+ {
+ buf[2] = 4;
+ ppp = 0x01;
+ }
+ else if(0x0 != reader->rsa_mod[0])
+ {
+ if(0x0 != PairingECMRotation(reader, er, n))
+ {
+ buf[2] = 2;
+ ppp = 0x03;
+ }
+ else
+ {
+ buf[2] = 0;
+ ppp = 0x02;
+ }
+ }
else
- { buf[2] = 0; }
+ {
+ buf[2] = 0;
+ ppp = 0x02;
+ }
memcpy(buf + 3, er->ecm, n);
insA2[4] = n + 3;
@@ -263,13 +391,25 @@ static int32_t conax_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, stru
if((cta_res[cta_lr - 2] == 0x98) || ((cta_res[cta_lr - 2] == 0x90)))
{
/*checks if answer is encrypted with RSA algo and decrypts it if needed*/
- if(0x81 == cta_res[0] && 2 == cta_res[2] >> 5) /*81 XX 5X*/
+ if(0x81 == cta_res[0] && 2 == cta_res[2] >> 5 && 0x03 == ppp) /*81 XX 5X*/
{
if(0x00 == cta_res[cta_lr - 1])
{ rc = RSA_CNX(reader, cta_res, reader->rsa_mod, exp, cta_lr, 64u, 3u); }
else
{ rc = -4; } /*card has no right to decode this channel*/
}
+ else if(0x01 == ppp)
+ {
+ if(0x00 == cta_res[cta_lr - 1])
+ {
+ /*trying to decode using CWPK*/
+ rc = CWPK_CNX(reader, cta_res); /*enabled when no loging needed*/
+ }
+ else
+ {
+ rc = -4;
+ }
+ }
if(0 == rc)
{
@@ -341,6 +481,10 @@ static int32_t conax_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, stru
case -4:
rdr_log(reader, "card has no right to decode this channel");
break;
+
+ case -8:
+ rdr_log(reader, "CWPK is faulty");
+ break;
}
/* answer 9011 - conax smart card need reset */
diff --git a/reader-dre-cas.c b/reader-dre-cas.c
index d3bc3815d..642a27e85 100644
--- a/reader-dre-cas.c
+++ b/reader-dre-cas.c
@@ -236,14 +236,20 @@ static int32_t drecas_MSP_command(struct s_reader *reader, const uint8_t *cmd, i
return OK;
}
+#define drecas_MSP_script_nb(cmd, len) \
+ drecas_MSP_command(reader, cmd, len, cta_res, &cta_lr); \
+
#define drecas_MSP_script(cmd, len) \
{ \
- drecas_MSP_command(reader, cmd, len, cta_res, &cta_lr); \
+ drecas_MSP_script_nb(cmd, len) \
}
+#define drecas_MSP_cmd_nb(cmd) \
+ drecas_MSP_command(reader, cmd, sizeof(cmd), cta_res, &cta_lr); \
+
#define drecas_MSP_cmd(cmd) \
{ \
- drecas_MSP_command(reader, cmd, sizeof(cmd), cta_res, &cta_lr); \
+ drecas_MSP_cmd_nb(cmd) \
}
static int32_t drecas_STM_command(struct s_reader *reader, const uint8_t *cmd, int32_t cmdlen, uint8_t *cta_res, uint16_t *p_cta_lr)
@@ -342,14 +348,20 @@ static int32_t drecas_STM_command(struct s_reader *reader, const uint8_t *cmd, i
return OK;
}
+#define drecas_STM_script_nb(cmd, len) \
+ drecas_STM_command(reader, cmd, len, cta_res, &cta_lr); \
+
#define drecas_STM_script(cmd, len) \
{ \
- drecas_STM_command(reader, cmd, len, cta_res, &cta_lr); \
+ drecas_STM_script_nb(cmd, len) \
}
+#define drecas_STM_cmd_nb(cmd) \
+ drecas_STM_command(reader, cmd, sizeof(cmd), cta_res, &cta_lr); \
+
#define drecas_STM_cmd(cmd) \
{ \
- drecas_STM_command(reader, cmd, sizeof(cmd), cta_res, &cta_lr); \
+ drecas_STM_cmd_nb(cmd) \
}
static int32_t drecas_set_provider_info(struct s_reader *reader)
@@ -363,7 +375,7 @@ static int32_t drecas_set_provider_info(struct s_reader *reader)
cs_clear_entitlement(reader);
- if((drecas_MSP_cmd(subscr))) // ask subscription packages, returns error on 0x11 card
+ if(({drecas_MSP_cmd_nb(subscr)})) // ask subscription packages, returns error on 0x11 card
{
uint8_t pbm[32];
char tmp_dbg[65];
@@ -451,12 +463,12 @@ static int32_t drecas_card_init(struct s_reader *reader, ATR *newatr)
cmd54[1] = csystem_data->provider;
uint8_t geocode = 0;
- if((drecas_MSP_cmd(cmd54))) // error would not be fatal, like on 0x11 cards
+ if(({drecas_MSP_cmd_nb(cmd54)})) // error would not be fatal, like on 0x11 cards
{ geocode = cta_res[7]; }
providers[1] = csystem_data->provider;
- if(!(drecas_MSP_cmd(providers)))
+ if(!({drecas_MSP_cmd_nb(providers)}))
{ return ERROR; } // fatal error
if((cta_res[2] != 0x09) || (cta_res[3] != 0xC0))
@@ -557,11 +569,11 @@ static int32_t drecas_card_init(struct s_reader *reader, ATR *newatr)
if(tempbuf[0] != '7' && tempbuf[1] != '4')
{
- rdr_log(reader, "Script %s", (drecas_MSP_script(usercmd, cmd_len)) ? "done" : "error");
+ rdr_log(reader, "Script %s", ({drecas_MSP_script_nb(usercmd, cmd_len)}) ? "done" : "error");
}
else
{
- rdr_log(reader, "Script %s", (drecas_STM_script(usercmd, cmd_len)) ? "done" : "error");
+ rdr_log(reader, "Script %s", ({drecas_STM_script_nb(usercmd, cmd_len)}) ? "done" : "error");
}
}
while(!feof(pFile));
@@ -637,7 +649,7 @@ static int32_t drecas_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, str
ecmcmd51[33] = csystem_data->provider; // no part of sig
- if((drecas_MSP_cmd(ecmcmd51))) // ecm request
+ if(({drecas_MSP_cmd_nb(ecmcmd51)})) // ecm request
{
if((cta_res[2] != 0x09) || (cta_res[3] != 0xC0))
{ return ERROR; } // exit if response is not 90 00
@@ -665,7 +677,7 @@ static int32_t drecas_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, str
return ERROR;
}
- if(!(drecas_STM_cmd(stm_keys_t.stmcmd34[er->ecm[5] + (er->ecm[6] == 0x3B ? 0 : 32)])))
+ if(!({drecas_STM_cmd_nb(stm_keys_t.stmcmd34[er->ecm[5] + (er->ecm[6] == 0x3B ? 0 : 32)])}))
{
rdr_log_dbg(reader, D_READER, "Error STM set key: %s",cs_hexdump(0, cta_res, cta_lr, tmp_dbg, sizeof(tmp_dbg)));
return ERROR;
@@ -681,7 +693,7 @@ static int32_t drecas_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, str
stm_curkey[0] = er->ecm[5];
stm_curkey[1] = er->ecm[6];
- if(!(drecas_STM_cmd(ecmcmd33)))
+ if(!({drecas_STM_cmd_nb(ecmcmd33)}))
{ return ERROR; }
if(cta_res[1] != 0x17 || cta_res[6] != 0xD2)
@@ -745,7 +757,7 @@ static int32_t drecas_do_emm(struct s_reader *reader, EMM_PACKET *ep)
memcpy(&emmcmd58[1], &ep->emm[40], 24);
emmcmd58[25] = csystem_data->provider;
- if((drecas_MSP_cmd(emmcmd58)))
+ if(({drecas_MSP_cmd_nb(emmcmd58)}))
if((cta_res[2] != 0x09) || (cta_res[3] != 0xC0))
{ return ERROR; }
}
@@ -765,7 +777,7 @@ static int32_t drecas_do_emm(struct s_reader *reader, EMM_PACKET *ep)
emmcmd52[0x39] = csystem_data->provider;
- if((drecas_MSP_cmd(emmcmd52)))
+ if(({drecas_MSP_cmd_nb(emmcmd52)}))
if((cta_res[2] != 0x09) || (cta_res[3] != 0xC0))
{ return ERROR; } // exit if response is not 90 00
}
@@ -802,7 +814,7 @@ static int32_t drecas_do_emm(struct s_reader *reader, EMM_PACKET *ep)
emmcmd52[0x39] = csystem_data->provider;
- if((drecas_MSP_cmd(emmcmd52)))
+ if(({drecas_MSP_cmd_nb(emmcmd52)}))
if((cta_res[2] != 0x09) || (cta_res[3] != 0xC0))
{ return ERROR; } // exit if response is not 90 00
}
diff --git a/reader-dre.c b/reader-dre.c
index f9d922234..0cafe07e4 100644
--- a/reader-dre.c
+++ b/reader-dre.c
@@ -177,19 +177,28 @@ static int32_t dre_command(struct s_reader *reader, const uint8_t *cmd, int32_t
return OK;
}
+#define dre_script_nb(cmd, len, cmd_type, crypted, keynum) \
+ dre_command(reader, cmd, len, cta_res, &cta_lr, crypted, keynum, crypted, cmd_type); \
+
#define dre_script(cmd, len, cmd_type, crypted, keynum) \
{ \
- dre_command(reader, cmd, len, cta_res, &cta_lr, crypted, keynum, crypted, cmd_type); \
+ dre_script_nb(cmd, len, cmd_type, crypted, keynum) \
}
+#define dre_cmd_nb(cmd) \
+ dre_command(reader, cmd, sizeof(cmd), cta_res, &cta_lr, 0, 0, 0, 0); \
+
#define dre_cmd(cmd) \
{ \
- dre_command(reader, cmd, sizeof(cmd), cta_res, &cta_lr, 0, 0, 0, 0); \
+ dre_cmd_nb(cmd) \
}
+#define dre_cmd_c_nb(cmd,crypted,keynum) \
+ dre_command(reader, cmd, sizeof(cmd),cta_res,&cta_lr, crypted, keynum, 1, 0); \
+
#define dre_cmd_c(cmd,crypted,keynum) \
{ \
- dre_command(reader, cmd, sizeof(cmd),cta_res,&cta_lr, crypted, keynum, 1, 0); \
+ dre_cmd_c_nb(cmd,crypted,keynum) \
}
static int32_t dre_set_provider_info(struct s_reader *reader)
@@ -236,7 +245,7 @@ static int32_t dre_set_provider_info(struct s_reader *reader)
chk_subscr:
- if((dre_script(subscr, subscr_cmd_len, 0, 0, 0))) // ask subscription packages, returns error on 0x11 card
+ if(({dre_script_nb(subscr, subscr_cmd_len, 0, 0, 0)})) // ask subscription packages, returns error on 0x11 card
{
uint8_t pbm[subscr_len];
char tmp_dbg[subscr_len*2+1];
@@ -411,7 +420,7 @@ static int32_t dre_card_init(struct s_reader *reader, ATR *newatr)
switch(atr[6])
{
case 0:
- if(!(dre_cmd(cmd56))) { return ERROR; }
+ if(!({dre_cmd_nb(cmd56)})) { return ERROR; }
if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00)) { return ERROR; }
switch(cta_res[4])
@@ -483,11 +492,11 @@ static int32_t dre_card_init(struct s_reader *reader, ATR *newatr)
cmd54[1] = csystem_data->provider;
uint8_t geocode = 0;
- if((dre_cmd(cmd54))) // error would not be fatal, like on 0x11 cards
+ if(({dre_cmd_nb(cmd54)})) // error would not be fatal, like on 0x11 cards
{ geocode = cta_res[3]; }
providers[1] = csystem_data->provider;
- if(!(dre_cmd(providers)))
+ if(!({dre_cmd_nb(providers)}))
{ return ERROR; } // fatal error
if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00))
@@ -639,7 +648,7 @@ static int32_t dre_card_init(struct s_reader *reader, ATR *newatr)
/*ret =*/
- rdr_log(reader, "Script %s", (dre_script(usercmd, cmd_len, ignoreProvid, crypted, cryptkey)) ? "done" : "error");
+ rdr_log(reader, "Script %s", ({dre_script_nb(usercmd, cmd_len, ignoreProvid, crypted, cryptkey)}) ? "done" : "error");
}
while(!feof(pFile));
}
@@ -708,7 +717,7 @@ static int32_t dre_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct
rdr_log_dbg(reader, D_READER, "unused ECM info front:%s", cs_hexdump(0, er->ecm, 8, tmp_dbg, sizeof(tmp_dbg)));
rdr_log_dbg(reader, D_READER, "unused ECM info back:%s", cs_hexdump(0, er->ecm + 24, er->ecm[2] + 2 - 24, tmp_dbg, sizeof(tmp_dbg)));
- if((dre_cmd(ecmcmd41))) // ecm request
+ if(({dre_cmd_nb(ecmcmd41)})) // ecm request
{
if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00))
{ return ERROR; } // exit if response is not 90 00
@@ -734,7 +743,7 @@ static int32_t dre_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct
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(({dre_cmd_nb(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
@@ -863,7 +872,7 @@ static int32_t dre_do_emm(struct s_reader *reader, EMM_PACKET *ep)
memcpy(&emmcmd58[1], &ep->emm[40], 24);
emmcmd58[25] = csystem_data->provider;
- if((dre_cmd(emmcmd58)))
+ if(({dre_cmd_nb(emmcmd58)}))
if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00))
{ return ERROR; }
}
@@ -882,7 +891,7 @@ static int32_t dre_do_emm(struct s_reader *reader, EMM_PACKET *ep)
emmcmd52[0x39] = csystem_data->provider;
- if((dre_cmd(emmcmd52)))
+ if(({dre_cmd_nb(emmcmd52)}))
if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00))
{ return ERROR; } // exit if response is not 90 00
}
@@ -918,7 +927,7 @@ static int32_t dre_do_emm(struct s_reader *reader, EMM_PACKET *ep)
emmcmd52[0x39] = csystem_data->provider;
- if((dre_cmd(emmcmd52)))
+ if(({dre_cmd_nb(emmcmd52)}))
if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00))
{ return ERROR; } // exit if response is not 90 00
}
@@ -1031,7 +1040,7 @@ static int32_t dre_do_emm(struct s_reader *reader, EMM_PACKET *ep)
memcpy(&emmcmd91[9], &ep->emm[keypos], 8);
- if((dre_cmd(emmcmd91)))
+ if(({dre_cmd_nb(emmcmd91)}))
if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00) || (cta_res[2] != 0xA2))
return ERROR; // exit if response is not 90 00
@@ -1188,7 +1197,7 @@ static int32_t dre_do_emm(struct s_reader *reader, EMM_PACKET *ep)
emmcmd42[49] = ep->emm[i * 49 + 41]; // keynr
emmcmd42[50] = 0x58 + ep->emm[40]; // package nr
emmcmd42[51] = csystem_data->provider;
- if((dre_cmd(emmcmd42)))
+ if(({dre_cmd_nb(emmcmd42)}))
{
if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00))
{ return ERROR; } // exit if response is not 90 00
@@ -1208,7 +1217,7 @@ static int32_t dre_do_emm(struct s_reader *reader, EMM_PACKET *ep)
59 05 A2 02 05 01 5B
90 00 */
- if((dre_cmd(emmcmd42))) // first emm request
+ if(({dre_cmd_nb(emmcmd42)})) // first emm request
{
if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00))
{ return ERROR; } // exit if response is not 90 00
@@ -1221,7 +1230,7 @@ static int32_t dre_do_emm(struct s_reader *reader, EMM_PACKET *ep)
emmcmd42[50] = 0x58;
emmcmd42[49] = ep->emm[54]; // keynr
- if((dre_cmd(emmcmd42))) // second emm request
+ if(({dre_cmd_nb(emmcmd42)})) // second emm request
{
if((cta_res[cta_lr - 2] != 0x90) || (cta_res[cta_lr - 1] != 0x00))
{ return ERROR; } // exit if response is not 90 00
diff --git a/reader-nagra-common.c b/reader-nagra-common.c
index eaf40c88c..0b044398a 100644
--- a/reader-nagra-common.c
+++ b/reader-nagra-common.c
@@ -2,83 +2,661 @@
#include "reader-common.h"
#include "reader-nagra-common.h"
-// returns 1 if shared emm matches SA, unique emm matches serial, or global or unknown
+int32_t get_prov_idx(struct s_reader *rdr, const uint8_t *provid)
+{
+ int prov;
+ for(prov = 0; prov < rdr->nprov; prov++) // search for provider index
+ {
+ if(!memcmp(provid, &rdr->prid[prov][2], 2))
+ {
+ return (prov);
+ }
+ }
+ return (-1);
+}
+
int32_t nagra_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
{
- switch(ep->emm[0])
+ if(rdr->cak7type == 3 || rdr->autype == 1)
{
- case 0x83:
- memset(ep->hexserial, 0x00, 0x08);
- ep->hexserial[0] = ep->emm[5];
- ep->hexserial[1] = ep->emm[4];
- ep->hexserial[2] = ep->emm[3];
- if(ep->emm[7] == 0x10)
- {
+ int i;
+
+ switch(ep->emm[0])
+ {
+ case 0x82:
+ memset(ep->hexserial, 0, 8);
+ memcpy(ep->hexserial, ep->emm + 3, 6);
+ if(!memcmp(rdr->hexserial, ep->hexserial, 6))
+ {
+ ep->type = UNIQUE;
+ return 1;
+ }
+ else if ((ep->emm[3] == 0x00) && (ep->emm[4] == 0x00) && (ep->emm[5] == 0x00) && (ep->emm[6] == 0x00) && (ep->emm[7] == 0x00) && (ep->emm[8] == 0xD3) && (ep->emm[9] == 0x87))
+ {
+ ep->type = GLOBAL;
+ return 1;
+ }
+ return 0;
+
+ case 0x84:
ep->type = SHARED;
- return (!memcmp(rdr->sa[0], ep->hexserial, 0x03));
- }
- else
- {
- ep->hexserial[3] = ep->emm[6];
+ memset(ep->hexserial, 0, 8);
+ memcpy(ep->hexserial, ep->emm + 5, 3);
+ i = get_prov_idx(rdr, ep->emm + 3);
+
+ if(i == -1)
+ {
+ return 0;
+ }
+
+ return (!memcmp(rdr->sa[i], ep->hexserial, 3));
+
+ case 0x83:
+ ep->type = GLOBAL;
+ uint8_t filtr[] = {0x83, 0x00, 0x74};
+ return (!memcmp(ep->emm, filtr, 3));
+
+ case 0x90:
ep->type = UNIQUE;
- return (!memcmp(rdr->hexserial + 2, ep->hexserial, 0x04));
- }
+ if(rdr->cwpkcaid_length && rdr->nuid_length)
+ {
+ memset(ep->hexserial, 0x00, 0x08);
+ ep->hexserial[0] = ep->emm[5];
+ ep->hexserial[1] = ep->emm[4];
+ ep->hexserial[2] = ep->emm[3];
+ ep->hexserial[3] = ep->emm[6];
+ return (!memcmp(rdr->nuid, ep->hexserial, 4));
+ }
+ return 0;
+
+ default:
+ ep->type = UNKNOWN;
+ return 0;
+ }
+ }
+ else if(rdr->cak7type == 1)
+ {
+ int i;
+ switch(ep->emm[0])
+ {
+ case 0x82:
+ ep->type = GLOBAL;
+ if(rdr->emm82 == 1 && ep->emm[3] == 0x00 && ep->emm[4] == 0x00 && ep->emm[5] == 0x00)
+ {
+ return 1;
+ }
+ return 0;
+
+ case 0x83:
+ if(ep->emm[7] == 0x10)
+ {
+ ep->type = SHARED;
+
+ for(i = 0; i < rdr->nemm83s; i++)
+ {
+ if(!memcmp(rdr->emm83s[i] + 1, ep->emm + 3, 0x03))
+ {
+ return 1;
+ }
+ }
+ }
+ else
+ {
+ ep->type = UNIQUE;
+
+ for(i = 0; i < rdr->nemm83u; i++)
+ {
+ if(!memcmp(rdr->emm83u[i] + 1, ep->emm + 3, 0x04))
+ {
+ return 1;
+ }
+ }
+ }
+ return 0;
- case 0x82:
- ep->type = GLOBAL;
- return 1;
+ case 0x84:
+ ep->type = GLOBAL;
- default:
- ep->type = UNKNOWN;
- return 1;
+ for(i = 0; i < rdr->nemm84; i++)
+ {
+ if(!memcmp(rdr->emm84[i] + 1, ep->emm + 3, 0x02))
+ {
+ return 1;
+ }
+ }
+ return 0;
+
+ case 0x87:
+ ep->type = SHARED;
+
+ for(i = 0; i < rdr->nemm87; i++)
+ {
+ if(!memcmp(rdr->emm87[i] + 1, ep->emm + 3, 0x04))
+ {
+ return 1;
+ }
+ }
+ return 0;
+
+ case 0x90:
+ ep->type = UNIQUE;
+ if(rdr->cwpkcaid_length && rdr->nuid_length)
+ {
+ memset(ep->hexserial, 0x00, 0x08);
+ ep->hexserial[0] = ep->emm[5];
+ ep->hexserial[1] = ep->emm[4];
+ ep->hexserial[2] = ep->emm[3];
+ ep->hexserial[3] = ep->emm[6];
+ return (!memcmp(rdr->nuid, ep->hexserial, 4));
+ }
+ return 0;
+
+ default:
+ ep->type = UNKNOWN;
+ return 0;
+ }
+ }
+ else if(rdr->autype == 2)
+ {
+ int i;
+ switch(ep->emm[0])
+ {
+ case 0x82:
+ ep->type = GLOBAL;
+ if(ep->emm[3] == 0x00 && ep->emm[4] == 0x00 && ep->emm[5] == 0x00)
+ {
+ return 1;
+ }
+ return 0;
+
+ case 0x83:
+ memset(ep->hexserial, 0x00, 0x08);
+ ep->hexserial[0] = ep->emm[5];
+ ep->hexserial[1] = ep->emm[4];
+ ep->hexserial[2] = ep->emm[3];
+ if(ep->emm[7] == 0x10)
+ {
+ ep->type = SHARED;
+
+ for(i = 0; i < rdr->nprov; i++)
+ {
+ if(!memcmp(rdr->sa[i], "\x00\x00\x00", 3))
+ {
+ continue;
+ }
+
+ if(!memcmp(rdr->sa[i], ep->hexserial, 0x03))
+ {
+ return 1;
+ }
+ }
+ }
+ else
+ {
+ ep->hexserial[3] = ep->emm[6];
+ ep->type = UNIQUE;
+
+ return (!memcmp(rdr->hexserial + 2, ep->hexserial, 0x04));
+ }
+ return 0;
+
+ case 0x84:
+ ep->type = GLOBAL;
+ return 1;
+
+ case 0x87:
+ memset(ep->hexserial, 0x00, 0x08);
+ ep->hexserial[0] = ep->emm[5];
+ ep->hexserial[1] = ep->emm[4];
+ ep->hexserial[2] = ep->emm[3];
+ ep->hexserial[3] = ep->emm[6];
+ ep->type = SHARED;
+
+ for(i = 0; i < rdr->nprov; i++)
+ {
+ if(!memcmp(rdr->sa[i], "\x00\x00\x00", 3))
+ {
+ continue;
+ }
+ if(!memcmp(rdr->sa[i], ep->hexserial, 0x04))
+ {
+ return 1;
+ }
+ }
+ return 0;
+
+ default:
+ ep->type = UNKNOWN;
+ return 0;
+ }
+ }
+ else
+ {
+ int i;
+ switch(ep->emm[0])
+ {
+ case 0x82:
+ memset(ep->hexserial, 0x00, 0x08);
+ ep->hexserial[0] = ep->emm[5];
+ ep->hexserial[1] = ep->emm[6];
+ ep->hexserial[2] = ep->emm[7];
+ ep->hexserial[3] = ep->emm[8];
+ if (!memcmp(rdr->hexserial + 2, ep->hexserial, 0x04))
+ {
+ ep->type = UNIQUE;
+ return 1;
+ }
+ else if ((ep->emm[3] == 0x00) && (ep->emm[4] == 0x00) && (ep->emm[5] == 0x00) && (ep->emm[6] == 0x00) && (ep->emm[7] == 0x00) && ((ep->emm[8] == 0x04) || (ep->emm[8] == 0xD3)) && ((ep->emm[9] == 0x84) || (ep->emm[9] == 0x8F) || (ep->emm[9] == 0x87)))
+ {
+ ep->type = GLOBAL;
+ return 1;
+ }
+ return 0;
+
+ case 0x84:
+ memset(ep->hexserial, 0x00, 0x08);
+ memcpy(ep->hexserial, ep->emm + 5, 3);
+ if ((ep->emm[2] == 0x77) && (ep->emm[3] == 0x00))
+ {
+ ep->type = SHARED;
+ i = get_prov_idx(rdr, ep->emm + 3);
+
+ if(i == -1)
+ {
+ return 0;
+ }
+
+ return (!memcmp(rdr->sa[i], ep->hexserial, 3));
+ }
+ else if ((ep->emm[3] == 0x00) && ((ep->emm[4] == 0x71) || (ep->emm[4] == 0x32) || (ep->emm[4] == 0xEC)) && (ep->emm[5] == 0x00) && (ep->emm[6] == 0x00) && (ep->emm[7] == 0x00) && (ep->emm[8] == 0x04) && (ep->emm[9] == 0x84))
+ {
+ ep->type = GLOBAL;
+ return 1;
+ }
+ return 0;
+
+ case 0x83:
+ memset(ep->hexserial, 0x00, 0x08);
+ ep->hexserial[0] = ep->emm[5];
+ ep->hexserial[1] = ep->emm[4];
+ ep->hexserial[2] = ep->emm[3];
+ ep->hexserial[3] = ep->emm[6];
+ if(ep->emm[7] == 0x10)
+ {
+ ep->type = SHARED;
+
+ for(i = 0; i < rdr->nprov; i++)
+ {
+ if(!memcmp(rdr->sa[i], "\x00\x00\x00", 3))
+ {
+ continue;
+ }
+
+ if(!memcmp(rdr->sa[i], ep->hexserial, 0x03))
+ {
+ return 1;
+ }
+ }
+ }
+ else if (!memcmp(rdr->hexserial + 2, ep->hexserial, 0x04))
+ {
+ ep->type = UNIQUE;
+ return 1;
+ }
+ else if ((ep->emm[5] == 0x04) && (ep->emm[6] == 0x70))
+ {
+ ep->type = GLOBAL;
+ return 1;
+ }
+ return 0;
+
+ case 0x87:
+ memset(ep->hexserial, 0x00, 0x08);
+ ep->hexserial[0] = ep->emm[5];
+ ep->hexserial[1] = ep->emm[4];
+ ep->hexserial[2] = ep->emm[3];
+ ep->hexserial[3] = ep->emm[6];
+ ep->type = SHARED;
+
+ for(i = 0; i < rdr->nprov; i++)
+ {
+ if(!memcmp(rdr->sa[i], "\x00\x00\x00", 3))
+ {
+ continue;
+ }
+ if(!memcmp(rdr->sa[i], ep->hexserial, 0x03))
+ {
+ return 1;
+ }
+ }
+ return 0;
+
+ default:
+ ep->type = UNKNOWN;
+ return 0;
+ }
}
}
int32_t nagra_get_emm_filter(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count)
{
- if(*emm_filters == NULL)
+ if(rdr->cak7type == 3 || rdr->autype == 1)
+ {
+ if(*emm_filters == NULL)
+ {
+ const unsigned int max_filter_count = 2 + (2 * rdr->nprov);
+ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
+ {
+ return ERROR;
+ }
+
+ struct s_csystem_emm_filter *filters = *emm_filters;
+ *filter_count = 0;
+
+ int32_t idx = 0;
+
+ filters[idx].type = EMM_UNIQUE;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x82;
+ filters[idx].mask[0] = 0xFF;
+ memcpy(&filters[idx].filter[1], rdr->hexserial, 6);
+ memset(&filters[idx].mask[1], 0xFF, 6);
+ idx++;
+
+ int32_t prov;
+ for(prov = 0; prov < rdr->nprov; prov++)
+ {
+ if(!memcmp(rdr->sa[prov], "\x00\x00\x00", 3))
+ {
+ continue;
+ }
+
+ filters[idx].type = EMM_GLOBAL;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x83;
+ filters[idx].mask[0] = 0xFF;
+ memcpy(&filters[idx].filter[1], &rdr->prid[prov][2], 2);
+ memset(&filters[idx].mask[1], 0xFF, 2);
+ idx++;
+
+ filters[idx].type = EMM_SHARED;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x84;
+ filters[idx].mask[0] = 0xFF;
+ memcpy(&filters[idx].filter[1], &rdr->prid[prov][2], 2);
+ memset(&filters[idx].mask[1], 0xFF, 2);
+ memcpy(&filters[idx].filter[3], &rdr->sa[prov], 3);
+ memset(&filters[idx].mask[3], 0xFF, 3);
+ idx++;
+ }
+
+ if(rdr->cwpkcaid_length && rdr->nuid_length)
+ {
+ filters[idx].type = EMM_UNIQUE;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x90;
+ filters[idx].filter[1] = rdr->nuid[2];
+ filters[idx].filter[2] = rdr->nuid[1];
+ filters[idx].filter[3] = rdr->nuid[0];
+ filters[idx].filter[4] = rdr->nuid[3];
+ memset(&filters[idx].mask[0], 0xFF, 5);
+ idx++;
+ }
+
+ *filter_count = idx;
+ }
+
+ return OK;
+ }
+ else if(rdr->cak7type == 1)
{
- const unsigned int max_filter_count = 3;
- if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
+ if(*emm_filters == NULL)
{
- return ERROR;
+ const unsigned int max_filter_count = 2 + (4 * rdr->nprov);
+ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
+ {
+ return ERROR;
+ }
+
+ struct s_csystem_emm_filter *filters = *emm_filters;
+ *filter_count = 0;
+
+ int32_t idx = 0;
+
+ if(rdr->emm82 == 1)
+ {
+ filters[idx].type = EMM_GLOBAL;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x82;
+ filters[idx].mask[0] = 0xFF;
+ idx++;
+ }
+
+ int32_t i;
+ for(i = 0; i < rdr->nemm83u; i++)
+ {
+ filters[idx].type = EMM_UNIQUE;
+ filters[idx].enabled = 1;
+ memcpy(&filters[idx].filter[0], rdr->emm83u[i], 6);
+ memset(&filters[idx].mask[0], 0xFF, 6);
+ idx++;
+ }
+
+ for(i = 0; i < rdr->nemm83s; i++)
+ {
+ filters[idx].type = EMM_SHARED;
+ filters[idx].enabled = 1;
+ memcpy(&filters[idx].filter[0], rdr->emm83s[i], 6);
+ memset(&filters[idx].mask[0], 0xFF, 6);
+ idx++;
+ }
+
+ for(i = 0; i < rdr->nemm84; i++)
+ {
+ filters[idx].type = EMM_GLOBAL;
+ filters[idx].enabled = 1;
+ memcpy(&filters[idx].filter[0], rdr->emm84[i], 3);
+ memset(&filters[idx].mask[0], 0xFF, 3);
+ idx++;
+ }
+
+ for(i = 0; i < rdr->nemm87; i++)
+ {
+ filters[idx].type = EMM_SHARED;
+ filters[idx].enabled = 1;
+ memcpy(&filters[idx].filter[0], rdr->emm87[i], 6);
+ memset(&filters[idx].mask[0], 0xFF, 6);
+ idx++;
+ }
+
+ if(rdr->cwpkcaid_length && rdr->nuid_length)
+ {
+ filters[idx].type = EMM_UNIQUE;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x90;
+ filters[idx].filter[1] = rdr->nuid[2];
+ filters[idx].filter[2] = rdr->nuid[1];
+ filters[idx].filter[3] = rdr->nuid[0];
+ filters[idx].filter[4] = rdr->nuid[3];
+ memset(&filters[idx].mask[0], 0xFF, 5);
+ idx++;
+ }
+
+ *filter_count = idx;
}
- struct s_csystem_emm_filter *filters = *emm_filters;
- *filter_count = 0;
-
- int32_t idx = 0;
-
- filters[idx].type = EMM_UNIQUE;
- filters[idx].enabled = 1;
- filters[idx].filter[0] = 0x83;
- filters[idx].filter[1] = rdr->hexserial[4];
- filters[idx].filter[2] = rdr->hexserial[3];
- filters[idx].filter[3] = rdr->hexserial[2];
- filters[idx].filter[4] = rdr->hexserial[5];
- filters[idx].filter[5] = 0x00;
- memset(&filters[idx].mask[0], 0xFF, 6);
- idx++;
-
- filters[idx].type = EMM_SHARED;
- filters[idx].enabled = 1;
- filters[idx].filter[0] = 0x83;
- filters[idx].filter[1] = rdr->sa[0][2];
- filters[idx].filter[2] = rdr->sa[0][1];
- filters[idx].filter[3] = rdr->sa[0][0];
- filters[idx].filter[4] = 0x00;
- filters[idx].filter[5] = 0x10;
- memset(&filters[idx].mask[0], 0xFF, 6);
- idx++;
-
- filters[idx].type = EMM_GLOBAL;
- filters[idx].enabled = 1;
- filters[idx].filter[0] = 0x82;
- filters[idx].mask[0] = 0xFF;
- idx++;
-
- *filter_count = idx;
+ return OK;
}
+ else if(rdr->autype == 2)
+ {
+ if(*emm_filters == NULL)
+ {
+ const unsigned int max_filter_count = 3 + (2 * rdr->nprov);
+ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
+ {
+ return ERROR;
+ }
+
+ struct s_csystem_emm_filter *filters = *emm_filters;
+ *filter_count = 0;
+
+ int32_t idx = 0;
+
+ filters[idx].type = EMM_GLOBAL;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x82;
+ filters[idx].mask[0] = 0xFF;
+ idx++;
+
+ filters[idx].type = EMM_GLOBAL;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x84;
+ filters[idx].mask[0] = 0xFF;
+ idx++;
+
+ filters[idx].type = EMM_UNIQUE;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x83;
+ filters[idx].filter[1] = rdr->hexserial[4];
+ filters[idx].filter[2] = rdr->hexserial[3];
+ filters[idx].filter[3] = rdr->hexserial[2];
+ filters[idx].filter[4] = rdr->hexserial[5];
+ filters[idx].filter[5] = 0x00;
+ memset(&filters[idx].mask[0], 0xFF, 6);
+ idx++;
+
+ int i;
+ for(i = 0; i < rdr->nprov; i++)
+ {
+ if(!memcmp(rdr->sa[i], "\x00\x00\x00", 3))
+ {
+ continue;
+ }
+
+ filters[idx].type = EMM_SHARED;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x83;
+ filters[idx].filter[1] = rdr->sa[i][2];
+ filters[idx].filter[2] = rdr->sa[i][1];
+ filters[idx].filter[3] = rdr->sa[i][0];
+ filters[idx].filter[4] = 0x00;
+ filters[idx].filter[5] = 0x10;
+ memset(&filters[idx].mask[0], 0xFF, 6);
+ idx++;
- return OK;
+ filters[idx].type = EMM_SHARED;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x87;
+ filters[idx].filter[1] = rdr->sa[i][2];
+ filters[idx].filter[2] = rdr->sa[i][1];
+ filters[idx].filter[3] = rdr->sa[i][0];
+ filters[idx].filter[4] = rdr->sa[i][3];
+ filters[idx].filter[5] = 0x00;
+ memset(&filters[idx].mask[0], 0xFF, 6);
+ idx++;
+ }
+
+ *filter_count = idx;
+ }
+
+ return OK;
+ }
+ else
+ {
+ if(*emm_filters == NULL)
+ {
+ const unsigned int max_filter_count = 5 + (3 * rdr->nprov);
+ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
+ {
+ return ERROR;
+ }
+
+ struct s_csystem_emm_filter *filters = *emm_filters;
+ *filter_count = 0;
+
+ int32_t idx = 0;
+
+ filters[idx].type = EMM_UNIQUE;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x82;
+ filters[idx].mask[0] = 0xFF;
+ memcpy(&filters[idx].filter[1], rdr->hexserial, 6);
+ memset(&filters[idx].mask[1], 0xFF, 6);
+ idx++;
+
+ filters[idx].type = EMM_UNIQUE;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x83;
+ filters[idx].filter[1] = rdr->hexserial[4];
+ filters[idx].filter[2] = rdr->hexserial[3];
+ filters[idx].filter[3] = rdr->hexserial[2];
+ filters[idx].filter[4] = rdr->hexserial[5];
+ filters[idx].filter[5] = 0x00;
+ memset(&filters[idx].mask[0], 0xFF, 6);
+ idx++;
+
+ filters[idx].type = EMM_GLOBAL;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x82;
+ filters[idx].mask[0] = 0xFF;
+ idx++;
+
+ filters[idx].type = EMM_GLOBAL;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x84;
+ filters[idx].mask[0] = 0xFF;
+ idx++;
+
+ filters[idx].type = EMM_GLOBAL;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x83;
+ filters[idx].mask[0] = 0xFF;
+ idx++;
+
+ int32_t prov;
+ for(prov = 0; prov < rdr->nprov; prov++)
+ {
+ if(!memcmp(rdr->sa[prov], "\x00\x00\x00", 3))
+ {
+ continue;
+ }
+
+ filters[idx].type = EMM_SHARED;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x84;
+ filters[idx].mask[0] = 0xFF;
+ memcpy(&filters[idx].filter[1], &rdr->prid[prov][2], 2);
+ memset(&filters[idx].mask[1], 0xFF, 2);
+ memcpy(&filters[idx].filter[3], &rdr->sa[prov], 3);
+ memset(&filters[idx].mask[3], 0xFF, 3);
+ idx++;
+
+ filters[idx].type = EMM_SHARED;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x83;
+ filters[idx].filter[1] = rdr->sa[prov][2];
+ filters[idx].filter[2] = rdr->sa[prov][1];
+ filters[idx].filter[3] = rdr->sa[prov][0];
+ filters[idx].filter[4] = 0x00;
+ filters[idx].filter[5] = 0x10;
+ memset(&filters[idx].mask[0], 0xFF, 6);
+ idx++;
+
+ filters[idx].type = EMM_SHARED;
+ filters[idx].enabled = 1;
+ filters[idx].filter[0] = 0x87;
+ filters[idx].filter[1] = rdr->sa[prov][2];
+ filters[idx].filter[2] = rdr->sa[prov][1];
+ filters[idx].filter[3] = rdr->sa[prov][0];
+ filters[idx].filter[4] = 0x00;
+ filters[idx].filter[5] = 0x00;
+ memset(&filters[idx].mask[0], 0xFF, 6);
+ idx++;
+ }
+
+ *filter_count = idx;
+ }
+
+ return OK;
+ }
}
diff --git a/reader-nagra.c b/reader-nagra.c
index 141206d34..3e67b77d3 100644
--- a/reader-nagra.c
+++ b/reader-nagra.c
@@ -425,13 +425,13 @@ static int32_t NegotiateSessionKey(struct s_reader *reader)
if(!csystem_data->is_n3_na)
{
- if (reader->nuid_length == 4) //nuid is set
+ if (reader->cak63nuid_length == 4) //nuid is set
{
// inject provid
cmd2a[26] = reader->prid[0][2];
cmd2a[27] = reader->prid[0][3];
- memcpy(&cmd2a[1], reader->nuid, 4); // inject NUID
+ memcpy(&cmd2a[1], reader->cak63nuid, 4); // inject NUID
if (!do_cmd(reader, 0x2a,0x1E,0xAA,0x42, cmd2a, cta_res, &cta_lr))
{
@@ -659,7 +659,7 @@ static void addProvider(struct s_reader *reader, uint8_t *cta_res)
static int32_t ParseDataType(struct s_reader *reader, uint8_t dt, uint8_t *cta_res, uint16_t cta_lr)
{
struct nagra_data *csystem_data = reader->csystem_data;
- char ds[36], de[36];
+ char ds[20], de[16];
uint16_t chid;
switch(dt)
@@ -828,7 +828,7 @@ static int32_t nagra2_card_init(struct s_reader *reader, ATR *newatr)
}
memcpy(reader->rom, cta_res + 2, 15);
}
- else if(reader->detect_seca_nagra_tunneled_card && memcmp(atr + 7, "pp", 2) == 0 && ((atr[9]&0x0F) >= 10))
+ else if(!reader->cak7_mode && reader->detect_seca_nagra_tunneled_card && memcmp(atr + 7, "pp", 2) == 0 && ((atr[9]&0x0F) >= 10))
{
rdr_log(reader, "detect seca/nagra tunneled card");
@@ -1394,14 +1394,14 @@ static int32_t nagra2_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, str
{
rdr_log_dbg(reader, D_READER, "3DES encryption of CWs detected. Using CWPK index:%02X", (csystem_data->ird_info & 7));
- if(reader->cwekey_length != 16)
+ if(reader->cak63cwekey_length != 16)
{
rdr_log_dbg(reader, D_READER, "ERROR: Invalid CWPK, can not decrypt CW");
return ERROR;
}
- des_ecb3_decrypt(_cwe0, reader->cwekey);
- des_ecb3_decrypt(_cwe1, reader->cwekey);
+ des_ecb3_decrypt(_cwe0, reader->cak63cwekey);
+ des_ecb3_decrypt(_cwe1, reader->cak63cwekey);
rdr_log_dbg(reader, D_READER, "CW0 after 3DES decrypt: %s", cs_hexdump(1, _cwe0, 8, tmp_dbg, sizeof(tmp_dbg)));
rdr_log_dbg(reader, D_READER, "CW1 after 3DES decrypt: %s", cs_hexdump(1, _cwe1, 8, tmp_dbg, sizeof(tmp_dbg)));
diff --git a/reader-nagracak7.c b/reader-nagracak7.c
index 6fc06ad00..e0368051d 100644
--- a/reader-nagracak7.c
+++ b/reader-nagracak7.c
@@ -1,25 +1,21 @@
#include "globals.h"
#ifdef READER_NAGRA_MERLIN
+#include "math.h"
#include "cscrypt/bn.h"
#include "cscrypt/idea.h"
#include "csctapi/icc_async.h"
#include "oscam-time.h"
#include "reader-common.h"
#include "reader-nagra-common.h"
-#include "reader-nagracak7.h"
#include "oscam-work.h"
#include "cscrypt/des.h"
#include "cscrypt/mdc2.h"
-
+static const uint8_t public_exponent[] = { 0x01, 0x00, 0x01 };
static const uint8_t d00ff[] = { 0x00, 0xFF, 0xFF, 0xFF };
-static uint8_t data1[] = { 0x00, 0x00, 0x00, 0x01 };
-
// Datatypes
-#define SYSID_CAID 0x02
-#define IRDINFO 0x03
-#define DT05 0x05
-#define TIERS 0x0C
-
+#define IRDINFO 0x03
+#define TIERS 0x0C
+#define SYSID 0x05
static time_t tier_date(uint64_t date, char *buf, int32_t l)
{
time_t ut = +694224000L + (date >> 1);
@@ -32,8 +28,7 @@ static time_t tier_date(uint64_t date, char *buf, int32_t l)
}
return ut;
}
-
-void rsa_decrypt(uint8_t *edata50, int len, uint8_t *out, uint8_t *key, int keylen, uint8_t *expo, uint8_t expolen)
+static void rsa_decrypt(uint8_t *edata50, int len, uint8_t *out, uint8_t *key, int keylen)
{
BN_CTX *ctx0 = BN_CTX_new();
#ifdef WITH_LIBCRYPTO
@@ -44,7 +39,7 @@ void rsa_decrypt(uint8_t *edata50, int len, uint8_t *out, uint8_t *key, int keyl
BIGNUM *bnCT0 = BN_CTX_get(ctx0);
BIGNUM *bnPT0 = BN_CTX_get(ctx0);
BN_bin2bn(&key[0], keylen, bnN0);
- BN_bin2bn(&expo[0], expolen, bnE0);
+ BN_bin2bn(public_exponent, 0x03, bnE0);
BN_bin2bn(&edata50[0], len, bnCT0);
BN_mod_exp(bnPT0, bnCT0, bnE0, bnN0, ctx0);
memset(out,0x00,len);
@@ -52,88 +47,381 @@ void rsa_decrypt(uint8_t *edata50, int len, uint8_t *out, uint8_t *key, int keyl
BN_CTX_end(ctx0);
BN_CTX_free(ctx0);
}
-
static void addProvider(struct s_reader *reader, uint8_t *cta_res)
{
- uint8_t i;
+ int i;
bool toadd = true;
-
for(i = 0; i < reader->nprov; i++)
{
- if((cta_res[19] == reader->prid[i][2]) && (cta_res[20] == reader->prid[i][3]))
+ if((cta_res[0] == reader->prid[i][2]) && (cta_res[1] == reader->prid[i][3]))
{
toadd = false;
}
}
-
if(toadd)
{
reader->prid[reader->nprov][0] = 0;
reader->prid[reader->nprov][1] = 0;
- reader->prid[reader->nprov][2] = cta_res[19];
- reader->prid[reader->nprov][3] = cta_res[20];
- memcpy(reader->sa[reader->nprov], reader->sa[0], 0x04);
+ reader->prid[reader->nprov][2] = cta_res[0];
+ reader->prid[reader->nprov][3] = cta_res[1];
reader->nprov += 1;
}
}
-
+static int32_t get_prov_index(struct s_reader *reader, const uint8_t *provid)
+{
+ int prov;
+ for(prov = 0; prov < reader->nprov; prov++)
+ {
+ if(!memcmp(provid, &reader->prid[prov][2], 2))
+ {
+ return (prov);
+ }
+ }
+ return (-1);
+}
+static void addSA(struct s_reader *reader, uint8_t *cta_res)
+{
+ if((cta_res[0] == 0x83 && cta_res[5] == 0x10) || cta_res[0] == 0x87)
+ {
+ int i;
+ bool toadd = true;
+ if(reader->evensa)
+ {
+ unsigned long sax = (cta_res[3] << 16) + (cta_res[2] << 8) + (cta_res[1]);
+ if(sax % 2 != 0)
+ {
+ sax--;
+ cta_res[3]=(sax>>16)&0xFF;
+ cta_res[2]=(sax>>8)&0xFF;
+ cta_res[1]=(sax)&0xFF;
+ }
+ }
+ for(i = 0; i < reader->nsa; i++)
+ {
+ if((cta_res[1] == reader->sa[i][2]) && (cta_res[2] == reader->sa[i][1]) && (cta_res[3] == reader->sa[i][0]) && (cta_res[4] == reader->sa[i][3]))
+ {
+ toadd = false;
+ }
+ }
+ if(toadd && (memcmp(cta_res + 1, "\x00\x00\x00", 3)))
+ {
+ reader->sa[reader->nsa][0] = cta_res[3];
+ reader->sa[reader->nsa][1] = cta_res[2];
+ reader->sa[reader->nsa][2] = cta_res[1];
+ reader->sa[reader->nsa][3] = cta_res[4];
+ reader->nsa += 1;
+ }
+ }
+}
+static void addSAseca(struct s_reader *reader, uint8_t *cta_res)
+{
+ if(cta_res[0] == 0x84)
+ {
+ addProvider(reader, cta_res + 1);
+ if(memcmp(cta_res + 3, "\x00\x00\x00", 3))
+ {
+ int i;
+ i = get_prov_index(reader, cta_res + 1);
+ memcpy(reader->sa[i], cta_res + 3, 3);
+ }
+ }
+}
+static void addemmfilter(struct s_reader *reader, uint8_t *cta_res)
+{
+ if(cta_res[0] == 0x82)
+ {
+ reader->emm82 = 1;
+ }
+ else if(cta_res[0] == 0x84)
+ {
+ int i;
+ bool toadd = true;
+ for(i = 0; i < reader->nemm84; i++)
+ {
+ if(!memcmp(cta_res, reader->emm84[i], 3))
+ {
+ toadd = false;
+ }
+ }
+ if(toadd && (memcmp(cta_res + 1, "\x00\x00", 2)))
+ {
+ reader->emm84[reader->nemm84][0] = cta_res[0];
+ reader->emm84[reader->nemm84][1] = cta_res[1];
+ reader->emm84[reader->nemm84][2] = cta_res[2];
+ reader->nemm84 += 1;
+ }
+ }
+ else if(cta_res[0] == 0x83 && cta_res[5] == 0x00)
+ {
+ int i;
+ bool toadd = true;
+ for(i = 0; i < reader->nemm83u; i++)
+ {
+ if(!memcmp(cta_res, reader->emm83u[i], 6))
+ {
+ toadd = false;
+ }
+ }
+ if(toadd && (memcmp(cta_res + 1, "\x00\x00\x00\x00", 4)))
+ {
+ memcpy(reader->emm83u[reader->nemm83u], cta_res, 6);
+ reader->nemm83u += 1;
+ }
+ }
+ else if(cta_res[0] == 0x83 && cta_res[5] == 0x10)
+ {
+ int i;
+ bool toadd = true;
+ if(reader->evensa)
+ {
+ unsigned long sax = (cta_res[3] << 16) + (cta_res[2] << 8) + (cta_res[1]);
+ if(sax % 2 != 0)
+ {
+ sax--;
+ cta_res[3]=(sax>>16)&0xFF;
+ cta_res[2]=(sax>>8)&0xFF;
+ cta_res[1]=(sax)&0xFF;
+ }
+ }
+ for(i = 0; i < reader->nemm83s; i++)
+ {
+ if(!memcmp(cta_res, reader->emm83s[i], 6))
+ {
+ toadd = false;
+ }
+ }
+ if(toadd && (memcmp(cta_res + 1, "\x00\x00\x00", 3)))
+ {
+ memcpy(reader->emm83s[reader->nemm83s], cta_res, 6);
+ reader->nemm83s += 1;
+ }
+ }
+ else if(cta_res[0] == 0x87)
+ {
+ int i;
+ bool toadd = true;
+ if(reader->evensa)
+ {
+ unsigned long sax = (cta_res[3] << 16) + (cta_res[2] << 8) + (cta_res[1]);
+ if(sax % 2 != 0)
+ {
+ sax--;
+ cta_res[3]=(sax>>16)&0xFF;
+ cta_res[2]=(sax>>8)&0xFF;
+ cta_res[1]=(sax)&0xFF;
+ }
+ }
+ for(i = 0; i < reader->nemm87; i++)
+ {
+ if(!memcmp(cta_res, reader->emm87[i], 6))
+ {
+ toadd = false;
+ }
+ }
+ if(toadd && (memcmp(cta_res + 1, "\x00\x00\x00", 3)))
+ {
+ memcpy(reader->emm87[reader->nemm87], cta_res, 6);
+ reader->nemm87 += 1;
+ }
+ }
+}
static int32_t ParseDataType(struct s_reader *reader, uint8_t dt, uint8_t *cta_res, uint16_t cta_lr)
{
- char ds[36], de[36];
-
+ char ds[27], de[27];
switch(dt)
{
- case SYSID_CAID:
+ case 0x02:
{
reader->prid[0][0] = 0x00;
reader->prid[0][1] = 0x00;
reader->prid[0][2] = cta_res[19];
reader->prid[0][3] = cta_res[20];
-
reader->prid[1][0] = 0x00;
reader->prid[1][1] = 0x00;
reader->prid[1][2] = 0x00;
reader->prid[1][3] = 0x00;
- memcpy(reader->sa[1], reader->sa[0], 0x04);
reader->nprov += 1;
reader->caid = (SYSTEM_NAGRA | cta_res[25]);
rdr_log_dbg(reader, D_READER, "CAID : %04X", reader->caid);
return OK;
}
-
case IRDINFO: // case 0x03
{
if(cta_res[21] == 0x9C)
{
uint32_t timestamp = b2i(0x04, cta_res + 22);
- reader->card_valid_to = tier_date(timestamp, de, 11);
- rdr_log(reader, "Provider Sys ID: %02X %02X is active to: %s", cta_res[19], cta_res[20], de);
+ uint8_t timestamp186D[4] = {0xA6, 0x9E, 0xFB, 0x7F};
+ uint32_t timestamp186Db2i = b2i(0x04, timestamp186D);
+ if(reader->caid == 0x186D)
+ {
+ reader->card_valid_to = tier_date(timestamp186Db2i, de, 11);
+ }
+ else
+ {
+ reader->card_valid_to = tier_date(timestamp, de, 11);
+ }
+ uint16_t chid = 0;
+ uint32_t id = b2i(0x02, cta_res + 19);
+ uint32_t start_date;
+ uint32_t expire_date;
+ start_date = 1;
+ expire_date = b2i(0x04, cta_res + 22);
+ cs_add_entitlement(reader,
+ reader->caid,
+ id,
+ chid,
+ 0,
+ tier_date(start_date, ds, 11),
+ tier_date(expire_date, de, 11),
+ 4,
+ 1);
+ rdr_log(reader, "|%04X|%04X |%s |%s |", id, chid, ds, de);
+ addProvider(reader, cta_res + 19);
+ }
+ if((reader->caid == 0x1856) && (cta_res[21] == 0x01))
+ {
+ uint16_t chid = 0;
+ uint32_t id = b2i(0x02, cta_res + 19);
+ uint32_t start_date;
+ uint32_t expire_date;
+ start_date = 1;
+ expire_date = b2i(0x04, cta_res + 22);
+ cs_add_entitlement(reader,
+ reader->caid,
+ id,
+ chid,
+ 0,
+ tier_date(start_date, ds, 11),
+ tier_date(expire_date, de, 11),
+ 4,
+ 1);
+ rdr_log(reader, "|%04X|%04X |%s |%s |", id, chid, ds, de);
+ addProvider(reader, cta_res + 19);
+ }
+ if(reader->protocol_type == ATR_PROTOCOL_TYPE_T0)
+ {
+ uint16_t chid = 0;
+ uint32_t id = b2i(0x02, cta_res + 19);
+ uint32_t start_date;
+ uint32_t expire_date;
+ start_date = 1;
+ expire_date = b2i(0x04, cta_res + 22);
+ cs_add_entitlement(reader,
+ reader->caid,
+ id,
+ chid,
+ 0,
+ tier_date(start_date, ds, 11),
+ tier_date(expire_date, de, 11),
+ 4,
+ 1);
+ rdr_log(reader, "|%04X|%04X |%s |%s |", id, chid, ds, de);
+ addProvider(reader, cta_res + 19);
+ }
+ return OK;
+ }
+ case 0x04:
+ {
+ if(cta_res[18] != 0x80)
+ {
+ addProvider(reader, cta_res + 19);
+ uint8_t check[] = {0x00, 0x01};
+ uint8_t checkecmcaid[] = {0xFF, 0x07};
+ if (reader->caid == 0x186D)
+ {
+ check[0] = (reader->caid - 0x03) & 0xFF;
+ }
+ else if (reader->caid == 0x1856)
+ {
+ check[0] = (reader->caid + 0x28) & 0xFF;
+ }
+ else
+ {
+ check[0] = reader->caid & 0xFF;
+ }
+ int p;
+ for(p=23; p < (cta_lr - 6); p++)
+ {
+ if(!memcmp(cta_res + p, check, 2))
+ {
+ addProvider(reader, cta_res + p + 2);
+ if(reader->cak7type == 3)
+ {
+ addSAseca(reader, cta_res + p + 5);
+ }
+ else
+ {
+ if ((reader->caid == 0x1884) && (((cta_res + p + 5)[0] == 0x83) || ((cta_res + p + 5)[0] == 0x87)) && ((cta_res + p + 5)[2] == reader->cardid[1]) && ((cta_res + p + 5)[3] == reader->cardid[0]) && ((cta_res + p + 5)[4] == 0x00))
+ {
+ (cta_res + p + 5)[1] -= 0x01;
+ }
+ if ((reader->caid == 0x1856) && ((cta_res + p + 5)[0] == 0x87) && ((cta_res + p + 5)[1] != reader->cardid[2]) && ((cta_res + p + 5)[2] != reader->cardid[1]) && ((cta_res + p + 5)[3] != reader->cardid[0]) && ((cta_res + p + 5)[4] != reader->cardid[3]))
+ {
+ (cta_res + p + 5)[4] = 0x00;
+ }
+ addSA(reader, cta_res + p + 5);
+ addemmfilter(reader, cta_res + p + 5);
+ }
+ }
+ if(!memcmp(cta_res + p, checkecmcaid, 2))
+ {
+ reader->caid = (SYSTEM_NAGRA | (cta_res + p + 2)[0]);
+ }
+ }
+ }
+ return OK;
+ }
+ case 0x09:
+ {
+ if((cta_res[19] == cta_res[23]) && (cta_res[20] == cta_res[24]))
+ {
+ addProvider(reader, cta_res + 19);
}
return OK;
}
-
- case DT05: // case 0x05
+ case SYSID: // case 0x05
{
- IDEA_KEY_SCHEDULE ks;
memcpy(reader->edata,cta_res + 26, 0x70);
reader->dt5num = cta_res[20];
- rsa_decrypt(reader->edata, 0x70, reader->out, reader->mod1, reader->mod1_length, reader->public_exponent, reader->public_exponent_length);
-
+ char tmp[8];
+ rdr_log(reader, "Card has DT05_%s", cs_hexdump(1, &reader->dt5num, 1, tmp, sizeof(tmp)));
if(reader->dt5num == 0x00)
{
+ IDEA_KEY_SCHEDULE ks;
+ rsa_decrypt(reader->edata, 0x70, reader->out, reader->mod1, reader->mod1_length);
memcpy(reader->kdt05_00,&reader->out[18], 0x5C + 2);
memcpy(&reader->kdt05_00[0x5C + 2], cta_res + 26 + 0x70, 6);
memcpy(reader->ideakey1, reader->out, 16);
+ rdr_log_dump_dbg(reader, D_READER, reader->ideakey1, 16, "IDEAKEY1: ");
memcpy(reader->block3, cta_res + 26 + 0x70 + 6, 8);
idea_set_encrypt_key(reader->ideakey1, &ks);
memset(reader->v, 0, sizeof(reader->v));
idea_cbc_encrypt(reader->block3, reader->iout, 8, &ks, reader->v, IDEA_DECRYPT);
memcpy(&reader->kdt05_00[0x5C + 2 + 6],reader->iout, 8);
+ uint8_t mdc_hash1[MDC2_DIGEST_LENGTH];
+ memset(mdc_hash1,0x00,MDC2_DIGEST_LENGTH);
+ uint8_t check1[0x7E];
+ memset(check1, 0x00, 0x7E);
+ memcpy(check1 + 18, reader->kdt05_00, 0x6C);
+ MDC2_CTX c1;
+ MDC2_Init(&c1);
+ MDC2_Update(&c1, check1, 0x7E);
+ MDC2_Final(&(mdc_hash1[0]), &c1);
+ rdr_log_dump_dbg(reader, D_READER, mdc_hash1, 16, "MDC_HASH: ");
+ if(memcmp(mdc_hash1 + 1, reader->ideakey1 + 1, 14) == 0)
+ {
+ rdr_log(reader, "DT05_00 is correct");
+ }
+ else
+ {
+ rdr_log(reader, "DT05_00 error - check MOD1");
+ }
rdr_log_dump_dbg(reader, D_READER, reader->kdt05_00, sizeof(reader->kdt05_00), "DT05_00: ");
}
-
if(reader->dt5num == 0x10)
{
+ IDEA_KEY_SCHEDULE ks;
+ rsa_decrypt(reader->edata, 0x70, reader->out, reader->mod1, reader->mod1_length);
memcpy(reader->kdt05_10, &reader->out[16], 6 * 16);
memcpy(reader->ideakey1, reader->out, 16);
memcpy(reader->block3, cta_res + 26 + 0x70, 8);
@@ -143,9 +431,14 @@ static int32_t ParseDataType(struct s_reader *reader, uint8_t dt, uint8_t *cta_r
memcpy(&reader->kdt05_10[6 * 16],reader->iout,8);
rdr_log_dump_dbg(reader, D_READER, reader->kdt05_10, sizeof(reader->kdt05_10), "DT05_10: ");
}
+ if(reader->dt5num == 0x20)
+ {
+ rsa_decrypt(reader->edata, 0x70, reader->out, reader->mod2, reader->mod2_length);
+ memcpy(reader->tmprsa, reader->out, 0x70);
+ reader->hasunique = 1;
+ }
return OK;
}
-
case TIERS: // case 0x0C
{
uint16_t chid;
@@ -156,28 +449,40 @@ static int32_t ParseDataType(struct s_reader *reader, uint8_t dt, uint8_t *cta_r
uint32_t expire_date1;
uint32_t expire_date2;
uint32_t expire_date;
-
switch(reader->caid)
{
+ case 0x1843: // HD02
+ start_date = b2i(0x04, cta_res + 42);
+ expire_date1 = b2i(0x04, cta_res + 28);
+ expire_date2 = b2i(0x04, cta_res + 46);
+ expire_date = expire_date1 <= expire_date2 ? expire_date1 : expire_date2;
+ break;
case 0x1860: // HD03
start_date = b2i(0x04, cta_res + 42);
expire_date1 = b2i(0x04, cta_res + 28);
expire_date2 = b2i(0x04, cta_res + 46);
expire_date = expire_date1 <= expire_date2 ? expire_date1 : expire_date2;
break;
-
case 0x186A: // HD04, HD05
start_date = b2i(0x04, cta_res + 53);
expire_date1 = b2i(0x04, cta_res + 39);
expire_date2 = b2i(0x04, cta_res + 57);
expire_date = expire_date1 <= expire_date2 ? expire_date1 : expire_date2;
break;
-
+ case 0x1861: // Polsat, Vodafone D08
+ start_date = b2i(0x04, cta_res + 42);
+ expire_date = b2i(0x04, cta_res + 28);
+ break;
+ case 0x1830: // Max TV
+ start_date = b2i(0x04, cta_res + 42);
+ expire_date1 = b2i(0x04, cta_res + 28);
+ expire_date2 = b2i(0x04, cta_res + 46);
+ expire_date = expire_date1 <= expire_date2 ? expire_date1 : expire_date2;
+ break;
default: // unknown card
start_date = 1;
- expire_date = 0x569EFB7F;
+ expire_date = 0xA69EFB7F;
}
-
cs_add_entitlement(reader,
reader->caid,
id,
@@ -188,70 +493,61 @@ static int32_t ParseDataType(struct s_reader *reader, uint8_t dt, uint8_t *cta_r
4,
1);
rdr_log(reader, "|%04X|%04X |%s |%s |", id, chid, ds, de);
- addProvider(reader, cta_res);
+ addProvider(reader, cta_res + 19);
}
return OK;
}
-
default:
return OK;
}
return ERROR;
}
-
static int32_t CAK7do_cmd(struct s_reader *reader, uint8_t dt, uint8_t len, uint8_t *res, uint16_t *rlen, int32_t sub, uint8_t retlen)
{
uint8_t dtdata[0x10];
memset(dtdata, 0xCC, len);
-
dtdata[7] = 0x04;
dtdata[8] = 0x04;
-
dtdata[9] = (sub >> 16) & 0xFF;
dtdata[10] = (sub >> 8) & 0xFF;
dtdata[11] = (sub) & 0xFF;
-
dtdata[12] = dt;
-
do_cak7_cmd(reader, res, rlen, dtdata, sizeof(dtdata), retlen);
-
return OK;
}
-
static int32_t CAK7GetDataType(struct s_reader *reader, uint8_t dt)
{
def_resp;
-
int32_t sub = 0x00;
uint8_t retlen = 0x10;
while(1)
{
CAK7do_cmd(reader, dt, 0x10, cta_res, &cta_lr, sub, retlen);
+ rdr_log_dump_dbg(reader, D_READER, cta_res, cta_lr, "Decrypted Answer:");
// hier eigentlich check auf 90 am ende usw... obs halt klarging ...
-
- if((cta_lr == 0) || (cta_res[cta_lr-2] == 0x6F && cta_res[cta_lr-1] == 0x01))
+ if(cta_lr == 0)
+ {
+ break;
+ }
+ if(cta_res[cta_lr-2] == 0x6F && cta_res[cta_lr-1] == 0x01)
{
reader->card_status = CARD_NEED_INIT;
add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
break;
}
-
uint32_t newsub = (cta_res[9] << 16) + (cta_res[10] << 8) + (cta_res[11]);
if(newsub == 0xFFFFFF)
{
break;
}
-
if(cta_res[12] == dt)
{
uint8_t oretlen = retlen;
retlen = cta_res[13] + 0x10 + 0x2;
-
while(retlen % 0x10 != 0x00)
{
retlen++;
}
-
if(retlen == oretlen)
{
sub = newsub + 1;
@@ -264,82 +560,315 @@ static int32_t CAK7GetDataType(struct s_reader *reader, uint8_t dt)
break;
}
}
-
return OK;
}
-
-void CAK7_getCamKey(struct s_reader *reader)
+static void sub_6AD78(uint32_t *dinit) // gbox function
+{
+ uint32_t v0 = (uint32_t) * dinit;
+ double f0;
+ f0 = v0;
+ double f12 = 16807;
+ double f15 = 2147483647;
+ f12 = f0 * f12;
+ double v12;
+ v12 = fmod(f12, f15);
+ *dinit = v12;
+}
+static void calc_cak7_exponent(uint32_t *dinit, uint8_t *out, uint8_t len)
+{
+ memset(out, 0x00, len);
+ sub_6AD78(dinit);
+ int nR4 = 0;
+ int nR5 = 0;
+ while(true)
+ {
+ uint32_t nR0 = (uint32_t)* dinit;
+ int nR3 = nR4 + 3;
+ nR5 += 4;
+ if(nR3 > len)
+ {
+ break;
+ }
+ out[nR5 - 1] = ((nR0 ) & 0xFF);
+ out[nR5 - 2] = ((nR0 >> 8) & 0xFF);
+ out[nR5 - 3] = ((nR0 >> 16) & 0xFF);
+ out[nR5 - 4] = ((nR0 >> 24) & 0xFF);
+ nR4 += 4;
+ sub_6AD78(dinit);
+ }
+ uint32_t nR0 = (uint32_t)* dinit;
+ while(nR4 < len)
+ {
+ out[nR4] = nR0 & 0xFF;
+ nR4++;
+ nR0 >>= 8;
+ }
+ out[0] &= 0x03;
+ out[0x10] |= 0x01;
+}
+static void IdeaDecrypt(unsigned char *data, int len, const unsigned char *key, unsigned char *iv)
+{
+unsigned char v[8];
+if(!iv) { memset(v,0,sizeof(v)); iv=v; }
+IDEA_KEY_SCHEDULE ks;
+idea_set_encrypt_key(key,&ks);
+idea_cbc_encrypt(data,data,len&~7,&ks,iv,IDEA_DECRYPT);
+}
+static inline void xxxor(uint8_t *data, int32_t len, const uint8_t *v1, const uint8_t *v2)
+{
+ uint32_t i;
+ switch(len)
+ {
+ case 16:
+ for(i = 0; i < 16; ++i)
+ {
+ data[i] = v1[i] ^ v2[i];
+ }
+ break;
+ case 8:
+ for(i = 0; i < 8; ++i)
+ {
+ data[i] = v1[i] ^ v2[i];
+ }
+ break;
+ case 4:
+ for(i = 0; i < 4; ++i)
+ {
+ data[i] = v1[i] ^ v2[i];
+ }
+ break;
+ default:
+ while(len--)
+ {
+ *data++ = *v1++ ^ *v2++;
+ }
+ break;
+ }
+}
+static void CreateRSAPair60(struct s_reader *reader, const unsigned char *key)
+{
+unsigned char idata[96];
+int i;
+for(i=11; i>=0; i--) {
+unsigned char *d=&idata[i*8];
+memcpy(d,&key[13],8);
+*d^=i;
+IdeaDecrypt(d,8,key,0);
+xxxor(d,8,d,&key[13]);
+*d^=i;
+}
+BN_CTX *ctx5 = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+BN_CTX_start(ctx5);
+#endif
+BIGNUM *p = BN_CTX_get(ctx5);
+BIGNUM *q = BN_CTX_get(ctx5);
+BIGNUM *m = BN_CTX_get(ctx5);
+BIGNUM *e = BN_CTX_get(ctx5);
+BIGNUM *a = BN_CTX_get(ctx5);
+BIGNUM *r = BN_CTX_get(ctx5);
+// Calculate P
+idata[0] |= 0x80;
+idata[47] |= 1;
+BN_bin2bn(idata,48,p);
+BN_add_word(p,(key[21] << 5 ) | ((key[22] & 0xf0) >> 3));
+// Calculate Q
+idata[48] |= 0x80;
+idata[95] |= 1;
+BN_bin2bn(idata+48,48,q);
+BN_add_word(q,((key[22]&0xf)<<9) | (key[23]<<1));
+// Calculate M=P*Q
+BN_mul(m,p,q,ctx5);
+memset(reader->key60,0x00,0x60);
+BN_bn2bin(m, reader->key60 + (0x60 - BN_num_bytes(m)));
+rdr_log_dump_dbg(reader, D_READER, reader->key60, sizeof(reader->key60), "key60: ");
+// Calculate D
+BN_sub_word(p,1);
+BN_sub_word(q,1);
+BN_mul(e,p,q,ctx5);
+BN_bin2bn(public_exponent,3,a);
+BN_mod_inverse(r, a, e, ctx5);
+memset(reader->exp60,0x00,0x60);
+BN_bn2bin(r, reader->exp60 + (0x60 - BN_num_bytes(r)));
+rdr_log_dump_dbg(reader, D_READER, reader->exp60, sizeof(reader->exp60), "exp60: ");
+BN_CTX_end(ctx5);
+BN_CTX_free(ctx5);
+}
+static void CreateRSAPair68(struct s_reader *reader, const unsigned char *key)
+{
+unsigned char idata[104];
+int i;
+for(i=12; i>=0; i--) {
+unsigned char *d=&idata[i*8];
+memcpy(d,&key[13],8);
+*d^=i;
+IdeaDecrypt(d,8,key,0);
+xxxor(d,8,d,&key[13]);
+*d^=i;
+}
+BN_CTX *ctx6 = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+BN_CTX_start(ctx6);
+#endif
+BIGNUM *p = BN_CTX_get(ctx6);
+BIGNUM *q = BN_CTX_get(ctx6);
+BIGNUM *m = BN_CTX_get(ctx6);
+BIGNUM *e = BN_CTX_get(ctx6);
+BIGNUM *a = BN_CTX_get(ctx6);
+BIGNUM *r = BN_CTX_get(ctx6);
+// Calculate P
+idata[0] |= 0x80;
+idata[51] |= 1;
+BN_bin2bn(idata,52,p);
+BN_add_word(p,(key[21] << 5 ) | ((key[22] & 0xf0) >> 3));
+// Calculate Q
+idata[52] |= 0x80;
+idata[103] |= 1;
+BN_bin2bn(idata+52,52,q);
+BN_add_word(q,((key[22]&0xf)<<9) | (key[23]<<1));
+// Calculate M=P*Q
+BN_mul(m,p,q,ctx6);
+memset(reader->key68,0x00,0x68);
+BN_bn2bin(m, reader->key68 + (0x68 - BN_num_bytes(m)));
+rdr_log_dump_dbg(reader, D_READER, reader->key68, sizeof(reader->key68), "key68: ");
+// Calculate D
+BN_sub_word(p,1);
+BN_sub_word(q,1);
+BN_mul(e,p,q,ctx6);
+BN_bin2bn(public_exponent,3,a);
+BN_mod_inverse(r, a, e, ctx6);
+memset(reader->exp68,0x00,0x68);
+BN_bn2bin(r, reader->exp68 + (0x68 - BN_num_bytes(r)));
+rdr_log_dump_dbg(reader, D_READER, reader->exp68, sizeof(reader->exp68), "exp68: ");
+BN_CTX_end(ctx6);
+BN_CTX_free(ctx6);
+}
+static void dt05_20(struct s_reader *reader)
+{
+ uint8_t data_20_00[72];
+ uint8_t sig_20_00[16];
+ uint8_t data_20_id[72];
+ uint8_t data_20_x[64];
+ uint8_t data_20_fin[72];
+ uint8_t data_20_flag58[16];
+ rdr_log_dump_dbg(reader, D_READER, reader->tmprsa, sizeof(reader->tmprsa), "DT05_20 after RSA: ");
+ // copy signature
+ memcpy(sig_20_00, reader->tmprsa+24, 16);
+ // copy data
+ memcpy(data_20_00, reader->tmprsa+40, 72);
+ // IDEA encrypt 0x48 data
+ int i;
+ int offs = 0;
+ for(i=0; i<9; i++)
+ {
+ IDEA_KEY_SCHEDULE ks;
+ idea_set_encrypt_key(reader->key3310, &ks);
+ idea_ecb_encrypt(data_20_00+offs, data_20_id+offs, &ks);
+ offs+=8;
+ }
+ // xor
+ for (i=0; i<64; i++)
+ {
+ data_20_x[i] = data_20_00[i] ^ data_20_id[i+8];
+ }
+ rdr_log_dump_dbg(reader, D_READER, data_20_x, sizeof(data_20_x), "data_20_x: ");
+ // create final data block
+ memcpy(data_20_fin,data_20_id,8);
+ memcpy(data_20_fin+8,data_20_x,64);
+ rdr_log_dump_dbg(reader, D_READER, data_20_fin, sizeof(data_20_fin), "data_20_fin: ");
+ uint8_t mdc_hash4[MDC2_DIGEST_LENGTH];
+ memset(mdc_hash4,0x00,MDC2_DIGEST_LENGTH);
+ uint8_t check4[112];
+ memset(check4, 0x00, 112);
+ memcpy(check4, reader->cardid, 4);
+ memcpy(check4 + 4, reader->idird, 4);
+ memcpy(check4 + 23, reader->tmprsa + 23, 1);
+ memcpy(check4 + 40, data_20_fin, 72);
+ MDC2_CTX c4;
+ MDC2_Init(&c4);
+ MDC2_Update(&c4, check4, 112);
+ MDC2_Final(&(mdc_hash4[0]), &c4);
+ if(memcmp(mdc_hash4, sig_20_00, 16) == 0)
+ {
+ rdr_log(reader, "DT05_20 is correct");
+ }
+ else
+ {
+ rdr_log(reader, "DT05_20 error - check MOD2");
+ }
+ // Store 3des software key Flag58 CW overencrypt
+ memcpy(data_20_flag58, data_20_x+16, 16);
+ memcpy(reader->key3des, data_20_flag58, 16);
+ rdr_log_dump_dbg(reader, D_READER, reader->key3des, sizeof(reader->key3des), "Flag58 3DES Key: ");
+ // create rsa pair from final data
+ memcpy(reader->klucz68, data_20_fin, 0x18);
+ rdr_log_dump_dbg(reader, D_READER, reader->klucz68, sizeof(reader->klucz68), "klucz68: ");
+}
+static int32_t CAK7_cmd03_global(struct s_reader *reader)
{
def_resp;
- uint8_t cmd0e[] = {0xCC,0xCC,0xCC,0xCC,0x00,0x00,0x09,0x0E,0x83,0x00,0x00,0x00,0x00,0x00,0x64,0x65,0x6D,0x6F,0x34,0x11,0x9D,
- 0x7E,0xEE,0xCE,0x53,0x09,0x80,0xAE,0x6B,0x5A,0xEE,0x3A,0x41,0xCE,0x09,0x75,0xEF,0xA6,0xBF,0x1E,0x98,0x4F,
- 0xA4,0x11,0x6F,0x43,0xCA,0xCD,0xD0,0x6E,0x69,0xFA,0x25,0xC1,0xF9,0x11,0x8E,0x7A,0xD0,0x19,0xC0,0xEB,0x00,
- 0xC0,0x57,0x2A,0x40,0xB7,0xFF,0x8A,0xBB,0x25,0x21,0xD7,0x50,0xE7,0x35,0xA1,0x85,0xCD,0xA6,0xD3,0xDE,0xB3,
- 0x3D,0x16,0xD4,0x94,0x76,0x8A,0x82,0x8C,0x70,0x25,0xD4,0x00,0xD0,0x64,0x8C,0x26,0xB9,0x5F,0x44,0xFF,0x73,
- 0x70,0xAB,0x43,0xF5,0x68,0xA2,0xB1,0xB5,0x8A,0x8E,0x02,0x5F,0x96,0x06,0xA8,0xC3,0x4F,0x15,0xCD,0x99,0xC2,
- 0x69,0xB8,0x35,0x68,0x11,0x4C,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0xCC,0xCC,0xCC,0xCC};
-
- get_random_bytes(data1, 0x04);
- if (data1[3] == 0xFF)
- {
- data1[3]--;
- }
- memcpy(cmd0e + 9, data1, 0x04);
- data1[3]++;
-
- if (reader->irdid_length == 4)
- {
- memcpy(&cmd0e[14], reader->irdid, reader->irdid_length); // inject irdid
- }
-
- // inject provid
- cmd0e[18] = reader->prid[0][2];
- cmd0e[19] = reader->prid[0][3];
-
- if (reader->nuid_length == 4)
- {
- memcpy(&cmd0e[132], reader->nuid, reader->nuid_length); // inject NUID
- }
-
- do_cak7_cmd(reader,cta_res, &cta_lr, cmd0e, sizeof(cmd0e), 0x20);
-
- reader->cak7_restart = (cta_res[22] << 16);
- reader->cak7_restart += (cta_res[23] << 8);
- reader->cak7_restart += (cta_res[24] );
- reader->cak7_restart--;
-
- memcpy(reader->cardid,cta_res + 14, 4);
- rdr_log_dump_dbg(reader, D_READER, reader->cardid, 0x04, "CardSerial: ");
-
- memcpy(reader->hexserial + 2, reader->cardid, 4);
- memcpy(reader->sa[0], reader->cardid, 3);
- memcpy(reader->sa[1], reader->sa[0], 4);
-
- unsigned long datal = (cta_res[9] << 24) + (cta_res[10] << 16) + (cta_res[11] << 8) + (cta_res[12]);
- datal++;
- reader->data2[0] = (datal >> 24) & 0xFF;
- reader->data2[1] = (datal >> 16) & 0xFF;
- reader->data2[2] = (datal >> 8) & 0xFF;
- reader->data2[3] = (datal ) & 0xFF;
-
- rsa_decrypt(reader->data50, reader->data50_length, reader->data, reader->mod50, reader->mod50_length, reader->public_exponent, reader->public_exponent_length);
-
- memcpy(&reader->step1[0], d00ff, 4);
- memcpy(&reader->step1[4], reader->data, 0x50);
- memcpy(&reader->step1[4 + 0x50], reader->irdid, reader->irdid_length);
- memcpy(&reader->step1[4 + 4 + 0x50], data1, 0x04);
- memcpy(&reader->step1[4 + 4 + 4 + 0x50], reader->data2, 0x04);
- rsa_decrypt(reader->step1, 0x60, reader->data, reader->key60, reader->key60_length, reader->exp60, reader->exp60_length);
-
+ if(reader->cak7_seq <= 15)
+ {
+ unsigned char klucz[24];
+ memset(klucz, 0x00, 24);
+ memcpy(klucz, reader->key3588, 24);
+ CreateRSAPair60(reader, klucz);
+ }
+ BN_CTX *ctx1 = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+ BN_CTX_start(ctx1);
+#endif
+ BIGNUM *bnN1 = BN_CTX_get(ctx1);
+ BIGNUM *bnE1 = BN_CTX_get(ctx1);
+ BIGNUM *bnCT1 = BN_CTX_get(ctx1);
+ BIGNUM *bnPT1 = BN_CTX_get(ctx1);
+ BN_bin2bn(&reader->key60[0], 0x60, bnN1);
+ BN_bin2bn(&reader->exp60[0], 0x60, bnE1);
+ BN_bin2bn(&reader->step1[0], 0x60, bnCT1);
+ BN_mod_exp(bnPT1, bnCT1, bnE1, bnN1, ctx1);
+ memset(reader->data, 0x00, sizeof(reader->data));
+ BN_bn2bin(bnPT1, reader->data + (0x60 - BN_num_bytes(bnPT1)));
+ BN_CTX_end(ctx1);
+ BN_CTX_free(ctx1);
memcpy(&reader->step2[0], d00ff, 4);
memcpy(&reader->step2[4], reader->cardid, 4);
memcpy(&reader->step2[8], reader->data, 0x60);
- rsa_decrypt(reader->step2, 0x68, reader->data, reader->kdt05_10, 0x68, reader->public_exponent, reader->public_exponent_length);
-
+ rdr_log_dump_dbg(reader, D_READER, reader->step2, sizeof(reader->step2), "STEP 2:");
+ BN_CTX *ctx2 = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+ BN_CTX_start(ctx2);
+#endif
+ BIGNUM *bnN2 = BN_CTX_get(ctx2);
+ BIGNUM *bnE2 = BN_CTX_get(ctx2);
+ BIGNUM *bnCT2 = BN_CTX_get(ctx2);
+ BIGNUM *bnPT2 = BN_CTX_get(ctx2);
+ BN_bin2bn(&reader->kdt05_10[0], 0x68, bnN2);
+ BN_bin2bn(public_exponent, 3, bnE2);
+ BN_bin2bn(&reader->step2[0], 0x68, bnCT2);
+ BN_mod_exp(bnPT2, bnCT2, bnE2, bnN2, ctx2);
+ memset(reader->data, 0x00, sizeof(reader->data));
+ BN_bn2bin(bnPT2, reader->data + (0x68 - BN_num_bytes(bnPT2)));
+ BN_CTX_end(ctx2);
+ BN_CTX_free(ctx2);
memcpy(&reader->step3[0], d00ff, 4);
memcpy(&reader->step3[4], reader->data, 0x68);
- rsa_decrypt(reader->step3, 0x6c, reader->data, reader->kdt05_00, 0x6c, reader->public_exponent, reader->public_exponent_length);
-
+ rdr_log_dump_dbg(reader, D_READER, reader->step3, sizeof(reader->step3), "STEP 3:");
+ BN_CTX *ctx3 = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+ BN_CTX_start(ctx3);
+#endif
+ BIGNUM *bnN3 = BN_CTX_get(ctx3);
+ BIGNUM *bnE3 = BN_CTX_get(ctx3);
+ BIGNUM *bnCT3 = BN_CTX_get(ctx3);
+ BIGNUM *bnPT3 = BN_CTX_get(ctx3);
+ BN_bin2bn(&reader->kdt05_00[0], 0x6c, bnN3);
+ BN_bin2bn(public_exponent, 3, bnE3);
+ BN_bin2bn(&reader->step3[0], 0x6c, bnCT3);
+ BN_mod_exp(bnPT3, bnCT3, bnE3, bnN3, ctx3);
+ memset(reader->data, 0x00, sizeof(reader->data));
+ BN_bn2bin(bnPT3, reader->data + (0x6c - BN_num_bytes(bnPT3)));
+ BN_CTX_end(ctx3);
+ BN_CTX_free(ctx3);
uint8_t cmd03[] = {0xCC,0xCC,0xCC,0xCC,0x00,0x00,0x0A,0x03,0x6C,
0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
@@ -349,64 +878,450 @@ void CAK7_getCamKey(struct s_reader *reader)
0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC};
-
memcpy(&cmd03[9],reader->data,0x6c);
do_cak7_cmd(reader,cta_res,&cta_lr,cmd03,sizeof(cmd03),0x90);
-
+ if(cta_lr == 0)
+ {
+ rdr_log(reader, "card is not responding to CMD03 - check your data");
+ return ERROR;
+ }
+ rdr_log_dump_dbg(reader, D_READER, cta_res, 0x90, "CMD03 ANSWER:");
memcpy(reader->encrypted,&cta_res[10],0x68);
- rsa_decrypt(reader->encrypted, 0x68, reader->result, reader->kdt05_10, 0x68, reader->public_exponent, reader->public_exponent_length);
-
+ BN_CTX *ctx = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+ BN_CTX_start(ctx);
+#endif
+ BIGNUM *bnN = BN_CTX_get(ctx);
+ BIGNUM *bnE = BN_CTX_get(ctx);
+ BIGNUM *bnCT = BN_CTX_get(ctx);
+ BIGNUM *bnPT = BN_CTX_get(ctx);
+ BN_bin2bn(&reader->kdt05_10[0], 104, bnN);
+ BN_bin2bn(public_exponent, 3, bnE);
+ BN_bin2bn(&reader->encrypted[0], 104, bnCT);
+ BN_mod_exp(bnPT, bnCT, bnE, bnN, ctx);
+ memset(reader->result, 0, 104);
+ BN_bn2bin(bnPT, reader->result + (104 - BN_num_bytes(bnPT)));
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ //uint8_t stillencrypted[0x50];
memcpy(reader->stillencrypted,&reader->result[12],0x50);
- rsa_decrypt(reader->stillencrypted, 0x50, reader->resultrsa, reader->mod50, reader->mod50_length, reader->public_exponent, reader->public_exponent_length);
-
- uint8_t mdc_hash[MDC2_DIGEST_LENGTH];
- memset(mdc_hash,0x00,MDC2_DIGEST_LENGTH);
- MDC2_CTX c;
- MDC2_Init(&c);
- MDC2_Update(&c, reader->resultrsa, sizeof(reader->resultrsa));
- MDC2_Final(&(mdc_hash[0]), &c);
-
- memcpy(&reader->cak7_aes_key[16],mdc_hash,16);
- memcpy(reader->cak7_aes_key,mdc_hash,16);
+ //uint8_t resultrsa[0x50];
+ BN_CTX *ctxs = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+ BN_CTX_start(ctxs);
+#endif
+ BIGNUM *bnNs = BN_CTX_get(ctxs);
+ BIGNUM *bnEs = BN_CTX_get(ctxs);
+ BIGNUM *bnCTs = BN_CTX_get(ctxs);
+ BIGNUM *bnPTs = BN_CTX_get(ctxs);
+ BN_bin2bn(&reader->mod50[0], reader->mod50_length, bnNs);
+ BN_bin2bn(&reader->cak7expo[0], 0x11, bnEs);
+ BN_bin2bn(&reader->stillencrypted[0], 0x50, bnCTs);
+ BN_mod_exp(bnPTs, bnCTs, bnEs, bnNs, ctxs);
+ memset(reader->resultrsa, 0x00, 0x50);
+ BN_bn2bin(bnPTs, reader->resultrsa + (0x50 - BN_num_bytes(bnPTs)));
+ BN_CTX_end(ctxs);
+ BN_CTX_free(ctxs);
+ uint8_t mdc_hash3[MDC2_DIGEST_LENGTH];
+ memset(mdc_hash3,0x00,MDC2_DIGEST_LENGTH);
+ MDC2_CTX c3;
+ MDC2_Init(&c3);
+ MDC2_Update(&c3, reader->resultrsa, sizeof(reader->resultrsa));
+ MDC2_Final(&(mdc_hash3[0]), &c3);
+ memcpy(&reader->cak7_aes_key[16],mdc_hash3,16);
+ memcpy(reader->cak7_aes_key,mdc_hash3,16);
+ char tmp7[128];
+ rdr_log(reader, "New AES: %s", cs_hexdump(1, reader->cak7_aes_key, 16, tmp7, sizeof(tmp7)));
+ return OK;
}
-
-void CAK7_reinit(struct s_reader *reader)
+static int32_t CAK7_cmd03_unique(struct s_reader *reader)
{
- ATR newatr[ATR_MAX_SIZE];
- memset(newatr, 0, 1);
- if(ICC_Async_Activate(reader, newatr, 0))
+ def_resp;
+ BN_CTX *ctx1 = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+ BN_CTX_start(ctx1);
+#endif
+ BIGNUM *bnN1 = BN_CTX_get(ctx1);
+ BIGNUM *bnE1 = BN_CTX_get(ctx1);
+ BIGNUM *bnCT1 = BN_CTX_get(ctx1);
+ BIGNUM *bnPT1 = BN_CTX_get(ctx1);
+ BN_bin2bn(&reader->key3460[0], 0x60, bnN1);
+ BN_bin2bn(public_exponent, 3, bnE1);
+ BN_bin2bn(&reader->step1[0], 0x60, bnCT1);
+ BN_mod_exp(bnPT1, bnCT1, bnE1, bnN1, ctx1);
+ memset(reader->data, 0x00, sizeof(reader->data));
+ BN_bn2bin(bnPT1, reader->data + (0x60 - BN_num_bytes(bnPT1)));
+ BN_CTX_end(ctx1);
+ BN_CTX_free(ctx1);
+ memcpy(&reader->step2[0], d00ff, 4);
+ memcpy(&reader->step2[4], reader->cardid, 4);
+ memcpy(&reader->step2[8], reader->data, 0x60);
+ rdr_log_dump_dbg(reader, D_READER, reader->step2, sizeof(reader->step2), "STEP 2:");
+ if(reader->cak7_seq <= 15)
{
- reader->card_status = CARD_NEED_INIT;
- add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
+ dt05_20(reader);
+ CreateRSAPair68(reader, reader->klucz68);
+ }
+ BN_CTX *ctx2 = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+ BN_CTX_start(ctx2);
+#endif
+ BIGNUM *bnN2 = BN_CTX_get(ctx2);
+ BIGNUM *bnE2 = BN_CTX_get(ctx2);
+ BIGNUM *bnCT2 = BN_CTX_get(ctx2);
+ BIGNUM *bnPT2 = BN_CTX_get(ctx2);
+ BN_bin2bn(&reader->key68[0], 0x68, bnN2);
+ BN_bin2bn(&reader->exp68[0], 0x68, bnE2);
+ BN_bin2bn(&reader->step2[0], 0x68, bnCT2);
+ BN_mod_exp(bnPT2, bnCT2, bnE2, bnN2, ctx2);
+ memset(reader->data, 0x00, sizeof(reader->data));
+ BN_bn2bin(bnPT2, reader->data + (0x68 - BN_num_bytes(bnPT2)));
+ BN_CTX_end(ctx2);
+ BN_CTX_free(ctx2);
+ memcpy(&reader->step3[0], d00ff, 4);
+ memcpy(&reader->step3[4], reader->data, 0x68);
+ rdr_log_dump_dbg(reader, D_READER, reader->step3, sizeof(reader->step3), "STEP 3:");
+ BN_CTX *ctx3 = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+ BN_CTX_start(ctx3);
+#endif
+ BIGNUM *bnN3 = BN_CTX_get(ctx3);
+ BIGNUM *bnE3 = BN_CTX_get(ctx3);
+ BIGNUM *bnCT3 = BN_CTX_get(ctx3);
+ BIGNUM *bnPT3 = BN_CTX_get(ctx3);
+ BN_bin2bn(&reader->kdt05_00[0], 0x6c, bnN3);
+ BN_bin2bn(public_exponent, 3, bnE3);
+ BN_bin2bn(&reader->step3[0], 0x6c, bnCT3);
+ BN_mod_exp(bnPT3, bnCT3, bnE3, bnN3, ctx3);
+ memset(reader->data, 0x00, sizeof(reader->data));
+ BN_bn2bin(bnPT3, reader->data + (0x6c - BN_num_bytes(bnPT3)));
+ BN_CTX_end(ctx3);
+ BN_CTX_free(ctx3);
+ uint8_t cmd03[] = {0xCC,0xCC,0xCC,0xCC,0x00,0x00,0x0A,0x03,0x6C,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC};
+ memcpy(&cmd03[9],reader->data,0x6c);
+ do_cak7_cmd(reader,cta_res,&cta_lr,cmd03,sizeof(cmd03),0x90);
+ if(cta_lr == 0)
+ {
+ rdr_log(reader, "card is not responding to CMD03 - check your data");
+ return ERROR;
+ }
+ rdr_log_dump_dbg(reader, D_READER, cta_res, 0x90, "CMD03 ANSWER:");
+ memcpy(reader->encrypted,&cta_res[18],0x60);
+ BN_CTX *ctx = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+ BN_CTX_start(ctx);
+#endif
+ BIGNUM *bnN = BN_CTX_get(ctx);
+ BIGNUM *bnE = BN_CTX_get(ctx);
+ BIGNUM *bnCT = BN_CTX_get(ctx);
+ BIGNUM *bnPT = BN_CTX_get(ctx);
+ BN_bin2bn(&reader->key3460[0], 96, bnN);
+ BN_bin2bn(public_exponent, 3, bnE);
+ BN_bin2bn(&reader->encrypted[0], 96, bnCT);
+ BN_mod_exp(bnPT, bnCT, bnE, bnN, ctx);
+ memset(reader->result, 0, 96);
+ BN_bn2bin(bnPT, reader->result + (96 - BN_num_bytes(bnPT)));
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ rdr_log_dump_dbg(reader, D_READER, reader->result, 96, "after RSA_3460: ");
+ //uint8_t stillencrypted[0x50];
+ memcpy(reader->stillencrypted,&reader->result[4],0x50);
+ //uint8_t resultrsa[0x50];
+ BN_CTX *ctxs = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+ BN_CTX_start(ctxs);
+#endif
+ BIGNUM *bnNs = BN_CTX_get(ctxs);
+ BIGNUM *bnEs = BN_CTX_get(ctxs);
+ BIGNUM *bnCTs = BN_CTX_get(ctxs);
+ BIGNUM *bnPTs = BN_CTX_get(ctxs);
+ BN_bin2bn(&reader->mod50[0], reader->mod50_length, bnNs);
+ BN_bin2bn(&reader->cak7expo[0], 0x11, bnEs);
+ BN_bin2bn(&reader->stillencrypted[0], 0x50, bnCTs);
+ BN_mod_exp(bnPTs, bnCTs, bnEs, bnNs, ctxs);
+ memset(reader->resultrsa, 0x00, 0x50);
+ BN_bn2bin(bnPTs, reader->resultrsa + (0x50 - BN_num_bytes(bnPTs)));
+ BN_CTX_end(ctxs);
+ BN_CTX_free(ctxs);
+ uint8_t mdc_hash5[MDC2_DIGEST_LENGTH];
+ memset(mdc_hash5,0x00,MDC2_DIGEST_LENGTH);
+ MDC2_CTX c5;
+ MDC2_Init(&c5);
+ MDC2_Update(&c5, reader->resultrsa, sizeof(reader->resultrsa));
+ MDC2_Final(&(mdc_hash5[0]), &c5);
+ memcpy(&reader->cak7_aes_key[16],mdc_hash5,16);
+ memcpy(reader->cak7_aes_key,mdc_hash5,16);
+ char tmp7[128];
+ rdr_log(reader, "New AES: %s", cs_hexdump(1, reader->cak7_aes_key, 16, tmp7, sizeof(tmp7)));
+ return OK;
+}
+static int32_t CAK7_GetCamKey(struct s_reader *reader)
+{
+ def_resp;
+ uint8_t cmd0e[] = {0xCC,0xCC,0xCC,0xCC,0x00,0x00,0x00,0x0E,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
+ 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC};
+ if(!reader->nuid_length)
+ {
+ uint8_t cmd02[] = {0x02,0x7B};
+ memcpy(cmd0e + 7, cmd02, 2);
+ rdr_log(reader, "using CMD02");
+ }
+ else
+ {
+ memcpy(cmd0e + 132, reader->nuid, reader->nuid_length); // inject NUID
+ uint8_t cwekeycount = 0;
+ if(reader->cwekey0_length)
+ { cwekeycount++; }
+ if(reader->cwekey1_length)
+ { cwekeycount++; }
+ if(reader->cwekey2_length)
+ { cwekeycount++; }
+ if(reader->cwekey3_length)
+ { cwekeycount++; }
+ if(reader->cwekey4_length)
+ { cwekeycount++; }
+ if(reader->cwekey5_length)
+ { cwekeycount++; }
+ if(reader->cwekey6_length)
+ { cwekeycount++; }
+ if(reader->cwekey7_length)
+ { cwekeycount++; }
+ if(cwekeycount == 0)
+ {
+ rdr_log(reader, "only NUID defined - enter at least CWPK0");
+ return ERROR;
+ }
+ else
+ {
+ if(reader->otpcsc_length)
+ {
+ memcpy(cmd0e + 136, reader->otpcsc, reader->otpcsc_length);
+ }
+ else
+ {
+ if(!reader->cwpkota)
+ {
+ cmd0e[136] = 0x00;
+ cmd0e[137] = cwekeycount;
+ }
+ else
+ {
+ cmd0e[136] = 0x00;
+ cmd0e[137] = 0x00;
+ }
+ }
+ if(reader->otacsc_length)
+ {
+ memcpy(cmd0e + 138, reader->otacsc, reader->otacsc_length);
+ }
+ else
+ {
+ if(reader->cwpkota)
+ {
+ cmd0e[138] = 0x00;
+ cmd0e[139] = cwekeycount;
+ }
+ else
+ {
+ cmd0e[138] = 0x00;
+ cmd0e[139] = 0x00;
+ }
+ }
+ }
+ char tmp[16];
+ rdr_log(reader, "OTP CSC No. of keys: %s", cs_hexdump(1, cmd0e + 136, 2, tmp, sizeof(tmp)));
+ rdr_log(reader, "OTA CSC No. of keys: %s", cs_hexdump(1, cmd0e + 138, 2, tmp, sizeof(tmp)));
+ }
+ if(reader->forcepair_length)
+ {
+ rdr_log(reader, "Forcing Pairing Type");
+ memcpy(cmd0e + 13, reader->forcepair, 1);
+ }
+ else
+ {
+ if(reader->hasunique == 1)
+ {
+ cmd0e[13] = 0x40;
+ }
+ }
+ memcpy(cmd0e + 14, reader->idird, 4);
+ if(reader->cmd0eprov_length)
+ {
+ memcpy(cmd0e + 18, reader->cmd0eprov, 2);
+ }
+ else
+ {
+ memcpy(cmd0e + 18, reader->prid[0] + 2, 2);
+ }
+ memcpy(cmd0e + 20, reader->key3588 + 24, 0x70);
+ if(reader->cak7_seq <= 15)
+ {
+ srand(time(NULL));
+ }
+ uint32_t data1r = rand() % 4294967294u;
+ reader->timestmp1[0]=(data1r>>24)&0xFF;
+ reader->timestmp1[1]=(data1r>>16)&0xFF;
+ reader->timestmp1[2]=(data1r>>8)&0xFF;
+ reader->timestmp1[3]=(data1r)&0xFF;
+ memcpy(cmd0e + 9, reader->timestmp1, 0x04);
+ rdr_log_dump_dbg(reader, D_READER, reader->timestmp1, 4, "DATA1 CMD0E:");
+ rdr_log_dump_dbg(reader, D_READER, reader->prid[0], 4, "SysID:");
+ do_cak7_cmd(reader,cta_res, &cta_lr, cmd0e, sizeof(cmd0e), 0x20);
+ if(cta_lr == 0)
+ {
+ rdr_log(reader, "card is not responding to CMD02/E - check your data");
+ return ERROR;
+ }
+ rdr_log_dump_dbg(reader, D_READER, cta_res, 0x20, "Decrypted answer to CMD02/0E:");
+ reader->needrestart = (cta_res[22] << 16);
+ reader->needrestart += (cta_res[23] << 8);
+ reader->needrestart += (cta_res[24] );
+ reader->needrestart--;
+ if(reader->cak7_seq <= 15)
+ {
+ rdr_log(reader, "card needs FASTreinit after %d CMDs", reader->needrestart);
}
else
{
- reader->cak7_seq = 0;
- CAK7_getCamKey(reader);
+ uint32_t cmdleft = reader->needrestart - reader->cak7_seq;
+ rdr_log(reader, "%d CMDs left to FASTreinit", cmdleft);
}
+ reader->dword_83DBC = (cta_res[18] << 24);
+ reader->dword_83DBC += (cta_res[19] << 16);
+ reader->dword_83DBC += (cta_res[20] << 8);
+ reader->dword_83DBC += (cta_res[21] );
+ calc_cak7_exponent(&reader->dword_83DBC, reader->cak7expo, 0x11);
+ rdr_log_dump_dbg(reader, D_READER, reader->cak7expo, 0x11, "CAK7 Exponent:");
+ memcpy(reader->cardid,cta_res + 14, 4);
+ rdr_log_dump_dbg(reader, D_READER, reader->cardid, 0x04, "CardSerial: ");
+ memcpy(reader->hexserial + 2, reader->cardid, 4);
+ unsigned long datal = (cta_res[9] << 24) + (cta_res[10] << 16) + (cta_res[11] << 8) + (cta_res[12]);
+ datal++;
+ reader->data2[0] = (datal >> 24) & 0xFF;
+ reader->data2[1] = (datal >> 16) & 0xFF;
+ reader->data2[2] = (datal >> 8) & 0xFF;
+ reader->data2[3] = (datal ) & 0xFF;
+ data1r++;
+ reader->timestmp2[0]=(data1r>>24)&0xFF;
+ reader->timestmp2[1]=(data1r>>16)&0xFF;
+ reader->timestmp2[2]=(data1r>>8)&0xFF;
+ reader->timestmp2[3]=(data1r)&0xFF;
+ memcpy(reader->ecmheader,cta_res + 18,4);
+ if(reader->cak7_seq <= 15)
+ {
+ uint8_t mdc_hash2[MDC2_DIGEST_LENGTH];
+ memset(mdc_hash2,0x00,MDC2_DIGEST_LENGTH);
+ uint8_t check2[0x78];
+ memset(check2, 0x00, 0x78);
+ memcpy(check2, reader->cardid, 4);
+ memcpy(check2 + 16, reader->kdt05_10, 0x68);
+ MDC2_CTX c2;
+ MDC2_Init(&c2);
+ MDC2_Update(&c2, check2, 0x78);
+ MDC2_Final(&(mdc_hash2[0]), &c2);
+ rdr_log_dump_dbg(reader, D_READER, reader->ideakey1, 16, "IDEAKEY1: ");
+ rdr_log_dump_dbg(reader, D_READER, mdc_hash2, 16, "MDC_HASH: ");
+ if(memcmp(mdc_hash2 + 1, reader->ideakey1 + 1, 14) == 0)
+ {
+ rdr_log(reader, "DT05_10 is correct");
+ }
+ else
+ {
+ rdr_log(reader, "DT05_10 error - check MOD1");
+ }
+ }
+ BN_CTX *ctx0 = BN_CTX_new();
+#ifdef WITH_LIBCRYPTO
+ BN_CTX_start(ctx0);
+#endif
+ BIGNUM *bnN0 = BN_CTX_get(ctx0);
+ BIGNUM *bnE0 = BN_CTX_get(ctx0);
+ BIGNUM *bnCT0 = BN_CTX_get(ctx0);
+ BIGNUM *bnPT0 = BN_CTX_get(ctx0);
+ BN_bin2bn(&reader->mod50[0], 0x50, bnN0);
+ BN_bin2bn(&reader->cak7expo[0], 0x11, bnE0);
+ BN_bin2bn(&reader->data50[0], 0x50, bnCT0);
+ BN_mod_exp(bnPT0, bnCT0, bnE0, bnN0, ctx0);
+ memset(reader->data, 0x00, sizeof(reader->data));
+ BN_bn2bin(bnPT0, reader->data + (0x50 - BN_num_bytes(bnPT0)));
+ BN_CTX_end(ctx0);
+ BN_CTX_free(ctx0);
+ rdr_log_dump_dbg(reader, D_READER, reader->timestmp2, 4, "DATA1 CMD03:");
+ memcpy(&reader->step1[0], d00ff, 4);
+ memcpy(&reader->step1[4], reader->data, 0x50);
+ memcpy(&reader->step1[4 + 0x50], reader->idird, 0x04);
+ memcpy(&reader->step1[4 + 4 + 0x50], reader->timestmp2, 0x04);
+ memcpy(&reader->step1[4 + 4 + 4 + 0x50], reader->data2, 0x04);
+ rdr_log_dump_dbg(reader, D_READER, reader->step1, sizeof(reader->step1), "STEP 1:");
+ reader->pairtype = cta_res[13];
+ if((reader->pairtype > 0x00) && (reader->pairtype < 0xC0))
+ {
+ rdr_log(reader,"Card is starting in GLOBAL mode");
+ if(!CAK7_cmd03_global(reader))
+ {return ERROR;}
+ }
+ else if(reader->pairtype == 0xC0)
+ {
+ rdr_log(reader,"Card is starting in UNIQUE mode");
+ if(!reader->mod2_length)
+ {
+ rdr_log(reader, "no mod2 defined");
+ return ERROR;
+ }
+ if(!reader->key3460_length)
+ {
+ rdr_log(reader, "no key3460 defined");
+ return ERROR;
+ }
+ if(!reader->key3310_length)
+ {
+ rdr_log(reader, "no key3310 defined");
+ return ERROR;
+ }
+ if(!CAK7_cmd03_unique(reader))
+ {return ERROR;}
+ }
+ else
+ {
+ rdr_log(reader,"Unknown Pairing Type");
+ return ERROR;
+ }
+ return OK;
}
-
static int32_t nagra3_card_init(struct s_reader *reader, ATR *newatr)
{
get_atr;
-
- memset(reader->hexserial, 0x00, 0x08);
-
- reader->public_exponent[0] = 0x01;
- reader->public_exponent[1] = 0x00;
- reader->public_exponent[2] = 0x01;
- reader->public_exponent_length = 3;
-
- reader->irdid[0] = 0x64;
- reader->irdid[1] = 0x65;
- reader->irdid[2] = 0x6D;
- reader->irdid[3] = 0x6F;
- reader->irdid_length = 4;
-
+ memset(reader->hexserial, 0, 8);
reader->cak7_seq = 0;
+ reader->hasunique = 0;
+ memset(reader->ecmheader, 0, 4);
cs_clear_entitlement(reader);
-
- if(memcmp(atr + 11, "DNASP4", 6) == 0)
+ if(memcmp(atr + 8, "DNASP4", 6) == 0)
+ {
+ if((memcmp(atr + 8, "DNASP400", 8) == 0) && !reader->cak7_mode)
+ {
+ return ERROR;
+ }
+ else
+ {
+ memcpy(reader->rom, atr + 8, 15);
+ rdr_log(reader,"Rom revision: %.15s", reader->rom);
+ }
+ }
+ else if(memcmp(atr + 11, "DNASP4", 6) == 0)
{
memcpy(reader->rom, atr + 11, 15);
rdr_log(reader,"Rom revision: %.15s", reader->rom);
@@ -415,29 +1330,89 @@ static int32_t nagra3_card_init(struct s_reader *reader, ATR *newatr)
{
return ERROR;
}
-
- // check the completeness of the required CAK7 keys
- if(reader->mod1_length && reader->irdid_length && reader->data50_length && reader->mod50_length && reader->key60_length && reader->exp60_length && reader->nuid_length)
+ reader->nprov = 1;
+ /*reader->nsa = 0;
+ reader->nemm84 = 0;
+ reader->nemm83u = 0;
+ reader->nemm83s = 0;
+ reader->nemm87 = 0;*/
+ if(!reader->mod1_length)
{
- rdr_log_dbg(reader, D_READER, "All parameters for CAK7 global pairing are set.");
+ rdr_log(reader, "no MOD1 defined");
+ return ERROR;
}
- else
+ if(!reader->key3588_length)
{
- rdr_log(reader, "ERROR: Not all required CAK7 parameters are set!");
- reader->card_status = CARD_FAILURE;
- return ERROR;
+ rdr_log(reader, "no key3588 defined");
+ return ERROR;
+ }
+ if(!reader->data50_length)
+ {
+ rdr_log(reader, "no data50 defined");
+ return ERROR;
+ }
+ if(!reader->mod50_length)
+ {
+ rdr_log(reader, "no mod50 defined");
+ return ERROR;
+ }
+ if(!reader->idird_length)
+ {
+ rdr_log(reader, "no idird defined");
+ return ERROR;
+ }
+ CAK7GetDataType(reader, 0x02);
+ CAK7GetDataType(reader, 0x05);
+ if(!CAK7_GetCamKey(reader))
+ {return ERROR;}
+ CAK7GetDataType(reader, 0x09);
+ char tmp[4 * 3 + 1];
+ reader->nsa = 0;
+ reader->nemm84 = 0;
+ reader->nemm83u = 0;
+ reader->nemm83s = 0;
+ reader->nemm87 = 0;
+ CAK7GetDataType(reader, 0x04);
+ if(reader->forceemmg)
+ {
+ reader->emm82 = 1;
+ }
+ int i;
+ for(i = 1; i < reader->nprov; i++)
+ {
+ rdr_log(reader, "Prv.ID: %s", cs_hexdump(1, reader->prid[i], 4, tmp, sizeof(tmp)));
+ }
+ if(reader->cak7type != 3)
+ {
+ rdr_log(reader, "-----------------------------------------");
+ rdr_log(reader, "| EMM Filters (PRIVATE!!) |");
+ rdr_log(reader, "+---------------------------------------+");
+ if(reader->emm82 == 1)
+ {
+ rdr_log(reader, "|emm82 |");
+ }
+ char tmp7[48];
+ for(i = 0; i < reader->nemm84; i++)
+ {
+ rdr_log(reader, "|emm84 : %s |", cs_hexdump(1, reader->emm84[i], 3, tmp7, sizeof(tmp7)));
+ }
+ for(i = 0; i < reader->nemm83u; i++)
+ {
+ rdr_log(reader, "|emm83U: %s |", cs_hexdump(1, reader->emm83u[i], 6, tmp7, sizeof(tmp7)));
+ }
+ for(i = 0; i < reader->nemm83s; i++)
+ {
+ rdr_log(reader, "|emm83S: %s |", cs_hexdump(1, reader->emm83s[i], 6, tmp7, sizeof(tmp7)));
+ }
+ for(i = 0; i < reader->nemm87; i++)
+ {
+ rdr_log(reader, "|emm87 : %s |", cs_hexdump(1, reader->emm87[i], 6, tmp7, sizeof(tmp7)));
+ }
+ rdr_log(reader, "-----------------------------------------");
}
-
- reader->nprov = 1;
-
- CAK7GetDataType(reader, DT05);
- CAK7GetDataType(reader, SYSID_CAID); // sysid+caid
- CAK7_getCamKey(reader);
-
rdr_log(reader, "ready for requests");
return OK;
}
-
static int32_t nagra3_card_info(struct s_reader *reader)
{
char tmp[4 * 3 + 1];
@@ -446,73 +1421,157 @@ static int32_t nagra3_card_info(struct s_reader *reader)
rdr_log_sensitive(reader, "SER: {%s}", cs_hexdump(1, reader->hexserial + 2, 4, tmp, sizeof(tmp)));
rdr_log(reader, "CAID: %04X", reader->caid);
rdr_log(reader, "Prv.ID: %s(sysid)", cs_hexdump(1, reader->prid[0], 4, tmp, sizeof(tmp)));
- CAK7GetDataType(reader, IRDINFO);
cs_clear_entitlement(reader); // reset the entitlements
rdr_log(reader, "-----------------------------------------");
rdr_log(reader, "|id |tier |valid from |valid to |");
rdr_log(reader, "+----+--------+------------+------------+");
- CAK7GetDataType(reader, TIERS);
+ CAK7GetDataType(reader, 0x03);
+ CAK7GetDataType(reader, 0x0C);
rdr_log(reader, "-----------------------------------------");
- uint8_t i;
- for(i = 1; i < reader->nprov; i++)
+ return OK;
+}
+static int32_t fastreinit(struct s_reader *reader)
+{
+ ATR newatr[ATR_MAX_SIZE];
+ memset(newatr, 0, 1);
+ if(ICC_Async_Activate(reader, newatr, 0))
{
- rdr_log(reader, "Prv.ID: %s", cs_hexdump(1, reader->prid[i], 4, tmp, sizeof(tmp)));
+ return ERROR;
+ }
+ reader->cak7_seq = 0;
+ if(!CAK7_GetCamKey(reader))
+ {
+ return ERROR;
}
-
- struct timeb now;
- cs_ftime(&now);
- reader->last_refresh=now;
-
return OK;
}
-
static void nagra3_post_process(struct s_reader *reader)
{
- if(reader->cak7_seq >= reader->cak7_restart)
+ if(reader->cak7_seq >= reader->needrestart)
{
- rdr_log(reader, "reinit necessary to reset command counter");
- CAK7_reinit(reader);
+ rdr_log(reader, "card needs FASTreinit to prevent crash");
+ if(!fastreinit(reader))
+ {
+ rdr_log(reader, "FASTreinit failed - need to restart reader");
+ reader->card_status = CARD_NEED_INIT;
+ add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
+ }
}
else if((reader->cak7_camstate & 64) == 64)
{
- rdr_log_dbg(reader, D_READER, "renew Session Key: CAK7");
- add_job(reader->client, ACTION_READER_RENEW_SK, NULL, 0); //CAK7_getCamKey
+ rdr_log(reader, "negotiating new Session Key");
+ if(!CAK7_GetCamKey(reader))
+ {
+ rdr_log(reader, "negotiations failed - trying FASTreinit");
+ if(!fastreinit(reader))
+ {
+ rdr_log(reader, "FASTreinit failed - need to restart reader");
+ reader->card_status = CARD_NEED_INIT;
+ add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
+ }
+ }
}
}
-
static int32_t nagra3_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea)
{
def_resp;
-
+ if(reader->cak7type == 3)
+ {
+ if(er->ecm[2] > 0x61 && er->ecm[7] == 0x5C && er->ecm[100] == 0x0B)
+ {
+ if(er->ecm[101] == 0x03 || er->ecm[101] == 0x04)
+ {
+ if(er->ecm[104] > reader->pairtype)
+ {
+ rdr_log(reader, "reinit card in Unique Pairing Mode");
+ return ERROR;
+ }
+ if(er->ecm[104] == 0x80 && reader->pairtype == 0x80)
+ {
+ rdr_log(reader, "reinit card in Unique Pairing Mode");
+ return ERROR;
+ }
+ }
+ if(er->ecm[101] == 0x04 && !reader->nuid_length)
+ {
+ rdr_log(reader, "reinit card with NUID");
+ return ERROR;
+ }
+ }
+ }
+ else
+ {
+ if(er->ecm[2] > 0x86 && er->ecm[4] == 0x84 && er->ecm[137] == 0x0B)
+ {
+ if(er->ecm[138] == 0x03 || er->ecm[138] == 0x04)
+ {
+ if(er->ecm[141] > reader->pairtype)
+ {
+ rdr_log(reader, "reinit card in Unique Pairing Mode");
+ return ERROR;
+ }
+ if(er->ecm[141] == 0x80 && reader->pairtype == 0x80)
+ {
+ rdr_log(reader, "reinit card in Unique Pairing Mode");
+ return ERROR;
+ }
+ }
+ if(er->ecm[138] == 0x04 && !reader->nuid_length)
+ {
+ rdr_log(reader, "reinit card with NUID");
+ return ERROR;
+ }
+ }
+ }
uint8_t ecmreq[0xC0];
memset(ecmreq,0xCC,0xC0);
-
ecmreq[ 7] = 0x05;
- ecmreq[ 8] = 0x8A;
- ecmreq[ 9] = 0x00;
- ecmreq[10] = 0x00;
- ecmreq[11] = 0x00;
- ecmreq[12] = 0x00;
- ecmreq[13] = 0x01;
- memcpy(&ecmreq[14], er->ecm + 4, er->ecm[4] + 1);
-
+ if(reader->caid == 0x1830)
+ {
+ ecmreq[ 9] = 0x00;
+ ecmreq[10] = 0x00;
+ ecmreq[11] = 0x00;
+ ecmreq[12] = 0x00;
+ ecmreq[13] = 0x00;
+ }
+ else
+ {
+ ecmreq[ 9] = 0x04;
+ ecmreq[10] = reader->ecmheader[0];
+ ecmreq[11] = reader->ecmheader[1];
+ ecmreq[12] = reader->ecmheader[2];
+ ecmreq[13] = reader->ecmheader[3];
+ }
+ if(reader->cak7type == 3)
+ {
+ ecmreq[8] = er->ecm[7] + 6;
+ memcpy(&ecmreq[14], er->ecm + 7, er->ecm[7] + 1);
+ }
+ else
+ {
+ ecmreq[8] = er->ecm[4] + 6;
+ memcpy(&ecmreq[14], er->ecm + 4, er->ecm[4] + 1);
+ }
+ if((er->ecm[2] == 0xAC) && (er->ecm[3] == 0x05))
+ {
+ ecmreq[15] = 0x0A;
+ }
do_cak7_cmd(reader, cta_res, &cta_lr, ecmreq, sizeof(ecmreq), 0xB0);
-
- if(cta_res[cta_lr - 2] != 0x90 && cta_res[cta_lr - 1] != 0x00)
+ rdr_log_dump_dbg(reader, D_READER, cta_res, 0xB0, "Decrypted ECM Answer:");
+ if((cta_res[cta_lr - 2] != 0x90 && cta_res[cta_lr - 1] != 0x00) || cta_lr == 0)
{
rdr_log(reader, "(ECM) Reader will be restart now cause: %02X %02X card answer!!!", cta_res[cta_lr - 2], cta_res[cta_lr - 1]);
reader->card_status = CARD_NEED_INIT;
add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
}
-
- if(cta_res[27] == 0x5C)
+ else if(cta_res[27] != 0x00 && cta_res[27] != 0xCC)
{
+ memcpy(reader->ecmheader, cta_res + 9, 4);
+ reader->cak7_camstate = cta_res[4];
uint8_t _cwe0[8];
uint8_t _cwe1[8];
-
- if(cta_res[78] == 0x01)
+ if(cta_res[78] == 0x01 || reader->forcecwswap)
{
- rdr_log (reader,"Swap dcw is at use !");
memcpy(_cwe0,&cta_res[52], 0x08);
memcpy(_cwe1,&cta_res[28], 0x08);
}
@@ -521,124 +1580,164 @@ static int32_t nagra3_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, str
memcpy(_cwe0,&cta_res[28], 0x08);
memcpy(_cwe1,&cta_res[52], 0x08);
}
-
- if(!reader->cwekey_length)
+ if(cta_res[27] == 0x5C)
{
- rdr_log_dbg(reader, D_READER, "ERROR: CWPK is not set, can not decrypt CW");
- return ERROR;
+ if(!reader->cwekey0_length)
+ {
+ rdr_log(reader, "ERROR: CWPK is not set, can not decrypt CW");
+ return ERROR;
+ }
+ des_ecb3_decrypt(_cwe0, reader->cwekey0);
+ des_ecb3_decrypt(_cwe1, reader->cwekey0);
}
- des_ecb3_decrypt(_cwe0, reader->cwekey);
- des_ecb3_decrypt(_cwe1, reader->cwekey);
-
- int chkok = 1;
- if(((_cwe0[0] + _cwe0[1] + _cwe0[2]) & 0xFF) != _cwe0[3])
+ else if(cta_res[27] == 0x58)
{
- chkok = 0;
- rdr_log_dbg(reader, D_READER, "CW0 checksum error [0]");
+ des_ecb3_decrypt(_cwe0, reader->key3des);
+ des_ecb3_decrypt(_cwe1, reader->key3des);
}
-
- if(((_cwe0[4] + _cwe0[5] + _cwe0[6]) & 0xFF) != _cwe0[7])
+ rdr_log_dbg(reader, D_READER, "CW Decrypt ok");
+ memcpy(ea->cw, _cwe0, 0x08);
+ memcpy(ea->cw + 8, _cwe1, 0x08);
+ return OK;
+ }
+ else if(cta_res[23] == 0x00)
+ {
+ memcpy(reader->ecmheader, cta_res + 9, 4);
+ reader->cak7_camstate = cta_res[4];
+ if(reader->hasunique && reader->pairtype < 0xC0)
{
- chkok = 0;
- rdr_log_dbg(reader, D_READER, "CW0 checksum error [1]");
+ rdr_log(reader, "reinit card in Unique Pairing Mode");
}
-
- if(((_cwe1[0] + _cwe1[1] + _cwe1[2]) & 0xFF) != _cwe1[3])
+ else
{
- chkok = 0;
- rdr_log_dbg(reader, D_READER, "CW1 checksum error [0]");
+ rdr_log(reader, "card has no right to decode this channel");
}
-
- if(((_cwe1[4] + _cwe1[5] + _cwe1[6]) & 0xFF) != _cwe1[7])
+ }
+ else if(cta_res[23] == 0x04)
+ {
+ if(!reader->nuid_length)
{
- chkok = 0;
- rdr_log_dbg(reader, D_READER, "CW1 checksum error [1]");
+ rdr_log(reader, "reinit card with NUID");
}
-
- reader->cak7_camstate = cta_res[4];
- if(chkok == 1)
+ else
{
- rdr_log_dbg(reader, D_READER, "CW Decrypt ok");
- memcpy(ea->cw, _cwe0, 0x08);
- memcpy(ea->cw + 8, _cwe1, 0x08);
- return OK;
+ rdr_log(reader, "wrong OTP/OTA CSC values");
}
}
-
+ else
+ {
+ rdr_log(reader, "card got wrong ECM");
+ }
return ERROR;
}
-
static int32_t nagra3_do_emm(struct s_reader *reader, EMM_PACKET *ep)
{
def_resp;
- uint8_t emmreq[0xC0];
- memset(emmreq, 0xCC, 0xC0);
- emmreq[ 7] = 0x05;
- emmreq[ 8] = 0x8A;
- emmreq[ 9] = 0x00;
- emmreq[10] = 0x00;
- emmreq[11] = 0x00;
- emmreq[12] = 0x00;
- emmreq[13] = 0x01;
- memcpy(&emmreq[14], ep->emm + 9, ep->emm[9] + 1);
- do_cak7_cmd(reader, cta_res, &cta_lr, emmreq, sizeof(emmreq), 0xB0);
-
- if(cta_lr == 0)
- {
- rdr_log_dbg(reader, D_READER, "card reinit necessary");
- CAK7_reinit(reader);
- }
- else if(cta_res[cta_lr - 2] != 0x90 && cta_res[cta_lr - 1] != 0x00)
+ if(ep->emm[0] == 0x90)
{
- rdr_log(reader, "(EMM) Reader will be restart now cause: %02X %02X card answer!!!", cta_res[cta_lr - 2], cta_res[cta_lr - 1]);
- CAK7_reinit(reader);
+ rdr_log(reader, "OSCam got your BoxEMM");
+ char tmp[128];
+ rdr_log(reader, "NUID: %s", cs_hexdump(1, reader->nuid, 4, tmp, sizeof(tmp)));
+ rdr_log(reader, "Index: %s", cs_hexdump(1, ep->emm + 10, 1, tmp, sizeof(tmp)));
+ rdr_log(reader, "eCWPK: %s", cs_hexdump(1, ep->emm + 11, 16, tmp, sizeof(tmp)));
}
else
{
- if(reader->cak7_seq >= reader->cak7_restart)
+ uint8_t emmreq[0xC0];
+ memset(emmreq, 0xCC, 0xC0);
+ emmreq[ 7] = 0x05;
+ if(reader->caid == 0x1830)
{
- rdr_log_dbg(reader, D_READER, "reinit necessary to reset command counter");
- CAK7_reinit(reader);
+ emmreq[ 9] = 0x00;
+ emmreq[10] = 0x00;
+ emmreq[11] = 0x00;
+ emmreq[12] = 0x00;
+ emmreq[13] = 0x00;
}
- else if(cta_res[4] == 0x80)
+ else
{
- rdr_log_dbg(reader, D_READER, "EMM forced card to reinit");
- reader->card_status = CARD_NEED_INIT;
- add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
- return OK;
+ emmreq[ 9] = 0x04;
+ emmreq[10] = reader->ecmheader[0];
+ emmreq[11] = reader->ecmheader[1];
+ emmreq[12] = reader->ecmheader[2];
+ emmreq[13] = reader->ecmheader[3];
}
- else if(cta_res[13] == 0x02)
+ if(reader->cak7type == 3)
{
- rdr_log_dbg(reader, D_READER, "Revision update - card reinit necessary");
- reader->card_status = CARD_NEED_INIT;
- add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
- return OK;
+ int32_t i;
+ uint8_t *prov_id_ptr;
+ switch(ep->type)
+ {
+ case SHARED:
+ emmreq[8] = ep->emm[9] + 6;
+ prov_id_ptr = ep->emm + 3;
+ memcpy(&emmreq[14], ep->emm + 9, ep->emm[9] + 1);
+ break;
+ case UNIQUE:
+ emmreq[8] = ep->emm[12] + 6;
+ prov_id_ptr = ep->emm + 9;
+ memcpy(&emmreq[14], ep->emm + 12, ep->emm[12] + 1);
+ break;
+ case GLOBAL:
+ emmreq[8] = ep->emm[6] + 6;
+ prov_id_ptr = ep->emm + 3;
+ memcpy(&emmreq[14], ep->emm + 6, ep->emm[6] + 1);
+ break;
+ default:
+ rdr_log(reader, "EMM: Congratulations, you have discovered a new EMM on Merlin.");
+ rdr_log(reader, "This has not been decoded yet.");
+ return ERROR;
+ }
+ i = get_prov_index(reader, prov_id_ptr);
+ if(i == -1)
+ {
+ rdr_log(reader, "EMM: skipped since provider id doesnt match");
+ return SKIPPED;
+ }
}
- else if((cta_res[4] & 64) == 64)
+ else
{
- rdr_log_dbg(reader, D_READER, "negotiating new Session Key");
- CAK7_getCamKey(reader);
+ emmreq[8] = ep->emm[9] + 6;
+ memcpy(&emmreq[14], ep->emm + 9, ep->emm[9] + 1);
}
- else if(cta_res[8] == 0x0E)
+ do_cak7_cmd(reader, cta_res, &cta_lr, emmreq, sizeof(emmreq), 0xB0);
+ if((cta_res[cta_lr-2] != 0x90 && cta_res[cta_lr-1] != 0x00) || cta_lr == 0)
{
- rdr_log_dbg(reader, D_READER, "card got wrong EMM");
- return OK;
+ rdr_log(reader, "(EMM) Reader will be restart now cause: %02X %02X card answer!!!", cta_res[cta_lr - 2], cta_res[cta_lr - 1]);
+ reader->card_status = CARD_NEED_INIT;
+ add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
}
-
- struct timeb now;
- cs_ftime(&now);
- int64_t gone_now = comp_timeb(&now, &reader->emm_last);
- int64_t gone_refresh = comp_timeb(&reader->emm_last, &reader->last_refresh);
- if(((gone_now > (int64_t)3600*1000) && (gone_now < (int64_t)365*24*3600*1000)) || ((gone_refresh > (int64_t)12*3600*1000) && (gone_refresh < (int64_t)365*24*3600*1000)))
+ else
{
- reader->last_refresh=now;
- add_job(reader->client, ACTION_READER_CARDINFO, NULL, 0); // refresh entitlement since it might have been changed!
+ memcpy(reader->ecmheader, cta_res + 9, 4);
+ if(reader->cak7_seq >= reader->needrestart)
+ {
+ rdr_log(reader, "card needs FASTreinit to prevent crash");
+ if(!fastreinit(reader))
+ {
+ rdr_log(reader, "FASTreinit failed - need to restart reader");
+ reader->card_status = CARD_NEED_INIT;
+ add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
+ }
+ }
+ else if((cta_res[4] & 64) == 64)
+ {
+ rdr_log(reader, "negotiating new Session Key");
+ if(!CAK7_GetCamKey(reader))
+ {
+ rdr_log(reader, "negotiations failed - trying FASTreinit");
+ if(!fastreinit(reader))
+ {
+ rdr_log(reader, "FASTreinit failed - need to restart reader");
+ reader->card_status = CARD_NEED_INIT;
+ add_job(reader->client, ACTION_READER_RESTART, NULL, 0);
+ }
+ }
+ }
}
}
-
return OK;
}
-
const struct s_cardsystem reader_nagracak7 =
{
.desc = "nagra merlin",
@@ -651,5 +1750,4 @@ const struct s_cardsystem reader_nagracak7 =
.get_emm_type = nagra_get_emm_type,
.get_emm_filter = nagra_get_emm_filter,
};
-
#endif
diff --git a/reader-seca.c b/reader-seca.c
index 76826095d..33d451222 100644
--- a/reader-seca.c
+++ b/reader-seca.c
@@ -441,7 +441,14 @@ static int32_t seca_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struc
if((cta_res[0] == 0x93) && (cta_res[1] == 0x02))
{
write_cmd(ins3a, NULL); // get cw
- snprintf(ea->msglog, MSGLOGSIZE, "unsubscribed 93 02");
+ if(er->ecm[2] > 0x61 && er->ecm[7] == 0x5C && er->ecm[100] == 0x0B)
+ {
+ rdr_log(reader, "reinit card in CAK7 mode");
+ }
+ else
+ {
+ snprintf(ea->msglog, MSGLOGSIZE, "unsubscribed 93 02");
+ }
return ERROR;
} // exit if unsubscribed
diff --git a/reader-viaccess.c b/reader-viaccess.c
index 4aa6185c1..dbf916e73 100644
--- a/reader-viaccess.c
+++ b/reader-viaccess.c
@@ -6,7 +6,120 @@
#include "reader-common.h"
#include "cscrypt/des.h"
#include "oscam-work.h"
-
+typedef unsigned int uint;
+typedef unsigned char byte;
+uint8_t N98Init = 0;
+uint KeyS[132];
+char SBoxInverse[] = {
+ 13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2,
+ 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0,
+ 12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7,
+ 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1,
+ 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1,
+ 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0,
+ 15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11,
+ 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 };
+uint getBit(uint number, int bt)
+{
+ return (number >> bt ) & 1;
+}
+void SBitslice(uint* Iarray, int offsetin, uint* Oarray, int offsetout, int row, char* box)
+{
+ int bi,input,l,output;
+ uint calcArray[4] = {0,0,0,0};
+ for (bi = 0; bi < 32; bi++)
+ {
+ input = 0;
+ for (l = 0; l < 4; l++)
+ input += getBit(Iarray[l+offsetin],bi) << l;
+ output = box[input+16*row];
+ for (l = 0; l < 4; l++)
+ calcArray[l] += getBit(output,l) << bi;
+ }
+ for (l = 0; l < 4; l++)
+ Oarray[l+offsetout] = calcArray[l];
+}
+void xorBlock(uint* data, int offset)
+{
+ int i;
+ for (i = 0; i < 4; i++)
+ data[i] ^= KeyS[i + 4*offset];
+}
+uint rotr(uint val, int nbits)
+{
+ return ((val >> nbits) + (val << (32 - nbits)));
+}
+void LTBitsliceInverse(uint* data)
+{
+ uint C0 = data[0];
+ uint C1 = data[1];
+ uint C2 = data[2];
+ uint C3 = data[3];
+ C2 = rotr(C2,22);
+ C0 = rotr(C0,5);
+ C2 ^= C3 ^ (C1 << 7);
+ C0 ^= C1 ^ C3;
+ C3 = rotr(C3,7);
+ C3 ^= C2 ^ (C0 << 3);
+ C1 = rotr(C1,1);
+ C1 ^= C0 ^ C2;
+ C2 = rotr(C2,3);
+ C0 = rotr(C0,13);
+ data[0] = C0;
+ data[1] = C1;
+ data[2] = C2;
+ data[3] = C3;
+}
+void N98_decrypt(byte* data)
+{
+ int r; // round
+ int i,j;
+ uint N98[4]; // make 32 bits words
+ for(i = 0; i < 4; i++)
+ N98[i] = data[4*i] + (data[4*i+1] << 8) + (data[4*i+2] << 16) + (data[4*i+3] << 24);
+ for(r = 31; r >= 0; r--) // decrypt, inverse order
+ {
+ if (r == 31) {
+ xorBlock(N98,32);
+ } else {
+ LTBitsliceInverse(N98); // inverse Linear Transform
+ }
+ SBitslice(N98,0,N98,0, (r & 7), SBoxInverse); // SBox inverse, bitslice mode
+ xorBlock(N98, r);
+ }
+ for(i = 0; i < 4; i++) // set bytes to caller's array
+ for(j = 0; j < 4; j++)
+ data[4*i+j] = (N98[i] >> 8*j) & 0xFF;
+}
+void MakeSubKeys(uint* KeySch, char key98Idx)
+{
+ int i,k;
+ char j;
+ uint w[140] = {0};
+ char Sbox[128];
+ // uint KeyS[132];
+ // calc SBox , inverse of SBoxInverse
+ for(i = 0; i < 8; i++) //row
+ {
+ for(j = 0; j < 16; j++) // search for column
+ {
+ k=0;
+ while (SBoxInverse[k+16*i] != j)
+ k = k +1;
+ Sbox[j+16*i] = k;
+ }
+ }
+ switch (key98Idx)
+ {
+ case 0x21:
+ w[0]=0x6341F22E; w[1]=0x002E2D10; w[2]=0x181D7704; w[3]=0x1D93A0F3; w[4]=1; w[5]=0; w[6]=0; w[7]=0;
+ break;
+ }
+ for(i = 0; i < 132; i++)
+ w[i+8] = rotr(w[i+0] ^ w[i+3] ^ w[i+5] ^ w[i+7] ^ 0x9E3779B9 ^ i, 21);
+ for(i = 0; i < 33; i++)
+ SBitslice(w,4*i+8,KeySch,4*i, ((35-i) & 7), Sbox); // SBox , bitslice mode
+}
struct geo_cache
{
uint32_t provid;
@@ -14,33 +127,27 @@ struct geo_cache
uint8_t geo_len;
int32_t number_ecm;
};
-
struct viaccess_data
{
struct geo_cache last_geo;
uint8_t availkeys[CS_MAXPROV][16];
};
-
struct via_date
{
uint16_t day_s : 5;
uint16_t month_s : 4;
uint16_t year_s : 7;
-
uint16_t day_e : 5;
uint16_t month_e : 4;
uint16_t year_e : 7;
};
-
static void parse_via_date(const uint8_t *buf, struct via_date *vd, int32_t fend)
{
uint16_t date;
-
date = (buf[0] << 8) | buf[1];
vd->day_s = date & 0x1f;
vd->month_s = (date >> 5) & 0x0f;
vd->year_s = (date >> 9) & 0x7f;
-
if(fend)
{
date = (buf[2] << 8) | buf[3];
@@ -49,55 +156,44 @@ static void parse_via_date(const uint8_t *buf, struct via_date *vd, int32_t fend
vd->year_e = (date >> 9) & 0x7f;
}
}
-
struct emm_rass *find_rabuf(struct s_client *client, int32_t provid, uint8_t nano, int8_t add)
{
struct emm_rass *e;
LL_ITER it;
-
if(!client->ra_buf)
{
client->ra_buf = ll_create("client->ra_buf");
}
-
it = ll_iter_create(client->ra_buf);
-
while((e = ll_iter_next(&it)) != NULL)
{
if(!add && e->provid == provid && e->emmlen != 0)
{
return e;
}
-
if(add && e->provid == provid && e->emm[0] == nano)
{
return e;
}
}
-
if(!add)
{
return NULL;
}
-
if(!cs_malloc(&e, sizeof(struct emm_rass)))
{
return NULL;
}
-
e->provid = provid;
ll_append(client->ra_buf, e);
return e;
}
-
static void show_class(struct s_reader *reader, const char *p, uint32_t provid, const uint8_t *b, int32_t l)
{
int32_t i, j;
-
// b -> via date (4 uint8_ts)
b += 4;
l -= 4;
-
j = l - 1;
for(; j >= 0; j--)
{
@@ -109,7 +205,6 @@ static void show_class(struct s_reader *reader, const char *p, uint32_t provid,
struct via_date vd;
parse_via_date(b - 4, &vd, 1);
cls = (l - (j + 1)) * 8 + i;
-
if(p) // just show class info, dont add entitlement!
{
rdr_log(reader, "%sclass: %02X, expiry date: %04d/%02d/%02d - %04d/%02d/%02d", p, cls,
@@ -121,7 +216,6 @@ static void show_class(struct s_reader *reader, const char *p, uint32_t provid,
rdr_log(reader, "class: %02X, expiry date: %04d/%02d/%02d - %04d/%02d/%02d", cls,
vd.year_s + 1980, vd.month_s, vd.day_s,
vd.year_e + 1980, vd.month_e, vd.day_e);
-
//convert time:
time_t start_t, end_t;
struct tm tm;
@@ -130,7 +224,6 @@ static void show_class(struct s_reader *reader, const char *p, uint32_t provid,
tm.tm_mon = vd.month_s - 1; // january is 0 in tm_mon
tm.tm_mday = vd.day_s;
start_t = cs_timegm(&tm);
-
tm.tm_year = vd.year_e + 80; //via year starts in 1980, tm_year starts in 1900
tm.tm_mon = vd.month_e - 1; // january is 0 in tm_mon
tm.tm_mday = vd.day_e;
@@ -141,15 +234,12 @@ static void show_class(struct s_reader *reader, const char *p, uint32_t provid,
}
}
}
-
static int8_t add_find_class(struct s_reader *reader, uint32_t provid, const uint8_t *b, int32_t l, int8_t add)
{
int32_t i, j, freshdate = 0;
-
// b -> via date (4 uint8_ts)
b += 4;
l -= 4;
-
j = l - 1;
for(; j >= 0; j--)
{
@@ -174,15 +264,13 @@ static int8_t add_find_class(struct s_reader *reader, uint32_t provid, const uin
parse_via_date(b - 4, &vd, 1);
time_t start_t, end_t;
struct tm tm;
-
//convert time:
memset(&tm, 0, sizeof(tm));
tm.tm_year = vd.year_s + 80; // via year starts in 1980, tm_year starts in 1900
tm.tm_mon = vd.month_s - 1; // january is 0 in tm_mon
tm.tm_mday = vd.day_s;
start_t = cs_timegm(&tm);
-
- tm.tm_year = vd.year_e + 80; // via year starts in 1980, tm_year starts in 1900
+ tm.tm_year = vd.year_e + 80; //via year starts in 1980, tm_year starts in 1900
tm.tm_mon = vd.month_e - 1; // january is 0 in tm_mon
tm.tm_mday = vd.day_e;
end_t = cs_timegm(&tm);
@@ -202,15 +290,12 @@ static int8_t add_find_class(struct s_reader *reader, uint32_t provid, const uin
}
}
}
-
if(freshdate == 0)
{
return -2;
}
-
return 1; // emmdate is fresh!
}
-
static void show_subs(struct s_reader *reader, const uint8_t *emm)
{
switch(emm[0])
@@ -220,22 +305,18 @@ static void show_subs(struct s_reader *reader, const uint8_t *emm)
show_class(reader, "nano A9: ", 1, emm + 2, emm[1]);
break;
}
-
case 0xA6:
{
char szGeo[256];
-
memset(szGeo, 0, 256);
cs_strncpy(szGeo, (char *)emm + 2, emm[1]);
rdr_log(reader, "nano A6: geo %s", szGeo);
break;
}
-
case 0xB6:
{
uint8_t m; // modexp
struct via_date vd;
-
m = emm[emm[1] + 1];
parse_via_date(emm + 2, &vd, 0);
rdr_log(reader, "nano B6: modexp %d%d%d%d%d%d: %02d/%02d/%04d",
@@ -250,12 +331,10 @@ static void show_subs(struct s_reader *reader, const uint8_t *emm)
}
}
}
-
static int32_t chk_prov(struct s_reader *reader, uint8_t *id, uint8_t keynr)
{
struct viaccess_data *csystem_data = reader->csystem_data;
int32_t i, j, rc;
-
for(rc = i = 0; (!rc) && (i < reader->nprov); i++)
{
if(!memcmp(&reader->prid[i][1], id, 3))
@@ -271,25 +350,18 @@ static int32_t chk_prov(struct s_reader *reader, uint8_t *id, uint8_t keynr)
}
return (rc);
}
-
static int32_t get_maturity(struct s_reader *reader)
{
/* retrieve maturity rating on the card */
-
def_resp;
-
uint8_t insac[] = { 0xca, 0xac, 0x00, 0x00, 0x00 }; // select data
uint8_t insb8[] = { 0xca, 0xb8, 0x00, 0x00, 0x00 }; // read selected data
-
insac[2] = 0x06;
write_cmd(insac, NULL); // request maturity rating
-
insb8[4] = 0x02;
write_cmd(insb8, NULL); // read maturity rating nano + len
-
insb8[4] = cta_res[1];
write_cmd(insb8, NULL); // read maturity rating
-
reader->maturity = cta_res[cta_lr - 3] & 0x0F;
if (reader->maturity < 0xF)
{
@@ -301,15 +373,12 @@ static int32_t get_maturity(struct s_reader *reader)
}
return 0;
}
-
static int32_t unlock_parental(struct s_reader *reader)
{
/* disabling parental lock. assuming pin "0000" if no pin code is provided in the config */
-
static const uint8_t inDPL[] = { 0xca, 0x24, 0x02, 0x00, 0x09 };
uint8_t cmDPL[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F };
def_resp;
-
if(strcmp(reader->pincode, "none"))
{
rdr_log(reader, "Using PIN %s", reader->pincode);
@@ -322,7 +391,6 @@ static int32_t unlock_parental(struct s_reader *reader)
rdr_log(reader, "Using PIN 0000!");
}
write_cmd(inDPL, cmDPL);
-
if(!(cta_res[cta_lr - 2] == 0x90 && cta_res[cta_lr - 1] == 0))
{
if(strcmp(reader->pincode, "none"))
@@ -339,17 +407,14 @@ static int32_t unlock_parental(struct s_reader *reader)
rdr_log(reader, "Parental lock disabled");
get_maturity(reader);
}
-
return 0;
}
-
int32_t hdSurEncBasicCrypt_D2_0F_11(int32_t Value, int32_t XorVal)
{
int32_t i = (Value << 13) - Value + 0x1B59;
i = (i * Value) + 0x07CF;
return (i ^ XorVal);
}
-
int32_t hdSurEncCryptLookup_D2_0F_11(uint8_t Value, uint8_t AddrInd)
{
static const uint8_t lookup[] =
@@ -518,7 +583,6 @@ int32_t hdSurEncCryptLookup_D2_0F_11(uint8_t Value, uint8_t AddrInd)
uint8_t b = Value ^ hdSurEncBasicCrypt_D2_0F_11(Value, lookup[(((AddrInd * 2) + 0) * 256) + Value]);
return (Value ^ hdSurEncBasicCrypt_D2_0F_11(b, lookup[(((AddrInd * 2) + 1) * 256) + b]));
}
-
void hdSurEncPhase1_D2_0F_11(uint8_t *CWs)
{
static const uint8_t lookup1[] =
@@ -531,14 +595,12 @@ void hdSurEncPhase1_D2_0F_11(uint8_t *CWs)
static const int8_t lookup2[] = { 1, -1, -1, 1, -1, 2, 1, -2, -1, 1, 2, -2, 1, -2, -2, 4 };
static const int8_t CAddrIndex[] = { 0, 1, 3, 4 };
int32_t i, j, i1, i2, i3;
-
for(i = 3; i >= 0; --i)
{
for(j = 0; j <= 15; ++j)
{
CWs[j] = CWs[j] ^ hdSurEncBasicCrypt_D2_0F_11(j , lookup1 [(16 * i) + j]);
}
-
uint8_t Buffer[16];
uint32_t k;
for(i1 = 0; i1 <= 3; ++i1)
@@ -554,7 +616,6 @@ void hdSurEncPhase1_D2_0F_11(uint8_t *CWs)
}
}
memcpy(CWs, Buffer, 16);
-
// CW positions are mixed around here
uint8_t a4[4];
for(i1 = 1; i1 <= 3; ++i1)
@@ -563,11 +624,9 @@ void hdSurEncPhase1_D2_0F_11(uint8_t *CWs)
{
a4[i2] = i1 + (i2 * 4);
}
-
for(i2 = 0; i2 <= i1 - 1; ++i2) // the given code in Func1_3 seems to be wrong here(3 instead of i1-1)!
{
uint8_t tmp = CWs[a4[0]];
-
for(i3 = 1; i3 <= 3; ++i3)
{
CWs[a4[i3 - 1]] = CWs[a4[i3]];
@@ -575,24 +634,20 @@ void hdSurEncPhase1_D2_0F_11(uint8_t *CWs)
CWs[a4[3]] = tmp;
}
}
-
for(i1 = 0; i1 <= 15; ++i1)
{
CWs[i1] = hdSurEncCryptLookup_D2_0F_11(CWs[i1], CAddrIndex[i1 & 3]);
}
}
}
-
void hdSurEncPhase2_D2_0F_11_sub(uint8_t *CWa, uint8_t *CWb, uint8_t AddrInd)
{
uint8_t Buffer[8];
uint8_t tmp, i;
-
for(i = 0; i <= 7; ++i)
{
Buffer[i] = hdSurEncCryptLookup_D2_0F_11(CWb[i], AddrInd);
}
-
// some bitshifting
tmp = Buffer[7];
for(i = 7; i >= 1; --i)
@@ -600,14 +655,12 @@ void hdSurEncPhase2_D2_0F_11_sub(uint8_t *CWa, uint8_t *CWb, uint8_t AddrInd)
Buffer[i] = ((Buffer[1] >> 4) & 0xFF) | ((Buffer[i - 1] << 4) & 0xFF);
}
Buffer[0] = ((Buffer[0] >> 4) & 0xFF) | ((tmp << 4) & 0xFF);
-
// saving the result
for(i = 0; i <= 7; ++i)
{
CWa[i] = CWa[i] ^ Buffer[i];
}
}
-
void hdSurEncPhase2_D2_0F_11(uint8_t *CWs)
{
hdSurEncPhase2_D2_0F_11_sub(CWs, CWs + 8, 0);
@@ -616,7 +669,6 @@ void hdSurEncPhase2_D2_0F_11(uint8_t *CWs)
hdSurEncPhase2_D2_0F_11_sub(CWs + 8, CWs, 3);
hdSurEncPhase2_D2_0F_11_sub(CWs, CWs + 8, 4);
}
-
void CommonMain_1_D2_13_15(const uint8_t *datain, uint8_t *dataout)
{
const uint8_t Tab3[88] = {
@@ -626,10 +678,8 @@ void CommonMain_1_D2_13_15(const uint8_t *datain, uint8_t *dataout)
0x09, 0x06, 0x06, 0x04, 0x09, 0x06, 0x06, 0x04, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x02, 0x02,
0x04, 0x02, 0x04, 0x02, 0x02, 0x01, 0x02, 0x01, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02, 0x03, 0x02,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
-
int i1,i2;
unsigned long bb;
-
for (i1 = 0; i1 < 11; i1++)
{
bb = 0;
@@ -640,23 +690,17 @@ void CommonMain_1_D2_13_15(const uint8_t *datain, uint8_t *dataout)
dataout[i1] = (bb & 0xFF);
}
}
-
-
unsigned short CommonMain_2_D2_13_15(const uint8_t *data, const unsigned long num)
{
unsigned long bb1, bb2;
-
bb1 = num >> 3;
bb2 = (data[bb1] << 24) + (data[bb1 + 1] << 16) + (data[bb1 + 2] << 8);
-
return ((bb2 >> (21 - (num & 7))) & 0x7FF);
}
-
void CommonMain_3_D2_13_15(uint8_t *data0, uint8_t *data1, int nbrloop)
{
int i;
unsigned long bb1, bb2;
-
bb1 = 0;
bb2 = 0;
for (i = nbrloop - 1; i >= 0; i--)
@@ -669,10 +713,8 @@ void CommonMain_3_D2_13_15(uint8_t *data0, uint8_t *data1, int nbrloop)
bb2 >>= 8;
}
}
-
void CommonMain_D2_13_15(const uint8_t *datain, uint8_t *dataout, int loopval)
{
-
const uint8_t Tab0_Comp[0x800] = {
0x54,0x75,0x01,0x0C,0x7C,0xE2,0xC3,0xC2,0x5E,0x13,0x26,0xCA,0xB2,0xCD,0xB8,0x3D,
0x02,0x2C,0xE4,0x19,0x41,0x3D,0xE4,0x0F,0xEC,0xF1,0x45,0x83,0xE2,0xE2,0x72,0xF9,
@@ -802,8 +844,6 @@ void CommonMain_D2_13_15(const uint8_t *datain, uint8_t *dataout, int loopval)
0xA1,0x9B,0x45,0x15,0x90,0x63,0x22,0x5D,0x68,0x4B,0xCF,0xFA,0x6A,0x06,0xF0,0x26,
0xAC,0x6C,0x3A,0x89,0x25,0xF3,0x5E,0x90,0x06,0x93,0xB6,0x35,0x0D,0x85,0x60,0x98,
0xBC,0x6E,0xF2,0xA5,0x17,0x29,0x70,0xD6,0xFF,0x0C,0xD0,0xC0,0x35,0xD7,0x4A,0xFD };
-
-
const uint8_t Tab1_Comp[11*8] = {
0x70,0x49,0xD7,0xE3,0xDF,0x3C,0x96,0x03,0x2A,0x70,0x82,0xA6,0x5F,0xDE,0xCC,0x0C,
0x2A,0x62,0x2A,0x3E,0xA4,0x0C,0x0A,0xAB,0x4F,0x06,0x5D,0xD4,0x14,0xAA,0xE1,0xC3,
@@ -811,28 +851,23 @@ void CommonMain_D2_13_15(const uint8_t *datain, uint8_t *dataout, int loopval)
0x8F,0x85,0xC9,0x04,0x56,0xBA,0xEB,0x3F,0x42,0x9F,0xCB,0x66,0x55,0x45,0x1C,0x96,
0xFF,0x4D,0x35,0xDF,0x88,0x0E,0xDC,0xC8,0x4E,0x3F,0x81,0x74,0xD8,0x77,0x4C,0x8E,
0x00,0xC0,0x64,0x83,0x4E,0xBB,0xF0,0xB1 };
-
unsigned short buff8[8];
uint8_t buff11[11 + 1]; // +1 to avoid func2 bug
int i1, i2;
buff11[11] = 0;
-
CommonMain_1_D2_13_15(datain, buff11);
for (i1 = 0; i1 < 11; i1++)
{
buff11[i1] ^= Tab1_Comp[(loopval * 11) + i1];
}
-
for (i1 = 0; i1 < 8; i1++)
{
buff8[i1] = CommonMain_2_D2_13_15(buff11, i1 * 11);
}
-
for (i1 = 0; i1 < 8; i1++)
{
dataout[i1] = Tab0_Comp[buff8[i1]];
}
-
i1 = 1;
while (i1 < 8)
{
@@ -845,24 +880,20 @@ void CommonMain_D2_13_15(const uint8_t *datain, uint8_t *dataout, int loopval)
i1 *= 2;
}
}
-
void Common_D2_13_15(uint8_t *cw0, const uint8_t *cw1, int loopval)
{
int i;
uint8_t buff8[8];
-
CommonMain_D2_13_15(cw1, buff8, loopval);
for (i = 0; i < 8; i++)
{
cw0[i] ^= buff8[i];
}
}
-
void ExchangeCWs(uint8_t *cw0, uint8_t *cw1)
{
int i;
uint8_t b;
-
for (i = 0; i < 8; i++)
{
b = cw1[i];
@@ -870,12 +901,9 @@ void ExchangeCWs(uint8_t *cw0, uint8_t *cw1)
cw0[i] = b;
}
}
-
-
void hdSurEncPhase1_D2_13_15(uint8_t *cws)
{
int i;
-
for (i = 0; i <= 7; i++)
{
// Possible code
@@ -890,11 +918,9 @@ void hdSurEncPhase1_D2_13_15(uint8_t *cws)
}
ExchangeCWs((uint8_t *) &cws[0], (uint8_t *) &cws[8]);
}
-
void hdSurEncPhase2_D2_13_15(uint8_t *cws)
{
int i;
-
for (i = 7; i >= 0; i--)
{
// Possible code
@@ -909,8 +935,6 @@ void hdSurEncPhase2_D2_13_15(uint8_t *cws)
}
ExchangeCWs((uint8_t *) &cws[8], (uint8_t *) &cws[0]);
}
-
-
static int32_t viaccess_card_init(struct s_reader *reader, ATR *newatr)
{
get_atr;
@@ -926,25 +950,20 @@ static int32_t viaccess_card_init(struct s_reader *reader, ATR *newatr)
static uint8_t ins8702_data[] = { 0x00, 0x00, 0x11};
static uint8_t ins8704[] = { 0x87, 0x04, 0x00, 0x00, 0x07 };
static uint8_t ins8706[] = { 0x87, 0x06, 0x00, 0x00, 0x04 };
-
if((atr[1] != 0x77) || ((atr[2] != 0x18) && (atr[2] != 0x11) && (atr[2] != 0x19)) || ((atr[9] != 0x68) && (atr[9] != 0x6C) && (atr[9] != 0x64)))
{
return ERROR;
}
-
write_cmd(insFAC, FacDat);
if(!(cta_res[cta_lr - 2] == 0x90 && cta_res[cta_lr - 1] == 0))
{
return ERROR;
}
-
if(!cs_malloc(&reader->csystem_data, sizeof(struct viaccess_data)))
{
return ERROR;
}
-
struct viaccess_data *csystem_data = reader->csystem_data;
-
write_cmd(insFAC, ins8702_data);
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
{
@@ -959,7 +978,6 @@ static int32_t viaccess_card_init(struct s_reader *reader, ATR *newatr)
}
}
}
-
reader->caid = 0x500;
memset(reader->prid, 0xff, sizeof(reader->prid));
insac[2] = 0xa4;
@@ -970,7 +988,6 @@ static int32_t viaccess_card_init(struct s_reader *reader, ATR *newatr)
// rdr_log(reader, "[viaccess-reader] type: Viaccess, ver: %s serial: %llu", ver, b2ll(5, cta_res+2));
rdr_log_sensitive(reader, "type: Viaccess (%sstandard atr), caid: %04X, serial: {%llu}",
atr[9] == 0x68 ? "" : "non-", reader->caid, (unsigned long long) b2ll(5, cta_res + 2));
-
i = 0;
insa4[2] = 0x00;
write_cmd(insa4, NULL); // select issuer 0
@@ -985,37 +1002,31 @@ static int32_t viaccess_card_init(struct s_reader *reader, ATR *newatr)
memcpy(&csystem_data->availkeys[i][0], cta_res + 10, 16);
snprintf((char *)buf + cs_strlen((char *)buf), sizeof(buf) - cs_strlen((char *)buf), ",%06X", b2i(3, &reader->prid[i][1]));
// rdr_log(reader, "[viaccess-reader] buf: %s", buf);
-
insac[2] = 0xa5;
write_cmd(insac, NULL); // request sa
insb8[4] = 0x06;
write_cmd(insb8, NULL); // read sa
memcpy(&reader->sa[i][0], cta_res + 2, 4);
-
insa4[2] = 0x02;
write_cmd(insa4, NULL); // select next issuer
i++;
}
reader->nprov = i;
rdr_log(reader, "providers: %d (%s)", reader->nprov, buf + 1);
-
get_maturity(reader);
if(cfg.ulparent)
{
unlock_parental(reader);
}
-
rdr_log(reader, "ready for requests");
return OK;
}
-
bool dcw_crc(uint8_t *dw)
{
int8_t i;
for(i = 0; i < 16; i += 4) if(dw[i + 3] != ((dw[i] + dw[i + 1] + dw[i + 2]) & 0xFF)) { return 0; }
return 1;
}
-
static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea)
{
def_resp;
@@ -1024,7 +1035,6 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
uint8_t insf8[] = { 0xca, 0xf8, 0x00, 0x00, 0x00 }; // set geographic info
static const uint8_t insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x12 }; // read dcw
struct viaccess_data *csystem_data = reader->csystem_data;
-
// //XXX what is the 4th uint8_t for ??
int32_t ecm88Len = MIN(MAX_ECM_SIZE - 4, SCT_LEN(er->ecm) - 4);
if(ecm88Len < 1)
@@ -1040,32 +1050,29 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
int32_t rc = 0;
int32_t hasD2 = 0;
uint8_t hasE0 = 0;
+ int32_t has98 = 0;
int32_t curEcm88len = 0;
int32_t nanoLen = 0;
uint8_t *nextEcm;
uint8_t DE04[MAX_ECM_SIZE];
int32_t D2KeyID = 0;
int32_t curnumber_ecm = 0;
+ uint8_t SubECM = 0;
+ char key98Idx = 0;
// nanoD2 d2 02 0d 02 -> D2 nano, len 2
// 0b, 0f, 13 -> pre AES decrypt CW
// 0d, 11, 15 -> post AES decrypt CW
-
int32_t nanoD2 = 0; // knowns D2 nanos: 0x0b ,0x0d ,0x0f ,0x11, 0x13, 0x15
-
memset(DE04, 0, sizeof(DE04)); //fix dorcel de04 bug
-
nextEcm = ecm88Data;
-
while(ecm88Len > 0 && !rc)
{
-
if(ecm88Data[0] == 0x00 && ecm88Data[1] == 0x00)
{
// nano 0x00 and len 0x00 aren't valid... something is obviously wrong with this ecm.
rdr_log(reader, "ECM: Invalid ECM structure. Rejecting");
return ERROR;
}
-
// 80 33 nano 80 (ecm) + len (33)
if(ecm88Data[0] == 0x80) // nano 80, give ecm len
{
@@ -1074,12 +1081,10 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
ecm88Data += 2;
ecm88Len -= 2;
}
-
if(!curEcm88len) // there was no nano 80 -> simple ecm
{
curEcm88len = ecm88Len;
}
-
// d2 02 0d 02 -> D2 nano, len 2, select the AES key to be used
if(ecm88Data[0] == 0xd2)
{
@@ -1089,37 +1094,31 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
nanoD2 = 0x0b;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x0b");
}
-
if(ecm88Data[2] == 0x0d)
{
nanoD2 = 0x0d;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x0d");
}
-
if(ecm88Data[2] == 0x0f)
{
nanoD2 = 0x0f;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x0f");
}
-
if(ecm88Data[2] == 0x11)
{
nanoD2 = 0x11;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x11");
}
-
if(ecm88Data[2] == 0x13)
{
nanoD2 = 0x13;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x13");
}
-
if(ecm88Data[2] == 0x15)
{
nanoD2 = 0x15;
rdr_log_dbg(reader, D_READER, "ECM: nano D2 0x15");
}
-
// use the d2 arguments to get the key # to be used
int32_t len = ecm88Data[1] + 2;
D2KeyID = ecm88Data[3];
@@ -1132,7 +1131,6 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
{
hasD2 = 0;
}
-
// 40 07 03 0b 00 -> nano 40, len =7 ident 030B00 (tntsat), key #0 <== we're pointing here
// 09 -> use key #9
// 05 67 00
@@ -1141,10 +1139,8 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
uint8_t ident[3], keynr;
uint8_t *ecmf8Data = 0;
int32_t ecmf8Len = 0;
-
nanoLen = ecm88Data[1] + 2;
keynr = ecm88Data[4] & 0x0F;
-
// 40 07 03 0b 00 -> nano 40, len =7 ident 030B00 (tntsat), key #0 <== we're pointing here
// 09 -> use key #9
if(nanoLen > 5)
@@ -1156,18 +1152,17 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
// as some card don't support this
if(csystem_data->last_geo.number_ecm > 0)
{
- if(csystem_data->last_geo.number_ecm == curnumber_ecm && !(ecm88Data[nanoLen - 1] == 0x01))
+ if(csystem_data->last_geo.number_ecm == curnumber_ecm && !(ecm88Data[nanoLen - 1] == 0x00)) // select permut 4, accept 01 and FF
{
keynr = ecm88Data[5];
rdr_log_dbg(reader, D_READER, "keyToUse = %02x, ECM ending with %02x", ecm88Data[5], ecm88Data[nanoLen - 1]);
}
else
{
- if(ecm88Data[nanoLen - 1] == 0x01)
- {
- rdr_log_dbg(reader, D_READER, "Skip ECM ending with = %02x for ecm number (%x) for provider %02x%02x%02x",
- ecm88Data[nanoLen - 1], curnumber_ecm, ecm88Data[2], ecm88Data[3], ecm88Data[4]);
- }
+ // if(ecm88Data[nanoLen - 1] == 0x00) // select permut 4
+ // {
+ // rdr_log_dbg(reader, D_READER, "Skip ECM ending with = %02x for ecm number (%x) for provider %02x%02x%02x", ecm88Data[nanoLen - 1], curnumber_ecm, ecm88Data[2], ecm88Data[3], ecm88Data[4]);
+ // }
rdr_log_dbg(reader, D_READER, "Skip ECM ending with = %02x for ecm number (%x)", ecm88Data[nanoLen - 1], curnumber_ecm);
ecm88Data = nextEcm;
ecm88Len -= curEcm88len;
@@ -1180,11 +1175,9 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
rdr_log_dbg(reader, D_READER, "keyToUse = %02x", ecm88Data[5]);
}
}
-
memcpy(ident, &ecm88Data[2], sizeof(ident));
provid = b2i(3, ident);
ident[2] &= 0xF0;
-
if(hasD2 && reader->aes_list)
{
// check that we have the AES key to decode the CW
@@ -1194,32 +1187,51 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
return ERROR;
}
}
-
if(!chk_prov(reader, ident, keynr))
{
rdr_log_dbg(reader, D_READER, "ECM: provider or key not found on card");
snprintf(ea->msglog, MSGLOGSIZE, "provider(%02x%02x%02x) or key(%d) not found on card", ident[0], ident[1], ident[2], keynr);
return ERROR;
}
-
+ SubECM = ecm88Data[nanoLen - 1] ; // 01 permut 4 , FF no permut
ecm88Data += nanoLen;
ecm88Len -= nanoLen;
curEcm88len -= nanoLen;
-
- // DE04
if(ecm88Data[0] == 0xDE && ecm88Data[1] == 0x04)
{
memcpy(DE04, &ecm88Data[0], 6);
ecm88Data += 6;
}
-
- // E0 (seen so far in logs: E0020002 or E0022002, but not in all cases delivers invalid cw so just detect!)
- if(ecm88Data[0] == 0xE0 && ecm88Data[1] == 0x02)
+ if((ecm88Data[0] == 0xD9) && (ecm88Data[1] == 0x0A))
{
- rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano E0 ECM detected!");
- hasE0=1;
+ rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano D9/0A ECM detected!");
+ if((ecm88Data[12] == 0xE0) && (ecm88Data[13] == 0x02) && (ecm88Data[15] == 0x02)) // accept parental data 0F for ecm88Data[2]
+ {
+ rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano E0 ECM detected!");
+ hasE0 = 1;
+ }
+ if(((ecm88Data[16] ==0x98) || (ecm88Data[19] == 0x98)) && ((ecm88Data[17] == 0x08) || (ecm88Data[20] == 0x08)))
+ {
+ rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano 98 ECM detected!");
+ has98 = 1;
+ key98Idx = ecm88Data[25];
+ rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano 98 Index : %02X",key98Idx);
+ }
+ }
+ else
+ {
+ if((ecm88Data[0] == 0xE0) && (ecm88Data[1] == 0x02) && (ecm88Data[3] == 0x02)) // accept parental data 0F for ecm88Data[2]
+ {
+ rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano E0 ECM detected!");
+ hasE0 = 1;
+ }
+ }
+ if((ecm88Data[4] == 0x98) && (ecm88Data[5] == 0x08))
+ {
+ rdr_log_dbg(reader, D_READER,"[viaccess-reader] nano 98 ECM detected!");
+ has98 = 1;
+ key98Idx = ecm88Data[0x0D];
}
-
if(csystem_data->last_geo.provid != provid)
{
csystem_data->last_geo.provid = provid;
@@ -1227,7 +1239,6 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
csystem_data->last_geo.geo[0] = 0;
write_cmd(insa4, ident); // set provider
}
-
// Nano D2 0x0b, 0x0f, 0x13 -> pre AES decrypt CW
if(hasD2 && (nanoD2 == 0x0b|| nanoD2 == 0x0f|| nanoD2 == 0x13))
{
@@ -1243,38 +1254,33 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
ecm88DataCW = ecm88DataCW + cwStart + 2;
must_exit = 1;
}
- cwStart++;
+ cwStart = cwStart + ecm88Data[cwStart + 1] + 2; // parse via nanos
+ // cwStart++; // error if EA 10 in nanos datas
}
-
if(nanoD2 == 0x0f)
{
hdSurEncPhase1_D2_0F_11(ecm88DataCW);
hdSurEncPhase2_D2_0F_11(ecm88DataCW);
}
-
if(nanoD2 == 0x13)
{
hdSurEncPhase1_D2_13_15(ecm88DataCW);
}
-
// use AES from list to decrypt CW
rdr_log_dbg(reader, D_READER, "Decoding CW : using AES key id %d for provider %06x", D2KeyID, (provid & 0xFFFFF0));
if(aes_decrypt_from_list(reader->aes_list, 0x500, (uint32_t)(provid & 0xFFFFF0), D2KeyID, &ecm88DataCW[0], 16) == 0)
{
snprintf(ea->msglog, MSGLOGSIZE, "Missing AES key(%d)[aka E%X]",D2KeyID, D2KeyID);
}
-
if(nanoD2 == 0x0f)
{
hdSurEncPhase1_D2_0F_11(ecm88DataCW);
}
-
if(nanoD2 == 0x13)
{
hdSurEncPhase2_D2_13_15(ecm88DataCW);
}
}
-
while(ecm88Len > 1 && ecm88Data[0] < 0xA0)
{
nanoLen = ecm88Data[1] + 2;
@@ -1287,7 +1293,6 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
curEcm88len -= nanoLen;
ecm88Data += nanoLen;
}
-
if(ecmf8Len)
{
if(csystem_data->last_geo.geo_len != ecmf8Len || memcmp(csystem_data->last_geo.geo, ecmf8Data, csystem_data->last_geo.geo_len))
@@ -1322,7 +1327,6 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
{
write_cmd(ins88, (uint8_t *)ecm88Data); // request dcw
}
-
write_cmd(insc0, NULL); // read dcw
switch(cta_res[0])
{
@@ -1332,21 +1336,18 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
memcpy(ea->cw, cta_res + 2, 8);
rc = 1;
} break;
-
case 0xe9: // odd
if(cta_res[1] == 8)
{
memcpy(ea->cw + 8, cta_res + 2, 8);
rc = 1;
} break;
-
case 0xea: // complete
if(cta_res[1] == 16)
{
memcpy(ea->cw, cta_res + 2, 16);
rc = 1;
} break;
-
default :
ecm88Data = nextEcm;
ecm88Len -= curEcm88len;
@@ -1363,9 +1364,7 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
return ERROR; /*Lets interupt the loop and exit, because we don't know this ECM type.*/
}
}
-
// Nano D2 0d, 11, 15 -> post AES decrypt CW
-
if(hasD2 && !dcw_crc(ea->cw) && (nanoD2 == 0x0d || nanoD2 == 0x11 || nanoD2 == 0x15))
{
if(nanoD2 == 0x11)
@@ -1373,72 +1372,81 @@ static int32_t viaccess_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, s
hdSurEncPhase1_D2_0F_11(ea->cw);
hdSurEncPhase2_D2_0F_11(ea->cw);
}
-
if(nanoD2 == 0x15)
{
hdSurEncPhase1_D2_13_15(ea->cw);
}
rdr_log_dbg(reader, D_READER, "Decoding CW : using AES key id %d for provider %06x", D2KeyID, (provid & 0xFFFFF0));
rc = aes_decrypt_from_list(reader->aes_list, 0x500, (uint32_t)(provid & 0xFFFFF0), D2KeyID, ea->cw, 16);
-
if(rc == 0)
{
snprintf(ea->msglog, MSGLOGSIZE, "Missing AES key(%d)[aka E%X]",D2KeyID, D2KeyID);
}
-
if(nanoD2 == 0x11)
{
hdSurEncPhase1_D2_0F_11(ea->cw);
}
-
if(nanoD2 == 0x15)
{
hdSurEncPhase2_D2_13_15(ea->cw);
}
}
-
+ if (has98)
+ {
+ if (N98Init == 0)
+ {
+ MakeSubKeys(KeyS, key98Idx);
+ N98Init = 1;
+ }
+ uint8_t inp[16];
+ memcpy(inp,ea->cw,16);
+ N98_decrypt(inp);
+ memcpy(ea->cw,inp,16);
+ }
if (hasE0)
{
if (reader->initCA28)
{
- rdr_log_dbg(reader, D_READER, "Decrypting nano E0 encrypted cw.");
- uint8_t returnedcw[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ uint8_t returnedcw[16];
memcpy(returnedcw,ea->cw,16);
-
// Processing 3DES
// Processing even cw
des(returnedcw, reader->key_schedule1, 0); // decrypt
des(returnedcw, reader->key_schedule2, 1); // crypt
des(returnedcw, reader->key_schedule1, 0); // decrypt
-
// Processing odd cw
des(returnedcw + 8, reader->key_schedule1, 0); // decrypt
des(returnedcw + 8, reader->key_schedule2, 1); // crypt
des(returnedcw + 8, reader->key_schedule1, 0); // decrypt
-
// returning value
memcpy(ea->cw,returnedcw, 16);
}
else
{
- snprintf(ea->msglog, MSGLOGSIZE, "nano E0 detected, no valid boxkey / deskey defined: no decoding");
+ snprintf(ea->msglog, MSGLOGSIZE, "Nano E0 detected, no valid boxkey + deskey defined: no decoding");
}
}
+ if (SubECM == 1)
+ {
+ uint8_t rw[16];
+ memcpy(rw, ea->cw, 16);
+ memcpy(ea->cw, rw+4, 4);
+ memcpy(ea->cw+4, rw, 4);
+ memcpy(ea->cw+8, rw+12, 4);
+ memcpy(ea->cw+12, rw+8, 4);
+ }
return (rc ? OK : ERROR);
}
-
static int32_t viaccess_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
{
uint32_t provid = 0;
rdr_log_dbg(rdr, D_EMM, "Entered viaccess_get_emm_type ep->emm[0]=%02x", ep->emm[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:
@@ -1454,13 +1462,11 @@ static int32_t viaccess_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
{
return 1; // let server decide!
}
-
case 0x8A:
case 0x8B:
ep->type = GLOBAL;
rdr_log_dbg(rdr, D_EMM, "GLOBAL");
return 1;
-
case 0x8C:
case 0x8D:
ep->type = SHARED;
@@ -1468,13 +1474,11 @@ static int32_t viaccess_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
// 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);
-
// local reader
int8_t i;
for(i = 0; i < rdr->nprov; i++)
@@ -1485,14 +1489,12 @@ static int32_t viaccess_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
}
return (!memcmp(&rdr->sa[0][0], ep->hexserial, 3));
} /* fallthrough */
-
default:
ep->type = UNKNOWN;
rdr_log_dbg(rdr, D_EMM, "UNKNOWN");
return 1;
}
}
-
static int32_t viaccess_get_emm_filter(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count)
{
if(*emm_filters == NULL)
@@ -1500,18 +1502,14 @@ static int32_t viaccess_get_emm_filter(struct s_reader *rdr, struct s_csystem_em
bool network = is_network_reader(rdr);
int8_t device_emm = ((rdr->deviceemm > 0) ? 1 : 0); // set to 1 if device specific emms should be catched too
const unsigned int max_filter_count = 4 + ((device_emm != 0 && rdr->nprov > 0) ? 1:0) + (3 * ((rdr->nprov > 0) ? (rdr->nprov - 1) : 0));
-
if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
{
return ERROR;
}
-
struct s_csystem_emm_filter *filters = *emm_filters;
*filter_count = 0;
-
int32_t idx = 0;
int32_t prov;
-
if(rdr->nprov > 0 && device_emm == 1)
{
filters[idx].type = EMM_GLOBAL; // 8A or 8B no reassembly needed!
@@ -1522,7 +1520,6 @@ static int32_t viaccess_get_emm_filter(struct s_reader *rdr, struct s_csystem_em
filters[idx].mask[3] = 0x80;
idx++;
}
-
// shared are most important put them on top, define first since viaccess produces a lot of filters!
for(prov = 0; (prov < rdr->nprov); prov++)
{
@@ -1530,7 +1527,6 @@ static int32_t viaccess_get_emm_filter(struct s_reader *rdr, struct s_csystem_em
{
continue;
}
-
filters[idx].type = EMM_SHARED; // 8C or 8D always first part of shared, second part delivered by 8E!
filters[idx].enabled = 1;
filters[idx].filter[0] = 0x8C;
@@ -1542,7 +1538,6 @@ static int32_t viaccess_get_emm_filter(struct s_reader *rdr, struct s_csystem_em
filters[idx].mask[5] = 0xF0; // ignore last digit since this is key on card indicator!
}
idx++;
-
filters[idx].type = EMM_SHARED; // 8E second part reassembly with 8c/8d needed!
filters[idx].enabled = 1;
filters[idx].filter[0] = 0x8E;
@@ -1554,7 +1549,6 @@ static int32_t viaccess_get_emm_filter(struct s_reader *rdr, struct s_csystem_em
}
idx++;
}
-
// globals are less important, define last since viaccess produces a lot of filters!
for(prov = 0; (prov < rdr->nprov); prov++)
{
@@ -1562,7 +1556,6 @@ static int32_t viaccess_get_emm_filter(struct s_reader *rdr, struct s_csystem_em
{
continue;
}
-
filters[idx].type = EMM_GLOBAL; // 8A or 8B no reassembly needed!
filters[idx].enabled = 1;
filters[idx].filter[0] = 0x8A;
@@ -1580,7 +1573,6 @@ static int32_t viaccess_get_emm_filter(struct s_reader *rdr, struct s_csystem_em
}
idx++;
}
-
filters[idx].type = EMM_UNIQUE;
filters[idx].enabled = 1;
filters[idx].filter[0] = 0x88;
@@ -1596,13 +1588,10 @@ static int32_t viaccess_get_emm_filter(struct s_reader *rdr, struct s_csystem_em
memset(&filters[idx].mask[1], 0xFF, 3);
}
idx++;
-
*filter_count = idx;
}
-
return OK;
}
-
static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
{
def_resp;
@@ -1612,9 +1601,7 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
uint8_t ins18[] = { 0xca, 0x18, 0x01, 0x01, 0x00 }; // set subscription
uint8_t ins1c[] = { 0xca, 0x1c, 0x01, 0x01, 0x00 }; // set subscription, encrypted
struct viaccess_data *csystem_data = reader->csystem_data;
-
int32_t emmdatastart = 7;
-
if (ep->emm[1] == 0x01) // emm from cccam
{
emmdatastart = 12;
@@ -1631,22 +1618,17 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
emmdatastart = 5;
}
}
-
if(ep->type == UNIQUE)
{
emmdatastart++;
}
-
if(ep->type == GLOBAL && emmdatastart == 7)
{
emmdatastart -= 4;
}
-
int32_t emmLen = SCT_LEN(ep->emm) - emmdatastart;
int32_t rc = 0;
-
rdr_log_dump(reader, ep->emm, emmLen + emmdatastart, "RECEIVED EMM VIACCESS");
-
int32_t emmUpToEnd;
uint8_t *emmParsed = ep->emm + emmdatastart;
int32_t provider_ok = 0;
@@ -1661,17 +1643,13 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
uint8_t *nano9EData = 0;
uint8_t *nanoF0Data = 0;
uint8_t *nanoA9Data = 0;
-
for(emmUpToEnd = emmLen; (emmParsed[1] != 0) && (emmUpToEnd > 0); emmUpToEnd -= (2 + emmParsed[1]), emmParsed += (2 + emmParsed[1]))
{
rdr_log_dump(reader, emmParsed, emmParsed[1] + 2, "NANO");
-
if(emmParsed[0] == 0x90 && emmParsed[1] == 0x03)
{
/* identification of the service operator */
-
uint8_t soid[3], ident[3], i;
-
for(i = 0; i < 3; i++)
{
soid[i] = ident[i] = emmParsed[2 + i];
@@ -1679,7 +1657,6 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
ident[2] &= 0xF0;
emm_provid = b2i(3, ident);
keynr = soid[2] & 0x0F;
-
if(chk_prov(reader, ident, keynr))
{
provider_ok = 1;
@@ -1689,7 +1666,6 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
rdr_log(reader, "EMM: ignored since provider or key not present on card (%x, %x)", emm_provid, keynr);
return SKIPPED;
}
-
// check if the provider changes. If yes, set the new one. If not, don't... card will return an error if we do.
if(csystem_data->last_geo.provid != emm_provid)
{
@@ -1706,22 +1682,17 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
csystem_data->last_geo.provid = 0;
csystem_data->last_geo.geo_len = 0;
csystem_data->last_geo.geo[0] = 0;
-
}
else if(emmParsed[0] == 0x9e && emmParsed[1] == 0x20)
{
/* adf */
-
if(!nano91Data)
{
/* adf is not crypted, so test it */
-
uint8_t custwp;
uint8_t *afd;
-
custwp = reader->sa[0][3];
afd = (uint8_t *)emmParsed + 2;
-
if(afd[31 - custwp / 8] & (1 << (custwp & 7)))
{
rdr_log_dbg(reader, D_READER, "emm for our card %08X", b2i(4, &reader->sa[0][0]));
@@ -1732,10 +1703,8 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
return SKIPPED;
}
}
-
// memorize
nano9EData = emmParsed;
-
}
else if(emmParsed[0] == 0x81)
{
@@ -1783,7 +1752,6 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
return SKIPPED;
}
int8_t match = add_find_class(reader, emm_provid, emmParsed + 2, emmParsed[1], 0);
-
if(match == -2)
{
rdr_log(reader, "shared emm provid %06X all classes have entitlementdate already same or newer -> skipped!", emm_provid);
@@ -1791,12 +1759,10 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
}
nanoA9Data = emmParsed;
}
-
memcpy(ins18Data + ins18Len, emmParsed, emmParsed[1] + 2);
ins18Len += emmParsed [1] + 2;
}
}
-
if(!provider_ok)
{
rdr_log_dbg(reader, D_READER, "provider not found in emm, continue anyway");
@@ -1804,13 +1770,11 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
keynr = 1;
///return ERROR;
}
-
if(!nanoF0Data)
{
rdr_log_dump(reader, ep->emm, ep->emmlen, "can't find 0xf0 in emm...");
return ERROR; // error
}
-
if(nano9EData)
{
if(!nano91Data)
@@ -1835,7 +1799,6 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
memcpy(insData, nano91Data, nano91Data[1] + 2);
memcpy(insData + nano91Data[1] + 2, nano9EData, nano9EData[1] + 2);
write_cmd(insf4, insData);
-
if((cta_res[cta_lr - 2] != 0x90 && cta_res[cta_lr - 2] != 0x91) || cta_res[cta_lr - 1] != 0x00)
{
rdr_log_dump(reader, insf4, 5, "set adf encrypted cmd:");
@@ -1845,7 +1808,6 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
}
}
}
-
if(!nano92Data)
{
// send subscription
@@ -1855,7 +1817,6 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
memcpy(insData, ins18Data, ins18Len);
memcpy(insData + ins18Len, nanoF0Data, nanoF0Data[1] + 2);
write_cmd(ins18, insData);
-
if((cta_res[cta_lr - 2] == 0x90 || cta_res[cta_lr - 2] == 0x91) && cta_res[cta_lr - 1] == 0x00)
{
if(nanoA9Data)
@@ -1869,7 +1830,6 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
{
rdr_log_dump(reader, ins18, 5, "set subscription cmd:");
rdr_log_dump(reader, insData, ins18[4], "set subscription data:");
-
if(!(cta_res[cta_lr -2] == 0x90 && cta_res[cta_lr - 1] == 0x40)) // dont throw softerror 9040 in log!
{
rdr_log(reader, "update error: %02X %02X", cta_res[cta_lr - 2], cta_res[cta_lr - 1]);
@@ -1879,41 +1839,55 @@ static int32_t viaccess_do_emm(struct s_reader *reader, EMM_PACKET *ep)
rc = 2; // skipped
}
}
-
}
else
{
// send subscription encrypted
-
if(!nano81Data)
{
rdr_log_dump(reader, ep->emm, ep->emmlen, "0x92 found, but can't find 0x81 in emm...");
return ERROR; // error
}
-
ins1c[2] = nano9EData ? 0x01 : 0x00; // found 9E nano ?
if(ep->type == UNIQUE)
{
ins1c[2] = 0x02;
}
-
ins1c[3] = keynr; // key
ins1c[4] = nano92Data[1] + 2 + nano81Data[1] + 2 + nanoF0Data[1] + 2;
memcpy(insData, nano92Data, nano92Data[1] + 2);
memcpy(insData + nano92Data[1] + 2, nano81Data, nano81Data[1] + 2);
memcpy(insData + nano92Data[1] + 2 + nano81Data[1] + 2, nanoF0Data, nanoF0Data[1] + 2);
write_cmd(ins1c, insData);
-
if((cta_res[cta_lr - 2] == 0x90 || cta_res[cta_lr - 2] == 0x91) && (cta_res[cta_lr - 1] == 0x00 || cta_res[cta_lr - 1] == 0x08))
{
rdr_log(reader, "update successfully written");
}
+ if(cta_res[cta_lr - 2] == 0x98 && cta_res[cta_lr - 1] == 0x00 )
+ {
+ static const uint8_t insFAC[] = { 0x87, 0x02, 0x00, 0x00, 0x03 }; // init FAC
+ static uint8_t ins8702_data[] = { 0x00, 0x00, 0x11};
+ static uint8_t ins8704[] = { 0x87, 0x04, 0x00, 0x00, 0x07 };
+ static uint8_t ins8706[] = { 0x87, 0x06, 0x00, 0x00, 0x04 };
+ write_cmd(insFAC, ins8702_data);
+ if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
+ {
+ write_cmd(ins8704, NULL);
+ if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
+ {
+ write_cmd(ins8706, NULL);
+ if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
+ {
+ csystem_data->last_geo.number_ecm = (cta_res[2] << 8) | (cta_res[3]);
+ rdr_log(reader, "using ecm #%x for long viaccess ecm", csystem_data->last_geo.number_ecm);
+ }
+ }
+ }
+ }
rc = 1;
}
-
return rc;
}
-
static int32_t viaccess_card_info(struct s_reader *reader)
{
def_resp;
@@ -1926,31 +1900,24 @@ static int32_t viaccess_card_info(struct s_reader *reader)
uint8_t insa4[] = { 0xca, 0xa4, 0x00, 0x00, 0x00 }; // select issuer
uint8_t insc0[] = { 0xca, 0xc0, 0x00, 0x00, 0x00 }; // read data item
static const uint8_t ins24[] = { 0xca, 0x24, 0x00, 0x00, 0x09 }; // set pin
-
uint8_t cls[] = { 0x00, 0x21, 0xff, 0x9f};
+ uint8_t prebook[] = {0x00,0x00,0x00,0xFF,0xFF,0xFF };
static const uint8_t pin[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04};
struct viaccess_data *csystem_data = reader->csystem_data;
-
csystem_data->last_geo.provid = 0;
csystem_data->last_geo.geo_len = 0;
csystem_data->last_geo.geo[0] = 0;
-
rdr_log(reader, "card detected");
-
cs_clear_entitlement(reader); //reset the entitlements
-
// set pin
write_cmd(ins24, pin);
-
insac[2] = 0xa4;
write_cmd(insac, NULL); // request unique id
insb8[4] = 0x07;
write_cmd(insb8, NULL); // read unique id
rdr_log_sensitive(reader, "serial: {%llu}", (unsigned long long) b2ll(5, cta_res + 2));
-
insa4[2] = 0x00;
write_cmd(insa4, NULL); // select issuer 0
-
for(i = 1; (cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0); i++)
{
bool added = false;
@@ -1960,13 +1927,11 @@ static int32_t viaccess_card_info(struct s_reader *reader)
write_cmd(insc0, NULL); // show provider properties
cta_res[2] &= 0xF0;
l_provid = b2i(3, cta_res);
-
insac[2] = 0xa5;
write_cmd(insac, NULL); // request sa
insb8[4] = 0x06;
write_cmd(insb8, NULL); // read sa
l_sa = b2i(4, cta_res + 2);
-
insac[2] = 0xa7;
write_cmd(insac, NULL); // request name
insb8[4] = 0x02;
@@ -1976,7 +1941,6 @@ static int32_t viaccess_card_info(struct s_reader *reader)
write_cmd(insb8, NULL); // read name
cta_res[l] = 0;
trim((char *)cta_res);
-
if(cta_res[0])
{
snprintf((char *)l_name, sizeof(l_name), ", name: %.55s", cta_res);
@@ -1985,7 +1949,6 @@ static int32_t viaccess_card_info(struct s_reader *reader)
{
l_name[0] = 0;
}
-
// read GEO
insac[2] = 0xa6;
write_cmd(insac, NULL); // request GEO
@@ -1996,7 +1959,6 @@ static int32_t viaccess_card_info(struct s_reader *reader)
insb8[4] = l;
write_cmd(insb8, NULL); // read geo
rdr_log_sensitive(reader, "provider: %d, id: {%06X%s}, sa: {%08X}, geo: %s", i, l_provid, l_name, l_sa, (l < 4) ? "empty" : cs_hexdump(1, cta_res, l, tmp, sizeof(tmp)));
-
// read classes subscription
insac[2] = 0xa9;
insac[4] = 4;
@@ -2009,7 +1971,6 @@ static int32_t viaccess_card_info(struct s_reader *reader)
cls[1] = tmpdate & 0xff;
}
write_cmd(insac, cls); // request class subs
-
while((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0))
{
insb8[4] = 0x02;
@@ -2026,13 +1987,30 @@ static int32_t viaccess_card_info(struct s_reader *reader)
}
}
}
-
if(!added)
{
// add entitlement info for provid without class
cs_add_entitlement(reader, reader->caid, l_provid, 0, 0, 0, 0, 5, 1);
}
-
+ // Read List of «pre-booked pay-per-view per programme» entitlements within the range [INUMB, FNUMB]
+ insac[2] = 0xaa;
+ insac[4] = 6;
+ write_cmd(insac, prebook ); // request class subs
+ while((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00))
+ {
+ insb8[4] = 0x08;
+ write_cmd(insb8, NULL); // read PVV
+ if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0))
+ {
+ l = cta_res[1];
+ write_cmd(insb8, NULL); // read PPV
+ if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0x00 || cta_res[cta_lr - 1] == 0x08))
+ {
+ cs_add_entitlement(reader, reader->caid, l_provid, b2i(3, cta_res+2), 0 , 0, 0, 2, 1);
+ cs_add_entitlement(reader, reader->caid, l_provid, b2i(3, cta_res+5), 0 , 0, 0, 2, 1);
+ }
+ }
+ }
insac[4] = 0;
insa4[2] = 0x02;
write_cmd(insa4, NULL); // select next provider
@@ -2049,7 +2027,6 @@ static int32_t viaccess_card_info(struct s_reader *reader)
uint8_t ins28_data[4];
memcpy(ins28_data, reader->boxkey, 4);
write_cmd(ins28, ins28_data); // unlock card to reply on E002xxyy
-
if((cta_res[cta_lr - 2] == 0x90) && (cta_res[cta_lr - 1] == 0))
{
rdr_log(reader, "CA 28 initialisation successful!");
@@ -2066,7 +2043,6 @@ static int32_t viaccess_card_info(struct s_reader *reader)
//end process init CA 28
return OK;
}
-
static int32_t viaccess_reassemble_emm(struct s_reader *rdr, struct s_client *client, EMM_PACKET *ep)
{
uint8_t *buffer = ep->emm;
@@ -2075,13 +2051,11 @@ static int32_t viaccess_reassemble_emm(struct s_reader *rdr, struct s_client *cl
int16_t k;
int32_t prov, provid = 0;
struct emm_rass *r_emm = NULL;
-
// Viaccess
if(*len > 500)
{
return 0;
}
-
switch(buffer[0])
{
case 0x8c:
@@ -2090,24 +2064,20 @@ static int32_t viaccess_reassemble_emm(struct s_reader *rdr, struct s_client *cl
provid = b2i(3, ep->emm + 5); // extract provid from emm
provid &= 0xFFFFF0; // last digit is dont care
r_emm = find_rabuf(client, provid, (uint8_t) buffer[0], 1);
-
if(!r_emm)
{
cs_log("[viaccess] ERROR: Can't allocate EMM reassembly buffer.");
return 0;
}
-
if(!memcmp(&r_emm->emm, &buffer[0], *len)) // skip same shared emm, this make sure emmlen isnt replaced. emmlen = 0 means this shared emm has been used for reassembly
{
return 0;
}
-
memset(&r_emm->emm[0], 0, sizeof(r_emm->emm)); // zero it!
memcpy(&r_emm->emm[0], &buffer[0], *len); // put the fresh new shared emm
r_emm->emmlen = *len; // put the emmlen indicating that this shared emm isnt being reassembled
rdr_log_dump_dbg(rdr, D_EMM, r_emm->emm, r_emm->emmlen, "%s: received fresh emm-gh for provid %06X", __func__, provid);
return 0;
-
case 0x8e:
// emm-s part 2
for(prov = 0; prov < rdr->nprov ; prov++)
@@ -2120,14 +2090,12 @@ static int32_t viaccess_reassemble_emm(struct s_reader *rdr, struct s_client *cl
provid = b2i(4, ep->provid); // use provid from emm since we have nothing better!
provid &= 0xFFFFF0; // last digit is dont care
}
-
else
{
provid = b2i(4, rdr->prid[prov]); // get corresponding provid from reader since there is no provid in emm payload!
provid &= 0xFFFFF0; // last digit is dont care
}
r_emm = find_rabuf(client, provid, 0, 0); // nano = don't care, the shared 8c or 8d not been written gets returned!
-
if(!r_emm || !r_emm->emmlen)
{
continue; // match but no emm-gh found for this provider
@@ -2138,14 +2106,12 @@ static int32_t viaccess_reassemble_emm(struct s_reader *rdr, struct s_client *cl
}
}
}
-
if(!r_emm || !r_emm->emmlen)
{
return 0; // stop -> no emm-gh found!
}
//extract nanos from emm-gh and emm-s
uint8_t emmbuf[512];
-
rdr_log_dbg(rdr, D_EMM, "%s: start extracting nanos", __func__);
//extract from emm-gh
for(i = 3; i < r_emm->emmlen; i += r_emm->emm[i + 1] + 2)
@@ -2154,27 +2120,23 @@ static int32_t viaccess_reassemble_emm(struct s_reader *rdr, struct s_client *cl
memcpy(emmbuf + pos, r_emm->emm + i, r_emm->emm[i + 1] + 2);
pos += r_emm->emm[i + 1] + 2;
}
-
if(buffer[2] == 0x2c)
{
//add 9E 20 nano + first 32 uint8_ts of emm content
memcpy(emmbuf + pos, "\x9E\x20", 2);
memcpy(emmbuf + pos + 2, buffer + 7, 32);
pos += 34;
-
//add F0 08 nano + 8 subsequent uint8_ts of emm content
memcpy(emmbuf + pos, "\xF0\x08", 2);
memcpy(emmbuf + pos + 2, buffer + 39, 8);
pos += 10;
}
-
else if(buffer[2] == 0x34 && (provid >> 8) == 0x0702)
{
//add 9E 20 nano + first 32 uint8_ts of emm content
memcpy(emmbuf + pos, "\x9E\x20", 2);
memcpy(emmbuf + pos + 2, buffer + 7, 32);
pos += 34;
-
//add F0 10 nano + 16 subsequent uint8_ts of emm content
memcpy(emmbuf + pos, "\xF0\x10", 2);
memcpy(emmbuf + pos + 2, buffer + 39, 16);
@@ -2190,25 +2152,19 @@ static int32_t viaccess_reassemble_emm(struct s_reader *rdr, struct s_client *cl
pos += buffer[k + 1] + 2;
}
}
-
rdr_log_dump_dbg(rdr, D_EMM, buffer, *len, "%s: %s emm-s", __func__, (buffer[2] == 0x2c) ? "fixed" : "variable");
-
emm_sort_nanos(buffer + 7, emmbuf, pos);
pos += 7;
-
//calculate emm length and set it on position 2
buffer[2] = pos - 3;
-
rdr_log_dump_dbg(rdr, D_EMM, r_emm->emm, r_emm->emmlen, "%s: emm-gh provid %06X", __func__, provid);
rdr_log_dump_dbg(rdr, D_EMM, buffer, pos, "%s: assembled emm", __func__);
-
*len = pos;
r_emm->emmlen = 0; // mark this shared 8c or 8d as being used for reassembly and send to reader!
break;
}
return 1;
}
-
const struct s_cardsystem reader_viaccess =
{
.desc = "viaccess",
@@ -2221,5 +2177,4 @@ const struct s_cardsystem reader_viaccess =
.get_emm_type = viaccess_get_emm_type,
.get_emm_filter = viaccess_get_emm_filter,
};
-
#endif
diff --git a/reader-videoguard-common.c b/reader-videoguard-common.c
index 9875bf833..5ebf755a7 100644
--- a/reader-videoguard-common.c
+++ b/reader-videoguard-common.c
@@ -64,7 +64,10 @@ void set_known_card_info(struct s_reader *reader, const uint8_t *atr, const uint
22, 1997, 0, NDS2, "VideoGuard Sky Italia (0919)" },
{ { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x4A, 0x01, 0x00, 0x00 },
- 22, 2004, 0, NDS2, "VideoGuard Dolce Romania (092F)" },
+ 22, 2004, 0, NDS2, "VideoGuard Telekom (Dolce TV) Romania (092F)" },
+
+ { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0F, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x5A, 0x4A, 0x03 },
+ 21, 2004, 0, NDS2, "VideoGuard Telekom (Dolce TV) Romania (0952)" },
{ { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x4B, 0x01, 0x00, 0x00 },
22, 2004, 0, NDS2, "VideoGuard Viasat Ukraine (0931)" },
@@ -120,8 +123,32 @@ void set_known_card_info(struct s_reader *reader, const uint8_t *atr, const uint
{ { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0910)" },
+ { { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
+ 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0910) FastMode" },
+
+ { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
+ 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0910) FastMode" },
+
+ { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
+ 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0910) FastMode" },
+
{ { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
- 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0910)" },
+ 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0910) FastMode" },
+
+ { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x41, 0x5A, 0x03 },
+ 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0913)"},
+
+ { { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x41, 0x5A, 0x03 },
+ 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0913) FastMode"},
+
+ { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x41, 0x5A, 0x03 },
+ 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0913) FastMode"},
+
+ { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x41, 0x5A, 0x03 },
+ 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0913) FastMode"},
+
+ { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x41, 0x5A, 0x03 },
+ 21, 2004, 50, NDS2, "VideoGuard Astro Malaysia (0913) FastMode"},
{ { 0x3F, 0xFF, 0x11, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x11 },
22, 2004, 50, NDS2, "VideoGuard Astro Malaysia (09AC)" },
@@ -260,51 +287,51 @@ void set_known_card_info(struct s_reader *reader, const uint8_t *atr, const uint
{ { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x45, 0x01, 0x00, 0x14 },
22, 2004, 0, NDS2, "VideoGuard OTE TV Sat (09BE)" },
-
+
{ { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x33, 0x54, 0x83 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3VV (0927)" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0002 Card (0927)" },
{ { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x33, 0x54, 0x83 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3VV (0927) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0002 Card (0927) FastMode" },
{ { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x33, 0x54, 0x83 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3VV (0927) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0002 Card (0927) FastMode" },
{ { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x33, 0x54, 0x83 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3VV (0927) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0002 Card (0927) FastMode" },
{ { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x33, 0x54, 0x83 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3VV (0927) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0002 Card (0927) FastMode" },
{ { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x54, 0x33, 0x03 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3TV (0927)" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0001 Card (0927)" },
{ { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x54, 0x33, 0x03 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3TV (0927) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0001 Card (0927) FastMode" },
{ { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x54, 0x33, 0x03 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3TV (0927) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0001 Card (0927) FastMode" },
{ { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x54, 0x33, 0x03 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3TV (0927) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0001 Card (0927) FastMode" },
{ { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x54, 0x33, 0x03 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3TV (0927) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0001 Card (0927) FastMode" },
{ { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x33, 0x54, 0x83 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3VV (09BF)" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0004 Card (09BF)" },
{ { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x33, 0x54, 0x83 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3VV (09BF) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0004 Card (09BF) FastMode" },
{ { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x33, 0x54, 0x83 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3VV (09BF) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0004 Card (09BF) FastMode" },
{ { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x33, 0x54, 0x83 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3VV (09BF) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0004 Card (09BF) FastMode" },
{ { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x33, 0x54, 0x83 },
- 21, 2008, 0, NDS2, "VideoGuard TrueVisions T3VV (09BF) FastMode" },
+ 21, 2008, 0, NDS2, "VideoGuard TrueVisions 0004 Card (09BF) FastMode" },
// NDS Version Unknown as Yet
{ { 0x3F, 0x7F, 0x13, 0x25, 0x02, 0x40, 0xB0, 0x12, 0x69, 0xFF, 0x4A, 0x50, 0x90, 0x41, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00 },
diff --git a/reader-videoguard2.c b/reader-videoguard2.c
index 6ad95bca6..c8bb8bcc3 100644
--- a/reader-videoguard2.c
+++ b/reader-videoguard2.c
@@ -2,7 +2,6 @@
#ifdef READER_VIDEOGUARD
#include "cscrypt/md5.h"
#include "cscrypt/des.h"
-#include "cscrypt/aes.h"
#include "oscam-work.h"
#include "reader-common.h"
#include "reader-videoguard-common.h"
@@ -11,7 +10,7 @@
static void do_post_dw_hash(struct s_reader *reader, uint8_t *cw, const uint8_t *ecm_header_data)
{
int32_t i, ecmi, ecm_header_count;
- uint8_t buffer[0x85]; // original 0x80 but with 0x7D mask applied +8 bytes cw it was still to small
+ uint8_t buffer[0x85]; // original 0x80 but with 0x7D mask applied +8 bytes cw it was still too small
uint8_t md5tmp[MD5_DIGEST_LENGTH];
static const uint16_t Hash3[] = { 0x0123, 0x4567, 0x89AB, 0xCDEF, 0xF861, 0xCB52 };
@@ -894,17 +893,6 @@ static int32_t videoguard2_card_init(struct s_reader *reader, ATR *newatr)
return ERROR;
}
- int d37423_ok = 0;
- static const uint8_t ins7403[5] = { 0xD0, 0x74, 0x03, 0x00, 0x00 }; // taken from v13 boot log
- if(do_cmd(reader, ins7403, NULL, NULL, cta_res) < 0)
- {
- rdr_log(reader, "classD0 ins7403: failed");
- }
- else
- {
- d37423_ok = (cta_res[2] >> 5) & 1;
- }
-
if(reader->ins7E11[0x01]) // the position of the ins7E is taken from v13 log
{
uint8_t ins742b[5] = { 0xD0, 0x74, 0x2b, 0x00, 0x00 };
@@ -1054,6 +1042,17 @@ static int32_t videoguard2_card_init(struct s_reader *reader, ATR *newatr)
return ERROR;
}
+ int d37423_ok = 0;
+ static const uint8_t ins7403[5] = { 0xD1, 0x74, 0x03, 0x00, 0x00 }; // taken from v13 boot log
+ if(do_cmd(reader, ins7403, NULL, NULL, cta_res) < 0)
+ {
+ rdr_log(reader, "classD1 ins7403: failed");
+ }
+ else
+ {
+ d37423_ok = (cta_res[2] >> 5) & 1;
+ }
+
// new ins74 present at boot
if(d37423_ok) // from ins7403 answer
{
@@ -1063,19 +1062,19 @@ static int32_t videoguard2_card_init(struct s_reader *reader, ATR *newatr)
rdr_log(reader, "classD1 ins7423: failed");
}
}
-/*
- static const uint8_t ins742A[5] = { 0xD1, 0x74, 0x2A, 0x00, 0x00 };
+
+ static const uint8_t ins742A[5] = { 0xD0, 0x74, 0x2A, 0x00, 0x00 };
if(do_cmd(reader, ins742A, NULL, NULL, cta_res) < 0)
{
- rdr_log(reader, "classD1 ins742A: failed");
+ rdr_log(reader, "classD0 ins742A: failed");
}
- static const uint8_t ins741C[5] = { 0xD1, 0x74, 0x1C, 0x00, 0x00 };
- if(do_cmd(reader, ins741C, NULL, NULL, cta_res) < 0)
+ static const uint8_t ins741B[5] = { 0xD1, 0x74, 0x1B, 0x00, 0x00 };
+ if(do_cmd(reader, ins741B, NULL, NULL, cta_res) < 0)
{
- rdr_log(reader, "classD1 ins741C: failed");
+ rdr_log(reader, "classD1 ins741B: failed");
}
-*/
+
static const uint8_t ins4Ca[5] = { 0xD1, 0x4C, 0x00, 0x00, 0x00 };
payload4C[4] = 0x83;
@@ -1111,18 +1110,19 @@ static int32_t videoguard2_card_init(struct s_reader *reader, ATR *newatr)
}
// get PIN settings
- static const uint8_t ins7411[5] = { 0xD1, 0x74, 0x11, 0x00, 0x00 };
+ static const uint8_t ins7411[5] = { 0xD3, 0x74, 0x11, 0x00, 0x00 };
uint8_t payload2e4[4];
- if(do_cmd(reader, ins7411, NULL, NULL, cta_res) < 0)
+ uint8_t rbuff[264];
+ if(do_cmd(reader, ins7411, NULL, rbuff, cta_res) < 0)
{
- rdr_log(reader, "classD1 ins7411: unable to get PIN");
+ rdr_log(reader, "classD3 ins7411: unable to get PIN");
return ERROR;
}
else
{
memset(payload2e4, 0, 4);
- memcpy(payload2e4, cta_res + 2, 4);
- reader->VgPin = (cta_res[4] << 8) + cta_res[5];
+ memcpy(payload2e4, rbuff + 7, 4);
+ reader->VgPin = (rbuff[9] << 8) + rbuff[10];
rdr_log(reader, "Pincode read: %04hu", reader->VgPin);
}
@@ -1168,15 +1168,12 @@ static int32_t videoguard2_card_init(struct s_reader *reader, ATR *newatr)
}
// fix for 09ac cards
- uint8_t dimeno_magic[0x10] = { 0xF9, 0xFB, 0xCD, 0x5A, 0x76, 0xB5, 0xC4, 0x5C,
- 0xC8, 0x2E, 0x1D, 0xE1, 0xCC, 0x5B, 0x6B, 0x02 };
-
+ uint8_t dimeno_magic[0x10] = { 0xF9, 0xFB, 0xCD, 0x5A, 0x76, 0xB5, 0xC4, 0x5C, 0xC8, 0x2E, 0x1D, 0xE1, 0xCC, 0x5B, 0x6B, 0x02 };
int32_t a;
for(a = 0; a < 4; a++)
{
dimeno_magic[a] = dimeno_magic[a] ^ boxID[a];
}
-
AES_set_decrypt_key(dimeno_magic, 128, &(csystem_data->astrokey));
rdr_log(reader, "type: %s, caid: %04X", csystem_data->card_desc, reader->caid);
@@ -1284,7 +1281,7 @@ static int32_t videoguard2_do_ecm(struct s_reader *reader, const ECM_REQUEST *er
memcpy(buff_55, t_body, 1 );
break;
- case 0x56: // tag data for aes
+ case 0x56: // tag data for aes
memcpy(buff_56, t_body, 8);
break;
@@ -1321,7 +1318,7 @@ static int32_t videoguard2_do_ecm(struct s_reader *reader, const ECM_REQUEST *er
rdr_log(reader, "classD3 ins54: no cw --> Card isn't active");
test_0F = 0;
}
- else // These Messages are only nessensary if the Card is active
+ else // These Messages are only necessary if the Card is active
{
if((buff_0F[1] >> 4) & 1) // case 0f_0x xx 10 xx xx xx xx
{
@@ -1368,22 +1365,22 @@ static int32_t videoguard2_do_ecm(struct s_reader *reader, const ECM_REQUEST *er
// copy cw1 in place
memcpy(ea->cw + 0, rbuff + 5, 8);
+ //case 55_01 xx where bit3==1, bit2==0, bit1==0, and bit0==1, ins7e and CW-Overcrypt may not required
+ if(((buff_55[0] >> 3) & 1) && (~((buff_55[0] >> 2) & 1)) && (~((buff_55[0] >> 1) & 1)) && (buff_55[0] & 1))
+ {
+ rdr_log_dbg(reader, D_READER, "classD3 ins54: Tag55_01 = %02X, ins7e and CW-overcrypt may not required", buff_55[0]);
+ }
+
// case 55_01 xx where bit0==1, CW is crypted
if(buff_55[0] & 1)
{
- if((buff_55[0] >> 3) & 1) //case 55_01 xx where bit3==1, CW-Overcrypt may not required
- {
- rdr_log_dbg(reader, D_READER, "classD3 ins54: Tag55_01 = %02X, CW-overcrypt may not required", buff_55[0]);
- }
if(~((buff_55[0] >> 2) & 1)) //case 55_01 xx where bit2==0
{
if((buff_55[0] >> 1) & 1) //case 55_01 xx where bit1==1, unique Pairing
{
rdr_log_dbg(reader, D_READER, "classD3 ins54: CW is crypted, trying to decrypt unique pairing mode 0x%02X", buff_55[0]);
- if((buff_56[0]|buff_56[1]|buff_56[2]|buff_56[3]|buff_56[4]|buff_56[5]|buff_56[6]|buff_56[7]) != 0) { //when 56_08 is non-zero use AES (mini-patch by para)
- rdr_log_dbg(reader, D_READER, "crypted CW is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
- ea->cw[0], ea->cw[1], ea->cw[2], ea->cw[3], ea->cw[4], ea->cw[5], ea->cw[6], ea->cw[7],
- buff_56[0], buff_56[1], buff_56[2], buff_56[3], buff_56[4], buff_56[5], buff_56[6], buff_56[7]);
+ if((buff_56[0]|buff_56[1]|buff_56[2]|buff_56[3]|buff_56[4]|buff_56[5]|buff_56[6]|buff_56[7]) != 0) { //when 56_08 is non-zero use AES
+ rdr_log_dbg(reader, D_READER, "encrypted AES buffer is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", ea->cw[0], ea->cw[1], ea->cw[2], ea->cw[3], ea->cw[4], ea->cw[5], ea->cw[6], ea->cw[7], buff_56[0], buff_56[1], buff_56[2], buff_56[3], buff_56[4], buff_56[5], buff_56[6], buff_56[7]);
uint8_t aesbuf[0x10];
uint8_t keybuf[0x10];
AES_KEY aeskey;
@@ -1391,12 +1388,14 @@ static int32_t videoguard2_do_ecm(struct s_reader *reader, const ECM_REQUEST *er
memcpy(aesbuf + 8, buff_56, 8);
memcpy(keybuf, &(reader->k1_unique), 16);
if(reader->k1_unique[16] == 0x10) {
- rdr_log_dbg(reader, D_READER, "use k1(AES) for CW decryption in unique pairing mode");
+ rdr_log_dbg(reader, D_READER, "use k1(AES) for AES buffer decryption in unique pairing mode");
AES_set_decrypt_key(keybuf, 128, &aeskey);
AES_decrypt(aesbuf, aesbuf, &aeskey);
- rdr_log_dbg(reader, D_READER, "decrypted CW is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
- aesbuf[0], aesbuf[1], aesbuf[2], aesbuf[3], aesbuf[4], aesbuf[5], aesbuf[6], aesbuf[7],
- aesbuf[8], aesbuf[9], aesbuf[10], aesbuf[11], aesbuf[12], aesbuf[13], aesbuf[14], aesbuf[15]);
+ if(er->ecm[0] & 1){ //log decrypted CW
+ rdr_log_dbg(reader, D_READER, "decrypted CW is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", aesbuf[8], aesbuf[9], aesbuf[10], aesbuf[11], aesbuf[12], aesbuf[13], aesbuf[14], aesbuf[15], aesbuf[0], aesbuf[1], aesbuf[2], aesbuf[3], aesbuf[4], aesbuf[5], aesbuf[6], aesbuf[7]);
+ } else {
+ rdr_log_dbg(reader, D_READER, "decrypted CW is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", aesbuf[0], aesbuf[1], aesbuf[2], aesbuf[3], aesbuf[4], aesbuf[5], aesbuf[6], aesbuf[7], aesbuf[8], aesbuf[9], aesbuf[10], aesbuf[11], aesbuf[12], aesbuf[13], aesbuf[14], aesbuf[15]);
+ }
memcpy(ea->cw + 0, aesbuf, 8);
}
else {
@@ -1438,9 +1437,7 @@ static int32_t videoguard2_do_ecm(struct s_reader *reader, const ECM_REQUEST *er
{
rdr_log_dbg(reader, D_READER, "classD3 ins54: CW is crypted, trying to decrypt generic pairing mode 0x%02X", buff_55[0]);
if((buff_56[0]|buff_56[1]|buff_56[2]|buff_56[3]|buff_56[4]|buff_56[5]|buff_56[6]|buff_56[7]) != 0) { //when 56_08 is non-zero use AES
- rdr_log_dbg(reader, D_READER, "crypted CW is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
- ea->cw[0], ea->cw[1], ea->cw[2], ea->cw[3], ea->cw[4], ea->cw[5], ea->cw[6], ea->cw[7],
- buff_56[0], buff_56[1], buff_56[2], buff_56[3], buff_56[4], buff_56[5], buff_56[6], buff_56[7]);
+ rdr_log_dbg(reader, D_READER, "encrypted AES buffer is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", ea->cw[0], ea->cw[1], ea->cw[2], ea->cw[3], ea->cw[4], ea->cw[5], ea->cw[6], ea->cw[7], buff_56[0], buff_56[1], buff_56[2], buff_56[3], buff_56[4], buff_56[5], buff_56[6], buff_56[7]);
uint8_t aesbuf[0x10];
uint8_t keybuf[0x10];
AES_KEY aeskey;
@@ -1448,16 +1445,18 @@ static int32_t videoguard2_do_ecm(struct s_reader *reader, const ECM_REQUEST *er
memcpy(aesbuf + 8, buff_56, 8);
memcpy(keybuf, &(reader->k1_generic), 16);
if(reader->k1_generic[16] == 0x10) {
- rdr_log_dbg(reader, D_READER, "use k1(AES) for CW decryption in generic pairing mode");
+ rdr_log_dbg(reader, D_READER, "use k1(AES) for AES buffer decryption in generic pairing mode");
AES_set_decrypt_key(keybuf, 128, &aeskey);
AES_decrypt(aesbuf, aesbuf, &aeskey);
- rdr_log_dbg(reader, D_READER, "decrypted CW is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
- aesbuf[0], aesbuf[1], aesbuf[2], aesbuf[3], aesbuf[4], aesbuf[5], aesbuf[6], aesbuf[7],
- aesbuf[8], aesbuf[9], aesbuf[10], aesbuf[11], aesbuf[12], aesbuf[13], aesbuf[14], aesbuf[15]);
+ if(er->ecm[0] & 1){ //log decrypted CW
+ rdr_log_dbg(reader, D_READER, "decrypted CW is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", aesbuf[8], aesbuf[9], aesbuf[10], aesbuf[11], aesbuf[12], aesbuf[13], aesbuf[14], aesbuf[15], aesbuf[0], aesbuf[1], aesbuf[2], aesbuf[3], aesbuf[4], aesbuf[5], aesbuf[6], aesbuf[7]);
+ } else {
+ rdr_log_dbg(reader, D_READER, "decrypted CW is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", aesbuf[0], aesbuf[1], aesbuf[2], aesbuf[3], aesbuf[4], aesbuf[5], aesbuf[6], aesbuf[7], aesbuf[8], aesbuf[9], aesbuf[10], aesbuf[11], aesbuf[12], aesbuf[13], aesbuf[14], aesbuf[15]);
+ }
memcpy(ea->cw + 0, aesbuf, 8);
}
else {
- rdr_log_dbg(reader, D_READER, "k1 for generic pairing mode is not set");
+ rdr_log_dbg(reader, D_READER, "k1 for generic pairing mode is not set correctly");
return ERROR;
}
}
@@ -1492,7 +1491,7 @@ static int32_t videoguard2_do_ecm(struct s_reader *reader, const ECM_REQUEST *er
}
}
}
- else //unknown pairing mode
+ else //unknown pairing mode
{
rdr_log_dbg(reader, D_READER, "classD3 ins54: CW is crypted, unknown pairing mode 0x%02X", buff_55[0]);
if(er->ecm[0] & 1){ //log crypted CW
@@ -1507,11 +1506,19 @@ static int32_t videoguard2_do_ecm(struct s_reader *reader, const ECM_REQUEST *er
// case 55_01 xx where bit2==1, old dimeno_PostProcess_Decrypt(reader, rbuff, ea->cw);
if((buff_55[0] >> 2) & 1)
{
- uint8_t buffer[0x10];
- memcpy(buffer, rbuff + 5, 8);
- memcpy(buffer + 8, buff_56, 8);
- AES_decrypt(buffer, buffer, &(csystem_data->astrokey));
- memcpy(ea->cw + 0, buffer, 8); // copy calculated CW in right place
+ rdr_log_dbg(reader, D_READER, "classD3 ins54: CW is crypted, trying to decrypt AES boxkey mode 0x%02X", buff_55[0]);
+ rdr_log_dbg(reader, D_READER, "encrypted AES buffer is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", ea->cw[0], ea->cw[1], ea->cw[2], ea->cw[3], ea->cw[4], ea->cw[5], ea->cw[6], ea->cw[7], buff_56[0], buff_56[1], buff_56[2], buff_56[3], buff_56[4], buff_56[5], buff_56[6], buff_56[7]);
+ uint8_t aesbuf[0x10];
+ memcpy(aesbuf, rbuff + 5, 8);
+ memcpy(aesbuf + 8, buff_56, 8);
+ rdr_log_dbg(reader, D_READER, "use dimeno magic for AES buffer decryption");
+ AES_decrypt(aesbuf, aesbuf, &(csystem_data->astrokey));
+ if(er->ecm[0] & 1){ //log decrypted CW
+ rdr_log_dbg(reader, D_READER, "decrypted CW is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", aesbuf[8], aesbuf[9], aesbuf[10], aesbuf[11], aesbuf[12], aesbuf[13], aesbuf[14], aesbuf[15], aesbuf[0], aesbuf[1], aesbuf[2], aesbuf[3], aesbuf[4], aesbuf[5], aesbuf[6], aesbuf[7]);
+ } else {
+ rdr_log_dbg(reader, D_READER, "decrypted CW is: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", aesbuf[0], aesbuf[1], aesbuf[2], aesbuf[3], aesbuf[4], aesbuf[5], aesbuf[6], aesbuf[7], aesbuf[8], aesbuf[9], aesbuf[10], aesbuf[11], aesbuf[12], aesbuf[13], aesbuf[14], aesbuf[15]);
+ }
+ memcpy(ea->cw + 0, aesbuf, 8); // copy calculated CW in right place
}
if(new_len != lenECMpart2)
diff --git a/webif/config/dvbapi.html b/webif/config/dvbapi.html
index 92e49ced4..730145f87 100644
--- a/webif/config/dvbapi.html
+++ b/webif/config/dvbapi.html
@@ -64,4 +64,5 @@
-
\ No newline at end of file
+
+##TPLDEMUXERFIX##
diff --git a/webif/config/dvbapi_demuxerfix.html b/webif/config/dvbapi_demuxerfix.html
new file mode 100644
index 000000000..55ff073b5
--- /dev/null
+++ b/webif/config/dvbapi_demuxerfix.html
@@ -0,0 +1,2 @@
+
Refers to Stream Relay |
+ Fix Demuxer: | |
diff --git a/webif/config/streamrelay.html b/webif/config/streamrelay.html
index 6fe538713..af860a9bb 100644
--- a/webif/config/streamrelay.html
+++ b/webif/config/streamrelay.html
@@ -14,13 +14,6 @@
Source Stream Port: | |
Source Stream User: | |
Source Stream Password: | |
+##TPLSTREAMCLIENTSOURCEHOST##
Relay Port: | |
- ECM fix delay: | |
- Process EMM from stream: |
-
-
- |
-
\ No newline at end of file
+ Relay Buffer Time: | |
diff --git a/webif/config/streamrelay_streamclientsourcehost.html b/webif/config/streamrelay_streamclientsourcehost.html
new file mode 100644
index 000000000..e782c80fe
--- /dev/null
+++ b/webif/config/streamrelay_streamclientsourcehost.html
@@ -0,0 +1 @@
+ Use stream client as Source Stream Host: | |
diff --git a/webif/include/jquery.js b/webif/include/jquery.js
index e83647587..7f37b5d99 100644
--- a/webif/include/jquery.js
+++ b/webif/include/jquery.js
@@ -1,5 +1,2 @@
-/*! jQuery v1.12.4 | (c) jQuery Foundation | jquery.org/license */
-!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.addEventListener?(d.removeEventListener("DOMContentLoaded",K),a.removeEventListener("load",K)):(d.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(d.addEventListener||"load"===a.event.type||"complete"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener("DOMContentLoaded",K),a.addEventListener("load",K);else{d.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll("left")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst="0"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName("body")[0],c&&c.style&&(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement("div");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b},N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0;
-}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),"object"!=typeof b&&"function"!=typeof b||(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement("div"),b=d.createDocumentFragment(),c=d.createElement("input");a.innerHTML=" a",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName("tbody").length,l.htmlSerialize=!!a.getElementsByTagName("link").length,l.html5Clone="<:nav>"!==d.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML="",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement("input"),c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={option:[1,""],legend:[1,""],area:[1,""],param:[1,""],thead:[1,""],tr:[2,""],col:[2,""],td:[3,""],_default:l.htmlSerialize?[0,"",""]:[1,"X","
"]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}var ga=/<|?\w+;/,ha=/r;r++)if(g=a[r],g||0===g)if("object"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement("div")),j=($.exec(g)||["",""])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g="table"!==j||ha.test(g)?""!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],"tbody")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent="";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,"input"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),"script"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||"")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b]=c in a)||(e.setAttribute(c,"t"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return"undefined"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(G)||[""],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),h=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,"events")||{})[b.type]&&n._data(i,"handle"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]","i"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,wa=/