From 50a47a1c20e06bb057d52bdd4462dad041a181ed Mon Sep 17 00:00:00 2001 From: bust3d Date: Mon, 4 Mar 2024 17:27:02 +0000 Subject: [PATCH] added Streamrelay libdvbcsa - thanks to lpm11 , fegol, icb, loka, kitte888, youtube18, WXbet and many more added cak7 patch - thanks to ohmza, TV-Gamer and others git-svn-id: https://svn.streamboard.tv/oscam/trunk@11735 4b0bc96b-bc66-0410-9d44-ebda105a78c1 --- CMakeLists.txt | 82 +- Distribution/doc/html/oscam.conf.5.html | 10 + Distribution/doc/man/oscam.conf.5 | 8 + Distribution/doc/txt/oscam.conf.txt | 6 + Makefile | 21 +- config.h | 2 + config.sh | 8 +- csctapi/icc_async.c | 167 +- globals.h | 118 +- module-dvbapi.c | 37 +- module-radegast.c | 10 + module-streamrelay.c | 1242 ++++++++++++++ module-streamrelay.h | 74 + module-webif.c | 229 ++- oscam-config-global.c | 26 +- oscam-config-reader.c | 767 ++++++++- oscam-emm.c | 32 +- oscam-work.c | 9 - oscam-work.h | 5 +- oscam.c | 17 + reader-common.c | 5 + reader-conax.c | 152 +- reader-nagra-common.c | 724 +++++++- reader-nagra.c | 14 +- reader-nagracak7.c | 1802 +++++++++++++++++--- reader-seca.c | 9 +- webif/config/dvbapi.html | 1 + webif/config/dvbapi_demuxerfix.html | 2 + webif/config/streamrelay.html | 10 +- .../config/streamrelay_streamclientsourcehost.html | 1 + webif/pages_index.txt | 7 +- webif/readerconfig/readerconfig_cccambit.html | 9 + webif/readerconfig/readerconfig_hwreader.html | 1 + .../readerconfig/readerconfig_hwreader_conax.html | 2 + .../readerconfig/readerconfig_hwreader_nagra.html | 4 +- .../readerconfig_hwreader_nagracak7.html | 35 +- webif/readerconfig/readerconfig_ncd524bit.html | 9 + webif/readerconfig/readerconfig_ncd525bit.html | 9 + 38 files changed, 5154 insertions(+), 512 deletions(-) create mode 100644 module-streamrelay.c create mode 100644 module-streamrelay.h rewrite reader-nagra-common.c (80%) create mode 100644 webif/config/dvbapi_demuxerfix.html create mode 100644 webif/config/streamrelay_streamclientsourcehost.html create mode 100644 webif/readerconfig/readerconfig_hwreader_conax.html rewrite webif/readerconfig/readerconfig_hwreader_nagracak7.html (63%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 497a0086..49c45924 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,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 (LIBDVBCASDIR) + check_include_file ("${LIBDVBCASDIR}/include/dvbcsa/dvbcsa.h" FOUND_LIBDVBCSA) + set (LIBADVBCSA_LIBRARY "${LIBDVBCASDIR}/libdvbcsa.a") + set (LIBDVBCSA_LIBRARY "${LIBDVBCASDIR}/libdvbcsa.so") + else (LIBDVBCASDIR) + check_include_file ("dvbcsa/dvbcsa.h" FOUND_LIBDVBCSA) + find_library (LIBADVBCSA_LIBRARY NAMES libdvbcsa.a) + find_library (LIBDVBCSA_LIBRARY NAMES dvbcsa) + endif (LIBDVBCASDIR) + + 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 @@ -626,7 +659,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... @@ -652,7 +685,28 @@ 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, 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+ if (CMAKE_COMPILER_IS_GNUCC) execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) @@ -660,7 +714,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") @@ -807,9 +861,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) @@ -824,5 +878,23 @@ 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 LIBDVBCASDIR) + message (STATUS " use static libdvbcsa functions") + else(STATICLIBDVBCSA AND NOT LIBDVBCASDIR) + if (LIBDVBCASDIR AND STATIC_LIBDVBCSA EQUAL 0) + message(STATUS " use system libdvbcsa from selected LIBDVBCASDIR functions") + elseif (LIBDVBCASDIR AND STATIC_LIBDVBCSA EQUAL 1) + message(STATUS " use static libdvbcsa from selected LIBDVBCASDIR functions") + elseif(LIBDVBCASDIR) + message(STATUS " use system libdvbcsa from selected LIBDVBCASDIR functions") + elseif(NOT LIBDVBCASDIR AND NOT STATIC_LIBDVBCSA) + message (STATUS " use system libdvbcsa functions") + endif(LIBDVBCASDIR AND STATIC_LIBDVBCSA EQUAL 0) + endif(STATICLIBDVBCSA AND NOT LIBDVBCASDIR) +endif (HAVE_LIBDVBCSA) message (STATUS "") diff --git a/Distribution/doc/html/oscam.conf.5.html b/Distribution/doc/html/oscam.conf.5.html index 898183c0..6a8c40d2 100644 --- a/Distribution/doc/html/oscam.conf.5.html +++ b/Distribution/doc/html/oscam.conf.5.html @@ -1634,6 +1634,16 @@ mode writing provider name into oscam.srvid2 file:

+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 4eef8154..ec579442 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 0c7e2a75..4d9e1651 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 4b35141e..d6e51dd1 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,11 @@ ifeq ($(uname_S),FreeBSD) LIB_DL := endif -override STD_LIBS := -lm $(LIB_PTHREAD) $(LIB_DL) $(LIB_RT) +ifeq "$(shell ./config.sh --enabled MODULE_STREAMRELAY)" "Y" + LIB_DVBCSA = -ldvbcsa +endif + +override STD_LIBS := -lm $(LIB_PTHREAD) $(LIB_DL) $(LIB_RT) $(LIB_DVBCSA) override STD_DEFS := -D'CS_SVN_VERSION="$(SVN_REV)"' override STD_DEFS += -D'CS_CONFDIR="$(CONF_DIR)"' @@ -58,13 +62,23 @@ 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 +CC_OPTS = -O2 -ggdb -pipe -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-schedule-insns 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 += -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 # Check for the linker version and if it matches disable --gc-sections # For more information about the bug see: @@ -298,6 +312,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 @@ -416,7 +431,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 $@ diff --git a/config.h b/config.h index f505ca32..5eebaa03 100644 --- a/config.h +++ b/config.h @@ -22,6 +22,7 @@ //#define LCDSUPPORT 1 //#define LEDSUPPORT 1 //#define IPV6SUPPORT 1 +//#define WITH_ARM_NEON 1 #define MODULE_MONITOR 1 //#define MODULE_CAMD33 1 @@ -37,6 +38,7 @@ //#define MODULE_PANDORA 1 //#define MODULE_GHTTP 1 #define MODULE_SCAM 1 +//#define MODULE_STREAMRELAY 1 #define WITH_CARDREADER 1 diff --git a/config.sh b/config.sh index a801d003..a53a2dcc 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_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" -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" +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" @@ -26,6 +26,7 @@ CONFIG_WITH_LB=y # CONFIG_LEDSUPPORT=n # CONFIG_CLOCKFIX=n # CONFIG_IPV6SUPPORT=n +# CONFIG_WITH_ARM_NEON=n # CONFIG_MODULE_CAMD33=n CONFIG_MODULE_CAMD35=y CONFIG_MODULE_CAMD35_TCP=y @@ -39,6 +40,7 @@ CONFIG_MODULE_GBOX=y # CONFIG_MODULE_PANDORA=n CONFIG_MODULE_SCAM=y # CONFIG_MODULE_GHTTP=n +# CONFIG_MODULE_STREAMRELAY=n CONFIG_WITH_CARDREADER=y CONFIG_READER_NAGRA_COMMON=y CONFIG_READER_NAGRA=y @@ -468,6 +470,7 @@ menu_addons() { 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") \ 2> ${tempfile} opt=${?} @@ -492,6 +495,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/csctapi/icc_async.c b/csctapi/icc_async.c index 34d6c83b..14c39637 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,8 +76,14 @@ 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; @@ -83,9 +91,84 @@ void do_cak7_cmd(struct s_reader *reader,unsigned char *cta_res, uint16_t *p_cta calculate_cak7_cmd(reader,data,inlen,&req[5]); 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 +328,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 +375,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 +389,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 +400,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 +481,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 +517,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/globals.h b/globals.h index 157a9c84..8a0eb45d 100644 --- a/globals.h +++ b/globals.h @@ -1557,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; @@ -1575,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]; @@ -1606,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]; @@ -1615,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 @@ -1645,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; @@ -1652,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]; @@ -1663,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 +2401,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 +2452,22 @@ 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; + 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 3e1b4819..7959c733 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 @@ -6817,10 +6826,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) + { + 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 { - ecmcounter++; +#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) @@ -7855,8 +7878,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) { diff --git a/module-radegast.c b/module-radegast.c index b514203e..da3265ae 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 00000000..80b10d40 --- /dev/null +++ b/module-streamrelay.c @@ -0,0 +1,1242 @@ +#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)) ? er->ecm[21] : 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]; + + 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); + } + 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", cluster_size); + + 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 00000000..5b678570 --- /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.c b/module-webif.c index 118e2be0..1e62ca2d 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,21 @@ 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, "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 +1683,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 +1763,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 @@ -2660,6 +2665,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); } @@ -2722,7 +2730,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) @@ -2731,6 +2782,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) @@ -2747,39 +2830,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]); } + } + + // Force Pairing Type (CAK7) + len = rdr->forcepair_length; + if(len > 0) + { + for(i = 0; i < len ; 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]); } } - // cwekey (CAK7) - len = rdr->cwekey_length; + // cwekey7 (CAK7) + len = rdr->cwekey7_length; if(len > 0) { for(i = 0; i < len ; i++) - { tpl_printf(vars, TPLAPPEND, "CWEKEY", "%02X", rdr->cwekey[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]) { diff --git a/oscam-config-global.c b/oscam-config-global.c index 3df1e16e..6b6e7074 100644 --- a/oscam-config-global.c +++ b/oscam-config-global.c @@ -910,23 +910,24 @@ 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_FUNC("stream_relay_ctab" , OFS(stream_relay_ctab), check_caidtab_fn), DEF_LAST_OPT }; #else @@ -1355,6 +1356,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 c91ae93f..61a15324 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-emm.c b/oscam-emm.c index fc75799c..d0df4bab 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 85f21240..bee981dc 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" @@ -338,12 +335,6 @@ void *work_thread(void *ptr) #endif break; -#ifdef READER_NAGRA_MERLIN - case ACTION_READER_RENEW_SK: - CAK7_getCamKey(reader); - break; -#endif - case ACTION_READER_INIT: if(!cl->init_done) { reader_init(reader); } diff --git a/oscam-work.h b/oscam-work.h index 5fb9e75e..ac836895 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 d0731072..2541802e 100644 --- a/oscam.c +++ b/oscam.c @@ -22,6 +22,7 @@ #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" @@ -409,6 +410,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"); @@ -436,6 +441,11 @@ 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"); +#else + fprintf(fp, "%-40s %s\n", "ARM NEON (SIMD/MPE) support:", "not supported!"); +#endif fprintf(fp, "\n"); write_conf(MODULE_CAMD33, "camd 3.3x"); @@ -451,6 +461,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"); @@ -1833,6 +1844,9 @@ int32_t main(int32_t argc, char *argv[]) init_sidtab(); init_readerdb(); +#ifdef MODULE_STREAMRELAY + init_stream_server(); +#endif cfg.account = init_userdb(); init_signal(); init_provid(); @@ -1918,6 +1932,9 @@ int32_t main(int32_t argc, char *argv[]) #ifdef MODULE_GBOX stop_gbx_ticker(); #endif +#ifdef MODULE_STREAMRELAY + stop_stream_server(); +#endif webif_close(); azbox_close(); coolapi_close_all(); diff --git a/reader-common.c b/reader-common.c index 5df23a69..cb6753f7 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 00317be7..3b08ade2 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-nagra-common.c b/reader-nagra-common.c dissimilarity index 80% index eaf40c88..410afca8 100644 --- a/reader-nagra-common.c +++ b/reader-nagra-common.c @@ -1,84 +1,640 @@ -#include "globals.h" -#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 nagra_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr) -{ - switch(ep->emm[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; - return (!memcmp(rdr->sa[0], ep->hexserial, 0x03)); - } - else - { - ep->hexserial[3] = ep->emm[6]; - ep->type = UNIQUE; - return (!memcmp(rdr->hexserial + 2, ep->hexserial, 0x04)); - } - - case 0x82: - ep->type = GLOBAL; - return 1; - - default: - ep->type = UNKNOWN; - return 1; - } -} - -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) - { - const unsigned int max_filter_count = 3; - 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] = 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; -} +#include "globals.h" +#include "reader-common.h" +#include "reader-nagra-common.h" + +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) +{ + if(rdr->cak7type == 3 || rdr->autype == 1) + { + 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; + 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; + 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 0x84: + ep->type = GLOBAL; + + 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: + ep->type = SHARED; + return 1; + + 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(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) + { + if(*emm_filters == NULL) + { + 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; + } + + 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++; + + 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 = 6 + (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++; + + 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] = 0x87; + filters[idx].mask[0] = 0xFF; + 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++; + } + + *filter_count = idx; + } + + return OK; + } +} diff --git a/reader-nagra.c b/reader-nagra.c index 141206d3..3e67b77d 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 6fc06ad0..2f5450ac 100644 --- a/reader-nagracak7.c +++ b/reader-nagracak7.c @@ -1,24 +1,23 @@ #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) { @@ -33,7 +32,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 +43,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); @@ -55,12 +54,12 @@ void rsa_decrypt(uint8_t *edata50, int len, uint8_t *out, uint8_t *key, int keyl 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; } @@ -70,20 +69,202 @@ static void addProvider(struct s_reader *reader, uint8_t *cta_res) { 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; @@ -94,7 +275,7 @@ static int32_t ParseDataType(struct s_reader *reader, uint8_t dt, uint8_t *cta_r 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); @@ -106,34 +287,185 @@ static int32_t ParseDataType(struct s_reader *reader, uint8_t dt, uint8_t *cta_r 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}; + 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; + } + addSA(reader, cta_res + p + 5); + addemmfilter(reader, cta_res + p + 5); + } + } + } + } + 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,6 +475,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; } @@ -159,6 +499,13 @@ static int32_t ParseDataType(struct s_reader *reader, uint8_t dt, uint8_t *cta_r 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); @@ -173,9 +520,21 @@ static int32_t ParseDataType(struct s_reader *reader, uint8_t dt, uint8_t *cta_r expire_date = expire_date1 <= expire_date2 ? expire_date1 : expire_date2; break; + case 0x1861: // 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, @@ -188,7 +547,7 @@ 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; } @@ -227,15 +586,19 @@ static int32_t CAK7GetDataType(struct s_reader *reader, uint8_t dt) 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) { @@ -268,145 +631,874 @@ static int32_t CAK7GetDataType(struct s_reader *reader, uint8_t dt) return OK; } -void CAK7_getCamKey(struct s_reader *reader) +static void sub_6AD78(uint32_t *dinit) // gbox function { - 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}; + 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; +} - get_random_bytes(data1, 0x04); - if (data1[3] == 0xFF) +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) { - data1[3]--; + 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); + } - memcpy(cmd0e + 9, data1, 0x04); - data1[3]++; - if (reader->irdid_length == 4) + uint32_t nR0 = (uint32_t)* dinit; + while(nR4 < len) { - memcpy(&cmd0e[14], reader->irdid, reader->irdid_length); // inject irdid + out[nR4] = nR0 & 0xFF; + nR4++; + nR0 >>= 8; } - // inject provid - cmd0e[18] = reader->prid[0][2]; - cmd0e[19] = reader->prid[0][3]; + out[0] &= 0x03; + out[0x10] |= 0x01; - 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); +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); +} - reader->cak7_restart = (cta_res[22] << 16); - reader->cak7_restart += (cta_res[23] << 8); - reader->cak7_restart += (cta_res[24] ); - reader->cak7_restart--; +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; + } +} - memcpy(reader->cardid,cta_res + 14, 4); - rdr_log_dump_dbg(reader, D_READER, reader->cardid, 0x04, "CardSerial: "); +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); +} - memcpy(reader->hexserial + 2, reader->cardid, 4); - memcpy(reader->sa[0], reader->cardid, 3); - memcpy(reader->sa[1], reader->sa[0], 4); +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); +} - 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; +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]; - rsa_decrypt(reader->data50, reader->data50_length, reader->data, reader->mod50, reader->mod50_length, reader->public_exponent, reader->public_exponent_length); + rdr_log_dump_dbg(reader, D_READER, reader->tmprsa, sizeof(reader->tmprsa), "DT05_20 after RSA: "); - 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); + // copy signature + memcpy(sig_20_00, reader->tmprsa+24, 16); - 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); + // copy data + memcpy(data_20_00, reader->tmprsa+40, 72); - 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); + // IDEA encrypt 0x48 data + int i; + int offs = 0; - 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}; + 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; + } - memcpy(&cmd03[9],reader->data,0x6c); - do_cak7_cmd(reader,cta_res,&cta_lr,cmd03,sizeof(cmd03),0x90); + // xor + for (i=0; i<64; i++) + { + data_20_x[i] = data_20_00[i] ^ data_20_id[i+8]; + } - 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); + rdr_log_dump_dbg(reader, D_READER, data_20_x, sizeof(data_20_x), "data_20_x: "); - 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); + // create final data block + memcpy(data_20_fin,data_20_id,8); + memcpy(data_20_fin+8,data_20_x,64); - 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); + rdr_log_dump_dbg(reader, D_READER, data_20_fin, sizeof(data_20_fin), "data_20_fin: "); - memcpy(&reader->cak7_aes_key[16],mdc_hash,16); - memcpy(reader->cak7_aes_key,mdc_hash,16); -} + 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); -void CAK7_reinit(struct s_reader *reader) -{ - ATR newatr[ATR_MAX_SIZE]; - memset(newatr, 0, 1); - if(ICC_Async_Activate(reader, newatr, 0)) + if(memcmp(mdc_hash4, sig_20_00, 16) == 0) { - reader->card_status = CARD_NEED_INIT; - add_job(reader->client, ACTION_READER_RESTART, NULL, 0); + rdr_log(reader, "DT05_20 is correct"); } else { - reader->cak7_seq = 0; - CAK7_getCamKey(reader); + rdr_log(reader, "DT05_20 error - check MOD2"); } -} -static int32_t nagra3_card_init(struct s_reader *reader, ATR *newatr) + // 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) { - get_atr; + def_resp; + 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); + 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); + 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[10],0x68); + + 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); + + //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; +} + +static int32_t CAK7_cmd03_unique(struct s_reader *reader) +{ + 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) + { + 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; + } + + 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 + { + 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"); + } + } - memset(reader->hexserial, 0x00, 0x08); + 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); - reader->public_exponent[0] = 0x01; - reader->public_exponent[1] = 0x00; - reader->public_exponent[2] = 0x01; - reader->public_exponent_length = 3; + rdr_log_dump_dbg(reader, D_READER, reader->timestmp2, 4, "DATA1 CMD03:"); - reader->irdid[0] = 0x64; - reader->irdid[1] = 0x65; - reader->irdid[2] = 0x6D; - reader->irdid[3] = 0x6F; - reader->irdid_length = 4; + 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, 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); @@ -416,23 +1508,53 @@ 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); + if(memcmp(atr + 20, "RevS64", 6) == 0) + { + reader->caid += 0x03; } + else if(memcmp(atr + 20, "RevW60", 6) == 0) + { + reader->caid -= 0x28; + } + CAK7GetDataType(reader, 0x05); + if(!CAK7_GetCamKey(reader)) + {return ERROR;} - reader->nprov = 1; - - CAK7GetDataType(reader, DT05); - CAK7GetDataType(reader, SYSID_CAID); // sysid+caid - CAK7_getCamKey(reader); + CAK7GetDataType(reader, 0x09); rdr_log(reader, "ready for requests"); return OK; @@ -446,37 +1568,111 @@ 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; + + 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))); } - struct timeb now; - cs_ftime(&now); - reader->last_refresh=now; + 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, "-----------------------------------------"); + } + + 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)) + { + return ERROR; + } + reader->cak7_seq = 0; + if(!CAK7_GetCamKey(reader)) + { + return ERROR; + } 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); + } + } } } @@ -484,35 +1680,112 @@ static int32_t nagra3_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, str { 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); } @@ -522,120 +1795,177 @@ static int32_t nagra3_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, str 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; - } - des_ecb3_decrypt(_cwe0, reader->cwekey); - des_ecb3_decrypt(_cwe1, reader->cwekey); + if(!reader->cwekey0_length) + { + rdr_log(reader, "ERROR: CWPK is not set, can not decrypt CW"); + return ERROR; + } - int chkok = 1; - if(((_cwe0[0] + _cwe0[1] + _cwe0[2]) & 0xFF) != _cwe0[3]) + des_ecb3_decrypt(_cwe0, reader->cwekey0); + des_ecb3_decrypt(_cwe1, reader->cwekey0); + } + 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; } diff --git a/reader-seca.c b/reader-seca.c index 76826095..33d45122 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/webif/config/dvbapi.html b/webif/config/dvbapi.html index 1485267e..730145f8 100644 --- a/webif/config/dvbapi.html +++ b/webif/config/dvbapi.html @@ -65,3 +65,4 @@ +##TPLDEMUXERFIX## diff --git a/webif/config/dvbapi_demuxerfix.html b/webif/config/dvbapi_demuxerfix.html new file mode 100644 index 00000000..55ff073b --- /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 6fe53871..dc7ece93 100644 --- a/webif/config/streamrelay.html +++ b/webif/config/streamrelay.html @@ -14,13 +14,5 @@ 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 diff --git a/webif/config/streamrelay_streamclientsourcehost.html b/webif/config/streamrelay_streamclientsourcehost.html new file mode 100644 index 00000000..e782c80f --- /dev/null +++ b/webif/config/streamrelay_streamclientsourcehost.html @@ -0,0 +1 @@ + Use stream client as Source Stream Host: diff --git a/webif/pages_index.txt b/webif/pages_index.txt index 919c5c9e..dfee9469 100644 --- a/webif/pages_index.txt +++ b/webif/pages_index.txt @@ -62,6 +62,7 @@ CONFIGCCCAM config/cccam.html CONFIGCCCAMCTRL config/cccam_control.html MODULE_CCCSHARE CONFIGCONTENT config/config.html CONFIGDVBAPI config/dvbapi.html HAVE_DVBAPI +DEMUXERFIX config/dvbapi_demuxerfix.html MODULE_STREAMRELAY CCCAMRESHAREBIT config/cccreshare.html MODULE_GBOX CONFIGGBOX config/gbox.html MODULE_GBOX CONFIGGLOBAL config/global.html @@ -88,13 +89,14 @@ CONFIGMENUMONITOR config/menu_monitor.html CONFIGMENUNEWCAMD config/menu_newcamd.html MODULE_NEWCAMD CONFIGMENURADEGAST config/menu_radegast.html MODULE_RADEGAST CONFIGMENUSCAM config/menu_scam.html MODULE_SCAM -CONFIGMENUSTREAMRELAY config/menu_streamrelay.html WITH_EMU +CONFIGMENUSTREAMRELAY config/menu_streamrelay.html MODULE_STREAMRELAY +STREAMCLIENTSOURCEHOST config/streamrelay_streamclientsourcehost.html MODULE_RADEGAST CONFIGMENUSERIAL config/menu_serial.html MODULE_SERIAL CONFIGMONITOR config/monitor.html MODULE_MONITOR CONFIGNEWCAMD config/newcamd.html MODULE_NEWCAMD CONFIGRADEGAST config/radegast.html MODULE_RADEGAST CONFIGSCAM config/scam.html MODULE_SCAM -CONFIGSTREAMRELAY config/streamrelay.html WITH_EMU +CONFIGSTREAMRELAY config/streamrelay.html MODULE_STREAMRELAY CONFIGSERIAL config/serial.html MODULE_SERIAL CONFIGSERIALDEVICEBIT config/serial_devices.html MODULE_SERIAL CONFIGWEBIF config/webif.html @@ -209,6 +211,7 @@ READERCONFIGBOXKEY readerconfig/readerconfig_hwreader_boxkey.html READERCONFIGIRDETO readerconfig/readerconfig_hwreader_irdeto.html READER_IRDETO READERCONFIGNAGRA readerconfig/readerconfig_hwreader_nagra.html READER_NAGRA READERCONFIGNAGRACAK7 readerconfig/readerconfig_hwreader_nagracak7.html READER_NAGRA_MERLIN +READERCONFIGCONAX readerconfig/readerconfig_hwreader_conax.html READER_CONAX READERCONFIGNANO readerconfig/readerconfig_hwreader_nano.html WITH_CARDREADER READERPINCODE readerconfig/readerconfig_hwreader_pincode.html READER_CONAX,READER_CRYPTOWORKS,READER_VIACCESS,READER_SECA READERCONFIGRSAKEY readerconfig/readerconfig_hwreader_rsakey.html READER_NAGRA,READER_IRDETO,READER_CONAX diff --git a/webif/readerconfig/readerconfig_cccambit.html b/webif/readerconfig/readerconfig_cccambit.html index 85232402..82fba335 100644 --- a/webif/readerconfig/readerconfig_cccambit.html +++ b/webif/readerconfig/readerconfig_cccambit.html @@ -1,3 +1,12 @@ + AU NAGRA type: + + + + Inactivity timeout: s Reconnect timeout: s Request timeout: ms diff --git a/webif/readerconfig/readerconfig_hwreader.html b/webif/readerconfig/readerconfig_hwreader.html index 83f06dcd..7e95600f 100644 --- a/webif/readerconfig/readerconfig_hwreader.html +++ b/webif/readerconfig/readerconfig_hwreader.html @@ -21,6 +21,7 @@ ##TPLREADERCONFIGCRYPTOWORKS## ##TPLREADERCONFIGNAGRA## ##TPLREADERCONFIGNAGRACAK7## +##TPLREADERCONFIGCONAX## ##TPLREADERCONFIGIRDETO## ##TPLREADERCONFIGVIACCESS## ##TPLREADERCONFIGDRE## diff --git a/webif/readerconfig/readerconfig_hwreader_conax.html b/webif/readerconfig/readerconfig_hwreader_conax.html new file mode 100644 index 00000000..53a8bc6a --- /dev/null +++ b/webif/readerconfig/readerconfig_hwreader_conax.html @@ -0,0 +1,2 @@ + Reader specific settings for Conax + CWPK: diff --git a/webif/readerconfig/readerconfig_hwreader_nagra.html b/webif/readerconfig/readerconfig_hwreader_nagra.html index 44b56638..65fabcb5 100644 --- a/webif/readerconfig/readerconfig_hwreader_nagra.html +++ b/webif/readerconfig/readerconfig_hwreader_nagra.html @@ -9,5 +9,5 @@ Detect tunneled Seca cards: - Nuid: - CWPK: + CAK6.3 Nuid: + CAK6.3 CWPK: diff --git a/webif/readerconfig/readerconfig_hwreader_nagracak7.html b/webif/readerconfig/readerconfig_hwreader_nagracak7.html dissimilarity index 63% index 25957c92..cdc3c948 100644 --- a/webif/readerconfig/readerconfig_hwreader_nagracak7.html +++ b/webif/readerconfig/readerconfig_hwreader_nagracak7.html @@ -1,6 +1,29 @@ - Reader specific settings for Nagra Merlin - mod1: - data50: - mod50: - key60: - exp60: + Reader specific settings for Nagra Merlin + Init card in CAK7 mode: + Force CW swap: + Force Even SA: + Force EMMs 0x82: + mod1: + mod2: + key3588: + key3460: + key3310: + data50: + mod50: + idird: + CMD0E ProvID: use only if CMD0E needs ProvID other than sysid + Nuid: + Force Pairing (00 - global): + Force OTP CSC (optional): + Force OTA CSC (optional): + CaID BoxEMM: + OTA (Over-The-Air) CWPK: + CWPK0: + CWPK1: + CWPK2: + CWPK3: + CWPK4: + CWPK5: + CWPK6: + CWPK7: + diff --git a/webif/readerconfig/readerconfig_ncd524bit.html b/webif/readerconfig/readerconfig_ncd524bit.html index 6c1233bc..8bf83c3a 100644 --- a/webif/readerconfig/readerconfig_ncd524bit.html +++ b/webif/readerconfig/readerconfig_ncd524bit.html @@ -1,3 +1,12 @@ + AU NAGRA type: + + + + User: Password: Key: diff --git a/webif/readerconfig/readerconfig_ncd525bit.html b/webif/readerconfig/readerconfig_ncd525bit.html index 6c1233bc..8bf83c3a 100644 --- a/webif/readerconfig/readerconfig_ncd525bit.html +++ b/webif/readerconfig/readerconfig_ncd525bit.html @@ -1,3 +1,12 @@ + AU NAGRA type: + + + + User: Password: Key: -- 2.11.4.GIT