diff --git a/package/lean/dvb/dvb-firmware/Makefile b/package/lean/dvb/dvb-firmware/Makefile new file mode 100644 index 0000000000..8c6d0f0b40 --- /dev/null +++ b/package/lean/dvb/dvb-firmware/Makefile @@ -0,0 +1,40 @@ +# +# Copyright (C) 2017 McMCC +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=dvb-firmware +PKG_VERSION:=1.0 +PKG_RELEASE:=2 + +include $(INCLUDE_DIR)/package.mk + +define Package/dvb-firmware + SECTION:=dvb-firmware + CATEGORY:=Firmware + TITLE:=dvb-firmware megapack +endef + +define Package/dvb-firmware/description + dvb-firmware is specialised software that is both specific to some hardware + and also integral for its proper functioning. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR)/firmware + $(CP) ./src/* $(PKG_BUILD_DIR)/firmware +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/dvb-firmware/install + $(INSTALL_DIR) $(1)/lib/firmware + $(CP) $(PKG_BUILD_DIR)/firmware/* $(1)/lib/firmware +endef + +$(eval $(call BuildPackage,dvb-firmware)) diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-mn88472-02.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-mn88472-02.fw new file mode 100644 index 0000000000..1f0177813b Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-demod-mn88472-02.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-mn88473-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-mn88473-01.fw new file mode 100644 index 0000000000..1b2eceabb0 Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-demod-mn88473-01.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-01.fw new file mode 100644 index 0000000000..5882a21424 Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-01.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-02.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-02.fw new file mode 100644 index 0000000000..62d627625e Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-02.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-a20-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-a20-01.fw new file mode 100644 index 0000000000..13f09efe22 Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-a20-01.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-a30-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-a30-01.fw new file mode 100644 index 0000000000..96186e7afb Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-a30-01.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-b40-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-b40-01.fw new file mode 100644 index 0000000000..9f892cea60 Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-b40-01.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-d60-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-d60-01.fw new file mode 100644 index 0000000000..2a47ab5354 Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2168-d60-01.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-demod-si2183-b60-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2183-b60-01.fw new file mode 100644 index 0000000000..2a47ab5354 Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-demod-si2183-b60-01.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-fe-ds3000.fw b/package/lean/dvb/dvb-firmware/src/dvb-fe-ds3000.fw new file mode 100644 index 0000000000..e239559d9b Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-fe-ds3000.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-tuner-si2141-a10-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-tuner-si2141-a10-01.fw new file mode 100644 index 0000000000..b7be881fb5 Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-tuner-si2141-a10-01.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-tuner-si2158-a20-01.fw b/package/lean/dvb/dvb-firmware/src/dvb-tuner-si2158-a20-01.fw new file mode 100644 index 0000000000..42efbe0de3 Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-tuner-si2158-a20-01.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-usb-dw2101.fw b/package/lean/dvb/dvb-firmware/src/dvb-usb-dw2101.fw new file mode 100644 index 0000000000..05a876f923 Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-usb-dw2101.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-usb-dw2102.fw b/package/lean/dvb/dvb-firmware/src/dvb-usb-dw2102.fw new file mode 100644 index 0000000000..bf60205671 Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-usb-dw2102.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-usb-dw2104.fw b/package/lean/dvb/dvb-firmware/src/dvb-usb-dw2104.fw new file mode 100644 index 0000000000..b1fc1c95db Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-usb-dw2104.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-usb-dw3101.fw b/package/lean/dvb/dvb-firmware/src/dvb-usb-dw3101.fw new file mode 100644 index 0000000000..92d6b0e841 Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-usb-dw3101.fw differ diff --git a/package/lean/dvb/dvb-firmware/src/dvb-usb-tbsqbox-id5521.fw b/package/lean/dvb/dvb-firmware/src/dvb-usb-tbsqbox-id5521.fw new file mode 100644 index 0000000000..969a642b4b Binary files /dev/null and b/package/lean/dvb/dvb-firmware/src/dvb-usb-tbsqbox-id5521.fw differ diff --git a/package/lean/dvb/libdvbcsa/Makefile b/package/lean/dvb/libdvbcsa/Makefile new file mode 100644 index 0000000000..1bdb22213c --- /dev/null +++ b/package/lean/dvb/libdvbcsa/Makefile @@ -0,0 +1,57 @@ +# +# Copyright (C) 2014 nanpuyue +# Copyright (C) 2017 Tomasz Maciej Nowak +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk + +PKG_NAME := libdvbcsa +PKG_RELEASE := 1 + +PKG_SOURCE_PROTO := git +PKG_SOURCE_URL := https://github.com/glenvt18/libdvbcsa.git +PKG_SOURCE_VERSION := 2a1e61e569a621c55c2426f235f42c2398b7f18f + +PKG_VERSION := 1.1.0-$(shell printf '%.8s' $(PKG_SOURCE_VERSION)) +#PKG_SOURCE := $(PKG_NAME)-$(PKG_VERSION).tar.gz +#PKG_SOURCE_URL := http://download.videolan.org/pub/videolan/libdvbcsa/$(PKG_VERSION)/ +#PKG_HASH := 4db78af5cdb2641dfb1136fe3531960a477c9e3e3b6ba19a2754d046af3f456d + +PKG_LICENSE := GPL-2.0 +PKG_LICENSE_FILE := COPYING + +PKG_MAINTAINER := Tomasz Maciej Nowak + +PKG_INSTALL := 1 + +include $(INCLUDE_DIR)/package.mk + +define Package/libdvbcsa + SECTION := libs + CATEGORY := Libraries + TITLE := DVB Common Scrambling Algorithm library + URL := https://www.videolan.org/developers/libdvbcsa.html +endef + +define Package/libdvbcsa/description + libdvbcsa is a free implementation of the DVB Common Scrambling + Algorithm - DVB/CSA - with encryption and decryption capabilities +endef + +define Build/Configure + (cd $(PKG_BUILD_DIR); ./bootstrap) + $(call Build/Configure/Default) +endef + +define Build/InstallDev + $(CP) $(PKG_INSTALL_DIR)/usr $(1)/ +endef + +define Package/libdvbcsa/install + $(INSTALL_DIR) $(1)/usr/lib + $(CP) $(PKG_INSTALL_DIR)/usr/lib/libdvbcsa.so* $(1)/usr/lib/ +endef + +$(eval $(call BuildPackage,libdvbcsa)) diff --git a/package/lean/dvb/oscam/Makefile b/package/lean/dvb/oscam/Makefile new file mode 100755 index 0000000000..f35f90be4d --- /dev/null +++ b/package/lean/dvb/oscam/Makefile @@ -0,0 +1,89 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=oscam +PKG_REV:=11402 +PKG_VERSION:=1.20-$(PKG_REV) +PKG_RELEASE:=1 + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_VERSION:=175e3c61ebf8df3611f980f88ff8b153c4f456d7 +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_URL:=http://repo.or.cz/oscam.git +PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.bz2 +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +PKG_MAINTAINER:=OSCam developers +PKG_LICENSE:=GPL-3.0 +PKG_LICENSE_FILES:=COPYING + + +PKG_BUILD_PARALLEL:=1 +PKG_USE_MIPS16:=0 + +include $(INCLUDE_DIR)/package.mk + +define Package/oscam + SECTION:=net + CATEGORY:=Network + DEPENDS:=+libopenssl +libusb-1.0 +kmod-usb-serial +kmod-usb-serial-ch341 +kmod-usb-serial-ftdi +kmod-usb-serial-pl2303 +libpcsclite +pcscd +ccid + TITLE:=OSCam is an Open Source Conditional Access Module software + URL:=http://www.streamboard.tv/oscam/ +endef + +define Package/oscam/description + OSCam is an Open Source Conditional Access Module software, + based on the very good MpCS version 0.9d created by ​dukat. +endef + +define Package/oscam/conffiles +/etc/oscam/oscam.conf +/etc/oscam/oscam.server +/etc/oscam/oscam.user +/etc/oscam/SoftCam.Key +/etc/oscam/oscam.dvbapi +endef + +CONFIGURE_CMD = ./config.sh +CONFIGURE_ARGS = \ + --enable all + +MAKE_FLAGS += \ + CONF_DIR=/etc/oscam \ + OSCAM_BIN=Distribution/oscam \ + USE_SSL=1 \ + USE_LIBUSB=1 \ + USE_PCSC=1 \ + USE_LIBCRYPTO=1 + + +define Package/oscam/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/Distribution/oscam $(1)/usr/bin/oscam + + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/oscam.init $(1)/etc/init.d/oscam + + $(INSTALL_DIR) $(1)/etc/oscam + $(INSTALL_CONF) ./files/oscam.conf $(1)/etc/oscam + $(INSTALL_CONF) ./files/oscam.server $(1)/etc/oscam + $(INSTALL_CONF) ./files/oscam.user $(1)/etc/oscam + $(INSTALL_CONF) ./files/SoftCam.Key $(1)/etc/oscam + $(INSTALL_CONF) ./files/oscam.dvbapi $(1)/etc/oscam + + +endef + + +define Package/$(PKG_NAME)/prerm + #!/bin/sh + # if run within buildroot exit + [ -n "$${IPKG_INSTROOT}" ] && exit 0 + + # stop running scripts + /etc/init.d/oscam disable + /etc/init.d/oscam stop + + exit 0 +endef + +$(eval $(call BuildPackage,oscam)) diff --git a/package/lean/dvb/oscam/files/SoftCam.Key b/package/lean/dvb/oscam/files/SoftCam.Key new file mode 100644 index 0000000000..8a660e921f --- /dev/null +++ b/package/lean/dvb/oscam/files/SoftCam.Key @@ -0,0 +1,1462 @@ +# :::::::::: sat-life.info 17.06.2016 ::::::::::::::: +# <><><><><> by Serjoga latvia <><><><><><> +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: NAGRA ::::::::: +#^^^^^^^^^^^^^^^^^^^^^^^ +::::::: UNity Media ::::::: +N 1102 00 F8780ECD862D143B9B23ECFFCBB872A4 ; UnityMedia Cable TV (german) +N 1102 01 FAD9E99827B3D66B624FA382E52615E1 ; UnityMedia Cable TV (german) +N 1102 M1 C75C2FECF494F6DD71BBF898C63F7FEBA11345DF14C71EE656 BC23016C2F90A881429B82A68C095E472C997752D5890341CF 9E06691672482718750B918AAE92 ; UnityMedia Cable TV (german) +#^^^^^^^^^^^^^^^^^^^^^^^^ +::::::: Cablecom Swiss Cable TV ::::::: +N 7301 00 950B684C48CAC1B9DBBCC03162FA4726 ;Cablecom Swiss Cable TV (Switzerland) +N 7301 01 FE0C200B4B1D3302CA107133D7771D79 ;Cablecom Swiss Cable TV (Switzerland) +N 7301 M1 7544E982065D53E7CF049AF2E725544A50268DA1462F15D8A197ECE4B80FE221122F92AD56324380A04878EBF563427DD85C38645907583E23AC5153E300CF84 ;Cablecom Swiss Cable TV (switzerland) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: IRDETO2 ::::::: +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +I 060400 02 2D265F5993B812E4A73BA29A2778BEC5 ### Bulsat 39.0E +I 060400 03 B3A283325BF7A18BA8B4084BFB5F9370 ### Bulsat 39.0E +I 060400 04 1E98FD1658E5414BC32E3D37775646DF ### Bulsat 39.0E +I 060400 06 78A6823BF854E0F8886FF60C0FAA6528 ### Bulsat 39.0E +I 060400 M1 98B4DCAD44E8C9504C3F4E51692A7047 ### Bulsat 39.0E +I 060400 M2 AE652B210BF89FC69507609842FD303E ### Bulsat 39.0E +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Viacess ::::::: +V 023800 08 955CF3C92800F39F54B93005DF826DBF , SSR/SRG Swiss (13.0E) +V 023800 D1 0B552C11AF0A2FB8 ; Des1_Key +V 023800 X1 3D1229C2ED29C130 ; XORArray +V 023800 P1 0304000207050106 ; PermArray +V 023800 C1 DA4E0B42134F433B ; ChainArray +V 023800 T1 495EE3839DD6544AF23FC1EC7C684D973CF873926F1CF0F586DA31A1156BA69A3461A28A965DCB2A5B932757B3D34640CF1A654C20A548C3E6B97DBD104363092FC89C3D67D82EAE3600075C330E8D946AE8AD5F06E7F42BB79FAC284B250153BE217A3EFD3291440D8F501DC5A8A7147BBBED12C4BF89DBDCD162700C3A95AFB4F6B103C6FB18DDC77623E4FC4EF169AA6613294F7E240FB59E1FAB42049959D91B22B6F9351E6E6DC2909B5A52477FC082FE2C8098A358D739DE71D23B6075B00AA937746C848841CAC926F7EAE230DF79BC2DEEF305B845A019777887BAD0FAE5CE028BE1385551EFCDFF0B72D4E9168E08D5561781CC11A4E0858C64B2EB1E84CC47F20C8155 ;TransformTable +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +V 007400 08 2FB60239D4D8C4D6 ;Mezzo 13E +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +V 021110 08 35F6B9217C2BA83F38C3C1FD23A5D321 ;Ant-1 Europe 9E +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +V 030B00 T1 7F308A9B0B803C4B6BBFEFB041F03B58E3BCAFBEE583B415A53571952BABE9A17964A8BA8BE4E053DB6AD5511C063739D81786DD92871BD7B718E7312DDC77F3DE1AD4FC60932909703D97B9688F2C5B6221F501D0894F995028A9FD4A3F9861F71F20AD030846CF546C44DF76C18D0078F607A0F17A2E32119FF4852F4913C2599E9623EB1924EDDA25FECAF894226533579DC3A39C0E56044882BD755AACFA26A6B3E80567ECB136E6FF4D107E8CB8AAE1EE8E5FC42A9A525DC702CD72B20F88D9437D16D65ECB406D144CF9745C127CC0C9A7A49069BB0DEAC8C563AE664ED26FB57B271D6E3ECEC645D3D142E238A2B63A340AFB73911E84CC47F20C8155 ; TransformTable +V 030B00 X1 8B2908AE39B0101A ;XORTABLE +V 030B00 P1 0704020305000601 ;PERMTABLE +V 030B00 C1 FC3C5F15D7A0B437 ;CW1XOR +V 030B00 08 D92A82E3111C9AFDED4626AD0B542E5B ;TNTSat +V 030B00 09 CC72AAFE5265D6D04608E832CEB9EC4D ;TNTSat +V 030B00 0A EE2679604A7DDD32E4F8CB913500D38E ;TNTSat +V 030B00 0B 7C6A2428C020023B163E4FE024FF5D9D ;TNTSat +V 030B00 E1 F627E52F1782BE037223B0D349E0361A ;AES KEY Decrypt +V 030B00 E2 EF3CB8D36A862097A33FC47101041BE3 ;TNTSat HD SurEncryption Key +V 030B00 E4 6B1B024D36F60974973CB81FA5E8F01C ;WB2 HD SurEncryption +V 030B00 E15 127003F8E95100367A556121C779FB6E ;TNT Sat HD +V 030B00 E17 1DE5B042AD670BB16A3A76BDAD2F7AC0 +V 030B00 EC 9A3EAB0203EBFFCA85B4F18280749F56 ;WB SurEncryption Key +V 030B00 ED 2504B382B16D8C6758DB960E311E9351 ;WB2 SurEncryption Key +V 030B00 EE 349883E54D58336DCA750A878ACC5CD5 ;WB2 SD SurEncryption +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::::: VideoGuard ::::::::: +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +S 090F 00 1585C5E4B852ECF7C3D908BA224A66F282154FB218486397DC19D8519A39FCCA1C24D065A9662DD6533B86BA40EA4C6DD91E4114FE15AFC318C5F8A7A8010001 ;Viasat (4.9E) +S 093E 00 1585C5E4B852ECF7C3D908BA224A66F282154FB218486397DC19D8519A39FCCA1C24D065A9662DD6533B86BA40EA4C6DD91E4114FE15AFC318C5F8A7A8010001 ;Viasat (4.9E) +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::::: PowerVu ::::::::: +P 0011 00 437DD3B2A0A6D5 ;VTV HD 40.5W +P 0011 01 466B3B814138E1 ;VTV HD 40.5W +P 0013 00 437DD3B2A0A6D5 ;Gol TV HD 40.5W +P 0013 01 466B3B814138E1 ;Gol TV HD 40.5W +P 0017 00 437DD3B2A0A6D5 ;Gol TV Alternate 40.5W +P 0017 01 466B3B814138E1 ;Gol TV Alternate 40.5W + +P 9CA0 00 216447C54874C3 ;Discovery Showcase Europe HD 0.9W +P 9CA0 01 70F4D06DB57699 ;Discovery Showcase Europe HD 0.9W +P A8C0 00 216447C54874C3 ;ID Xtra Europe Russian HD 0.9W +P A8C0 01 70F4D06DB57699 ;ID Xtra Europe Russian HD 0.9W +P A8D0 00 216447C54874C3 ;ID Xtra Europe HD 0.9W +P A8D0 01 70F4D06DB57699 ;ID Xtra Europe HD 0.9W +P 5140 00 216447C54874C3 ;Historia Poland 0.9W +P 5140 01 70F4D06DB57699 ;Historia Poland 0.9W +P 5780 00 216447C54874C3 ;Discovery Iberia 0.9W +P 5780 01 70F4D06DB57699 ;Discovery Iberia 0.9W +P BB80 00 216447C54874C3 ;DTX 0.9W +P BB80 01 70F4D06DB57699 ;DTX 0.9W +P 9C60 00 216447C54874C3 ;Discovery Russia HD 0.9W +P 9C60 01 70F4D06DB57699 ;Discovery Russia HD 0.9W +P AF00 00 216447C54874C3 ;Discovery Poland HD 0.9W +P AF00 01 70F4D06DB57699 ;Discovery Poland HD 0.9W +P C830 00 216447C54874C3 ;Science Europe Russia HD 0.9W +P C830 01 70F4D06DB57699 ;Science Europe Russia HD 0.9W +P C850 00 216447C54874C3 ;Science Europe HD 0.9W +P C850 01 70F4D06DB57699 ;Science Europe HD 0.9W +P A2A0 00 216447C54874C3 ;Animal Planet Russia HD 0.9W +P A2A0 01 70F4D06DB57699 ;Animal Planet Russia HD 0.9W +P A290 00 216447C54874C3 ;Animal Planet Poland HD 0.9W +P A290 01 70F4D06DB57699 ;Animal Planet Poland HD 0.9W +P A2E0 00 216447C54874C3 ;Animal Planet HD 0.9W +P A2E0 01 70F4D06DB57699 ;Animal Planet HD 0.9W +P 0650 00 7F468E8B047CDE ;NBC Universal 0.9W +P 0650 01 679352FC3DEDF4 ;NBC Universal 0.9W + +P 0140 00 A25AE797314F61 ;HBO Hungary 4.0W +P 0140 01 4245667429DFEE ;HBO Hungary 4.0W +P 0020 00 A25AE797314F61 ;HBO Hungary 4.0W +P 0020 01 4245667429DFEE ;HBO Hungary 4.0W +P 0310 00 A25AE797314F61 ;HBO Comedy 4.0W +P 0310 01 4245667429DFEE ;HBO Comedy 4.0W +P 0330 00 A25AE797314F61 ;HBO Comedy Hungary/Czech 4.0W +P 0330 01 4245667429DFEE ;HBO Comedy Hungary/Czech 4.0W +P 0E90 00 A25AE797314F61 ;HBO Poland 4.0W +P 0E90 01 4245667429DFEE ;HBO Paland 4.0W +P 02A0 00 A25AE797314F61 ;HBO COMEDY HUNGARY, 4W +P 02A0 01 4245667429DFEE ;HBO COMEDY HUNGARY, 4W +P 0340 00 A25AE797314F61 ;HBO HUNGARY (AC3), 4W +P 0340 01 4245667429DFEE ;HBO HUNGARY (AC3), 4W +P 0CC0 00 A25AE797314F61 ;HBO 2 4.0W +P 0CC0 01 4245667429DFEE ;HBO 2 4.0W +P 00C9 00 A25AE797314F61 ;HBO2 HUNGARY, 4W +P 0C90 01 4245667429DFEE ;HBO2 HUNGARY, 4W +P 0CB0 00 A25AE797314F61 ;HBO2 OrigHu, 4W +P 0CB0 01 4245667429DFEE ;HBO2 OrigHu, 4W +P 0CA0 00 A25AE797314F61 ;HBO2 CZECH, 4W +P 0CA0 01 4245667429DFEE ;HBO2 CZECH, 4W +P 0E60 00 A25AE797314F61 ;Cinemax International 4.0W +P 0E60 01 4245667429DFEE ;Cinemax International 4.0W +P 0EC0 00 A25AE797314F61 ;Cinemax International 2 4.0W +P 0EC0 01 4245667429DFEE ;Cinemax International 2 4.0W +P 0F60 00 A25AE797314F61 ;Cinemax 2 International 4.0W +P 0F60 01 4245667429DFEE ;Cinemax 2 International 4.0W +P 0E70 00 A25AE797314F61 ;CINEMAX HUNGARY, 4W +P 0E70 01 4245667429DFEE ;CINEMAX HUNGARY, 4W +P 0F10 00 A25AE797314F61 ;CINEMAX 2 HUNGARY, 4W +P 0F10 01 4245667429DFEE ;CINEMAX 2 HUNGARY, 4W +P 0FB0 00 A25AE797314F61 ;CINEMAX 2 HUNGARY/Czech, 4W +P 0FB0 01 4245667429DFEE ;CINEMAX 2 HUNGARY/Czech, 4W +P 0F30 00 A25AE797314F61 ;CINEMAX 2 POLAND, 4W +P 0F30 01 4245667429DFEE ;CINEMAX 2 POLAND, 4W + +P 1FE0 00 B07EC58F412BD7 ;The Fight Network 15.0W +P 1FE0 01 A52E79D341F87F ;The Fight Network 15.0W + +P 00B0 00 6DADC79AAD00CF ;AFN Sports HD 9.0E +P 00B0 01 9E83D4513F3B23 ;AFN Sports HD 9.0E +P 0010 00 6DADC79AAD00CF ;AFN Sports 9.0E +P 0010 01 9E83D4513F3B23 ;AFN Sports 9.0E +P 0060 00 6DADC79AAD00CF ;AFN Sports 2 9.0E +P 0060 01 9E83D4513F3B23 ;AFN Sports 2 9.0E +P 0020 00 6DADC79AAD00CF ;AFN Prime Atlantic 9.0E +P 0020 01 9E83D4513F3B23 ;AFN Prime Atlantic 9.0E +P 0070 00 6DADC79AAD00CF ;Guide 9.0E +P 0070 01 9E83D4513F3B23 ;Guide 9.0E +P 0030 00 6DADC79AAD00CF ;Spectrum 9.0E +P 0030 01 9E83D4513F3B23 ;Spectrum 9.0E +P 0050 00 6DADC79AAD00CF ;News 9.0E +P 0050 01 9E83D4513F3B23 ;News 9.0E +P 0040 00 6DADC79AAD00CF ;Pacific 9.0E +P 0040 01 9E83D4513F3B23 ;Pacific 9.0E +P 0090 00 6DADC79AAD00CF ;Fam/Pulse 9.0E +P 0090 01 9E83D4513F3B23 ;Fam/Pulse 9.0E +P 00A0 00 6DADC79AAD00CF ;Movie 9.0E +P 00A0 01 9E83D4513F3B23 ;Movie 9.0E +P 06B0 00 6DADC79AAD00CF ;Decoder Expired 9.0E +P 06B0 01 9E83D4513F3B23 ;Decoder Expired 9.0E +P 0630 00 6DADC79AAD00CF ;Download 9.0E +P 0630 01 9E83D4513F3B23 ;Download 9.0E + +P 02C0 00 0123456789ABCD ;Snai Virtuali 1 16E +P 02C0 01 97D6968EEC34A3 ;Snai Virtuali 1 16E +P 0370 00 0123456789ABCD ;CH 55 Virtuali 3 16E +P 0370 01 97D6968EEC34A3 ;CH 55 Virtuali 3 16E + +#______________________12303 H 25548__________________________________ +P 2620 00 3AAB2C9D1A23BB ;DIVA Romania 4.9E +P 2620 01 01104AD73016C3 ;DIVA Romania 4.9E +P 1650 00 3AAB2C9D1A23BB ;CN TCM Russia 4.9E +P 1650 01 01104AD73016C3 ;CN TCM Russia 4.9E +P 1640 00 3AAB2C9D1A23BB ;CN/TCM RSEE 4.9E +P 1640 01 01104AD73016C3 ;CN/TCM RSEE 4.9E +P 26C0 00 3AAB2C9D1A23BB ;Universal Croatia-Slovenia 4.9E +P 26C0 01 01104AD73016C3 ;Universal Croatia-Slovenia 4.9E + +#______________________12322 V 27500__________________________________ +P 44C0 00 CBC3ECF15309C6 ;Discovery Turkey HD 4.9E +P 44C0 01 C19C56769B52AA ;Discovery Turkey HD 4.9E +P 1F40 00 CBC3ECF15309C6 ;Discovery Science Polska 4.9E +P 1F40 01 C19C56769B52AA ;Discovery Science Polska 4.9E +P 0640 00 CBC3ECF15309C6 ;Animal Planet Europe 4.9E +P 0640 01 C19C56769B52AA ;Animal Planet Europe 4.9E +P 0C80 00 CBC3ECF15309C6 ;Discovery central Europe 4.9E +P 0C80 01 C19C56769B52AA ;Discovery central Europe 4.9E +P 12D0 00 CBC3ECF15309C6 ;ID Europe 4.9E +P 12D0 01 C19C56769B52AA ;ID Europe 4.9E +P 1900 00 CBC3ECF15309C6 ;ID Extra Europe 4.9E +P 1900 01 C19C56769B52AA ;ID Extra Europe 4.9E +P 3850 00 CBC3ECF15309C6 ;Science Europe 4.9E +P 3850 01 C19C56769B52AA ;Science Europe 4.9E +P 1F40 00 CBC3ECF15309C6 ;Discovery World 4.9E +P 1F40 01 C19C56769B52AA ;Discovery World 4.9E +P 3E80 00 CBC3ECF15309C6 ;Discovery World 4.9E +P 3E80 01 C19C56769B52AA ;Discovery World 4.9E + +#______________________12360 V 27500_______________________________ +P 125C 00 216447C54874C3 ;Eurosport 2 Wimbledon HD 4.9E +P 125C 01 70F4D06DB57699 ;Eurosport 2 Wimbledon HD 4.9E +P 7080 00 216447C54874C3 ;Science Poland HD 4.9E +P 7080 01 70F4D06DB57699 ;Science Poland HD 4.9E +P 6A40 00 216447C54874C3 ;Animal Planet Poland HD 4.9E +P 6A40 01 70F4D06DB57699 ;Animal Planet Poland HD 4.9E +P C1C0 00 216447C54874C3 ;TLC Poland HD 4.9E & 0.9W +P C1C0 01 70F4D06DB57699 ;TLC Poland HD 4.9E & 0.9W +P 2BC0 00 216447C54874C3 ;Discovery Bulgaria 4.9E +P 2BC0 01 70F4D06DB57699 ;Discovery Bulgaria 4.9E +P B540 00 216447C54874C3 ;TLC Pan Regional 4.9E +P B540 01 70F4D06DB57699 ;TLC Pan Regional 4.9E +P 2580 00 216447C54874C3 ;Turbo Xtra Poland 4.9E +P 2580 01 70F4D06DB57699 ;Turbo Xtra Poland 4.9E +P 8340 00 216447C54874C3 ;ID Poland 4.9E +P 8340 01 70F4D06DB57699 ;ID Poland 4.9E +P 6400 00 216447C54874C3 ;ID Sweden 4.9E +P 6400 01 70F4D06DB57699 ;ID Sweden 4.9E +P 3200 00 216447C54874C3 ;TLC Balcans 4.9E +P 3200 01 70F4D06DB57699 ;TLC Balcans 4.9E +P 12C0 00 216447C54874C3 ;Discovery Channel Romania 4.9E +P 12C0 01 70F4D06DB57699 ;Discovery Channel Romania 4.9E +P 3840 00 216447C54874C3 ;Discovery Ukraine 4.9E +P 3840 01 70F4D06DB57699 ;Discovery Ukraine 4.9E +P 5DC0 00 216447C54874C3 ;Discovery Life Poland 4.9E +P 5DC0 01 70F4D06DB57699 ;Discovery Life Poland 4.9E +#______________________________________________________ +P 0930 00 C56B7706315E3F ;New Boyles Sport 4.9E +P 0930 01 DD51BECAA44C1F ;New Boyles Sport 4.9E +P 0350 00 C56B7706315E3F ;William Hill 4.9E +P 0350 01 DD51BECAA44C1F ;William Hill 4.9E +P 0560 00 C56B7706315E3F ;SIS 2 4.9E +P 0560 01 DD51BECAA44C1F ;SIS 2 4.9E +P 0170 00 C56B7706315E3F ;Coral TV2 4.9E +P 0170 01 DD51BECAA44C1F ;Coral TV2 4.9E +P 0420 00 C56B7706315E3F ;Ladbrokes 1 4.9E +P 0420 01 DD51BECAA44C1F ;Ladbrokes 1 4.9E + +P 0650 00 2E40E327BB7837 ;MTN Worldwide TV (34.5W & 47.5W & 57.0 & 20W) +P 0650 01 FFFA91E97B2570 ;MTN Worldwide TV (34.5W & 47.5W & 57.0 & 20W) + +P 0020 00 5A5E959C3743B7 ;SET Asia 66E +P 0020 01 C367E0F812D1DE ;SET Asia 66E +P 0050 00 5A5E959C3743B7 ;SET Middle East 66E +P 0050 01 C367E0F812D1DE ;SET Middle East 66E +P 0060 00 5A5E959C3743B7 ;Sony Max Asia 66E +P 0060 01 C367E0F812D1DE ;Sony Max Asia 66E +P 0070 00 5A5E959C3743B7 ;Sony Max UK 66E +P 0070 01 C367E0F812D1DE ;Sony Max UK 66E +P 0090 00 5A5E959C3743B7 ;Sony SAB TV Asia 66E +P 0090 01 C367E0F812D1DE ;Sony SAB TV Asia 66E +P 00A0 00 5A5E959C3743B7 ;Max Middle East 66E +P 00A0 01 C367E0F812D1DE ;Max Middle East 66E +P 00D0 00 5A5E959C3743B7 ;Sony Six 66E +P 00D0 01 C367E0F812D1DE ;Sony Six 66E +P 0320 00 5A5E959C3743B7 ;Sony Six HD 66E +P 0320 01 C367E0F812D1DE ;Sony Six HD 66E +P 0330 00 5A5E959C3743B7 ;SET Asia HD 66E +P 0330 01 C367E0F812D1DE ;SET Asia HD 66E +P 0340 00 5A5E959C3743B7 ;PIX HD 66E +P 0340 01 C367E0F812D1DE ;PIX HD 66E +P 0350 00 5A5E959C3743B7 ;AXN SA HD 66E +P 0350 01 C367E0F812D1DE ;AXN SA HD 66E +P 0360 00 5A5E959C3743B7 ;MAX SA HD 66E +P 0360 01 C367E0F812D1DE ;MAX SA HD 66E +P 0370 00 5A5E959C3743B7 ;Sony ESPN HD 66E +P 0370 01 C367E0F812D1DE ;Sony ESPN HD 66E +P 0420 00 5A5E959C3743B7 ;MAX INTERNATIONL 66E +P 0420 01 C367E0F812D1DE ;MAX INTERNATIONL 66E +P 0CA0 00 5A5E959C3743B7 ;SET INTERNATIONL 66E +P 0CA0 01 C367E0F812D1DE ;SET INTERNATIONL 66E +P 0FF0 00 5A5E959C3743B7 ;SOFTWAR 66E +P 0FF0 01 C367E0F812D1DE ;SOFTWAR 66E + +P 0150 00 113754C6C0CEE1 ;AS7 SD 1 (105.5E) +P 0150 01 00000000000000 ;AS7 SD 1 (105.5E) +P 0160 00 113754C6C0CEE1 ;AS7 SD 2 (105.5E) +P 0160 01 00000000000000 ;AS7 SD 2 (105.5E) +P 0170 00 113754C6C0CEE1 ;AS7 SD 3 (105.5E) +P 0170 01 00000000000000 ;AS7 SD 3 (105.5E) +P 0180 00 113754C6C0CEE1 ;AS7 SD 4 (105.5E) +P 0180 01 00000000000000 ;AS7 SD 4 (105.5E) +P 0470 00 113754C6C0CEE1 ;AS7 HD 1 (105.5E) +P 0470 01 00000000000000 ;AS7 HD 1 (105.5E) +P 0480 00 113754C6C0CEE1 ;AS7 HD 2 (105.5E) +P 0480 01 00000000000000 ;AS7 HD 2 (105.5E) +P 0490 00 113754C6C0CEE1 ;AS7 HD 3 (105.5E) +P 0490 01 00000000000000 ;AS7 HD 3 (105.5E) +P 04A0 00 113754C6C0CEE1 ;AS7 HD 4 (105.5E) +P 04A0 01 00000000000000 ;AS7 HD 4 (105.5E) +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::::: BISS ::::::::: +# ^^^^^^^^^^^^^^^^^^^^^^^^ +F 0009002D 00 764924E3510382D6 ;TEST (4.0W) +F 0009002D 01 764924E3510382D6 ;TEST (4.0W) +F 00050101 00 764924E3510382D6 ;FilmUaDrama (4.0W) +F 00050101 01 764924E3510382D6 ;FilmUaDrama (4.0W) +F 00060101 00 764924E3510382D6 ;FilmUAction (4.0W +F 00060101 01 764924E3510382D6 ;FilmUAction (4.0W) +F 00050501 00 123ABC08123ABC08 ;EuroNews (4.0W) +F 00050501 01 123ABC08123ABC08 ;EuroNews (4.0W) +F 00090901 00 AABBCC31CCBBAA31 ;NTV Mir (Amos 4W) +F 00090901 01 AABBCC31CCBBAA31 ;NTV Mir (Amos 4W) +F 00040401 00 107220A215050721 ;TV Kiev (Amos 4W) +F 00040401 01 107220A215050721 ;TV Kiev (Amos 4W) +F 00080801 00 AC1234F24321CA2E ;Inter (Amos 4W) +F 00080801 01 AC1234F24321CA2E ;Inter (Amos 4W) +F 00090901 00 1234AC001234AC00 ;INTER+ (4.0W) +F 00090901 01 1234AC001234AC00 ;INTER+ (4.0W) +F 00010101 00 AC1234004321CA00 ;Inter (4.0W) +F 00010101 01 AC1234004321CA00 ;Inter (4.0W) +F 00030301 00 654321C91234569C ;1+1Plus (4.0W) +F 00030301 01 654321C91234569C ;1+1Plus (4.0W) +F 00040401 00 1231236612312366 ;Mega (4.0W) +F 00040401 01 1231236612312366 ;Mega (4.0W) +F 00050501 00 130419308313049A ;Test (4.0W ) +F 00050501 01 130419308313049A ;Test (4.0W ) +F 000C1201 00 198313AF041983A0 ;Test 2 (4.0W) +F 000C1201 01 198313AF041983A0 ;Test 2 (4.0W) +F 000D0131 00 1006102611071129 ;Pershiy (4.0W) +F 000D0131 01 1006102611071129 ;Pershiy (4.0W) +F 000C0C01 00 1A2B3C81C3B2A116 ;Trofey (4.0W) +F 000C0C01 01 1A2B3C81C3B2A116 ;Trofey (4.0W) +F 00010501 00 1234569C654321C9 ;Unian TV (4W) +F 00010501 01 1234569C654321C9 ;Unian TV (4W) +F 000808C0 00 2222226622222266 ;TV 1 Bosnia (4W) +F 000808C0 01 2222226622222266 ;TV 1 Bosnia (4W) + +F 0028008D 00 A1B2C316D4E5F8B1 ;ERT Digital - ERT HD (3.0E) +F 0028008D 01 A1B2C316D4E5F8B1 ;ERT Digital - ERT HD (3.0E) +F 0014008B 00 A1B2C316D4E5F8B1 ;ERT Digital - ET2 (3.0E) +F 0014008B 01 A1B2C316D4E5F8B1 ;ERT Digital - ET2 (3.0E) +F 0023008E 00 A1B2C316D4E5F8B1 ;ERT Digital - ET3 (3.0E) +F 0023008E 01 A1B2C316D4E5F8B1 ;ERT Digital - ET3 (3.0E) +F 000A008A 00 A1B2C316D4E5F8B1 ;ERT Digital - ET1 (3.0E) +F 000A008A 01 A1B2C316D4E5F8B1 ;ERT Digital - ET1 (3.0E) +F 0064047E 00 1111113311111133 ;ALPHA TV Greece (3.0E) +F 0064047E 01 1111113311111133 ;ALPHA TV Greece (3.0E) +F 015E0550 00 1111113311111133 ;ART (3.0E) +F 015E0550 01 1111113311111133 ;ART (3.0E) +F 0320073A 00 1111113311111133 ;ETV (3.0E) +F 0320073A 01 1111113311111133 ;ETV (3.0E) +F 02580672 00 1111113311111133 ;Skai (3.0E) +F 02580672 01 1111113311111133 ;Skai (3.0E) +F 02BC06D7 00 1111113311111133 ;Star Channel (3.0E) +F 02BC06D7 01 1111113311111133 ;Star Channel (3.0E) +F 01F4060E 00 1111113311111133 ;Mega Channel (3.0E) +F 01F4060E 01 1111113311111133 ;Mega Channel (3.0E) +F 019005AA 00 1111113311111133 ;Macedonia TV (3.0E) +F 019005AA 01 1111113311111133 ;Macedonia TV (3.0E) +F 012C0546 00 1111113311111133 ;ANT 1 (3.0E) +F 012C0546 01 1111113311111133 ;ANT 1 (3.0E) + +F 1A131A14 00 1122336633221166 ;XSport (4.9E) +F 1A131A14 01 1122336633221166 ;XSport (4.9E) +F 17ED17EE 00 1A2B3CAC4D5E6F0B ;1+1 Internetional (4.9E) +F 17ED17EE 01 1A2B3CAC4D5E6F0B ;1+1 Internetional (4.9E) +F 182E182F 00 5EB22B2576F5016 ;Ukraina-SD (4.9E) +F 182E182F 01 5EB22B2576F5016 ;Ukraina-SD (4.9E) +F 19D219D3 00 A5EB22B2576F5016 ;TRK Ukraina (4.9E) +F 19D219D3 01 A5EB22B2576F5016 ;TRK Ukraina (4.9E) +F 1A0E1A0F 00 A5EB2200576F7500 ;34 Telekanal (4.9E) +F 1A0E1A0F 01 A5EB2200576F7500 ;34 Telekanal (4.9E) +F 1A181A19 00 A5EB22B2576F25EB ;NLO TV (4.9E) +F 1A181A19 01 A5EB22B2576F25EB ;NLO TV (4.9E) +F 1A221A23 00 A5EB22B2576F25EB ;Indigo (4.9E) +F 1A221A23 01 A5EB22B2576F25EB ;Indigo (4.9E) +F 1B4E1B4F 00 1234AC001234AC00 ;Inter+ (4.9E) +F 1B4E1B4F 01 1234AC001234AC00 ;Inter+ (4.9E) +F 17DE17DF 00 19090628117660E7 ;TET (4.9E) +F 17DE17DF 01 19090628117660E7 ;TET (4.9E) + +F 00010100 00 AABB127734CCDDDD ;Fox Sport Europe (7E) +F 00010100 01 AABB127734CCDDDD ;Fox Sport Europe (7E) +F 00320802 00 C7B2A51ED4E3F1A8 ;Mena Media Feed (7E) +F 00320802 01 C7B2A51ED4E3F1A8 ;Mena Media Feed (7E) +F 00030202 00 1FD100F000000000 ;EVN-TV ( EVN EVNTV EVN TV / EUROVISION TV / EURO VISION NEWS ) (7E) +F 00030202 01 1FD100F000000000 ;EVN-TV ( EVN EVNTV EVN TV / EUROVISION TV / EURO VISION NEWS ) (7E) + +F 03E60BB6 00 1A2B3C814D5E6F1A ;TEST 4 (9.0E) +F 03E60BB6 01 1A2B3C814D5E6F1A ;TEST 4 (9.0E) +F 03E70BB7 00 1A2B3C814D5E6F1A ;TEST 8 (9.0E) +F 03E70BB7 01 1A2B3C814D5E6F1A ;TEST 8 (9.0E) +F 027211F9 00 E876F04E8BA51141 ;EFB1 (9.0E) +F 027211F9 01 E876F04E8BA51141 ;EFB1 (9.0E) +F 042101C9 00 1111113322222266 ;ODIE (9.0E) +F 042101C9 01 1111113322222266 ;ODIE (9.0E) +F 002E07FE 00 E876F04E8BA51141 ;Eurofootball Gonki (9.0E) +F 002E07FE 01 E876F04E8BA51141 ;Eurofootball Gonki (9.0E) +F 002D07FD 00 C0379C93E08FBB2A ;Monitor Games (9.0E) +F 002D07FD 01 C0379C93E08FBB2A ;Monitor Games (9.0E) +F 00370807 00 E876F04E8BA51141 ;Opap TV (9.0E) +F 00370807 01 E876F04E8BA51141 ;Opap TV (9.0E) +F 00130731 00 2000ABCBCD2000ED ;Sat2000 (9.0E) +F 00130731 01 2000ABCBCD2000ED ;Sat2000 (9.0E) + +F 00020B0F 00 6C37BA5D492D7EF4 ;BARAEM (10E) +F 00020B0F 01 6C37BA5D492D7EF4 ;BARAEM (10E) +F 00010B07 00 6C37BA5D492D7EF4 ;JEEM SD (10E) +F 00010B07 01 6C37BA5D492D7EF4 ;JEEM SD (10E) +F 00030B19 00 6C37BA5D492D7EF4 ;JEEM HD (10E) +F 00030B19 01 6C37BA5D492D7EF4 ;JEEM HD (10E) +F 00080202 00 F8C5A966EBA461F0 ;NBA TV (10.0E) +F 00080202 01 F8C5A966EBA461F0 ;NBA TV (10.0E) +F 00010191 00 F87384EF72A4CDE3 ;NBA TV HD (10.0E) +F 00010191 01 F87384EF72A4CDE3 ;NBA TV HD (10.0E) +F 000E0579 00 2557AC28CE25574B ;Barca Tv (10.0E) +F 000E0579 01 2557AC28CE25574B ;Barca Tv (10.0E) +F 00070201 00 2EEA2E46FE9E59F5 ;NBA-ADHOC (10.0E) +F 00070201 01 2EEA2E46FE9E59F5 ;NBA-ADHOC (10.0E) +F 00020201 00 AE7B80A9F968AF10 ;NBA POOL EUROPE 1 (10.0E) +F 00020201 01 AE7B80A9F968AF10 ;NBA POOL EUROPE 1 (10.0E) +F 00040259 00 E6CC37E9DB183A2D ;IMG A Europe (10.0E) +F 00040259 01 E6CC37E9DB183A2D ;IMG A Europe (10.0E) +F 000301F5 00 AA8B5F9427006F96 ;USRSC Europe ESPN (10E) +F 000301F5 01 AA8B5F9427006F96 ;USRSC Europe ESPN (10E) +F 00050191 00 23B8EEC92B6534C4 ;Chelsea TV (10.0E) +F 00050191 01 23B8EEC92B6534C4 ;Chelsea TV (10.0E) +F 00060259 00 11C4461BCE347A7C ;Premier League HD (10.0E) +F 00060259 01 11C4461BCE347A7C ;Premier League HD (10.0E) +F 000107D1 00 205976EF823DB574 ;MUTV (9.0E-10.0E ) +F 000107D1 01 205976EF823DB574 ;MUTV (9.0E-10.0E ) +F 007B03E9 00 3D10CB184EEC7DB7 ;Service-123HD (10.0E) +F 007B03E9 01 3D10CB184EEC7DB7 ;Service-123HD (10.0E) +F 01C80FA1 00 D05FC9F85131B537 ;Service-456HD (10.0E) +F 01C80FA1 01 D05FC9F85131B537 ;Service-456HD (10.0E) +F 000307F8 00 0000232301151026 ;Sahar 1 (10.0E) +F 000307F8 01 0000232301151026 ;Sahar 1 (10.0E) +F 00040816 00 0000232301151026 ;Sahar 2 (10.0E) +F 00040816 01 0000232301151026 ;Sahar 2 (10.0E) +F 00031004 00 159ACD7CEBF614F5 ;MGM ME (10.0E) +F 00031004 01 159ACD7CEBF614F5 ;MGM ME (10.0E) +F 0001012C 00 1234569C789FFF16 ;Sharqiya News (10.0E) +F 0001012C 01 1234569C789FFF16 ;Sharqiya News (10.0E) +F 0002076E 00 0000232301151026 ;Alalam News Channel (10.0E) +F 0002076E 01 0000232301151026 ;Alalam News Channel (10.0E) +F 0005080C 00 0000232301151026 ;Al Kawthar (10.0E) +F 0005080C 01 0000232301151026 ;Al Kawthar (10.0E) +F 00011023 00 0000232301151026 ;iFilm (10.0E) +F 00011023 01 0000232301151026 ;iFilm (10.0E) +F 002A0021 00 2301234701230125 ;DEFUALT (10.0E) +F 002A0021 01 2301234701230125 ;DEFUALT (10.0E) +F 00010032 00 0204757B6840751D ;ORTC (10.0E) +F 00010032 01 0204757B6840751D ;ORTC (10.0E) + +F 2A2F006E 00 1A2B3C814D5E6F1A ;TEST 6 (13.0E) +F 2A2F006E 01 1A2B3C814D5E6F1A ;TEST 6 (13.0E) +F 00030028 00 CA50B7D131D6585F ;Al Aoula Maroc (13.0E) +F 00030028 01 CA50B7D131D6585F ;Al Aoula Maroc (13.0E) +F 34D2052A 00 1A2B3C814D5E6F1A ;1+1 International (13.0E) +F 34D2052A 01 1A2B3C814D5E6F1A ;1+1 International (13.0E) + +F 00010134 00 124578CF875421FC ;SIC International (16E) +F 00010134 01 124578CF875421FC ;SIC International (16E) +F 00100121 00 2016013727BAFFE0 ;Kombat Sport (16E) +F 00100121 01 2016013727BAFFE0 ;Kombat Sport (16E) +F 00010310 00 BC33584706679502 ;EUTELSAT 16A S3-01 (16E) +F 00010310 01 BC33584706679502 ;EUTELSAT 16A S3-01 (16E) +F 03FA070A 00 9E186D23B5A74CA8 ;HNL (16E) +F 03FA070A 01 9E186D23B5A74CA8 ;HNL (16E) +F 00160201 00 CDEF12CE5678905E ;National 24 Plus (16.0E) +F 00160201 01 CDEF12CE5678905E ;National 24 Plus (16.0E) +F 000A0101 00 458825F27453682F ;National TV (16.0E) +F 000A0101 01 458825F27453682F ;National TV (16.0E) +F 00010064 00 C48DAF008FDA9700 ;Kanal D1 (16.0E) +F 00010064 01 C48DAF008FDA9700 ;Kanal D1 (16.0E) +F 00C80200 00 71F0F0519D8C234C ;SRTV Feed (16.0E) +F 00C80200 01 71F0F0519D8C234C ;SRTV Feed (16.0E) +F 000E00FD 00 1111113311111133 ;Test HD (16.0E) +F 000E00FD 01 1111113311111133 ;Test HD (16.0E) +F 00010200 00 1B5C69E0AA08E99B ;SNAI LIVE & SNAI LIVE2 (16E) +F 00010200 01 1B5C69E0AA08E99B ;SNAI LIVE & SNAI LIVE2 (16E) +F 00020201 00 1B5C69E0AA08E99B ;SNAI LIVE & SNAI LIVE2 (16E) +F 00020201 01 1B5C69E0AA08E99B ;SNAI LIVE & SNAI LIVE2 (16E) + +F 000D0191 00 12312366456456FF ;STN Test Transcode - [ TRACE Africa ] (19.2E) +F 000D0191 01 12312366456456FF ;STN Test Transcode - [ TRACE Africa ] (19.2E) +F 00130192 00 12312366456456FF ;STN Test Remux - [ MA CHAINE SPORT Extreme ] (19.2E) +F 00130192 01 12312366456456FF ;STN Test Remux - [ MA CHAINE SPORT Extreme ] (19.2E) + +F 007F04F6 00 1A1B1C511D1E1F5A ;Sahar University Network 1 (20.0E) +F 007F04F6 01 1A1B1C511D1E1F5A ;Sahar University Network 1 (20.0E) +F 00750492 00 1111113311111133 ;IRIB Varzesh (20.0E) +F 00750492 01 1111113311111133 ;IRIB Varzesh (20.0E) + +F 00070301 00 A9E746D68358E5C0 ;Topaz 1 (21.5E) +F 00070301 01 A9E746D68358E5C0 ;Topaz 1 (21.5E) + +F 000103E9 00 ACDE109A0616BCD8 ;MBC MASR FEED (21.6E) +F 000103E9 01 ACDE109A0616BCD8 ;MBC MASR FEED (21.6E) + +F 4E860838 00 917CA5B26B78D2B5 ;Majd feed (26.0E) +F 4E860838 01 917CA5B26B78D2B5 ;Majd feed (26.0E) +F 000501FE 00 1111224422333388 ;TV 5 (26.0E) +F 000501FE 01 1111224422333388 ;TV 5 (26.0E) +F 00290429 00 1212123612121236 ;Drama USA (26E) +F 00290429 01 1212123612121236 ;Drama USA (26E) +F 00140250 00 1234569C789ABCCE ;Nilesat promo (26E) +F 00140250 01 1234569C789ABCCE ;Nilesat promo (26E) + +F 00010064 00 21CD07F51168017A ;ERI TV Earth (30.5E) +F 00010064 01 21CD07F51168017A ;ERI TV Earth (30.5E) +F 012F03EB 00 1111113311111133 ;IRIB TV 3 (30.5E) +F 012F03EB 01 1111113311111133 ;IRIB TV 3 (30.5E) + +F 0FA000A3 00 A4D352C91B6C28AF :SES Test(31E) +F 0FA000A3 01 A4D352C91B6C28AF :SES Test(31E) + +F 1C3E1C3F 00 1111113311111133 ;BTB (31.5E) +F 1C3E1C3F 01 1111113311111133 ;BTB (31.5E) +F 1C341C35 00 1111113311111133 ;BTB (31.5E) +F 1C341C35 01 1111113311111133 ;BTB (31.5E) + +F 00020055 00 1111113311111133 ;Armenia 1 TV (36E) +F 00020055 01 1111113311111133 ;Armenia 1 TV (36E) +F 0A100682 00 1AEF010A0EDEF1DD ;Armenia TV Region (36E) +F 0A100682 01 1AEF010A0EDEF1DD ;Armenia TV Region (36E) + +F 000202C7 00 1111113311111133 ;Kentron TV (39E) +F 000202C7 01 1111113311111133 ;Kentron TV (39E) + +F 00640065 00 0327022C106251C3 ;GTRK Nizhny Novgorod (40E) +F 00640065 01 0327022C106251C3 ;GTRK Nizhny Novgorod (40E) +F 00010134 00 0327022C106251C3 ;GTRK Package (40E) +F 00010134 01 0327022C106251C3 ;GTRK Package (40E) +F 00010021 00 0327022C106251C3 ;GTRK Vainah (40E) +F 00010021 01 0327022C106251C3 ;GTRK Vainah (40E) +F 00030136 00 0327022C106251C3 ;GTRK Komi Gor (40E) +F 00030136 01 0327022C106251C3 ;GTRK Komi Gor (40E) +F 00020201 00 0327022C106251C3 ;Rossiya 1 (0h) (40E) +F 00020201 01 0327022C106251C3 ;Rossiya 1 (0h) (40E) +F 00050204 00 0327022C106251C3 ;Rossiya 1 (+2h) (40E) +F 00050204 01 0327022C106251C3 ;Rossiya 1 (+2h) (40E) + +F 3C281130 00 F0212435149122C7 ;Nat Geo Wild HD Turkiye (42E) +F 3C281130 01 F0212435149122C7 ;Nat Geo Wild HD Turkiye (42E) +F 00010200 00 1012002223000326 ;TX9 (42E) +F 00010200 01 1012002223000326 ;TX9 (42E) +F 00020202 00 1012002223000326 ;TX10 (42E) +F 00020202 01 1012002223000326 ;TX10 (42E) +F 00030204 00 1012002223000326 ;TX11 (42E) +F 00030204 01 1012002223000326 ;TX11 (42E) +F 00040206 00 1012002223000326 ;TX12 (42E) +F 00040206 01 1012002223000326 ;TX12 (42E) +F 000717FF 00 DFFEFCD9FDBF18D4 ;NBA TV (42.0E) +F 000717FF 01 DFFEFCD9FDBF18D4 ;NBA TV (42.0E) +F 00010134 00 2012ABDDCD2012FF ;Xazar TV (42.0E) +F 00010134 01 2012ABDDCD2012FF ;Xazar TV (42.0E) +F 296D0645 00 1000001000000000 ;TRT World HD (42.0E) +F 296D0645 01 1000001000000000 ;TRT World HD (42.0E) +F 296A0642 00 1000001000000000 ;TRT HABER HD (42.0E) +F 296A0642 01 1000001000000000 ;TRT HABER HD (42.0E) +F 001109AB 00 1000001000000000 ;Fog TV (42.0E) +F 001109AB 01 1000001000000000 ;Fog TV (42.0E) +F 000B1F9A 00 3453450034534500 ;Idman_Azerbaycan (42.0E) +F 000B1F9A 01 3453450034534500 ;Idman_Azerbaycan (42.0E) +F 00011BB2 00 1234560065432100 ;AzTV Azerbaijan (42.0E) +F 00011BB2 01 1234560065432100 ;AzTV Azerbaijan (42.0E) +F 00010134 00 98B0AFF78711C65E ;NTV ANK.Buro (42.0E) +F 00010134 01 98B0AFF78711C65E ;NTV ANK.Buro (42.0E) +F 00070207 00 1000000000000000 ;Star TV Turkey (42.0E) +F 00070207 01 1000000000000000 ;Star TV Turkey (42.0E) +F 3DB80C71 00 1000001000000000 ;7/24 (42E) +F 3DB80C71 01 1000001000000000 ;7/24 (42E) +F 3DB91FFF 00 002123441361188C ;Intercom Radio (42.0E) +F 3DB91FFF 01 002123441361188C ;Intercom Radio (42.0E) +F 2BC31FFF 00 002123441361188C ;Intercom Radio (42.0E) (42E) +F 2BC31FFF 01 002123441361188C ;Intercom Radio (42.0E) (42E) +F 2BC41FFF 00 002123441361188C ;Intercom HT (Radyo) (42E) +F 2BC41FFF 01 002123441361188C ;Intercom HT (Radyo) (42E) +F 2BC51FFF 00 002123441361188C ;Intercom BL (Radyo) (42E) +F 2BC51FFF 01 002123441361188C ;Intercom BL (Radyo) (42E) +F 001A1FFF 00 1000001010000010 ;DOST FM Radyo (42.0E) +F 001A1FFF 01 1000001010000010 ;DOST FM Radyo (42.0E) +F 06121FFF 00 1000000000000000 :Fenerbahce Radyo (42.0E) +F 06121FFF 01 1000000000000000 ;Fenerbahce Radyo (42.0E) + +F 000101E1 00 1111113311111133 ;IRMAK TV (46E) +F 000101E1 01 1111113311111133 ;IRMAK TV (46E) +F 00010201 00 1028ACE4EB4473A2 ;CBC SPORT HD(46E) +F 00010201 01 1028ACE4EB4473A2 ;CBC SPORT HD(46E) +F 000103E9 00 002005250019566F ;1 TV Georgia (46.0E) +F 000103E9 01 002005250019566F ;1 TV Georgia (46.0E) +F 000B0835 00 0020050000195600 ;2 TV Georgia (46.0E) +F 000B0835 01 0020050000195600 ;2 TV Georgia (46.0E) +F 00010200 00 204710771089710A ;Region TV(46.0E) +F 00010200 01 204710771089710A ;Region TV(46.0E) +F 00010134 00 1234560065432100 ;AzTV Azerbaycan (46.0E) +F 00010134 01 1234560065432100 ;AzTV Azerbaycan (46.0E) +F 000B0198 00 345345CC345345CC ;Idman TV (46.0E) +F 000B0198 01 345345CC345345CC ;Idman TV (46.0E) +F 00070211 00 1234569C654321C9 ;Medeniyet TV (46.0E) +F 00070211 01 1234569C654321C9 ;Medeniyet TV (46.0E) +F 00031F9A 00 1212123612121236 ;ITV Azerbaycan (46.0E) +F 00031F9A 01 1212123612121236 ;ITV Azerbaycan (46.0E) +F 00020198 00 3453450034534500 ;Idman Azerbaycan (46.0E) +F 00020198 01 3453450034534500 ;Idman Azerbaycan (46.0E) +F 6D66006E 00 12345696543219 ;ZDF (46E) +F 6D66006E 01 12345696543219 ;ZDF (46E) + +F 02940295 00 54709155198649E8 ;TEST 1 (TV Center) (49E) +F 02940295 01 54709155198649E8 ;TEST 1 (TV Center) (49E) +F 05140135 00 0327022C106251C3 ;GTRK Ugoria (49E) +F 05140135 01 0327022C106251C3 ;GTRK Ugoria (49E) +F 00020135 00 0327022C106251C3 ;GTRK Region Tyumen (49E) +F 00020135 01 0327022C106251C3 ;GTRK Region Tyumen (49E) +F 00010198 00 0327022C106251C3 ;GTRK Pomorie (49E) +F 00010198 01 0327022C106251C3 ;GTRK Pomorie (49E) +F 00010200 00 0327022C106251C3 ;GTRK Karelija (49E) +F 00010200 01 0327022C106251C3 ;GTRK Karelija (49E) +F 00020201 00 0327022C106251C3 ;Rossiya 1 (0h) (49E) +F 00020201 01 0327022C106251C3 ;Rossiya 1 (0h) (49E) +F 00050204 00 0327022C106251C3 ;Rossiya 1 (+2h) (49E) +F 00050204 01 0327022C106251C3 ;Rossiya 1 (+2h) (49E) + +F 000C00C9 00 0000000000000100 ;Nash Dom (53E) +F 000C00C9 01 0000000000000100 ;Nash Dom (53E) +F 00060205 00 0327022C106251C3 ;Rossiya 1 (+4h) (53E) +F 00060205 01 0327022C106251C3 ;Rossiya 1 (+4h) (53E) +F 00020201 00 0327022C106251C3 ;Rossiya 1 (+6h) (53E) +F 00020201 01 0327022C106251C3 ;Rossiya 1 (+6h) (53E) +F 00050204 00 0327022C106251C3 ;Rossiya 1 (+8h) (53E) +F 00050204 01 0327022C106251C3 ;Rossiya 1 (+8h) (53E) + +F 00640066 00 2608396712043811 ;Match! TV (55.0E) +F 00640066 01 2608396712043811 ;Match! TV (55.0E) +F 01F401F6 00 0327022C106251C3 ;Rossia 1 (55.0E) +F 01F401F6 01 0327022C106251C3 ;Rossia 1 (55.0E) +F 00060259 00 62696E39676F7349 ;Lifestyle TV 6 (55E) +F 00060259 01 62696E39676F7349 ;Lifestyle TV 6 (55E) +F 000702BD 00 62696E39676F7349 ;Lifestyle TV 7 (55E) +F 000702BD 01 62696E39676F7349 ;Lifestyle TV 7 (55E) +F 000D0042 00 C12345006789AB00 ;STS (55E) +F 000D0042 01 C12345006789AB00 ;STS (55E) +F 00080036 00 ABC1238F45678935 ;Che (55E) +F 00080036 01 ABC1238F45678935 ;Che (55E) +F 000E002D 00 D12345006789AB00 ;Home (55E) +F 000E002D 01 D12345006789AB00 ;Home (55E) +F 000C002E 00 1234569C789ABCCE ;STS Love (55E) +F 000C002E 01 1234569C789ABCCE ;STS Love (55E) +F 0009003F 00 C12345006789AB00 ;STS +2 (55E) Disney+7h (90E) +F 0009003F 01 C12345006789AB00 ;STS +2 (55E) Disney+7h (90E) +F 000B0033 00 ABC1238F45678935 ;Che +2 (55E) +F 000B0033 01 ABC1238F45678935 ;Che +2 (55E) +F 000A002A 00 D12345006789AB00 ;Home +2 (55E) +F 000A002A 01 D12345006789AB00 ;Home +2 (55E) +F 00020026 00 6BA1E5F174BBCAF9 ;Disney +2 (55E) +F 00020026 01 6BA1E5F174BBCAF9 ;Disney +2 (55E) +F 00010065 00 62696E39676F7349 ;BB1 (55E) +F 00010065 01 62696E39676F7349 ;BB1 (55E) +F 000200C9 00 62696E39676F7349 ;BB2 (55E) +F 000200C9 01 62696E39676F7349 ;BB2 (55E) +F 0003012D 00 62696E39676F7349 ;BB3 (55E) +F 0003012D 01 62696E39676F7349 ;BB3 (55E) +F 00040191 00 62696E39676F7349 ;BB4 (55E) +F 00040191 01 62696E39676F7349 ;BB4 (55E) +F 000501F5 00 62696E39676F7349 ;BB5 (55E) +F 000501F5 01 62696E39676F7349 ;BB5 (55E) +F 00060259 00 169037DD278403AE ;Test1 (55E) +F 00060259 01 169037DD278403AE ;Test1 (55E) +F 000702BD 00 169037DD278403AE ;Test2 (55E) +F 000702BD 01 169037DD278403AE ;Test2 (55E) +F 00080321 00 169037DD278403AE ;Test3 (55E) +F 00080321 01 169037DD278403AE ;Test3 (55E) + +F 0001044C 00 1234569C7890ABB3 ;Armenian Public TV (60E) +F 0001044C 01 1234569C7890ABB3 ;Armenian Public TV (60E) +F 000204B0 00 1234569C7890ABB3 ;Shoghakat TV (60E) +F 000204B0 01 1234569C7890ABB3 ;Shoghakat TV (60E) +F 00030514 00 1234569C7890ABB3 ;Armenia TV Satellite (60E) +F 00030514 01 1234569C7890ABB3 ;Armenia TV Satellite (60E) +F 00040578 00 1234569C7890ABB3 ;Shant TV (60E) +F 00040578 01 1234569C7890ABB3 ;Shant TV (60E) +F 000505DC 00 1234569C7890ABB3 ;H2 (60E) +F 000505DC 01 1234569C7890ABB3 ;H2 (60E) +F 00060640 00 1234569C7890ABB3 ;Kentron (60E) +F 00060640 01 1234569C7890ABB3 ;Kentron (60E) +F 000706A4 00 1234569C7890ABB3 ;Yerkir Media (60E) +F 000706A4 01 1234569C7890ABB3 ;Yerkir Media (60E) +F 00080708 00 1234569C7890ABB3 ;RTR-Planeta (60E) +F 00080708 01 1234569C7890ABB3 ;RTR-Planeta (60E) + +#F 00010200 00 ;Stan Sport (68.5E) +#F 00010200 01 ;Stan Sport (68.5E) + +F 06400641 00 6BA1E5F174BBCAF9 ;Disney (75.0E) +F 06400641 01 6BA1E5F174BBCAF9 ;Disney (75.0E) +F 03840386 00 1234569C789ABCCE ;Mir Audio Service (75.0E) +F 03840386 01 1234569C789ABCCE ;Mir Audio Service (75.0E) + +F 05160CE6 00 0103050907090B1B ;Test_1302 +F 05160CE6 01 0103050907090B1B ;Test_1302 +F 04E61FFF 00 1212123612121236 ;Radio Kunel (85E) +F 04E61FFF 01 1212123612121236 ;Radio Kunel (85E) +F 057E0D4E 00 C12345006789AB00 ;STS +4 (85E) +F 057E0D4E 01 C12345006789AB00 ;STS +4 (85E) +F 05800D50 00 ABC1238F45678935 ;Peretz +4 (85E) +F 05800D50 01 ABC1238F45678935 ;Peretz +4 (85E) +F 057F0D4F 00 D12345006789AB00 ;Home +4 (85E) +F 057F0D4F 01 D12345006789AB00 ;Home +4 (85E) +F 051E0CEE 00 1234569C789ABCCE ; Love (85E) +F 051E0CEE 01 1234569C789ABCCE ; Love (85E) +F 0325070D 00 D12345006789AB00 ;Home 0 (85E) +F 0325070D 01 D12345006789AB00 ;Home 0 (85E) +F 0326070E 00 D12345006789AB00 ;Home 2 (85E) +F 0326070E 01 D12345006789AB00 ;Home 2 (85E) +F 00FB04E3 00 D12345006789AB00 ;Home -4 (85E) +F 00FB04E3 01 D12345006789AB00 ;Home -4 (85E) +F 00FC04E4 00 1234569C789ABCCE ;Home-R (85E) +F 00FC04E4 01 1234569C789ABCCE ;Home-R (85E) +F 00FB04E3 00 1234569C789ABCCE ;Home -7 (85E) +F 00FB04E3 01 1234569C789ABCCE ;Home -7 (85E) +F 03210709 00 C12345006789AB00 ;STS 0 (85E) +F 03210709 01 C12345006789AB00 ;STS 0 (85E) +F 0322070A 00 C12345006789AB00 ;STS 2 (85E) +F 0322070A 01 C12345006789AB00 ;STS 2 (85E) +F 0005003C 00 C12345006789AB00 ;STS +4 (85E) +F 0005003C 01 C12345006789AB00 ;STS +4 (85E) +F 00FA04E2 00 C12345006789AB00 ;STS -4 (85E) +F 00FA04E2 01 C12345006789AB00 ;STS -4 (85E) +F 0323070B 00 ABC1238F45678935 ;Peretz 0 (85E) +F 0323070B 01 ABC1238F45678935 ;Peretz 0 (85E) +F 0324070C 00 ABC1238F45678935 ;Peretz 2 (85E) +F 0324070C 01 ABC1238F45678935 ;Peretz 2 (85E) +F 00FD04E5 00 ABC1238F45678935 ;Perez -4 (85E) +F 00FD04E5 01 ABC1238F45678935 ;Perez -4 (85E) +F 0063044B 00 198313AF041983A0 ;Test-99 (85.1E) +F 0063044B 01 198313AF041983A0 ;Test-99 (85.1E) +F 03890771 00 BABABA2EBABABA2E ;Test Bryansk (85.1E) +F 03890771 01 BABABA2EBABABA2E ;Test Bryansk (85.1E) +F 04611FFF 00 1234560012345600 ;Mir Belogore radio (85.1E) +F 04611FFF 01 1234560012345600 ;Mir Belogore radio (85.1E) + +F 00010134 00 0327022C106251C3 ;GTRK Bira (90E) +F 00010134 01 0327022C106251C3 ;GTRK Bira (90E) +F 001102BD 00 2608396712043811 ;Rossia 2 (90E) +F 001102BD 01 2608396712043811 ;Rossia 2 (90E) +F 00010134 00 0327022C106251C3 ;GTRK Chita (90E) +F 00010134 01 0327022C106251C3 ;GTRK Chita (90E) +F 00010133 00 0327022C106251C3 ;GTRK Gorny Altai (90E) +F 00010133 01 0327022C106251C3 ;GTRK Gorny Altai (90E) +F 00010200 00 0327022C106251C3 ;GTRK Tver (90E) +F 00010200 01 0327022C106251C3 ;GTRK Tver (90E) +F 00010028 00 57081372163689D5 ;MUSIC BOX RU (90E) +F 00010028 01 57081372163689D5 ;MUSIC BOX RU (90E) +F 0002002B 00 3710468D3138036C ;MUSIC BOX TV (90E) +F 0002002B 01 3710468D3138036C ;MUSIC BOX TV (90E) +F 0007003C 00 C12345006789AB00 ;STS +4 (90E) +F 0007003C 01 C12345006789AB00 ;STS +4 (90E) +F 00090038 00 ABC1238F45678935 ;Che +4 (90E) +F 00090038 01 ABC1238F45678935 ;Che +4 (90E) +F 00080034 00 D12345006789AB00 ;Home +4(90E) +F 00080034 01 D12345006789AB00 ;Home +4(90E) +F 01B20022 00 1234569C789ABCCE ;STS Love+7 (90E) +F 01B20022 01 1234569C789ABCCE ;STS Love+7 (90E) +F 0007003E 00 6BA1E5F174BBCAF9 ;Disney +7 (90E) +F 0007003E 01 6BA1E5F174BBCAF9 ;Disney +7 (90E) +F 000A004E 00 C12345676789AB9B ;STS +7 (90E) +F 000A004E 01 C12345676789AB9B ;STS +7 (90E) +F 000F0051 00 ABC1238F45678935 ;Peretz +7 (90E) +F 000F0051 01 ABC1238F45678935 ;Peretz+7 (90E) +F 000C0055 00 D12345396789AB9B ;Home +7 (90E) +F 000C0055 01 D12345396789AB9B ;Home +7 (90E) +F 000D004A 00 5322017658567422 ;HUMOR TV (90E) +F 000D004A 01 5322017658567422 ;HUMOR TV (90E) +F 0004002B 00 A260696B7182988B ;Jug Don Tv (90E) +F 0004002B 01 A260696B7182988B ;Jug Don Tv (90E) +F 001111F9 00 40A73F262C34AE0E ;Test Am (90E) +F 001111F9 01 40A73F262C34AE0E ;Test Am (90E) +F 00120059 00 3901356F2673059E ;Football (90E) +F 00120059 01 3901356F2673059E ;Football (90E) +F 00090065 00 6BA1E5F174BBCAF9 ;Disney (+7h)(90E) 11265 30000 3/4 S2 +F 00090065 01 6BA1E5F174BBCAF9 ;Disney (+7h)(90E) 11265 30000 3/4 S2 +F 000A003C 00 C12345676789AB9B ;STS (+7h)(90E) 11265 30000 3/4 S2 +F 000A003C 01 C12345676789AB9B ;STS (+7h)(90E) 11265 30000 3/4 S2 +F 000B003F 00 ABC1238F45678935 ;Che+7(90E) 11265 30000 3/4 S2 +F 000B003F 01 ABC1238F45678935 ;Che+7(90E) 11265 30000 3/4 S2 +F 000C0043 00 D12345396789AB9B ;HOME+7(90E) 11265 30000 3/4 S2 +F 000C0043 01 D12345396789AB9B ;HOME+7(90E) 11265 30000 3/4 S2 +F 000D0046 00 3901350026730500 ;Football (90) 11265 30000 3/4 S2 +F 000D0046 01 3901350026730500 ;Football (90) 11265 30000 3/4 S2 + +F 00060205 00 0327022C106251C3 ;Dubl-3+RRD3 (96.5E) 3675 V 33483 +F 00060205 01 0327022C106251C3 ;Dubl-3+RRD3 (96.5E) 3675 V 33483 +F 00020201 00 0327022C106251C3 ;Rossiya 1 (+6h) (96.5E) 3875 V 33484 +F 00020201 01 0327022C106251C3 ;Rossiya 1 (+6h) (96.5E) 3875 V 33484 +F 00010580 00 0327022C106251C3 ;GTRK Novosibirsk (96.5E) 3758 V 4340 +F 00010580 01 0327022C106251C3 ;GTRK Novosibirsk (96.5E) 3758 V 4340 +F 00010134 00 0327022C106251C3 ;GTRK Altai (96.5E) 3817 V 4270 +F 00010134 01 0327022C106251C3 ;GTRK Altai (96.5E) 3817 V 4270 +F 00010060 00 0327022C106251C3 ;GTRK Tomsk (96.5E) 10979 H 3200 +F 00010060 01 0327022C106251C3 ;GTRK Tomsk (96.5E) 10979 H 3200 +F 00020201 00 0327022C106251C3 ;Dubl-2+RRD2 (96.5E) +F 00020201 01 0327022C106251C3 ;Dubl-2+RRD2 (96.5E) +F 00060205 00 0327022C106251C3 ;Dubl-3+RRD3 (96.5E) +F 00060205 01 0327022C106251C3 ;Dubl-3+RRD3 (96.5E) +F 00010580 00 0327022C106251C3 ;GTRK Novosibirsk (96.5E) +F 00010580 01 0327022C106251C3 ;GTRK Novosibirsk (96.5E) +F 00050204 00 0327022C106251C3 ;Rossiya 1 (+8h) (96.5E) +F 00050204 01 0327022C106251C3 ;Rossiya 1 (+8h) (96.5E) +F 00020201 00 0327022C106251C3 ;Rossiya 1 (+6h) (96.5E) +F 00020201 01 0327022C106251C3 ;Rossiya 1 (+6h) (96.5E) +F 00010134 00 0327022C106251C3 ;GTRK Krasnoyarsk (96.5E) +F 00010134 01 0327022C106251C3 ;GTRK Krasnoyarsk (96.5E) +F 00010060 00 0327022C106251C3 ;GTRK Tomsk (96.5E) +F 00010060 01 0327022C106251C3 ;GTRK Tomsk (96.5E) + +F 00020201 00 0327022C106251C3 ;Rossiya 1 (+6h) (103E) +F 00020201 01 0327022C106251C3 ;Rossiya 1 (+6h) (103E) +F 00050204 00 0327022C106251C3 ;Rossiya 1 (+8h) (103E) +F 00050204 01 0327022C106251C3 ;Rossiya 1 (+8h) (103E) + +F 00010134 00 0327022C106251C3 ;GTRK Magadan (140E) +F 00010134 01 0327022C106251C3 ;GTRK Magadan (140E) +F 00010100 00 0327022C106251C3 ;GTRK Amur (140E) +F 00010100 01 0327022C106251C3 ;GTRK Amur (140E) +F 00650134 00 0327022C106251C3 ;GTRK Kamchatka (140E) +F 00650134 01 0327022C106251C3 ;GTRK Kamchatka (140E) +F 00020204 00 0327022C106251C3 ;Rossiya 1 (+8h) (140E) +F 00020204 01 0327022C106251C3 ;Rossiya 1 (+8h) (140E) +F 00060201 00 0327022C106251C3 ;Rossiya 1 (+6h) (140E) +F 00060201 01 0327022C106251C3 ;Rossiya 1 (+6h) (140E) +F 000702BD 00 2608396712043811 ;Rossiya 2 (140E) +F 000702BD 01 2608396712043811 ;Rossiya 2 (140E) +F 00010201 00 0327022C106251C3 ;GTRK Sakhalin (140E) +F 00010201 01 0327022C106251C3 ;GTRK Sakhalin (140E) +F 033500DD 00 C12345676789AB9B ;STS (+7h) (140E) +F 033500DD 01 C12345676789AB9B ;STS (+7h) (140E) +F 033600DE 00 D12345396789AB9B ;Home (+7h) (140E) +F 033600DE 01 D12345396789AB9B ;Home (+7h) (140E) +F 033700DF 00 0327022C106251C3 ;Peretz (+7h) (140E) +F 033700DF 01 0327022C106251C3 ;Peretz (+7h) (140E) + +F 00010200 00 F34698D188513B14 ;ITA 473 ch1 & ITA 473 ch2 + New Freq 12715 H 7500 (5W) +F 00010200 01 F34698D188513B14 ;ITA 473 ch1 & ITA 473 ch2 + New Freq 12715 H 7500 (5W) +F 0065012D 00 3C4D5EE76F12AB2C ;Reversible Guadeloupe (5.0W) +F 0065012D 01 3C4D5EE76F12AB2C ;Reversible Guadeloupe (5.0W) + +F 12700213 00 1234569C789C3347 ;Dubai 33 (7.0W) +F 12700213 01 1234569C789C3347 ;Dubai 33 (7.0W) +F 000B044D 00 444333BA22211154 ;MBC Test 1 (7.0W) +F 000B044D 01 444333BA22211154 ;MBC Test 1 (7.0W) + +F 03850134 00 AB737C9A54D199BE ;Caribbean 901 (15.0W) +F 03850134 01 AB737C9A54D199BE ;Caribbean 901 (15.0W) +F 03860135 00 B86E4C72DD273E42 ;Syndication 902 (15.0W) +F 03860135 01 B86E4C72DD273E42 ;Syndication 902 (15.0W) + +F 000405B4 00 E876F04E8BA51141 ;EFB Ch.1 (24.5W) +F 000405B4 01 E876F04E8BA51141 ;EFB Ch.1 (24.5W) + +F 45401901 00 D581F94F24112D62 ;Channel 5 HD (27.5W) +F 45401901 01 D581F94F24112D62 ;Channel 5 HD (27.5W) +F 4F801D4D 00 D581F94F24112D62 ;Film 4+1 UK (27.5W) +F 4F801D4D 01 D581F94F24112D62 ;Film 4+1 UK (27.5W) +F 444017D5 00 D581F94F24112D62 ;BBC HD (27.5W) +F 444017D5 01 D581F94F24112D62 ;BBC HD (27.5W) +F 448419C9 00 D581F94F24112D62 ;BBC One HD (27.5W) +F 448419C9 01 D581F94F24112D62 ;BBC One HD (27.5W) +F 44C81839 00 D581F94F24112D62 ;ITV1 HD (27.5W) +F 44C81839 01 D581F94F24112D62 ;ITV1 HD (27.5W) +F 4500189D 00 D581F94F24112D62 ;Channel 4 HD (27.5W) +F 4500189D 01 D581F94F24112D62 ;Channel 4 HD (27.5W) +F 4CC01A2D 00 D581F94F24112D62 ;303 (27.5W) +F 4CC01A2D 01 D581F94F24112D62 ;303 (27.5W) +F 10440065 00 D581F94F24112D62 ;BBC ONE (27.5W) +F 10440065 01 D581F94F24112D62 ;BBC ONE (27.5W) +F 10BF00C9 00 D581F94F24112D62 ;BBC TWO (27.5W) +F 10BF00C9 01 D581F94F24112D62 ;BBC TWO (27.5W) +F 10C0012D 00 D581F94F24112D62 ;BBC THREE (27.5W) +F 10C0012D 01 D581F94F24112D62 ;BBC THREE (27.5W) +F 11C00191 00 D581F94F24112D62 ;BBC FOUR (27.5W) +F 11C00191 01 D581F94F24112D62 ;BBC FOUR (27.5W) +F 110001F5 00 D581F94F24112D62 ;BBC NEWS (27.5W) +F 110001F5 01 D581F94F24112D62 ;BBC NEWS (27.5W) +F 1200012D 00 D581F94F24112D62 ;CBBC (27.5W) +F 1200012D 01 D581F94F24112D62 ;CBBC (27.5W) +F 12400191 00 D581F94F24112D62 ;CBeebies (27.5W) +F 12400191 01 D581F94F24112D62 ;CBeebies (27.5W) +F 12800259 00 D581F94F24112D62 ;BBC Parliament (27.5W) +F 12800259 01 D581F94F24112D62 ;BBC Parliament (27.5W) +F 107D13ED 00 D581F94F24112D62 ;BBC ONE NI (27.5W) +F 107D13ED 01 D581F94F24112D62 ;BBC ONE NI (27.5W) +F 107C1005 00 D581F94F24112D62 ;BBC ONE Scot (27.5W) +F 107C1005 01 D581F94F24112D62 ;BBC ONE Scot (27.5W) +F 107E0C1D 00 D581F94F24112D62 ;BBC ONE Wales (27.5W) +F 107E0C1D 01 D581F94F24112D62 ;BBC ONE Wales (27.5W) +F 11401FFF 00 D581F94F24112D62 ;BBC Red Button (27.5W) +F 11401FFF 01 D581F94F24112D62 ;BBC Red Button (27.5W) + +F 00010101 00 383838A8383838A8 ;Agencia EFE (30W) +F 00010101 01 383838A8383838A8 ;Agencia EFE (30W) +F 001106A4 00 851267FE339412D9 ;RESUMEN 10 (30.0W) +F 001106A4 01 851267FE339412D9 ;RESUMEN 10 (30.0W) +F 01F40443 00 12481670326412A8 ;SD TVI Internacional (30.0W) +F 01F40443 01 12481670326412A8 ;SD TVI Internacional (30.0W +F 000707D7 00 F9E8D7B8C6B5A41F ;Fox Sports HD (30.0W) +F 000707D7 01 F9E8D7B8C6B5A41F ;Fox Sports HD (30.0W) +F 02BD1B63 00 383838A8383838A8 ;National Geographic HD (30.0W) +F 02BD1B63 01 383838A8383838A8 ;National Geographic HD (30.0W) +F 02BE1B6D 00 383838A8383838A8 ;National Geographic Portugal (30.0W) +F 02BE1B6D 01 383838A8383838A8 ;National Geographic Portugal (30.0W) +# ........................ +# ::::::::: CCW'S ::::::::: +#^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: MTV Portugal 9E CCW's ::::::: +F 06A50969 00 ;MTV Portugal (9E) +F 06A50969 01 ;MTV Portugal (9E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: FreeX TV/French Lover/XTSY ::::::: +F 128F1D7F 00 ; XTSY (13.0E) +F 128F1D7F 01 ; XTSY (13.0E) +F 08330FA2 00 ;Free-X TV (13.0E) +F 08330FA2 01 ;Free-X TV (13.0E) +F 08320FA1 00 ;French Lover TV (13.0E) +F 08320FA1 01 ;French Lover TV (13.0E) +# ::::::: PentHause HD 9E CCW's ::::::: +F 000A0026 00 ;Penthouse HD (9.0E) +F 000A0026 01 ;Penthouse HD (9.0E) +F 00140027 00 ;Penthouse HD 1 (9.0E) +F 00140027 01 ;Penthouse HD 1 (9.0E) +F 001E0028 00 ;Penthouse HD 2 (9.0E) +F 001E0028 01 ;Penthouse HD 2 (9.0E +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#:::::::: CSLink & SkyLink 23E CCW's :::::::: +F 23290640 00 ;FilmBox (23.5E) +F 23290640 01 ;FilmBox (23.5E) +F 232B0641 00 ;FilmBox Extra (23.5E) +F 232B0641 01 ;FilmBox Extra (23.5E) +F 13AE00B2 00 ;NatGeo Wild Hungary (23.5E) +F 13AE00B2 01 ;NatGeo Wild Hungary (23.5E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#:::::::: MTV Networks 13E CCW's ::::::: +F 000619D0 00 ;Viacom Blink! (13.0E) +F 000619D0 01 ;Viacom Blink! (13.0E) +F 00011B59 00 ;MTV Live HD (13.0E) +F 00011B59 01 ;MTV Live HD (13.0E) +F 000A184F 00 ;Comedy Central Polska (13.0E) +F 00071803 00 ;VH1 (13.0E) +F 00071803 01 ;VH1 (13.0E) +F 00041EE0 00 ;Comedy Central Family Polska (13.0E) +F 00041EE0 01 ;Comedy Central Family Polska (13.0E) +F 000A184F 01 ;Comedy Central Polska (13.0E) +F 000B1850 00 ;Nickeladeon Europe (13.0E) +F 000B1850 01 ;Nickeladeon Europe (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: MTV Network 19.2E CCW's ::::::: +F 70021790 00 ; MTV Pulse (19.2E) +F 70021790 01 ; MTV Pulse (19.2E) +F 70031791 00 ; MTV IDOL (19.2E) +F 70031791 01 ; MTV IDOL (19.2E) +F 6FFF1B59 00 ; MTV Music (19.2E) +F 6FFF1B59 01 ; MTV Music (19.2E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: HUSTLER HD-3D/Redlight Premium/Redlight 3D-HD +F 42231E21 00 ;Redlight Premium (13.0E) +F 42231E21 01 ;Redlight Premium (13.0E) +F 42241D74 00 ;Redlight 3D-HD (13.0E) +F 42241D74 01 ;Redlight 3D-HD (13.0E) +F 42251E0B 00 ;HUSTLER HD-3D (13.0E) +F 42251E0B 01 ;HUSTLER HD-3D (13.0E) +F 42251ECA 00 ;HUSTLER HD-3D (13.0E) +F 42251ECA 01 ;HUSTLER HD-3D (13.0E) +F 42251D60 00 ;HUSTLER HD-3D (13.0E) +F 42251D60 01 ;HUSTLER HD-3D (13.0E) +F 42251D5F 00 ;HUSTLER HD-3D (13.0E) +F 42251D5F 01 ;HUSTLER HD-3D (13.0E) +F 42251D55 00 ;HUSTLER HD-3D (13.0E) +F 42251D55 01 ;HUSTLER HD-3D (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: SSR/SRG Swiss (TSR/RSI LA/SF 13E CCW's ::::::: +F 433102CF 00 ; SF 1 HD (13.0E) +F 433102CF 01 ; SF 1 HD (13.0E) +F 433202CF 00 ; SF Zwei HD (13.0E) +F 433202CF 01 ; SF Zwei HD (13.0E) +F 433302CF 00 ; TSR 1 HD (13.0E) +F 433302CF 01 ; TSR 1 HD (13.0E) +F 433402CF 00 ; TSR 2 HD (13.0E) +F 433402CF 01 ; TSR 2 HD (13.0E) +F 36B202CE 00 ; TSR 1 (13.0E) +F 36B202CE 01 ; TSR 1 (13.0E) +F 36B302CE 00 ; TSI 1 (13.0E) +F 36B302CE 01 ; TSI 1 (13.0E) +F 36B802CE 00 ; TSR 2 (13.0E) +F 36B802CE 01 ; TSR 2 (13.0E) +F 36B902CE 00 ; TSI 2 (13.0E) +F 36B902CE 01 ; TSI 2 (13.0E) +F 36E302CE 00 ; RSI La 1 HD (13.0E) +F 36E302CE 01 ; RSI La 1 HD (13.0E) +F 038502CD 00 ; SF 1 (13.0E) +F 038502CD 01 ; SF 1 (13.0E) +F 038B02CD 00 ; SF 2 (13.0E) +F 038B02CD 01 ; SF 2 (13.0E) +F 038F02CD 00 ; SFI (13.0E) +F 038F02CD 01 ; SFI (13.0E) +F 03B702CD 00 ; RSI La 2 HD (13.0E) +F 03B702CD 01 ; RSI La 2 HD (13.0E) +F 03DE02CD 00 ; HD suisse (13.0E) +F 03DE02CD 01 ; HD suisse (13.0E) +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: Total TV (16.0E) CCW's ::::::: +F 032503B7 00 ;Fox Life (16.0E) +F 032503B7 01 ;Fox Life (16.0E) +F 032403B8 00 ;Fox Crime (16.0E) +F 032403B8 01 ;Fox Crime (16.0E) +F 032603B9 00 ;Nat Geographic (16.0E) +F 032603B9 01 ;Nat Geographic (16.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Baby Tv 13E CCW's Keys ::::::: +F 439D0807 00 ; BABY TV (13.0E) +F 439D0807 01 ; BABY TV (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# :::::: Raduga TV 75E CCW's ::::::: +F 012C0132 00 ;ESP Russian (75E) +F 012C0132 01 ;ESP Russian (75E) +F 01900196 00 ;ESP2 Russian (75E) +F 01900196 01 ;ESP2 Russian (75E) +F 012C0131 00 ;ESP Russian (75E) +F 012C0131 01 ;ESP Russian (75E) +F 01900195 00 ;ESP2 Russian (75E) +F 01900195 01 ;ESP2 Russian (75E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: AXN Adria CCW's :::::: +F 1AC21D51 00 ;AXN Adria (16E) +F 1AC21D51 01 ;AXN Adria (16E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: Dozhdj/NTV 4.9E/90.0E CCW's :::::: +F 010E010F 00 ;Dozhdj 4.9E +F 010E010F 01 ;Dozhdj 4.9E +F 000A0032 00 ;NTV 4.9E +F 000A0032 01 ;NTV 4.9E +F 02710270 00 ;Dozhdj 90.0E +F 02710270 01 ;Dozhdj 90.0E +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Telelombardia 13E CCW's +F 0E200269 00 ; Telelombardia (13.0E) +F 0E200269 01 ; Telelombardia (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: NSAB 5E CCW's ::::::: +F 19E619EF 00 ;Football (4.8E) +F 19E619EF 01 ;Football (4.8E) +F 1A041A0D 00 ;Football+ (4.8E) +F 1A041A0D 01 ;Football+ (4.8E) +F 17FC1805 00 ;Kanal Ukraina (4.8E) +F 17FC1805 01 ;Kanal Ukraina (4.8E) +F 19DC19E5 00 ;Ukraina (4.8E) +F 19DC19E5 01 ;Ukraina (4.8E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: EQUIDIA 13E CCW's ::::::: +F 043900 00 ;EQUIDIA PRO P1 13E +F 043900 01 ;EQUIDIA PRO P1 13E +F 043900 00 ;EQUIDIA PRO 13E +F 043900 01 ;EQUIDIA PRO 13E +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Sky Italia DCW Keys (13E) ::::::: +F 2FD20516 00 ;DMAX (13.0E) +F 2FD20516 01 ;DMAX (13.0E) +F 2FD3051C 00 ;Frisbee (13.0E) +F 2FD3051C 01 ;Frisbee (13.0E) +F 2FD4051F 00 ;Radio Capital Tv (13.0E) +F 2FD4051F 01 ;Radio Capital Tv (13.0E) +F 2FD50519 00 ;K2 (13.0E) +F 2FD50519 01 ;K2 (13.0E) +F 2FDE050D 00 ;Nick Junior +1 (13.0E) +F 2FDE050D 01 ;Nick Junior +1 (13.0E) +F 2FE0050A 00 ;AXN +1 (13.0E) +F 2FE0050A 01 ;AXN +1 (13.0E) +F 2FE704FC 00 ;GXT +1 (13.0E) +F 2FE704FC 01 ;GXT +1 (13.0E) +F 2FE804F8 00 ;Cartoon Network +1 (13.0E) +F 2FE804F8 01 ;Cartoon Network +1 (13.0E) +F 2FE904FF 00 ;Boomerang +1 (13.0E) +F 2FE904FF 01 ;Boomerang +1 (13.0E) +F 2FF00507 00 ;Comedy Central +1 (13.0E) +F 2FF00507 01 ;Comedy Central +1 (13.0E) +F 2FF104F9 00 ;Nickelodeon+1 (13.0E) +F 2FF104F9 01 ;Nickelodeon+1 (13.0E) +F 1FAC0532 00 ;Sky News International (13.0E) +F 1FAC0532 01 ;Sky News International (13.0E) +F 1FBF052C 00 ;Yacht & Sail (13.0E) +F 1FBF052C 01 ;Yacht & Sail (13.0E) +F 1FC90522 00 ;Cult Network Italia (13.0E) +F 1FC90522 01 ;Cult Network Italia (13.0E) +F 2DD9070A 00 ;Sky Sport 3 Italia (13.0E) +F 2DD9070A 01 ;Sky Sport 3 Italia (13.0E) +F 420F008D 00 ;Primocanale(13.0E) +F 420F008D 01 ;Primocanale(13.0E) +F 420B008B 00 ;TG Norba 24(13.0E) +F 420B008B 01 ;TG Norba 24(13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Daring Tv 13E CCW's ::::::: +F 43B317FF 00 ; Daring!TV (13.0E) +F 43B317FF 01 ; Daring!TV (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Trace Tropical HD 9E CCW's ::::::: +F 08CB09D5 00 ;Trace Tropical HD(9.0E) +F 08CB09D5 01 ;Trace Tropical HD(9.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Sky Box Office DCW Keys ::::::: +F 14AB0503 00 ;Sky Box Office(28.2E) +F 14AB0503 01 ;Sky Box Office(28.2E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: WDS Tv CCW's ::::::: +F 01F50553 00 ;WDS TV (100E) +F 01F50553 01 ;WDS TV (100E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: MTV Trax CCW's ::::::: +F 1B6D050B 00 ; MTV Trax (28.2E) +F 1B6D050B 01 ; MTV Trax (28.2E) +#::::::: Sky Sport Active CCW's ::::::::::: +F 152305C8 00 ;1381 (28.2E) +F 152305C8 01 ;1381 (28.2E) +F 152405C8 00 ;1382 (28.2E) +F 152405C8 01 ;1382 (28.2E) +F 152505C8 00 ;1383 (28.2E) +F 152505C8 01 ;1383 (28.2E) +F 152605C8 00 ;1384 (28.2E) +F 152605C8 01 ;1384 (28.2E) +F 152705C8 00 ;1385 (28.2E) +F 152705C8 01 ;1385 (28.2E) +F 152805C8 00 ;1386 (28.2E) +F 152805C8 01 ;1386 (28.2E) +F 156905C8 00 ;1481 (28.2E) +F 156905C8 01 ;1481 (28.2E) +F 156A05C8 00 ;1482 (28.2E) +F 156A05C8 01 ;1482 (28.2E) +F 156B05C8 00 ;1483 (28.2E) +F 156B05C8 01 ;1483 (28.2E) +F 156C05C8 00 ;1484 (28.2E) +F 156C05C8 01 ;1484 (28.2E) +F 156D05C8 00 ;1485 (28.2E) +F 156D05C8 01 ;1485 (28.2E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Private Spice 13.0E CCW's ::::::: +F 125102B3 00 ;Private Spice (13.0E) +F 125102B3 01 ;Private Spice (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: 19E CCW's ::::::: +F 0FA20565 00 ; SBS6 (19.2E) +F 0FA20565 01 ; SBS6 (19.2E) +F 0FA30566 00 ; NE5 (19.2E) +F 0FA30566 01 ; NE5 (19.2E) +F 0FAB0567 00 ; NED1 (19.2E) +F 0FAB0567 01 ; NED1 (19.2E) +F 0FAC0568 00 ; NED2 (19.2E) +F 0FAC0568 01 ; NED2 (19.2E) +F 0FAD0569 00 ; NED3 (19.2E) +F 0FAD0569 01 ; NED3 (19.2E) +#.......................... +# ::::::: Canal Sat 19.2E +F 7A4D0BD9 00 ;L'Equipe 21 (19.2E) +F 7A4D0BD9 01 ;L'Equipe 21 (19.2E) +F 24BF19AC 00 ;M6 Music Hits(19.2E) +F 24BF19AC 01 ;M6 Music Hits(19.2E) +F 24BD1998 00 ;Cinecinema Star(19.2E) +F 24BD1998 01 ;Cinecinema Star(19.2E) +F 24C01A1A 00 ;Discovery Channel France(19.2E) +F 24C01A1A 01 ;Discovery Channel France(19.2E) +F 24BC19F2 00 ;InfoSport(19.2E) +F 24BC19F2 01 ;InfoSport(19.2E) +F 24C119C1 00 ;Pink TV(19.2E) +F 24C119C1 01 ;Pink TV(19.2E) +F 24BA19DF 00 ;Se'rie Club(19.2E) +F 24BA19DF 01 ;Se'rie Club(19.2E) +F 24BE1A06 00 ;Te'le'toon(19.2E) +F 24BE1A06 01 ;Te'le'toon(19.2E) +F 24C21A9C 00 ;Te'le'toon +1(19.2E) +F 24C21A9C 01 ;Te'le'toon +1(19.2E) +F 24B91971 00 ;TPS Star(19.2E) +F 24B91971 01 ;TPS Star(19.2E) +F 6FF1191A 00 ;VH1 Classic 19.2E +F 6FF1191A 01 ;VH1 Classic 19.2E +F 6FF7180A 00 ;Game One 19.2E +F 6FF7180A 01 ;Game One 19.2E +F 6FFC180C 00 ;Nickelodeon France 19.2E +F 6FFC180C 01 ;Nickelodeon France 19.2E +F 6FFF19B2 00 ;VH1 Europe 19.2E +F 6FFF19B2 01 ;VH1 Europe 19.2E +F 6FF317B1 00 ;MTV Rocks 19.2E +F 6FF317B1 01 ;MTV Rocks 19.2E +F 6FEF190D 00 ;MTV Dance 19.2E +F 6FEF190D 01 ;MTV Dance 19.2E +F 6FEC1806 00 ;MTV France 19.2E +F 6FEC1806 01 ;MTV France 19.2E +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: Weddeng Tv and Deepam Tv 13E CCW's ::::::: +F 12350295 00 ;Wedding TV (13.0E) +F 12350295 01 ;Wedding TV (13.0E) +F 11FE0263 00 ;Deepam TV (13.0E) +F 11FE0263 01 ;Deepam TV (13.0E) +#............................... +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: SIC 16E CCW's +F 000103E9 00 ;SIC Internacional (16E) by Serjoga latvia +F 000103E9 01 ;SIC Internacional (16E) by Serjoga latvia +#.................................. +#^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Dorcel TV 13.0E CCW's ::::::: +F 227B1216 00 ;Dorcel TV (13.0E) +F 227B1216 01 ;Dorcel TV (13.0E) +F 2288121B 00 ;Dorcel TV (13.0E) +F 2288121B 01 ;Dorcel TV (13.0E) +F 37860B75 00 ;DorcelTV (13.0E) +F 37860B75 01 ;DorcelTV (13.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#............................................... +# ::::::: Nat Geo HD UK 16.0E CCW's ::::::: +F 03E91BCC 00 ;Nat Geo HD UK (16.0E) by Serjoga latvia +F 03E91BCC 01 ;Nat Geo HD UK (16.0E) by Serjoga latvia +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ..................................................... +# ::::::: HAYAT TV SAT/HAYAT TV BIH 16.0E CCW's ::::::: +F 00010065 00 ;HAYAT TV BIH (16.0E) +F 00010065 01 ;HAYAT TV BIH (16.0E) +F 00020064 00 ;HAYAT PLUS (16.0E) +F 00020064 01 ;HAYAT PLUS (16.0E) +F 00030064 00 ;Hayat Folk TV (16.0E) +F 00030064 01 ;Hayat Folk TV (16.0E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Hustler Tv 19.2E CCW's +F 07FA05AA 00 ;Hustler TV viaccess (19.2E) +F 07FA05AA 01 ;Hustler TV viaccess (19.2E) +F 07FA05AA 00 ;Hustler TV seca (19.2E) +F 07FA05AA 01 ;Hustler TV seca (19.2E) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +#::::::: Trace TV 13.0E CCW's ::::::: +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +F 13F10AF5 00 ;Trace TV (13.0E) +F 13F10AF5 01 ;Trace TV (13.0E) +#.......................... +#::::::: SciFi & Universal CCWs +F 3A351B9E 00 ;UNIVERSAL (13.0E) +F 3A351B9E 01 ;UNIVERSAL (13.0E) +F 3A361B9F 00 ;SCi Fi (13.0E) +F 3A361B9F 01 ;SCi Fi (13.0E) +F 3A34057B 00 ;Sport Klub (13.0E) +F 3A34057B 01 ;Sport Klub (13.0E) +#........................ +#::::::: CONTO TV CCW's::::::: +#^^^^^^^^^^^^^^^^^^^^^^^^^ +F 20EC0518 00 ;CONTO TV 2 (13.0E) +F 20EC0518 01 ;CONTO TV 2 (13.0E) +F 20EF0524 00 ;CONTO TV 4 +F 20EF0524 01 ;CONTO TV 4 +#............................... +#::::::: RTVI CCW's ::::::: +#^^^^^^^^^^^^^^^^^^^^^^^^ +F 39D20399 00 ; RTVi Europe (13.0E) +F 39D20399 01 ; RTVi Europe (13.0E) +F 39D3039B 00 ; RTVi Detskii Mir (13.0E) +F 39D3039B 01 ; RTVi Detskii Mir (13.0E) +F 39D4039A 00 ; RTVi Nashe Kino (13.0E) +F 39D4039A 01 ; RTVi Nashe Kino (13.0E) +#................................ +#::::::: Satisfaction TV CCW's ::::::: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +F 35D81777 00 ;Pink O TV (13E) +F 35D81777 01 ;Pink O TV (13E) +F 35C10542 00 ;Extocica TV (13E) +F 35C10542 01 ;Extocica TV (13E) +F 35C80548 00 ;PassionXXX (13E) +F 35C80548 01 ;PassionXXX (13E) +F 35C30545 00 ;SCT (13E) +F 35C30545 01 ;SCT (13E) +F 000A0549 00 ;SCT HD (13E) +F 000A0549 01 ;SCT HD (13E) +F 35C60546 00 ;CentoxCento (13E) +F 35C60546 01 ;CentoxCento (13E) +F 35C70547 00 ;Sesto Senso TV (13E) +F 35C70547 01 ;Sesto Senso TV (13E) +F 35C00541 00 ;TGirls TV (13E) +F 35C00541 01 ;TGirls TV (13E) +#........................................ +#::::::: Belgium Package CCW's 13E ::::::: +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +F 362F16BD 00 ;La Une (13.0E) +F 362F16BD 01 ;La Une (13.0E) +F 363016BE 00 ;La Deux (13.0E) +F 363016BE 01 ;La Deux (13.0E) +F 363116BF 00 ;RTL-TVi (13.0E) +F 363116BF 01 ;RTL-TVi (13.0E) +F 363216C0 00 ;Club-RTL (13.0E) +F 363216C0 01 ;Club-RTL (13.0E) +F 363316C1 00 ;Plug-RTL (13.0E) +F 39D4039A 01 ;Plug-RTL (13.0E) +F 363416C2 00 ;Disney Channel (13.0E) +F 39D4039A 01 ;Disney Channel (13.0E) +#....................................... +#::::::: JSC SPORT CCW's ::::::: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +F 20F514B8 00 ; JSC Sports +1 (13.0E) +F 20F514B8 01 ; JSC Sports +1 (13.0E) +F 20F61648 00 ; JSC Sports +2 (13.0E) +F 20F61648 01 ; JSC Sports +2 (13.0E) +F 20F71710 00 ; JSC Sports +3 (13.0E) +F 20F71710 01 ; JSC Sports +3 (13.0E) +F 20F817D8 00 ; JSC Sports +4 (13.0E) +F 20F817D8 01 ; JSC Sports +4 (13.0E) +F 20F9183C 00 ; JSC Sports +5 (13.0E) +F 20F9183C 01 ; JSC Sports +5 (13.0E) +F 20FA18A0 00 ; JSC Sports +6 (13.0E) +F 20FA18A0 01 ; JSC Sports +6 (13.0E) +F 20FB1904 00 ; JSC Sports +7 (13.0E) +F 20FB1904 01 ; JSC Sports +7 (13.0E) +F 20FC1968 00 ; JSC Sports +8 (13.0E) +F 20FC1968 01 ; JSC Sports +8 (13.0E) +F 20FD19CC 00 ; JSC Sports +9 (13.0E) +F 20FD19CC 01 ; JSC Sports +9 (13.0E) +F 20FE1A30 00 ; JSC Sports +10 (13.0E) +F 20FE1A30 01 ; JSC Sports +10 (13.0E) +F 20FF1AC7 00 ; JSC World Cup (13.0E) +F 20FF1AC7 01 ; JSC World Cup (13.0E) +#........................................... +#::::::: Rai/Tivusat 13E CCW's +F 0D491081 00 ;Rai HD (13.0E) +F 0D491081 01 ;Rai HD (13.0E) +F 0D4B1083 00 ;Rai 3 TGR FVG (13.0E) +F 0D4B1083 01 ;Rai 3 TGR FVG (13.0E) +F 0D521087 00 ;Rai 5 (13.0E) +F 0D521087 01 ;Rai 5 (13.0E) +F 0D661088 00 ;Rai yoyo (13.0E) +F 0D661088 01 ;Rai yoyo (13.0E) +#............................................. +#::::::: TV Globo 13E CCW's ::::::: +F 34D61F40 00 ;TV Globo (13.0E) +F 34D61F40 01 ;TV Globo (13.0E) +#............................................. +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Nick Jr. 13E CCW's::::::: +F 001E0326 00 (13.0E) +F 001E0326 01 (13.0E) +#.............................................. +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: AustriaSat/HD+ CCW's::::::: +F 15191C9E 00 ;Tele 5 HD (19.2E) +F 15191C9E 01 ;Tele 5 HD (19.2E) +F 157F1AE2 00 ;Deluxe Music HD (19.2E) +F 157F1AE2 01 ;Deluxe Music HD (19.2E) +F 52741AC2 00 ;N24 HD (19.2E) +F 52741AC2 01 ;N24 HD (19.2E) +F 14B51AEC 00 ;ProSieben HD (19.2E) +F 14B51AEC 01 ;ProSieben HD (19.2E) +F 52731AC0 00 ;NICH/CC HD (19.2E) +F 52731AC0 01 ;NICH/CC HD (19.2E) +# .................................................. +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: Overon/M7 (SkyLink/CSLink) 23.5E CCW's ::::::: +F 02C5044D 00 ;NatGeo Wild HD DUT (23.5E) +F 02C5044D 01 ;NatGeo Wild HD DUT (23.5E) +F 02C71BC7 00 ;M1 - Magyar TV (23.5E) +F 02C71BC7 01 ;M1 - Magyar TV (23.5E) +F 02C91BDB 00 ;Duna TV (23.5E) +F 02C91BDB 01 ;Duna TV (23.5E) +F 02CA1BE5 00 ;Duna World (23.5E) +F 02CA1BE5 01 ;Duna World (23.5E) +F 02CB1BEF 00 ;RTL Klub (23.5E) +F 02CB1BEF 01 ;RTL Klub (23.5E) +F 02CC1BF9 00 ;TV 2 (Hungary) (23.5E) +F 02CC1BF9 01 ;TV 2 (Hungary) (23.5E) +F 02CD1C03 00 ;Hir TV (23.5E) +F 02CD1C03 01 ;Hir TV (23.5E) +F 02CE1C0D 00 ;Magyar ATV (23.5E) +F 02CE1C0D 01 ;Magyar ATV (23.5E) +F 02CF1C17 00 ;Nota TV (23.5E) +F 02CF1C17 01 ;Nota TV (23.5E) +F 02D01C21 00 ;4!Story TV (23.5E) +F 02D01C21 01 ;4!Story TV (23.5E) +F 02D21C35 00 ;Viasat 3 (23.5E) +F 02D21C35 01 ;Viasat 3 (23.5E) +F 02D31C3F 00 ;RTL 2 Hungary (23.5E) +F 02D31C3F 01 ;RTL 2 Hungary (23.5E) +F 02D41C49 00 ;Super TV 2 (23.5E) +F 02D41C49 01 ;Super TV 2 (23.5E) +F 02D51C53 00 ;SportKlub (23.5E) +F 02D51C53 01 ;SportKlub (23.5E) +F 02D61C5D 00 ;Sport 1 Hungary (23.5E) +F 02D61C5D 01 ;Sport 1 Hungary (23.5E) +F 02D71C67 00 ;Cool TV (23.5E) +F 02D71C67 01 ;Cool TV (23.5E) +F 02D81C71 00 ;Digi Sport Hungary (23.5E) +F 02D81C71 01 ;Digi Sport Hungary (23.5E) +F 02D91C7B 00 ;Comedy Central Hungary (23.5E) +F 02D91C7B 01 ;Comedy Central Hungary (23.5E) +F 02DA1C85 00 ;Discovery Channel Hungary (23.5E) +F 02DA1C85 01 ;Discovery Channel Hungary (23.5E) +F 02DB1C8F 00 ;Sport 2 Hungary (23.5E) +F 02DB1C8F 01 ;Sport 2 Hungary (23.5E) +F 02DC1C99 00 ;FEM3 (23.5E) +F 02DC1C99 01 ;FEM3 (23.5E) +F 02F9044D 00 ;NatGeo Wild HD (23.5E) +F 02F9044D 01 ;NatGeo Wild HD (23.5E) +F 15EB044D 00 ;NatGeo Wild HD CZ (23.5E) +F 15EB044D 01 ;NatGeo Wild HD CZ (23.5E) +# ........................................................... +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: BFBS 10E CCW's ::::::: +F 1F490BC1 00 ;09 BBC One Delay (10.0E) +F 1F490BC1 01 ;09 BBC One Delay (10.0E) +F 1F420BBA 00 ;02 BBC Two (10.0E) +F 1F420BBA 01 ;02 BBC Two (10.0E) +F 1F440BBC 00 ;04 BFBS Extra (10.0E) +F 1F440BBC 01 ;04 BFBS Extra (10.0E) +F 1F470BBF 00 ;07 BFBS Sport (10.0E) +F 1F470BBF 01 ;07 BFBS Sport (10.0E) +F 1F450BBD 00 ;05 Sky Sports 1 (10.0E) +F 1F450BBD 01 ;05 Sky Sports 1 (10.0E) +F 1F460BBE 00 ;Sky Sports 2) (10.0E) +F 1F460BBE 01 ;Sky Sports 2) (10.0E) +F 1F480BC0 00 ;08 Sky News (10.0E) +F 1F480BC0 01 ;08 Sky News (10.0E) +# ........................................................... +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# ::::::: TRING TV 16.0E CCWs ::::::: +F 00320037 00 ;JOLLY HD (16.0E) +F 00320037 01 ;JOLLY HD (16.0E) +F 00070A32 00 ;RTV21 (16.0E) +F 00070A32 01 ;RTV21 (16.0E) +F 0C260C2A 00 ;RTV21 PLUS (16.0E) +F 0C260C2A 01 ;RTV21 PLUS (16.0E) +F 003C0041 00 ;BBF (16.0E) +F 003C0041 01 ;BBF (16.0E) +F 08D40A46 00 ;TRING FANTASY (16.0E) +F 08D40A46 01 ;TRING FANTASY (16.0E) +F 00461004 00 ;TRING HISTORY (16.0E) +F 00461004 01 ;TRING HISTORY (16.0E) +F 038A0775 00 ;Fox Life (16.0E) +F 038A0775 01 ;Fox Life (16.0E) +F 00501068 00 ;LIVING (16.0E) +F 00501068 01 ;LIVING (16.0E) +F 005E07CA 00 ;Agon Channel (16.0E) +F 005E07CA 01 ;Agon Channel (16.0E) + +F 3B630517 00 ;Eurosport 2 HD (13.0E) +F 3B630517 01 ;Eurosport 2 HD (13.0E) + +F 363B1421 00 ;ESP2 NE (13.0E) +F 363B1421 01 ;ESP2 NE (13.0E) + +F 32CA012E 00 ;ORF2 (19.2E) +F 32CA012E 01 ;ORF2 (19.2E) + +# ::::::: BeiN Sports 19.2E CCWs ::::::: + +F 189D0BD7 00 ;BeIN Sport 1 HD (19.2E) +F 189D0BD7 01 ;BeIN Sport 1 HD (19.2E) +F 189E0BD8 00 ;BeIN Sport 2 HD (19.2E) +F 189E0BD8 01 ;BeIN Sport 2 HD (19.2E) +F 18A00BDA 00 ;BeIN Sport 3 HD (19.2E) +F 18A00BDA 01 ;BeIN Sport 3 HD (19.2E) + +# ::::::: FilBox 42E CCWs ::::::: + +F 3EE61966 00 50CCA6C21AF69BAB ;Fightbox HD (42.0E) +F 3EE61966 01 50CCA6C21AF69BAB ;Fightbox HD (42.0E) +F 3EEA196A 00 3D8B26EEDEB7861B ;DaVinci Learning (42.0E) +F 3EEA196A 01 3D8B26EEDEB7861B ;DaVinci Learning (42.0E) + +# ::::::: Pershiy Avtomobilniy (1 Auto) 4Ws ::::::: + +F 000B1111 00 ;Pershiy Avtomobilniy (1 Auto) (4W) +F 000B1111 01 ;Pershiy Avtomobilniy (1 Auto) (4W ) + + +# :::::::::: sat-life.info ::::::::::::::: +# <><><><><> by Serjoga latvia <><><><><><> diff --git a/package/lean/dvb/oscam/files/oscam.conf b/package/lean/dvb/oscam/files/oscam.conf new file mode 100755 index 0000000000..7305dab931 --- /dev/null +++ b/package/lean/dvb/oscam/files/oscam.conf @@ -0,0 +1,43 @@ +# oscam.conf generated automatically by Streamboard OSCAM 1.20-unstable_svn SVN r11390 +# Read more: http://www.streamboard.tv/svn/oscam/trunk/Distribution/doc/txt/oscam.conf.txt + +[global] +logfile = /var/log/oscam/oscam.log +nice = 0 +maxlogsize = 1000 +preferlocalcards = 1 + +[cache] + +[cccam] +port = 12000 +nodeid = AC2D31EE10E41520 +version = 2.1.1 +reshare = 1 +ignorereshare = 1 +stealth = 1 + +[streamrelay] + +[dvbapi] +enabled = 1 +au = 1 +pmt_mode = 4 +request_mode = 1 +listen_port = 9000 +delayer = 80 +user = TVH +boxtype = pc + +[webif] +httpport = 8888 +httpuser = oscam +httppwd = oscam +httpshowmeminfo = 1 +httpshowuserinfo = 1 +httpshowecminfo = 1 +httpshowloadinfo = 1 +httpallowed = 0.0.0.0-255.255.255.255 +aulow = 120 +httputf8 = 1 + diff --git a/package/lean/dvb/oscam/files/oscam.dvbapi b/package/lean/dvb/oscam/files/oscam.dvbapi new file mode 100644 index 0000000000..68fc1c0275 --- /dev/null +++ b/package/lean/dvb/oscam/files/oscam.dvbapi @@ -0,0 +1,31 @@ +P: 0500:040620 # NTV+ (36Е) +P: 0500:041200 # NTV+ (36Е) +P: 0500:060A00 # NTV+ (36E) +P: 0500:060C00 # NTV+ (36E) +P: 0500:023100 # trk football (Shara)(5Е) +P: 0500:041200 # trk football (Shara)(5Е) +P: 0500:041700 # Dorcel TV (13Е) +P: 0500:042300 # rtvi (13Е) +P: 0500:042700 # SCT, S1-7-HQ,HD (13Е) +P: 0500:042800 # Absat/BisTV (13Е) +P: 0500:043800 # REDLIGHT HD, Redlight Premium & Daring! TV (13Е) +P: 0100:000068 # Cyfra+ 13e +P: 09CD:0 # Sky 13e +P: 1803:007001 # Polsat (13Е) +P: 1803:007101 # Polsat (13Е) +P: 1803:000000 # Polsat (13Е) +P: 090D:0 # yes 4w +P: 090F:0 # viasat baltic 5e + +# EMU +P: 2600:000000 # BISS +P: 0500:023800 # srg (EMU)(13Е) +P: 0E00:000000 # PowerVU +P: 0500:007400 +P: 0D00:000000 +P: 0D05:000000 +P: 0D02:000000 +P: 1801:000000 + +# Ignor +I:0 diff --git a/package/lean/dvb/oscam/files/oscam.init b/package/lean/dvb/oscam/files/oscam.init new file mode 100755 index 0000000000..90f38202e9 --- /dev/null +++ b/package/lean/dvb/oscam/files/oscam.init @@ -0,0 +1,23 @@ +#!/bin/sh /etc/rc.common + +START=99 +OSCAM_PATH=/usr/bin + +[ -f /tmp/oscam ] && +{ + OSCAM_PATH=/tmp + [ -x /tmp/oscam ] || chmod +x /tmp/oscam +} + +start() { + logger "Starting Oscam" + [ -d /var/log/oscam ] || mkdir -p /var/log/oscam + service_start ${OSCAM_PATH}/oscam -b -r 2 -u +} + +stop() { + logger "Stopping Oscam" + service_stop ${OSCAM_PATH}/oscam -b -r 2 -u +} + + diff --git a/package/lean/dvb/oscam/files/oscam.server b/package/lean/dvb/oscam/files/oscam.server new file mode 100644 index 0000000000..fb6b220cb2 --- /dev/null +++ b/package/lean/dvb/oscam/files/oscam.server @@ -0,0 +1,61 @@ +# oscam.server generated automatically by Streamboard OSCAM 1.20-unstable_svn SVN r11401 +# Read more: http://www.streamboard.tv/svn/oscam/trunk/Distribution/doc/txt/oscam.server.txt + +[reader] +label = emulator +protocol = emu +device = emulator +caid = 0D00,0D02,090F,0500,1801,0604,2600,FFFF,0E00 +detect = cd +ident = 0D00:000000,000004,000010,000014,000020,0000C0,0000C4,0000C8,0000CC;0D02:000000,00008C,0000A0,0000A4,0000A8;090F:000000;0500:000000,030B00,023800,021110,007400,007800;1801:000000,007301,001101;0604:000000;2600:000000;FFFF:000000;0E00:000000 +group = 1 +emmcache = 2,3,2,0 +emu_auproviders = 0500:030B00;0604:010200;0E00:000000 + +# Example for NTV+, all disable + +[reader] +label = reshare1 +description = TVShara1 +enable = 0 +protocol = cccam +device = s4.oscam.org,444 +user = test1 +password = test1 +inactivitytimeout = 200 +reconnecttimeout = 10 +caid = 0500 +group = 1 +cccversion = 2.3.0 +cccreshare = 1 + +[reader] +label = reshare2 +description = TVShara2 +enable = 0 +protocol = newcamd +device = s4.oscam.org,2004 +key = 0102030405060708091011121314 +user = test2 +password = test2 +inactivitytimeout = 200 +reconnecttimeout = 10 +connectoninit = 1 +caid = 0500 +ident = 0500:060A00,041200,060C00,040620 +group = 1 +cccreshare = 1 + +[reader] +label = reshare3 +description = TVShara3 +enable = 0 +protocol = cs357x +device = s4.oscam.org,333 +user = test3 +password = test3 +caid = 0500 +ident = 0500:060A00,041200,060C00,040620 +group = 1 +cccreshare = 1 + diff --git a/package/lean/dvb/oscam/files/oscam.user b/package/lean/dvb/oscam/files/oscam.user new file mode 100644 index 0000000000..5e02dd83e3 --- /dev/null +++ b/package/lean/dvb/oscam/files/oscam.user @@ -0,0 +1,27 @@ +# oscam.user generated automatically by Streamboard OSCAM 1.20-unstable_svn SVN r11401 +# Read more: http://www.streamboard.tv/svn/oscam/trunk/Distribution/doc/txt/oscam.user.txt + +[account] +user = tvheadend_x +pwd = tvheadend_x +monlevel = 4 +au = 1 +group = 1 +max_connections = 100 +cccreshare = 1 + +[account] +user = user1 +pwd = user1 +monlevel = 4 +au = 1 +group = 1 +max_connections = 100 +cccreshare = 1 + +[account] +user = monitor +pwd = monitor +monlevel = 4 +group = 1 + diff --git a/package/lean/dvb/oscam/patches/002-config.patch b/package/lean/dvb/oscam/patches/002-config.patch new file mode 100644 index 0000000000..4131221770 --- /dev/null +++ b/package/lean/dvb/oscam/patches/002-config.patch @@ -0,0 +1,41 @@ +diff -ruNp trunk.orig/config.h trunk/config.h +--- trunk.orig/config.h 2018-03-25 14:31:53.147349681 +0300 ++++ trunk/config.h 2018-03-25 14:46:42.842348711 +0300 +@@ -22,7 +22,7 @@ + //#define IPV6SUPPORT 1 + #define MODULE_MONITOR 1 + +-//#define MODULE_CAMD33 1 ++#define MODULE_CAMD33 1 + #define MODULE_CAMD35 1 + #define MODULE_CAMD35_TCP 1 + #define MODULE_NEWCAMD 1 +@@ -62,10 +62,14 @@ + #define CARDREADER_STINGER 1 + #define CARDREADER_DRECAS 1 + ++#define WITH_PCSC 1 ++ + #ifdef WITH_PCSC + #define CARDREADER_PCSC 1 + #endif + ++#define WITH_LIBUSB 1 ++ + #ifdef WITH_LIBUSB + #define CARDREADER_SMART 1 + #endif +@@ -83,11 +87,11 @@ + #endif + + #ifdef WITH_STAPI +-#define CARDREADER_STAPI 1 ++//#define CARDREADER_STAPI 1 + #endif + + #ifdef WITH_STAPI5 +-#define CARDREADER_STAPI5 1 ++//#define CARDREADER_STAPI5 1 + #endif + + #ifdef READER_DRE diff --git a/package/lean/dvb/oscam/patches/003-fix_ver.patch b/package/lean/dvb/oscam/patches/003-fix_ver.patch new file mode 100644 index 0000000000..fa15519521 --- /dev/null +++ b/package/lean/dvb/oscam/patches/003-fix_ver.patch @@ -0,0 +1,121 @@ +diff -ruNp trunk.patches/globals.h trunk/globals.h +--- trunk.patches/globals.h 2018-04-03 02:48:24.952386413 +0300 ++++ trunk/globals.h 2018-04-03 03:02:59.558440627 +0300 +@@ -365,6 +365,9 @@ typedef unsigned char uchar; + #ifndef CS_SVN_VERSION + # define CS_SVN_VERSION "test" + #endif ++#ifndef CS_EMU_VERSION ++# define CS_EMU_VERSION "000" ++#endif + #ifndef CS_TARGET + # define CS_TARGET "unknown" + #endif +diff -ruNp trunk.patches/Makefile trunk/Makefile +--- trunk.patches/Makefile 2018-04-03 02:44:08.318254054 +0300 ++++ trunk/Makefile 2018-04-03 03:01:12.325689204 +0300 +@@ -5,7 +5,8 @@ SHELL = /bin/sh + .PHONY: all tests help README.build README.config simple default debug config menuconfig allyesconfig allnoconfig defconfig clean distclean + + VER := $(shell ./config.sh --oscam-version) +-SVN_REV := $(shell ./config.sh --oscam-revision) ++#SVN_REV := $(shell ./config.sh --oscam-revision) ++#EMU_REV := 000 + + uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') + +@@ -35,7 +36,7 @@ ifdef USE_SSL + override USE_LIBCRYPTO=1 + endif + +-CONF_DIR = /usr/local/etc ++CONF_DIR = /opt/etc/oscam + + LIB_PTHREAD = -lpthread + LIB_DL = -ldl +@@ -52,6 +53,7 @@ endif + + override STD_LIBS := $(LIB_PTHREAD) $(LIB_DL) $(LIB_RT) + override STD_DEFS := -D'CS_SVN_VERSION="$(SVN_REV)"' ++override STD_DEFS += -D'CS_EMU_VERSION="$(EMU_REV)"' + override STD_DEFS += -D'CS_CONFDIR="$(CONF_DIR)"' + + # Compiler warnings +diff -ruNp trunk.patches/module-dvbapi.c trunk/module-dvbapi.c +--- trunk.patches/module-dvbapi.c 2018-04-03 02:48:24.956386446 +0300 ++++ trunk/module-dvbapi.c 2018-04-03 03:06:13.063827549 +0300 +@@ -533,7 +533,7 @@ int32_t dvbapi_net_send(uint32_t request + if (cfg.dvbapi_extended_cw_api == 2) + strcat(capabilities, ",e2"); + +- *info_len = snprintf((char *) &packet[size], sizeof(packet) - size, "OSCam v%s, build r%s (%s); %s", CS_VERSION, CS_SVN_VERSION, CS_TARGET, capabilities + 1); ++ *info_len = snprintf((char *) &packet[size], sizeof(packet) - size, "OSCam v%s, build r%s + EMU r%s (%s); %s", CS_VERSION, CS_SVN_VERSION, CS_EMU_VERSION, CS_TARGET, capabilities + 1); + size += *info_len; + break; + } +diff -ruNp trunk.patches/module-lcd.c trunk/module-lcd.c +--- trunk.patches/module-lcd.c 2018-04-03 02:44:10.102269013 +0300 ++++ trunk/module-lcd.c 2018-04-03 03:15:44.360059325 +0300 +@@ -81,6 +81,7 @@ static void refresh_lcd_file(void) + + fprintf(fpsave, "Version: %s\n", CS_VERSION); + fprintf(fpsave, "Revision: %s\n", CS_SVN_VERSION); ++ fprintf(fpsave, "EMU rev.: %s\n", CS_EMU_VERSION); + if(days == 0) + { fprintf(fpsave, "up: %02d:%02d:%02d\n", hours, mins, secs); } + else +diff -ruNp trunk.patches/oscam.c trunk/oscam.c +--- trunk.patches/oscam.c 2018-04-03 02:48:24.956386446 +0300 ++++ trunk/oscam.c 2018-04-03 03:10:28.813703490 +0300 +@@ -144,7 +144,7 @@ static void show_usage(void) + "| | | \\___ \\| | / _` | '_ ` _ \\\n" + "| |_| |___) | |_| (_| | | | | | |\n" + " \\___/|____/ \\___\\__,_|_| |_| |_|\n\n"); +- printf("OSCam cardserver v%s, build r%s (%s)\n", CS_VERSION, CS_SVN_VERSION, CS_TARGET); ++ printf("OSCam cardserver v%s, build r%s + EMU r%s (%s)\n", CS_VERSION, CS_SVN_VERSION, CS_EMU_VERSION, CS_TARGET); + printf("Copyright (C) 2009-2015 OSCam developers.\n"); + printf("This program is distributed under GPLv3.\n"); + printf("OSCam is based on Streamboard mp-cardserver v0.9d written by dukat\n"); +@@ -376,6 +376,7 @@ static void write_versionfile(bool use_s + } + + fprintf(fp, "Version: oscam-%s-r%s\n", CS_VERSION, CS_SVN_VERSION); ++ fprintf(fp, "EMU: r%s\n", CS_EMU_VERSION); + fprintf(fp, "Compiler: %s\n", CS_TARGET); + fprintf(fp, "Box type: %s (%s)\n", boxtype_get(), boxname_get()); + fprintf(fp, "PID: %d\n", getppid()); +@@ -634,7 +635,7 @@ static void cs_dumpstack(int32_t sig) + + fprintf(stderr, "crashed with signal %d on %swriting oscam.crash\n", sig, buf); + +- fprintf(fp, "%sOSCam cardserver v%s, build r%s (%s)\n", buf, CS_VERSION, CS_SVN_VERSION, CS_TARGET); ++ fprintf(fp, "%sOSCam cardserver v%s, build r%s + EMU r%s (%s)\n", buf, CS_VERSION, CS_SVN_VERSION, CS_EMU_VERSION, CS_TARGET); + fprintf(fp, "FATAL: Signal %d: %s Fault. Logged StackTrace:\n\n", sig, (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown")); + fclose(fp); + +diff -ruNp trunk.patches/oscam-conf.c trunk/oscam-conf.c +--- trunk.patches/oscam-conf.c 2018-04-03 02:44:10.086268878 +0300 ++++ trunk/oscam-conf.c 2018-04-03 03:13:07.970887467 +0300 +@@ -509,8 +509,8 @@ FILE *create_config_file(const char *con + cs_log("ERROR: Cannot create file \"%s\" (errno=%d %s)", temp_file, errno, strerror(errno)); + return NULL; + } +- fprintf(f, "# %s generated automatically by Streamboard OSCAM %s SVN r%s\n", +- conf_filename, CS_VERSION, CS_SVN_VERSION); ++ fprintf(f, "# %s generated automatically by Streamboard OSCAM %s SVN r%s + EMU r%s\n", ++ conf_filename, CS_VERSION, CS_SVN_VERSION, CS_EMU_VERSION); + fprintf(f, "# Read more: http://www.streamboard.tv/svn/oscam/trunk/Distribution/doc/txt/%s.txt\n\n", + conf_filename); + return f; +diff -ruNp trunk.patches/oscam-log.c trunk/oscam-log.c +--- trunk.patches/oscam-log.c 2018-04-03 02:44:09.766266195 +0300 ++++ trunk/oscam-log.c 2018-04-03 03:12:04.910417167 +0300 +@@ -232,7 +232,7 @@ int32_t cs_open_logfiles(void) + // according to syslog docu: calling closelog is not necessary and calling openlog multiple times is safe + // We use openlog to set the default syslog settings so that it's possible to allow switching syslog on and off + openlog(syslog_ident, LOG_NDELAY | LOG_PID, LOG_DAEMON); +- cs_log(">> OSCam << cardserver %s, version " CS_VERSION ", build r" CS_SVN_VERSION " (" CS_TARGET ")", starttext); ++ cs_log(">> OSCam << cardserver %s, version " CS_VERSION ", build r" CS_SVN_VERSION " + EMU r" CS_EMU_VERSION " (" CS_TARGET ")", starttext); + + return (fp <= (FILE *)0); + } diff --git a/package/lean/dvb/oscam/patches/004-oscam_emu.patch b/package/lean/dvb/oscam/patches/004-oscam_emu.patch new file mode 100644 index 0000000000..bcab190d73 --- /dev/null +++ b/package/lean/dvb/oscam/patches/004-oscam_emu.patch @@ -0,0 +1,12988 @@ +diff -ruNp trunk.patches/CMakeLists.txt trunk/CMakeLists.txt +--- trunk.patches/CMakeLists.txt 2018-04-03 02:44:09.770266229 +0300 ++++ trunk/CMakeLists.txt 2018-04-03 03:20:07.654045339 +0300 +@@ -101,6 +101,7 @@ include_directories ( + ${CMAKE_CURRENT_SOURCE_DIR}/csctapi + ${CMAKE_CURRENT_SOURCE_DIR}/cscrypt + ${CMAKE_CURRENT_SOURCE_DIR}/minilzo ++ ${CMAKE_CURRENT_SOURCE_DIR}/ffdecsa + ${CMAKE_CURRENT_SOURCE_DIR}/extapi/cygwin + /usr/include/w32api + ${OPTIONAL_INCLUDE_DIR} +@@ -110,6 +111,7 @@ include_directories ( + ${CMAKE_CURRENT_SOURCE_DIR}/csctapi + ${CMAKE_CURRENT_SOURCE_DIR}/cscrypt + ${CMAKE_CURRENT_SOURCE_DIR}/minilzo ++ ${CMAKE_CURRENT_SOURCE_DIR}/ffdecsa + ${OPTIONAL_INCLUDE_DIR} + ) + endif (OSCamOperatingSystem MATCHES "Windows/Cygwin") +@@ -420,6 +422,13 @@ endif (HAVE_PCSC) + # Manage config.h based on command line parameters + # Manipulate config file based on given parameters and read unset parameters + ++execute_process (COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/config.sh --enabled WITH_EMU OUTPUT_VARIABLE CONFIG_WITH_EMU OUTPUT_STRIP_TRAILING_WHITESPACE) ++if (CONFIG_WITH_EMU MATCHES "Y" AND NOT WITH_EMU EQUAL 1) ++ add_definitions ("-DWITH_EMU") ++ set (WITH_EMU "1") ++ message(STATUS " EMU is added by config compiling with EMU") ++endif(CONFIG_WITH_EMU MATCHES "Y" AND NOT WITH_EMU EQUAL 1) ++ + execute_process (COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/config.sh --show-valid OUTPUT_VARIABLE config_vars_string OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCHALL "[A-Z0-9_]+" config_vars ${config_vars_string}) + +@@ -449,6 +458,7 @@ execute_process (COMMAND make --no-print + add_subdirectory (csctapi) + add_subdirectory (minilzo) + add_subdirectory (cscrypt) ++add_subdirectory (ffdecsa) + + #----------------------- file groups ------------------------------ + execute_process (COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/config.sh --enabled MODULE_CAMD33 OUTPUT_VARIABLE CAMD33 OUTPUT_STRIP_TRAILING_WHITESPACE) +@@ -498,7 +508,7 @@ add_library (${csoscam} STATIC ${csoscam + + set (exe_name "oscam") + add_executable (${exe_name} ${exe_srcs} ${exe_hdrs}) +-target_link_libraries (${exe_name} ${csoscam} ${csmodules} ${csreaders} csctapi cscrypt minilzo) ++target_link_libraries (${exe_name} ${csoscam} ${csmodules} ${csreaders} csctapi cscrypt minilzo ffdecsa) + if(HAVE_LIBRT AND HAVE_LIBUSB) + if (LIBUSBDIR) + set (libusb_link "imp_libusb") +@@ -647,6 +657,11 @@ add_definitions ("-D'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}\"'") + #----------------------- global compile and link options ------------------------------ ++#enable sse2 on x86 ++if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") ++ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse -msse2 -msse3") ++endif (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") ++ + # disable warning about unused but set variables in gcc 4.6+ + if (CMAKE_COMPILER_IS_GNUCC) + execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) +@@ -731,6 +746,22 @@ endif( HAVE_LIBRT OR HAVE_LIBRT_STATIC) + + #-------------------------------------------------------------------------------- + ++if (NOT OSCamOperatingSystem MATCHES "Mac OS X") ++if (NOT DEFINED ENV{ANDROID_NDK}) ++if (NOT DEFINED ENV{ANDROID_STANDALONE_TOOLCHAIN}) ++ if(WITH_EMU) ++ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key) ++ execute_process(COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key ${CMAKE_CURRENT_BINARY_DIR}/SoftCam.Key) ++ else(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key) ++ execute_process(COMMAND touch ${CMAKE_CURRENT_BINARY_DIR}/SoftCam.Key) ++ endif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/SoftCam.Key) ++ execute_process(COMMAND touch ${CMAKE_CURRENT_BINARY_DIR}/utils/SoftCam.Key) ++ set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--format=binary -Wl,SoftCam.Key -Wl,--format=default" ) ++ endif(WITH_EMU) ++endif (NOT DEFINED ENV{ANDROID_STANDALONE_TOOLCHAIN}) ++endif (NOT DEFINED ENV{ANDROID_NDK}) ++endif (NOT OSCamOperatingSystem MATCHES "Mac OS X") ++ + #----------------------- installation ----------------------------- + + file (GLOB config_files "${CMAKE_CURRENT_SOURCE_DIR}/Distribution/oscam.*") +@@ -819,4 +850,8 @@ endif(STATIC_LIBUSB EQUAL 1) + endif(STATICLIBUSB AND NOT LIBUSBDIR) + endif (HAVE_LIBUSB) + ++if (WITH_EMU) ++ message(STATUS " Compile with EMU support") ++endif (WITH_EMU) ++ + message (STATUS "") +diff -ruNp trunk.patches/config.h trunk/config.h +--- trunk.patches/config.h 2018-04-03 02:48:33.320455383 +0300 ++++ trunk/config.h 2018-04-03 03:20:07.654045339 +0300 +@@ -1,6 +1,7 @@ + #ifndef CONFIG_H_ + #define CONFIG_H_ + ++#define WITH_EMU 1 + #define WEBIF 1 + #define WEBIF_LIVELOG 1 + #define WEBIF_JQUERY 1 +diff -ruNp trunk.patches/config.sh trunk/config.sh +--- trunk.patches/config.sh 2018-04-03 02:44:09.134260896 +0300 ++++ trunk/config.sh 2018-04-03 03:20:07.654045339 +0300 +@@ -1,6 +1,6 @@ + #!/bin/sh + +-addons="WEBIF WEBIF_LIVELOG WEBIF_JQUERY TOUCH WITH_SSL HAVE_DVBAPI READ_SDT_CHARSETS IRDETO_GUESSING CS_ANTICASC WITH_DEBUG MODULE_MONITOR WITH_LB CS_CACHEEX CW_CYCLE_CHECK LCDSUPPORT LEDSUPPORT CLOCKFIX IPV6SUPPORT" ++addons="WEBIF WEBIF_LIVELOG WEBIF_JQUERY TOUCH WITH_SSL HAVE_DVBAPI READ_SDT_CHARSETS IRDETO_GUESSING CS_ANTICASC WITH_DEBUG MODULE_MONITOR WITH_LB CS_CACHEEX CW_CYCLE_CHECK LCDSUPPORT LEDSUPPORT CLOCKFIX IPV6SUPPORT WITH_EMU" + protocols="MODULE_CAMD33 MODULE_CAMD35 MODULE_CAMD35_TCP MODULE_NEWCAMD MODULE_CCCAM MODULE_CCCSHARE MODULE_GBOX MODULE_RADEGAST MODULE_SCAM MODULE_SERIAL MODULE_CONSTCW MODULE_PANDORA MODULE_GHTTP" + readers="READER_NAGRA READER_IRDETO READER_CONAX READER_CRYPTOWORKS READER_SECA READER_VIACCESS READER_VIDEOGUARD READER_DRE READER_TONGFANG READER_BULCRYPT READER_GRIFFIN READER_DGCRYPT" + card_readers="CARDREADER_PHOENIX CARDREADER_INTERNAL CARDREADER_SC8IN1 CARDREADER_MP35 CARDREADER_SMARGO CARDREADER_DB2COM CARDREADER_STAPI CARDREADER_STAPI5 CARDREADER_STINGER CARDREADER_DRECAS" +@@ -24,6 +24,7 @@ CONFIG_CW_CYCLE_CHECK=y + # CONFIG_LEDSUPPORT=n + CONFIG_CLOCKFIX=y + # CONFIG_IPV6SUPPORT=n ++CONFIG_WITH_EMU=y + # CONFIG_MODULE_CAMD33=n + CONFIG_MODULE_CAMD35=y + CONFIG_MODULE_CAMD35_TCP=y +@@ -289,12 +290,15 @@ get_opts() { + + update_deps() { + # Calculate dependencies +- enabled_any $(get_opts readers) $(get_opts card_readers) && enable_opt WITH_CARDREADER >/dev/null +- disabled_all $(get_opts readers) $(get_opts card_readers) && disable_opt WITH_CARDREADER >/dev/null ++ enabled_any $(get_opts readers) $(get_opts card_readers) WITH_EMU && enable_opt WITH_CARDREADER >/dev/null ++ disabled_all $(get_opts readers) $(get_opts card_readers) WITH_EMU && disable_opt WITH_CARDREADER >/dev/null + disabled WEBIF && disable_opt WEBIF_LIVELOG >/dev/null + disabled WEBIF && disable_opt WEBIF_JQUERY >/dev/null + enabled MODULE_CCCSHARE && enable_opt MODULE_CCCAM >/dev/null + enabled_any CARDREADER_DB2COM CARDREADER_MP35 CARDREADER_SC8IN1 CARDREADER_STINGER && enable_opt CARDREADER_PHOENIX >/dev/null ++ enabled WITH_EMU && enable_opt READER_VIACCESS >/dev/null ++ enabled WITH_EMU && enable_opt READER_DRE >/dev/null ++ enabled WITH_EMU && enable_opt MODULE_NEWCAMD >/dev/null + } + + list_config() { +@@ -344,9 +348,9 @@ list_config() { + not_have_flag USE_LIBCRYPTO && echo "CONFIG_LIB_AES=y" || echo "# CONFIG_LIB_AES=n" + enabled MODULE_CCCAM && echo "CONFIG_LIB_RC6=y" || echo "# CONFIG_LIB_RC6=n" + not_have_flag USE_LIBCRYPTO && enabled MODULE_CCCAM && echo "CONFIG_LIB_SHA1=y" || echo "# CONFIG_LIB_SHA1=n" +- enabled_any READER_DRE MODULE_SCAM READER_VIACCESS && echo "CONFIG_LIB_DES=y" || echo "# CONFIG_LIB_DES=n" +- enabled_any MODULE_CCCAM READER_NAGRA READER_SECA && echo "CONFIG_LIB_IDEA=y" || echo "# CONFIG_LIB_IDEA=n" +- not_have_flag USE_LIBCRYPTO && enabled_any READER_CONAX READER_CRYPTOWORKS READER_NAGRA && echo "CONFIG_LIB_BIGNUM=y" || echo "# CONFIG_LIB_BIGNUM=n" ++ enabled_any READER_DRE MODULE_SCAM READER_VIACCESS WITH_EMU && echo "CONFIG_LIB_DES=y" || echo "# CONFIG_LIB_DES=n" ++ enabled_any MODULE_CCCAM READER_NAGRA READER_SECA WITH_EMU && echo "CONFIG_LIB_IDEA=y" || echo "# CONFIG_LIB_IDEA=n" ++ not_have_flag USE_LIBCRYPTO && enabled_any READER_CONAX READER_CRYPTOWORKS READER_NAGRA WITH_EMU && echo "CONFIG_LIB_BIGNUM=y" || echo "# CONFIG_LIB_BIGNUM=n" + } + + make_config_c() { +@@ -457,6 +461,7 @@ 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_EMU "Emulator support" $(check_test "WITH_EMU") \ + 2> ${tempfile} + + opt=${?} +diff -ruNp trunk.patches/cscrypt/aes.c trunk/cscrypt/aes.c +--- trunk.patches/cscrypt/aes.c 2018-04-03 02:44:10.098268979 +0300 ++++ trunk/cscrypt/aes.c 2018-04-03 03:20:07.654045339 +0300 +@@ -1250,4 +1250,71 @@ void AES_decrypt(const unsigned char *in + rk[3]; + PUTU32(out + 12, s3); + } ++ ++void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, ++ const unsigned long length, const AES_KEY *key, ++ unsigned char *ivec, const int enc) ++{ ++ unsigned long n; ++ unsigned long len = length; ++ unsigned char tmp[AES_BLOCK_SIZE]; ++ ++ assert(in && out && key && ivec); ++ assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc)); ++ ++ if(AES_ENCRYPT == enc) ++ { ++ while(len >= AES_BLOCK_SIZE) ++ { ++ for(n=0; n < AES_BLOCK_SIZE; ++n) ++ tmp[n] = in[n] ^ ivec[n]; ++ ++ AES_encrypt(tmp, out, key); ++ memcpy(ivec, out, AES_BLOCK_SIZE); ++ len -= AES_BLOCK_SIZE; ++ in += AES_BLOCK_SIZE; ++ out += AES_BLOCK_SIZE; ++ } ++ ++ if(len) ++ { ++ for(n=0; n < len; ++n) ++ tmp[n] = in[n] ^ ivec[n]; ++ ++ for(n=len; n < AES_BLOCK_SIZE; ++n) ++ tmp[n] = ivec[n]; ++ ++ AES_encrypt(tmp, tmp, key); ++ memcpy(out, tmp, AES_BLOCK_SIZE); ++ memcpy(ivec, tmp, AES_BLOCK_SIZE); ++ } ++ } ++ else ++ { ++ while(len >= AES_BLOCK_SIZE) ++ { ++ memcpy(tmp, in, AES_BLOCK_SIZE); ++ AES_decrypt(in, out, key); ++ ++ for(n=0; n < AES_BLOCK_SIZE; ++n) ++ out[n] ^= ivec[n]; ++ ++ memcpy(ivec, tmp, AES_BLOCK_SIZE); ++ len -= AES_BLOCK_SIZE; ++ in += AES_BLOCK_SIZE; ++ out += AES_BLOCK_SIZE; ++ } ++ ++ if(len) ++ { ++ memcpy(tmp, in, AES_BLOCK_SIZE); ++ AES_decrypt(tmp, tmp, key); ++ ++ for(n=0; n < len; ++n) ++ out[n] ^= ivec[n]; ++ ++ memcpy(ivec, tmp, AES_BLOCK_SIZE); ++ } ++ } ++} + #endif +diff -ruNp trunk.patches/cscrypt/aes.h trunk/cscrypt/aes.h +--- trunk.patches/cscrypt/aes.h 2018-04-03 02:44:10.098268979 +0300 ++++ trunk/cscrypt/aes.h 2018-04-03 03:20:07.654045339 +0300 +@@ -42,6 +42,9 @@ void AES_encrypt(const unsigned char *in + void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); + ++void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, ++ const unsigned long length, const AES_KEY *key, ++ unsigned char *ivec, const int enc); + #endif /* !HEADER_AES_H */ + + #endif +diff -ruNp trunk.patches/cscrypt/md5.c trunk/cscrypt/md5.c +--- trunk.patches/cscrypt/md5.c 2018-04-03 02:44:10.090268912 +0300 ++++ trunk/cscrypt/md5.c 2018-04-03 03:20:07.654045339 +0300 +@@ -25,13 +25,6 @@ + + #if !defined(WITH_SSL) && !defined(WITH_LIBCRYPTO) + +-typedef struct MD5Context +-{ +- uint32_t buf[4]; +- uint32_t bits[2]; +- uint32_t in[16]; +-} MD5_CTX; +- + #ifdef __i386__ + #define byteReverse(a, b) + #else +@@ -155,7 +148,7 @@ static void MD5_Transform(uint32_t buf[4 + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +-static void MD5_Init(MD5_CTX *ctx) ++void MD5_Init(MD5_CTX *ctx) + { + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; +@@ -170,7 +163,7 @@ static void MD5_Init(MD5_CTX *ctx) + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +-static void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, unsigned int len) ++void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, unsigned int len) + { + uint32_t t; + +@@ -219,7 +212,7 @@ static void MD5_Update(MD5_CTX *ctx, con + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +-static void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) ++void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx) + { + unsigned count; + unsigned char *p; +diff -ruNp trunk.patches/cscrypt/md5.h trunk/cscrypt/md5.h +--- trunk.patches/cscrypt/md5.h 2018-04-03 02:44:10.102269013 +0300 ++++ trunk/cscrypt/md5.h 2018-04-03 03:20:07.654045339 +0300 +@@ -7,8 +7,16 @@ + #define MD5_DIGEST_LENGTH 16 + + unsigned char *MD5(const unsigned char *input, unsigned long len, unsigned char *output_hash); +-#endif + +-char *__md5_crypt(const char *text_pass, const char *salt, char *crypted_passwd); ++typedef struct MD5Context { ++ uint32_t buf[4]; ++ uint32_t bits[2]; ++ uint32_t in[16]; ++} MD5_CTX; + ++void MD5_Init(MD5_CTX *ctx); ++void MD5_Update(MD5_CTX *ctx, const unsigned char *buf, unsigned int len); ++void MD5_Final(unsigned char digest[MD5_DIGEST_LENGTH], MD5_CTX *ctx); ++#endif ++char *__md5_crypt(const char *text_pass, const char *salt, char *crypted_passwd); + #endif +diff -ruNp trunk.patches/csctapi/cardreaders.h trunk/csctapi/cardreaders.h +--- trunk.patches/csctapi/cardreaders.h 2018-04-03 02:44:09.226261666 +0300 ++++ trunk/csctapi/cardreaders.h 2018-04-03 03:20:07.654045339 +0300 +@@ -14,5 +14,6 @@ extern const struct s_cardreader cardrea + extern const struct s_cardreader cardreader_stapi; + extern const struct s_cardreader cardreader_stinger; + extern const struct s_cardreader cardreader_drecas; ++extern const struct s_cardreader cardreader_emu; + + #endif +diff -ruNp trunk.patches/ffdecsa/CMakeLists.txt trunk/ffdecsa/CMakeLists.txt +--- trunk.patches/ffdecsa/CMakeLists.txt 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/CMakeLists.txt 2018-04-03 03:20:07.654045339 +0300 +@@ -0,0 +1,8 @@ ++project (ffdecsa) ++ ++file (GLOB ffdecsa_srcs "ffdecsa.c") ++file (GLOB ffdecsa_hdrs "*.h") ++ ++set (lib_name "ffdecsa") ++ ++add_library (${lib_name} STATIC ${ffdecsa_srcs} ${ffdecsa_hdrs}) +diff -ruNp trunk.patches/ffdecsa/COPYING trunk/ffdecsa/COPYING +--- trunk.patches/ffdecsa/COPYING 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/COPYING 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,339 @@ ++ GNU GENERAL PUBLIC LICENSE ++ Version 2, June 1991 ++ ++ Copyright (C) 1989, 1991 Free Software Foundation, Inc. ++ 675 Mass Ave, Cambridge, MA 02139, USA ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The licenses for most software are designed to take away your ++freedom to share and change it. By contrast, the GNU General Public ++License is intended to guarantee your freedom to share and change free ++software--to make sure the software is free for all its users. This ++General Public License applies to most of the Free Software ++Foundation's software and to any other program whose authors commit to ++using it. (Some other Free Software Foundation software is covered by ++the GNU Library General Public License instead.) You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++this service if you wish), that you receive source code or can get it ++if you want it, that you can change the software or use pieces of it ++in new free programs; and that you know you can do these things. ++ ++ To protect your rights, we need to make restrictions that forbid ++anyone to deny you these rights or to ask you to surrender the rights. ++These restrictions translate to certain responsibilities for you if you ++distribute copies of the software, or if you modify it. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must give the recipients all the rights that ++you have. You must make sure that they, too, receive or can get the ++source code. And you must show them these terms so they know their ++rights. ++ ++ We protect your rights with two steps: (1) copyright the software, and ++(2) offer you this license which gives you legal permission to copy, ++distribute and/or modify the software. ++ ++ Also, for each author's protection and ours, we want to make certain ++that everyone understands that there is no warranty for this free ++software. If the software is modified by someone else and passed on, we ++want its recipients to know that what they have is not the original, so ++that any problems introduced by others will not reflect on the original ++authors' reputations. ++ ++ Finally, any free program is threatened constantly by software ++patents. We wish to avoid the danger that redistributors of a free ++program will individually obtain patent licenses, in effect making the ++program proprietary. To prevent this, we have made it clear that any ++patent must be licensed for everyone's free use or not licensed at all. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ GNU GENERAL PUBLIC LICENSE ++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++ 0. This License applies to any program or other work which contains ++a notice placed by the copyright holder saying it may be distributed ++under the terms of this General Public License. The "Program", below, ++refers to any such program or work, and a "work based on the Program" ++means either the Program or any derivative work under copyright law: ++that is to say, a work containing the Program or a portion of it, ++either verbatim or with modifications and/or translated into another ++language. (Hereinafter, translation is included without limitation in ++the term "modification".) Each licensee is addressed as "you". ++ ++Activities other than copying, distribution and modification are not ++covered by this License; they are outside its scope. The act of ++running the Program is not restricted, and the output from the Program ++is covered only if its contents constitute a work based on the ++Program (independent of having been made by running the Program). ++Whether that is true depends on what the Program does. ++ ++ 1. You may copy and distribute verbatim copies of the Program's ++source code as you receive it, in any medium, provided that you ++conspicuously and appropriately publish on each copy an appropriate ++copyright notice and disclaimer of warranty; keep intact all the ++notices that refer to this License and to the absence of any warranty; ++and give any other recipients of the Program a copy of this License ++along with the Program. ++ ++You may charge a fee for the physical act of transferring a copy, and ++you may at your option offer warranty protection in exchange for a fee. ++ ++ 2. You may modify your copy or copies of the Program or any portion ++of it, thus forming a work based on the Program, and copy and ++distribute such modifications or work under the terms of Section 1 ++above, provided that you also meet all of these conditions: ++ ++ a) You must cause the modified files to carry prominent notices ++ stating that you changed the files and the date of any change. ++ ++ b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any ++ part thereof, to be licensed as a whole at no charge to all third ++ parties under the terms of this License. ++ ++ c) If the modified program normally reads commands interactively ++ when run, you must cause it, when started running for such ++ interactive use in the most ordinary way, to print or display an ++ announcement including an appropriate copyright notice and a ++ notice that there is no warranty (or else, saying that you provide ++ a warranty) and that users may redistribute the program under ++ these conditions, and telling the user how to view a copy of this ++ License. (Exception: if the Program itself is interactive but ++ does not normally print such an announcement, your work based on ++ the Program is not required to print an announcement.) ++ ++These requirements apply to the modified work as a whole. If ++identifiable sections of that work are not derived from the Program, ++and can be reasonably considered independent and separate works in ++themselves, then this License, and its terms, do not apply to those ++sections when you distribute them as separate works. But when you ++distribute the same sections as part of a whole which is a work based ++on the Program, the distribution of the whole must be on the terms of ++this License, whose permissions for other licensees extend to the ++entire whole, and thus to each and every part regardless of who wrote it. ++ ++Thus, it is not the intent of this section to claim rights or contest ++your rights to work written entirely by you; rather, the intent is to ++exercise the right to control the distribution of derivative or ++collective works based on the Program. ++ ++In addition, mere aggregation of another work not based on the Program ++with the Program (or with a work based on the Program) on a volume of ++a storage or distribution medium does not bring the other work under ++the scope of this License. ++ ++ 3. You may copy and distribute the Program (or a work based on it, ++under Section 2) in object code or executable form under the terms of ++Sections 1 and 2 above provided that you also do one of the following: ++ ++ a) Accompany it with the complete corresponding machine-readable ++ source code, which must be distributed under the terms of Sections ++ 1 and 2 above on a medium customarily used for software interchange; or, ++ ++ b) Accompany it with a written offer, valid for at least three ++ years, to give any third party, for a charge no more than your ++ cost of physically performing source distribution, a complete ++ machine-readable copy of the corresponding source code, to be ++ distributed under the terms of Sections 1 and 2 above on a medium ++ customarily used for software interchange; or, ++ ++ c) Accompany it with the information you received as to the offer ++ to distribute corresponding source code. (This alternative is ++ allowed only for noncommercial distribution and only if you ++ received the program in object code or executable form with such ++ an offer, in accord with Subsection b above.) ++ ++The source code for a work means the preferred form of the work for ++making modifications to it. For an executable work, complete source ++code means all the source code for all modules it contains, plus any ++associated interface definition files, plus the scripts used to ++control compilation and installation of the executable. However, as a ++special exception, the source code distributed need not include ++anything that is normally distributed (in either source or binary ++form) with the major components (compiler, kernel, and so on) of the ++operating system on which the executable runs, unless that component ++itself accompanies the executable. ++ ++If distribution of executable or object code is made by offering ++access to copy from a designated place, then offering equivalent ++access to copy the source code from the same place counts as ++distribution of the source code, even though third parties are not ++compelled to copy the source along with the object code. ++ ++ 4. You may not copy, modify, sublicense, or distribute the Program ++except as expressly provided under this License. Any attempt ++otherwise to copy, modify, sublicense or distribute the Program is ++void, and will automatically terminate your rights under this License. ++However, parties who have received copies, or rights, from you under ++this License will not have their licenses terminated so long as such ++parties remain in full compliance. ++ ++ 5. You are not required to accept this License, since you have not ++signed it. However, nothing else grants you permission to modify or ++distribute the Program or its derivative works. These actions are ++prohibited by law if you do not accept this License. Therefore, by ++modifying or distributing the Program (or any work based on the ++Program), you indicate your acceptance of this License to do so, and ++all its terms and conditions for copying, distributing or modifying ++the Program or works based on it. ++ ++ 6. Each time you redistribute the Program (or any work based on the ++Program), the recipient automatically receives a license from the ++original licensor to copy, distribute or modify the Program subject to ++these terms and conditions. You may not impose any further ++restrictions on the recipients' exercise of the rights granted herein. ++You are not responsible for enforcing compliance by third parties to ++this License. ++ ++ 7. If, as a consequence of a court judgment or allegation of patent ++infringement or for any other reason (not limited to patent issues), ++conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot ++distribute so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you ++may not distribute the Program at all. For example, if a patent ++license would not permit royalty-free redistribution of the Program by ++all those who receive copies directly or indirectly through you, then ++the only way you could satisfy both it and this License would be to ++refrain entirely from distribution of the Program. ++ ++If any portion of this section is held invalid or unenforceable under ++any particular circumstance, the balance of the section is intended to ++apply and the section as a whole is intended to apply in other ++circumstances. ++ ++It is not the purpose of this section to induce you to infringe any ++patents or other property right claims or to contest validity of any ++such claims; this section has the sole purpose of protecting the ++integrity of the free software distribution system, which is ++implemented by public license practices. Many people have made ++generous contributions to the wide range of software distributed ++through that system in reliance on consistent application of that ++system; it is up to the author/donor to decide if he or she is willing ++to distribute software through any other system and a licensee cannot ++impose that choice. ++ ++This section is intended to make thoroughly clear what is believed to ++be a consequence of the rest of this License. ++ ++ 8. If the distribution and/or use of the Program is restricted in ++certain countries either by patents or by copyrighted interfaces, the ++original copyright holder who places the Program under this License ++may add an explicit geographical distribution limitation excluding ++those countries, so that distribution is permitted only in or among ++countries not thus excluded. In such case, this License incorporates ++the limitation as if written in the body of this License. ++ ++ 9. The Free Software Foundation may publish revised and/or new versions ++of the General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++Each version is given a distinguishing version number. If the Program ++specifies a version number of this License which applies to it and "any ++later version", you have the option of following the terms and conditions ++either of that version or of any later version published by the Free ++Software Foundation. If the Program does not specify a version number of ++this License, you may choose any version ever published by the Free Software ++Foundation. ++ ++ 10. If you wish to incorporate parts of the Program into other free ++programs whose distribution conditions are different, write to the author ++to ask for permission. For software which is copyrighted by the Free ++Software Foundation, write to the Free Software Foundation; we sometimes ++make exceptions for this. Our decision will be guided by the two goals ++of preserving the free status of all derivatives of our free software and ++of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++REPAIR OR CORRECTION. ++ ++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++POSSIBILITY OF SUCH DAMAGES. ++ ++ END OF TERMS AND CONDITIONS ++ ++ Appendix: How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++convey the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) 19yy ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this ++when it starts in an interactive mode: ++ ++ Gnomovision version 69, Copyright (C) 19yy name of author ++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may ++be called something other than `show w' and `show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++ `Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++ , 1 April 1989 ++ Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Library General ++Public License instead of this License. +diff -ruNp trunk.patches/ffdecsa/ffdecsa.c trunk/ffdecsa/ffdecsa.c +--- trunk.patches/ffdecsa/ffdecsa.c 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/ffdecsa.c 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,926 @@ ++/* FFdecsa -- fast decsa algorithm ++ * ++ * Copyright (C) 2003-2004 fatih89r ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++ ++#include "ffdecsa.h" ++ ++#ifndef NULL ++#define NULL 0 ++#endif ++ ++//#define DEBUG ++#ifdef DEBUG ++#define DBG(a) a ++#else ++#define DBG(a) ++#endif ++ ++//// parallelization stuff, large speed differences are possible ++// possible choices ++#define PARALLEL_32_4CHAR 320 ++#define PARALLEL_32_4CHARA 321 ++#define PARALLEL_32_INT 322 ++#define PARALLEL_64_8CHAR 640 ++#define PARALLEL_64_8CHARA 641 ++#define PARALLEL_64_2INT 642 ++#define PARALLEL_64_LONG 643 ++#define PARALLEL_64_MMX 644 ++#define PARALLEL_128_16CHAR 1280 ++#define PARALLEL_128_16CHARA 1281 ++#define PARALLEL_128_4INT 1282 ++#define PARALLEL_128_2LONG 1283 ++#define PARALLEL_128_2MMX 1284 ++#define PARALLEL_128_SSE 1285 ++#define PARALLEL_128_SSE2 1286 ++ ++//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// ++#ifndef PARALLEL_MODE ++ ++#if defined(__x86_64__) || defined(_M_X64) ++#define PARALLEL_MODE PARALLEL_128_SSE2 ++ ++#elif defined(__mips__) || defined(__mips) || defined(__MIPS__) ++#define PARALLEL_MODE PARALLEL_64_LONG ++ ++#elif defined(__sh__) || defined(__SH4__) ++#define PARALLEL_MODE PARALLEL_32_INT ++#define COPY_UNALIGNED_PKT ++#define MEMALIGN_VAL 4 ++ ++#else ++#define PARALLEL_MODE PARALLEL_32_INT ++#endif ++ ++#endif ++//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice //////// ++ ++#include "parallel_generic.h" ++//// conditionals ++#if PARALLEL_MODE==PARALLEL_32_4CHAR ++#include "parallel_032_4char.h" ++#elif PARALLEL_MODE==PARALLEL_32_4CHARA ++#include "parallel_032_4charA.h" ++#elif PARALLEL_MODE==PARALLEL_32_INT ++#include "parallel_032_int.h" ++#elif PARALLEL_MODE==PARALLEL_64_8CHAR ++#include "parallel_064_8char.h" ++#elif PARALLEL_MODE==PARALLEL_64_8CHARA ++#include "parallel_064_8charA.h" ++#elif PARALLEL_MODE==PARALLEL_64_2INT ++#include "parallel_064_2int.h" ++#elif PARALLEL_MODE==PARALLEL_64_LONG ++#include "parallel_064_long.h" ++#elif PARALLEL_MODE==PARALLEL_64_MMX ++#include "parallel_064_mmx.h" ++#elif PARALLEL_MODE==PARALLEL_128_16CHAR ++#include "parallel_128_16char.h" ++#elif PARALLEL_MODE==PARALLEL_128_16CHARA ++#include "parallel_128_16charA.h" ++#elif PARALLEL_MODE==PARALLEL_128_4INT ++#include "parallel_128_4int.h" ++#elif PARALLEL_MODE==PARALLEL_128_2LONG ++#include "parallel_128_2long.h" ++#elif PARALLEL_MODE==PARALLEL_128_2MMX ++#include "parallel_128_2mmx.h" ++#elif PARALLEL_MODE==PARALLEL_128_SSE ++#include "parallel_128_sse.h" ++#elif PARALLEL_MODE==PARALLEL_128_SSE2 ++#include "parallel_128_sse2.h" ++#else ++#error "unknown/undefined parallel mode" ++#endif ++ ++// stuff depending on conditionals ++ ++#define BYTES_PER_GROUP (GROUP_PARALLELISM/8) ++#define BYPG BYTES_PER_GROUP ++#define BITS_PER_GROUP GROUP_PARALLELISM ++#define BIPG BITS_PER_GROUP ++ ++// platform specific ++ ++#ifdef __arm__ ++#if !defined(MEMALIGN_VAL) || MEMALIGN_VAL<4 ++#undef MEMALIGN_VAL ++#define MEMALIGN_VAL 4 ++#endif ++#define COPY_UNALIGNED_PKT ++#endif ++ ++// ++ ++#ifndef MALLOC ++#define MALLOC(X) malloc(X) ++#endif ++#ifndef FREE ++#define FREE(X) free(X) ++#endif ++#ifdef MEMALIGN_VAL ++#define MEMALIGN __attribute__((aligned(MEMALIGN_VAL))) ++#else ++#define MEMALIGN ++#endif ++ ++//// debug tool ++ ++#ifdef DEBUG ++static void dump_mem(const char *string, const unsigned char *p, int len, int linelen){ ++ int i; ++ for(i=0;i>4)&0xf; ++ iA[1]=(ck[0] )&0xf; ++ iA[2]=(ck[1]>>4)&0xf; ++ iA[3]=(ck[1] )&0xf; ++ iA[4]=(ck[2]>>4)&0xf; ++ iA[5]=(ck[2] )&0xf; ++ iA[6]=(ck[3]>>4)&0xf; ++ iA[7]=(ck[3] )&0xf; ++ iB[0]=(ck[4]>>4)&0xf; ++ iB[1]=(ck[4] )&0xf; ++ iB[2]=(ck[5]>>4)&0xf; ++ iB[3]=(ck[5] )&0xf; ++ iB[4]=(ck[6]>>4)&0xf; ++ iB[5]=(ck[6] )&0xf; ++ iB[6]=(ck[7]>>4)&0xf; ++ iB[7]=(ck[7] )&0xf; ++} ++ ++//----- stream main function ++ ++#define STREAM_INIT ++#include "stream.c" ++#undef STREAM_INIT ++ ++#define STREAM_NORMAL ++#include "stream.c" ++#undef STREAM_NORMAL ++ ++ ++//-----block decypher ++ ++//-----key schedule for block decypher ++ ++static void key_schedule_block( ++ unsigned char *ck, // [In] ck[0]-ck[7] 8 bytes | Key. ++ unsigned char *kk) // [Out] kk[0]-kk[55] 56 bytes | Key schedule. ++{ ++ static const unsigned char key_perm[0x40] = { ++ 0x12,0x24,0x09,0x07,0x2A,0x31,0x1D,0x15, 0x1C,0x36,0x3E,0x32,0x13,0x21,0x3B,0x40, ++ 0x18,0x14,0x25,0x27,0x02,0x35,0x1B,0x01, 0x22,0x04,0x0D,0x0E,0x39,0x28,0x1A,0x29, ++ 0x33,0x23,0x34,0x0C,0x16,0x30,0x1E,0x3A, 0x2D,0x1F,0x08,0x19,0x17,0x2F,0x3D,0x11, ++ 0x3C,0x05,0x38,0x2B,0x0B,0x06,0x0A,0x2C, 0x20,0x3F,0x2E,0x0F,0x03,0x26,0x10,0x37, ++ }; ++ ++ int i,j,k; ++ int bit[64]; ++ int newbit[64]; ++ int kb[7][8]; ++ ++ // 56 steps ++ // 56 key bytes kk(55)..kk(0) by key schedule from ck ++ ++ // kb(6,0) .. kb(6,7) = ck(0) .. ck(7) ++ kb[6][0] = ck[0]; ++ kb[6][1] = ck[1]; ++ kb[6][2] = ck[2]; ++ kb[6][3] = ck[3]; ++ kb[6][4] = ck[4]; ++ kb[6][5] = ck[5]; ++ kb[6][6] = ck[6]; ++ kb[6][7] = ck[7]; ++ ++ // calculate kb[5] .. kb[0] ++ for(i=5; i>=0; i--){ ++ // 64 bit perm on kb ++ for(j=0; j<8; j++){ ++ for(k=0; k<8; k++){ ++ bit[j*8+k] = (kb[i+1][j] >> (7-k)) & 1; ++ newbit[key_perm[j*8+k]-1] = bit[j*8+k]; ++ } ++ } ++ for(j=0; j<8; j++){ ++ kb[i][j] = 0; ++ for(k=0; k<8; k++){ ++ kb[i][j] |= newbit[j*8+k] << (7-k); ++ } ++ } ++ } ++ ++ // xor to give kk ++ for(i=0; i<7; i++){ ++ for(j=0; j<8; j++){ ++ kk[i*8+j] = kb[i][j] ^ i; ++ } ++ } ++ ++} ++ ++//-----block utils ++ ++static inline __attribute__((always_inline)) void trasp_N_8 (unsigned char *in,unsigned char* out,int count){ ++ int *ri=(int *)in; ++ int *ibi=(int *)out; ++ int j,i,k,g; ++ // copy and first step ++ for(g=0;g>16) | (b&0xffff0000) ; ++ } ++ } ++ } ++//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); ++// now 01010101 ++ for(j=0;j<8;j+=2){ ++ for(i=0;i<1;i++){ ++ for(k=0;k>8) | (b&0xff00ff00); ++ } ++ } ++ } ++//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); ++// now 00000000 ++} ++ ++static inline __attribute__((always_inline)) void trasp_8_N (unsigned char *in,unsigned char* out,int count){ ++ int *ri=(int *)in; ++ int *bdi=(int *)out; ++ int j,i,k,g; ++#define INTS_PER_ROW (GROUP_PARALLELISM/8*2) ++//dump_mem("NE1 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); ++// now 00000000 ++ for(j=0;j<8;j+=2){ ++ for(i=0;i<1;i++){ ++ for(k=0;k>8) | (b&0xff00ff00); ++ } ++ } ++ } ++//dump_mem("NE2 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); ++// now 01010101 ++ for(j=0;j<8;j+=4){ ++ for(i=0;i<2;i++){ ++ for(k=0;k>16) | (b&0xffff0000) ; ++ } ++ } ++ } ++//dump_mem("NE3 r[roff]",&r[roff],GROUP_PARALLELISM*8,GROUP_PARALLELISM); ++// now 01230123 ++ for(g=0;g=0;i--){ ++ { ++ MEMALIGN batch tkkmulti=kkmulti[i]; ++ batch *si=(batch *)sbox_in; ++ batch *r6_N=(batch *)(r+roff+GROUP_PARALLELISM*6); ++ for(g=0;gck,pk,8); ++// precalculations for stream ++ key_schedule_stream(key->ck,key->iA,key->iB); ++ for(by=0;by<8;by++){ ++ for(bi=0;bi<8;bi++){ ++ key->ck_g[by][bi]=(key->ck[by]&(1<iA_g[by][bi]=(key->iA[by]&(1<iB_g[by][bi]=(key->iB[by]&(1<ck,key->kk); ++ for(i=0;i<56;i++){ ++ for(j=0;jkkmulti[i])+j)=key->kk[i]; ++ } ++ } ++} ++ ++void set_control_words(void *keys, const unsigned char *ev, const unsigned char *od){ ++ schedule_key(&((struct csa_keys_t *)keys)->even,ev); ++ schedule_key(&((struct csa_keys_t *)keys)->odd,od); ++} ++ ++void set_even_control_word(void *keys, const unsigned char *pk){ ++ schedule_key(&((struct csa_keys_t *)keys)->even,pk); ++} ++ ++void set_odd_control_word(void *keys, const unsigned char *pk){ ++ schedule_key(&((struct csa_keys_t *)keys)->odd,pk); ++} ++ ++//-----get control words ++ ++void get_control_words(void *keys, unsigned char *even, unsigned char *odd){ ++ memcpy(even,&((struct csa_keys_t *)keys)->even.ck,8); ++ memcpy(odd,&((struct csa_keys_t *)keys)->odd.ck,8); ++} ++ ++//----- decrypt ++ ++int decrypt_packets(void *keys, unsigned char **cluster){ ++ // statistics, currently unused ++ int stat_no_scramble=0; ++ int stat_reserved=0; ++ int stat_decrypted[2]={0,0}; ++ int stat_decrypted_mini=0; ++ unsigned char **clst; ++ unsigned char **clst2; ++ int grouped; ++ int group_ev_od; ++ int advanced; ++ int can_advance; ++ unsigned char *g_pkt[GROUP_PARALLELISM]; ++ int g_len[GROUP_PARALLELISM]; ++ int g_offset[GROUP_PARALLELISM]; ++ int g_n[GROUP_PARALLELISM]; ++ int g_residue[GROUP_PARALLELISM]; ++ unsigned char *pkt; ++ int xc0,ev_od,len,offset,n,residue; ++ struct csa_key_t* k; ++ int i,j,iter,g; ++ int t23,tsmall; ++ int alive[24]; ++//icc craziness int pad1=0; //////////align! FIXME ++ unsigned char *encp[GROUP_PARALLELISM]; ++ MEMALIGN unsigned char stream_in[GROUP_PARALLELISM*8]; ++ MEMALIGN unsigned char stream_out[GROUP_PARALLELISM*8]; ++ MEMALIGN unsigned char ib[GROUP_PARALLELISM*8]; ++ MEMALIGN unsigned char block_out[GROUP_PARALLELISM*8]; ++#ifdef COPY_UNALIGNED_PKT ++ unsigned char *unaligned[GROUP_PARALLELISM]; ++ MEMALIGN unsigned char alignedBuff[GROUP_PARALLELISM][188]; ++#endif ++ struct stream_regs regs; ++ ++//icc craziness i=(int)&pad1;//////////align!!! FIXME ++ ++ // build a list of packets to be processed ++ clst=cluster; ++ grouped=0; ++ advanced=0; ++ can_advance=1; ++ group_ev_od=-1; // silence incorrect compiler warning ++ pkt=*clst; ++ do{ // find a new packet ++ if(grouped==GROUP_PARALLELISM){ ++ // full ++ break; ++ } ++ if(pkt==NULL){ ++ // no more ranges ++ break; ++ } ++ if(pkt>=*(clst+1)){ ++ // out of this range, try next ++ clst++;clst++; ++ pkt=*clst; ++ continue; ++ } ++ ++ do{ // handle this packet ++ xc0=pkt[3]&0xc0; ++ DBG(fprintf(stderr," exam pkt=%p, xc0=%02x, can_adv=%i\n",pkt,xc0,can_advance)); ++ if(xc0==0x00){ ++ DBG(fprintf(stderr,"skip clear pkt %p (can_advance is %i)\n",pkt,can_advance)); ++ advanced+=can_advance; ++ stat_no_scramble++; ++ break; ++ } ++ if(xc0==0x40){ ++ DBG(fprintf(stderr,"skip reserved pkt %p (can_advance is %i)\n",pkt,can_advance)); ++ advanced+=can_advance; ++ stat_reserved++; ++ break; ++ } ++ if(xc0==0x80||xc0==0xc0){ // encrypted ++ ev_od=(xc0&0x40)>>6; // 0 even, 1 odd ++ if(grouped==0) group_ev_od=ev_od; // this group will be all even (or odd) ++ if(group_ev_od==ev_od){ // could be added to group ++ pkt[3]&=0x3f; // consider it decrypted now ++ if(pkt[3]&0x20){ // incomplete packet ++ offset=4+pkt[4]+1; ++ len=188-offset; ++ n=len>>3; ++ residue=len-(n<<3); ++ if(n==0){ // decrypted==encrypted! ++ DBG(fprintf(stderr,"DECRYPTED MINI! (can_advance is %i)\n",can_advance)); ++ advanced+=can_advance; ++ stat_decrypted_mini++; ++ break; // this doesn't need more processing ++ } ++ }else{ ++ len=184; ++ offset=4; ++ n=23; ++ residue=0; ++ } ++ g_pkt[grouped]=pkt; ++ g_len[grouped]=len; ++ g_offset[grouped]=offset; ++ g_n[grouped]=n; ++ g_residue[grouped]=residue; ++ DBG(fprintf(stderr,"%2i: eo=%i pkt=%p len=%03i n=%2i residue=%i\n",grouped,ev_od,pkt,len,n,residue)); ++ grouped++; ++ advanced+=can_advance; ++ stat_decrypted[ev_od]++; ++ } ++ else{ ++ can_advance=0; ++ DBG(fprintf(stderr,"skip pkt %p and can_advance set to 0\n",pkt)); ++ break; // skip and go on ++ } ++ } ++ } while(0); ++ ++ if(can_advance){ ++ // move range start forward ++ *clst+=188; ++ } ++ // next packet, if there is one ++ pkt+=188; ++ } while(1); ++ DBG(fprintf(stderr,"-- result: grouped %i pkts, advanced %i pkts\n",grouped,advanced)); ++ ++ // delete empty ranges and compact list ++ clst2=cluster; ++ for(clst=cluster;*clst!=NULL;clst+=2){ ++ // if not empty ++ if(*clst<*(clst+1)){ ++ // it will remain ++ *clst2=*clst; ++ *(clst2+1)=*(clst+1); ++ clst2+=2; ++ } ++ } ++ *clst2=NULL; ++ ++ if(grouped==0){ ++ // no processing needed ++ return advanced; ++ } ++ ++ // sort them, longest payload first ++ // we expect many n=23 packets and a few n<23 ++ DBG(fprintf(stderr,"PRESORTING\n")); ++ for(i=0;i=0;tsmall--){ ++ if(g_n[tsmall]==23) break; ++ } ++DBG(fprintf(stderr,"tsmall after for =%i\n",tsmall)); ++ ++ if(tsmall-t23<1) break; ++ ++DBG(fprintf(stderr,"swap t23=%i,tsmall=%i\n",t23,tsmall)); ++ ++ g_swap(t23,tsmall); ++ ++ t23++; ++ tsmall--; ++DBG(fprintf(stderr,"new t23=%i,tsmall=%i\n\n",t23,tsmall)); ++ } ++ DBG(fprintf(stderr,"packets with n=23, t23=%i grouped=%i\n",t23,grouped)); ++ DBG(fprintf(stderr,"MIDSORTING\n")); ++ for(i=0;ig_n[i]){ ++ g_swap(i,j); ++ } ++ } ++ } ++ DBG(fprintf(stderr,"POSTSORTING\n")); ++ for(i=0;i=0;i--){ ++ alive[i]+=alive[i+1]; ++ } ++ DBG(fprintf(stderr,"ALIVE\n")); ++ for(i=0;i<=23;i++){ ++ DBG(fprintf(stderr,"alive%2i=%i\n",i,alive[i])); ++ } ++ ++ // choose key ++ if(group_ev_od==0){ ++ k=&((struct csa_keys_t *)keys)->even; ++ } ++ else{ ++ k=&((struct csa_keys_t *)keys)->odd; ++ } ++ ++ //INIT ++//#define INITIALIZE_UNUSED_INPUT ++#ifdef INITIALIZE_UNUSED_INPUT ++// unnecessary zeroing. ++// without this, we operate on uninitialized memory ++// when grouped>>>>ITER 0\n")); ++ iter=0; ++ stream_cypher_group_init(®s,k->iA_g,k->iB_g,stream_in); ++ // fill first ib ++ for(g=0;g0;iter++){ ++DBG(fprintf(stderr,">>>>>ITER %i\n",iter)); ++ // alive and just dead packets: calc block ++ block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]); ++DBG(dump_mem("BLO_ib ",block_out,8*alive[iter-1],8)); ++ // all packets (dead too): calc stream ++ stream_cypher_group_normal(®s,stream_out); ++//dump_mem("stream_out",stream_out,GROUP_PARALLELISM*8,BYPG); ++ ++ // alive packets: calc ib ++ for(g=0;g>>>>ITER 23\n")); ++ iter=23; ++ // calc block ++ block_decypher_group(k->kkmulti,ib,block_out,alive[iter-1]); ++DBG(dump_mem("23BLO_ib ",block_out,8*alive[iter-1],8)); ++ // just dead packets: write decrypted data ++ for(g=alive[iter];g=4?32-1:0))+j); ++ } ++} ++ ++typedef unsigned int batch; ++#define BYTES_PER_BATCH 4 ++#define B_FFN_ALL_29() 0x29292929 ++#define B_FFN_ALL_02() 0x02020202 ++#define B_FFN_ALL_04() 0x04040404 ++#define B_FFN_ALL_10() 0x10101010 ++#define B_FFN_ALL_40() 0x40404040 ++#define B_FFN_ALL_80() 0x80808080 ++ ++#define M_EMPTY() +diff -ruNp trunk.patches/ffdecsa/parallel_064_long.h trunk/ffdecsa/parallel_064_long.h +--- trunk.patches/ffdecsa/parallel_064_long.h 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/parallel_064_long.h 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,39 @@ ++/* FFdecsa -- fast decsa algorithm ++ * ++ * Copyright (C) 2007 Dark Avenger ++ * 2003-2004 fatih89r ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include "parallel_std_def.h" ++ ++typedef unsigned long long group; ++#define GROUP_PARALLELISM 64 ++#define FF0() 0x0ULL ++#define FF1() 0xffffffffffffffffULL ++ ++typedef unsigned long long batch; ++#define BYTES_PER_BATCH 8 ++#define B_FFN_ALL_29() 0x2929292929292929ULL ++#define B_FFN_ALL_02() 0x0202020202020202ULL ++#define B_FFN_ALL_04() 0x0404040404040404ULL ++#define B_FFN_ALL_10() 0x1010101010101010ULL ++#define B_FFN_ALL_40() 0x4040404040404040ULL ++#define B_FFN_ALL_80() 0x8080808080808080ULL ++ ++#define M_EMPTY() ++ ++#include "fftable.h" +diff -ruNp trunk.patches/ffdecsa/parallel_128_sse2.h trunk/ffdecsa/parallel_128_sse2.h +--- trunk.patches/ffdecsa/parallel_128_sse2.h 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/parallel_128_sse2.h 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,82 @@ ++/* FFdecsa -- fast decsa algorithm ++ * ++ * Copyright (C) 2007 Dark Avenger ++ * 2003-2004 fatih89r ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++ ++#define MEMALIGN_VAL 16 ++ ++union __u128i { ++ unsigned int u[4]; ++ __m128i v; ++}; ++ ++static const union __u128i ff0 = {{0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}}; ++static const union __u128i ff1 = {{0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU}}; ++ ++typedef __m128i group; ++#define GROUP_PARALLELISM 128 ++#define FF0() ff0.v ++#define FF1() ff1.v ++#define FFAND(a,b) _mm_and_si128((a),(b)) ++#define FFOR(a,b) _mm_or_si128((a),(b)) ++#define FFXOR(a,b) _mm_xor_si128((a),(b)) ++#define FFNOT(a) _mm_xor_si128((a),FF1()) ++#define MALLOC(X) _mm_malloc(X,16) ++#define FREE(X) _mm_free(X) ++ ++/* BATCH */ ++ ++static const union __u128i ff29 = {{0x29292929U, 0x29292929U, 0x29292929U, 0x29292929U}}; ++static const union __u128i ff02 = {{0x02020202U, 0x02020202U, 0x02020202U, 0x02020202U}}; ++static const union __u128i ff04 = {{0x04040404U, 0x04040404U, 0x04040404U, 0x04040404U}}; ++static const union __u128i ff10 = {{0x10101010U, 0x10101010U, 0x10101010U, 0x10101010U}}; ++static const union __u128i ff40 = {{0x40404040U, 0x40404040U, 0x40404040U, 0x40404040U}}; ++static const union __u128i ff80 = {{0x80808080U, 0x80808080U, 0x80808080U, 0x80808080U}}; ++ ++typedef __m128i batch; ++#define BYTES_PER_BATCH 16 ++#define B_FFN_ALL_29() ff29.v ++#define B_FFN_ALL_02() ff02.v ++#define B_FFN_ALL_04() ff04.v ++#define B_FFN_ALL_10() ff10.v ++#define B_FFN_ALL_40() ff40.v ++#define B_FFN_ALL_80() ff80.v ++ ++#define B_FFAND(a,b) FFAND(a,b) ++#define B_FFOR(a,b) FFOR(a,b) ++#define B_FFXOR(a,b) FFXOR(a,b) ++#define B_FFSH8L(a,n) _mm_slli_epi64((a),(n)) ++#define B_FFSH8R(a,n) _mm_srli_epi64((a),(n)) ++ ++#define M_EMPTY() ++ ++#undef BEST_SPAN ++#define BEST_SPAN 16 ++ ++#undef XOR_BEST_BY ++inline static void XOR_BEST_BY(unsigned char *d, unsigned char *s1, unsigned char *s2) ++{ ++ __m128i vs1 = _mm_load_si128((__m128i*)s1); ++ __m128i vs2 = _mm_load_si128((__m128i*)s2); ++ vs1 = _mm_xor_si128(vs1, vs2); ++ _mm_store_si128((__m128i*)d, vs1); ++} ++ ++#include "fftable.h" +diff -ruNp trunk.patches/ffdecsa/parallel_generic.h trunk/ffdecsa/parallel_generic.h +--- trunk.patches/ffdecsa/parallel_generic.h 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/parallel_generic.h 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,102 @@ ++/* FFdecsa -- fast decsa algorithm ++ * ++ * Copyright (C) 2003-2004 fatih89r ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++ ++ ++#if 0 ++//// generics ++#define COPY4BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ ++ *pd = *ps; }while(0) ++#define COPY8BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd = *ps; }while(0) ++#define COPY16BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd = *ps; \ ++ *(pd+1) = *(ps+1); }while(0) ++#define COPY32BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd = *ps; \ ++ *(pd+1) = *(ps+1) \ ++ *(pd+2) = *(ps+2) \ ++ *(pd+3) = *(ps+3); }while(0) ++#define XOR4BY(d,s1,s2) do{ int *pd=(int *)(d), *ps1=(int *)(s1), *ps2=(int *)(s2); \ ++ *pd = *ps1 ^ *ps2; }while(0) ++#define XOR8BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ ++ *pd = *ps1 ^ *ps2; }while(0) ++#define XOR16BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ ++ *pd = *ps1 ^ *ps2; \ ++ *(pd+8) = *(ps1+8) ^ *(ps2+8); }while(0) ++#define XOR32BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ ++ *pd = *ps1 ^ *ps2; \ ++ *(pd+1) = *(ps1+1) ^ *(ps2+1); \ ++ *(pd+2) = *(ps1+2) ^ *(ps2+2); \ ++ *(pd+3) = *(ps1+3) ^ *(ps2+3); }while(0) ++#define XOR32BV(d,s1,s2) do{ int *const pd=(int *const)(d), *ps1=(const int *const)(s1), *ps2=(const int *const)(s2); \ ++ int z; \ ++ for(z=0;z<8;z++){ \ ++ pd[z]=ps1[z]^ps2[z]; \ ++ } \ ++ }while(0) ++#define XOREQ4BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ ++ *pd ^= *ps; }while(0) ++#define XOREQ8BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd ^= *ps; }while(0) ++#define XOREQ16BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd ^= *ps; \ ++ *(pd+1) ^=*(ps+1); }while(0) ++#define XOREQ32BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd ^= *ps; \ ++ *(pd+1) ^=*(ps+1); \ ++ *(pd+2) ^=*(ps+2); \ ++ *(pd+3) ^=*(ps+3); }while(0) ++#define XOREQ32BY4(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ ++ *pd ^= *ps; \ ++ *(pd+1) ^=*(ps+1); \ ++ *(pd+2) ^=*(ps+2); \ ++ *(pd+3) ^=*(ps+3); \ ++ *(pd+4) ^=*(ps+4); \ ++ *(pd+5) ^=*(ps+5); \ ++ *(pd+6) ^=*(ps+6); \ ++ *(pd+7) ^=*(ps+7); }while(0) ++#define XOREQ32BV(d,s) do{ unsigned char *pd=(unsigned char *)(d), *ps=(unsigned char *)(s); \ ++ int z; \ ++ for(z=0;z<32;z++){ \ ++ pd[z]^=ps[z]; \ ++ } \ ++ }while(0) ++ ++#else ++#define XOR_4_BY(d,s1,s2) do{ int *pd=(int *)(d), *ps1=(int *)(s1), *ps2=(int *)(s2); \ ++ *pd = *ps1 ^ *ps2; }while(0) ++#define XOR_8_BY(d,s1,s2) do{ long long int *pd=(long long int *)(d), *ps1=(long long int *)(s1), *ps2=(long long int *)(s2); \ ++ *pd = *ps1 ^ *ps2; }while(0) ++#define XOREQ_4_BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ ++ *pd ^= *ps; }while(0) ++#define XOREQ_8_BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd ^= *ps; }while(0) ++#define COPY_4_BY(d,s) do{ int *pd=(int *)(d), *ps=(int *)(s); \ ++ *pd = *ps; }while(0) ++#define COPY_8_BY(d,s) do{ long long int *pd=(long long int *)(d), *ps=(long long int *)(s); \ ++ *pd = *ps; }while(0) ++ ++#define BEST_SPAN 8 ++#define XOR_BEST_BY(d,s1,s2) do{ XOR_8_BY(d,s1,s2); }while(0); ++#define XOREQ_BEST_BY(d,s) do{ XOREQ_8_BY(d,s); }while(0); ++#define COPY_BEST_BY(d,s) do{ COPY_8_BY(d,s); }while(0); ++ ++#define END_MM do{ }while(0); ++#endif +diff -ruNp trunk.patches/ffdecsa/parallel_std_def.h trunk/ffdecsa/parallel_std_def.h +--- trunk.patches/ffdecsa/parallel_std_def.h 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/parallel_std_def.h 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,29 @@ ++/* FFdecsa -- fast decsa algorithm ++ * ++ * Copyright (C) 2003-2004 fatih89r ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#define FFXOR(a,b) ((a)^(b)) ++#define FFAND(a,b) ((a)&(b)) ++#define FFOR(a,b) ((a)|(b)) ++#define FFNOT(a) (~(a)) ++ ++#define B_FFAND(a,b) ((a)&(b)) ++#define B_FFOR(a,b) ((a)|(b)) ++#define B_FFXOR(a,b) ((a)^(b)) ++#define B_FFSH8L(a,n) ((a)<<(n)) ++#define B_FFSH8R(a,n) ((a)>>(n)) +diff -ruNp trunk.patches/ffdecsa/stream.c trunk/ffdecsa/stream.c +--- trunk.patches/ffdecsa/stream.c 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/ffdecsa/stream.c 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,906 @@ ++/* FFdecsa -- fast decsa algorithm ++ * ++ * Copyright (C) 2003-2004 fatih89r ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++ ++ ++// define statics only once, when STREAM_INIT ++#ifdef STREAM_INIT ++struct stream_regs { ++ group A[32+10][4]; // 32 because we will move back (virtual shift register) ++ group B[32+10][4]; // 32 because we will move back (virtual shift register) ++ group X[4]; ++ group Y[4]; ++ group Z[4]; ++ group D[4]; ++ group E[4]; ++ group F[4]; ++ group p; ++ group q; ++ group r; ++ }; ++ ++static inline void trasp64_32_88ccw(unsigned char *data){ ++/* 64 rows of 32 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ ++#define row ((unsigned int *)data) ++ int i,j; ++ for(j=0;j<64;j+=32){ ++ unsigned int t,b; ++ for(i=0;i<16;i++){ ++ t=row[j+i]; ++ b=row[j+16+i]; ++ row[j+i] = (t&0x0000ffff) | ((b )<<16); ++ row[j+16+i]=((t )>>16) | (b&0xffff0000) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned int t,b; ++ for(i=0;i<8;i++){ ++ t=row[j+i]; ++ b=row[j+8+i]; ++ row[j+i] = (t&0x00ff00ff) | ((b&0x00ff00ff)<<8); ++ row[j+8+i] =((t&0xff00ff00)>>8) | (b&0xff00ff00); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned int t,b; ++ for(i=0;i<4;i++){ ++ t=row[j+i]; ++ b=row[j+4+i]; ++ row[j+i] =((t&0x0f0f0f0f)<<4) | (b&0x0f0f0f0f); ++ row[j+4+i] = (t&0xf0f0f0f0) | ((b&0xf0f0f0f0)>>4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned int t,b; ++ for(i=0;i<2;i++){ ++ t=row[j+i]; ++ b=row[j+2+i]; ++ row[j+i] =((t&0x33333333)<<2) | (b&0x33333333); ++ row[j+2+i] = (t&0xcccccccc) | ((b&0xcccccccc)>>2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned int t,b; ++ for(i=0;i<1;i++){ ++ t=row[j+i]; ++ b=row[j+1+i]; ++ row[j+i] =((t&0x55555555)<<1) | (b&0x55555555); ++ row[j+1+i] = (t&0xaaaaaaaa) | ((b&0xaaaaaaaa)>>1); ++ } ++ } ++#undef row ++} ++ ++static inline void trasp64_32_88cw(unsigned char *data){ ++/* 64 rows of 32 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ ++#define row ((unsigned int *)data) ++ int i,j; ++ for(j=0;j<64;j+=32){ ++ unsigned int t,b; ++ for(i=0;i<16;i++){ ++ t=row[j+i]; ++ b=row[j+16+i]; ++ row[j+i] = (t&0x0000ffff) | ((b )<<16); ++ row[j+16+i]=((t )>>16) | (b&0xffff0000) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned int t,b; ++ for(i=0;i<8;i++){ ++ t=row[j+i]; ++ b=row[j+8+i]; ++ row[j+i] = (t&0x00ff00ff) | ((b&0x00ff00ff)<<8); ++ row[j+8+i] =((t&0xff00ff00)>>8) | (b&0xff00ff00); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned int t,b; ++ for(i=0;i<4;i++){ ++ t=row[j+i]; ++ b=row[j+4+i]; ++ row[j+i] =((t&0xf0f0f0f0)>>4) | (b&0xf0f0f0f0); ++ row[j+4+i]= (t&0x0f0f0f0f) | ((b&0x0f0f0f0f)<<4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned int t,b; ++ for(i=0;i<2;i++){ ++ t=row[j+i]; ++ b=row[j+2+i]; ++ row[j+i] =((t&0xcccccccc)>>2) | (b&0xcccccccc); ++ row[j+2+i]= (t&0x33333333) | ((b&0x33333333)<<2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned int t,b; ++ for(i=0;i<1;i++){ ++ t=row[j+i]; ++ b=row[j+1+i]; ++ row[j+i] =((t&0xaaaaaaaa)>>1) | (b&0xaaaaaaaa); ++ row[j+1+i]= (t&0x55555555) | ((b&0x55555555)<<1); ++ } ++ } ++#undef row ++} ++ ++//64-64---------------------------------------------------------- ++static inline void trasp64_64_88ccw(unsigned char *data){ ++/* 64 rows of 64 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ ++#define row ((unsigned long long int *)data) ++ int i,j; ++ for(j=0;j<64;j+=64){ ++ unsigned long long int t,b; ++ for(i=0;i<32;i++){ ++ t=row[j+i]; ++ b=row[j+32+i]; ++ row[j+i] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ row[j+32+i]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=32){ ++ unsigned long long int t,b; ++ for(i=0;i<16;i++){ ++ t=row[j+i]; ++ b=row[j+16+i]; ++ row[j+i] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ row[j+16+i]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned long long int t,b; ++ for(i=0;i<8;i++){ ++ t=row[j+i]; ++ b=row[j+8+i]; ++ row[j+i] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ row[j+8+i] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned long long int t,b; ++ for(i=0;i<4;i++){ ++ t=row[j+i]; ++ b=row[j+4+i]; ++ row[j+i] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); ++ row[j+4+i] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned long long int t,b; ++ for(i=0;i<2;i++){ ++ t=row[j+i]; ++ b=row[j+2+i]; ++ row[j+i] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); ++ row[j+2+i] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned long long int t,b; ++ for(i=0;i<1;i++){ ++ t=row[j+i]; ++ b=row[j+1+i]; ++ row[j+i] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); ++ row[j+1+i] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); ++ } ++ } ++#undef row ++} ++ ++static inline void trasp64_64_88cw(unsigned char *data){ ++/* 64 rows of 64 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ ++#define row ((unsigned long long int *)data) ++ int i,j; ++ for(j=0;j<64;j+=64){ ++ unsigned long long int t,b; ++ for(i=0;i<32;i++){ ++ t=row[j+i]; ++ b=row[j+32+i]; ++ row[j+i] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ row[j+32+i]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=32){ ++ unsigned long long int t,b; ++ for(i=0;i<16;i++){ ++ t=row[j+i]; ++ b=row[j+16+i]; ++ row[j+i] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ row[j+16+i]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned long long int t,b; ++ for(i=0;i<8;i++){ ++ t=row[j+i]; ++ b=row[j+8+i]; ++ row[j+i] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ row[j+8+i] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned long long int t,b; ++ for(i=0;i<4;i++){ ++ t=row[j+i]; ++ b=row[j+4+i]; ++ row[j+i] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); ++ row[j+4+i] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned long long int t,b; ++ for(i=0;i<2;i++){ ++ t=row[j+i]; ++ b=row[j+2+i]; ++ row[j+i] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); ++ row[j+2+i] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned long long int t,b; ++ for(i=0;i<1;i++){ ++ t=row[j+i]; ++ b=row[j+1+i]; ++ row[j+i] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); ++ row[j+1+i] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); ++ } ++ } ++#undef row ++} ++ ++//64-128---------------------------------------------------------- ++static inline void trasp64_128_88ccw(unsigned char *data){ ++/* 64 rows of 128 bits transposition (bytes transp. - 8x8 rotate counterclockwise)*/ ++#define halfrow ((unsigned long long int *)data) ++ int i,j; ++ for(j=0;j<64;j+=64){ ++ unsigned long long int t,b; ++ for(i=0;i<32;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+32+i)]; ++ halfrow[2*(j+i)] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ halfrow[2*(j+32+i)]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+32+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ halfrow[2*(j+32+i)+1]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=32){ ++ unsigned long long int t,b; ++ for(i=0;i<16;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+16+i)]; ++ halfrow[2*(j+i)] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ halfrow[2*(j+16+i)]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+16+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ halfrow[2*(j+16+i)+1]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned long long int t,b; ++ for(i=0;i<8;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+8+i)]; ++ halfrow[2*(j+i)] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ halfrow[2*(j+8+i)] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+8+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ halfrow[2*(j+8+i)+1] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned long long int t,b; ++ for(i=0;i<4;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+4+i)]; ++ halfrow[2*(j+i)] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); ++ halfrow[2*(j+4+i)] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+4+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0x0f0f0f0f0f0f0f0fULL)<<4) | (b&0x0f0f0f0f0f0f0f0fULL); ++ halfrow[2*(j+4+i)+1] = (t&0xf0f0f0f0f0f0f0f0ULL) | ((b&0xf0f0f0f0f0f0f0f0ULL)>>4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned long long int t,b; ++ for(i=0;i<2;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+2+i)]; ++ halfrow[2*(j+i)] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); ++ halfrow[2*(j+2+i)] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+2+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0x3333333333333333ULL)<<2) | (b&0x3333333333333333ULL); ++ halfrow[2*(j+2+i)+1] = (t&0xccccccccccccccccULL) | ((b&0xccccccccccccccccULL)>>2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned long long int t,b; ++ for(i=0;i<1;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+1+i)]; ++ halfrow[2*(j+i)] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); ++ halfrow[2*(j+1+i)] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+1+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0x5555555555555555ULL)<<1) | (b&0x5555555555555555ULL); ++ halfrow[2*(j+1+i)+1] = (t&0xaaaaaaaaaaaaaaaaULL) | ((b&0xaaaaaaaaaaaaaaaaULL)>>1); ++ } ++ } ++#undef halfrow ++} ++ ++static inline void trasp64_128_88cw(unsigned char *data){ ++/* 64 rows of 128 bits transposition (bytes transp. - 8x8 rotate clockwise)*/ ++#define halfrow ((unsigned long long int *)data) ++ int i,j; ++ for(j=0;j<64;j+=64){ ++ unsigned long long int t,b; ++ for(i=0;i<32;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+32+i)]; ++ halfrow[2*(j+i)] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ halfrow[2*(j+32+i)]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+32+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x00000000ffffffffULL) | ((b )<<32); ++ halfrow[2*(j+32+i)+1]=((t )>>32) | (b&0xffffffff00000000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=32){ ++ unsigned long long int t,b; ++ for(i=0;i<16;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+16+i)]; ++ halfrow[2*(j+i)] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ halfrow[2*(j+16+i)]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+16+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x0000ffff0000ffffULL) | ((b&0x0000ffff0000ffffULL)<<16); ++ halfrow[2*(j+16+i)+1]=((t&0xffff0000ffff0000ULL)>>16) | (b&0xffff0000ffff0000ULL) ; ++ } ++ } ++ for(j=0;j<64;j+=16){ ++ unsigned long long int t,b; ++ for(i=0;i<8;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+8+i)]; ++ halfrow[2*(j+i)] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ halfrow[2*(j+8+i)] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+8+i)+1]; ++ halfrow[2*(j+i)+1] = (t&0x00ff00ff00ff00ffULL) | ((b&0x00ff00ff00ff00ffULL)<<8); ++ halfrow[2*(j+8+i)+1] =((t&0xff00ff00ff00ff00ULL)>>8) | (b&0xff00ff00ff00ff00ULL); ++ } ++ } ++ for(j=0;j<64;j+=8){ ++ unsigned long long int t,b; ++ for(i=0;i<4;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+4+i)]; ++ halfrow[2*(j+i)] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); ++ halfrow[2*(j+4+i)] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+4+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0xf0f0f0f0f0f0f0f0ULL)>>4) | (b&0xf0f0f0f0f0f0f0f0ULL); ++ halfrow[2*(j+4+i)+1] = (t&0x0f0f0f0f0f0f0f0fULL) | ((b&0x0f0f0f0f0f0f0f0fULL)<<4); ++ } ++ } ++ for(j=0;j<64;j+=4){ ++ unsigned long long int t,b; ++ for(i=0;i<2;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+2+i)]; ++ halfrow[2*(j+i)] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); ++ halfrow[2*(j+2+i)] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+2+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0xccccccccccccccccULL)>>2) | (b&0xccccccccccccccccULL); ++ halfrow[2*(j+2+i)+1] = (t&0x3333333333333333ULL) | ((b&0x3333333333333333ULL)<<2); ++ } ++ } ++ for(j=0;j<64;j+=2){ ++ unsigned long long int t,b; ++ for(i=0;i<1;i++){ ++ t=halfrow[2*(j+i)]; ++ b=halfrow[2*(j+1+i)]; ++ halfrow[2*(j+i)] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); ++ halfrow[2*(j+1+i)] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); ++ t=halfrow[2*(j+i)+1]; ++ b=halfrow[2*(j+1+i)+1]; ++ halfrow[2*(j+i)+1] =((t&0xaaaaaaaaaaaaaaaaULL)>>1) | (b&0xaaaaaaaaaaaaaaaaULL); ++ halfrow[2*(j+1+i)+1] = (t&0x5555555555555555ULL) | ((b&0x5555555555555555ULL)<<1); ++ } ++ } ++#undef halfrow ++} ++#endif ++ ++ ++#ifdef STREAM_INIT ++void stream_cypher_group_init( ++ struct stream_regs *regs, ++ group iA[8][4], // [In] iA00,iA01,...iA73 32 groups | Derived from key. ++ group iB[8][4], // [In] iB00,iB01,...iB73 32 groups | Derived from key. ++ unsigned char *sb) // [In] (SB0,SB1,...SB7)...x32 32*8 bytes | Extra input. ++#endif ++#ifdef STREAM_NORMAL ++void stream_cypher_group_normal( ++ struct stream_regs *regs, ++ unsigned char *cb) // [Out] (CB0,CB1,...CB7)...x32 32*8 bytes | Output. ++#endif ++{ ++#ifdef STREAM_INIT ++ group in1[4]; ++ group in2[4]; ++#endif ++ group extra_B[4]; ++ group fa,fb,fc,fd,fe; ++ group s1a,s1b,s2a,s2b,s3a,s3b,s4a,s4b,s5a,s5b,s6a,s6b,s7a,s7b; ++ group next_E[4]; ++ group tmp0,tmp1,tmp2,tmp3,tmp4; ++#ifdef STREAM_INIT ++ group *sb_g=(group *)sb; ++#endif ++#ifdef STREAM_NORMAL ++ group *cb_g=(group *)cb; ++#endif ++ int aboff; ++ int i,j,k,b; ++ int dbg; ++ ++#ifdef STREAM_INIT ++ DBG(fprintf(stderr,":::::::::: BEGIN STREAM INIT\n")); ++#endif ++#ifdef STREAM_NORMAL ++ DBG(fprintf(stderr,":::::::::: BEGIN STREAM NORMAL\n")); ++#endif ++#ifdef STREAM_INIT ++for(j=0;j<64;j++){ ++ DBG(fprintf(stderr,"precall prerot stream_in[%2i]=",j)); ++ DBG(dump_mem("",sb+BYPG*j,BYPG,BYPG)); ++} ++ ++DBG(dump_mem("stream_prerot ",sb,GROUP_PARALLELISM*8,BYPG)); ++#if GROUP_PARALLELISM==32 ++trasp64_32_88ccw(sb); ++#endif ++#if GROUP_PARALLELISM==64 ++trasp64_64_88ccw(sb); ++#endif ++#if GROUP_PARALLELISM==128 ++trasp64_128_88ccw(sb); ++#endif ++DBG(dump_mem("stream_postrot",sb,GROUP_PARALLELISM*8,BYPG)); ++ ++for(j=0;j<64;j++){ ++ DBG(fprintf(stderr,"precall stream_in[%2i]=",j)); ++ DBG(dump_mem("",sb+BYPG*j,BYPG,BYPG)); ++} ++#endif ++ ++ aboff=32; ++ ++#ifdef STREAM_INIT ++ // load first 32 bits of ck into A[aboff+0]..A[aboff+7] ++ // load last 32 bits of ck into B[aboff+0]..B[aboff+7] ++ // all other regs = 0 ++ for(i=0;i<8;i++){ ++ for(b=0;b<4;b++){ ++DBG(fprintf(stderr,"dbg from iA A[%i][%i]=",i,b)); ++DBG(dump_mem("",(unsigned char *)&iA[i][b],BYPG,BYPG)); ++DBG(fprintf(stderr," dbg from iB B[%i][%i]=",i,b)); ++DBG(dump_mem("",(unsigned char *)&iB[i][b],BYPG,BYPG)); ++ regs->A[aboff+i][b]=iA[i][b]; ++ regs->B[aboff+i][b]=iB[i][b]; ++ } ++ } ++ for(b=0;b<4;b++){ ++ regs->A[aboff+8][b]=FF0(); ++ regs->A[aboff+9][b]=FF0(); ++ regs->B[aboff+8][b]=FF0(); ++ regs->B[aboff+9][b]=FF0(); ++ } ++ for(b=0;b<4;b++){ ++ regs->X[b]=FF0(); ++ regs->Y[b]=FF0(); ++ regs->Z[b]=FF0(); ++ regs->D[b]=FF0(); ++ regs->E[b]=FF0(); ++ regs->F[b]=FF0(); ++ } ++ regs->p=FF0(); ++ regs->q=FF0(); ++ regs->r=FF0(); ++#endif ++ ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"dbg A0[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->A[aboff+0][dbg],BYPG,BYPG)); ++ DBG(fprintf(stderr,"dbg B0[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->B[aboff+0][dbg],BYPG,BYPG)); ++} ++ ++//////////////////////////////////////////////////////////////////////////////// ++ ++ // EXTERNAL LOOP - 8 bytes per operation ++ for(i=0;i<8;i++){ ++ ++ DBG(fprintf(stderr,"--BEGIN EXTERNAL LOOP %i\n",i)); ++ ++#ifdef STREAM_INIT ++ for(b=0;b<4;b++){ ++ in1[b]=sb_g[8*i+4+b]; ++ in2[b]=sb_g[8*i+b]; ++ } ++#endif ++ ++ // INTERNAL LOOP - 2 bits per iteration ++ for(j=0; j<4; j++){ ++ ++ DBG(fprintf(stderr,"---BEGIN INTERNAL LOOP %i (EXT %i, INT %i)\n",j,i,j)); ++ ++ // from A0..A9, 35 bits are selected as inputs to 7 s-boxes ++ // 5 bits input per s-box, 2 bits output per s-box ++ ++ // we can select bits with zero masking and shifting operations ++ // and synthetize s-boxes with optimized boolean functions. ++ // this is the actual reason we do all the crazy transposition ++ // stuff to switch between normal and bit slice representations. ++ // this code really flies. ++ ++ fe=regs->A[aboff+3][0];fa=regs->A[aboff+0][2];fb=regs->A[aboff+5][1];fc=regs->A[aboff+6][3];fd=regs->A[aboff+8][0]; ++/* 1000 1110 1110 0001 : lev 7: */ //tmp0=( fa^( fb^( ( ( ( fa|fb )^fc )|( fc^fd ) )^ALL_ONES ) ) ); ++/* 1110 0010 0011 0011 : lev 6: */ //tmp1=( ( fa|fb )^( ( fc&( fa|( fb^fd ) ) )^ALL_ONES ) ); ++/* 0011 0110 1000 1101 : lev 5: */ //tmp2=( fa^( ( fb&fd )^( ( fa&fd )|fc ) ) ); ++/* 0101 0101 1001 0011 : lev 5: */ //tmp3=( ( fa&fc )^( fa^( ( fa&fb )|fd ) ) ); ++/* 1000 1110 1110 0001 : lev 7: */ tmp0=FFXOR(fa,FFXOR(fb,FFXOR(FFOR(FFXOR(FFOR(fa,fb),fc),FFXOR(fc,fd)),FF1()))); ++/* 1110 0010 0011 0011 : lev 6: */ tmp1=FFXOR(FFOR(fa,fb),FFXOR(FFAND(fc,FFOR(fa,FFXOR(fb,fd))),FF1())); ++/* 0011 0110 1000 1101 : lev 5: */ tmp2=FFXOR(fa,FFXOR(FFAND(fb,fd),FFOR(FFAND(fa,fd),fc))); ++/* 0101 0101 1001 0011 : lev 5: */ tmp3=FFXOR(FFAND(fa,fc),FFXOR(fa,FFOR(FFAND(fa,fb),fd))); ++ s1a=FFXOR(tmp0,FFAND(fe,tmp1)); ++ s1b=FFXOR(tmp2,FFAND(fe,tmp3)); ++//dump_mem("s1as1b-fe",&fe,BYPG,BYPG); ++//dump_mem("s1as1b-fa",&fa,BYPG,BYPG); ++//dump_mem("s1as1b-fb",&fb,BYPG,BYPG); ++//dump_mem("s1as1b-fc",&fc,BYPG,BYPG); ++//dump_mem("s1as1b-fd",&fd,BYPG,BYPG); ++ ++ fe=regs->A[aboff+1][1];fa=regs->A[aboff+2][2];fb=regs->A[aboff+5][3];fc=regs->A[aboff+6][0];fd=regs->A[aboff+8][1]; ++/* 1001 1110 0110 0001 : lev 6: */ //tmp0=( fa^( ( fb&( fc|fd ) )^( fc^( fd^ALL_ONES ) ) ) ); ++/* 0000 0011 0111 1011 : lev 5: */ //tmp1=( ( fa&( fb^fd ) )|( ( fa|fb )&fc ) ); ++/* 1100 0110 1101 0010 : lev 6: */ //tmp2=( ( fb&fd )^( ( fa&fd )|( fb^( fc^ALL_ONES ) ) ) ); ++/* 0001 1110 1111 0101 : lev 5: */ //tmp3=( ( fa&fd )|( fa^( fb^( fc&fd ) ) ) ); ++/* 1001 1110 0110 0001 : lev 6: */ tmp0=FFXOR(fa,FFXOR(FFAND(fb,FFOR(fc,fd)),FFXOR(fc,FFXOR(fd,FF1())))); ++/* 0000 0011 0111 1011 : lev 5: */ tmp1=FFOR(FFAND(fa,FFXOR(fb,fd)),FFAND(FFOR(fa,fb),fc)); ++/* 1100 0110 1101 0010 : lev 6: */ tmp2=FFXOR(FFAND(fb,fd),FFOR(FFAND(fa,fd),FFXOR(fb,FFXOR(fc,FF1())))); ++/* 0001 1110 1111 0101 : lev 5: */ tmp3=FFOR(FFAND(fa,fd),FFXOR(fa,FFXOR(fb,FFAND(fc,fd)))); ++ s2a=FFXOR(tmp0,FFAND(fe,tmp1)); ++ s2b=FFXOR(tmp2,FFAND(fe,tmp3)); ++ ++ fe=regs->A[aboff+0][3];fa=regs->A[aboff+1][0];fb=regs->A[aboff+4][1];fc=regs->A[aboff+4][3];fd=regs->A[aboff+5][2]; ++/* 0100 1011 1001 0110 : lev 5: */ //tmp0=( fa^( fb^( ( fc&( fa|fd ) )^fd ) ) ); ++/* 1101 0101 1000 1100 : lev 7: */ //tmp1=( ( fa&fc )^( ( fa^fd )|( ( fb|fc )^( fd^ALL_ONES ) ) ) ); ++/* 0010 0111 1101 1000 : lev 4: */ //tmp2=( fa^( ( ( fb^fc )&fd )^fc ) ); ++/* 1111 1111 1111 1111 : lev 0: */ //tmp3=ALL_ONES; ++/* 0100 1011 1001 0110 : lev 5: */ tmp0=FFXOR(fa,FFXOR(fb,FFXOR(FFAND(fc,FFOR(fa,fd)),fd))); ++/* 1101 0101 1000 1100 : lev 7: */ tmp1=FFXOR(FFAND(fa,fc),FFOR(FFXOR(fa,fd),FFXOR(FFOR(fb,fc),FFXOR(fd,FF1())))); ++/* 0010 0111 1101 1000 : lev 4: */ tmp2=FFXOR(fa,FFXOR(FFAND(FFXOR(fb,fc),fd),fc)); ++/* 1111 1111 1111 1111 : lev 0: */ tmp3=FF1(); ++ s3a=FFXOR(tmp0,FFAND(FFNOT(fe),tmp1)); ++ s3b=FFXOR(tmp2,FFAND(fe,tmp3)); ++ ++ fe=regs->A[aboff+2][3];fa=regs->A[aboff+0][1];fb=regs->A[aboff+1][3];fc=regs->A[aboff+3][2];fd=regs->A[aboff+7][0]; ++/* 1011 0101 0100 1001 : lev 7: */ //tmp0=( fa^( ( fc&( fa^fd ) )|( fb^( fc|( fd^ALL_ONES ) ) ) ) ); ++/* 0010 1101 0110 0110 : lev 6: */ //tmp1=( ( fa&fb )^( fb^( ( ( fa|fc )&fd )^fc ) ) ); ++/* 0110 0111 1101 0000 : lev 7: */ //tmp2=( fa^( ( fb&fc )|( ( ( fa&( fb^fd ) )|fc )^fd ) ) ); ++/* 1111 1111 1111 1111 : lev 0: */ //tmp3=ALL_ONES; ++/* 1011 0101 0100 1001 : lev 7: */ tmp0=FFXOR(fa,FFOR(FFAND(fc,FFXOR(fa,fd)),FFXOR(fb,FFOR(fc,FFXOR(fd,FF1()))))); ++/* 0010 1101 0110 0110 : lev 6: */ tmp1=FFXOR(FFAND(fa,fb),FFXOR(fb,FFXOR(FFAND(FFOR(fa,fc),fd),fc))); ++/* 0110 0111 1101 0000 : lev 7: */ tmp2=FFXOR(fa,FFOR(FFAND(fb,fc),FFXOR(FFOR(FFAND(fa,FFXOR(fb,fd)),fc),fd))); ++/* 1111 1111 1111 1111 : lev 0: */ tmp3=FF1(); ++ s4a=FFXOR(tmp0,FFAND(fe,FFXOR(tmp1,tmp0))); ++ s4b=FFXOR(FFXOR(s4a,tmp2),FFAND(fe,tmp3)); ++ ++ fe=regs->A[aboff+4][2];fa=regs->A[aboff+3][3];fb=regs->A[aboff+5][0];fc=regs->A[aboff+7][1];fd=regs->A[aboff+8][2]; ++/* 1000 1111 0011 0010 : lev 7: */ //tmp0=( ( ( fa&( fb|fc ) )^fb )|( ( ( fa^fc )|fd )^ALL_ONES ) ); ++/* 0110 1011 0000 1011 : lev 6: */ //tmp1=( fb^( ( fc^fd )&( fc^( fb|( fa^fd ) ) ) ) ); ++/* 0001 1010 0111 1001 : lev 6: */ //tmp2=( ( fa&fc )^( fb^( ( fb|( fa^fc ) )&fd ) ) ); ++/* 0101 1101 1101 0101 : lev 4: */ //tmp3=( ( ( fa^fb )&( fc^ALL_ONES ) )|fd ); ++/* 1000 1111 0011 0010 : lev 7: */ tmp0=FFOR(FFXOR(FFAND(fa,FFOR(fb,fc)),fb),FFXOR(FFOR(FFXOR(fa,fc),fd),FF1())); ++/* 0110 1011 0000 1011 : lev 6: */ tmp1=FFXOR(fb,FFAND(FFXOR(fc,fd),FFXOR(fc,FFOR(fb,FFXOR(fa,fd))))); ++/* 0001 1010 0111 1001 : lev 6: */ tmp2=FFXOR(FFAND(fa,fc),FFXOR(fb,FFAND(FFOR(fb,FFXOR(fa,fc)),fd))); ++/* 0101 1101 1101 0101 : lev 4: */ tmp3=FFOR(FFAND(FFXOR(fa,fb),FFXOR(fc,FF1())),fd); ++ s5a=FFXOR(tmp0,FFAND(fe,tmp1)); ++ s5b=FFXOR(tmp2,FFAND(fe,tmp3)); ++ ++ fe=regs->A[aboff+2][1];fa=regs->A[aboff+3][1];fb=regs->A[aboff+4][0];fc=regs->A[aboff+6][2];fd=regs->A[aboff+8][3]; ++/* 0011 0110 0010 1101 : lev 6: */ //tmp0=( ( ( fa&fc )&fd )^( ( fb&( fa|fd ) )^fc ) ); ++/* 1110 1110 1011 1011 : lev 3: */ //tmp1=( ( ( fa^fc )&fd )^ALL_ONES ); ++/* 0101 1000 0110 0111 : lev 6: */ //tmp2=( ( fa&( fb|fc ) )^( fb^( ( fb&fc )|fd ) ) ); ++/* 0001 0011 0000 0001 : lev 5: */ //tmp3=( fc&( ( fa&( fb^fd ) )^( fb|fd ) ) ); ++/* 0011 0110 0010 1101 : lev 6: */ tmp0=FFXOR(FFAND(FFAND(fa,fc),fd),FFXOR(FFAND(fb,FFOR(fa,fd)),fc)); ++/* 1110 1110 1011 1011 : lev 3: */ tmp1=FFXOR(FFAND(FFXOR(fa,fc),fd),FF1()); ++/* 0101 1000 0110 0111 : lev 6: */ tmp2=FFXOR(FFAND(fa,FFOR(fb,fc)),FFXOR(fb,FFOR(FFAND(fb,fc),fd))); ++/* 0001 0011 0000 0001 : lev 5: */ tmp3=FFAND(fc,FFXOR(FFAND(fa,FFXOR(fb,fd)),FFOR(fb,fd))); ++ s6a=FFXOR(tmp0,FFAND(fe,tmp1)); ++ s6b=FFXOR(tmp2,FFAND(fe,tmp3)); ++ ++ fe=regs->A[aboff+1][2];fa=regs->A[aboff+2][0];fb=regs->A[aboff+6][1];fc=regs->A[aboff+7][2];fd=regs->A[aboff+7][3]; ++/* 0111 1000 1001 0110 : lev 5: */ //tmp0=( fb^( ( fc&fd )|( fa^( fc^fd ) ) ) ); ++/* 0100 1001 0101 1011 : lev 6: */ //tmp1=( ( fb|fd )&( ( fa&fc )|( fb^( fc^fd ) ) ) ); ++/* 0100 1001 1011 1001 : lev 5: */ //tmp2=( ( fa|fb )^( ( fc&( fb|fd ) )^fd ) ); ++/* 1111 1111 1101 1101 : lev 3: */ //tmp3=( fd|( ( fa&fc )^ALL_ONES ) ); ++/* 0111 1000 1001 0110 : lev 5: */ tmp0=FFXOR(fb,FFOR(FFAND(fc,fd),FFXOR(fa,FFXOR(fc,fd)))); ++/* 0100 1001 0101 1011 : lev 6: */ tmp1=FFAND(FFOR(fb,fd),FFOR(FFAND(fa,fc),FFXOR(fb,FFXOR(fc,fd)))); ++/* 0100 1001 1011 1001 : lev 5: */ tmp2=FFXOR(FFOR(fa,fb),FFXOR(FFAND(fc,FFOR(fb,fd)),fd)); ++/* 1111 1111 1101 1101 : lev 3: */ tmp3=FFOR(fd,FFXOR(FFAND(fa,fc),FF1())); ++ s7a=FFXOR(tmp0,FFAND(fe,tmp1)); ++ s7b=FFXOR(tmp2,FFAND(fe,tmp3)); ++ ++ ++/* ++ we have just done this: ++ ++ int sbox1[0x20] = {2,0,1,1,2,3,3,0, 3,2,2,0,1,1,0,3, 0,3,3,0,2,2,1,1, 2,2,0,3,1,1,3,0}; ++ int sbox2[0x20] = {3,1,0,2,2,3,3,0, 1,3,2,1,0,0,1,2, 3,1,0,3,3,2,0,2, 0,0,1,2,2,1,3,1}; ++ int sbox3[0x20] = {2,0,1,2,2,3,3,1, 1,1,0,3,3,0,2,0, 1,3,0,1,3,0,2,2, 2,0,1,2,0,3,3,1}; ++ int sbox4[0x20] = {3,1,2,3,0,2,1,2, 1,2,0,1,3,0,0,3, 1,0,3,1,2,3,0,3, 0,3,2,0,1,2,2,1}; ++ int sbox5[0x20] = {2,0,0,1,3,2,3,2, 0,1,3,3,1,0,2,1, 2,3,2,0,0,3,1,1, 1,0,3,2,3,1,0,2}; ++ int sbox6[0x20] = {0,1,2,3,1,2,2,0, 0,1,3,0,2,3,1,3, 2,3,0,2,3,0,1,1, 2,1,1,2,0,3,3,0}; ++ int sbox7[0x20] = {0,3,2,2,3,0,0,1, 3,0,1,3,1,2,2,1, 1,0,3,3,0,1,1,2, 2,3,1,0,2,3,0,2}; ++ ++ s12 = sbox1[ (((A3>>0)&1)<<4) | (((A0>>2)&1)<<3) | (((A5>>1)&1)<<2) | (((A6>>3)&1)<<1) | (((A8>>0)&1)<<0) ] ++ |sbox2[ (((A1>>1)&1)<<4) | (((A2>>2)&1)<<3) | (((A5>>3)&1)<<2) | (((A6>>0)&1)<<1) | (((A8>>1)&1)<<0) ]; ++ s34 = sbox3[ (((A0>>3)&1)<<4) | (((A1>>0)&1)<<3) | (((A4>>1)&1)<<2) | (((A4>>3)&1)<<1) | (((A5>>2)&1)<<0) ] ++ |sbox4[ (((A2>>3)&1)<<4) | (((A0>>1)&1)<<3) | (((A1>>3)&1)<<2) | (((A3>>2)&1)<<1) | (((A7>>0)&1)<<0) ]; ++ s56 = sbox5[ (((A4>>2)&1)<<4) | (((A3>>3)&1)<<3) | (((A5>>0)&1)<<2) | (((A7>>1)&1)<<1) | (((A8>>2)&1)<<0) ] ++ |sbox6[ (((A2>>1)&1)<<4) | (((A3>>1)&1)<<3) | (((A4>>0)&1)<<2) | (((A6>>2)&1)<<1) | (((A8>>3)&1)<<0) ]; ++ s7 = sbox7[ (((A1>>2)&1)<<4) | (((A2>>0)&1)<<3) | (((A6>>1)&1)<<2) | (((A7>>2)&1)<<1) | (((A7>>3)&1)<<0) ]; ++*/ ++ ++ // use 4x4 xor to produce extra nibble for T3 ++ ++ extra_B[3]=FFXOR(FFXOR(FFXOR(regs->B[aboff+2][0],regs->B[aboff+5][1]),regs->B[aboff+6][2]),regs->B[aboff+8][3]); ++ extra_B[2]=FFXOR(FFXOR(FFXOR(regs->B[aboff+5][0],regs->B[aboff+7][1]),regs->B[aboff+2][3]),regs->B[aboff+3][2]); ++ extra_B[1]=FFXOR(FFXOR(FFXOR(regs->B[aboff+4][3],regs->B[aboff+7][2]),regs->B[aboff+3][0]),regs->B[aboff+4][1]); ++ extra_B[0]=FFXOR(FFXOR(FFXOR(regs->B[aboff+8][2],regs->B[aboff+5][3]),regs->B[aboff+2][1]),regs->B[aboff+7][0]); ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"extra_B[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)&extra_B[dbg],BYPG,BYPG)); ++} ++ ++ // T1 = xor all inputs ++ // in1, in2, D are only used in T1 during initialisation, not generation ++ for(b=0;b<4;b++){ ++ regs->A[aboff-1][b]=FFXOR(regs->A[aboff+9][b],regs->X[b]); ++ } ++ ++#ifdef STREAM_INIT ++ for(b=0;b<4;b++){ ++ regs->A[aboff-1][b]=FFXOR(FFXOR(regs->A[aboff-1][b],regs->D[b]),((j % 2) ? in2[b] : in1[b])); ++ } ++#endif ++ ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"next_A0[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->A[aboff-1][dbg],BYPG,BYPG)); ++} ++ ++ // T2 = xor all inputs ++ // in1, in2 are only used in T1 during initialisation, not generation ++ // if p=0, use this, if p=1, rotate the result left ++ for(b=0;b<4;b++){ ++ regs->B[aboff-1][b]=FFXOR(FFXOR(regs->B[aboff+6][b],regs->B[aboff+9][b]),regs->Y[b]); ++ } ++ ++#ifdef STREAM_INIT ++ for(b=0;b<4;b++){ ++ regs->B[aboff-1][b]=FFXOR(regs->B[aboff-1][b],((j % 2) ? in1[b] : in2[b])); ++ } ++#endif ++ ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"next_B0[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->B[aboff-1][dbg],BYPG,BYPG)); ++} ++ ++ // if p=1, rotate left (yes, this is what we're doing) ++ tmp3=regs->B[aboff-1][3]; ++ regs->B[aboff-1][3]=FFXOR(regs->B[aboff-1][3],FFAND(FFXOR(regs->B[aboff-1][3],regs->B[aboff-1][2]),regs->p)); ++ regs->B[aboff-1][2]=FFXOR(regs->B[aboff-1][2],FFAND(FFXOR(regs->B[aboff-1][2],regs->B[aboff-1][1]),regs->p)); ++ regs->B[aboff-1][1]=FFXOR(regs->B[aboff-1][1],FFAND(FFXOR(regs->B[aboff-1][1],regs->B[aboff-1][0]),regs->p)); ++ regs->B[aboff-1][0]=FFXOR(regs->B[aboff-1][0],FFAND(FFXOR(regs->B[aboff-1][0],tmp3),regs->p)); ++ ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"next_B0[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->B[aboff-1][dbg],BYPG,BYPG)); ++} ++ ++ // T3 = xor all inputs ++ for(b=0;b<4;b++){ ++ regs->D[b]=FFXOR(FFXOR(regs->E[b],regs->Z[b]),extra_B[b]); ++ } ++ ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"D[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->D[dbg],BYPG,BYPG)); ++} ++ ++ // T4 = sum, carry of Z + E + r ++ for(b=0;b<4;b++){ ++ next_E[b]=regs->F[b]; ++ } ++ ++ tmp0=FFXOR(regs->Z[0],regs->E[0]); ++ tmp1=FFAND(regs->Z[0],regs->E[0]); ++ regs->F[0]=FFXOR(regs->E[0],FFAND(regs->q,FFXOR(regs->Z[0],regs->r))); ++ tmp3=FFAND(tmp0,regs->r); ++ tmp4=FFOR(tmp1,tmp3); ++ ++ tmp0=FFXOR(regs->Z[1],regs->E[1]); ++ tmp1=FFAND(regs->Z[1],regs->E[1]); ++ regs->F[1]=FFXOR(regs->E[1],FFAND(regs->q,FFXOR(regs->Z[1],tmp4))); ++ tmp3=FFAND(tmp0,tmp4); ++ tmp4=FFOR(tmp1,tmp3); ++ ++ tmp0=FFXOR(regs->Z[2],regs->E[2]); ++ tmp1=FFAND(regs->Z[2],regs->E[2]); ++ regs->F[2]=FFXOR(regs->E[2],FFAND(regs->q,FFXOR(regs->Z[2],tmp4))); ++ tmp3=FFAND(tmp0,tmp4); ++ tmp4=FFOR(tmp1,tmp3); ++ ++ tmp0=FFXOR(regs->Z[3],regs->E[3]); ++ tmp1=FFAND(regs->Z[3],regs->E[3]); ++ regs->F[3]=FFXOR(regs->E[3],FFAND(regs->q,FFXOR(regs->Z[3],tmp4))); ++ tmp3=FFAND(tmp0,tmp4); ++ regs->r=FFXOR(regs->r,FFAND(regs->q,FFXOR(FFOR(tmp1,tmp3),regs->r))); // ultimate carry ++ ++/* ++ we have just done this: (believe it or not) ++ ++ if (q) { ++ F = Z + E + r; ++ r = (F >> 4) & 1; ++ F = F & 0x0f; ++ } ++ else { ++ F = E; ++ } ++*/ ++ for(b=0;b<4;b++){ ++ regs->E[b]=next_E[b]; ++ } ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"F[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->F[dbg],BYPG,BYPG)); ++} ++DBG(fprintf(stderr,"r=")); ++DBG(dump_mem("",(unsigned char *)®s->r,BYPG,BYPG)); ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"E[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->E[dbg],BYPG,BYPG)); ++} ++ ++ // this simple instruction is virtually shifting all the shift registers ++ aboff--; ++ ++/* ++ we've just done this: ++ ++ A9=A8;A8=A7;A7=A6;A6=A5;A5=A4;A4=A3;A3=A2;A2=A1;A1=A0;A0=next_A0; ++ B9=B8;B8=B7;B7=B6;B6=B5;B5=B4;B4=B3;B3=B2;B2=B1;B1=B0;B0=next_B0; ++*/ ++ ++ regs->X[0]=s1a; ++ regs->X[1]=s2a; ++ regs->X[2]=s3b; ++ regs->X[3]=s4b; ++ regs->Y[0]=s3a; ++ regs->Y[1]=s4a; ++ regs->Y[2]=s5b; ++ regs->Y[3]=s6b; ++ regs->Z[0]=s5a; ++ regs->Z[1]=s6a; ++ regs->Z[2]=s1b; ++ regs->Z[3]=s2b; ++ regs->p=s7a; ++ regs->q=s7b; ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"X[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->X[dbg],BYPG,BYPG)); ++} ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"Y[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->Y[dbg],BYPG,BYPG)); ++} ++for(dbg=0;dbg<4;dbg++){ ++ DBG(fprintf(stderr,"Z[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)®s->Z[dbg],BYPG,BYPG)); ++} ++DBG(fprintf(stderr,"p=")); ++DBG(dump_mem("",(unsigned char *)®s->p,BYPG,BYPG)); ++DBG(fprintf(stderr,"q=")); ++DBG(dump_mem("",(unsigned char *)®s->q,BYPG,BYPG)); ++ ++#ifdef STREAM_NORMAL ++ // require 4 loops per output byte ++ // 2 output bits are a function of the 4 bits of D ++ // xor 2 by 2 ++ cb_g[8*i+7-2*j]=FFXOR(regs->D[2],regs->D[3]); ++ cb_g[8*i+6-2*j]=FFXOR(regs->D[0],regs->D[1]); ++for(dbg=0;dbg<8;dbg++){ ++ DBG(fprintf(stderr,"op[%i]=",dbg)); ++ DBG(dump_mem("",(unsigned char *)&cb_g[8*i+dbg],BYPG,BYPG)); ++} ++#endif ++ ++DBG(fprintf(stderr,"---END INTERNAL LOOP\n")); ++ ++ } // INTERNAL LOOP ++ ++DBG(fprintf(stderr,"--END EXTERNAL LOOP\n")); ++ ++ } // EXTERNAL LOOP ++ ++ // move 32 steps forward, ready for next call ++ for(k=0;k<10;k++){ ++ for(b=0;b<4;b++){ ++DBG(fprintf(stderr,"moving forward AB k=%i b=%i\n",k,b)); ++ regs->A[32+k][b]=regs->A[k][b]; ++ regs->B[32+k][b]=regs->B[k][b]; ++ } ++ } ++ ++ ++//////////////////////////////////////////////////////////////////////////////// ++ ++#ifdef STREAM_NORMAL ++for(j=0;j<64;j++){ ++ DBG(fprintf(stderr,"postcall prerot cb[%2i]=",j)); ++ DBG(dump_mem("",(unsigned char *)(cb+BYPG*j),BYPG,BYPG)); ++} ++ ++#if GROUP_PARALLELISM==32 ++trasp64_32_88cw(cb); ++#endif ++#if GROUP_PARALLELISM==64 ++trasp64_64_88cw(cb); ++#endif ++#if GROUP_PARALLELISM==128 ++trasp64_128_88cw(cb); ++#endif ++ ++for(j=0;j<64;j++){ ++ DBG(fprintf(stderr,"postcall postrot cb[%2i]=",j)); ++ DBG(dump_mem("",(unsigned char *)(cb+BYPG*j),BYPG,BYPG)); ++} ++#endif ++ ++#ifdef STREAM_INIT ++ DBG(fprintf(stderr,":::::::::: END STREAM INIT\n")); ++#endif ++#ifdef STREAM_NORMAL ++ DBG(fprintf(stderr,":::::::::: END STREAM NORMAL\n")); ++#endif ++ ++} ++ +diff -ruNp trunk.patches/globals.h trunk/globals.h +--- trunk.patches/globals.h 2018-04-03 03:02:59.558440627 +0300 ++++ trunk/globals.h 2018-04-03 03:20:07.658045369 +0300 +@@ -392,17 +392,17 @@ typedef unsigned char uchar; + #define CS_ECM_RINGBUFFER_MAX 0x10 // max size for ECM last responsetimes ringbuffer. Keep this set to power of 2 values! + + // Support for multiple CWs per channel and other encryption algos +-//#define WITH_EXTENDED_CW 1 ++#define WITH_EXTENDED_CW 1 + + #if defined(READER_DRE) || defined(READER_DRECAS) || defined(READER_VIACCESS) + #define MAX_ECM_SIZE 1024 + #define MAX_EMM_SIZE 1024 + #else +-#define MAX_ECM_SIZE 596 +-#define MAX_EMM_SIZE 512 ++#define MAX_ECM_SIZE 1024 ++#define MAX_EMM_SIZE 1024 + #endif + +-#define CS_EMMCACHESIZE 512 //nr of EMMs that each reader will cache ++#define CS_EMMCACHESIZE 1024 //nr of EMMs that each reader will cache + #define MSGLOGSIZE 64 //size of string buffer for a ecm to return messages + + #define D_TRACE 0x0001 // Generate very detailed error/trace messages per routine +@@ -434,6 +434,7 @@ typedef unsigned char uchar; + #define R_SMART 0x7 // Smartreader+ + #define R_PCSC 0x8 // PCSC + #define R_DRECAS 0x9 // Reader DRECAS ++#define R_EMU 0x17 // Reader EMU + /////////////////// proxy readers after R_CS378X + #define R_CAMD35 0x20 // Reader cascading camd 3.5x + #define R_CAMD33 0x21 // Reader cascading camd 3.3x +@@ -861,6 +862,13 @@ typedef struct s_entitlement + uint32_t class; // the class needed for some systems + time_t start; // startdate + time_t end; // enddate ++#ifdef WITH_EMU ++ bool isKey; ++ bool isData; ++ char name[8]; ++ uint8_t *key; ++ uint32_t keyLength; ++#endif + } S_ENTITLEMENT; + + struct s_client ; +@@ -985,6 +993,7 @@ struct s_cardsystem + void (*post_process)(struct s_reader *); + int32_t (*get_emm_type)(struct emm_packet_t *, struct s_reader *); + int32_t (*get_emm_filter)(struct s_reader *, struct s_csystem_emm_filter **, unsigned int *); ++ int32_t (*get_emm_filter_adv)(struct s_reader *, struct s_csystem_emm_filter **, unsigned int *, uint16_t, uint32_t, uint16_t); + int32_t (*get_tunemm_filter)(struct s_reader *, struct s_csystem_emm_filter **, unsigned int *); + }; + +@@ -1717,6 +1726,14 @@ struct s_reader + #ifdef MODULE_GHTTP + uint8_t ghttp_use_ssl; + #endif ++#ifdef WITH_EMU ++ FTAB emu_auproviders; // AU providers for Emu reader ++ int8_t emu_datecodedenabled; // date-coded keys for BISS ++ char *extee36; // path to "ee36.bin" - Set by the user via the webif ++ char *extee56; // path to "ee56.bin" - Set by the user via the webif ++ uint8_t dre36_force_group; ++ uint8_t dre56_force_group; ++#endif + uint8_t cnxlastecm; // == 0 - las ecm has not been paired ecm, > 0 last ecm has been paired ecm + LLIST *emmstat; //emm stats + CS_MUTEX_LOCK emmstat_lock; +@@ -2167,6 +2184,7 @@ struct s_config + int8_t dvbapi_read_sdt; + int8_t dvbapi_write_sdt_prov; + int8_t dvbapi_extended_cw_api; ++ int8_t dvbapi_extended_cw_pids; // pid limiter + #endif + + #ifdef CS_ANTICASC +@@ -2213,6 +2231,18 @@ struct s_config + IN_ADDR_T scam_srvip; + struct s_ip *scam_allowed; + #endif ++ ++#ifdef WITH_EMU ++ char *emu_stream_source_host; ++ int32_t emu_stream_source_port; ++ char *emu_stream_source_auth_user; ++ char *emu_stream_source_auth_password; ++ int32_t emu_stream_relay_port; ++ uint32_t emu_stream_ecm_delay; ++ int8_t emu_stream_relay_enabled; ++ int8_t emu_stream_emm_enabled; ++#endif ++ + int32_t max_cache_time; //seconds ecms are stored in ecmcwcache + int32_t max_hitcache_time; //seconds hits are stored in cspec_hitcache (to detect dyn wait_time) + +@@ -2394,4 +2424,8 @@ static inline bool caid_is_bulcrypt(uint + static inline bool caid_is_dre(uint16_t caid) { return caid == 0x4AE0 || caid == 0x4AE1 || caid == 0x2710;} + const char *get_cardsystem_desc_by_caid(uint16_t caid); + ++#ifdef WITH_EMU ++FILTER* get_emu_prids_for_caid(struct s_reader *rdr, uint16_t caid); ++#endif ++ + #endif +diff -ruNp trunk.patches/Makefile trunk/Makefile +--- trunk.patches/Makefile 2018-04-03 03:01:12.325689204 +0300 ++++ trunk/Makefile 2018-04-03 03:20:07.654045339 +0300 +@@ -67,6 +67,13 @@ STRIP = $(CROSS_DIR)$(CROSS)strip + + LDFLAGS = -Wl,--gc-sections + ++TARGETHELP := $(shell $(CC) --target-help 2>&1) ++ifneq (,$(findstring sse2,$(TARGETHELP))) ++override CFLAGS += -fexpensive-optimizations -mmmx -msse -msse2 -msse3 ++else ++override CFLAGS += -fexpensive-optimizations ++endif ++ + # The linker for powerpc have bug that prevents --gc-sections from working + # Check for the linker version and if it matches disable --gc-sections + # For more information about the bug see: +@@ -270,6 +277,21 @@ SRC-$(CONFIG_CS_CACHEEX) += module-cccam + SRC-$(CONFIG_MODULE_CCCAM) += module-cccam.c + SRC-$(CONFIG_MODULE_CCCSHARE) += module-cccshare.c + SRC-$(CONFIG_MODULE_CONSTCW) += module-constcw.c ++SRC-$(CONFIG_WITH_EMU) += module-emulator.c ++SRC-$(CONFIG_WITH_EMU) += module-emulator-osemu.c ++SRC-$(CONFIG_WITH_EMU) += module-emulator-stream.c ++SRC-$(CONFIG_WITH_EMU) += ffdecsa/ffdecsa.c ++UNAME := $(shell uname -s) ++ifneq ($(UNAME),Darwin) ++ifndef ANDROID_NDK ++ifndef ANDROID_STANDALONE_TOOLCHAIN ++ifeq "$(CONFIG_WITH_EMU)" "y" ++TOUCH_SK := $(shell touch SoftCam.Key) ++override LDFLAGS += -Wl,--format=binary -Wl,SoftCam.Key -Wl,--format=default ++endif ++endif ++endif ++endif + SRC-$(CONFIG_CS_CACHEEX) += module-csp.c + SRC-$(CONFIG_CW_CYCLE_CHECK) += module-cw-cycle-check.c + SRC-$(CONFIG_WITH_AZBOX) += module-dvbapi-azbox.c +@@ -368,7 +390,7 @@ SRC := $(subst config.c,$(OBJDIR)/config + # starts the compilation. + all: + @./config.sh --use-flags "$(USE_FLAGS)" --objdir "$(OBJDIR)" --make-config.mak +- @-mkdir -p $(OBJDIR)/cscrypt $(OBJDIR)/csctapi $(OBJDIR)/minilzo $(OBJDIR)/webif ++ @-mkdir -p $(OBJDIR)/cscrypt $(OBJDIR)/csctapi $(OBJDIR)/minilzo $(OBJDIR)/ffdecsa $(OBJDIR)/webif + @-printf "\ + +-------------------------------------------------------------------------------\n\ + | OSCam ver: $(VER) rev: $(SVN_REV) target: $(TARGET)\n\ +diff -ruNp trunk.patches/module-dvbapi.c trunk/module-dvbapi.c +--- trunk.patches/module-dvbapi.c 2018-04-03 03:06:13.063827549 +0300 ++++ trunk/module-dvbapi.c 2018-04-03 03:20:07.658045369 +0300 +@@ -1471,7 +1471,15 @@ void dvbapi_start_emm_filter(int32_t dem + } + if(match) + { +- csystem = get_cardsystem_by_caid(caid); ++ if(rdr->typ == R_EMU) ++ { ++ csystem = rdr->csystem; ++ } ++ else ++ { ++ csystem = get_cardsystem_by_caid(caid); ++ } ++ + if(csystem) + { + if(caid != ncaid) +@@ -1490,7 +1498,14 @@ void dvbapi_start_emm_filter(int32_t dem + } + else if (csystem->get_emm_filter) + { +- csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); ++ if(rdr->typ == R_EMU) ++ { ++ csystem->get_emm_filter_adv(rdr, &dmx_filter, &filter_count, caid, provid, demux[demux_index].program_number); ++ } ++ else ++ { ++ csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); ++ } + } + } + else +@@ -2076,6 +2091,8 @@ int32_t dvbapi_start_descrambling(int32_ + er->vpid = demux[demux_id].ECMpids[pid].VPID; + er->pmtpid = demux[demux_id].pmtpid; + er->onid = demux[demux_id].onid; ++ er->tsid = demux[demux_id].tsid; ++ er->ens = demux[demux_id].enigma_namespace; + er->msgid = msgid; + + #ifdef WITH_STAPI5 +@@ -2113,19 +2130,30 @@ int32_t dvbapi_start_descrambling(int32_ + if(caid_is_fake(demux[demux_id].ECMpids[pid].CAID) || caid_is_biss(demux[demux_id].ECMpids[pid].CAID)) + { + int32_t j, n; +- er->ecmlen = 5; ++ er->ecmlen = 7; + er->ecm[0] = 0x80; // to pass the cache check it must be 0x80 or 0x81 + er->ecm[1] = 0x00; +- er->ecm[2] = 0x02; ++ er->ecm[2] = 0x04; + i2b_buf(2, er->srvid, er->ecm + 3); ++ i2b_buf(2, er->pmtpid, er->ecm + 5); + +- for(j = 0, n = 5; j < demux[demux_id].STREAMpidcount; j++, n += 2) ++ for(j = 0, n = 7; j < demux[demux_id].STREAMpidcount; j++, n += 2) + { + i2b_buf(2, demux[demux_id].STREAMpids[j], er->ecm + n); + er->ecm[2] += 2; + er->ecmlen += 2; + } + ++ er->ens &= 0x0FFFFFFF; // clear top 4 bits (in case of DVB-T/C or garbage), prepare for flagging ++ er->ens |= 0xA0000000; // flag to emu: this is the namespace, not a pid ++ ++ i2b_buf(2, er->tsid, er->ecm + 3 + er->ecm[2]); // place tsid after the last stream pid ++ i2b_buf(2, er->onid, er->ecm + 3 + er->ecm[2] + 2); // place onid right after tsid ++ i2b_buf(4, er->ens, er->ecm + 3 + er->ecm[2] + 4); // place namespace at the end of the ecm ++ ++ er->ecm[2] += 8; ++ er->ecmlen += 8; ++ + cs_log("Demuxer %d trying to descramble PID %d CAID %04X PROVID %06X ECMPID %04X ANY CHID PMTPID %04X VPID %04X", demux_id, pid, + demux[demux_id].ECMpids[pid].CAID, demux[demux_id].ECMpids[pid].PROVID, demux[demux_id].ECMpids[pid].ECM_PID, + demux[demux_id].pmtpid, demux[demux_id].ECMpids[pid].VPID); +@@ -3192,6 +3220,7 @@ int32_t dvbapi_parse_capmt(unsigned char + { + uint32_t i = 0, start_descrambling = 0; + int32_t j = 0; ++ int32_t max_pids = 64; + int32_t demux_id = -1; + uint16_t demux_index, adapter_index, pmtpid; + uint32_t ca_mask; +@@ -3354,6 +3383,12 @@ int32_t dvbapi_parse_capmt(unsigned char + uint32_t es_info_length = 0, vpid = 0; + struct s_dvbapi_priority *addentry; + ++ // pid limiter for PowerVu ++ if(demux[demux_id].ECMpids[0].CAID >> 8 == 0x0E) ++ { ++ max_pids = cfg.dvbapi_extended_cw_pids; ++ } ++ + for(i = program_info_length + program_info_start; i + 4 < length; i += es_info_length + 5) + { + uint8_t stream_type = buffer[i]; +@@ -3361,7 +3396,7 @@ int32_t dvbapi_parse_capmt(unsigned char + uint8_t is_audio = 0; + es_info_length = b2i(2, buffer + i +3)&0x0FFF; + +- if(demux[demux_id].STREAMpidcount < ECM_PIDS) ++ if(demux[demux_id].STREAMpidcount < max_pids) // was "ECM_PIDS" (pid limiter) + { + + demux[demux_id].STREAMpids[demux[demux_id].STREAMpidcount] = elementary_pid; +@@ -4375,6 +4410,7 @@ void dvbapi_process_input(int32_t demux_ + if(filtertype == TYPE_ECM) + { + uint32_t chid = 0x10000; ++ int8_t pvu_skip = 0; + ECM_REQUEST *er; + + if(len != 0) // len = 0 receiver encountered an internal bufferoverflow! +@@ -4401,9 +4437,24 @@ void dvbapi_process_input(int32_t demux_ + return; + } + +- if(curpid->table == buffer[0] && !caid_is_irdeto(curpid->CAID)) // wait for odd / even ecm change (only not for irdeto!) ++ if(curpid->CAID >> 8 == 0x0E) + { +- ++ pvu_skip = 1; ++ ++ if(sctlen - 11 > buffer[9]) ++ { ++ if(buffer[11 + buffer[9]] > curpid->pvu_counter || (curpid->pvu_counter == 255 && buffer[11 + buffer[9]] == 0) ++ || ((curpid->pvu_counter - buffer[11 + buffer[9]]) > 5)) ++ { ++ curpid->pvu_counter = buffer[11 + buffer[9]]; ++ pvu_skip = 0; ++ } ++ } ++ } ++ ++ if((curpid->table == buffer[0] && !caid_is_irdeto(curpid->CAID)) || pvu_skip) // wait for odd / even ecm change (only not for irdeto!) ++ { ++ + if(!(er = get_ecmtask())) + { + return; +@@ -4685,6 +4736,40 @@ void dvbapi_process_input(int32_t demux_ + dvbapi_stop_filternum(demux_id, filter_num, msgid); + return; + } ++ ++#ifdef WITH_EMU ++ if((demux[demux_id].demux_fd[filter_num].caid>>8) == 0x10) ++ { ++ uint32_t i; ++ uint32_t emmhash; ++ ++ if(sctlen < 4) ++ { ++ return; ++ } ++ ++ for(i=0; i+2caid>>8 != 0x0E || !cfg.emu_stream_relay_enabled) ++#endif + switch(selected_api) + { + #if defined(WITH_STAPI) || defined(WITH_STAPI5) +diff -ruNp trunk.patches/module-dvbapi.h trunk/module-dvbapi.h +--- trunk.patches/module-dvbapi.h 2018-04-03 02:48:24.956386446 +0300 ++++ trunk/module-dvbapi.h 2018-04-03 03:20:07.658045369 +0300 +@@ -136,6 +136,7 @@ struct s_ecmpids + int8_t useMultipleIndices; + uint32_t streams; + uint32_t cadata; ++ int16_t pvu_counter; + }; + + typedef struct filter_s +@@ -158,6 +159,9 @@ typedef struct filter_s + uint32_t SlotHandle[10]; + uint32_t BufferHandle[10]; + #endif ++#ifdef WITH_EMU ++ uint32_t cadata; ++#endif + } FILTERTYPE; + + struct s_emmpids +diff -ruNp trunk.patches/module-emulator.c trunk/module-emulator.c +--- trunk.patches/module-emulator.c 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/module-emulator.c 2018-04-03 03:20:07.662045399 +0300 +@@ -0,0 +1,904 @@ ++#define MODULE_LOG_PREFIX "emu" ++ ++#include "globals.h" ++#include "oscam-string.h" ++#include "oscam-config.h" ++#include "oscam-conf-chk.h" ++#include "oscam-time.h" ++#include "oscam-reader.h" ++#include "module-emulator-osemu.h" ++#include "module-emulator-stream.h" ++ ++/* ++ * Readers in OSCam consist of 2 basic parts. ++ * The hardware or the device part. This is where physical smart cards are inserted ++ * and made available to OSCam. ++ * The software or the emulation part. This is where the actual card reading is done, ++ * including ecm and emm processing (i.e emulation of the various cryptosystems). ++ * In the Emu reader, the device part has no meaning, but we have to create it in ++ * order to be compatible with OSCam's reader structure. ++*/ ++ ++/* ++ * Create the Emu "emulation" part. This is of type s_cardsystem. ++ * Similar structures are found in the main sources folder (files reader-xxxxxx.c) ++ * for every cryptosystem supported by OSCam. ++ * Here we read keys from our virtual card (aka the SoftCam.Key file) and we inform ++ * OSCam about them. This is done with the emu_card_info() function. Keep in mind ++ * that Emu holds all its keys to separate structures for faster access. ++ * In addition, ECM and EMM requests are processed here, with the emu_do_ecm() and ++ * emu_do_emm() functions. ++*/ ++ ++#define CS_OK 1 ++#define CS_ERROR 0 ++ ++static uint8_t oneByte = 0x01; ++extern char cs_confdir[128]; ++ ++static void set_hexserial_to_version(struct s_reader *rdr) ++{ ++ char cVersion[32]; ++ uint32_t version = GetOSemuVersion(); ++ uint8_t hversion[2]; ++ memset(hversion, 0, 2); ++ snprintf(cVersion, sizeof(cVersion), "%04d", version); ++ CharToBin(hversion, cVersion, 4); ++ rdr->hexserial[3] = hversion[0]; ++ rdr->hexserial[4] = hversion[1]; ++} ++ ++static void set_prids(struct s_reader *rdr) ++{ ++ int32_t i, j; ++ ++ rdr->nprov = 0; ++ ++ for (i = 0; (i < rdr->emu_auproviders.nfilts) && (rdr->nprov < CS_MAXPROV); i++) ++ { ++ for (j = 0; (j < rdr->emu_auproviders.filts[i].nprids) && (rdr->nprov < CS_MAXPROV); j++) ++ { ++ i2b_buf(4, rdr->emu_auproviders.filts[i].prids[j], rdr->prid[i]); ++ rdr->nprov++; ++ } ++ } ++} ++ ++static void emu_add_entitlement(struct s_reader *rdr, uint16_t caid, uint32_t provid, uint8_t *key, char *keyName, uint32_t keyLength, uint8_t isData) ++{ ++ if (!rdr->ll_entitlements) ++ { ++ rdr->ll_entitlements = ll_create("ll_entitlements"); ++ } ++ ++ S_ENTITLEMENT *item; ++ if (cs_malloc(&item, sizeof(S_ENTITLEMENT))) ++ { ++ // fill item ++ item->caid = caid; ++ item->provid = provid; ++ item->id = 0; ++ item->class = 0; ++ item->start = 0; ++ item->end = 2147472000; ++ item->type = 0; ++ item->isKey = 1; ++ memcpy(item->name, keyName, 8); ++ item->key = key; ++ item->keyLength = keyLength; ++ item->isData = isData; ++ ++ // add item ++ ll_append(rdr->ll_entitlements, item); ++ } ++} ++ ++static void refresh_entitlements(struct s_reader *rdr) ++{ ++ uint32_t i; ++ KeyData *tmpKeyData; ++ ++ cs_clear_entitlement(rdr); ++ ++ for (i = 0; i < CwKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, CwKeys.EmuKeys[i].provider >> 8, CwKeys.EmuKeys[i].provider & 0xFF, ++ CwKeys.EmuKeys[i].key, CwKeys.EmuKeys[i].keyName, CwKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ for (i = 0; i < ViKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x500, ViKeys.EmuKeys[i].provider, ViKeys.EmuKeys[i].key, ++ ViKeys.EmuKeys[i].keyName, ViKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ for (i = 0; i < NagraKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x1801, NagraKeys.EmuKeys[i].provider, NagraKeys.EmuKeys[i].key, ++ NagraKeys.EmuKeys[i].keyName, NagraKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ for (i = 0; i < IrdetoKeys.keyCount; i++) ++ { ++ tmpKeyData = &IrdetoKeys.EmuKeys[i]; ++ do ++ { ++ emu_add_entitlement(rdr, tmpKeyData->provider >> 8, tmpKeyData->provider & 0xFF, ++ tmpKeyData->key, tmpKeyData->keyName, tmpKeyData->keyLength, 0); ++ ++ tmpKeyData = tmpKeyData->nextKey; ++ } ++ while (tmpKeyData != NULL); ++ } ++ ++ for (i = 0; i < NDSKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, NDSKeys.EmuKeys[i].provider, 0, NDSKeys.EmuKeys[i].key, ++ NDSKeys.EmuKeys[i].keyName, NDSKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ emu_add_entitlement(rdr, 0x090F, 0, viasat_const, "00", 64, 1); ++ emu_add_entitlement(rdr, 0x093E, 0, viasat_const, "00", 64, 1); ++ ++ for (i = 0; i < BissKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x2600, BissKeys.EmuKeys[i].provider, BissKeys.EmuKeys[i].key, ++ BissKeys.EmuKeys[i].keyName, BissKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ emu_add_entitlement(rdr, 0xFFFF, 0, &oneByte, "00", 1, 1); ++ ++ for (i = 0; i < PowervuKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x0E00, PowervuKeys.EmuKeys[i].provider, PowervuKeys.EmuKeys[i].key, ++ PowervuKeys.EmuKeys[i].keyName, PowervuKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ for (i = 0; i < DreKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x4AE1, DreKeys.EmuKeys[i].provider, DreKeys.EmuKeys[i].key, ++ DreKeys.EmuKeys[i].keyName, DreKeys.EmuKeys[i].keyLength, 0); ++ } ++ ++ for (i = 0; i < TandbergKeys.keyCount; i++) ++ { ++ emu_add_entitlement(rdr, 0x1010, TandbergKeys.EmuKeys[i].provider, TandbergKeys.EmuKeys[i].key, ++ TandbergKeys.EmuKeys[i].keyName, TandbergKeys.EmuKeys[i].keyLength, 0); ++ } ++} ++ ++static int32_t emu_do_ecm(struct s_reader *rdr, const struct ecm_request_t *er, struct s_ecm_answer *ea) ++{ ++ ++ if (!ProcessECM(rdr, er->ecmlen, er->caid, er->prid, er->ecm, ea->cw, er->srvid, er->pid, &ea->cw_ex)) ++ { ++ return CS_OK; ++ } ++ ++ return CS_ERROR; ++} ++ ++static int32_t emu_do_emm(struct s_reader *rdr, struct emm_packet_t *emm) ++{ ++ uint32_t keysAdded = 0; ++ ++ if (emm->emmlen < 3) ++ { ++ return CS_ERROR; ++ } ++ ++ if (SCT_LEN(emm->emm) > emm->emmlen) ++ { ++ return CS_ERROR; ++ } ++ ++ if (!ProcessEMM(rdr, b2i(2, emm->caid), b2i(4, emm->provid), emm->emm, &keysAdded)) ++ { ++ if (keysAdded > 0) ++ { ++ refresh_entitlements(rdr); ++ } ++ ++ return CS_OK; ++ } ++ ++ return CS_ERROR; ++} ++ ++static int32_t emu_card_info(struct s_reader *rdr) ++{ ++ // Delete keys from Emu's memory ++ clear_emu_keydata(); ++ ++ // Read keys built in the OSCam-Emu binary ++#if !defined(__APPLE__) && !defined(__ANDROID__) ++ read_emu_keymemory(rdr); ++#endif ++ ++ // Read keys from SoftCam.Key file ++ set_emu_keyfile_path(cs_confdir); ++ ++ if (!read_emu_keyfile(rdr, cs_confdir)) ++ { ++ if (read_emu_keyfile(rdr, "/var/keys/")) ++ { ++ set_emu_keyfile_path("/var/keys/"); ++ } ++ } ++ ++ // Load keys from external files (set via the webif or the reader config directly) ++ read_emu_eebin(rdr->extee36, "ee36.bin"); // Read "ee36.bin" ++ read_emu_eebin(rdr->extee56, "ee56.bin"); // Read "ee56.bin" ++ read_emu_deskey(rdr->des_key, rdr->des_key_length); // Read overcrypt keys for DreCrypt ADEC ++ ++ cs_log("Total keys in memory: W:%d V:%d N:%d I:%d S:%d F:%d P:%d D:%d T:%d", \ ++ CwKeys.keyCount, ViKeys.keyCount, NagraKeys.keyCount, \ ++ IrdetoKeys.keyCount, NDSKeys.keyCount, BissKeys.keyCount, \ ++ PowervuKeys.keyCount, DreKeys.keyCount, TandbergKeys.keyCount); ++ ++ // Inform OSCam about all available keys. ++ // This is used for listing the "entitlements" in the webif's reader page. ++ refresh_entitlements(rdr); ++ ++ set_prids(rdr); ++ ++ set_hexserial_to_version(rdr); ++ ++ return CS_OK; ++} ++ ++/* ++static int32_t emu_card_init(struct s_reader *UNUSED(rdr), struct s_ATR *UNUSED(atr)) ++{ ++ return CS_ERROR; ++} ++*/ ++ ++int32_t emu_get_via3_emm_type(EMM_PACKET *ep, struct s_reader *rdr) ++{ ++ uint32_t provid = 0; ++ ++ if(ep->emm[3] == 0x90 && ep->emm[4] == 0x03) ++ { ++ provid = b2i(3, ep->emm+5); ++ provid &=0xFFFFF0; ++ i2b_buf(4, provid, ep->provid); ++ } ++ ++ switch(ep->emm[0]) ++ { ++ case 0x88: ++ ep->type = UNIQUE; ++ memset(ep->hexserial, 0, 8); ++ memcpy(ep->hexserial, ep->emm + 4, 4); ++ rdr_log_dbg(rdr, D_EMM, "UNIQUE"); ++ return 1; ++ ++ case 0x8A: ++ case 0x8B: ++ ep->type = GLOBAL; ++ rdr_log_dbg(rdr, D_EMM, "GLOBAL"); ++ return 1; ++ ++ case 0x8C: ++ case 0x8D: ++ ep->type = SHARED; ++ rdr_log_dbg(rdr, D_EMM, "SHARED (part)"); ++ // We need those packets to pass otherwise we would never ++ // be able to complete EMM reassembly ++ return 1; ++ ++ case 0x8E: ++ ep->type = SHARED; ++ rdr_log_dbg(rdr, D_EMM, "SHARED"); ++ memset(ep->hexserial, 0, 8); ++ memcpy(ep->hexserial, ep->emm + 3, 3); ++ return 1; ++ ++ default: ++ ep->type = UNKNOWN; ++ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); ++ return 1; ++ } ++} ++ ++int32_t emu_get_ird2_emm_type(EMM_PACKET *ep, struct s_reader *rdr) ++{ ++ int32_t l = (ep->emm[3] & 0x07); ++ int32_t base = (ep->emm[3] >> 3); ++ char dumprdrserial[l * 3], dumpemmserial[l * 3]; ++ ++ switch(l) ++ { ++ ++ case 0: ++ // global emm, 0 bytes addressed ++ ep->type = GLOBAL; ++ rdr_log_dbg(rdr, D_EMM, "GLOBAL base = %02x", base); ++ return 1; ++ ++ case 2: ++ // shared emm, 2 bytes addressed ++ ep->type = SHARED; ++ memset(ep->hexserial, 0, 8); ++ memcpy(ep->hexserial, ep->emm + 4, l); ++ cs_hexdump(1, rdr->hexserial, l, dumprdrserial, sizeof(dumprdrserial)); ++ cs_hexdump(1, ep->hexserial, l, dumpemmserial, sizeof(dumpemmserial)); ++ rdr_log_dbg_sensitive(rdr, D_EMM, "SHARED l = %d ep = {%s} rdr = {%s} base = %02x", l, ++ dumpemmserial, dumprdrserial, base); ++ return 1; ++ ++ case 3: ++ // unique emm, 3 bytes addressed ++ ep->type = UNIQUE; ++ memset(ep->hexserial, 0, 8); ++ memcpy(ep->hexserial, ep->emm + 4, l); ++ cs_hexdump(1, rdr->hexserial, l, dumprdrserial, sizeof(dumprdrserial)); ++ cs_hexdump(1, ep->hexserial, l, dumpemmserial, sizeof(dumpemmserial)); ++ rdr_log_dbg_sensitive(rdr, D_EMM, "UNIQUE l = %d ep = {%s} rdr = {%s} base = %02x", l, ++ dumpemmserial, dumprdrserial, base); ++ return 1; ++ ++ default: ++ ep->type = UNKNOWN; ++ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); ++ return 1; ++ } ++} ++ ++int32_t emu_get_pvu_emm_type(EMM_PACKET *ep, struct s_reader *rdr) ++{ ++ if(ep->emm[0] == 0x82) ++ { ++ ep->type = UNIQUE; ++ memset(ep->hexserial, 0, 8); ++ memcpy(ep->hexserial, ep->emm + 12, 4); ++ } ++ else ++ { ++ ep->type = UNKNOWN; ++ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); ++ } ++ return 1; ++} ++ ++int32_t emu_get_dre2_emm_type(EMM_PACKET *ep, struct s_reader *UNUSED(rdr)) ++{ ++ switch (ep->emm[0]) ++ { ++ case 0x82: ++ ep->type = GLOBAL; ++ return 1; ++ ++ case 0x86: ++ ep->type = SHARED; ++ memset(ep->hexserial, 0, 8); ++ ep->hexserial[0] = ep->emm[3]; ++ return 1; ++ ++ //case 0x87: ++ // ep->type = UNIQUE; ++ // return 1; //FIXME: no filling of ep->hexserial ++ ++ case 0x88: ++ ep->type = UNIQUE; ++ return 1; //FIXME: no filling of ep->hexserial ++ ++ case 0x91: ++ ep->type = GLOBAL; ++ return 1; ++ ++ default: ++ ep->type = UNKNOWN; ++ return 1; ++ } ++} ++ ++int32_t emu_get_tan_emm_type(EMM_PACKET *ep, struct s_reader *rdr) ++{ ++ if(ep->emm[0] == 0x82 || ep->emm[0] == 0x83) ++ { ++ ep->type = GLOBAL; ++ } ++ else ++ { ++ ep->type = UNKNOWN; ++ rdr_log_dbg(rdr, D_EMM, "UNKNOWN"); ++ } ++ return 1; ++} ++ ++static int32_t emu_get_emm_type(struct emm_packet_t *ep, struct s_reader *rdr) ++{ ++ switch(b2i(2, ep->caid)>>8) ++ { ++ case 0x05: ++ return emu_get_via3_emm_type(ep, rdr); ++ ++ case 0x06: ++ return emu_get_ird2_emm_type(ep, rdr); ++ ++ case 0x0E: ++ return emu_get_pvu_emm_type(ep, rdr); ++ ++ case 0x4A: ++ return emu_get_dre2_emm_type(ep, rdr); ++ ++ case 0x10: ++ return emu_get_tan_emm_type(ep, rdr); ++ ++ default: ++ break; ++ } ++ ++ return CS_ERROR; ++} ++ ++FILTER* get_emu_prids_for_caid(struct s_reader *rdr, uint16_t caid) ++{ ++ int32_t i; ++ ++ for(i = 0; i < rdr->emu_auproviders.nfilts; i++) ++ { ++ if(caid == rdr->emu_auproviders.filts[i].caid) ++ { ++ return &rdr->emu_auproviders.filts[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++static int32_t emu_get_via3_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid)) ++{ ++ if(*emm_filters == NULL) ++ { ++ const unsigned int max_filter_count = 1; ++ ++ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) ++ { return CS_ERROR; } ++ ++ struct s_csystem_emm_filter *filters = *emm_filters; ++ *filter_count = 0; ++ ++ int32_t idx = 0; ++ ++ filters[idx].type = EMM_GLOBAL; ++ filters[idx].enabled = 1; ++ filters[idx].filter[0] = 0x8A; ++ filters[idx].mask[0] = 0xFE; ++ filters[idx].filter[3] = 0x80; ++ filters[idx].mask[3] = 0x80; ++ idx++; ++ ++ *filter_count = idx; ++ } ++ ++ return CS_OK; ++} ++ ++static int32_t emu_get_ird2_emm_filter(struct s_reader* rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t caid, uint32_t UNUSED(provid)) ++{ ++ uint8_t hexserial[3], prid[4]; ++ FILTER* emu_provids; ++ int8_t have_provid = 0, have_serial = 0; ++ int32_t i; ++ ++ if(GetIrdeto2Hexserial(caid, hexserial)) ++ { have_serial = 1; } ++ ++ emu_provids = get_emu_prids_for_caid(rdr, caid); ++ if(emu_provids != NULL && emu_provids->nprids > 0) ++ { have_provid = 1; } ++ ++ if(*emm_filters == NULL) ++ { ++ const unsigned int max_filter_count = have_serial + (2*(have_provid ? emu_provids->nprids : 0)); ++ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) ++ { return CS_ERROR; } ++ ++ struct s_csystem_emm_filter *filters = *emm_filters; ++ *filter_count = 0; ++ ++ unsigned int idx = 0; ++ ++ if(have_serial) ++ { ++ filters[idx].type = EMM_UNIQUE; ++ filters[idx].enabled = 1; ++ filters[idx].filter[0] = 0x82; ++ filters[idx].mask[0] = 0xFF; ++ filters[idx].filter[1] = 0xFB; ++ filters[idx].mask[1] = 0x07; ++ memcpy(&filters[idx].filter[2], hexserial, 3); ++ memset(&filters[idx].mask[2], 0xFF, 3); ++ idx++; ++ } ++ ++ for(i=0; have_provid && inprids; i++) ++ { ++ i2b_buf(4, emu_provids->prids[i], prid); ++ ++ filters[idx].type = EMM_UNIQUE; ++ filters[idx].enabled = 1; ++ filters[idx].filter[0] = 0x82; ++ filters[idx].mask[0] = 0xFF; ++ filters[idx].filter[1] = 0xFB; ++ filters[idx].mask[1] = 0x07; ++ memcpy(&filters[idx].filter[2], &prid[1], 3); ++ memset(&filters[idx].mask[2], 0xFF, 3); ++ idx++; ++ ++ filters[idx].type = EMM_SHARED; ++ filters[idx].enabled = 1; ++ filters[idx].filter[0] = 0x82; ++ filters[idx].mask[0] = 0xFF; ++ filters[idx].filter[1] = 0xFA; ++ filters[idx].mask[1] = 0x07; ++ memcpy(&filters[idx].filter[2], &prid[1], 2); ++ memset(&filters[idx].mask[2], 0xFF, 2); ++ idx++; ++ } ++ ++ *filter_count = idx; ++ } ++ ++ return CS_OK; ++} ++ ++static int32_t emu_get_pvu_emm_filter(struct s_reader *UNUSED(rdr), struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count, uint16_t UNUSED(caid), uint32_t UNUSED(provid), uint16_t srvid) ++{ ++ uint8_t hexserials[16][4]; ++ int32_t i, count = 0; ++ ++ if(!GetPowervuHexserials(srvid, hexserials, 16, &count)) ++ { return CS_ERROR; } ++ ++ if(*emm_filters == NULL) ++ { ++ const unsigned int max_filter_count = count; ++ if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter))) ++ { return CS_ERROR; } ++ ++ struct s_csystem_emm_filter *filters = *emm_filters; ++ *filter_count = 0; ++ ++ int32_t idx = 0; ++ ++ for(i=0; i>8) ++ { ++ case 0x05: ++ return emu_get_via3_emm_filter(rdr, emm_filters, filter_count, caid, provid); ++ ++ case 0x06: ++ return emu_get_ird2_emm_filter(rdr, emm_filters, filter_count, caid, provid); ++ ++ case 0x0E: ++ return emu_get_pvu_emm_filter(rdr, emm_filters, filter_count, caid, provid, srvid); ++ ++ case 0x4A: ++ return emu_get_dre2_emm_filter(rdr, emm_filters, filter_count, caid, provid); ++ ++ case 0x10: ++ return emu_get_tan_emm_filter(rdr, emm_filters, filter_count, caid, provid); ++ ++ default: ++ break; ++ } ++ ++ return CS_ERROR; ++} ++ ++const struct s_cardsystem reader_emu = ++{ ++ .desc = "emu", ++ .caids = (uint16_t[]){ 0x0D, 0x09, 0x0500, 0x18, 0x06, 0x26, 0xFFFF, 0x0E, 0x4A, 0x10, 0 }, ++ .do_ecm = emu_do_ecm, ++ .do_emm = emu_do_emm, ++ .card_info = emu_card_info, ++ //.card_init = emu_card_init, // apparently this is not needed at all ++ .get_emm_type = emu_get_emm_type, ++ .get_emm_filter = emu_get_emm_filter, // needed to pass checks ++ .get_emm_filter_adv = emu_get_emm_filter_adv, ++}; ++ ++/* ++ * Create the Emu virtual "device" part. This is of type s_cardreader. ++ * Similar structures are found in the csctapi (Card System Card Terminal API) ++ * folder for every IFD (InterFace Device), aka smart card reader. ++ * Since we have no hardware to initialize, we start our Stream Relay server ++ * with the emu_reader_init() function. ++ * At Emu shutdown, we remove keys from memory with the emu_close() function. ++*/ ++ ++#define CR_OK 0 ++#define CR_ERROR 1 ++ ++static int32_t emu_reader_init(struct s_reader *UNUSED(reader)) ++{ ++ int32_t i; ++ char authtmp[128]; ++ ++ if (cfg.emu_stream_relay_enabled && (stream_server_thread_init == 0)) ++ { ++ stream_server_thread_init = 1; ++ SAFE_MUTEX_INIT(&emu_fixed_key_srvid_mutex, NULL); ++ ++ for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++) ++ { ++ SAFE_MUTEX_INIT(&emu_fixed_key_data_mutex[i], NULL); ++ ll_emu_stream_delayed_keys[i] = ll_create("ll_emu_stream_delayed_keys"); ++ memset(&emu_fixed_key_data[i], 0, sizeof(emu_stream_client_key_data)); ++ } ++ ++ start_thread("stream_key_delayer", stream_key_delayer, NULL, NULL, 1, 1); ++ cs_log("Stream key delayer initialized"); ++ ++ cs_strncpy(emu_stream_source_host, cfg.emu_stream_source_host, sizeof(emu_stream_source_host)); ++ emu_stream_source_port = cfg.emu_stream_source_port; ++ emu_stream_relay_port = cfg.emu_stream_relay_port; ++ emu_stream_emm_enabled = cfg.emu_stream_emm_enabled; ++ ++ if (cfg.emu_stream_source_auth_user && cfg.emu_stream_source_auth_password) ++ { ++ snprintf(authtmp, sizeof(authtmp), "%s:%s", cfg.emu_stream_source_auth_user, cfg.emu_stream_source_auth_password); ++ b64encode(authtmp, strlen(authtmp), &emu_stream_source_auth); ++ } ++ else ++ { ++ NULLFREE(emu_stream_source_auth); ++ } ++ ++ start_thread("stream_server", stream_server, NULL, NULL, 1, 1); ++ cs_log("Stream relay server initialized"); ++ } ++ ++ return CR_OK; ++} ++ ++static int32_t emu_close(struct s_reader *UNUSED(reader)) ++{ ++ cs_log("Reader is shutting down"); ++ ++ // Delete keys from Emu's memory ++ clear_emu_keydata(); ++ ++ return CR_OK; ++} ++ ++static int32_t emu_get_status(struct s_reader *UNUSED(reader), int32_t *in) { *in = 1; return CR_OK; } ++static int32_t emu_activate(struct s_reader *UNUSED(reader), struct s_ATR *UNUSED(atr)) { return CR_OK; } ++static int32_t emu_transmit(struct s_reader *UNUSED(reader), uint8_t *UNUSED(buffer), uint32_t UNUSED(size), uint32_t UNUSED(expectedlen), uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { return CR_OK; } ++static int32_t emu_receive(struct s_reader *UNUSED(reader), uint8_t *UNUSED(buffer), uint32_t UNUSED(size), uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { return CR_OK; } ++static int32_t emu_write_settings(struct s_reader *UNUSED(reader), struct s_cardreader_settings *UNUSED(s)) { return CR_OK; } ++static int32_t emu_card_write(struct s_reader *UNUSED(pcsc_reader),const uchar *UNUSED(buf) ,uint8_t *UNUSED(cta_res), uint16_t *UNUSED(cta_lr),int32_t UNUSED(l)) { return CR_OK; } ++static int32_t emu_set_protocol(struct s_reader *UNUSED(rdr),uint8_t *UNUSED(params),uint32_t *UNUSED(length), uint32_t UNUSED(len_request)) { return CR_OK; } ++ ++const struct s_cardreader cardreader_emu = ++{ ++ .desc = "emu", ++ .typ = R_EMU, ++ .skip_extra_atr_parsing = 1, ++ .reader_init = emu_reader_init, ++ .get_status = emu_get_status, ++ .activate = emu_activate, ++ .transmit = emu_transmit, ++ .receive = emu_receive, ++ .close = emu_close, ++ .write_settings = emu_write_settings, ++ .card_write = emu_card_write, ++ .set_protocol = emu_set_protocol, ++}; ++ ++void add_emu_reader(void) ++{ ++ // This function is called inside oscam.c and creates an emu [reader] with default ++ // settings in oscam.server file. If an emu [reader] already exists, it uses that. ++ ++ LL_ITER itr; ++ struct s_reader *rdr; ++ int8_t haveEmuReader = 0; ++ char *emuName = "emulator"; ++ char *ctab, *ftab, *emu_auproviders; ++ ++ // Check if emu [reader] entry already exists in oscam.server file and get it ++ itr = ll_iter_create(configured_readers); ++ while ((rdr = ll_iter_next(&itr))) ++ { ++ if (rdr->typ == R_EMU) ++ { ++ haveEmuReader = 1; ++ break; ++ } ++ } ++ ++ rdr = NULL; ++ ++ // If there's no emu [reader] in oscam.server, create one with default settings ++ if (!haveEmuReader) ++ { ++ if (!cs_malloc(&rdr, sizeof(struct s_reader))) ++ { ++ return; ++ } ++ ++ reader_set_defaults(rdr); ++ ++ rdr->enable = 1; ++ rdr->typ = R_EMU; ++ strncpy(rdr->label, emuName, strlen(emuName)); ++ strncpy(rdr->device, emuName, strlen(emuName)); ++ ++ // CAIDs ++ ctab = strdup("090F,0500,1801,0604,2600,FFFF,0E00,4AE1,1010"); ++ chk_caidtab(ctab, &rdr->ctab); ++ NULLFREE(ctab); ++ ++ // Idents ++ ftab = strdup("090F:000000;" ++ "0500:000000,023800,021110,007400,007800;" ++ "1801:000000,007301,001101,002111;" ++ "0604:000000;" ++ "2600:000000;" ++ "FFFF:000000;" ++ "0E00:000000;" ++ "4AE1:000011,000014,0000FE;" ++ "1010:000000;" ++ ); ++ chk_ftab(ftab, &rdr->ftab); ++ NULLFREE(ftab); ++ ++ // AU providers ++ emu_auproviders = strdup("0604:010200;0E00:000000;4AE1:000011,000014,0000FE;1010:000000;"); ++ chk_ftab(emu_auproviders, &rdr->emu_auproviders); ++ NULLFREE(emu_auproviders); ++ ++ // EMM cache ++ rdr->cachemm = 2; ++ rdr->rewritemm = 1; ++ rdr->logemm = 2; ++ rdr->deviceemm = 1; ++ ++ // User group ++ rdr->grp = 0x1ULL; ++ ++ // Add the "device" part to our emu reader ++ rdr->crdr = &cardreader_emu; ++ ++ reader_fixups_fn(rdr); ++ ll_append(configured_readers, rdr); ++ } ++ ++ // Set DVB Api delayer option ++#ifdef HAVE_DVBAPI ++ if (cfg.dvbapi_enabled && cfg.dvbapi_delayer < 60) ++ { ++ cfg.dvbapi_delayer = 60; ++ } ++#endif ++ ++ cs_log("OSCam-Emu version %d", GetOSemuVersion()); ++} +diff -ruNp trunk.patches/module-emulator-osemu.c trunk/module-emulator-osemu.c +--- trunk.patches/module-emulator-osemu.c 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/module-emulator-osemu.c 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,6488 @@ ++#define MODULE_LOG_PREFIX "emu" ++ ++#include "globals.h" ++#include "ffdecsa/ffdecsa.h" ++#include "cscrypt/bn.h" ++#include "cscrypt/des.h" ++#include "cscrypt/idea.h" ++#include "cscrypt/md5.h" ++ ++#ifdef WITH_EMU ++#include "oscam-aes.h" ++#include "oscam-string.h" ++#include "oscam-config.h" ++#include "oscam-conf-chk.h" ++#include "oscam-time.h" ++#include "module-newcamd-des.h" ++#include "reader-dre-common.h" ++// from reader-viaccess.c: ++void hdSurEncPhase1_D2_0F_11(uint8_t *CWs); ++void hdSurEncPhase2_D2_0F_11(uint8_t *CWs); ++void hdSurEncPhase1_D2_13_15(uint8_t *cws); ++void hdSurEncPhase2_D2_13_15(uint8_t *cws); ++#else ++#include "cscrypt/viades.h" ++#include "via3surenc.h" ++#include "dre2overcrypt.h" ++#endif ++ ++#include "module-emulator-osemu.h" ++#include "module-emulator-stream.h" ++ ++// Version info ++uint32_t GetOSemuVersion(void) ++{ ++ return atoi("$Version: 769 $"+10); ++} ++ ++/* ++ * Key DB ++ * ++ * The Emu reader gets keys from the OSCcam-Emu binary and the "SoftCam.Key" file. ++ * ++ * The keys are stored in structures of type "KeyDataContainer", one per CAS. Each ++ * container points to a dynamically allocated array of type "KeyData", which holds ++ * the actual keys. The array initially holds up to 64 keys (64 * KeyData), and it ++ * is expanded by 16 every time it's filled with keys. The "KeyDataContainer" also ++ * includes info about the number of keys it contains ("KeyCount") and the maximum ++ * number of keys it can store ("KeyMax"). ++ * ++ * The "KeyData" structure on the other hand, stores the actual key information, ++ * including the "identifier", "provider", "keyName", "key" and "keyLength". There ++ * is also a "nextKey" pointer to a similar "KeyData" structure which is only used ++ * for Irdeto multiple keys, in a linked list style structure. For all other CAS, ++ * the "nextKey" is a "NULL" pointer. ++ * ++ * For storing keys, the "SetKey" function is used. Duplicate keys are not allowed. ++ * When storing a key that is already present in the database, its "key" value is ++ * updated with the new one. For reading keys from the database, the "FindKey" ++ * function is used. To delete all keys in a container, the "DeleteKeysInContainer" ++ * function can be called. ++*/ ++ ++static char *emu_keyfile_path = NULL; ++ ++void set_emu_keyfile_path(const char *path) ++{ ++ if(emu_keyfile_path != NULL) { ++ free(emu_keyfile_path); ++ } ++ emu_keyfile_path = (char*)malloc(strlen(path)+1); ++ if(emu_keyfile_path == NULL) { ++ return; ++ } ++ memcpy(emu_keyfile_path, path, strlen(path)); ++ emu_keyfile_path[strlen(path)] = 0; ++} ++ ++int32_t CharToBin(uint8_t *out, const char *in, uint32_t inLen) ++{ ++ uint32_t i, tmp; ++ for(i=0; i= fileNameLen && strcasecmp(path+pathLength-fileNameLen, EMU_KEY_FILENAME) == 0) { ++ // cut file name ++ path[pathLength-fileNameLen] = '\0'; ++ } ++ ++ pathLength = strlen(path); ++ if(path[pathLength-1] == '/' || path[pathLength-1] == '\\') { ++ // cut trailing / ++ path[pathLength-1] = '\0'; ++ } ++ ++ pDir = opendir(path); ++ if (pDir == NULL) { ++ cs_log("Cannot open key file path: %s", path); ++ free(path); ++ return; ++ } ++ ++ while((pDirent = readdir(pDir)) != NULL) { ++ if(strcasecmp(pDirent->d_name, EMU_KEY_FILENAME) == 0) { ++ strncpy(filename, pDirent->d_name, sizeof(filename)); ++ break; ++ } ++ } ++ closedir(pDir); ++ ++ if(pDirent == NULL) { ++ strncpy(filename, EMU_KEY_FILENAME, sizeof(filename)); ++ } ++ ++ pathLength = strlen(path)+1+strlen(filename)+1; ++ filepath = (char*)malloc(pathLength); ++ if(filepath == NULL) { ++ free(path); ++ return; ++ } ++ snprintf(filepath, pathLength, "%s/%s", path, filename); ++ free(path); ++ ++ cs_log("Writing key file: %s", filepath); ++ ++ file = fopen(filepath, "a"); ++ free(filepath); ++ if(file == NULL) { ++ return; ++ } ++ ++ Date2Str(dateText, sizeof(dateText), 0, 1); ++ ++ keyValue = (char*)malloc((keyLength*2)+1); ++ if(keyValue == NULL) { ++ fclose(file); ++ return; ++ } ++ cs_hexdump(0, key, keyLength, keyValue, (keyLength*2)+1); ++ ++ if(comment) ++ { ++ snprintf(line, sizeof(line), "\n%c %.4X %s %s ; added by OSEmu %s %s\n", identifier, provider, keyName, keyValue, dateText, comment); ++ } ++ else ++ { ++ snprintf(line, sizeof(line), "\n%c %.4X %s %s ; added by OSEmu %s\n", identifier, provider, keyName, keyValue, dateText); ++ } ++ ++ cs_log("Key written: %c %.4X %s %s", identifier, provider, keyName, keyValue); ++ ++ free(keyValue); ++ ++ fwrite(line, strlen(line), 1, file); ++ fclose(file); ++} ++ ++int32_t SetKey(char identifier, uint32_t provider, char *keyName, uint8_t *orgKey, uint32_t keyLength, ++ uint8_t writeKey, char *comment, struct s_reader *rdr) ++{ ++ uint32_t i, j; ++ uint8_t *tmpKey = NULL; ++ KeyDataContainer *KeyDB; ++ KeyData *tmpKeyData, *newKeyData; ++ identifier = (char)toupper((int)identifier); ++ ++ KeyDB = GetKeyContainer(identifier); ++ if(KeyDB == NULL) { ++ return 0; ++ } ++ ++ keyName = strtoupper(keyName); ++ ++ if (identifier == 'F') // Prepare BISS keys before saving to the db ++ { ++ // Convert legacy BISS "00" & "01" keynames ++ if (0 == strcmp(keyName, "00") || 0 == strcmp(keyName, "01")) ++ { ++ keyName = "00000000"; ++ } ++ ++ // All keyNames should have a length of 8 after converting ++ if (strlen(keyName) != 8) ++ { ++ cs_log("WARNING: Wrong key format in %s: F %08X %s", EMU_KEY_FILENAME, provider, keyName); ++ return 0; ++ } ++ ++ // Verify date-coded keyName (if enabled), ignoring old (expired) keys ++ if (rdr->emu_datecodedenabled) ++ { ++ char timeStr[9]; ++ Date2Str(timeStr, sizeof(timeStr), 0, 3); ++ ++ // Reject old date-coded keys, but allow our "00000000" evergreen label ++ if (strcmp("00000000", keyName) != 0 && strcmp(timeStr, keyName) >= 0) ++ { ++ return 0; ++ } ++ } ++ } ++ ++ // fix checksum for BISS keys with a length of 6 ++ if (identifier == 'F' && keyLength == 6) ++ { ++ tmpKey = (uint8_t*)malloc(8*sizeof(uint8_t)); ++ if(tmpKey == NULL) { ++ return 0; ++ } ++ ++ tmpKey[0] = orgKey[0]; ++ tmpKey[1] = orgKey[1]; ++ tmpKey[2] = orgKey[2]; ++ tmpKey[3] = ((orgKey[0] + orgKey[1] + orgKey[2]) & 0xff); ++ tmpKey[4] = orgKey[3]; ++ tmpKey[5] = orgKey[4]; ++ tmpKey[6] = orgKey[5]; ++ tmpKey[7] = ((orgKey[3] + orgKey[4] + orgKey[5]) & 0xff); ++ ++ keyLength = 8; ++ } ++ else // All keys with a length of 8, including BISS ++ { ++ tmpKey = (uint8_t*)malloc(keyLength*sizeof(uint8_t)); ++ if(tmpKey == NULL) { ++ return 0; ++ } ++ ++ memcpy(tmpKey, orgKey, keyLength); ++ } ++ ++ // fix patched mgcamd format for Irdeto ++ if(identifier == 'I' && provider < 0xFFFF) { ++ provider = provider<<8; ++ } ++ ++ // key already exists on db, update its value ++ for(i=0; ikeyCount; i++) { ++ ++ if(KeyDB->EmuKeys[i].provider != provider) { ++ continue; ++ } ++ ++ // Don't match keyName (i.e. expiration date) for BISS ++ if(identifier != 'F' && strcmp(KeyDB->EmuKeys[i].keyName, keyName)) { ++ continue; ++ } ++ ++ // allow multiple keys for Irdeto ++ if(identifier == 'I') ++ { ++ // reject duplicates ++ tmpKeyData = &KeyDB->EmuKeys[i]; ++ do { ++ if(memcmp(tmpKeyData->key, tmpKey, tmpKeyData->keyLength < keyLength ? tmpKeyData->keyLength : keyLength) == 0) { ++ free(tmpKey); ++ return 0; ++ } ++ tmpKeyData = tmpKeyData->nextKey; ++ } ++ while(tmpKeyData != NULL); ++ ++ // add new key ++ newKeyData = (KeyData*)malloc(sizeof(KeyData)); ++ if(newKeyData == NULL) { ++ free(tmpKey); ++ return 0; ++ } ++ newKeyData->identifier = identifier; ++ newKeyData->provider = provider; ++ if(strlen(keyName) < EMU_MAX_CHAR_KEYNAME) { ++ strncpy(newKeyData->keyName, keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ else { ++ memcpy(newKeyData->keyName, keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ newKeyData->keyName[EMU_MAX_CHAR_KEYNAME-1] = 0; ++ newKeyData->key = tmpKey; ++ newKeyData->keyLength = keyLength; ++ newKeyData->nextKey = NULL; ++ ++ tmpKeyData = &KeyDB->EmuKeys[i]; ++ j = 0; ++ while(tmpKeyData->nextKey != NULL) { ++ if(j == 0xFE) ++ { ++ break; ++ } ++ tmpKeyData = tmpKeyData->nextKey; ++ j++; ++ } ++ if(tmpKeyData->nextKey) ++ { ++ NULLFREE(tmpKeyData->nextKey->key); ++ NULLFREE(tmpKeyData->nextKey); ++ } ++ tmpKeyData->nextKey = newKeyData; ++ ++ if(writeKey) { ++ WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); ++ } ++ } ++ else // identifier != 'I' ++ { ++ free(KeyDB->EmuKeys[i].key); ++ KeyDB->EmuKeys[i].key = tmpKey; ++ KeyDB->EmuKeys[i].keyLength = keyLength; ++ ++ if (identifier == 'F') // Update keyName (i.e. expiration date) for BISS ++ { ++ strncpy(KeyDB->EmuKeys[i].keyName, keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ ++ if(writeKey) { ++ WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); ++ } ++ } ++ ++ return 1; ++ } ++ ++ // key does not exist on db ++ if(KeyDB->keyCount+1 > KeyDB->keyMax) ++ { ++ if(KeyDB->EmuKeys == NULL) // db is empty ++ { ++ KeyDB->EmuKeys = (KeyData*)malloc(sizeof(KeyData)*(KeyDB->keyMax+64)); ++ if(KeyDB->EmuKeys == NULL) { ++ free(tmpKey); ++ return 0; ++ } ++ KeyDB->keyMax+=64; ++ } ++ else // db is full, expand it ++ { ++ tmpKeyData = (KeyData*)realloc(KeyDB->EmuKeys, sizeof(KeyData)*(KeyDB->keyMax+16)); ++ if(tmpKeyData == NULL) { ++ free(tmpKey); ++ return 0; ++ } ++ KeyDB->EmuKeys = tmpKeyData; ++ KeyDB->keyMax+=16; ++ } ++ } ++ ++ KeyDB->EmuKeys[KeyDB->keyCount].identifier = identifier; ++ KeyDB->EmuKeys[KeyDB->keyCount].provider = provider; ++ if(strlen(keyName) < EMU_MAX_CHAR_KEYNAME) { ++ strncpy(KeyDB->EmuKeys[KeyDB->keyCount].keyName, keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ else { ++ memcpy(KeyDB->EmuKeys[KeyDB->keyCount].keyName, keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ KeyDB->EmuKeys[KeyDB->keyCount].keyName[EMU_MAX_CHAR_KEYNAME-1] = 0; ++ KeyDB->EmuKeys[KeyDB->keyCount].key = tmpKey; ++ KeyDB->EmuKeys[KeyDB->keyCount].keyLength = keyLength; ++ KeyDB->EmuKeys[KeyDB->keyCount].nextKey = NULL; ++ KeyDB->keyCount++; ++ ++ if(writeKey) { ++ WriteKeyToFile(identifier, provider, keyName, tmpKey, keyLength, comment); ++ } ++ ++ return 1; ++} ++ ++int32_t FindKey(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, uint8_t *key, ++ uint32_t maxKeyLength, uint8_t isCriticalKey, uint32_t keyRef, uint8_t matchLength, uint32_t *getProvider) ++{ ++ uint32_t i; ++ uint16_t j; ++ uint8_t provider_matching_key_count = 0; ++ KeyDataContainer *KeyDB; ++ KeyData *tmpKeyData; ++ ++ KeyDB = GetKeyContainer(identifier); ++ if(KeyDB == NULL) { ++ return 0; ++ } ++ ++ for(i=0; ikeyCount; i++) { ++ ++ if((KeyDB->EmuKeys[i].provider & ~providerIgnoreMask) != provider) { ++ continue; ++ } ++ ++ // Don't match keyName (i.e. expiration date) for BISS ++ if(identifier != 'F' && strcmp(KeyDB->EmuKeys[i].keyName, keyName)) { ++ continue; ++ } ++ ++ //matchLength cannot be used when multiple keys are allowed ++ //for a single provider/keyName combination. ++ //Currently this is only the case for Irdeto keys. ++ if(matchLength && KeyDB->EmuKeys[i].keyLength != maxKeyLength) { ++ continue; ++ } ++ ++ if(providerIgnoreMask) { ++ if(provider_matching_key_count < keyRef) { ++ provider_matching_key_count++; ++ continue; ++ } ++ else { ++ keyRef = 0; ++ } ++ } ++ ++ tmpKeyData = &KeyDB->EmuKeys[i]; ++ ++ j = 0; ++ while(jnextKey != NULL) { ++ j++; ++ tmpKeyData = tmpKeyData->nextKey; ++ } ++ ++ if(j == keyRef) { ++ memcpy(key, tmpKeyData->key, tmpKeyData->keyLength > maxKeyLength ? maxKeyLength : tmpKeyData->keyLength); ++ if(tmpKeyData->keyLength < maxKeyLength) { ++ memset(key+tmpKeyData->keyLength, 0, maxKeyLength - tmpKeyData->keyLength); ++ } ++ ++ if (identifier == 'F') // Report the keyName of found key back to BissGetKey() ++ { ++ strncpy(keyName, tmpKeyData->keyName, EMU_MAX_CHAR_KEYNAME); ++ } ++ ++ if(getProvider != NULL) { ++ (*getProvider) = tmpKeyData->provider; ++ } ++ return 1; ++ } ++ else { ++ break; ++ } ++ } ++ ++ if (isCriticalKey) ++ { ++ cs_log("Key not found: %c %X %s", identifier, provider, keyName); ++ } ++ ++ return 0; ++} ++ ++static int32_t UpdateKey(char identifier, uint32_t provider, char *keyName, uint8_t *key, uint32_t keyLength, uint8_t writeKey, char *comment) ++{ ++ uint32_t keyRef = 0; ++ uint8_t *tmpKey = (uint8_t*)malloc(sizeof(uint8_t)*keyLength); ++ if(tmpKey == NULL) ++ { ++ return 0; ++ } ++ ++ while(FindKey(identifier, provider, 0, keyName, tmpKey, keyLength, 0, keyRef, 0, NULL)) ++ { ++ if(memcmp(tmpKey, key, keyLength) == 0) ++ { ++ free(tmpKey); ++ return 0; ++ } ++ ++ keyRef++; ++ } ++ ++ free(tmpKey); ++ return SetKey(identifier, provider, keyName, key, keyLength, writeKey, comment, NULL); ++} ++ ++static int32_t UpdateKeysByProviderMask(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, uint8_t *key, ++ uint32_t keyLength, char *comment) ++{ ++ int32_t ret = 0; ++ uint32_t foundProvider = 0; ++ uint32_t keyRef = 0; ++ uint8_t *tmpKey = (uint8_t*)malloc(sizeof(uint8_t)*keyLength); ++ if(tmpKey == NULL) ++ { ++ return 0; ++ } ++ ++ while(FindKey(identifier, (provider & ~providerIgnoreMask), providerIgnoreMask, keyName, tmpKey, keyLength, 0, keyRef, 0, &foundProvider)) ++ { ++ keyRef++; ++ ++ if(memcmp(tmpKey, key, keyLength) == 0) ++ { ++ continue; ++ } ++ ++ if(SetKey(identifier, foundProvider, keyName, key, keyLength, 1, comment, NULL)) ++ { ++ ret = 1; ++ } ++ } ++ ++ free(tmpKey); ++ return ret; ++} ++ ++int32_t DeleteKeysInContainer(char identifier) ++{ ++ // Deletes all keys stored in memory for the specified identifier, ++ // but keeps the container itself, re-initialized at { NULL, 0, 0 }. ++ // Returns the count of deleted keys. ++ ++ uint32_t oldKeyCount, i; ++ KeyData *tmpKeyData; ++ KeyDataContainer *KeyDB = GetKeyContainer(identifier); ++ ++ if (KeyDB == NULL || KeyDB->EmuKeys == NULL || KeyDB->keyCount == 0) ++ { ++ return 0; ++ } ++ ++ for (i = 0; i < KeyDB->keyCount; i++) ++ { ++ // For Irdeto multiple keys only (linked list structure) ++ while (KeyDB->EmuKeys[i].nextKey != NULL) ++ { ++ tmpKeyData = KeyDB->EmuKeys[i].nextKey; ++ KeyDB->EmuKeys[i].nextKey = KeyDB->EmuKeys[i].nextKey->nextKey; ++ free(tmpKeyData->key); // Free key ++ free(tmpKeyData); // Free KeyData ++ } ++ ++ // For single keys (all identifiers, including Irdeto) ++ free(KeyDB->EmuKeys[i].key); // Free key ++ } ++ ++ // Free the KeyData array ++ NULLFREE(KeyDB->EmuKeys); ++ oldKeyCount = KeyDB->keyCount; ++ KeyDB->keyCount = 0; ++ KeyDB->keyMax = 0; ++ ++ return oldKeyCount; ++} ++ ++void clear_emu_keydata(void) ++{ ++ uint32_t total = 0; ++ ++ total = CwKeys.keyCount; ++ total += ViKeys.keyCount; ++ total += NagraKeys.keyCount; ++ total += IrdetoKeys.keyCount; ++ total += NDSKeys.keyCount; ++ total += BissKeys.keyCount; ++ total += PowervuKeys.keyCount; ++ total += DreKeys.keyCount; ++ total += TandbergKeys.keyCount; ++ ++ if (total != 0) ++ { ++ cs_log("Freeing keys in memory: W:%d V:%d N:%d I:%d S:%d F:%d P:%d D:%d T:%d", \ ++ CwKeys.keyCount, ViKeys.keyCount, NagraKeys.keyCount, \ ++ IrdetoKeys.keyCount, NDSKeys.keyCount, BissKeys.keyCount, \ ++ PowervuKeys.keyCount, DreKeys.keyCount, TandbergKeys.keyCount); ++ ++ DeleteKeysInContainer('W'); ++ DeleteKeysInContainer('V'); ++ DeleteKeysInContainer('N'); ++ DeleteKeysInContainer('I'); ++ DeleteKeysInContainer('S'); ++ DeleteKeysInContainer('F'); ++ DeleteKeysInContainer('P'); ++ DeleteKeysInContainer('D'); ++ DeleteKeysInContainer('T'); ++ } ++} ++ ++uint8_t read_emu_keyfile(struct s_reader *rdr, const char *opath) ++{ ++ char line[1200], keyName[EMU_MAX_CHAR_KEYNAME], keyString[1026]; ++ uint32_t pathLength, provider, keyLength; ++ uint8_t *key; ++ struct dirent *pDirent; ++ DIR *pDir; ++ char *path, *filepath, filename[EMU_KEY_FILENAME_MAX_LEN+1]; ++ FILE *file = NULL; ++ char identifier; ++ uint8_t fileNameLen = strlen(EMU_KEY_FILENAME); ++ ++ pathLength = strlen(opath); ++ path = (char*)malloc(pathLength+1); ++ if(path == NULL) { ++ return 0; ++ } ++ strncpy(path, opath, pathLength+1); ++ ++ pathLength = strlen(path); ++ if(pathLength >= fileNameLen && strcasecmp(path+pathLength-fileNameLen, EMU_KEY_FILENAME) == 0) { ++ // cut file name ++ path[pathLength-fileNameLen] = '\0'; ++ } ++ ++ pathLength = strlen(path); ++ if(path[pathLength-1] == '/' || path[pathLength-1] == '\\') { ++ // cut trailing / ++ path[pathLength-1] = '\0'; ++ } ++ ++ pDir = opendir(path); ++ if (pDir == NULL) { ++ cs_log("Cannot open key file path: %s", path); ++ free(path); ++ return 0; ++ } ++ ++ while((pDirent = readdir(pDir)) != NULL) { ++ if(strcasecmp(pDirent->d_name, EMU_KEY_FILENAME) == 0) { ++ strncpy(filename, pDirent->d_name, sizeof(filename)); ++ break; ++ } ++ } ++ closedir(pDir); ++ ++ if(pDirent == NULL) { ++ cs_log("Key file not found in: %s", path); ++ free(path); ++ return 0; ++ } ++ ++ pathLength = strlen(path)+1+strlen(filename)+1; ++ filepath = (char*)malloc(pathLength); ++ if(filepath == NULL) { ++ free(path); ++ return 0; ++ } ++ snprintf(filepath, pathLength, "%s/%s", path, filename); ++ free(path); ++ ++ cs_log("Reading key file: %s", filepath); ++ ++ file = fopen(filepath, "r"); ++ free(filepath); ++ if(file == NULL) { ++ return 0; ++ } ++ ++ set_emu_keyfile_path(opath); ++ ++ while(fgets(line, 1200, file)) { ++ if(sscanf(line, "%c %8x %11s %1024s", &identifier, &provider, keyName, keyString) != 4) { ++ continue; ++ } ++ ++ keyLength = strlen(keyString)/2; ++ key = (uint8_t*)malloc(keyLength); ++ if(key == NULL) { ++ fclose(file); ++ return 0; ++ } ++ ++ if (CharToBin(key, keyString, strlen(keyString))) // Conversion OK ++ { ++ SetKey(identifier, provider, keyName, key, keyLength, 0, NULL, rdr); ++ } ++ else // Non-hex characters in keyString ++ { ++ if ((identifier != ';' && identifier != '#' && // Skip warning for comments, etc. ++ identifier != '=' && identifier != '-' && ++ identifier != ' ') && ++ !(identifier == 'F' && 0 == strncmp(keyString, "XXXXXXXXXXXX", 12))) // Skip warning for BISS 'Example key' lines ++ { ++ // Alert user regarding faulty line ++ cs_log("WARNING: non-hex value in %s at %c %04X %s %s", EMU_KEY_FILENAME, identifier, provider, keyName, keyString); ++ } ++ } ++ free(key); ++ } ++ fclose(file); ++ ++ return 1; ++} ++ ++#if !defined(__APPLE__) && !defined(__ANDROID__) ++extern uint8_t SoftCamKey_Data[] __asm__("_binary_SoftCam_Key_start"); ++extern uint8_t SoftCamKey_DataEnd[] __asm__("_binary_SoftCam_Key_end"); ++ ++void read_emu_keymemory(struct s_reader *rdr) ++{ ++ char *keyData, *line, *saveptr, keyName[EMU_MAX_CHAR_KEYNAME], keyString[1026]; ++ uint32_t provider, keyLength; ++ uint8_t *key; ++ char identifier; ++ ++ keyData = (char*)malloc(SoftCamKey_DataEnd-SoftCamKey_Data+1); ++ if(keyData == NULL) { ++ return; ++ } ++ memcpy(keyData, SoftCamKey_Data, SoftCamKey_DataEnd-SoftCamKey_Data); ++ keyData[SoftCamKey_DataEnd-SoftCamKey_Data] = 0x00; ++ ++ line = strtok_r(keyData, "\n", &saveptr); ++ while(line != NULL) { ++ if(sscanf(line, "%c %8x %11s %1024s", &identifier, &provider, keyName, keyString) != 4) { ++ line = strtok_r(NULL, "\n", &saveptr); ++ continue; ++ } ++ keyLength = strlen(keyString)/2; ++ key = (uint8_t*)malloc(keyLength); ++ if(key == NULL) { ++ free(keyData); ++ return; ++ } ++ ++ if (CharToBin(key, keyString, strlen(keyString))) // Conversion OK ++ { ++ SetKey(identifier, provider, keyName, key, keyLength, 0, NULL, rdr); ++ } ++ else // Non-hex characters in keyString ++ { ++ if ((identifier != ';' && identifier != '#' && // Skip warning for comments, etc. ++ identifier != '=' && identifier != '-' && ++ identifier != ' ') && ++ !(identifier == 'F' && 0 == strncmp(keyString, "XXXXXXXXXXXX", 12))) // Skip warning for BISS 'Example key' lines ++ { ++ // Alert user regarding faulty line ++ cs_log("WARNING: non-hex value in internal keyfile at %c %04X %s %s", identifier, provider, keyName, keyString); ++ } ++ } ++ free(key); ++ line = strtok_r(NULL, "\n", &saveptr); ++ } ++ free(keyData); ++} ++#endif ++ ++void read_emu_eebin(const char *path, const char *name) ++{ ++ char tmp[256]; ++ FILE *file = NULL; ++ uint8_t i, buffer[64][32], dummy[2][32]; ++ uint32_t prvid; ++ ++ // Set path ++ if (path != NULL) ++ { ++ snprintf(tmp, 256, "%s%s", path, name); ++ } ++ else // No path set, use SoftCam.Keys's path ++ { ++ snprintf(tmp, 256, "%s%s", emu_keyfile_path, name); ++ } ++ ++ // Read file to buffer ++ if ((file = fopen(tmp, "rb")) != NULL) ++ { ++ cs_log("Reading key file: %s", tmp); ++ ++ if (fread(buffer, 1, sizeof(buffer), file) != sizeof(buffer)) ++ { ++ cs_log("Corrupt key file: %s", tmp); ++ fclose(file); ++ return; ++ } ++ ++ fclose(file); ++ } ++ else ++ { ++ if (path != NULL) ++ { ++ cs_log("Cannot open key file: %s", tmp); ++ } ++ ++ return; ++ } ++ ++ // Save keys to db ++ memset(dummy[0], 0x00, 32); ++ memset(dummy[1], 0xFF, 32); ++ prvid = (strncmp(name, "ee36.bin", 9) == 0) ? 0x4AE111 : 0x4AE114; ++ ++ for (i = 0; i < 32; i++) // Set "3B" type keys ++ { ++ // Write keys if they have "real" values ++ if ((memcmp(buffer[i], dummy[0], 32) !=0) && (memcmp(buffer[i], dummy[1], 32) != 0)) ++ { ++ snprintf(tmp, 5, "3B%02X", i); ++ SetKey('D', prvid, tmp, buffer[i], 32, 0, NULL, NULL); ++ } ++ } ++ ++ for (i = 0; i < 32; i++) // Set "56" type keys ++ { ++ // Write keys if they have "real" values ++ if ((memcmp(buffer[32 + i], dummy[0], 32) !=0) && (memcmp(buffer[32 + i], dummy[1], 32) != 0)) ++ { ++ snprintf(tmp, 5, "56%02X", i); ++ SetKey('D', prvid, tmp, buffer[32 + i], 32, 0, NULL, NULL); ++ } ++ } ++} ++ ++void read_emu_deskey(uint8_t *dreOverKey, uint8_t len) ++{ ++ uint8_t i; ++ ++ if (len == 128) ++ { ++ cs_log("Reading DreCrypt overcrypt (ADEC) key"); ++ ++ for (i = 0; i < 16; i++) ++ { ++ SetKey('D', i, "OVER", dreOverKey + (i * 8), 8, 0, NULL, NULL); ++ } ++ } ++ else if ((len != 0 && len < 128) || len > 128) ++ { ++ cs_log("DreCrypt overcrypt (ADEC) key has wrong length"); ++ } ++} ++ ++// Shared functions ++ ++static inline uint16_t GetEcmLen(const uint8_t *ecm) ++{ ++ return (((ecm[1] & 0x0f)<< 8) | ecm[2]) +3; ++} ++ ++static void ReverseMem(uint8_t *in, int32_t len) ++{ ++ uint8_t temp; ++ int32_t i; ++ for(i = 0; i < (len / 2); i++) { ++ temp = in[i]; ++ in[i] = in[len - i - 1]; ++ in[len - i - 1] = temp; ++ } ++} ++ ++static void ReverseMemInOut(uint8_t *out, const uint8_t *in, int32_t n) ++{ ++ if(n>0) { ++ out+=n; ++ do { ++ *(--out)=*(in++); ++ } ++ while(--n); ++ } ++} ++ ++static int8_t EmuRSAInput(BIGNUM *d, const uint8_t *in, int32_t n, int8_t le) ++{ ++ int8_t result = 0; ++ ++ if(le) { ++ uint8_t *tmp = (uint8_t *)malloc(sizeof(uint8_t)*n); ++ if(tmp == NULL) { ++ return 0; ++ } ++ ReverseMemInOut(tmp,in,n); ++ result = BN_bin2bn(tmp,n,d)!=0; ++ free(tmp); ++ } ++ else { ++ result = BN_bin2bn(in,n,d)!=0; ++ } ++ return result; ++} ++ ++static int32_t EmuRSAOutput(uint8_t *out, int32_t n, BIGNUM *r, int8_t le) ++{ ++ int32_t s = BN_num_bytes(r); ++ if(s>n) { ++ uint8_t *buff = (uint8_t *)malloc(sizeof(uint8_t)*s); ++ if(buff == NULL) { ++ return 0; ++ } ++ BN_bn2bin(r,buff); ++ memcpy(out,buff+s-n,n); ++ free(buff); ++ } ++ else if(s> 1) & 0xFE)); ++ key[2] = ((tmpKey[1] << 6) | ((tmpKey[2] >> 2) & 0xFE)); ++ key[3] = ((tmpKey[2] << 5) | ((tmpKey[3] >> 3) & 0xFE)); ++ key[4] = ((tmpKey[3] << 4) | ((tmpKey[4] >> 4) & 0xFE)); ++ key[5] = ((tmpKey[4] << 3) | ((tmpKey[5] >> 5) & 0xFE)); ++ key[6] = ((tmpKey[5] << 2) | ((tmpKey[6] >> 6) & 0xFE)); ++ key[7] = (tmpKey[6] << 1); ++ ++ for (i = 0; i < 8; i++) ++ { ++ parity = 1; ++ for (j = 1; j < 8; j++) if ((key[i] >> j) & 0x1) { parity = ~parity & 0x01; } ++ key[i] |= parity; ++ } ++} ++ ++// Cryptoworks EMU ++static int8_t GetCwKey(uint8_t *buf,uint32_t ident, uint8_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey) ++{ ++ ++ char keyName[EMU_MAX_CHAR_KEYNAME]; ++ uint32_t tmp; ++ ++ if((ident >> 4) == 0xD02A) { ++ keyIndex &=0xFE; // map to even number key indexes ++ } ++ if((ident >> 4) == 0xD00C) { ++ ident = 0x0D00C0; // map provider C? to C0 ++ } ++ else if(keyIndex == 6 && ((ident >> 8) == 0x0D05)) { ++ ident = 0x0D0504; // always use provider 04 system key ++ } ++ ++ tmp = keyIndex; ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", tmp); ++ if(FindKey('W', ident, 0, keyName, buf, keyLength, isCriticalKey, 0, 0, NULL)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static const uint8_t cw_sbox1[64] = { ++ 0xD8,0xD7,0x83,0x3D,0x1C,0x8A,0xF0,0xCF,0x72,0x4C,0x4D,0xF2,0xED,0x33,0x16,0xE0, ++ 0x8F,0x28,0x7C,0x82,0x62,0x37,0xAF,0x59,0xB7,0xE0,0x00,0x3F,0x09,0x4D,0xF3,0x94, ++ 0x16,0xA5,0x58,0x83,0xF2,0x4F,0x67,0x30,0x49,0x72,0xBF,0xCD,0xBE,0x98,0x81,0x7F, ++ 0xA5,0xDA,0xA7,0x7F,0x89,0xC8,0x78,0xA7,0x8C,0x05,0x72,0x84,0x52,0x72,0x4D,0x38 ++}; ++static const uint8_t cw_sbox2[64] = { ++ 0xD8,0x35,0x06,0xAB,0xEC,0x40,0x79,0x34,0x17,0xFE,0xEA,0x47,0xA3,0x8F,0xD5,0x48, ++ 0x0A,0xBC,0xD5,0x40,0x23,0xD7,0x9F,0xBB,0x7C,0x81,0xA1,0x7A,0x14,0x69,0x6A,0x96, ++ 0x47,0xDA,0x7B,0xE8,0xA1,0xBF,0x98,0x46,0xB8,0x41,0x45,0x9E,0x5E,0x20,0xB2,0x35, ++ 0xE4,0x2F,0x9A,0xB5,0xDE,0x01,0x65,0xF8,0x0F,0xB2,0xD2,0x45,0x21,0x4E,0x2D,0xDB ++}; ++static const uint8_t cw_sbox3[64] = { ++ 0xDB,0x59,0xF4,0xEA,0x95,0x8E,0x25,0xD5,0x26,0xF2,0xDA,0x1A,0x4B,0xA8,0x08,0x25, ++ 0x46,0x16,0x6B,0xBF,0xAB,0xE0,0xD4,0x1B,0x89,0x05,0x34,0xE5,0x74,0x7B,0xBB,0x44, ++ 0xA9,0xC6,0x18,0xBD,0xE6,0x01,0x69,0x5A,0x99,0xE0,0x87,0x61,0x56,0x35,0x76,0x8E, ++ 0xF7,0xE8,0x84,0x13,0x04,0x7B,0x9B,0xA6,0x7A,0x1F,0x6B,0x5C,0xA9,0x86,0x54,0xF9 ++}; ++static const uint8_t cw_sbox4[64] = { ++ 0xBC,0xC1,0x41,0xFE,0x42,0xFB,0x3F,0x10,0xB5,0x1C,0xA6,0xC9,0xCF,0x26,0xD1,0x3F, ++ 0x02,0x3D,0x19,0x20,0xC1,0xA8,0xBC,0xCF,0x7E,0x92,0x4B,0x67,0xBC,0x47,0x62,0xD0, ++ 0x60,0x9A,0x9E,0x45,0x79,0x21,0x89,0xA9,0xC3,0x64,0x74,0x9A,0xBC,0xDB,0x43,0x66, ++ 0xDF,0xE3,0x21,0xBE,0x1E,0x16,0x73,0x5D,0xA2,0xCD,0x8C,0x30,0x67,0x34,0x9C,0xCB ++}; ++static const uint8_t AND_bit1[8] = {0x00,0x40,0x04,0x80,0x21,0x10,0x02,0x08}; ++static const uint8_t AND_bit2[8] = {0x80,0x08,0x01,0x40,0x04,0x20,0x10,0x02}; ++static const uint8_t AND_bit3[8] = {0x82,0x40,0x01,0x10,0x00,0x20,0x04,0x08}; ++static const uint8_t AND_bit4[8] = {0x02,0x10,0x04,0x40,0x80,0x08,0x01,0x20}; ++ ++static void CW_SWAP_KEY(uint8_t *key) ++{ ++ uint8_t k[8]; ++ memcpy(k, key, 8); ++ memcpy(key, key + 8, 8); ++ memcpy(key + 8, k, 8); ++} ++ ++static void CW_SWAP_DATA(uint8_t *k) ++{ ++ uint8_t d[4]; ++ memcpy(d, k + 4, 4); ++ memcpy(k + 4 ,k ,4); ++ memcpy(k, d, 4); ++} ++ ++static void CW_DES_ROUND(uint8_t *d, uint8_t *k) ++{ ++ uint8_t aa[44] = {1,0,3,1,2,2,3,2,1,3,1,1,3,0,1,2,3,1,3,2,2,0,7,6,5,4,7,6,5,7,6,5,6,7,5,7,5,7,6,6,7,5,4,4}; ++ uint8_t bb[44] = {0x80,0x08,0x10,0x02,0x08,0x40,0x01,0x20,0x40,0x80,0x04,0x10,0x04,0x01,0x01,0x02,0x20,0x20,0x02,0x01, ++ 0x80,0x04,0x02,0x02,0x08,0x02,0x10,0x80,0x01,0x20,0x08,0x80,0x01,0x08,0x40,0x01,0x02,0x80,0x10,0x40,0x40,0x10,0x08,0x01 ++ }; ++ uint8_t ff[4] = {0x02,0x10,0x04,0x04}; ++ uint8_t l[24] = {0,2,4,6,7,5,3,1,4,5,6,7,7,6,5,4,7,4,5,6,4,7,6,5}; ++ ++ uint8_t des_td[8], i, o, n, c = 1, m = 0, r = 0, *a = aa, *b = bb, *f = ff, *p1 = l, *p2 = l+8, *p3 = l+16; ++ ++ for (m = 0; m < 2; m++) { ++ for(i = 0; i < 4; i++) { ++ des_td[*p1++] = ++ (m) ? ((d[*p2++]*2) & 0x3F) | ((d[*p3++] & 0x80) ? 0x01 : 0x00): (d[*p2++]/2) | ((d[*p3++] & 0x01) ? 0x80 : 0x00); ++ } ++ } ++ ++ for (i = 0; i < 8; i++) { ++ c = (c) ? 0 : 1; ++ r = (c) ? 6 : 7; ++ n = (i) ? i-1 : 1; ++ o = (c) ? ((k[n] & *f++) ? 1 : 0) : des_td[n]; ++ for (m = 1; m < r; m++) { ++ o = (c) ? (o*2) | ((k[*a++] & *b++) ? 0x01 : 0x00) : (o/2) | ((k[*a++] & *b++) ? 0x80 : 0x00); ++ } ++ n = (i) ? n+1 : 0; ++ des_td[n] = (c) ? des_td[n] ^ o : (o ^ des_td[n] )/4; ++ } ++ ++ for( i = 0; i < 8; i++) { ++ d[0] ^= (AND_bit1[i] & cw_sbox1[des_td[i]]); ++ d[1] ^= (AND_bit2[i] & cw_sbox2[des_td[i]]); ++ d[2] ^= (AND_bit3[i] & cw_sbox3[des_td[i]]); ++ d[3] ^= (AND_bit4[i] & cw_sbox4[des_td[i]]); ++ } ++ ++ CW_SWAP_DATA(d); ++} ++ ++static void CW_48_Key(uint8_t *inkey, uint8_t *outkey, uint8_t algotype) ++{ ++ uint8_t Round_Counter, i = 8, *key128 = inkey, *key48 = inkey + 0x10; ++ Round_Counter = 7 - (algotype & 7); ++ ++ memset(outkey, 0, 16); ++ memcpy(outkey, key48, 6); ++ ++ for( ; i > Round_Counter; i--) { ++ if (i > 1) { ++ outkey[i-2] = key128[i]; ++ } ++ } ++} ++ ++static void CW_LS_DES_KEY(uint8_t *key,uint8_t Rotate_Counter) ++{ ++ uint8_t round[] = {1,2,2,2,2,2,2,1,2,2,2,2,2,2,1,1}; ++ uint8_t i, n; ++ uint16_t k[8]; ++ ++ n = round[Rotate_Counter]; ++ ++ for (i = 0; i < 8; i++) { ++ k[i] = key[i]; ++ } ++ ++ for (i = 1; i < n + 1; i++) { ++ k[7] = (k[7]*2) | ((k[4] & 0x008) ? 1 : 0); ++ k[6] = (k[6]*2) | ((k[7] & 0xF00) ? 1 : 0); ++ k[7] &=0xff; ++ k[5] = (k[5]*2) | ((k[6] & 0xF00) ? 1 : 0); ++ k[6] &=0xff; ++ k[4] = ((k[4]*2) | ((k[5] & 0xF00) ? 1 : 0)) & 0xFF; ++ k[5] &= 0xff; ++ k[3] = (k[3]*2) | ((k[0] & 0x008) ? 1 : 0); ++ k[2] = (k[2]*2) | ((k[3] & 0xF00) ? 1 : 0); ++ k[3] &= 0xff; ++ k[1] = (k[1]*2) | ((k[2] & 0xF00) ? 1 : 0); ++ k[2] &= 0xff; ++ k[0] = ((k[0]*2) | ((k[1] & 0xF00) ? 1 : 0)) & 0xFF; ++ k[1] &= 0xff; ++ } ++ for (i = 0; i < 8; i++) { ++ key[i] = (uint8_t) k[i]; ++ } ++} ++ ++static void CW_RS_DES_KEY(uint8_t *k, uint8_t Rotate_Counter) ++{ ++ uint8_t i,c; ++ for (i = 1; i < Rotate_Counter+1; i++) { ++ c = (k[3] & 0x10) ? 0x80 : 0; ++ k[3] /= 2; ++ if (k[2] & 1) { ++ k[3] |= 0x80; ++ } ++ k[2] /= 2; ++ if (k[1] & 1) { ++ k[2] |= 0x80; ++ } ++ k[1] /= 2; ++ if (k[0] & 1) { ++ k[1] |= 0x80; ++ } ++ k[0] /= 2; ++ k[0] |= c ; ++ c = (k[7] & 0x10) ? 0x80 : 0; ++ k[7] /= 2; ++ if (k[6] & 1) { ++ k[7] |= 0x80; ++ } ++ k[6] /= 2; ++ if (k[5] & 1) { ++ k[6] |= 0x80; ++ } ++ k[5] /= 2; ++ if (k[4] & 1) { ++ k[5] |= 0x80; ++ } ++ k[4] /= 2; ++ k[4] |= c; ++ } ++} ++ ++static void CW_RS_DES_SUBKEY(uint8_t *k, uint8_t Rotate_Counter) ++{ ++ uint8_t round[] = {1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1}; ++ CW_RS_DES_KEY(k, round[Rotate_Counter]); ++} ++ ++static void CW_PREP_KEY(uint8_t *key ) ++{ ++ uint8_t DES_key[8],j; ++ int32_t Round_Counter = 6,i,a; ++ key[7] = 6; ++ memset(DES_key, 0 , 8); ++ do { ++ a = 7; ++ i = key[7]; ++ j = key[Round_Counter]; ++ do { ++ DES_key[i] = ( (DES_key[i] * 2) | ((j & 1) ? 1: 0) ) & 0xFF; ++ j /=2; ++ i--; ++ if (i < 0) { ++ i = 6; ++ } ++ a--; ++ } ++ while (a >= 0); ++ key[7] = i; ++ Round_Counter--; ++ } ++ while ( Round_Counter >= 0 ); ++ a = DES_key[4]; ++ DES_key[4] = DES_key[6]; ++ DES_key[6] = a; ++ DES_key[7] = (DES_key[3] * 16) & 0xFF; ++ memcpy(key,DES_key,8); ++ CW_RS_DES_KEY(key,4); ++} ++ ++static void CW_L2DES(uint8_t *data, uint8_t *key, uint8_t algo) ++{ ++ uint8_t i, k0[22], k1[22]; ++ memcpy(k0,key,22); ++ memcpy(k1,key,22); ++ CW_48_Key(k0, k1,algo); ++ CW_PREP_KEY(k1); ++ for (i = 0; i< 2; i++) { ++ CW_LS_DES_KEY( k1,15); ++ CW_DES_ROUND( data ,k1); ++ } ++} ++ ++static void CW_R2DES(uint8_t *data, uint8_t *key, uint8_t algo) ++{ ++ uint8_t i, k0[22],k1[22]; ++ memcpy(k0,key,22); ++ memcpy(k1,key,22); ++ CW_48_Key(k0, k1, algo); ++ CW_PREP_KEY(k1); ++ for (i = 0; i< 2; i++) { ++ CW_LS_DES_KEY(k1,15); ++ } ++ for (i = 0; i< 2; i++) { ++ CW_DES_ROUND( data ,k1); ++ CW_RS_DES_SUBKEY(k1,1); ++ } ++ CW_SWAP_DATA(data); ++} ++ ++static void CW_DES(uint8_t *data, uint8_t *inkey, uint8_t m) ++{ ++ uint8_t key[22], i; ++ memcpy(key, inkey + 9, 8); ++ CW_PREP_KEY( key ); ++ for (i = 16; i > 0; i--) { ++ if (m == 1) { ++ CW_LS_DES_KEY(key, (uint8_t) (i-1)); ++ } ++ CW_DES_ROUND( data ,key); ++ if (m == 0) { ++ CW_RS_DES_SUBKEY(key, (uint8_t) (i-1)); ++ } ++ } ++} ++ ++static void CW_DEC_ENC(uint8_t *d, uint8_t *k, uint8_t a,uint8_t m) ++{ ++ uint8_t n = m & 1; ++ CW_L2DES(d , k, a); ++ CW_DES (d , k, n); ++ CW_R2DES(d , k, a); ++ if (m & 2) { ++ CW_SWAP_KEY(k); ++ } ++} ++ ++static void Cryptoworks3DES(uint8_t *data, uint8_t *key) ++{ ++ uint32_t ks1[32], ks2[32]; ++ ++ des_set_key(key, ks1); ++ des_set_key(key+8, ks2); ++ ++ des(data, ks1, 0); ++ des(data, ks2, 1); ++ des(data, ks1, 0); ++} ++ ++static uint8_t CryptoworksProcessNano80(uint8_t *data, uint32_t caid, int32_t provider, uint8_t *opKey, uint8_t nanoLength, uint8_t nano80Algo) ++{ ++ int32_t i, j; ++ uint8_t key[16], desKey[16], t[8], dat1[8], dat2[8], k0D00C000[16]; ++ if(nanoLength < 11) { ++ return 0; ++ } ++ if(caid == 0x0D00 && provider != 0xA0 && !GetCwKey(k0D00C000, 0x0D00C0, 0, 16, 1)) { ++ return 0; ++ } ++ ++ if(nano80Algo > 1) { ++ return 0; ++ } ++ ++ memset(t, 0, 8); ++ memcpy(dat1, data, 8); ++ ++ if(caid == 0x0D00 && provider != 0xA0) { ++ memcpy(key, k0D00C000, 16); ++ } ++ else { ++ memcpy(key, opKey, 16); ++ } ++ Cryptoworks3DES(data, key); ++ memcpy(desKey, data, 8); ++ ++ memcpy(data, dat1, 8); ++ if(caid == 0x0D00 && provider != 0xA0) { ++ memcpy(key, &k0D00C000[8], 8); ++ memcpy(&key[8], k0D00C000, 8); ++ } ++ else { ++ memcpy(key, &opKey[8], 8); ++ memcpy(&key[8], opKey, 8); ++ } ++ Cryptoworks3DES(data, key); ++ memcpy(&desKey[8], data, 8); ++ ++ for(i=8; i+7 7) { ++ if (first) { ++ CW_L2DES(signature, key, algo); ++ } ++ CW_DES(signature, key, 1); ++ ++ sigPos = 0; ++ first = 0; ++ } ++ } ++ if(sigPos > 0) { ++ CW_DES(signature, key, 1); ++ } ++ CW_R2DES(signature, key, algo); ++} ++ ++static void CryptoworksDecryptDes(uint8_t *data, uint8_t algo, uint8_t *key) ++{ ++ int32_t i; ++ uint8_t k[22], t[8]; ++ ++ algo &= 7; ++ if(algo<7) { ++ CW_DEC_ENC(data, key, algo, 0); ++ } ++ else { ++ memcpy(k, key, 22); ++ for(i=0; i<3; i++) { ++ CW_DEC_ENC(data, k, algo, i&1); ++ memcpy(t,k,8); ++ memcpy(k,k+8,8); ++ memcpy(k+8,t,8); ++ } ++ } ++} ++ ++static int8_t CryptoworksECM(uint32_t caid, uint8_t *ecm, uint8_t *cw) ++{ ++ uint32_t ident; ++ uint8_t keyIndex = 0, nanoLength, newEcmLength, key[22], signature[8], nano80Algo = 1; ++ int32_t provider = -1; ++ uint16_t i, j, ecmLen = GetEcmLen(ecm); ++ ++ if(ecmLen < 8) { ++ return 1; ++ } ++ if(ecm[7] != ecmLen - 8) { ++ return 1; ++ } ++ ++ memset(key, 0, 22); ++ ++ for(i = 8; i+1 < ecmLen; i += ecm[i+1] + 2) { ++ if(ecm[i] == 0x83 && i+2 < ecmLen) { ++ provider = ecm[i+2] & 0xFC; ++ keyIndex = ecm[i+2] & 3; ++ keyIndex = keyIndex ? 1 : 0; ++ } ++ else if(ecm[i] == 0x84 && i+3 < ecmLen) { ++ //nano80Provider = ecm[i+2] & 0xFC; ++ //nano80KeyIndex = ecm[i+2] & 3; ++ //nano80KeyIndex = nano80KeyIndex ? 1 : 0; ++ nano80Algo = ecm[i+3]; ++ } ++ } ++ ++ if(provider < 0) { ++ switch(caid) { ++ case 0x0D00: ++ provider = 0xC0; ++ break; ++ case 0x0D02: ++ provider = 0xA0; ++ break; ++ case 0x0D03: ++ provider = 0x04; ++ break; ++ case 0x0D05: ++ provider = 0x04; ++ break; ++ default: ++ return 1; ++ } ++ } ++ ++ ident = (caid << 8) | provider; ++ if(!GetCwKey(key, ident, keyIndex, 16, 1)) { ++ return 2; ++ } ++ if(!GetCwKey(&key[16], ident, 6, 6, 1)) { ++ return 2; ++ } ++ ++ for(i = 8; i+1 < ecmLen; i += ecm[i+1] + 2) { ++ if(ecm[i] == 0x80 && i+2+7 < ecmLen && i+2+ecm[i+1] <= ecmLen ++ && (provider == 0xA0 || provider == 0xC0 || provider == 0xC4 || provider == 0xC8)) { ++ nanoLength = ecm[i+1]; ++ newEcmLength = CryptoworksProcessNano80(ecm+i+2, caid, provider, key, nanoLength, nano80Algo); ++ if(newEcmLength == 0 || newEcmLength > ecmLen-(i+2+3)) { ++ return 1; ++ } ++ ecm[i+2+3] = 0x81; ++ ecm[i+2+4] = 0x70; ++ ecm[i+2+5] = newEcmLength; ++ ecm[i+2+6] = 0x81; ++ ecm[i+2+7] = 0xFF; ++ return CryptoworksECM(caid, ecm+i+2+3, cw); ++ } ++ } ++ ++ if(ecmLen - 15 < 1) { ++ return 1; ++ } ++ CryptoworksSignature(ecm + 5, ecmLen - 15, key, signature); ++ for(i = 8; i+1 < ecmLen; i += ecm[i+1]+2) { ++ switch(ecm[i]) { ++ case 0xDA: ++ case 0xDB: ++ case 0xDC: ++ if(i+2+ecm[i+1] > ecmLen) { ++ break; ++ } ++ for(j=0; j+7 ecmLen) { ++ break; ++ } ++ if(memcmp(&ecm[i+2], signature, 8)) { ++ return 6; ++ } ++ break; ++ } ++ } ++ ++ for(i = 8; i+1 < ecmLen; i += ecm[i+1]+2) { ++ switch(ecm[i]) { ++ case 0xDB: ++ if(i+2+ecm[i+1] <= ecmLen && ecm[i+1] == 16) { ++ memcpy(cw, &ecm[i+2], 16); ++ return 0; ++ } ++ break; ++ } ++ } ++ ++ return 5; ++} ++ ++// SoftNDS EMU ++static const uint8_t nds_const[]= {0x0F,0x1E,0x2D,0x3C,0x4B,0x5A,0x69,0x78,0x87,0x96,0xA5,0xB4,0xC3,0xD2,0xE1,0xF0}; ++ ++uint8_t viasat_const[]= { ++ 0x15,0x85,0xC5,0xE4,0xB8,0x52,0xEC,0xF7,0xC3,0xD9,0x08,0xBA,0x22,0x4A,0x66,0xF2, ++ 0x82,0x15,0x4F,0xB2,0x18,0x48,0x63,0x97,0xDC,0x19,0xD8,0x51,0x9A,0x39,0xFC,0xCA, ++ 0x1C,0x24,0xD0,0x65,0xA9,0x66,0x2D,0xD6,0x53,0x3B,0x86,0xBA,0x40,0xEA,0x4C,0x6D, ++ 0xD9,0x1E,0x41,0x14,0xFE,0x15,0xAF,0xC3,0x18,0xC5,0xF8,0xA7,0xA8,0x01,0x00,0x01, ++}; ++ ++static int8_t SoftNDSECM(uint16_t caid, uint8_t *ecm, uint8_t *dw) ++{ ++ int32_t i; ++ uint8_t *tDW, irdEcmLen, offsetCw = 0, offsetP2 = 0; ++ uint8_t digest[16], md5_const[64]; ++ MD5_CTX mdContext; ++ uint16_t ecmLen = GetEcmLen(ecm); ++ ++ if(ecmLen < 7) { ++ return 1; ++ } ++ ++ if(ecm[3] != 0x00 || ecm[4] != 0x00 || ecm[5] != 0x01) { ++ return 1; ++ } ++ ++ irdEcmLen = ecm[6]; ++ if(irdEcmLen < (10+3+8+4) || irdEcmLen+6 >= ecmLen) { ++ return 1; ++ } ++ ++ for(i=0; 10+i+2 < irdEcmLen; i++) { ++ if(ecm[17+i] == 0x0F && ecm[17+i+1] == 0x40 && ecm[17+i+2] == 0x00) { ++ offsetCw = 17+i+3; ++ offsetP2 = offsetCw+9; ++ } ++ } ++ ++ if(offsetCw == 0 || offsetP2 == 0) { ++ return 1; ++ } ++ ++ if(offsetP2-7+4 > irdEcmLen) { ++ return 1; ++ } ++ ++ if(caid == 0x090F || caid == 0x093E) { ++ memcpy(md5_const, viasat_const, 64); ++ } ++ else if(!FindKey('S', caid, 0, "00", md5_const, 64, 1, 0, 0, NULL)) { ++ return 2; ++ } ++ ++ memset(dw,0,16); ++ tDW = &dw[ecm[0] == 0x81 ? 8 : 0]; ++ ++ MD5_Init(&mdContext); ++ MD5_Update(&mdContext, ecm+7, 10); ++ MD5_Update(&mdContext, ecm+offsetP2, 4); ++ MD5_Update(&mdContext, md5_const, 64); ++ MD5_Update(&mdContext, nds_const, 16); ++ MD5_Final(digest, &mdContext); ++ ++ for (i=0; i<8; i++) { ++ tDW[i] = digest[i+8] ^ ecm[offsetCw+i]; ++ } ++ ++ if(((tDW[0]+tDW[1]+tDW[2])&0xFF)-tDW[3]) { ++ return 6; ++ } ++ if(((tDW[4]+tDW[5]+tDW[6])&0xFF)-tDW[7]) { ++ return 6; ++ } ++ ++ return 0; ++} ++ ++// Viaccess EMU ++static int8_t GetViaKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey) ++{ ++ ++ char keyStr[EMU_MAX_CHAR_KEYNAME]; ++ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); ++ if(FindKey('V', ident, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) { ++ return 1; ++ } ++ ++ if(ident == 0xD00040 && FindKey('V', 0x030B00, 0, keyStr, buf, keyLength, isCriticalKey, 0, 0, NULL)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void Via1Mod(const uint8_t* key2, uint8_t* data) ++{ ++ int32_t kb, db; ++ for (db=7; db>=0; db--) { ++ for (kb=7; kb>3; kb--) { ++ int32_t a0=kb^db; ++ int32_t pos=7; ++ if (a0&4) { ++ a0^=7; ++ pos^=7; ++ } ++ a0=(a0^(kb&3)) + (kb&3); ++ if (!(a0&4)) { ++ data[db]^=(key2[kb] ^ ((data[kb^pos]*key2[kb^4]) & 0xFF)); ++ } ++ } ++ } ++ for (db=0; db<8; db++) { ++ for (kb=0; kb<4; kb++) { ++ int32_t a0=kb^db; ++ int32_t pos=7; ++ if (a0&4) { ++ a0^=7; ++ pos^=7; ++ } ++ a0=(a0^(kb&3)) + (kb&3); ++ if (!(a0&4)) { ++ data[db]^=(key2[kb] ^ ((data[kb^pos]*key2[kb^4]) & 0xFF)); ++ } ++ } ++ } ++} ++ ++static void Via1Decode(uint8_t *data, uint8_t *key) ++{ ++ Via1Mod(key+8, data); ++ nc_des(key, DES_ECM_CRYPT, data); ++ Via1Mod(key+8, data); ++} ++ ++static void Via1Hash(uint8_t *data, uint8_t *key) ++{ ++ Via1Mod(key+8, data); ++ nc_des(key, DES_ECM_HASH, data); ++ Via1Mod(key+8, data); ++} ++ ++static inline void Via1DoHash(uint8_t *hashbuffer, uint8_t *pH, uint8_t data, uint8_t *hashkey) ++{ ++ hashbuffer[*pH] ^= data; ++ (*pH)++; ++ ++ if(*pH == 8) { ++ Via1Hash(hashbuffer, hashkey); ++ *pH = 0; ++ } ++} ++ ++static int8_t Via1Decrypt(uint8_t* ecm, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex) ++{ ++ uint8_t work_key[16]; ++ uint8_t *data, *des_data1, *des_data2; ++ uint16_t ecmLen = GetEcmLen(ecm); ++ int32_t msg_pos; ++ int32_t encStart = 0, hash_start, i; ++ uint8_t signature[8], hashbuffer[8], prepared_key[16], hashkey[16]; ++ uint8_t tmp, k, pH, foundData = 0; ++ ++ if (ident == 0) { ++ return 4; ++ } ++ memset(work_key, 0, 16); ++ if(!GetViaKey(work_key, ident, '0', desKeyIndex, 8, 1)) { ++ return 2; ++ } ++ ++ if(ecmLen < 11) { ++ return 1; ++ } ++ data = ecm+9; ++ des_data1 = dw; ++ des_data2 = dw+8; ++ ++ msg_pos = 0; ++ pH = 0; ++ memset(hashbuffer, 0, sizeof(hashbuffer)); ++ memcpy(hashkey, work_key, sizeof(hashkey)); ++ memset(signature, 0, 8); ++ ++ while(9+msg_pos+2 < ecmLen) { ++ switch (data[msg_pos]) { ++ case 0xea: ++ if(9+msg_pos+2+15 < ecmLen) { ++ encStart = msg_pos + 2; ++ memcpy(des_data1, &data[msg_pos+2], 8); ++ memcpy(des_data2, &data[msg_pos+2+8], 8); ++ foundData |= 1; ++ } ++ break; ++ case 0xf0: ++ if(9+msg_pos+2+7 < ecmLen) { ++ memcpy(signature, &data[msg_pos+2], 8); ++ foundData |= 2; ++ } ++ break; ++ } ++ msg_pos += data[msg_pos+1]+2; ++ } ++ ++ if(foundData != 3) { ++ return 1; ++ } ++ ++ pH=i=0; ++ ++ if(data[0] == 0x9f && 10+data[1] <= ecmLen) { ++ Via1DoHash(hashbuffer, &pH, data[i++], hashkey); ++ Via1DoHash(hashbuffer, &pH, data[i++], hashkey); ++ ++ for (hash_start=0; hash_start < data[1]; hash_start++) { ++ Via1DoHash(hashbuffer, &pH, data[i++], hashkey); ++ } ++ ++ while (pH != 0) { ++ Via1DoHash(hashbuffer, &pH, 0, hashkey); ++ } ++ } ++ ++ if (work_key[7] == 0) { ++ for (; i < encStart + 16; i++) { ++ Via1DoHash(hashbuffer, &pH, data[i], hashkey); ++ } ++ memcpy(prepared_key, work_key, 8); ++ } ++ else { ++ prepared_key[0] = work_key[2]; ++ prepared_key[1] = work_key[3]; ++ prepared_key[2] = work_key[4]; ++ prepared_key[3] = work_key[5]; ++ prepared_key[4] = work_key[6]; ++ prepared_key[5] = work_key[0]; ++ prepared_key[6] = work_key[1]; ++ prepared_key[7] = work_key[7]; ++ memcpy(prepared_key+8, work_key+8, 8); ++ ++ if (work_key[7] & 1) { ++ for (; i < encStart; i++) { ++ Via1DoHash(hashbuffer, &pH, data[i], hashkey); ++ } ++ ++ k = ((work_key[7] & 0xf0) == 0) ? 0x5a : 0xa5; ++ ++ for (i=0; i<8; i++) { ++ tmp = des_data1[i]; ++ des_data1[i] = (k & hashbuffer[pH] ) ^ tmp; ++ Via1DoHash(hashbuffer, &pH, tmp, hashkey); ++ } ++ ++ for (i = 0; i < 8; i++) { ++ tmp = des_data2[i]; ++ des_data2[i] = (k & hashbuffer[pH] ) ^ tmp; ++ Via1DoHash(hashbuffer, &pH, tmp, hashkey); ++ } ++ } ++ else { ++ for (; i < encStart + 16; i++) { ++ Via1DoHash(hashbuffer, &pH, data[i], hashkey); ++ } ++ } ++ } ++ Via1Decode(des_data1, prepared_key); ++ Via1Decode(des_data2, prepared_key); ++ Via1Hash(hashbuffer, hashkey); ++ if(memcmp(signature, hashbuffer, 8)) { ++ return 6; ++ } ++ return 0; ++} ++ ++static int8_t Via26ProcessDw(uint8_t *indata, uint32_t ident, uint8_t desKeyIndex) ++{ ++ uint8_t pv1,pv2, i; ++ uint8_t Tmp[8], T1Key[300], P1Key[8], KeyDes1[16], KeyDes2[16], XorKey[8]; ++ uint32_t ks1[32], ks2[32]; ++ ++ if(!GetViaKey(T1Key, ident, 'T', 1, 300, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(P1Key, ident, 'P', 1, 8, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(KeyDes1, ident, 'D', 1, 16, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(KeyDes2, ident, '0', desKeyIndex, 16, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(XorKey, ident, 'X', 1, 8, 1)) { ++ return 2; ++ } ++ ++ for (i=0; i<8; i++) { ++ pv1 = indata[i]; ++ Tmp[i] = T1Key[pv1]; ++ } ++ for (i=0; i<8; i++) { ++ pv1 = P1Key[i]; ++ pv2 = Tmp[pv1]; ++ indata[i]=pv2; ++ } ++ ++ des_set_key(KeyDes1, ks1); ++ des(indata, ks1, 1); ++ ++ for (i=0; i<8; i++) { ++ indata[i] ^= XorKey[i]; ++ } ++ ++ des_set_key(KeyDes2, ks1); ++ des_set_key(KeyDes2+8, ks2); ++ des(indata, ks1, 0); ++ des(indata, ks2, 1); ++ des(indata, ks1, 0); ++ ++ for (i=0; i<8; i++) { ++ indata[i] ^= XorKey[i]; ++ } ++ ++ des_set_key(KeyDes1, ks1); ++ des(indata, ks1, 0); ++ ++ for (i=0; i<8; i++) { ++ pv1 = indata[i]; ++ pv2 = P1Key[i]; ++ Tmp[pv2] = pv1; ++ } ++ for (i=0; i<8; i++) { ++ pv1 = Tmp[i]; ++ pv2 = T1Key[pv1]; ++ indata[i] = pv2; ++ } ++ return 0; ++} ++ ++static int8_t Via26Decrypt(uint8_t* source, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex) ++{ ++ uint8_t tmpData[8], C1[8]; ++ uint8_t *pXorVector; ++ int32_t i,j; ++ ++ if (ident == 0) { ++ return 4; ++ } ++ if(!GetViaKey(C1, ident, 'C', 1, 8, 1)) { ++ return 2; ++ } ++ ++ for (i=0; i<2; i++) { ++ memcpy(tmpData, source+ i*8, 8); ++ Via26ProcessDw(tmpData, ident, desKeyIndex); ++ if (i!=0) { ++ pXorVector = source; ++ } ++ else { ++ pXorVector = &C1[0]; ++ } ++ for (j=0; j<8; j++) { ++ dw[i*8+j] = tmpData[j]^pXorVector[j]; ++ } ++ } ++ return 0; ++} ++ ++static void Via3Core(uint8_t *data, uint8_t Off, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) ++{ ++ uint8_t i; ++ uint32_t lR2, lR3, lR4, lR6, lR7; ++ ++ switch (ident) { ++ case 0x032820: { ++ for (i=0; i<4; i++) { ++ data[i]^= XorKey[(Off+i) & 0x07]; ++ } ++ lR2 = (data[0]^0xBD)+data[0]; ++ lR3 = (data[3]^0xEB)+data[3]; ++ lR2 = (lR2-lR3)^data[2]; ++ lR3 = ((0x39*data[1])<<2); ++ data[4] = (lR2|lR3)+data[2]; ++ lR3 = ((((data[0]+6)^data[0]) | (data[2]<<1))^0x65)+data[0]; ++ lR2 = (data[1]^0xED)+data[1]; ++ lR7 = ((data[3]+0x29)^data[3])*lR2; ++ data[5] = lR7+lR3; ++ lR2 = ((data[2]^0x33)+data[2]) & 0x0A; ++ lR3 = (data[0]+0xAD)^data[0]; ++ lR3 = lR3+lR2; ++ lR2 = data[3]*data[3]; ++ lR7 = (lR2 | 1) + data[1]; ++ data[6] = (lR3|lR7)+data[1]; ++ lR3 = data[1] & 0x07; ++ lR2 = (lR3-data[2]) & (data[0] | lR2 |0x01); ++ data[7] = lR2+data[3]; ++ for (i=0; i<4; i++) { ++ data[i+4] = T1Key[data[i+4]]; ++ } ++ } ++ break; ++ case 0x030B00: { ++ for (i=0; i<4; i++) { ++ data[i]^= XorKey[(Off+i) & 0x07]; ++ } ++ lR6 = (data[3] + 0x6E) ^ data[3]; ++ lR6 = (lR6*(data[2] << 1)) + 0x17; ++ lR3 = (data[1] + 0x77) ^ data[1]; ++ lR4 = (data[0] + 0xD7) ^ data[0]; ++ data[4] = ((lR4 & lR3) | lR6) + data[0]; ++ lR4 = ((data[3] + 0x71) ^ data[3]) ^ 0x90; ++ lR6 = (data[1] + 0x1B) ^ data[1]; ++ lR4 = (lR4*lR6) ^ data[0]; ++ data[5] = (lR4 ^ (data[2] << 1)) + data[1]; ++ lR3 = (data[3] * data[3])| 0x01; ++ lR4 = (((data[2] ^ 0x35) + data[2]) | lR3) + data[2]; ++ lR6 = data[1] ^ (data[0] + 0x4A); ++ data[6] = lR6 + lR4; ++ lR3 = (data[0] * (data[2] << 1)) | data[1]; ++ lR4 = 0xFE - data[3]; ++ lR3 = lR4 ^ lR3; ++ data[7] = lR3 + data[3]; ++ for (i=0; i<4; i++) { ++ data[4+i] = T1Key[data[4+i]]; ++ } ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void Via3Fct1(uint8_t *data, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) ++{ ++ uint8_t t; ++ Via3Core(data, 0, ident, XorKey, T1Key); ++ ++ switch (ident) { ++ case 0x032820: { ++ t = data[4]; ++ data[4] = data[7]; ++ data[7] = t; ++ } ++ break; ++ case 0x030B00: { ++ t = data[5]; ++ data[5] = data[7]; ++ data[7] = t; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static void Via3Fct2(uint8_t *data, uint32_t ident, uint8_t* XorKey, uint8_t* T1Key) ++{ ++ uint8_t t; ++ Via3Core(data, 4, ident, XorKey, T1Key); ++ ++ switch (ident) { ++ case 0x032820: { ++ t = data[4]; ++ data[4] = data[7]; ++ data[7] = data[5]; ++ data[5] = data[6]; ++ data[6] = t; ++ } ++ break; ++ case 0x030B00: { ++ t = data[6]; ++ data[6] = data[7]; ++ data[7] = t; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static int8_t Via3ProcessDw(uint8_t *data, uint32_t ident, uint8_t desKeyIndex) ++{ ++ uint8_t i; ++ uint8_t tmp[8], T1Key[300], P1Key[8], KeyDes[16], XorKey[8]; ++ uint32_t ks1[32], ks2[32]; ++ ++ if(!GetViaKey(T1Key, ident, 'T', 1, 300, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(P1Key, ident, 'P', 1, 8, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(KeyDes, ident, '0', desKeyIndex, 16, 1)) { ++ return 2; ++ } ++ if(!GetViaKey(XorKey, ident, 'X', 1, 8, 1)) { ++ return 2; ++ } ++ ++ for (i=0; i<4; i++) { ++ tmp[i] = data[i+4]; ++ } ++ Via3Fct1(tmp, ident, XorKey, T1Key); ++ for (i=0; i<4; i++) { ++ tmp[i] = data[i]^tmp[i+4]; ++ } ++ Via3Fct2(tmp, ident, XorKey, T1Key); ++ for (i=0; i<4; i++) { ++ tmp[i]^= XorKey[i+4]; ++ } ++ for (i=0; i<4; i++) { ++ data[i] = data[i+4]^tmp[i+4]; ++ data[i+4] = tmp[i]; ++ } ++ ++ des_set_key(KeyDes, ks1); ++ des_set_key(KeyDes+8, ks2); ++ ++ des(data, ks1, 0); ++ des(data, ks2, 1); ++ des(data, ks1, 0); ++ ++ for (i=0; i<4; i++) { ++ tmp[i] = data[i+4]; ++ } ++ Via3Fct2(tmp, ident, XorKey, T1Key); ++ for (i=0; i<4; i++) { ++ tmp[i] = data[i]^tmp[i+4]; ++ } ++ Via3Fct1(tmp, ident, XorKey, T1Key); ++ for (i=0; i<4; i++) { ++ tmp[i]^= XorKey[i]; ++ } ++ for (i=0; i<4; i++) { ++ data[i] = data[i+4]^tmp[i+4]; ++ data[i+4] = tmp[i]; ++ } ++ return 0; ++} ++ ++static void Via3FinalMix(uint8_t *dw) ++{ ++ uint8_t tmp[4]; ++ ++ memcpy(tmp, dw, 4); ++ memcpy(dw, dw + 4, 4); ++ memcpy(dw + 4, tmp, 4); ++ ++ memcpy(tmp, dw + 8, 4); ++ memcpy(dw + 8, dw + 12, 4); ++ memcpy(dw + 12, tmp, 4); ++} ++ ++static int8_t Via3Decrypt(uint8_t* source, uint8_t* dw, uint32_t ident, uint8_t desKeyIndex, uint8_t aesKeyIndex, uint8_t aesMode, int8_t doFinalMix) ++{ ++ int8_t aesAfterCore = 0; ++ int8_t needsAES = (aesKeyIndex != 0xFF); ++ uint8_t tmpData[8], C1[8]; ++ uint8_t *pXorVector; ++ char aesKey[16]; ++ int32_t i, j; ++ ++ if(ident == 0) { ++ return 4; ++ } ++ if(!GetViaKey(C1, ident, 'C', 1, 8, 1)) { ++ return 2; ++ } ++ if(needsAES && !GetViaKey((uint8_t*)aesKey, ident, 'E', aesKeyIndex, 16, 1)) { ++ return 2; ++ } ++ if(aesMode == 0x0D || aesMode == 0x11 || aesMode == 0x15) { ++ aesAfterCore = 1; ++ } ++ ++ if(needsAES && !aesAfterCore) { ++ if(aesMode == 0x0F) { ++ hdSurEncPhase1_D2_0F_11(source); ++ hdSurEncPhase2_D2_0F_11(source); ++ } ++ else if(aesMode == 0x13) { ++ hdSurEncPhase1_D2_13_15(source); ++ } ++ struct aes_keys aes; ++ aes_set_key(&aes, aesKey); ++ aes_decrypt(&aes, source, 16); ++ if(aesMode == 0x0F) { ++ hdSurEncPhase1_D2_0F_11(source); ++ } ++ else if(aesMode == 0x13) { ++ hdSurEncPhase2_D2_13_15(source); ++ } ++ } ++ ++ for(i=0; i<2; i++) { ++ memcpy(tmpData, source+i*8, 8); ++ Via3ProcessDw(tmpData, ident, desKeyIndex); ++ if (i!=0) { ++ pXorVector = source; ++ } ++ else { ++ pXorVector = &C1[0]; ++ } ++ for (j=0; j<8; j++) { ++ dw[i*8+j] = tmpData[j]^pXorVector[j]; ++ } ++ } ++ ++ if(needsAES && aesAfterCore) { ++ if(aesMode == 0x11) { ++ hdSurEncPhase1_D2_0F_11(dw); ++ hdSurEncPhase2_D2_0F_11(dw); ++ } ++ else if(aesMode == 0x15) { ++ hdSurEncPhase1_D2_13_15(dw); ++ } ++ struct aes_keys aes; ++ aes_set_key(&aes, aesKey); ++ aes_decrypt(&aes, dw, 16); ++ if(aesMode == 0x11) { ++ hdSurEncPhase1_D2_0F_11(dw); ++ } ++ if(aesMode == 0x15) { ++ hdSurEncPhase2_D2_13_15(dw); ++ } ++ } ++ ++ if(ident == 0x030B00) { ++ if(doFinalMix) { ++ Via3FinalMix(dw); ++ } ++ if(!isValidDCW(dw)) { ++ return 6; ++ } ++ } ++ return 0; ++} ++ ++static int8_t ViaccessECM(uint8_t *ecm, uint8_t *dw) ++{ ++ uint32_t currentIdent = 0; ++ uint8_t nanoCmd = 0, nanoLen = 0, version = 0, providerKeyLen = 0, desKeyIndex = 0, aesMode = 0, aesKeyIndex = 0xFF; ++ int8_t doFinalMix = 0, result = 1; ++ uint16_t i = 0, keySelectPos = 0, ecmLen = GetEcmLen(ecm); ++ ++ for (i=4; i+2 ecmLen) { ++ return 1; ++ } ++ ++ switch (nanoCmd) { ++ case 0x40: ++ if (nanoLen < 0x03) { ++ break; ++ } ++ version = ecm[i]; ++ if (nanoLen == 3) { ++ currentIdent = ((ecm[i]<<16)|(ecm[i+1]<<8))|(ecm[i+2]&0xF0); ++ desKeyIndex = ecm[i+2]&0x0F; ++ keySelectPos = i+3; ++ } ++ else { ++ currentIdent = (ecm[i]<<16)|(ecm[i+1]<<8)|((ecm[i+2]>>4)&0x0F); ++ desKeyIndex = ecm[i+3]; ++ keySelectPos = i+4; ++ } ++ providerKeyLen = nanoLen; ++ break; ++ case 0x90: ++ if (nanoLen < 0x03) { ++ break; ++ } ++ version = ecm[i]; ++ currentIdent = ((ecm[i]<<16)|(ecm[i+1]<<8))|(ecm[i+2]&0xF0); ++ desKeyIndex = ecm[i+2]&0x0F; ++ keySelectPos = i+4; ++ if((version == 3) && (nanoLen > 3)) { ++ desKeyIndex = ecm[i+(nanoLen-4)]&0x0F; ++ } ++ providerKeyLen = nanoLen; ++ break; ++ case 0x80: ++ nanoLen = 0; ++ break; ++ case 0xD2: ++ if (nanoLen < 0x02) { ++ break; ++ } ++ aesMode = ecm[i]; ++ aesKeyIndex = ecm[i+1]; ++ break; ++ case 0xDD: ++ nanoLen = 0; ++ break; ++ case 0xEA: ++ if (nanoLen < 0x10) { ++ break; ++ } ++ ++ if (version < 2) { ++ return Via1Decrypt(ecm, dw, currentIdent, desKeyIndex); ++ } ++ else if (version == 2) { ++ return Via26Decrypt(ecm + i, dw, currentIdent, desKeyIndex); ++ } ++ else if (version == 3) { ++ doFinalMix = 0; ++ if (currentIdent == 0x030B00 && providerKeyLen>3) { ++ if(keySelectPos+2 >= ecmLen) { ++ break; ++ } ++ if (ecm[keySelectPos] == 0x05 && ecm[keySelectPos+1] == 0x67 && (ecm[keySelectPos+2] == 0x00 || ecm[keySelectPos+2] == 0x01)) { ++ if(ecm[keySelectPos+2] == 0x01) { ++ doFinalMix = 1; ++ } ++ } ++ else { ++ break; ++ } ++ } ++ return Via3Decrypt(ecm + i, dw, currentIdent, desKeyIndex, aesKeyIndex, aesMode, doFinalMix); ++ } ++ break; ++ default: ++ break; ++ } ++ i += nanoLen; ++ } ++ return result; ++} ++ ++// Nagra EMU ++static int8_t GetNagraKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint8_t isCriticalKey) ++{ ++ char keyStr[EMU_MAX_CHAR_KEYNAME]; ++ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); ++ if(FindKey('N', ident, 0, keyStr, buf, keyName == 'M' ? 64 : 16, isCriticalKey, 0, 0, NULL)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int8_t Nagra2Signature(const uint8_t *vkey, const uint8_t *sig, const uint8_t *msg, int32_t len) ++{ ++ uint8_t buff[16]; ++ uint8_t iv[8]; ++ int32_t i,j; ++ ++ memcpy(buff,vkey,sizeof(buff)); ++ for(i=0; i+7=0; j--) { ++ buff[j+8]^=msg[i+j]; ++ } ++ } ++ buff[8]&=0x7F; ++ return (memcmp(sig, buff+8, 8) == 0); ++} ++ ++static int8_t DecryptNagra2ECM(uint8_t *in, uint8_t *out, const uint8_t *key, int32_t len, const uint8_t *vkey, uint8_t *keyM) ++{ ++ BIGNUM *exp, *mod; ++ uint8_t iv[8]; ++ int32_t i = 0, sign = in[0] & 0x80; ++ uint8_t binExp = 3; ++ int8_t result = 1; ++ ++ exp = BN_new(); ++ mod = BN_new(); ++ BN_bin2bn(&binExp, 1, exp); ++ BN_bin2bn(keyM, 64, mod); ++ ++ if(EmuRSA(out,in+1,64,exp,mod,1)<=0) { ++ BN_free(exp); ++ BN_free(mod); ++ return 0; ++ } ++ out[63]|=sign; ++ if(len>64) { ++ memcpy(out+64,in+65,len-64); ++ } ++ ++ memset(iv,0,sizeof(iv)); ++ if(in[0]&0x04) { ++ uint8_t key1[8], key2[8]; ++ ReverseMemInOut(key1,&key[0],8); ++ ReverseMemInOut(key2,&key[8],8); ++ ++ for(i=7; i>=0; i--) { ++ ReverseMem(out+8*i,8); ++ } ++ des_ede2_cbc_decrypt(out, iv, key1, key2, len); ++ for(i=7; i>=0; i--) { ++ ReverseMem(out+8*i,8); ++ } ++ } ++ else { ++ IDEA_KEY_SCHEDULE ek; ++ idea_set_encrypt_key(key, &ek); ++ idea_cbc_encrypt(out, out, len&~7, &ek, iv, IDEA_DECRYPT); ++ } ++ ++ ReverseMem(out,64); ++ if(result && EmuRSA(out,out,64,exp,mod,0)<=0) { ++ result = 0; ++ } ++ if(result && vkey && !Nagra2Signature(vkey,out,out+8,len-8)) { ++ result = 0; ++ } ++ ++ BN_free(exp); ++ BN_free(mod); ++ return result; ++} ++ ++static int8_t Nagra2ECM(uint8_t *ecm, uint8_t *dw) ++{ ++ uint32_t ident, identMask, tmp1, tmp2, tmp3; ++ uint8_t cmdLen, ideaKeyNr, *dec, ideaKey[16], vKey[16], m1Key[64], mecmAlgo = 0; ++ int8_t useVerifyKey = 0; ++ int32_t l=0, s; ++ uint16_t i = 0, ecmLen = GetEcmLen(ecm); ++ ++ if(ecmLen < 8) { ++ return 1; ++ } ++ cmdLen = ecm[4] - 5; ++ ident = (ecm[5] << 8) + ecm[6]; ++ ideaKeyNr = (ecm[7]&0x10)>>4; ++ if(ideaKeyNr) { ++ ideaKeyNr = 1; ++ } ++ if(ident == 1283 || ident == 1285 || ident == 1297) { ++ ident = 1281; ++ } ++ if(cmdLen <= 63 || ecmLen < cmdLen + 10) { ++ return 1; ++ } ++ ++ if(!GetNagraKey(ideaKey, ident, '0', ideaKeyNr, 1)) { ++ return 2; ++ } ++ if(GetNagraKey(vKey, ident, 'V', 0, 0)) { ++ useVerifyKey = 1; ++ } ++ if(!GetNagraKey(m1Key, ident, 'M', 1, 1)) { ++ return 2; ++ } ++ ReverseMem(m1Key, 64); ++ ++ dec = (uint8_t*)malloc(sizeof(uint8_t)*cmdLen); ++ if(dec == NULL) { ++ return 7; ++ } ++ if(!DecryptNagra2ECM(ecm+9, dec, ideaKey, cmdLen, useVerifyKey?vKey:0, m1Key)) { ++ free(dec); ++ return 1; ++ } ++ ++ for(i=(dec[14]&0x10)?16:20; i0) { ++ return 1; ++ } ++ ++ identMask = ident & 0xFF00; ++ if (identMask == 0x1100 || identMask == 0x500 || identMask == 0x3100) { ++ memcpy(&tmp1, dw, 4); ++ memcpy(&tmp2, dw + 4, 4); ++ memcpy(&tmp3, dw + 12, 4); ++ memcpy(dw, dw + 8, 4); ++ memcpy(dw + 4, &tmp3, 4); ++ memcpy(dw + 8, &tmp1, 4); ++ memcpy(dw + 12, &tmp2, 4); ++ } ++ return 0; ++} ++ ++// Irdeto EMU ++static int8_t GetIrdetoKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint8_t isCriticalKey, uint32_t *keyRef) ++{ ++ char keyStr[EMU_MAX_CHAR_KEYNAME]; ++ ++ if(*keyRef > 0xFF) ++ { ++ return 0; ++ } ++ ++ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); ++ if(FindKey('I', ident, 0, keyStr, buf, 16, *keyRef > 0 ? 0 : isCriticalKey, *keyRef, 0, NULL)) { ++ (*keyRef)++; ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void Irdeto2Encrypt(uint8_t *data, const uint8_t *seed, const uint8_t *key, int32_t len) ++{ ++ const uint8_t *tmp = seed;; ++ int32_t i; ++ uint32_t ks1[32], ks2[32]; ++ ++ des_set_key(key, ks1); ++ des_set_key(key+8, ks2); ++ ++ len&=~7; ++ ++ for(i=0; i+7> 16; ++ ++ switch (pos) ++ { ++ case 29: // Rascom QAF 1R ++ case 31: // Eutelsat 3B ++ { ++ pos = 30; ++ break; ++ } ++ ++ case 49: ++ case 50: // SES 5 ++ { ++ pos = 48; // Astra 4A ++ break; ++ } ++ ++ case 215: ++ { ++ pos = 216; // Eutelsat 21B ++ break; ++ } ++ ++ case 285: // Astra 2E ++ { ++ pos = 282; // Astra 2F/2G ++ break; ++ } ++ ++ case 328: // Intelsat 28 ++ case 329: ++ case 331: // Eutelsat 33C ++ { ++ pos = 330; ++ break; ++ } ++ ++ case 359: // Eutelsat 36B ++ case 361: // Express AMU1 ++ { ++ pos = 360; ++ break; ++ } ++ ++ case 451: // Intelsat 904 ++ { ++ pos = 450; // Intelsat 12 ++ break; ++ } ++ ++ case 550: ++ case 551: // G-Sat 8/16 ++ { ++ pos = 549; // Yamal 402 ++ break; ++ } ++ ++ case 748: ++ case 749: // ABS 2A ++ { ++ pos = 750; ++ break; ++ } ++ ++ case 848: // Horizons 2 ++ case 852: // Intelsat 15 ++ { ++ pos = 850; ++ break; ++ } ++ ++ case 914: // Mesasat 3a ++ { ++ pos = 915; // Mesasat 3/3b ++ break; ++ } ++ ++ case 934: // G-Sat 17 ++ case 936: // Insat 4B ++ { ++ pos = 935; // G-Sat 15 ++ break; ++ } ++ ++ case 3600 - 911: // Nimiq 6 ++ { ++ pos = 3600 - 910; // Galaxy 17 ++ } ++ ++ case 3600 - 870: // SES 2 ++ case 3600 - 872: // TKSat 1 ++ { ++ pos = 3600 - 871; ++ break; ++ } ++ ++ case 3600 - 432: // Sky Brasil 1 ++ case 3600 - 430: // Intelsat 11 ++ { ++ pos = 3600 - 431; ++ break; ++ } ++ ++ case 3600 - 376: // Telstar 11N ++ case 3600 - 374: // NSS 10 ++ { ++ pos = 3600 - 375; ++ break; ++ } ++ ++ case 3600 - 359: // Hispasat 36W-1 ++ { ++ pos = 3600 - 360; // Eutelsat 36 West A ++ break; ++ } ++ ++ case 3600 - 81: // Eutelsat 8 West B ++ { ++ pos = 3600 - 80; ++ break; ++ } ++ ++ case 3600 - 73: // Eutelsat 7 West A ++ case 3600 - 72: ++ case 3600 - 71: ++ { ++ pos = 3600 - 70; // Nilesat 201 ++ break; ++ } ++ ++ case 3600 - 10: // Intelsat 10-02 ++ case 3600 - 9: // Thor 6 ++ case 3600 - 7: // Thor 7 ++ case 3600 - 6: // Thor 7 ++ { ++ pos = 3600 - 8; // Thor 5 ++ break; ++ } ++ } ++ ++ *namespace = (*namespace & 0xF000FFFF) | (pos << 16); ++} ++ ++static void BissAnnotate(char *buf, uint8_t len, const uint8_t *ecm, uint16_t ecmLen, uint32_t hash, int8_t isNamespaceHash, int8_t datecoded) ++{ ++ // Extract useful information to append to the "Example key ..." message. ++ // ++ // For feeds, the orbital position & frequency are usually embedded in the namespace. ++ // See https://github.com/openatv/enigma2/blob/master/lib/dvb/frontend.cpp#L496 ++ // hash = (sat.orbital_position << 16); ++ // hash |= ((sat.frequency/1000)&0xFFFF)|((sat.polarisation&1) << 15); ++ // ++ // If the onid & tsid appear to be a unique DVB identifier, enigma2 strips the frequency ++ // from our namespace. See https://github.com/openatv/enigma2/blob/master/lib/dvb/scan.cpp#L59 ++ // In that case, our annotation contains the onid:tsid:sid triplet in lieu of frequency. ++ // ++ // For the universal case, we print the number of elementary stream pids & pmtpid. ++ // The sid and current time are included for all. Examples: ++ // ++ // F 1A2B3C4D 00000000 XXXXXXXXXXXXXXXX ; 110.5W 12345H sid:0001 added: 2017-10-17 @ 13:14:15 // namespace ++ // F 1A2B3C4D 20180123 XXXXXXXXXXXXXXXX ; 33.5E ABCD:9876:1234 added: 2017-10-17 @ 13:14:15 // stripped namespace ++ // F 1A2B3C4D 20180123 XXXXXXXXXXXXXXXX ; av:5 pmt:0134 sid:0001 added: 2017-10-17 @ 13:14:15 // universal ++ ++ uint8_t pidcount; ++ uint16_t frequency, degrees, pmtpid, srvid, tsid, onid; ++ uint32_t ens; ++ char compass, polarisation, timeStr1[9], timeStr2[19]; ++ ++ if (datecoded) ++ { ++ Date2Str(timeStr1, sizeof(timeStr1), 4, 3); ++ } ++ else ++ { ++ snprintf(timeStr1, sizeof(timeStr1), "00000000"); ++ } ++ ++ Date2Str(timeStr2, sizeof(timeStr2), 0, 2); ++ ++ if (isNamespaceHash) // Namespace hash ++ { ++ ens = b2i(4, ecm + ecmLen - 4); // Namespace will be the last 4 bytes of the ecm ++ degrees = (ens >> 16) & 0x0FFF; // Remove not-a-pid flag ++ ++ if (degrees > 1800) ++ { ++ degrees = 3600 - degrees; ++ compass = 'W'; ++ } ++ else ++ { ++ compass = 'E'; ++ } ++ ++ if (0 == (ens & 0xFFFF)) // Stripped namespace hash ++ { ++ srvid = b2i(2, ecm + 3); ++ tsid = b2i(2, ecm + ecmLen - 8); ++ onid = b2i(2, ecm + ecmLen - 6); ++ // Printing degree sign "\u00B0" requires c99 standard ++ snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; %5.1f%c %04X:%04X:%04X added: %s", ++ hash, timeStr1, degrees / 10.0, compass, onid, tsid, srvid, timeStr2); ++ } ++ else // Full namespace hash ++ { ++ srvid = b2i(2, ecm + 3); ++ frequency = ens & 0x7FFF; // Remove polarity bit ++ polarisation = ens & 0x8000 ? 'V' : 'H'; ++ // Printing degree sign "\u00B0" requires c99 standard ++ snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; %5.1f%c %5d%c sid:%04X added: %s", ++ hash, timeStr1, degrees / 10.0, compass, frequency, polarisation, srvid, timeStr2); ++ } ++ } ++ else // Universal hash ++ { ++ srvid = b2i(2, ecm + 3); ++ pmtpid = b2i(2, ecm + 5); ++ pidcount = (ecmLen - 15) / 2; // video + audio pids count ++ snprintf(buf, len, "F %08X %s XXXXXXXXXXXXXXXX ; av:%d pmt:%04X sid:%04X added: %s", ++ hash, timeStr1, pidcount, pmtpid, srvid, timeStr2); ++ } ++} ++ ++static int8_t BissIsCommonHash(uint32_t hash) ++{ ++ // Check universal hash against a number of commnon universal ++ // hashes in order to warn users about potential key clashes ++ ++ switch (hash) ++ { ++ case 0xBAFCD9FD: // 0001 0020 0200 1010 1020 (most common hash) ++ return 1; ++ case 0xA6A4FBD4: // 0001 0800 0200 1010 1020 ++ return 1; ++ case 0xEFAB7A4D: // 0001 0800 1010 1020 0200 ++ return 1; ++ case 0x83FA15D1: // 0001 0020 0134 0100 0101 ++ return 1; ++ case 0x58934C38: // 0001 0800 1010 1020 1030 0200 ++ return 1; ++ case 0x2C3CEC17: // 0001 0020 0134 0100 ++ return 1; ++ case 0x73DF7F7E: // 0001 0020 0200 1010 1020 1030 ++ return 1; ++ case 0xAFA85BC8: // 0001 0020 0021 0022 0023 ++ return 1; ++ case 0x8C51F31D: // 0001 0800 0200 1010 1020 1030 1040 ++ return 1; ++ case 0xE2F9BD29: // 0001 0800 0200 1010 1020 1030 ++ return 1; ++ case 0xB9EBE0FF: // 0001 0100 0200 1010 1020 (less common hash) ++ return 1; ++ default: ++ return 0; ++ } ++} ++ ++static int8_t BissIsValidNamespace(uint32_t namespace) ++{ ++ // Note to developers: ++ // If we ever have a satellite at 0.0E, edit to allow stripped namespace ++ // '0xA0000000' with an additional test on tsid and onid being != 0 ++ ++ uint16_t orbital, frequency; ++ ++ orbital = (namespace >> 16) & 0x0FFF; ++ frequency = namespace & 0x7FFF; ++ ++ if ((namespace & 0xA0000000) != 0xA0000000) return 0; // Value isn't flagged as namespace ++ if (namespace == 0xA0000000) return 0; // Empty namespace ++ if (orbital > 3599) return 0; // Allow only DVB-S ++ if (frequency == 0) return 1; // Stripped namespace ++ if (frequency >= 3400 && frequency <= 4200) return 1; // Super extended C band ++ if (frequency >= 10700 && frequency <= 12750) return 1; // Ku band Europe ++ ++ return 0; ++} ++ ++static int8_t BissGetKey(uint32_t provider, uint8_t *key, int8_t dateCoded, int8_t printMsg) ++{ ++ // If date-coded keys are enabled in the webif, this function evaluates the expiration date ++ // of the keys found. Expired keys are not sent to BissECM(). If date-coded keys are disabled, ++ // then all keys found are sent without any evaluation. It takes the "provider" as input and ++ // outputs the "key". Returns 0 (Key not found, or expired) or 1 (Key found). ++ ++ // printMsg: 0 => No message ++ // printMsg: 1 => Print message only if key is found ++ // printMsg: 2 => Always print message, regardless if key is found or not ++ ++ char keyExpDate[9] = "00000000"; ++ ++ if (FindKey('F', provider, 0, keyExpDate, key, 8, 0, 0, 0, NULL)) // Key found ++ { ++ if (dateCoded) // Date-coded keys are enabled, evaluate expiration date ++ { ++ char currentDate[9]; ++ Date2Str(currentDate, sizeof(currentDate), 0, 3); ++ ++ if (strncmp("00000000", keyExpDate, 9) == 0 || strncmp(currentDate, keyExpDate, 9) < 0) // Evergreen or not expired ++ { ++ if (printMsg == 1 || printMsg == 2) cs_log("Key found: F %08X %s", provider, keyExpDate); ++ return 1; ++ } ++ else // Key expired ++ { ++ key = NULL; // Make sure we don't send any expired key ++ if (printMsg == 2) cs_log("Key expired: F %08X %s", provider, keyExpDate); ++ return 0; ++ } ++ } ++ else // Date-coded keys are disabled, don't evaluate expiration date ++ { ++ if (printMsg == 1 || printMsg == 2) cs_log("Key found: F %08X %s", provider, keyExpDate); ++ return 1; ++ } ++ } ++ else // Key not found ++ { ++ if (printMsg == 2) cs_log("Key not found: F %08X", provider); ++ return 0; ++ } ++} ++ ++static int8_t BissECM(struct s_reader *rdr, const uint8_t *ecm, int16_t ecmDataLen, uint8_t *dw, uint16_t srvid, uint16_t ecmpid) ++{ ++ // Oscam's fake ecm consists of [sid] [pmtpid] [pid1] [pid2] ... [pidx] [tsid] [onid] [namespace] ++ // ++ // On enigma boxes tsid, onid and namespace should be non zero, while on non-enigma ++ // boxes they are usually all zero. ++ // The emulator creates a unique channel hash using srvid and enigma namespace or ++ // srvid, tsid, onid and namespace (in case of namespace without frequency) and ++ // another weaker (not unique) hash based on every pid of the channel. This universal ++ // hash should be available on all types of stbs (enigma and non-enigma). ++ ++ // Flags inside [namespace] ++ // ++ // emu r748- : no namespace, no flag ++ // emu r749 : 0x80000000 (full namespase), 0xC0000000 (stripped namespace, injected with tsid^onid^ecmpid^0x1FFF) ++ // emu r752+ : 0xA0000000 (pure namespace, either full, stripped, or null) ++ ++ // Key searches are made in order: ++ // Highest priority / tightest test first ++ // Lowest priority / loosest test last ++ // ++ // 1st: namespace hash (only on enigma boxes) ++ // 2nd: universal hash (all box types with emu r752+) ++ // 3rd: valid tsid, onid combination ++ // 4th: faulty ecmpid (other than 0x1FFF) ++ // 5th: reverse order pid (audio, video, pmt pids) ++ // 6th: standard BISS ecmpid (0x1FFF) ++ // 7th: default "All Feeds" key ++ ++ // If enabled in the webif, a date based key search can be performed. If the expiration ++ // date has passed, the key is not sent from BissGetKey(). This search method is only ++ // used in the namespace hash, universal hash and the default "All Feeds" key. ++ ++ uint8_t ecmCopy[EMU_MAX_ECM_LEN]; ++ uint16_t ecmLen = 0, pid = 0; ++ uint32_t i, ens = 0, hash = 0; ++ char tmpBuffer1[17], tmpBuffer2[90] = "0", tmpBuffer3[90] = "0"; ++ ++ if (ecmDataLen >= 3) ++ { ++ ecmLen = GetEcmLen(ecm); ++ } ++ ++ // First try using the unique namespace hash (enigma only) ++ if (ecmLen >= 13 && ecmLen <= ecmDataLen) // ecmLen >= 13, allow patching the ecmLen for r749 ecms ++ { ++ memcpy(ecmCopy, ecm, ecmLen); ++ ens = b2i(4, ecm + ecmLen - 4); // Namespace will be the last 4 bytes ++ ++ if (BissIsValidNamespace(ens)) // An r752+ extended ecm with valid namespace ++ { ++ BissUnifyOrbitals(&ens); ++ i2b_buf(4, ens, ecmCopy + ecmLen - 4); ++ ++ for (i = 0; i < 5; i++) // Find key matching hash made with frequency modified to: f+0, then f-1, f+1, f-2, lastly f+2 ++ { ++ ecmCopy[ecmLen - 1] = (i & 1) ? ecmCopy[ecmLen - 1] - i : ecmCopy[ecmLen - 1] + i; // frequency +/- 1, 2 MHz ++ ++ if (0 != (ens & 0xFFFF)) // Full namespace - Calculate hash with srvid and namespace only ++ { ++ i2b_buf(2, srvid, ecmCopy + ecmLen - 6); // Put [srvid] right before [namespace] ++ hash = crc32(0x2600, ecmCopy + ecmLen - 6, 6); ++ } ++ else // Namespace without frequency - Calculate hash with srvid, tsid, onid and namespace ++ { ++ i2b_buf(2, srvid, ecmCopy + ecmLen - 10); // Put [srvid] right before [tsid] [onid] [namespace] sequence ++ hash = crc32(0x2600, ecmCopy + ecmLen - 10, 10); ++ } ++ ++ if (BissGetKey(hash, dw, rdr->emu_datecodedenabled, i == 0 ? 2 : 1)) // Do not print "key not found" for frequency off by 1, 2 ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ ++ if (i == 0) // No key found matching our hash: create example SoftCam.Key BISS line for the live log ++ { ++ BissAnnotate(tmpBuffer2, sizeof(tmpBuffer2), ecmCopy, ecmLen, hash, 1, rdr->emu_datecodedenabled); ++ } ++ ++ if (0 == (ens & 0xFFFF)) // Namespace without frequency - Do not iterate ++ { ++ break; ++ } ++ } ++ } ++ ++ if ((ens & 0xA0000000) == 0x80000000) // r749 ecms only (exclude r752+ ecms) ++ { ++ cs_log("Hey! Network buddy, you need to upgrade your OSCam-Emu"); ++ ecmCopy[ecmLen] = 0xA0; // Patch ecm to look like r752+ ++ ecmLen += 4; ++ ecmDataLen += 4; ++ } ++ } ++ ++ // Try using the universal channel hash (namespace not available) ++ if (ecmLen >= 17 && ecmLen <= ecmDataLen) // ecmLen >= 17, length of r749 ecms has been patched to match r752+ ecms ++ { ++ ens = b2i(4, ecmCopy + ecmLen - 4); // Namespace will be last 4 bytes ++ ++ if ((ens & 0xE0000000) == 0xA0000000) // We have an r752+ style ecm which contains pmtpid ++ { ++ memcpy(ecmCopy, ecm, ecmLen - 8); // Make a new ecmCopy from the original ecm as the old ecmCopy may be altered in namespace hash (skip [tsid] [onid] [namespace]) ++ hash = crc32(0x2600, ecmCopy + 3, ecmLen - 3 - 8); // ecmCopy doesn't have [tsid] [onid] [namespace] part ++ ++ if (BissGetKey(hash, dw, rdr->emu_datecodedenabled, 2)) // Key found ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ ++ // No key found matching our hash: create example SoftCam.Key BISS line for the live log ++ BissAnnotate(tmpBuffer3, sizeof(tmpBuffer3), ecmCopy, ecmLen, hash, 0, rdr->emu_datecodedenabled); ++ } ++ } ++ ++ // Try using only [tsid][onid] (useful when many channels on a transpoder use the same key) ++ if (ecmLen >= 17 && ecmLen <= ecmDataLen) // ecmLen >= 17, length of r749 ecms has been patched to match r752+ ecms ++ { ++ ens = b2i(4, ecmCopy + ecmLen - 4); // Namespace will be last 4 bytes ++ ++ // We have an r752+ style ecm with stripped namespace, thus a valid [tsid][onid] combo to use as provider ++ if ((ens & 0xE000FFFF) == 0xA0000000 && BissGetKey(b2i(4, ecm + ecmLen - 8), dw, 0, 2)) ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ ++ if ((ens & 0xE0000000) == 0xA0000000) // Strip [tsid] [onid] [namespace] on r752+ ecms ++ { ++ ecmLen -= 8; ++ ecmDataLen -= 8; ++ } ++ } ++ ++ // Try using ecmpid if it seems to be faulty (should be 0x1FFF always for BISS) ++ if (ecmpid != 0x1FFF && ecmpid != 0) ++ { ++ if (BissGetKey((srvid << 16) | ecmpid, dw, 0, 2)) ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ } ++ ++ // Try to get the pid from oscam's fake ecm (only search [pid1] [pid2] ... [pidx] to be compatible with emu r748-) ++ if (ecmLen >= 7 && ecmLen <= ecmDataLen) // Use >= for radio channels with just one (audio) pid ++ { ++ // Reverse search order: last pid in list first ++ // Better identifies channels where they share identical video pid but have variable counts of audio pids ++ for (i = ecmLen - 2; i >= 5; i -= 2) ++ { ++ pid = b2i(2, ecm + i); ++ ++ if (BissGetKey((srvid << 16) | pid, dw, 0, 2)) ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ } ++ } ++ ++ // Try using the standard BISS ecm pid ++ if (ecmpid == 0x1FFF || ecmpid == 0) ++ { ++ if (BissGetKey((srvid << 16) | 0x1FFF, dw, 0, 2)) ++ { ++ memcpy(dw + 8, dw, 8); ++ return 0; ++ } ++ } ++ ++ // Default BISS key for events with many feeds sharing same key ++ if (ecmpid != 0 && BissGetKey(0xA11FEED5, dw, rdr->emu_datecodedenabled, 2)) // Limit to local ecms, block netwotk ecms ++ { ++ memcpy(dw + 8, dw, 8); ++ cs_hexdump(0, dw, 8, tmpBuffer1, sizeof(tmpBuffer1)); ++ cs_log("No specific match found. Using 'All Feeds' key: %s", tmpBuffer1); ++ return 0; ++ } ++ ++ // Print example key lines for available hash search methods, if no key is found ++ if (strncmp(tmpBuffer2, "0", 2)) cs_log("Example key based on namespace hash: %s", tmpBuffer2); ++ if (strncmp(tmpBuffer3, "0", 2)) cs_log("Example key based on universal hash: %s", tmpBuffer3); ++ ++ // Check if universal hash is common and warn user ++ if (BissIsCommonHash(hash)) cs_log("Feed has commonly used pids, universal hash clashes in SoftCam.Key are likely!"); ++ ++ return 2; ++} ++ ++// PowerVu Emu ++static uint8_t PowervuCrc8Calc(uint8_t *data, int len) ++{ ++ int i; ++ uint8_t crc = 0x00; ++ uint8_t crcTable[256] = {0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, ++ 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, ++ 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, ++ 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, ++ 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, ++ 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, ++ 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, ++ 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, ++ 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, ++ 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, ++ 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, ++ 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, ++ 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, ++ 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, ++ 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, ++ 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3}; ++ ++ for(i = 0; i < len; i++) ++ { ++ crc = crcTable[data[i] ^ crc]; ++ } ++ ++ return crc; ++} ++ ++static void PowervuPadData(uint8_t *data, int len, uint8_t *dataPadded) ++{ ++ int i; ++ uint8_t pad[] = {0x01, 0x02, 0x22, 0x04, 0x20, 0x2A, 0x1F, 0x03, 0x04, 0x06, 0x02, 0x0C, 0x2B, 0x2B, 0x01, 0x7B}; ++ ++ for(i = 0; i < len; i++) ++ { ++ dataPadded[i] = data[i]; ++ } ++ ++ dataPadded[len] = 0x01; ++ ++ for(i = len + 1; i < 0x2F; i++) ++ { ++ dataPadded[i] = 0x00; ++ } ++ ++ dataPadded[0x2F] = len; ++ ++ for(i = 0; i < 0x10; i++) ++ { ++ dataPadded[0x30 + i] = pad[i]; ++ } ++} ++ ++static void PowervuHashMode01CustomMD5(uint8_t *data, uint8_t *hash) ++{ ++ int i, j, s; ++ uint32_t a, b, c, d, f = 0, g; ++ ++ uint32_t T[] = {0x783E16F6, 0xC267AC13, 0xA2B17F12, 0x6B8A31A4, 0xF910654D, 0xB702DBCB, 0x266CEF60, 0x5145E47C, ++ 0xB92E00D6, 0xE80A4A64, 0x8A07FA77, 0xBA7D89A9, 0xEBED8022, 0x653AAF2B, 0xF118B03B, 0x6CC16544, ++ 0x96EB6583, 0xF4E27E35, 0x1ABB119E, 0x068D3EF2, 0xDAEAA8A5, 0x3C312A3D, 0x59538388, 0xA100772F, ++ 0xAB0165CE, 0x979959E7, 0x5DD8F53D, 0x189662BA, 0xFD021A9C, 0x6BC2D338, 0x1EFF667E, 0x40C66888, ++ 0x6E9F07FF, 0x0CEF442F, 0x82D20190, 0x4E8CAEAC, 0x0F7CB305, 0x2E73FBE7, 0x1CE884A2, 0x7A60BD52, ++ 0xC348B30D, 0x081CE3AA, 0xA12220E7, 0x38C7EC79, 0xCBD8DD3A, 0x62B4FBA5, 0xAD2A63DB, 0xE4D0852E, ++ 0x53DE980F, 0x9C8DDA59, 0xA6B4CEDE, 0xB48A7692, 0x0E2C46A4, 0xEB9367CB, 0x165D72EE, 0x75532B45, ++ 0xB9CA8E97, 0x08C8837B, 0x966F917B, 0x527515B4, 0xF27A5E5D, 0xB71E6267, 0x7603D7E6, 0x9837DD69}; // CUSTOM T ++ ++ uint8_t r[] = {0x06, 0x0A, 0x0F, 0x15, 0x05, 0x09, 0x0E, 0x14, 0x04, 0x0B, 0x10, 0x17, 0x07, 0x0C, 0x11, 0x16}; // STANDARD REORDERED ++ ++ uint8_t tIdxInit[] = {0, 1, 5, 0}; // STANDARD ++ uint8_t tIdxIncr[] = {1, 5, 3, 7}; // STANDARD ++ ++ uint32_t h[] = {0xEAD81D2E, 0xCE4DC6E9, 0xF9B5C301, 0x10325476}; // CUSTOM h0, h1, h2 STANDARD h3 ++ uint32_t dataLongs[0x10]; ++ ++ for (i = 0; i < 0x10; i++) ++ { ++ dataLongs[i] = (data[4 * i + 0] << 0) + (data[4 * i + 1] << 8) + (data[4 * i + 2] << 16) + (data[4 * i + 3] << 24); ++ } ++ ++ a = h[0]; ++ b = h[1]; ++ c = h[2]; ++ d = h[3]; ++ ++ for (i = 0; i < 4; i++) ++ { ++ g = tIdxInit[i]; ++ ++ for (j = 0; j < 16; j++) ++ { ++ if (i == 0) ++ { ++ f = (b & c) | (~b & d); ++ } ++ else if (i == 1) ++ { ++ f = (b & d) | (~d & c); ++ } ++ else if (i == 2) ++ { ++ f = (b ^ c ^ d); ++ } ++ else if (i == 3) ++ { ++ f = (~d | b) ^ c; ++ } ++ ++ f = dataLongs[g] + a + T[16 * i + j] + f; ++ ++ s = r[4 * i + (j & 3)]; ++ f = (f << s) | (f >> (32 - s)); ++ ++ a = d; ++ d = c; ++ c = b; ++ b += f; ++ ++ g = (g + tIdxIncr[i]) & 0xF; ++ } ++ } ++ ++ h[0] += a; ++ h[1] += b; ++ h[2] += c; ++ h[3] += d; ++ ++ for (i = 0; i < 4; i++) ++ { ++ hash[4 * i + 0] = h[i] >> 0; ++ hash[4 * i + 1] = h[i] >> 8; ++ hash[4 * i + 2] = h[i] >> 16; ++ hash[4 * i + 3] = h[i] >> 24; ++ } ++} ++ ++static void PowervuHashMode02(uint8_t *data, uint8_t *hash) ++{ ++ int i; ++ uint32_t a, b, c, d, e, f = 0, tmp; ++ uint32_t h[] = {0x81887F3A, 0x36CCA480, 0x99056FB1, 0x79705BAE}; ++ uint32_t dataLongs[0x50]; ++ ++ for (i = 0; i < 0x10; i++) ++ { ++ dataLongs[i] = (data[4 * i + 0] << 24) + (data[4 * i + 1] << 16) + (data[4 * i + 2] << 8) + (data[4 * i + 3] << 0); ++ } ++ ++ for (i = 0; i < 0x40; i++) ++ { ++ dataLongs[0x10 + i] = dataLongs[0x10 + i - 2]; ++ dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 7]; ++ dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 13]; ++ dataLongs[0x10 + i] ^= dataLongs[0x10 + i - 16]; ++ } ++ ++ a = dataLongs[0]; ++ b = dataLongs[1]; ++ c = dataLongs[2]; ++ d = dataLongs[3]; ++ e = dataLongs[4]; ++ ++ for (i = 0; i < 0x50; i++) ++ { ++ if (i < 0x15) f = (b & c) | (~b & d); ++ else if (i < 0x28) f = (b ^ c ^ d); ++ else if (i < 0x3D) f = (b & c) | (c & d) | (b & d); ++ else if (i < 0x50) f = (b ^ c ^ d); ++ ++ tmp = a; ++ a = e + f + (a << 5) + (a >> 27) + h[i / 0x14] + dataLongs[i]; ++ e = d; ++ d = c; ++ c = (b << 30) + (b >> 2); ++ b = tmp; ++ } ++ ++ dataLongs[0] += a; ++ dataLongs[1] += b; ++ dataLongs[2] += c; ++ dataLongs[3] += d; ++ ++ for (i = 0; i < 4; i++) ++ { ++ hash[4 * i + 0] = dataLongs[i] >> 24; ++ hash[4 * i + 1] = dataLongs[i] >> 16; ++ hash[4 * i + 2] = dataLongs[i] >> 8; ++ hash[4 * i + 3] = dataLongs[i] >> 0; ++ } ++} ++ ++static void PowervuHashMode03(uint8_t *data, uint8_t *hash) ++{ ++ int i, j, k, s, s2, tmp; ++ uint32_t a, b, c, d, f = 0, g; ++ uint32_t a2, b2, c2, d2, f2 = 0, g2; ++ ++ uint32_t T[] = { 0xC88F3F2E, 0x967506BA, 0xDA877A7B, 0x0DECCDFE }; ++ uint32_t T2[] = { 0x01F42668, 0x39C7CDA5, 0xD490E2FE, 0x9965235D }; ++ ++ uint8_t r[] = { 0x0B, 0x0E, 0x0F, 0x0C, 0x05, 0x08, 0x07, 0x09, 0x0B, 0x0D, 0x0E, 0x0F, 0x06, 0x07, 0x09, 0x08, ++ 0x07, 0x06, 0x08, 0x0D, 0x0B, 0x09, 0x07, 0x0F, 0x07, 0x0C, 0x0F, 0x09, 0x0B, 0x07, 0x0D, 0x0C }; ++ ++ uint8_t tIdxIncr[] = { 0x07, 0x04, 0x0D, 0x01, 0x0A, 0x06, 0x0F, 0x03, 0x0C, 0x00, 0x09, 0x05, 0x02, 0x0E, 0x0B, 0x08, ++ 0x05, 0x0D, 0x02, 0x00, 0x04, 0x09, 0x03, 0x08, 0x01, 0x0A, 0x07, 0x0B, 0x06, 0x0F, 0x0C, 0x0E }; ++ ++ uint32_t h[] = { 0xC8616857, 0x9D3F5B8E, 0x4D7B8F76, 0x97BC8D80 }; ++ ++ uint32_t dataLongs[0x50]; ++ uint32_t result[4]; ++ ++ for (i = 0; i < 0x10; i++) ++ { ++ dataLongs[i] = (data[4 * i + 0] << 24) + (data[4 * i + 1] << 16) + (data[4 * i + 2] << 8) + (data[4 * i + 3] << 0); ++ } ++ ++ a = h[0]; ++ b = h[1]; ++ c = h[2]; ++ d = h[3]; ++ ++ a2 = h[3]; ++ b2 = h[2]; ++ c2 = h[1]; ++ d2 = h[0]; ++ ++ for (i = 0; i < 4; i++) ++ { ++ for (j = 0; j < 16; j++) ++ { ++ tmp = j; ++ ++ for (k = 0; k < i; k++) ++ { ++ tmp = tIdxIncr[tmp]; ++ } ++ ++ g = 0x0F - tmp; ++ g2 = tmp; ++ ++ if (i == 0) f = (b & d) | (~d & c); ++ else if (i == 1) f = (~c | b) ^ d; ++ else if (i == 2) f = (~b & d) | (b & c); ++ else if (i == 3) f = (b ^ c ^ d); ++ ++ if (i == 0) f2 = (b2 ^ c2 ^ d2); ++ else if (i == 1) f2 = (~b2 & d2) | (b2 & c2); ++ else if (i == 2) f2 = (~c2 | b2) ^ d2; ++ else if (i == 3) f2 = (b2 & d2) | (~d2 & c2); ++ ++ f = dataLongs[g] + a + T[i] + f; ++ s = r[0x0F + (((i & 1) ^ 1) << 4) - j]; ++ f = (f << s) | (f >> (32 - s)); ++ ++ f2 = dataLongs[g2] + a2 + T2[i] + f2; ++ s2 = r[((i & 1) << 4) + j]; ++ f2 = (f2 << s2) | (f2 >> (32 - s2)); ++ ++ a = d; ++ d = (c << 10) | (c >> 22); ++ c = b; ++ b = f; ++ ++ a2 = d2; ++ d2 = (c2 << 10) | (c2 >> 22); ++ c2 = b2; ++ b2 = f2; ++ } ++ } ++ ++ result[0] = h[3] + b + a2; ++ result[1] = h[2] + c + b2; ++ result[2] = h[1] + d + c2; ++ result[3] = h[0] + a + d2; ++ ++ for (i = 0; i < 4; i++) ++ { ++ hash[4 * i + 0] = result[i] >> 0; ++ hash[4 * i + 1] = result[i] >> 8; ++ hash[4 * i + 2] = result[i] >> 16; ++ hash[4 * i + 3] = result[i] >> 24; ++ } ++} ++ ++uint8_t table04[] = { 0x02, 0x03, 0x07, 0x0B, 0x0D, 0x08, 0x00, 0x01, 0x2B, 0x2D, 0x28, 0x20, 0x21, 0x0A, 0x0C, 0x0E, ++ 0x22, 0x36, 0x23, 0x27, 0x29, 0x24, 0x25, 0x26, 0x2A, 0x3C, 0x3E, 0x3F, 0x0F, 0x2C, 0x2E, 0x2F, ++ 0x12, 0x13, 0x17, 0x1B, 0x1C, 0x18, 0x10, 0x11, 0x19, 0x14, 0x15, 0x16, 0x1A, 0x09, 0x04, 0x05, ++ 0x32, 0x33, 0x37, 0x3B, 0x06, 0x1C, 0x1E, 0x1F, 0x3D, 0x38, 0x30, 0x31, 0x39, 0x34, 0x35, 0x3A }; ++ ++uint8_t table05[] = { 0x08, 0x09, 0x0A, 0x03, 0x04, 0x3F, 0x27, 0x28, 0x29, 0x2A, 0x05, 0x0B, 0x1B, 0x1C, 0x1C, 0x1E, ++ 0x20, 0x0C, 0x0D, 0x22, 0x23, 0x24, 0x00, 0x01, 0x02, 0x06, 0x07, 0x25, 0x26, 0x0E, 0x0F, 0x21, ++ 0x10, 0x11, 0x12, 0x2E, 0x2F, 0x13, 0x14, 0x15, 0x2B, 0x2C, 0x2D, 0x16, 0x17, 0x18, 0x19, 0x1A, ++ 0x30, 0x31, 0x37, 0x3B, 0x3C, 0x3D, 0x3E, 0x1F, 0x38, 0x39, 0x32, 0x33, 0x34, 0x35, 0x36, 0x3A }; ++ ++uint8_t table06[] = { 0x00, 0x01, 0x02, 0x06, 0x07, 0x08, 0x03, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x04, 0x05, 0x09, 0x0D, ++ 0x20, 0x21, 0x22, 0x26, 0x27, 0x3A, 0x3B, 0x3C, 0x3E, 0x3F, 0x10, 0x11, 0x12, 0x16, 0x17, 0x28, ++ 0x18, 0x13, 0x14, 0x15, 0x19, 0x1C, 0x1A, 0x1B, 0x1C, 0x1E, 0x1F, 0x23, 0x24, 0x25, 0x29, 0x2D, ++ 0x30, 0x31, 0x32, 0x36, 0x37, 0x38, 0x33, 0x34, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x35, 0x39, 0x3D }; ++ ++uint8_t table07[] = { 0x10, 0x11, 0x12, 0x17, 0x1C, 0x1E, 0x0E, 0x38, 0x39, 0x3A, 0x13, 0x14, 0x29, 0x2A, 0x16, 0x1F, ++ 0x00, 0x01, 0x02, 0x3C, 0x3D, 0x3E, 0x3F, 0x07, 0x08, 0x09, 0x03, 0x04, 0x05, 0x06, 0x3B, 0x0A, ++ 0x20, 0x21, 0x22, 0x19, 0x1A, 0x1B, 0x1C, 0x0B, 0x0C, 0x15, 0x23, 0x24, 0x25, 0x26, 0x18, 0x0F, ++ 0x30, 0x31, 0x2B, 0x33, 0x34, 0x35, 0x36, 0x37, 0x27, 0x28, 0x2C, 0x2D, 0x2E, 0x2F, 0x32, 0x0D }; ++ ++uint8_t table08[] = { 0x10, 0x11, 0x1E, 0x17, 0x18, 0x19, 0x12, 0x13, 0x14, 0x1C, 0x1C, 0x15, 0x0D, 0x05, 0x06, 0x0A, ++ 0x00, 0x01, 0x0E, 0x07, 0x08, 0x09, 0x02, 0x2D, 0x25, 0x26, 0x2A, 0x2B, 0x2F, 0x03, 0x04, 0x0C, ++ 0x20, 0x21, 0x2E, 0x27, 0x28, 0x29, 0x30, 0x31, 0x3E, 0x37, 0x38, 0x39, 0x22, 0x23, 0x24, 0x2C, ++ 0x32, 0x33, 0x34, 0x3C, 0x3D, 0x35, 0x36, 0x3A, 0x3B, 0x0B, 0x0F, 0x16, 0x1A, 0x1B, 0x1F, 0x3F }; ++ ++uint8_t table09[] = { 0x20, 0x21, 0x24, 0x22, 0x23, 0x2A, 0x2B, 0x33, 0x35, 0x38, 0x39, 0x36, 0x2D, 0x2C, 0x2E, 0x2F, ++ 0x00, 0x01, 0x04, 0x02, 0x25, 0x28, 0x08, 0x09, 0x06, 0x07, 0x0A, 0x0B, 0x0D, 0x0C, 0x0E, 0x0F, ++ 0x10, 0x11, 0x14, 0x12, 0x13, 0x15, 0x19, 0x16, 0x29, 0x26, 0x03, 0x17, 0x1A, 0x1C, 0x1C, 0x1E, ++ 0x30, 0x31, 0x34, 0x32, 0x37, 0x3A, 0x3B, 0x3D, 0x3C, 0x3E, 0x3F, 0x1B, 0x05, 0x18, 0x27, 0x1F }; ++ ++uint8_t table0A[] = { 0x00, 0x04, 0x05, 0x0B, 0x0C, 0x06, 0x09, 0x0A, 0x0E, 0x0D, 0x0F, 0x25, 0x15, 0x1B, 0x1C, 0x16, ++ 0x10, 0x11, 0x01, 0x02, 0x03, 0x07, 0x08, 0x12, 0x13, 0x17, 0x18, 0x14, 0x23, 0x27, 0x28, 0x24, ++ 0x30, 0x31, 0x32, 0x33, 0x37, 0x38, 0x34, 0x35, 0x3B, 0x3C, 0x20, 0x21, 0x22, 0x2B, 0x2C, 0x26, ++ 0x36, 0x39, 0x3A, 0x3E, 0x3D, 0x19, 0x1A, 0x1E, 0x1C, 0x1F, 0x3F, 0x29, 0x2A, 0x2E, 0x2D, 0x2F }; ++ ++static void PowervuHashModes04to0ATables(uint8_t *data, uint8_t *hash, uint8_t *table) ++{ ++ int i; ++ ++ for (i = 0; i < 0x10; i++) ++ { ++ hash[i] = table[i]; ++ hash[i] ^= data[table[i]]; ++ hash[i] ^= table[0x10 + i]; ++ hash[i] ^= data[table[0x10 + i]]; ++ hash[i] ^= table[0x20 + i]; ++ hash[i] ^= data[table[0x20 + i]]; ++ hash[i] ^= table[0x30 + i]; ++ hash[i] ^= data[table[0x30 + i]]; ++ } ++} ++ ++static void PowervuCreateHash(uint8_t *data, int len, uint8_t *hash, int mode) ++{ ++ uint8_t dataPadded[0x40]; ++ ++ PowervuPadData(data, len, dataPadded); ++ ++ switch(mode) ++ { ++ case 1: ++ PowervuHashMode01CustomMD5(dataPadded, hash); ++ break; ++ ++ case 2: ++ PowervuHashMode02(dataPadded, hash); ++ break; ++ ++ case 3: ++ PowervuHashMode03(dataPadded, hash); ++ break; ++ ++ case 4: ++ PowervuHashModes04to0ATables(dataPadded, hash, table04); ++ break; ++ ++ case 5: ++ PowervuHashModes04to0ATables(dataPadded, hash, table05); ++ break; ++ ++ case 6: ++ PowervuHashModes04to0ATables(dataPadded, hash, table06); ++ break; ++ ++ case 7: ++ PowervuHashModes04to0ATables(dataPadded, hash, table07); ++ break; ++ ++ case 8: ++ PowervuHashModes04to0ATables(dataPadded, hash, table08); ++ break; ++ ++ case 9: ++ PowervuHashModes04to0ATables(dataPadded, hash, table09); ++ break; ++ ++ case 10: ++ PowervuHashModes04to0ATables(dataPadded, hash, table0A); ++ break; ++ ++ default: ++ cs_log("A new hash mode [%d] is in use.", mode); ++ break; ++ } ++} ++ ++static void PowervuCreateDataEcmEmm(uint8_t *emmEcm, uint8_t *pos, int lenHeader, int len, uint8_t *data) ++{ ++ int i; ++ ++ for(i = 0; i < len; i++) ++ { ++ data[i] = emmEcm[lenHeader + pos[i]]; ++ } ++} ++ ++static uint8_t PowervuCreateDataCw(uint8_t *seed, uint8_t lenSeed, uint8_t *baseCw, uint8_t val, uint8_t *seedEcmCw, uint8_t *data) ++{ ++ int i; ++ ++ for(i = 0; i < lenSeed; i++) ++ { ++ data[i] = seed[i]; ++ } ++ ++ for(i = 0; i < 7; i++) ++ { ++ data[lenSeed + i] = baseCw[i]; ++ } ++ ++ data[lenSeed + 7] = val; ++ ++ for(i = 0; i < 16; i++) ++ { ++ data[lenSeed + 7 + 1 + i] = seedEcmCw[i]; ++ } ++ ++ return lenSeed + 7 + 1 + 0x10; ++} ++ ++static uint8_t PowervuUnmaskEcm(uint8_t *ecm, uint8_t *seedEcmCw) ++{ ++ int i, l; ++ ++ uint8_t sourcePos[] = {0x04, 0x05, 0x06, 0x07, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x17, 0x1C, 0x1D, 0x1F, 0x23, ++ 0x24, 0x25, 0x26, 0x27, 0x29, 0x2C, 0x2D, 0x2E}; ++ uint8_t destPos[] = {0x08, 0x09, 0x11, 0x18, 0x19, 0x1A, 0x1B, 0x1E, 0x20, 0x21, 0x22, 0x28, 0x2A, 0x2B, 0x2F, 0x30}; ++ uint8_t seedCwPos[] = {0x07, 0x0A, 0x04, 0x0D, 0x05, 0x0E, 0x06, 0x0B, 0x10, 0x0C, 0x0F}; ++ ++ uint8_t data[0x18]; ++ uint8_t mask[0x10]; ++ uint8_t hashModeEcm; ++ uint8_t hashModeCw; ++ uint32_t crc; ++ ++ // Create seed for CW decryption ++ memset(seedEcmCw, 0, 0x10); ++ ++ int extraBytesLen = ecm[9]; ++ int startOffset = extraBytesLen + 0x0A; ++ ++ for (i = 0; i < 0x0B; i++) ++ { ++ seedEcmCw[i] = ecm[startOffset + seedCwPos[i]]; ++ } ++ ++ // Read hash mode CW ++ hashModeCw = ecm[28 + extraBytesLen] ^ PowervuCrc8Calc(seedEcmCw, 0x10); ++ ++ // Create mask for ECM decryption ++ PowervuCreateDataEcmEmm(ecm, sourcePos, startOffset, 0x18, data); ++ ++ hashModeEcm = ecm[8] ^ PowervuCrc8Calc(data, 0x18); ++ ++ PowervuCreateHash(data, 0x18, mask, hashModeEcm); ++ ++ // Fix header ++ ecm[3] &= 0x0F; ++ ecm[3] |= 0x30; ++ ecm[8] = 0x00; ++ ecm[28 + extraBytesLen] = 0x00; ++ ++ // Unmask body ++ for (i = 0; i < 0x10; i++) ++ { ++ ecm[startOffset + destPos[i]] ^= mask[i & 0x0F]; ++ } ++ ++ // Fix CRC (optional) ++ l = (((ecm[1] << 8) + ecm[2]) & 0xFFF) + 3 - 4; ++ ++ crc = fletcher_crc32(ecm, l); ++ ++ ecm[l + 0] = crc >> 24; ++ ecm[l + 1] = crc >> 16; ++ ecm[l + 2] = crc >> 8; ++ ecm[l + 3] = crc >> 0; ++ ++ return hashModeCw; ++} ++ ++static void PowervuCreateCw(uint8_t *seed, uint8_t lenSeed, uint8_t *baseCw, uint8_t val, ++ uint8_t *seedEcmCw, uint8_t *cw, int modeDesCsa, int hashMode) ++{ ++ uint8_t tableFixParity[] = {0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07, 0x08, 0x08, 0x0B, 0x0B, 0x0D, 0x0D, 0x0E, 0x0E, ++ 0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16, 0x19, 0x19, 0x1A, 0x1A, 0x1C, 0x1C, 0x1F, 0x1F, ++ 0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26, 0x29, 0x29, 0x2A, 0x2A, 0x2C, 0x2C, 0x2F, 0x2F, ++ 0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37, 0x38, 0x38, 0x3B, 0x3B, 0x3D, 0x3D, 0x3E, 0x3E, ++ 0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46, 0x49, 0x49, 0x4A, 0x4A, 0x4C, 0x4C, 0x4F, 0x4F, ++ 0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57, 0x58, 0x58, 0x5B, 0x5B, 0x5D, 0x5D, 0x5E, 0x5E, ++ 0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67, 0x68, 0x68, 0x6B, 0x6B, 0x6D, 0x6D, 0x6E, 0x6E, ++ 0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76, 0x79, 0x79, 0x7A, 0x7A, 0x7C, 0x7C, 0x7F, 0x7F, ++ 0x80, 0x80, 0x83, 0x83, 0x85, 0x85, 0x86, 0x86, 0x89, 0x89, 0x8A, 0x8A, 0x8C, 0x8C, 0x8F, 0x8F, ++ 0x91, 0x91, 0x92, 0x92, 0x94, 0x94, 0x97, 0x97, 0x98, 0x98, 0x9B, 0x9B, 0x9D, 0x9D, 0x9E, 0x9E, ++ 0xA1, 0xA1, 0xA2, 0xA2, 0xA4, 0xA4, 0xA7, 0xA7, 0xA8, 0xA8, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAE, ++ 0xB0, 0xB0, 0xB3, 0xB3, 0xB5, 0xB5, 0xB6, 0xB6, 0xB9, 0xB9, 0xBA, 0xBA, 0xBC, 0xBC, 0xBF, 0xBF, ++ 0xC1, 0xC1, 0xC2, 0xC2, 0xC4, 0xC4, 0xC7, 0xC7, 0xC8, 0xC8, 0xCB, 0xCB, 0xCD, 0xCD, 0xCE, 0xCE, ++ 0xD0, 0xD0, 0xD3, 0xD3, 0xD5, 0xD5, 0xD6, 0xD6, 0xD9, 0xD9, 0xDA, 0xDA, 0xDC, 0xDC, 0xDF, 0xDF, ++ 0xE0, 0xE0, 0xE3, 0xE3, 0xE5, 0xE5, 0xE6, 0xE6, 0xE9, 0xE9, 0xEA, 0xEA, 0xEC, 0xEC, 0xEF, 0xEF, ++ 0xF1, 0xF1, 0xF2, 0xF2, 0xF4, 0xF4, 0xF7, 0xF7, 0xF8, 0xF8, 0xFB, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE}; ++ ++ uint8_t data[0x1C]; ++ uint8_t hash[0x10]; ++ uint8_t lenData; ++ int i; ++ ++ lenData = PowervuCreateDataCw(seed, lenSeed, baseCw, val, seedEcmCw, data); ++ PowervuCreateHash(data, lenData, hash, hashMode); ++ ++ for(i = 0; i < 8; i++) ++ { ++ cw[i] = hash[i]; ++ } ++ ++ if(modeDesCsa == 0) // DES - Fix Parity Bits ++ { ++ for(i = 0; i < 8; i++) ++ { ++ cw[i] = tableFixParity[cw[i]]; ++ } ++ } ++ else if(modeDesCsa == 1) // CSA - Fix Checksums ++ { ++ cw[3] = cw[0] + cw[1] + cw[2]; ++ cw[7] = cw[4] + cw[5] + cw[6]; ++ } ++} ++ ++static int8_t GetPowervuKey(uint8_t *buf, uint32_t ident, char keyName, uint32_t keyIndex, uint32_t keyLength, uint8_t isCriticalKey, uint32_t keyRef) ++{ ++ char keyStr[EMU_MAX_CHAR_KEYNAME]; ++ ++ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "%c%X", keyName, keyIndex); ++ if(FindKey('P', ident, 0xFFFF0000, keyStr, buf, keyLength, isCriticalKey, keyRef, 0, NULL)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int8_t GetPowervuEmmKey(uint8_t *buf, uint32_t ident, char *keyName, uint32_t keyLength, uint8_t isCriticalKey, uint32_t keyRef, uint32_t *getProvider) ++{ ++ if(FindKey('P', ident, 0xFFFFFFFF, keyName, buf, keyLength, isCriticalKey, keyRef, 0, getProvider)) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static const uint8_t PowerVu_A0_S_1[16] = {0x33, 0xA4, 0x44, 0x3C, 0xCA, 0x2E, 0x75, 0x7B, 0xBC, 0xE6, 0xE5, 0x35, 0xA0, 0x55, 0xC9, 0xA2}; ++static const uint8_t PowerVu_A0_S_2[16] = {0x5A, 0xB0, 0x2C, 0xBC, 0xDA, 0x32, 0xE6, 0x92, 0x40, 0x53, 0x6E, 0xF9, 0x69, 0x11, 0x1E, 0xFB}; ++static const uint8_t PowerVu_A0_S_3[16] = {0x4E, 0x18, 0x9B, 0x19, 0x79, 0xFB, 0x01, 0xFA, 0xE3, 0xE1, 0x28, 0x3D, 0x32, 0xE4, 0x92, 0xEA}; ++static const uint8_t PowerVu_A0_S_4[16] = {0x05, 0x6F, 0x37, 0x66, 0x35, 0xE1, 0x58, 0xD0, 0xB4, 0x6A, 0x97, 0xAE, 0xD8, 0x91, 0x27, 0x56}; ++static const uint8_t PowerVu_A0_S_5[16] = {0x7B, 0x26, 0xAD, 0x34, 0x3D, 0x77, 0x39, 0x51, 0xE0, 0xE0, 0x48, 0x8C, 0x39, 0xF5, 0xE8, 0x47}; ++static const uint8_t PowerVu_A0_S_6[16] = {0x74, 0xFA, 0x4D, 0x79, 0x42, 0x39, 0xD1, 0xA4, 0x99, 0xA3, 0x97, 0x07, 0xDF, 0x14, 0x3A, 0xC4}; ++static const uint8_t PowerVu_A0_S_7[16] = {0xC6, 0x1E, 0x3C, 0x24, 0x11, 0x08, 0x5D, 0x6A, 0xEB, 0x97, 0xB9, 0x25, 0xA7, 0xFA, 0xE9, 0x1A}; ++static const uint8_t PowerVu_A0_S_8[16] = {0x9A, 0xAD, 0x72, 0xD7, 0x7C, 0x68, 0x3B, 0x55, 0x1D, 0x4A, 0xA2, 0xB0, 0x38, 0xB9, 0x56, 0xD0}; ++static const uint8_t PowerVu_A0_S_9[32] = {0x61, 0xDA, 0x5F, 0xB7, 0xEB, 0xC6, 0x3F, 0x6C, 0x09, 0xF3, 0x64, 0x38, 0x33, 0x08, 0xAA, 0x15, ++ 0xCC, 0xEF, 0x22, 0x64, 0x01, 0x2C, 0x12, 0xDE, 0xF4, 0x6E, 0x3C, 0xCD, 0x1A, 0x64, 0x63, 0x7C ++ }; ++ ++static const uint8_t PowerVu_00_S_1[16] = {0x97, 0x13, 0xEB, 0x6B, 0x04, 0x5E, 0x60, 0x3A, 0xD9, 0xCC, 0x91, 0xC2, 0x5A, 0xFD, 0xBA, 0x0C}; ++static const uint8_t PowerVu_00_S_2[16] = {0x61, 0x3C, 0x03, 0xB0, 0xB5, 0x6F, 0xF8, 0x01, 0xED, 0xE0, 0xE5, 0xF3, 0x78, 0x0F, 0x0A, 0x73}; ++static const uint8_t PowerVu_00_S_3[16] = {0xFD, 0xDF, 0xD2, 0x97, 0x06, 0x14, 0x91, 0xB5, 0x36, 0xAD, 0xBC, 0xE1, 0xB3, 0x00, 0x66, 0x41}; ++static const uint8_t PowerVu_00_S_4[16] = {0x8B, 0xD9, 0x18, 0x0A, 0xED, 0xEE, 0x61, 0x34, 0x1A, 0x79, 0x80, 0x8C, 0x1E, 0x7F, 0xC5, 0x9F}; ++static const uint8_t PowerVu_00_S_5[16] = {0xB0, 0xA1, 0xF2, 0xB8, 0xEA, 0x72, 0xDD, 0xD3, 0x30, 0x65, 0x2B, 0x1E, 0xE9, 0xE1, 0x45, 0x29}; ++static const uint8_t PowerVu_00_S_6[16] = {0x5D, 0xCA, 0x53, 0x75, 0xB2, 0x24, 0xCE, 0xAF, 0x21, 0x54, 0x9E, 0xBE, 0x02, 0xA9, 0x4C, 0x5D}; ++static const uint8_t PowerVu_00_S_7[16] = {0x42, 0x66, 0x72, 0x83, 0x1B, 0x2D, 0x22, 0xC9, 0xF8, 0x4D, 0xBA, 0xCD, 0xBB, 0x20, 0xBD, 0x6B}; ++static const uint8_t PowerVu_00_S_8[16] = {0xC4, 0x0C, 0x6B, 0xD3, 0x6D, 0x94, 0x7E, 0x53, 0xCE, 0x96, 0xAC, 0x40, 0x2C, 0x7A, 0xD3, 0xA9}; ++static const uint8_t PowerVu_00_S_9[32] = {0x31, 0x82, 0x4F, 0x9B, 0xCB, 0x6F, 0x9D, 0xB7, 0xAE, 0x68, 0x0B, 0xA0, 0x93, 0x15, 0x32, 0xE2, ++ 0xED, 0xE9, 0x47, 0x29, 0xC2, 0xA8, 0x92, 0xEF, 0xBA, 0x27, 0x22, 0x57, 0x76, 0x54, 0xC0, 0x59, ++ }; ++ ++static uint8_t PowervuSbox(uint8_t *input, uint8_t mode) ++{ ++ uint8_t s_index, bit, last_index, last_bit; ++ uint8_t const *Sbox1, *Sbox2, *Sbox3, *Sbox4, *Sbox5, *Sbox6, *Sbox7, *Sbox8, *Sbox9; ++ ++ if(mode) ++ { ++ Sbox1 = PowerVu_A0_S_1; ++ Sbox2 = PowerVu_A0_S_2; ++ Sbox3 = PowerVu_A0_S_3; ++ Sbox4 = PowerVu_A0_S_4; ++ Sbox5 = PowerVu_A0_S_5; ++ Sbox6 = PowerVu_A0_S_6; ++ Sbox7 = PowerVu_A0_S_7; ++ Sbox8 = PowerVu_A0_S_8; ++ Sbox9 = PowerVu_A0_S_9; ++ } ++ else ++ { ++ Sbox1 = PowerVu_00_S_1; ++ Sbox2 = PowerVu_00_S_2; ++ Sbox3 = PowerVu_00_S_3; ++ Sbox4 = PowerVu_00_S_4; ++ Sbox5 = PowerVu_00_S_5; ++ Sbox6 = PowerVu_00_S_6; ++ Sbox7 = PowerVu_00_S_7; ++ Sbox8 = PowerVu_00_S_8; ++ Sbox9 = PowerVu_00_S_9; ++ } ++ ++ bit = (GetBit(input[2],0)<<2) | (GetBit(input[3],4)<<1) | (GetBit(input[5],3)); ++ s_index = (GetBit(input[0],0)<<3) | (GetBit(input[2],6)<<2) | (GetBit(input[2],4)<<1) | (GetBit(input[5],7)); ++ last_bit = GetBit(Sbox1[s_index],7-bit); ++ ++ bit = (GetBit(input[5],0)<<2) | (GetBit(input[4],0)<<1) | (GetBit(input[6],2)); ++ s_index = (GetBit(input[2],1)<<3) | (GetBit(input[2],2)<<2) | (GetBit(input[5],5)<<1) | (GetBit(input[5],1)); ++ last_bit = last_bit | (GetBit(Sbox2[s_index],7-bit)<<1); ++ ++ bit = (GetBit(input[6],0)<<2) | (GetBit(input[1],7)<<1) | (GetBit(input[6],7)); ++ s_index = (GetBit(input[1],3)<<3) | (GetBit(input[3],7)<<2) | (GetBit(input[1],5)<<1) | (GetBit(input[5],2)); ++ last_bit = last_bit | (GetBit(Sbox3[s_index], 7-bit)<<2); ++ ++ bit = (GetBit(input[1],0)<<2) | (GetBit(input[2],7)<<1) | (GetBit(input[2],5)); ++ s_index = (GetBit(input[6],3)<<3) | (GetBit(input[6],4)<<2) | (GetBit(input[6],6)<<1) | (GetBit(input[3],5)); ++ last_index = GetBit(Sbox4[s_index], 7-bit); ++ ++ bit = (GetBit(input[3],3)<<2) | (GetBit(input[4],6)<<1) | (GetBit(input[3],2)); ++ s_index = (GetBit(input[3],1)<<3) | (GetBit(input[4],5)<<2) | (GetBit(input[3],0)<<1) | (GetBit(input[4],7)); ++ last_index = last_index | (GetBit(Sbox5[s_index], 7-bit)<<1); ++ ++ bit = (GetBit(input[5],4)<<2) | (GetBit(input[4],4)<<1) | (GetBit(input[1],2)); ++ s_index = (GetBit(input[2],3)<<3) | (GetBit(input[6],5)<<2) | (GetBit(input[1],4)<<1) | (GetBit(input[4],1)); ++ last_index = last_index | (GetBit(Sbox6[s_index], 7-bit)<<2); ++ ++ bit = (GetBit(input[0],6)<<2) | (GetBit(input[0],7)<<1) | (GetBit(input[0],4)); ++ s_index = (GetBit(input[0],5)<<3) | (GetBit(input[0],3)<<2) | (GetBit(input[0],1)<<1) | (GetBit(input[0],2)); ++ last_index = last_index | (GetBit(Sbox7[s_index], 7-bit)<<3); ++ ++ bit = (GetBit(input[4],2)<<2) | (GetBit(input[4],3)<<1) | (GetBit(input[1],1)); ++ s_index = (GetBit(input[1],6)<<3) | (GetBit(input[6],1)<<2) | (GetBit(input[5],6)<<1) | (GetBit(input[3],6)); ++ last_index = last_index | (GetBit(Sbox8[s_index], 7-bit)<<4); ++ ++ return (GetBit(Sbox9[last_index&0x1f],7-last_bit)&1) ? 1: 0; ++} ++ ++static void PowervuDecrypt(uint8_t *data, uint32_t length, uint8_t *key, uint8_t sbox) ++{ ++ uint32_t i; ++ int32_t j, k; ++ uint8_t curByte, tmpBit; ++ ++ for(i = 0; i < length; i++) ++ { ++ curByte = data[i]; ++ ++ for(j = 7; j >= 0; j--) ++ { ++ data[i] = SetBit(data[i], j, (GetBit(curByte, j)^PowervuSbox(key, sbox))^GetBit(key[0], 7)); ++ ++ tmpBit = GetBit(data[i], j)^(GetBit(key[6], 0)); ++ if (tmpBit) ++ { ++ key[3] ^= 0x10; ++ } ++ ++ for (k = 6; k > 0; k--) ++ { ++ key[k] = (key[k]>>1) | (key[k-1]<<7); ++ } ++ key[0] = (key[0]>>1); ++ ++ key[0] = SetBit(key[0], 7, tmpBit); ++ } ++ } ++} ++ ++#define PVU_CW_VID 0 // VIDeo ++#define PVU_CW_HSD 1 // High Speed Data ++#define PVU_CW_A1 2 // Audio 1 ++#define PVU_CW_A2 3 // Audio 2 ++#define PVU_CW_A3 4 // Audio 3 ++#define PVU_CW_A4 5 // Audio 4 ++#define PVU_CW_UTL 6 // UTiLity ++#define PVU_CW_VBI 7 // Vertical Blanking Interval ++ ++#define PVU_CONVCW_VID_ECM 0x80 // VIDeo ++#define PVU_CONVCW_HSD_ECM 0x40 // High Speed Data ++#define PVU_CONVCW_A1_ECM 0x20 // Audio 1 ++#define PVU_CONVCW_A2_ECM 0x10 // Audio 2 ++#define PVU_CONVCW_A3_ECM 0x08 // Audio 3 ++#define PVU_CONVCW_A4_ECM 0x04 // Audio 4 ++#define PVU_CONVCW_UTL_ECM 0x02 // UTiLity ++#define PVU_CONVCW_VBI_ECM 0x01 // Vertical Blanking Interval ++ ++static uint8_t PowervuGetConvcwIndex(uint8_t ecmTag) ++{ ++ switch(ecmTag) ++ { ++ case PVU_CONVCW_VID_ECM: ++ return PVU_CW_VID; ++ ++ case PVU_CONVCW_HSD_ECM: ++ return PVU_CW_HSD; ++ ++ case PVU_CONVCW_A1_ECM: ++ return PVU_CW_A1; ++ ++ case PVU_CONVCW_A2_ECM: ++ return PVU_CW_A2; ++ ++ case PVU_CONVCW_A3_ECM: ++ return PVU_CW_A3; ++ ++ case PVU_CONVCW_A4_ECM: ++ return PVU_CW_A4; ++ ++ case PVU_CONVCW_UTL_ECM: ++ return PVU_CW_UTL; ++ ++ case PVU_CONVCW_VBI_ECM: ++ return PVU_CW_VBI; ++ ++ default: ++ return PVU_CW_VBI; ++ } ++} ++ ++static uint16_t PowervuGetSeedIV(uint8_t seedType, uint8_t *ecm) ++{ ++ switch(seedType) ++ { ++ case PVU_CW_VID: ++ return ((ecm[0x10] & 0x1F) <<3) | 0; ++ case PVU_CW_HSD: ++ return ((ecm[0x12] & 0x1F) <<3) | 2; ++ case PVU_CW_A1: ++ return ((ecm[0x11] & 0x3F) <<3) | 1; ++ case PVU_CW_A2: ++ return ((ecm[0x13] & 0x3F) <<3) | 1; ++ case PVU_CW_A3: ++ return ((ecm[0x19] & 0x3F) <<3) | 1; ++ case PVU_CW_A4: ++ return ((ecm[0x1A] & 0x3F) <<3) | 1;; ++ case PVU_CW_UTL: ++ return ((ecm[0x14] & 0x0F) <<3) | 4; ++ case PVU_CW_VBI: ++ return (((ecm[0x15] & 0xF8)>>3)<<3) | 5; ++ default: ++ return 0; ++ } ++} ++ ++static uint8_t PowervuExpandSeed(uint8_t seedType, uint8_t *seed) ++{ ++ uint8_t seedLength = 0, i; ++ ++ switch(seedType) ++ { ++ case PVU_CW_VID: ++ case PVU_CW_HSD: ++ seedLength = 4; ++ break; ++ case PVU_CW_A1: ++ case PVU_CW_A2: ++ case PVU_CW_A3: ++ case PVU_CW_A4: ++ seedLength = 3; ++ break; ++ case PVU_CW_UTL: ++ case PVU_CW_VBI: ++ seedLength = 2; ++ break; ++ default: ++ return seedLength; ++ } ++ ++ for(i=seedLength; i<7; i++) ++ { ++ seed[i] = seed[i%seedLength]; ++ } ++ ++ return seedLength; ++} ++ ++static void PowervuCalculateSeed(uint8_t seedType, uint8_t *ecm, uint8_t *seedBase, uint8_t *key, uint8_t *seed, uint8_t sbox) ++{ ++ uint16_t tmpSeed; ++ ++ tmpSeed = PowervuGetSeedIV(seedType, ecm+23); ++ seed[0] = (tmpSeed >> 2) & 0xFF; ++ seed[1] = ((tmpSeed & 0x3) << 6) | (seedBase[0] >> 2); ++ seed[2] = ( seedBase[0] << 6) | (seedBase[1] >> 2); ++ seed[3] = ( seedBase[1] << 6) | (seedBase[2] >> 2); ++ seed[4] = ( seedBase[2] << 6) | (seedBase[3] >> 2); ++ seed[5] = ( seedBase[3] << 6); ++ ++ PowervuDecrypt(seed, 6, key, sbox); ++ ++ seed[0] = (seed[1] << 2) | (seed[2] >> 6); ++ seed[1] = (seed[2] << 2) | (seed[3] >> 6); ++ seed[2] = (seed[3] << 2) | (seed[4] >> 6); ++ seed[3] = (seed[4] << 2) | (seed[5] >> 6); ++} ++ ++static void PowervuCalculateCw(uint8_t seedType, uint8_t *seed, uint8_t csaUsed, uint8_t *convolvedCw, ++ uint8_t *cw, uint8_t *baseCw, uint8_t *seedEcmCw, uint8_t hashModeCw, ++ uint8_t needsUnmasking, uint8_t xorMode) ++{ ++ int32_t k; ++ uint8_t seedLength, val = 0; ++ ++ seedLength = PowervuExpandSeed(seedType, seed); ++ ++ if(csaUsed) ++ { ++ if(!needsUnmasking || (hashModeCw == 0)) ++ { ++ for(k = 0; k < 7; k++) ++ { ++ seed[k] ^= baseCw[k]; ++ } ++ ++ cw[0] = seed[0] ^ convolvedCw[0]; ++ cw[1] = seed[1] ^ convolvedCw[1]; ++ cw[2] = seed[2] ^ convolvedCw[2]; ++ cw[3] = seed[3] ^ convolvedCw[3]; ++ cw[4] = seed[3] ^ convolvedCw[4]; ++ cw[5] = seed[4] ^ convolvedCw[5]; ++ cw[6] = seed[5] ^ convolvedCw[6]; ++ cw[7] = seed[6] ^ convolvedCw[7]; ++ } ++ } ++ else ++ { ++ if(xorMode == 0) ++ { ++ for(k = 0; k < 7; k++) ++ { ++ cw[k] = seed[k] ^ baseCw[k]; ++ } ++ } ++ ++ if(xorMode == 1) ++ { ++ for(k = 0; k < 3; k++) ++ { ++ cw[k] = seed[k] ^ baseCw[k]; ++ } ++ ++ for(k = 3; k < 7; k++) ++ { ++ cw[k] = baseCw[k]; ++ } ++ } ++ ++ ExpandDesKey(cw); ++ } ++ ++ if(needsUnmasking && (hashModeCw > 0)) ++ { ++ switch(seedType) ++ { ++ case PVU_CW_VID: ++ val = 0; ++ break; ++ ++ case PVU_CW_A1: ++ case PVU_CW_A2: ++ case PVU_CW_A3: ++ case PVU_CW_A4: ++ val = 1; ++ break; ++ ++ case PVU_CW_HSD: ++ val = 2; ++ break; ++ ++ case PVU_CW_UTL: ++ val = 4; ++ break; ++ ++ case PVU_CW_VBI: ++ val = 5; ++ break; ++ } ++ PowervuCreateCw(seed, seedLength, baseCw, val, seedEcmCw, cw, csaUsed, hashModeCw); ++ } ++} ++ ++#ifdef WITH_EMU ++int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, uint16_t srvid, emu_stream_client_key_data *cdata, EXTENDED_CW* cw_ex) ++#else ++int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, emu_stream_client_key_data *cdata) ++#endif ++{ ++ int8_t ret = 1; ++ uint16_t ecmLen = GetEcmLen(ecm); ++ uint32_t ecmCrc32; ++ uint8_t nanoCmd, nanoChecksum, keyType, fixedKey, oddKey, bid, csaUsed; ++ uint16_t nanoLen; ++ uint32_t channelId, ecmSrvid, keyIndex; ++ uint32_t i, j, k; ++ uint8_t convolvedCw[8][8]; ++ uint8_t ecmKey[7], tmpEcmKey[7], seedBase[4], baseCw[7], seed[8][8], cw[8][8]; ++ uint8_t decrypt_ok; ++ uint8_t ecmPart1[14], ecmPart2[27]; ++ uint8_t sbox; ++ uint32_t keyRef1, keyRef2; ++ uint8_t calculateAllCws; ++ uint8_t seedEcmCw[0x10]; ++ uint8_t hashModeCw = 0, needsUnmasking, xorMode; ++#ifdef WITH_EMU ++ uint8_t *dwp; ++ emu_stream_cw_item *cw_item; ++ int8_t update_global_key = 0; ++ int8_t update_global_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++ ++ memset(update_global_keys, 0, sizeof(update_global_keys)); ++#endif ++ ++ if(ecmLen < 7) ++ { ++ return 1; ++ } ++ ++ needsUnmasking = (ecm[3] & 0xF0) == 0x50; ++ ++ if(needsUnmasking) ++ { ++ hashModeCw = PowervuUnmaskEcm(ecm, seedEcmCw); ++ } ++ ++ ecmCrc32 = b2i(4, ecm+ecmLen-4); ++ ++ if(fletcher_crc32(ecm, ecmLen-4) != ecmCrc32) ++ { ++ return 8; ++ } ++ ecmLen -= 4; ++ ++ for(i = 0; i < 8; i++) { ++ memset(convolvedCw[i], 0, 8); ++ } ++ ++ for(i = 3; i+3 < ecmLen; ) { ++ nanoLen = (((ecm[i] & 0x0f) << 8) | ecm[i+1]); ++ i += 2; ++ if(nanoLen > 0) ++ { ++ nanoLen--; ++ } ++ nanoCmd = ecm[i++]; ++ if(i+nanoLen > ecmLen) { ++ return 1; ++ } ++ ++ switch (nanoCmd) { ++ case 0x27: ++ if(nanoLen < 15) ++ { ++ break; ++ } ++ ++ nanoChecksum = 0; ++ for(j = 4; j < 15; j++) ++ { ++ nanoChecksum += ecm[i+j]; ++ } ++ ++ if(nanoChecksum != 0) ++ { ++ break; ++ } ++ ++ keyType = PowervuGetConvcwIndex(ecm[i+4]); ++ memcpy(convolvedCw[keyType], &ecm[i+6], 8); ++ break; ++ ++ default: ++ break; ++ } ++ i += nanoLen; ++ } ++ ++ for(i = 3; i+3 < ecmLen; ) { ++ nanoLen = (((ecm[i] & 0x0f) << 8) | ecm[i+1]); ++ i += 2; ++ if(nanoLen > 0) ++ { ++ nanoLen--; ++ } ++ nanoCmd = ecm[i++]; ++ if(i+nanoLen > ecmLen) { ++ return 1; ++ } ++ ++ switch (nanoCmd) { ++ case 0x20: ++ if(nanoLen < 54) ++ { ++ break; ++ } ++ ++ i += ecm[i + 3]; // Extra Data Length ++ ++ csaUsed = GetBit(ecm[i+7], 7); ++ fixedKey = !GetBit(ecm[i+6], 5); ++ oddKey = GetBit(ecm[i+6], 4); ++ xorMode = GetBit(ecm[i+6], 0); ++ bid = (GetBit(ecm[i+7], 1) << 1) | GetBit(ecm[i+7], 0); ++ sbox = GetBit(ecm[i+6], 3); ++ ++ keyIndex = (fixedKey << 3) | (bid << 2) | oddKey; ++ channelId = b2i(2, ecm+i+23); ++ ecmSrvid = (channelId >> 4) | ((channelId & 0xF) << 12); ++ ++ decrypt_ok = 0; ++ ++ memcpy(ecmPart1, ecm+i+8, 14); ++ memcpy(ecmPart2, ecm+i+27, 27); ++ ++ keyRef1 = 0; ++ keyRef2 = 0; ++ ++ do ++ { ++ if(!GetPowervuKey(ecmKey, ecmSrvid, '0', keyIndex, 7, 0, keyRef1++)) ++ { ++ if(!GetPowervuKey(ecmKey, channelId, '0', keyIndex, 7, 0, keyRef2++)) ++ { ++ cs_log("Key not found: P %04X 0%X", ecmSrvid, keyIndex); ++ return 2; ++ } ++ } ++ ++ PowervuDecrypt(ecm+i+8, 14, ecmKey, sbox); ++ if((ecm[i+6] != ecm[i+6+7]) || (ecm[i+6+8] != ecm[i+6+15])) ++ { ++ memcpy(ecm+i+8, ecmPart1, 14); ++ continue; ++ } ++ ++ memcpy(tmpEcmKey, ecmKey, 7); ++ ++ PowervuDecrypt(ecm+i+27, 27, ecmKey, sbox); ++ if((ecm[i+23] != ecm[i+23+29]) || (ecm[i+23+1] != ecm[i+23+30])) ++ { ++ memcpy(ecm+i+8, ecmPart1, 14); ++ memcpy(ecm+i+27, ecmPart2, 27); ++ continue; ++ } ++ ++ decrypt_ok = 1; ++ } ++ while(!decrypt_ok); ++ ++ memcpy(seedBase, ecm+i+6+2, 4); ++ ++#ifdef WITH_EMU ++ if(cdata == NULL) ++ { ++ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); ++ for(j = 0; j < EMU_STREAM_SERVER_MAX_CONNECTIONS; j++) ++ { ++ if(!stream_server_has_ecm[j] && emu_stream_cur_srvid[j] == srvid) ++ { ++ update_global_key = 1; ++ update_global_keys[j] = 1; ++ } ++ } ++ SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); ++ } ++ ++ if(cdata != NULL || update_global_key || cw_ex != NULL) ++#else ++ if(cdata != NULL) ++#endif ++ { ++ // Calculate all seeds ++ for(j = 0; j < 8; j++) ++ { ++ memcpy(ecmKey, tmpEcmKey, 7); ++ PowervuCalculateSeed(j, ecm+i, seedBase, ecmKey, seed[j], sbox); ++ } ++ } ++ else ++ { ++ // Calculate only video seed ++ memcpy(ecmKey, tmpEcmKey, 7); ++ PowervuCalculateSeed(PVU_CW_VID, ecm+i, seedBase, ecmKey, seed[PVU_CW_VID], sbox); ++ } ++ ++ memcpy(baseCw, ecm+i+6+8, 7); ++ ++#ifdef WITH_EMU ++ calculateAllCws = cdata != NULL || update_global_key || cw_ex != NULL; ++#else ++ calculateAllCws = cdata != NULL; ++#endif ++ if(calculateAllCws) ++ { ++ // Calculate all cws ++ for(j = 0; j < 8; j++) ++ { ++ PowervuCalculateCw(j, seed[j], csaUsed, convolvedCw[j], cw[j], baseCw, ++ seedEcmCw, hashModeCw, needsUnmasking, xorMode); ++ ++ if(csaUsed) ++ { ++ for(k = 0; k < 8; k += 4) { ++ cw[j][k + 3] = ((cw[j][k] + cw[j][k + 1] + cw[j][k + 2]) & 0xff); ++ } ++ } ++ } ++ ++#ifdef WITH_EMU ++ if(update_global_key) ++ { ++ for(j = 0; j < EMU_STREAM_SERVER_MAX_CONNECTIONS; j++) ++ { ++ if(update_global_keys[j]) ++ { ++ cw_item = (emu_stream_cw_item*)malloc(sizeof(emu_stream_cw_item)); ++ if(cw_item != NULL) ++ { ++ cw_item->csa_used = csaUsed; ++ cw_item->is_even = ecm[0] == 0x80 ? 1 : 0; ++ cs_ftime(&cw_item->write_time); ++ add_ms_to_timeb(&cw_item->write_time, cfg.emu_stream_ecm_delay); ++ memcpy(cw_item->cw, cw, sizeof(cw)); ++ ll_append(ll_emu_stream_delayed_keys[j], cw_item); ++ } ++ } ++ } ++ } ++ ++ if(cdata != NULL) ++ { ++#endif ++ for(j = 0; j < 8; j++) ++ { ++ if(csaUsed) ++ { ++ if(cdata->pvu_csa_ks[j] == NULL) ++ { cdata->pvu_csa_ks[j] = get_key_struct(); } ++ ++ if(ecm[0] == 0x80) ++ { set_even_control_word(cdata->pvu_csa_ks[j], cw[j]); } ++ else ++ { set_odd_control_word(cdata->pvu_csa_ks[j], cw[j]); } ++ ++ cdata->pvu_csa_used = 1; ++ } ++ else ++ { ++ if(ecm[0] == 0x80) ++ { des_set_key(cw[j], cdata->pvu_des_ks[j][0]); } ++ else ++ { des_set_key(cw[j], cdata->pvu_des_ks[j][1]); } ++ ++ cdata->pvu_csa_used = 0; ++ } ++ } ++#ifdef WITH_EMU ++ } ++ ++ if(cw_ex != NULL) ++ { ++ cw_ex->mode = CW_MODE_MULTIPLE_CW; ++ ++ if(csaUsed) ++ { ++ cw_ex->algo = CW_ALGO_CSA; ++ cw_ex->algo_mode = CW_ALGO_MODE_ECB; ++ } ++ else ++ { ++ cw_ex->algo = CW_ALGO_DES; ++ cw_ex->algo_mode = CW_ALGO_MODE_ECB; ++ } ++ ++ for(j = 0; j < 4; j++) ++ { ++ dwp = cw_ex->audio[j]; ++ ++ memset(dwp, 0, 16); ++ ++ if(ecm[0] == 0x80) ++ { ++ memcpy(dwp, cw[PVU_CW_A1+j], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 0; k < 8; k += 4) ++ { ++ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); ++ } ++ } ++ } ++ else ++ { ++ memcpy(&dwp[8], cw[PVU_CW_A1+j], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 8; k < 16; k += 4) ++ { ++ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); ++ } ++ } ++ } ++ } ++ ++ dwp = cw_ex->data; ++ ++ memset(dwp, 0, 16); ++ ++ if(ecm[0] == 0x80) ++ { ++ memcpy(dwp, cw[PVU_CW_HSD], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 0; k < 8; k += 4) ++ { ++ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); ++ } ++ } ++ } ++ else ++ { ++ memcpy(&dwp[8], cw[PVU_CW_HSD], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 8; k < 16; k += 4) ++ { ++ dwp[k + 3] = ((dwp[k] + dwp[k + 1] + dwp[k + 2]) & 0xff); ++ } ++ } ++ } ++ } ++#endif ++ } ++ else ++ { ++ // Calculate only video cw ++ PowervuCalculateCw(PVU_CW_VID, seed[PVU_CW_VID], csaUsed, convolvedCw[PVU_CW_VID], cw[PVU_CW_VID], baseCw, ++ seedEcmCw, hashModeCw, needsUnmasking, xorMode); ++ } ++ ++ memset(dw, 0, 16); ++ ++ if(ecm[0] == 0x80) ++ { ++ memcpy(dw, cw[PVU_CW_VID], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 0; k < 8; k += 4) ++ { ++ dw[k + 3] = ((dw[k] + dw[k + 1] + dw[k + 2]) & 0xff); ++ } ++ } ++ } ++ else ++ { ++ memcpy(&dw[8], cw[PVU_CW_VID], 8); ++ ++ if(csaUsed) ++ { ++ for(k = 8; k < 16; k += 4) ++ { ++ dw[k + 3] = ((dw[k] + dw[k + 1] + dw[k + 2]) & 0xff); ++ } ++ } ++ } ++ ++ return 0; ++ ++ default: ++ break; ++ } ++ i += nanoLen; ++ } ++ ++ return ret; ++} ++ ++ ++// Drecrypt EMU ++static void DREover(const uint8_t *ECMdata, uint8_t *dw) ++{ ++ uint8_t key[8]; ++ uint32_t key_schedule[32]; ++ ++ if (ECMdata[2] >= (43 + 4) && ECMdata[40] == 0x3A && ECMdata[41] == 0x4B) ++ { ++ if (!FindKey('D', ECMdata[42] & 0x0F, 0, "OVER", key, 8, 1, 0, 0, NULL)) ++ { ++ return; ++ } ++ ++ des_set_key(key, key_schedule); ++ ++ des(dw, key_schedule, 0); // even dw post-process ++ des(dw + 8, key_schedule, 0); // odd dw post-process ++ } ++} ++ ++static uint32_t DreGostDec(uint32_t inData) ++{ ++ static uint8_t Sbox[128] = ++ { ++ 0x0E,0x04,0x0D,0x01,0x02,0x0F,0x0B,0x08,0x03,0x0A,0x06,0x0C,0x05,0x09,0x00,0x07, ++ 0x0F,0x01,0x08,0x0E,0x06,0x0B,0x03,0x04,0x09,0x07,0x02,0x0D,0x0C,0x00,0x05,0x0A, ++ 0x0A,0x00,0x09,0x0E,0x06,0x03,0x0F,0x05,0x01,0x0D,0x0C,0x07,0x0B,0x04,0x02,0x08, ++ 0x07,0x0D,0x0E,0x03,0x00,0x06,0x09,0x0A,0x01,0x02,0x08,0x05,0x0B,0x0C,0x04,0x0F, ++ 0x02,0x0C,0x04,0x01,0x07,0x0A,0x0B,0x06,0x08,0x05,0x03,0x0F,0x0D,0x00,0x0E,0x09, ++ 0x0C,0x01,0x0A,0x0F,0x09,0x02,0x06,0x08,0x00,0x0D,0x03,0x04,0x0E,0x07,0x05,0x0B, ++ 0x04,0x0B,0x02,0x0E,0x0F,0x00,0x08,0x0D,0x03,0x0C,0x09,0x07,0x05,0x0A,0x06,0x01, ++ 0x0D,0x02,0x08,0x04,0x06,0x0F,0x0B,0x01,0x0A,0x09,0x03,0x0E,0x05,0x00,0x0C,0x07 ++ }; ++ uint8_t i, j; ++ ++ for(i = 0; i < 8; i++) ++ { ++ j = (inData >> 28) & 0x0F; ++ inData = (inData << 4) | (Sbox[i * 16 + j] & 0x0F); ++ } ++ ++ inData = (inData << 11) | (inData >> 21); ++ ++ return (inData); ++} ++ ++static void DrecryptDecrypt(uint8_t *Data, uint8_t *Key) // DRE GOST 28147-89 CORE ++{ ++ int i, j; ++ uint32_t L_part = 0, R_part = 0, temp = 0; ++ ++ for(i = 0; i < 4; i++) L_part = (L_part << 8) | (Data[i] & 0xFF), R_part = (R_part << 8) | (Data[i + 4] & 0xFF); ++ ++ for(i = 0; i < 4; i++) ++ { ++ temp = ((Key[i*8+0] & 0xFF) << 24) | ((Key[i*8+1] & 0xFF) << 16) | ((Key[i*8+2] & 0xFF) << 8) | (Key[i*8+3] & 0xFF); ++ R_part ^= DreGostDec(temp + L_part); ++ temp = ((Key[i*8+4] & 0xFF) << 24) | ((Key[i*8+5] & 0xFF) << 16) | ((Key[i*8+6] & 0xFF) << 8) | (Key[i*8+7] & 0xFF); ++ L_part ^= DreGostDec(temp + R_part); ++ } ++ ++ for(j = 0; j < 3; j++) ++ { ++ for(i = 3; i >= 0; i--) ++ { ++ temp = ((Key[i*8+4] & 0xFF) << 24) | ((Key[i*8+5] & 0xFF) << 16) | ((Key[i*8+6] & 0xFF) << 8) | (Key[i*8+7] & 0xFF); ++ R_part ^= DreGostDec(temp + L_part); ++ temp = ((Key[i*8+0] & 0xFF) << 24) | ((Key[i*8+1] & 0xFF) << 16) | ((Key[i*8+2] & 0xFF) << 8) | (Key[i*8+3] & 0xFF); ++ L_part ^= DreGostDec(temp + R_part); ++ } ++ } ++ ++ for(i = 0; i < 4; i++) Data[i] = (R_part >> i*8) & 0xFF, Data[i+4] = (L_part >> i*8) & 0xFF; ++} ++ ++static void DrecryptPostCw(uint8_t* ccw) ++{ ++ uint32_t i, j; ++ uint8_t tmp[4]; ++ ++ for(i = 0; i < 4; i++) ++ { ++ for(j = 0; j < 4; j++) ++ { ++ tmp[j] = ccw[3 - j]; ++ } ++ ++ for(j = 0; j < 4; j++) ++ { ++ ccw[j] = tmp[j]; ++ } ++ ++ ccw += 4; ++ } ++} ++ ++static void DrecryptSwap(uint8_t* ccw) ++{ ++ uint32_t tmp1, tmp2; ++ ++ memcpy(&tmp1, ccw, 4); ++ memcpy(&tmp2, ccw + 4, 4); ++ ++ memcpy(ccw, ccw + 8, 8); ++ ++ memcpy(ccw + 8 , &tmp1, 4); ++ memcpy(ccw + 8 + 4, &tmp2, 4); ++} ++ ++static int8_t Drecrypt2ECM(uint32_t provId, uint8_t *ecm, uint8_t *dw) ++{ ++ uint8_t ecmDataLen, ccw[16], key[32]; ++ uint16_t ecmLen, overcryptId; ++ char keyName[EMU_MAX_CHAR_KEYNAME]; ++ ++ ecmLen = GetEcmLen(ecm); ++ ++ if (ecmLen < 3) ++ { ++ return 1; // Not supported ++ } ++ ++ ecmDataLen = ecm[2]; ++ ++ if (ecmLen < ecmDataLen + 3) ++ { ++ return 4; // Corrupt data ++ } ++ ++ switch (provId & 0xFF) ++ { ++ case 0x11: ++ { ++ if (ecm[3] == 0x56) ++ { ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[5]); ++ ++ if (!FindKey('D', 0x4AE111, 0, keyName, key, 32, 1, 0, 0, NULL)) ++ { ++ return 2; ++ } ++ } ++ else ++ { ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[3]); ++ ++ if (!FindKey('D', 0x4AE111, 0, keyName, key, 32, 1, 0, 0, NULL)) ++ { ++ return 2; ++ } ++ } ++ ++ break; ++ } ++ ++ case 0x14: ++ { ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%02X%02X", ecm[6], ecm[5]); ++ ++ if (!FindKey('D', 0x4AE114, 0, keyName, key, 32, 1, 0, 0, NULL)) ++ { ++ return 2; ++ } ++ ++ break; ++ } ++ ++ default: ++ return 1; ++ } ++ ++ memcpy(ccw, ecm + 13, 16); ++ ++ DrecryptPostCw(key); ++ DrecryptPostCw(key + 16); ++ ++ DrecryptDecrypt(ccw, key); ++ DrecryptDecrypt(ccw + 8, key); ++ ++ if (ecm[2] >= 46 && ecm[43] == 1 && provId == 0x11) ++ { ++ DrecryptSwap(ccw); ++ overcryptId = b2i(2, &ecm[44]); ++ ++ Drecrypt2OverCW(overcryptId, ccw); ++ ++ if (isValidDCW(ccw)) ++ { ++ memcpy(dw, ccw, 16); ++ return 0; ++ } ++ ++ return 9; // ICG error ++ } ++ ++ DREover(ecm, ccw); ++ ++ if (isValidDCW(ccw)) ++ { ++ DrecryptSwap(ccw); ++ memcpy(dw, ccw, 16); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++// Tandberg EMU ++static uint16_t TandbergChecksum(uint8_t *data, uint8_t length) ++{ ++ // ECM and EMM checksum calculation ++ // 1. Combine data in 2 byte groups ++ // 2. Add them together ++ // 3. Multiply result by itself (power of 7) ++ // 4. XOR with fixed value 0x17E3 ++ ++ uint8_t i; ++ uint16_t checksum = 0; ++ ++ for(i = 0; i < length; i += 2) ++ { ++ checksum += (data[i] << 8) | data[i + 1]; ++ } ++ ++ checksum = checksum * checksum * checksum * checksum * checksum * checksum * checksum; ++ checksum ^= 0x17E3; ++ ++ return checksum; ++} ++ ++static int8_t GetTandbergKey(uint32_t keyIndex, char *keyName, uint8_t *key, uint32_t keyLength) ++{ ++ // keyIndex: ecm keys --> entitlementId ++ // emm keys --> aeskeyIndex ++ // aes keys --> keyIndex ++ ++ // keyName: ecm keys --> "01" ++ // emm keys --> "MK" or "MK01" ++ // aes keys --> "AES" ++ ++ return FindKey('T', keyIndex, 0, keyName, key, keyLength, 1, 0, 0, NULL); ++} ++ ++static int8_t TandbergECM(uint8_t *ecm, uint8_t *dw) ++{ ++ uint8_t nanoType, nanoLength; ++ uint8_t* nanoData; ++ uint32_t pos = 3; ++ uint32_t entitlementId; ++ uint32_t ks[32]; ++ uint8_t ecmKey[8]; ++ uint16_t ecmLen = GetEcmLen(ecm); ++ ++ if(ecmLen < 5) ++ { ++ return 1; ++ } ++ ++ do ++ { ++ nanoType = ecm[pos]; ++ nanoLength = ecm[pos+1]; ++ ++ if(pos + 2 + nanoLength > ecmLen) ++ { ++ break; ++ } ++ ++ nanoData = ecm + pos + 2; ++ ++ // ECM validation ++ uint16_t payloadChecksum = (nanoData[nanoLength - 2] << 8) | nanoData[nanoLength - 1]; ++ uint16_t calculatedChecksum = TandbergChecksum(nanoData, nanoLength - 2); ++ ++ if(calculatedChecksum != payloadChecksum) ++ { ++ cs_log("ECM checksum error (%.4X instead of %.4X)", calculatedChecksum, payloadChecksum); ++ return 8; ++ } ++ // End of ECM validation ++ ++ switch(nanoType) ++ { ++ case 0xEC: // Director v6 (September 2017) ++ { ++ if(nanoLength != 0x28) ++ { ++ cs_log("WARNING: nanoType EC length (%d) != %d", nanoLength, 0x28); ++ break; ++ } ++ ++ entitlementId = b2i(4, nanoData); ++ ++ if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) ++ { ++ return 2; ++ } ++ ++ cs_log("Active entitlement %.4X", entitlementId); ++ ++ // Step 1 - Decrypt DES CBC with ecmKey and iv = { 0 } (equal to nanoED) ++ uint8_t encryptedData[32] = { 0 }; ++ memcpy(encryptedData, nanoData + 6, 32); ++ ++ uint8_t iv[8] = { 0 }; ++ des_cbc_decrypt(encryptedData, iv, ecmKey, 32); ++ ++ uint8_t nanoMode = nanoData[5]; ++ ++ if ((nanoMode & 0x20) == 0) // Old algo ++ { ++ // Step 2 - Create CW (equal to nano ED) ++ dw[0] = encryptedData[0x05]; ++ dw[1] = encryptedData[0x19]; ++ dw[2] = encryptedData[0x1D]; ++ ++ dw[4] = encryptedData[0x0B]; ++ dw[5] = encryptedData[0x12]; ++ dw[6] = encryptedData[0x1A]; ++ ++ dw[8] = encryptedData[0x16]; ++ dw[9] = encryptedData[0x03]; ++ dw[10] = encryptedData[0x11]; ++ ++ dw[12] = encryptedData[0x18]; ++ dw[13] = encryptedData[0x10]; ++ dw[14] = encryptedData[0x0E]; ++ ++ return 0; ++ } ++ else // New algo (overencryption with AES) ++ { ++ // Step 2 - Prepare data for AES (it is like the creation of CW in nanoED but swapped each 8 bytes) ++ uint8_t dataEC[16] = { 0 }; ++ ++ dataEC[0] = encryptedData[0x02]; ++ dataEC[1] = encryptedData[0x0E]; ++ dataEC[2] = encryptedData[0x10]; ++ dataEC[3] = encryptedData[0x18]; ++ dataEC[4] = encryptedData[0x09]; ++ dataEC[5] = encryptedData[0x11]; ++ dataEC[6] = encryptedData[0x03]; ++ dataEC[7] = encryptedData[0x16]; ++ ++ dataEC[8] = encryptedData[0x13]; ++ dataEC[9] = encryptedData[0x1A]; ++ dataEC[10] = encryptedData[0x12]; ++ dataEC[11] = encryptedData[0x0B]; ++ dataEC[12] = encryptedData[0x04]; ++ dataEC[13] = encryptedData[0x1D]; ++ dataEC[14] = encryptedData[0x19]; ++ dataEC[15] = encryptedData[0x05]; ++ ++ // Step 3 - Decrypt AES CBC with new aesKey and iv 2EBD816A5E749A708AE45ADDD84333DE ++ uint8_t aesKeyIndex = nanoMode & 0x1F; // 32 possible AES keys ++ uint8_t aesKey[16] = { 0 }; ++ ++ if(!GetTandbergKey(aesKeyIndex, "AES", aesKey, 16)) ++ { ++ return 2; ++ } ++ ++ struct aes_keys aes; ++ aes_set_key(&aes, (char *)aesKey); ++ ++ uint8_t ivAes[16] = { 0x2E, 0xBD, 0x81, 0x6A, 0x5E, 0x74, 0x9A, 0x70, 0x8A, 0xE4, 0x5A, 0xDD, 0xD8, 0x43, 0x33, 0xDE }; ++ aes_cbc_decrypt(&aes, dataEC, 16, ivAes); ++ ++ // Step 4 - Create CW (a simple swap) ++ uint8_t offset; ++ for (offset = 0; offset < 16; offset++) ++ { ++ dw[offset] = dataEC[15 - offset]; ++ } ++ ++ return 0; ++ } ++ } ++ ++ case 0xED: // ECM_TAG_CW_DESCRIPTOR ++ { ++ if(nanoLength != 0x26) ++ { ++ cs_log("WARNING: nanoType ED length (%d) != %d", nanoLength, 0x26); ++ break; ++ } ++ ++ entitlementId = b2i(4, nanoData); ++ ++ if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) ++ { ++ return 2; ++ } ++ ++ cs_log("Active entitlement %.4X", entitlementId); ++ ++ uint8_t encryptedData[32] = { 0 }; ++ memcpy(encryptedData, nanoData + 4, 32); ++ ++ uint8_t iv[8] = { 0 }; ++ des_cbc_decrypt(encryptedData, iv, ecmKey, 32); ++ ++ dw[0] = encryptedData[0x05]; ++ dw[1] = encryptedData[0x19]; ++ dw[2] = encryptedData[0x1D]; ++ dw[4] = encryptedData[0x0B]; ++ dw[5] = encryptedData[0x12]; ++ dw[6] = encryptedData[0x1A]; ++ dw[8] = encryptedData[0x16]; ++ dw[9] = encryptedData[0x03]; ++ dw[10] = encryptedData[0x11]; ++ dw[12] = encryptedData[0x18]; ++ dw[13] = encryptedData[0x10]; ++ dw[14] = encryptedData[0x0E]; ++ ++ return 0; ++ } ++ ++ case 0xEE: // ECM_TAG_CW_DESCRIPTOR ++ { ++ if(nanoLength != 0x16) ++ { ++ cs_log("WARNING: nanoType EE length (%d) != %d", nanoLength, 0x16); ++ break; ++ } ++ ++ entitlementId = b2i(4, nanoData); ++ ++ if(!GetTandbergKey(entitlementId, "01", ecmKey, 8)) ++ { ++ return 2; ++ } ++ ++ cs_log("Active entitlement %.4X", entitlementId); ++ ++ memcpy(dw, nanoData + 4 + 8, 8); // even ++ memcpy(dw + 8, nanoData + 4, 8); // odd ++ ++ des_set_key(ecmKey, ks); ++ ++ des(dw, ks, 0); ++ des(dw + 8, ks, 0); ++ ++ return 0; ++ } ++ ++ default: ++ cs_log("WARNING: nanoType %.2X not supported", nanoType); ++ break; ++ } ++ ++ pos += 2 + nanoLength; ++ ++ } while (pos < ecmLen); ++ ++ return 1; ++} ++ ++const char* GetProcessECMErrorReason(int8_t result) ++{ ++ switch(result) { ++ case 0: ++ return "No error"; ++ case 1: ++ return "ECM not supported"; ++ case 2: ++ return "Key not found"; ++ case 3: ++ return "Nano80 problem"; ++ case 4: ++ return "Corrupt data"; ++ case 5: ++ return "CW not found"; ++ case 6: ++ return "CW checksum error"; ++ case 7: ++ return "Out of memory"; ++ case 8: ++ return "ECM checksum error"; ++ case 9: ++ return "ICG error"; ++ default: ++ return "Unknown"; ++ } ++} ++ ++/* Error codes ++0 OK ++1 ECM not supported ++2 Key not found ++3 Nano80 problem ++4 Corrupt data ++5 CW not found ++6 CW checksum error ++7 Out of memory ++8 ECM checksum error ++9 ICG error ++*/ ++#ifdef WITH_EMU ++int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, const uint8_t *ecm, ++ uint8_t *dw, uint16_t srvid, uint16_t ecmpid, EXTENDED_CW* cw_ex) ++#else ++int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, const uint8_t *ecm, ++ uint8_t *dw, uint16_t srvid, uint16_t ecmpid) ++#endif ++{ ++ int8_t result = 1, i; ++ uint8_t ecmCopy[EMU_MAX_ECM_LEN]; ++ uint16_t ecmLen = 0; ++ ++ if(ecmDataLen < 3) { ++ // accept requests without ecm only for biss ++ if((caid>>8) != 0x26 && caid != 0xFFFF) { ++ return 1; ++ } ++ } ++ else { ++ ecmLen = GetEcmLen(ecm); ++ } ++ ++ if(ecmLen > ecmDataLen) { ++ return 1; ++ } ++ ++ if(ecmLen > EMU_MAX_ECM_LEN) { ++ return 1; ++ } ++ memcpy(ecmCopy, ecm, ecmLen); ++ ++ if((caid >> 8) == 0x0D) { ++ result = CryptoworksECM(caid, ecmCopy, dw); ++ } ++ else if((caid >> 8) == 0x09) { ++ result = SoftNDSECM(caid, ecmCopy, dw); ++ } ++ else if(caid == 0x0500) { ++ result = ViaccessECM(ecmCopy, dw); ++ } ++ else if((caid >> 8) == 0x18) { ++ result = Nagra2ECM(ecmCopy, dw); ++ } ++ else if((caid >> 8) == 0x06) { ++ result = Irdeto2ECM(caid, ecmCopy, dw); ++ } ++ else if((caid >> 8) == 0x26 || caid == 0xFFFF) { ++ result = BissECM(rdr, ecm, ecmDataLen, dw, srvid, ecmpid); ++ } ++ else if((caid >> 8) == 0x0E) { ++#ifdef WITH_EMU ++ result = PowervuECM(ecmCopy, dw, srvid, NULL, cw_ex); ++#else ++ result = PowervuECM(ecmCopy, dw, NULL); ++#endif ++ } ++ else if(caid == 0x4AE1) { ++ result = Drecrypt2ECM(provider, ecmCopy, dw); ++ } ++ else if((caid >> 8) == 0x10) { ++ result = TandbergECM(ecmCopy, dw); ++ } ++ ++ // fix dcw checksum ++ if(result == 0 && !((caid >> 8) == 0x0E)) { ++ for(i = 0; i < 16; i += 4) { ++ dw[i + 3] = ((dw[i] + dw[i + 1] + dw[i + 2]) & 0xff); ++ } ++ } ++ ++ if(result != 0) { ++ cs_log("ECM failed: %s", GetProcessECMErrorReason(result)); ++ } ++ ++ return result; ++} ++ ++// Viaccess EMM EMU ++static int8_t ViaccessEMM(uint8_t *emm, uint32_t *keysAdded) ++{ ++ uint8_t nanoCmd = 0, subNanoCmd = 0, *tmp; ++ uint16_t i = 0, j = 0, k = 0, emmLen = GetEcmLen(emm); ++ uint8_t ecmKeys[6][16], keyD0[2], emmKey[16], emmXorKey[16], provName[17]; ++ uint8_t ecmKeyCount = 0, emmKeyIndex = 0, aesMode = 0x0D; ++ uint8_t nanoLen = 0, subNanoLen = 0, haveEmmXorKey = 0, haveNewD0 = 0; ++ uint32_t ui1, ui2, ui3, ecmKeyIndex[6], provider = 0, ecmProvider = 0; ++ char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; ++ struct aes_keys aes; ++ ++ memset(keyD0, 0, 2); ++ memset(ecmKeyIndex, 0, sizeof(uint32_t)*6); ++ ++ for(i=3; i+2 emmLen) { ++ return 1; ++ } ++ ++ switch(nanoCmd) { ++ case 0x90: { ++ if(nanoLen < 3) { ++ break; ++ } ++ ui1 = emm[i+2]; ++ ui2 = emm[i+1]; ++ ui3 = emm[i]; ++ provider = (ui1 | (ui2 << 8) | (ui3 << 16)); ++ if(provider == 0x00D00040) { ++ ecmProvider = 0x030B00; ++ } ++ else { ++ return 1; ++ } ++ break; ++ } ++ case 0xD2: { ++ if(nanoLen < 2) { ++ break; ++ } ++ emmKeyIndex = emm[i+1]; ++ break; ++ } ++ case 0x41: { ++ if(nanoLen < 1) { ++ break; ++ } ++ if(!GetViaKey(emmKey, provider, 'M', emmKeyIndex, 16, 1)) { ++ return 2; ++ } ++ memset(provName, 0, 17); ++ memset(emmXorKey, 0, 16); ++ k = nanoLen < 16 ? nanoLen : 16; ++ memcpy(provName, &emm[i], k); ++ aes_set_key(&aes, (char*)emmKey); ++ aes_decrypt(&aes, emmXorKey, 16); ++ for(j=0; j<16; j++) { ++ provName[j] ^= emmXorKey[j]; ++ } ++ provName[k] = 0; ++ ++ if(strcmp((char*)provName, "TNTSAT") != 0 && strcmp((char*)provName, "TNTSATPRO") != 0 ++ &&strcmp((char*)provName, "CSAT V") != 0) { ++ return 1; ++ } ++ break; ++ } ++ case 0xBA: { ++ if(nanoLen < 2) { ++ break; ++ } ++ GetViaKey(keyD0, ecmProvider, 'D', 0, 2, 0); ++ ui1 = (emm[i] << 8) | emm[i+1]; ++ if( (uint32_t)((keyD0[0] << 8) | keyD0[1]) < ui1 || (keyD0[0] == 0x00 && keyD0[1] == 0x00)) { ++ keyD0[0] = emm[i]; ++ keyD0[1] = emm[i+1]; ++ haveNewD0 = 1; ++ break; ++ } ++ return 0; ++ } ++ case 0xBC: { ++ break; ++ } ++ case 0x43: { ++ if(nanoLen < 16) { ++ break; ++ } ++ memcpy(emmXorKey, &emm[i], 16); ++ haveEmmXorKey = 1; ++ break; ++ } ++ case 0x44: { ++ if(nanoLen < 3) { ++ break; ++ } ++ if (!haveEmmXorKey) { ++ memset(emmXorKey, 0, 16); ++ } ++ tmp = (uint8_t*)malloc(((nanoLen/16)+1)*16*sizeof(uint8_t)); ++ if(tmp == NULL) { ++ return 7; ++ } ++ memcpy(tmp, &emm[i], nanoLen); ++ aes_set_key(&aes, (char*)emmKey); ++ for(j=0; j 5) { ++ break; ++ } ++ for(j=i; j+2 i+nanoLen) { ++ break; ++ } ++ switch(subNanoCmd) { ++ case 0xD2: { ++ if(nanoLen < 2) { ++ break; ++ } ++ aesMode = emm[j]; ++ emmKeyIndex = emm[j+1]; ++ break; ++ } ++ case 0x01: { ++ if(nanoLen < 17) { ++ break; ++ } ++ ecmKeyIndex[ecmKeyCount] = emm[j]; ++ memcpy(&ecmKeys[ecmKeyCount], &emm[j+1], 16); ++ if(!GetViaKey(emmKey, provider, 'M', emmKeyIndex, 16, 1)) { ++ break; ++ } ++ ++ if(aesMode == 0x0F || aesMode == 0x11) { ++ hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]); ++ hdSurEncPhase2_D2_0F_11(ecmKeys[ecmKeyCount]); ++ } ++ else if(aesMode == 0x13 || aesMode == 0x15) { ++ hdSurEncPhase1_D2_13_15(ecmKeys[ecmKeyCount]); ++ } ++ aes_set_key(&aes, (char*)emmKey); ++ aes_decrypt(&aes, ecmKeys[ecmKeyCount], 16); ++ if(aesMode == 0x0F || aesMode == 0x11) { ++ hdSurEncPhase1_D2_0F_11(ecmKeys[ecmKeyCount]); ++ } ++ else if(aesMode == 0x13 || aesMode == 0x15) { ++ hdSurEncPhase2_D2_13_15(ecmKeys[ecmKeyCount]); ++ } ++ ++ ecmKeyCount++; ++ break; ++ } ++ default: ++ break; ++ } ++ j += subNanoLen; ++ } ++ break; ++ } ++ case 0xF0: { ++ if(nanoLen != 4) { ++ break; ++ } ++ ui1 = ((emm[i+2] << 8) | (emm[i+1] << 16) | (emm[i] << 24) | emm[i+3]); ++ if(fletcher_crc32(emm + 3, emmLen - 11) != ui1) { ++ return 4; ++ } ++ ++ if(haveNewD0) { ++ ++ SetKey('V', ecmProvider, "D0", keyD0, 2, 1, NULL, NULL); ++ ++ for(j=0; j>2); ++ SetKey('I', ident, keyName, &emm[i+3], 16, 1, NULL, NULL); ++ ++ (*keysAdded)++; ++ cs_hexdump(0, &emm[i+3], 16, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: I %06X %s %s", ident, keyName, keyValue); ++ } ++ } ++ i+=l; ++ } ++ ++ if(*keysAdded > 0) { ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++static int8_t Irdeto2DoEMMTypePMK(uint32_t ident, uint8_t *emm, uint8_t *keySeed, uint8_t *keyIV, uint8_t *keyPMK, ++ uint16_t emmLen, uint8_t startOffset, uint8_t length, uint32_t *keysAdded) ++{ ++ uint32_t end, i, l, j; ++ char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[36]; ++ ++ Irdeto2Decrypt(&emm[startOffset], keyIV, keySeed, length); ++ ++ i = 13; ++ end = startOffset + (length-8 < 0 ? 0 : length-8); ++ ++ while(i 0) { ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ ++static const uint8_t fausto_xor[16] = { 0x22, 0x58, 0xBD, 0x85, 0x2E, 0x8E, 0x52, 0x80, 0xA3, 0x79, 0x98, 0x69, 0x68, 0xE2, 0xD8, 0x4D }; ++ ++static int8_t Irdeto2EMM(uint16_t caid, uint8_t *oemm, uint32_t *keysAdded) ++{ ++ uint8_t length, okeySeed[16], keySeed[16], keyIV[16], keyPMK[16], startOffset, emmType; ++ uint32_t ident; ++ uint32_t keySeedRef, keyIVRef, keyPMK0Ref, keyPMK1Ref, keyPMK0ERef, keyPMK1ERef; ++ uint8_t emmCopy[EMU_MAX_EMM_LEN], *emm = oemm; ++ uint16_t emmLen = GetEcmLen(emm); ++ ++ if(emmLen < 11) { ++ return 1; ++ } ++ ++ if(emm[3] == 0xC3 || emm[3] == 0xCB) { ++ emmType = 2; ++ startOffset = 11; ++ } ++ else { ++ emmType = 1; ++ startOffset = 10; ++ } ++ ++ ident = emm[startOffset-2] | caid << 8; ++ length = emm[startOffset-1]; ++ ++ ++ if(emmLen < length+startOffset) { ++ return 1; ++ } ++ ++ keySeedRef = 0; ++ while(GetIrdetoKey(okeySeed, ident, 'M', emmType == 1 ? 0 : 0xA, 1, &keySeedRef)) { ++ keyIVRef = 0; ++ while(GetIrdetoKey(keyIV, ident, 'M', 2, 1, &keyIVRef)) { ++ ++ keyPMK0Ref = 0; ++ keyPMK1Ref = 0; ++ keyPMK0ERef = 0; ++ keyPMK1ERef = 0; ++ ++ while(GetIrdetoKey(keyPMK, ident, 'M', emmType == 1 ? 3 : 0xB, 1, &keyPMK0Ref)) { ++ memcpy(keySeed, okeySeed, 16); ++ memcpy(emmCopy, oemm, emmLen); ++ emm = emmCopy; ++ if(emmType == 1) { ++ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { ++ return 0; ++ } ++ } ++ else { ++ if(Irdeto2DoEMMTypePMK(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { ++ return 0; ++ } ++ } ++ } ++ ++ if(emmType == 1) { ++ while(GetIrdetoKey(keyPMK, ident, 'M', 4, 1, &keyPMK1Ref)) { ++ memcpy(keySeed, okeySeed, 16); ++ memcpy(emmCopy, oemm, emmLen); ++ emm = emmCopy; ++ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { ++ return 0; ++ } ++ } ++ ++ while(GetIrdetoKey(keyPMK, ident, 'M', 5, 1, &keyPMK0ERef)) { ++ xxor(keyPMK, 16, keyPMK, fausto_xor); ++ memcpy(keySeed, okeySeed, 16); ++ memcpy(emmCopy, oemm, emmLen); ++ emm = emmCopy; ++ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { ++ return 0; ++ } ++ } ++ ++ while(GetIrdetoKey(keyPMK, ident, 'M', 6, 1, &keyPMK1ERef)) { ++ xxor(keyPMK, 16, keyPMK, fausto_xor); ++ memcpy(keySeed, okeySeed, 16); ++ memcpy(emmCopy, oemm, emmLen); ++ emm = emmCopy; ++ if(Irdeto2DoEMMTypeOP(ident, emm, keySeed, keyIV, keyPMK, emmLen, startOffset, length, keysAdded) == 0) { ++ return 0; ++ } ++ } ++ } ++ ++ if(keyPMK0Ref == 0 && keyPMK1Ref == 0 && keyPMK0ERef == 0 && keyPMK1ERef == 0) { ++ return 2; ++ } ++ } ++ if(keyIVRef == 0) { ++ return 2; ++ } ++ } ++ if(keySeedRef == 0) { ++ return 2; ++ } ++ ++ return 1; ++} ++ ++int32_t GetIrdeto2Hexserial(uint16_t caid, uint8_t *hexserial) ++{ ++ uint32_t i, len; ++ KeyDataContainer *KeyDB; ++ KeyData *tmpKeyData; ++ ++ KeyDB = GetKeyContainer('I'); ++ if(KeyDB == NULL) { ++ return 0; ++ } ++ ++ for(i=0; ikeyCount; i++) { ++ ++ if(KeyDB->EmuKeys[i].provider>>8 != caid) { ++ continue; ++ } ++ if(strcmp(KeyDB->EmuKeys[i].keyName, "MC")) { ++ continue; ++ } ++ ++ tmpKeyData = &KeyDB->EmuKeys[i]; ++ ++ len = tmpKeyData->keyLength; ++ if(len > 3) ++ { len = 3; } ++ ++ memcpy(hexserial+(3-len), tmpKeyData->key, len); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++ ++// PowerVu EMM EMU ++static void PowervuUnmaskEmm(uint8_t *emm) ++{ ++ int i, l; ++ ++ uint8_t sourcePos[] = {0x03, 0x0C, 0x0D, 0x11, 0x15, 0x18, 0x1D, 0x1F, 0x25, 0x2A, 0x32, 0x35, 0x3A, 0x3B, 0x3E, ++ 0x42, 0x47, 0x48, 0x53, 0x58, 0x5C, 0x61, 0x66, 0x69, 0x71, 0x72, 0x78, 0x7B, 0x81, 0x84}; ++ ++ uint8_t destPos[] = {0x02, 0x08, 0x0B, 0x0E, 0x13, 0x16, 0x1E, 0x23, 0x28, 0x2B, 0x2F, 0x33, 0x38, 0x3C, 0x40, ++ 0x44, 0x4A, 0x4D, 0x54, 0x57, 0x5A, 0x63, 0x68, 0x6A, 0x70, 0x75, 0x76, 0x7D, 0x82, 0x85}; ++ ++ uint8_t data[0x1E]; ++ uint8_t hashModeEmm; ++ uint8_t mask[0x10]; ++ uint32_t crc; ++ ++ // Create Mask for ECM decryption ++ PowervuCreateDataEcmEmm(emm, sourcePos, 0x13, 0x1E, data); ++ ++ hashModeEmm = emm[8] ^ PowervuCrc8Calc(data, 0x1E); ++ ++ PowervuCreateHash(data, 0x1E, mask, hashModeEmm); ++ ++ // Fix Header ++ emm[3] &= 0x0F; ++ emm[3] |= 0x10; ++ emm[8] = 0x00; ++ ++ // Unmask Body ++ for(i = 0; i < 0x1E; i++) ++ { ++ emm[0x13 + destPos[i]] ^= mask[i & 0x0F]; ++ } ++ ++ // Fix CRC (optional) ++ l = (((emm[1] << 8) + emm[2]) & 0xFFF) + 3 - 4; ++ crc = fletcher_crc32(emm, l); ++ ++ emm[l + 0] = crc >> 24; ++ emm[l + 1] = crc >> 16; ++ emm[l + 2] = crc >> 8; ++ emm[l + 3] = crc >> 0; ++} ++ ++static int8_t PowervuEMM(uint8_t *emm, uint32_t *keysAdded) ++{ ++ uint8_t emmInfo, emmType, decryptOk = 0; ++ uint16_t emmLen = GetEcmLen(emm); ++ uint32_t i, uniqueAddress, groupId, keyRef = 0; ++ //uint32_t emmCrc32; ++ uint8_t emmKey[7], tmpEmmKey[7], tmp[26]; ++ char keyName[EMU_MAX_CHAR_KEYNAME], keyValue[16]; ++ char uaInfo[4+8+1]; ++ ++ if(emmLen < 50) ++ { ++ return 1; ++ } ++ ++ // Check if unmasking is needed ++ if((emm[3] & 0xF0) == 0x50) ++ { ++ PowervuUnmaskEmm(emm); ++ } ++ ++ // looks like checksum does not work for all EMMs ++ //emmCrc32 = b2i(4, emm+emmLen-4); ++ // ++ //if(fletcher_crc32(emm, emmLen-4) != emmCrc32) ++ //{ ++ // return 8; ++ //} ++ emmLen -= 4; ++ ++ uniqueAddress = b2i(4, emm+12); ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.8X", uniqueAddress); ++ ++ do ++ { ++ if(!GetPowervuEmmKey(emmKey, 0, keyName, 7, 0, keyRef++, &groupId)) ++ { ++ cs_log_dbg(D_EMM, "EMM error: AU key for UA %s is missing", keyName); ++ return 2; ++ } ++ ++ for(i=19; i+27<=emmLen; i+=27) { ++ emmInfo = emm[i]; ++ ++ if(!GetBit(emmInfo, 7)) ++ { ++ continue; ++ } ++ ++ //keyNb = emm[i] & 0x0F; ++ ++ memcpy(tmp, emm+i+1, 26); ++ memcpy(tmpEmmKey, emmKey, 7); ++ PowervuDecrypt(emm+i+1, 26, tmpEmmKey, 0); ++ ++ if((emm[13] != emm[i+24]) || (emm[14] != emm[i+25]) || (emm[15] != emm[i+26])) ++ { ++ memcpy(emm+i+1, tmp, 26); ++ memcpy(tmpEmmKey, emmKey, 7); ++ PowervuDecrypt(emm+i+1, 26, tmpEmmKey, 1); ++ ++ if((emm[13] != emm[i+24]) || (emm[14] != emm[i+25]) || (emm[15] != emm[i+26])) ++ { ++ memcpy(emm+i+1, tmp, 26); ++ memcpy(tmpEmmKey, emmKey, 7); ++ continue; ++ } ++ } ++ ++ decryptOk = 1; ++ ++ emmType = emm[i+2] & 0x7F; ++ if(emmType > 1) ++ { ++ continue; ++ } ++ ++ snprintf(keyName, EMU_MAX_CHAR_KEYNAME, "%.2X", emmType); ++ snprintf(uaInfo, sizeof(uaInfo), "UA: %08X", uniqueAddress); ++ ++ if(emm[i+3] == 0 && emm[i+4] == 0) ++ { ++ cs_hexdump(0, &emm[i+3], 7, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: P %.4X**** %s %s -> REJECTED (looks invalid) UA: %.8X", groupId, keyName, keyValue, uniqueAddress); ++ continue; ++ } ++ ++ UpdateKeysByProviderMask('P', groupId<<16, 0x0000FFFF, keyName, &emm[i+3], 7, uaInfo); ++ ++ (*keysAdded)++; ++ cs_hexdump(0, &emm[i+3], 7, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: P %.4X**** %s %s ; UA: %.8X", groupId, keyName, keyValue, uniqueAddress); ++ } ++ ++ } while(!decryptOk); ++ ++ return 0; ++} ++ ++int32_t GetPowervuHexserials(uint16_t srvid, uint8_t hexserials[][4], int32_t length, int32_t* count) ++{ ++ //srvid == 0xFFFF -> get all ++ ++ uint32_t i, j; ++ uint32_t groupid; ++ int32_t len, k; ++ KeyDataContainer *KeyDB; ++ uint8_t tmp[4]; ++ int8_t alreadyAdded; ++ ++ KeyDB = GetKeyContainer('P'); ++ if(KeyDB == NULL) ++ { return 0; } ++ ++ (*count) = 0; ++ ++ for(i=0; ikeyCount && (*count)EmuKeys[i].provider <= 0x0000FFFF) // skip au keys ++ { continue; } ++ ++ if(srvid != 0xFFFF && (KeyDB->EmuKeys[i].provider & 0x0000FFFF) != srvid) ++ { continue; } ++ ++ groupid = KeyDB->EmuKeys[i].provider>>16; ++ ++ for(j=0; jkeyCount && (*count)EmuKeys[j].provider != groupid) // search au key with groupip ++ { continue; } ++ ++ len = strlen(KeyDB->EmuKeys[j].keyName); ++ ++ if(len < 3) ++ { continue;} ++ ++ if(len > 8) ++ { len = 8; } ++ ++ memset(tmp, 0, 4); ++ CharToBin(tmp+(4-(len/2)), KeyDB->EmuKeys[j].keyName, len); ++ ++ for(k=0, alreadyAdded=0; k<*count; k++) ++ { ++ if(!memcmp(hexserials[k], tmp, 4)) ++ { ++ alreadyAdded = 1; ++ break; ++ } ++ } ++ ++ if(!alreadyAdded) ++ { ++ memcpy(hexserials[*count], tmp, 4); ++ (*count)++; ++ } ++ } ++ ++ } ++ ++ return 1; ++} ++ ++// Drecrypt EMM EMU ++static int8_t DrecryptGetEmmKey(uint8_t *buf, uint32_t keyIdent, uint16_t keyName, uint8_t isCriticalKey) ++{ ++ char keyStr[EMU_MAX_CHAR_KEYNAME]; ++ snprintf(keyStr, EMU_MAX_CHAR_KEYNAME, "MK%04X", keyName); ++ return FindKey('D', keyIdent, 0, keyStr, buf, 32, isCriticalKey, 0, 0, NULL); ++} ++ ++static void DrecryptWriteEebin(const char *path, const char *name) ++{ ++ char tmp[256]; ++ FILE *file = NULL; ++ uint8_t i, buffer[64][32]; ++ uint32_t prvid; ++ ++ // Set path ++ if (path != NULL) ++ { ++ snprintf(tmp, 256, "%s%s", path, name); ++ } ++ else // No path set, use SoftCam.Keys's path ++ { ++ snprintf(tmp, 256, "%s%s", emu_keyfile_path, name); ++ } ++ ++ if ((file = fopen(tmp, "wb")) != NULL) ++ { ++ cs_log("Writing key file: %s", tmp); ++ } ++ else ++ { ++ cs_log("Error writing key file: %s", tmp); ++ return; ++ } ++ ++ // Load keys from db to buffer ++ prvid = (strncmp(name, "ee36.bin", 9) == 0) ? 0x4AE111 : 0x4AE114; ++ ++ for (i = 0; i < 32; i++) // Load "3B" type keys ++ { ++ snprintf(tmp, 5, "3B%02X", i); ++ if (!FindKey('D', prvid, 0, tmp, buffer[i], 32, 0, 0, 0, NULL)) ++ { ++ memset(buffer[i], 0xFF, 32); ++ } ++ } ++ ++ for (i = 0; i < 32; i++) // Load "56" type keys ++ { ++ snprintf(tmp, 5, "56%02X", i); ++ if (!FindKey('D', prvid, 0, tmp, buffer[32 + i], 32, 0, 0, 0, NULL)) ++ { ++ memset(buffer[32 + i], 0xFF, 32); ++ } ++ } ++ ++ // Write buffer to ee.bin file ++ fwrite(buffer, 1, sizeof(buffer), file); ++ fclose(file); ++} ++ ++static int8_t DrecryptProcessEMM(struct s_reader *rdr, uint32_t provId, uint8_t *emm, uint32_t *keysAdded) ++{ ++ uint16_t emmLen, emmDataLen; ++ uint32_t i, keyIdent; ++ uint16_t keyName; ++ uint8_t emmKey[32]; ++ uint8_t *curECMkey3B = NULL, *curECMkey56 = NULL; ++ uint8_t keynum =0, keyidx = 0, keyclass = 0, key1offset, key2offset; ++ char newKeyName[EMU_MAX_CHAR_KEYNAME], curKeyName[EMU_MAX_CHAR_KEYNAME], keyValue[100]; ++ ++ emmDataLen = GetEcmLen(emm); ++ emmLen = ((emm[1] & 0xF) << 8) | emm[2]; ++ ++ if (emmDataLen < emmLen + 3) ++ { ++ return 4; // Corrupt data ++ } ++ ++ if (emm[0] == 0x91) ++ { ++ Drecrypt2OverEMM(emm); ++ return 0; ++ } ++ else if (emm[0] == 0x82) ++ { ++ ReasmEMM82(emm); ++ return 0; ++ } ++ else if (emm[0] != 0x86) ++ { ++ return 1; // Not supported ++ } ++ ++ // Emm type 0x86 only ++ switch (emm[4]) ++ { ++ case 0x02: ++ keynum = 0x2C; ++ keyidx = 0x30; ++ keyclass = 0x26; ++ key1offset = 0x35; ++ key2offset = 0x6D; ++ break; ++ ++ case 0x4D: ++ keynum = 0x61; ++ keyidx = 0x60; ++ keyclass = 0x05; ++ key1offset = 0x62; ++ key2offset = 0x8B; ++ break; ++ ++ default: ++ return 1; // Not supported ++ } ++ ++ switch (provId & 0xFF) ++ { ++ case 0x11: ++ { ++ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "3B%02X", emm[keyclass]); ++ FindKey('D', 0x4AE111, 0, curKeyName, curECMkey3B, 32, 0, 0, 0, NULL); ++ ++ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "56%02X", emm[keyclass]); ++ FindKey('D', 0x4AE111, 0, curKeyName, curECMkey56, 32, 0, 0, 0, NULL); ++ ++ break; ++ } ++ ++ case 0x14: ++ { ++ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "3B%02X", emm[keyclass]); ++ FindKey('D', 0x4AE114, 0, curKeyName, curECMkey3B, 32, 0, 0, 0, NULL); ++ ++ snprintf(curKeyName, EMU_MAX_CHAR_KEYNAME, "56%02X", emm[keyclass]); ++ FindKey('D', 0x4AE114, 0, curKeyName, curECMkey56, 32, 0, 0, 0, NULL); ++ ++ break; ++ } ++ ++ default: ++ return 9; // Wrong provider ++ } ++ ++ keyIdent = (0x4AE1 << 8) | provId; ++ keyName = (emm[3] << 8) | emm[keynum]; ++ ++ if (!DrecryptGetEmmKey(emmKey, keyIdent, keyName, 1)) ++ { ++ return 2; ++ } ++ ++ // Key #1 ++ for (i = 0; i < 4; i++) ++ { ++ DrecryptDecrypt(&emm[key1offset + (i * 8)], emmKey); ++ } ++ ++ // Key #2 ++ for (i = 0; i < 4; i++) ++ { ++ DrecryptDecrypt(&emm[key2offset + (i * 8)], emmKey); ++ } ++ ++ // Key #1 ++ keyName = emm[keyidx] << 8 | emm[keyclass]; ++ snprintf(newKeyName, EMU_MAX_CHAR_KEYNAME, "%.4X", keyName); ++ ++ if (memcmp(&emm[key1offset], emm[keyidx] == 0x3b ? curECMkey3B : curECMkey56, 32) != 0) ++ { ++ memcpy(emm[keyidx] == 0x3b ? curECMkey3B : curECMkey56, &emm[key1offset], 32); ++ SetKey('D', keyIdent, newKeyName, &emm[key1offset], 32, 0, NULL, NULL); ++ (*keysAdded)++; ++ ++ cs_hexdump(0, &emm[key1offset], 32, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: D %.6X %s %s class %02X", keyIdent, newKeyName, keyValue, emm[keyclass]); ++ } ++ else ++ { ++ cs_log("Key %.6X %s already exists", keyIdent, newKeyName); ++ } ++ ++ // Key #2 ++ keyName = (emm[keyidx] == 0x56 ? 0x3B00 : 0x5600) | emm[keyclass]; ++ snprintf(newKeyName, EMU_MAX_CHAR_KEYNAME, "%.4X", keyName); ++ ++ if (memcmp(&emm[key2offset], emm[keyidx] == 0x3b ? curECMkey56 : curECMkey3B, 32) != 0) ++ { ++ memcpy(emm[keyidx] == 0x3b ? curECMkey56 : curECMkey3B, &emm[key2offset], 32); ++ SetKey('D', keyIdent, newKeyName, &emm[key2offset], 32, 0, NULL, NULL); ++ (*keysAdded)++; ++ ++ cs_hexdump(0, &emm[key2offset], 32, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: D %.6X %s %s class %02X", keyIdent, newKeyName, keyValue, emm[keyclass]); ++ } ++ else ++ { ++ cs_log("Key %.6X %s already exists", keyIdent, newKeyName); ++ } ++ ++ if (*keysAdded > 0) // Write new ecm keys to ee.bin file ++ { ++ switch (provId & 0xFF) ++ { ++ case 0x11: ++ DrecryptWriteEebin(rdr->extee36, "ee36.bin"); ++ break; ++ ++ case 0x14: ++ DrecryptWriteEebin(rdr->extee56, "ee56.bin"); ++ break; ++ ++ default: ++ cs_log("Provider %02X doesn't have a matching ee.bin file", provId & 0xFF); ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++static int8_t Drecrypt2EMM(struct s_reader *rdr, uint32_t provId, uint8_t *emm, uint32_t *keysAdded) ++{ ++ int8_t result = DrecryptProcessEMM(rdr, provId, emm, keysAdded); ++ ++ if (result == 2) ++ { ++ uint8_t keynum = 0, emmkey; ++ uint32_t i; ++ KeyDataContainer *KeyDB = GetKeyContainer('D'); ++ ++ if (KeyDB == NULL) ++ { ++ return result; ++ } ++ ++ for (i = 0; i < KeyDB->keyCount; i++) ++ { ++ if (KeyDB->EmuKeys[i].provider != ((0x4AE1 << 8) | provId)) ++ { ++ continue; ++ } ++ ++ if (strlen(KeyDB->EmuKeys[i].keyName) < 6) ++ { ++ continue; ++ } ++ ++ if (memcmp(KeyDB->EmuKeys[i].keyName, "MK", 2)) ++ { ++ continue; ++ } ++ ++ CharToBin(&keynum, KeyDB->EmuKeys[i].keyName + 4, 2); ++ emmkey = (emm[4] == 0x4D) ? emm[0x61] : emm[0x2C]; ++ ++ if (keynum == emmkey) ++ { ++ if (provId == 0x11) ++ { ++ CharToBin(&rdr->dre36_force_group, KeyDB->EmuKeys[i].keyName + 2, 2); ++ } ++ else ++ { ++ CharToBin(&rdr->dre56_force_group, KeyDB->EmuKeys[i].keyName + 2, 2); ++ } ++ ++ break; ++ } ++ } ++ } ++ ++ return result; ++} ++ ++int32_t GetDrecryptHexserials(uint16_t caid, uint32_t provid, uint8_t *hexserials, int32_t length, int32_t *count) ++{ ++ uint32_t i; ++ KeyDataContainer *KeyDB = GetKeyContainer('D'); ++ ++ if (KeyDB == NULL) ++ { ++ return 0; ++ } ++ ++ (*count) = 0; ++ ++ for (i = 0; i < KeyDB->keyCount && (*count) < length; i++) ++ { ++ ++ if (KeyDB->EmuKeys[i].provider != ((caid << 8) | provid)) ++ { ++ continue; ++ } ++ ++ if (strlen(KeyDB->EmuKeys[i].keyName) < 6) ++ { ++ continue; ++ } ++ ++ if (memcmp(KeyDB->EmuKeys[i].keyName, "MK", 2)) ++ { ++ continue; ++ } ++ ++ CharToBin(&hexserials[(*count)], KeyDB->EmuKeys[i].keyName + 2, 2); ++ ++ (*count)++; ++ } ++ ++ return 1; ++} ++ ++// Tandberg EMM EMU ++static uint8_t MixTable[] = ++{ ++ 0x12,0x78,0x4B,0x19,0x13,0x80,0x2F,0x84, ++ 0x86,0x4C,0x09,0x53,0x15,0x79,0x6B,0x49, ++ 0x10,0x4D,0x33,0x43,0x18,0x37,0x83,0x38, ++ 0x82,0x1B,0x6E,0x24,0x2A,0x85,0x3C,0x3D, ++ 0x5A,0x58,0x55,0x5D,0x20,0x41,0x65,0x51, ++ 0x0C,0x45,0x63,0x7F,0x0F,0x46,0x21,0x7C, ++ 0x2C,0x61,0x7E,0x0A,0x42,0x57,0x35,0x16, ++ 0x87,0x3B,0x4F,0x40,0x34,0x22,0x26,0x74, ++ 0x32,0x69,0x44,0x7A,0x6A,0x6D,0x0D,0x56, ++ 0x23,0x2B,0x5C,0x72,0x76,0x36,0x28,0x25, ++ 0x2E,0x52,0x5B,0x6C,0x7D,0x30,0x0B,0x5E, ++ 0x47,0x1F,0x7B,0x31,0x3E,0x11,0x77,0x1E, ++ 0x60,0x75,0x54,0x27,0x50,0x17,0x70,0x59, ++ 0x1A,0x2D,0x4A,0x67,0x3A,0x5F,0x68,0x08, ++ 0x4E,0x3F,0x29,0x6F,0x81,0x71,0x39,0x64, ++ 0x48,0x66,0x73,0x14,0x0E,0x1D,0x62,0x1C ++}; ++ ++void TandbergRotateBytes(unsigned char *in, int n) ++{ ++ if(n > 1) ++ { ++ unsigned char *e = in + n - 1; ++ do ++ { ++ unsigned char temp = *in; ++ *in++ = *e; ++ *e-- = temp; ++ } ++ while (in < e); ++ } ++} ++ ++static void TandbergECMKeyDecrypt(uint8_t* emmKey, uint8_t* tagData, uint8_t* ecmKey) ++{ ++ TandbergRotateBytes(emmKey, 8); ++ uint8_t iv[8] = { 0 }; ++ uint8_t* payLoad = tagData + 4 + 5; ++ des_cbc_decrypt(payLoad, iv, emmKey, 16); ++ ++ ecmKey[0] = payLoad[0x0F]; ++ ecmKey[1] = payLoad[0x01]; ++ ecmKey[2] = payLoad[0x0B]; ++ ecmKey[3] = payLoad[0x03]; ++ ecmKey[4] = payLoad[0x0E]; ++ ecmKey[5] = payLoad[0x04]; ++ ecmKey[6] = payLoad[0x0A]; ++ ecmKey[7] = payLoad[0x08]; ++} ++ ++static int8_t TandbergParseEMMNanoTags(uint8_t* data, uint32_t length, uint8_t keyIndex, uint32_t *keysAdded) ++{ ++ uint8_t tagType, tagLength, blockIndex; ++ uint32_t pos = 0, entitlementId; ++ int32_t i, k; ++ uint32_t ks[32]; ++ uint8_t* tagData; ++ uint8_t emmKey[8]; ++ char keyValue[17]; ++ uint8_t tagDataDecrypted[0x10][8]; ++ ++ if(length < 2) ++ { ++ return 1; ++ } ++ ++ while(pos < length) ++ { ++ tagType = data[pos]; ++ tagLength = data[pos+1]; ++ ++ if(pos + 2 + tagLength > length) ++ { ++ return 1; ++ } ++ ++ tagData = data + pos + 2; ++ ++ switch(tagType) ++ { ++ case 0xE4: // EMM_TAG_SECURITY_TABLE_DESCRIPTOR (ram emm keys) ++ { ++ uint8_t tagMode = data[pos + 2]; ++ ++ switch(tagMode) ++ { ++ case 0x01: // keySet 01 (MK01) ++ { ++ if(tagLength != 0x8A) ++ { ++ cs_log("WARNING: nanoTag E4 length (%d) != %d", tagLength, 0x8A); ++ break; ++ } ++ ++ if(!GetTandbergKey(keyIndex, "MK01", emmKey, 8)) ++ { ++ break; ++ } ++ ++ uint8_t iv[8] = { 0 }; ++ uint8_t* tagPayload = tagData + 2; ++ des_cbc_decrypt(tagPayload, iv, emmKey, 136); ++ ++ for (k = 0; k < 0x10; k++) // loop 0x10 keys ++ { ++ for (i = 0; i < 8; i++) // loop 8 bytes of key ++ { ++ tagDataDecrypted[k][i] = tagPayload[MixTable[8*k + i]]; ++ } ++ } ++ ++ blockIndex = tagData[1] & 0x03; ++ ++ for(i = 0; i < 0x10; i++) ++ { ++ SetKey('T', (blockIndex << 4) + i, "MK01", tagDataDecrypted[i], 8, 0, NULL, NULL); ++ } ++ } ++ break; ++ ++ case 0xFF: // keySet FF (MK) ++ { ++ if(tagLength != 0x82) ++ { ++ cs_log("WARNING: nanoTag E4 length (%d) != %d", tagLength, 0x82); ++ break; ++ } ++ ++ blockIndex = tagData[1] & 0x03; ++ ++ if(!GetTandbergKey(keyIndex, "MK", emmKey, 8)) ++ { ++ break; ++ } ++ ++ des_set_key(emmKey, ks); ++ ++ for(i = 0; i < 0x10; i++) ++ { ++ des(tagData + 2 + (i*8), ks, 0); ++ } ++ ++ for(i = 0; i < 0x10; i++) ++ { ++ SetKey('T', (blockIndex << 4) + i, "MK", tagData + 2 + (i*8), 8, 0, NULL, NULL); ++ } ++ } ++ break; ++ ++ default: ++ cs_log("WARNING: nanoTag E4 mode %.2X not supported", tagMode); ++ break; ++ } ++ break; ++ } ++ ++ case 0xE1: // EMM_TAG_EVENT_ENTITLEMENT_DESCRIPTOR (ecm keys) ++ { ++ uint8_t tagMode = data[pos + 2 + 4]; ++ ++ switch(tagMode) ++ { ++ case 0x00: // ecm keys from mode FF ++ { ++ if(tagLength != 0x12) ++ { ++ cs_log("WARNING: nanoTag E1 length (%d) != %d", tagLength, 0x12); ++ break; ++ } ++ ++ entitlementId = b2i(4, tagData); ++ ++ if(!GetTandbergKey(keyIndex, "MK", emmKey, 8)) ++ { ++ break; ++ } ++ ++ des_set_key(emmKey, ks); ++ des(tagData + 4 + 5, ks, 0); ++ ++ if((tagData + 4 + 5 + 7) != 0x00) // check if key looks valid (last byte 0x00) ++ { ++ break; ++ } ++ ++ if(UpdateKey('T', entitlementId, "01", tagData + 4 + 5, 8, 1, NULL)) ++ { ++ (*keysAdded)++; ++ cs_hexdump(0, tagData + 4 + 5, 8, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: T %.8X 01 %s", entitlementId, keyValue); ++ } ++ } ++ break; ++ ++ case 0x01: // ecm keys from mode 01 ++ { ++ if(tagLength != 0x1A) ++ { ++ cs_log("WARNING: nanoTag E1 length (%d) != %d", tagLength, 0x1A); ++ break; ++ } ++ ++ entitlementId = b2i(4, tagData); ++ ++ if(!GetTandbergKey(keyIndex, "MK01", emmKey, 8)) ++ { ++ break; ++ } ++ ++ uint8_t ecmKey[8] = { 0 }; ++ TandbergECMKeyDecrypt(emmKey, tagData, ecmKey); ++ ++ if(ecmKey[7] != 0x00) // check if key looks valid (last byte 0x00) ++ { ++ break; ++ } ++ ++ if(UpdateKey('T', entitlementId, "01", ecmKey, 8, 1, NULL)) ++ { ++ (*keysAdded)++; ++ cs_hexdump(0, ecmKey, 8, keyValue, sizeof(keyValue)); ++ cs_log("Key found in EMM: T %.8X 01 %s", entitlementId, keyValue); ++ } ++ } ++ break; ++ ++ default: ++ cs_log("WARNING: nanoTag E1 mode %.2X not supported", tagMode); ++ break; ++ } ++ break; ++ } ++ ++ default: ++ cs_log("WARNING: nanoTag %.2X not supported", tagType); ++ break; ++ } ++ ++ pos += 2 + tagLength; ++ } ++ ++ return 0; ++} ++ ++static int8_t TandbergParseEMMNanoData(uint8_t* data, uint32_t* nanoLength, uint32_t maxLength, uint8_t keyIndex, uint32_t *keysAdded) ++{ ++ uint32_t pos = 0; ++ uint16_t sectionLength; ++ int8_t ret = 0; ++ ++ if(maxLength < 2) ++ { ++ (*nanoLength) = 0; ++ return 1; ++ } ++ ++ sectionLength = ((data[pos]<<8) | data[pos+1]) & 0x0FFF; ++ ++ if(pos + 2 + sectionLength > maxLength) ++ { ++ (*nanoLength) = pos; ++ return 1; ++ } ++ ++ ret = TandbergParseEMMNanoTags(data + pos + 2, sectionLength, keyIndex, keysAdded); ++ ++ pos += 2 + sectionLength; ++ ++ (*nanoLength) = pos; ++ return ret; ++} ++ ++static int8_t TandbergEMM(uint8_t *emm, uint32_t *keysAdded) ++{ ++ uint8_t keyIndex, ret = 0; ++ uint16_t emmLen = GetEcmLen(emm); ++ uint32_t pos = 3; ++ uint32_t permissionDataType; ++ uint32_t nanoLength = 0; ++ ++ while (pos < emmLen && !ret) ++ { ++ permissionDataType = emm[pos]; ++ ++ switch(permissionDataType) ++ { ++ case 0x00: ++ { ++ break; ++ } ++ ++ case 0x01: ++ { ++ pos += 0x0A; ++ break; ++ } ++ ++ case 0x02: ++ { ++ pos += 0x26; ++ break; ++ } ++ ++ default: ++ cs_log("ERROR: unknown permissionDataType %.2X (pos: %d)", permissionDataType, pos); ++ return 1; ++ } ++ ++ if(pos+6 >= emmLen) ++ { ++ break; ++ } ++ ++ keyIndex = emm[pos+1]; ++ ++ // EMM validation ++ // Copy payload checksum bytes and then set them to zero, ++ // so they do not affect the calculated checksum. ++ uint16_t payloadChecksum = (emm[pos + 2] << 8) | emm[pos + 3]; ++ memset(emm + pos + 2, 0, 2); ++ uint16_t calculatedChecksum = TandbergChecksum(emm + 3, emmLen - 3); ++ ++ if(calculatedChecksum != payloadChecksum) ++ { ++ cs_log("EMM checksum error (%.4X instead of %.4X)", calculatedChecksum, payloadChecksum); ++ return 8; ++ } ++ // End of EMM validation ++ ++ pos += 0x04; ++ ret = TandbergParseEMMNanoData(emm + pos, &nanoLength, emmLen - pos, keyIndex, keysAdded); ++ pos += nanoLength; ++ } ++ ++ return ret; ++} ++ ++const char* GetProcessEMMErrorReason(int8_t result) ++{ ++ switch(result) { ++ case 0: ++ return "No error"; ++ case 1: ++ return "EMM not supported"; ++ case 2: ++ return "Key not found"; ++ case 3: ++ return "Nano80 problem"; ++ case 4: ++ return "Corrupt data"; ++ case 5: ++ return "Unknown"; ++ case 6: ++ return "Checksum error"; ++ case 7: ++ return "Out of memory"; ++ case 8: ++ return "EMM checksum error"; ++ case 9: ++ return "Wrong provider"; ++ default: ++ return "Unknown"; ++ } ++} ++ ++int8_t ProcessEMM(struct s_reader *rdr, uint16_t caid, uint32_t provider, const uint8_t *emm, uint32_t *keysAdded) ++{ ++ int8_t result = 1; ++ uint8_t emmCopy[EMU_MAX_EMM_LEN]; ++ uint16_t emmLen = GetEcmLen(emm); ++ ++ if(emmLen > EMU_MAX_EMM_LEN) { ++ return 1; ++ } ++ memcpy(emmCopy, emm, emmLen); ++ *keysAdded = 0; ++ ++ if(caid==0x0500) { ++ result = ViaccessEMM(emmCopy, keysAdded); ++ } ++ else if((caid>>8)==0x06) { ++ result = Irdeto2EMM(caid, emmCopy, keysAdded); ++ } ++ else if((caid>>8)==0x0E) { ++ result = PowervuEMM(emmCopy, keysAdded); ++ } ++ else if(caid==0x4AE1) { ++ result = Drecrypt2EMM(rdr, provider, emmCopy, keysAdded); ++ } ++ else if((caid>>8)==0x10) { ++ result = TandbergEMM(emmCopy, keysAdded); ++ } ++ ++ if(result != 0) { ++ cs_log_dbg(D_EMM,"EMM failed: %s", GetProcessEMMErrorReason(result)); ++ } ++ ++ return result; ++} +diff -ruNp trunk.patches/module-emulator-osemu.h trunk/module-emulator-osemu.h +--- trunk.patches/module-emulator-osemu.h 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/module-emulator-osemu.h 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,127 @@ ++#include "globals.h" ++#include "module-emulator-stream.h" ++ ++#ifndef EMULATOR_H_ ++#define EMULATOR_H_ ++ ++#define EMU_MAX_CHAR_KEYNAME 12 ++#define EMU_KEY_FILENAME "SoftCam.Key" ++#define EMU_KEY_FILENAME_MAX_LEN 31 ++#define EMU_MAX_ECM_LEN MAX_ECM_SIZE ++#define EMU_MAX_EMM_LEN MAX_EMM_SIZE ++ ++typedef struct KeyData KeyData; ++ ++struct KeyData ++{ ++ char identifier; ++ uint32_t provider; ++ char keyName[EMU_MAX_CHAR_KEYNAME]; ++ uint8_t *key; ++ uint32_t keyLength; ++ KeyData *nextKey; ++}; ++ ++typedef struct ++{ ++ KeyData *EmuKeys; ++ uint32_t keyCount; ++ uint32_t keyMax; ++} KeyDataContainer; ++ ++extern KeyDataContainer CwKeys; ++extern KeyDataContainer ViKeys; ++extern KeyDataContainer NagraKeys; ++extern KeyDataContainer IrdetoKeys; ++extern KeyDataContainer NDSKeys; ++extern KeyDataContainer BissKeys; ++extern KeyDataContainer PowervuKeys; ++extern KeyDataContainer DreKeys; ++extern KeyDataContainer TandbergKeys; ++extern uint8_t viasat_const[]; ++ ++uint32_t GetOSemuVersion(void); ++ ++void set_emu_keyfile_path(const char *path); ++void clear_emu_keydata(void); ++uint8_t read_emu_keyfile(struct s_reader *rdr, const char *path); ++ ++#if !defined(__APPLE__) && !defined(__ANDROID__) ++void read_emu_keymemory(struct s_reader *rdr); ++#endif ++ ++void read_emu_eebin(const char *path, const char *name); ++void read_emu_deskey(uint8_t *dreOverKey, uint8_t len); ++ ++int32_t CharToBin(uint8_t *out, const char *in, uint32_t inLen); ++ ++/* Error codes ++0 OK ++1 ECM not supported ++2 Key not found ++3 Nano80 problem ++4 Corrupt data ++5 CW not found ++6 CW checksum error ++7 Out of memory ++8 ECM checksum error ++9 ICG error ++*/ ++#ifdef WITH_EMU ++int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, ++ const uint8_t *ecm, uint8_t *dw, uint16_t srvid, uint16_t ecmpid, EXTENDED_CW* cw_ex); ++#else ++int8_t ProcessECM(struct s_reader *rdr, int16_t ecmDataLen, uint16_t caid, uint32_t provider, ++ const uint8_t *ecm, uint8_t *dw, uint16_t srvid, uint16_t ecmpid); ++#endif ++ ++const char* GetProcessECMErrorReason(int8_t result); ++ ++/* Error codes ++0 OK ++1 EMM not supported ++2 Key not found ++3 Nano80 problem ++4 Corrupt data ++5 ++6 Checksum error ++7 Out of memory ++*/ ++int8_t ProcessEMM(struct s_reader *rdr, uint16_t caid, uint32_t provider, const uint8_t *emm, uint32_t *keysAdded); ++ ++const char* GetProcessEMMErrorReason(int8_t result); ++ ++// hexserial must be of type "uint8_t hexserial[3]" ++// returns 0 on error, 1 on success ++int32_t GetIrdeto2Hexserial(uint16_t caid, uint8_t* hexserial); ++ ++// hexserials must be of type "uint8_t hexserials[length][4]" ++// if srvid == 0xFFFF all serials are returned (no srvid filtering) ++// returns 0 on error, 1 on success ++int32_t GetPowervuHexserials(uint16_t srvid, uint8_t hexserials[][4], int32_t length, int32_t* count); ++ ++// hexserials must be of type "uint8_t hexserials[length]" ++// returns 0 on error, 1 on success ++int32_t GetDrecryptHexserials(uint16_t caid, uint32_t provid, uint8_t *hexserials, int32_t length, int32_t* count); ++ ++#define PVU_CW_VID 0 // VIDeo ++#define PVU_CW_HSD 1 // High Speed Data ++#define PVU_CW_A1 2 // Audio 1 ++#define PVU_CW_A2 3 // Audio 2 ++#define PVU_CW_A3 4 // Audio 3 ++#define PVU_CW_A4 5 // Audio 4 ++#define PVU_CW_UTL 6 // UTiLity ++#define PVU_CW_VBI 7 // Vertical Blanking Interval ++ ++#ifdef WITH_EMU ++int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, uint16_t srvid, emu_stream_client_key_data *cdata, EXTENDED_CW* cw_ex); ++#else ++int8_t PowervuECM(uint8_t *ecm, uint8_t *dw, emu_stream_client_key_data *cdata); ++#endif ++ ++#ifdef WITH_EMU ++int32_t FindKey(char identifier, uint32_t provider, uint32_t providerIgnoreMask, char *keyName, uint8_t *key, ++ uint32_t maxKeyLength, uint8_t isCriticalKey, uint32_t keyRef, uint8_t matchLength, uint32_t *getProvider); ++#endif ++ ++#endif +diff -ruNp trunk.patches/module-emulator-stream.c trunk/module-emulator-stream.c +--- trunk.patches/module-emulator-stream.c 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/module-emulator-stream.c 2018-04-03 03:20:07.658045369 +0300 +@@ -0,0 +1,1105 @@ ++#define MODULE_LOG_PREFIX "emu" ++ ++#include "globals.h" ++#include "cscrypt/des.h" ++ ++#ifdef WITH_EMU ++#include "oscam-string.h" ++#include "oscam-config.h" ++#include "oscam-time.h" ++#include "oscam-net.h" ++ ++extern int32_t exit_oscam; ++#endif ++ ++#include "ffdecsa/ffdecsa.h" ++#include "module-emulator-osemu.h" ++#include "module-emulator-stream.h" ++ ++typedef struct ++{ ++ int32_t connfd; ++ int32_t connid; ++} emu_stream_client_conn_data; ++ ++int8_t stream_server_thread_init = 0; ++char emu_stream_source_host[256] = {"127.0.0.1"}; ++int32_t emu_stream_source_port = 8001; ++char *emu_stream_source_auth = NULL; ++int32_t emu_stream_relay_port = 17999; ++int8_t emu_stream_emm_enabled = 0; ++uint32_t cluster_size = 50; ++ ++static uint8_t emu_stream_server_mutex_init = 0; ++static pthread_mutex_t emu_stream_server_mutex; ++static int32_t glistenfd, gconncount = 0, gconnfd[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++ ++#ifdef WITH_EMU ++pthread_mutex_t emu_fixed_key_srvid_mutex; ++uint16_t emu_stream_cur_srvid[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++int8_t stream_server_has_ecm[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++ ++pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS]; ++#endif ++ ++static void SearchTsPackets(uint8_t *buf, uint32_t bufLength, uint16_t *packetSize, uint16_t *startOffset) ++{ ++ uint32_t i; ++ ++ (*packetSize) = 0; ++ (*startOffset) = 0; ++ ++ for(i=0; i free_data_length ? free_data_length : (len-offset); ++ ++ memcpy(data+(*data_pos), buf+offset, copySize); ++ (*data_pos) += copySize; ++ ++ found_start = 0; ++ for(i=0; i < *data_pos; i++) ++ { ++ if((data[i] & table_mask) == table_id) ++ { ++ if(i != 0) ++ { ++ if((*data_pos)-i > i) ++ { memmove(data, &data[i], (*data_pos)-i); } ++ else ++ { memcpy(data, &data[i], (*data_pos)-i); } ++ ++ *data_pos -= i; ++ } ++ found_start = 1; ++ break; ++ } ++ } ++ if(!found_start) ++ { *flag = 0; return; } ++ ++ *flag = 2; ++ ++ if(*data_pos < 3) ++ { return; } ++ ++ section_length = SCT_LEN(data); ++ ++ if(section_length > data_length || section_length < min_table_length) ++ { *flag = 0; return; } ++ ++ if((*data_pos) < section_length) ++ { return; } ++ ++ func(cdata); ++ ++ found_start = 0; ++ for(i=section_length; i < *data_pos; i++) ++ { ++ if((data[i] & table_mask) == table_id) ++ { ++ if((*data_pos)-i > i) ++ { memmove(data, &data[i], (*data_pos)-i); } ++ else ++ { memcpy(data, &data[i], (*data_pos)-i); } ++ ++ *data_pos -= i; ++ found_start = 1; ++ break; ++ } ++ } ++ if(!found_start) ++ { *data_pos = 0; } ++ ++ *flag = 1; ++} ++ ++static void ParsePATData(emu_stream_client_data *cdata) ++{ ++ uint8_t* data = cdata->pat_data; ++ uint16_t section_length = SCT_LEN(data); ++ uint16_t srvid; ++ int32_t i; ++ ++ for(i=8; i+7srvid == srvid) ++ { ++ cdata->pmt_pid = b2i(2, data+i+2) & 0x1FFF; ++ cs_log_dbg(D_READER, "Stream %i found pmt pid: 0x%04X (%i)",cdata->connid, cdata->pmt_pid, cdata->pmt_pid); ++ break; ++ } ++ } ++} ++ ++static void ParsePMTData(emu_stream_client_data *cdata) ++{ ++ uint8_t* data = cdata->pmt_data; ++ ++ uint16_t section_length = SCT_LEN(data); ++ int32_t i; ++ uint16_t program_info_length = 0, es_info_length = 0; ++ uint8_t descriptor_tag = 0, descriptor_length = 0; ++ uint8_t stream_type; ++ uint16_t stream_pid, caid; ++ ++ cdata->pcr_pid = b2i(2, data+8) &0x1FFF; ++ if(cdata->pcr_pid != 0x1FFF) ++ { ++ cs_log_dbg(D_READER, "Stream %i found pcr pid: 0x%04X (%i)",cdata->connid, cdata->pcr_pid, cdata->pcr_pid); ++ } ++ ++ program_info_length = b2i(2, data+10) &0xFFF; ++ ++ if(12+program_info_length >= section_length) ++ { return; } ++ ++ for(i=12; i+1 < 12+program_info_length; i+=descriptor_length+2) ++ { ++ descriptor_tag = data[i]; ++ descriptor_length = data[i+1]; ++ ++ if(descriptor_length < 1) ++ { break; } ++ ++ if(i+1+descriptor_length >= 12+program_info_length) ++ { break; } ++ ++ if(descriptor_tag == 0x09 && descriptor_length >= 4) ++ { ++ caid = b2i(2, data+i+2); ++ ++ if(caid>>8 == 0x0E) ++ { ++ cdata->ecm_pid = b2i(2, data+i+4) &0x1FFF; ++ cs_log_dbg(D_READER, "Stream %i found ecm pid: 0x%04X (%i)", cdata->connid, cdata->ecm_pid, cdata->ecm_pid); ++ break; ++ } ++ } ++ } ++ ++ for(i=12+program_info_length; i+4video_pid = stream_pid; ++ cs_log_dbg(D_READER, "Stream %i found video pid: 0x%04X (%i)",cdata->connid, stream_pid, stream_pid); ++ } ++ ++ else if(stream_type == 0x03 || stream_type == 0x04 || stream_type == 0x05 || stream_type == 0x06 || ++ stream_type == 0x0F || stream_type == 0x11 || (stream_type >= 0x81 && stream_type <= 0x87) || stream_type == 0x8A) ++ { ++ if(cdata->audio_pid_count >= EMU_STREAM_MAX_AUDIO_SUB_TRACKS) ++ { continue; } ++ ++ cdata->audio_pids[cdata->audio_pid_count] = stream_pid; ++ cdata->audio_pid_count++; ++ cs_log_dbg(D_READER, "Stream %i found audio pid: 0x%04X (%i)", cdata->connid, stream_pid, stream_pid); ++ } ++ } ++} ++ ++static void ParseCATData(emu_stream_client_data *cdata) ++{ ++ uint8_t* data = cdata->cat_data; ++ uint32_t i; ++ ++ for(i = 8; i < (b2i(2, data + 1)&0xFFF) - 1; i += data[i + 1] + 2) ++ { ++ if(data[i] != 0x09) { continue; } ++ ++ uint16_t caid = b2i(2, data + i + 2); ++ uint16_t emm_pid = b2i(2, data + i +4)&0x1FFF; ++ ++ if(caid>>8 == 0x0E) ++ { ++ cdata->emm_pid = emm_pid; ++ cs_log_dbg(D_READER, "Stream %i found audio pid: 0x%04X (%i)", cdata->connid, emm_pid, emm_pid); ++ break; ++ } ++ } ++} ++ ++static void ParseEMMData(emu_stream_client_data *cdata) ++{ ++ uint8_t* data = cdata->emm_data; ++ uint32_t keysAdded = 0; ++ ++ ProcessEMM(NULL, 0x0E00, 0, data, &keysAdded); ++ ++ if(keysAdded) ++ { ++ cs_log("Stream %i found %i keys", cdata->connid, keysAdded); ++ } ++} ++ ++static void ParseECMData(emu_stream_client_data *cdata) ++{ ++ uint8_t* data = cdata->ecm_data; ++ uint16_t section_length = SCT_LEN(data); ++ uint8_t dcw[16]; ++ ++ if(section_length < 0xb) ++ { return; } ++ ++ if(data[0xb] > cdata->ecm_nb || (cdata->ecm_nb == 255 && data[0xb] == 0) ++ || ((cdata->ecm_nb - data[0xb]) > 5)) ++ { ++ cdata->ecm_nb = data[0xb]; ++#ifdef WITH_EMU ++ PowervuECM(data, dcw, cdata->srvid, &cdata->key, NULL); ++#else ++ PowervuECM(data, dcw, &cdata->key); ++#endif ++ } ++} ++ ++static void ParseTSPackets(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize) ++{ ++ uint32_t i, j, k; ++ uint32_t tsHeader; ++ uint16_t pid, offset; ++ uint8_t scramblingControl, payloadStart, oddeven; ++ int8_t oddKeyUsed; ++ uint32_t *deskey; ++ uint8_t *pdata; ++ uint8_t *packetClusterA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS][64]; // separate cluster arrays for video and each audio track ++ uint8_t *packetClusterV[256]; ++ void *csakeyA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS] = {0}; ++ void *csakeyV = 0; ++ emu_stream_client_key_data *keydata; ++ uint32_t scrambled_packets = 0; ++ uint32_t scrambled_packetsA[EMU_STREAM_MAX_AUDIO_SUB_TRACKS] = {0}; ++ packetClusterV[0] = NULL; ++ uint32_t cs =0; // video cluster start ++ uint32_t ce =1; // video cluster end ++ uint32_t csa[EMU_STREAM_MAX_AUDIO_SUB_TRACKS] = {0}; // cluster index for audio tracks ++ ++ for(i=0; i> 8; ++ scramblingControl = tsHeader & 0xc0; ++ payloadStart = (tsHeader & 0x400000) >> 22; ++ ++ if(tsHeader & 0x20) ++ { offset = 4 + stream_buf[i+4] + 1; } ++ else ++ { offset = 4; } ++ ++ if(packetSize-offset < 1) ++ { continue; } ++ ++ if(pid == 1) ++ { ++ // set to null pid ++ stream_buf[i+1] |= 0x1f; ++ stream_buf[i+2] = 0xff; ++ ++ if(emu_stream_emm_enabled && !data->emm_pid) ++ { ++ ParseTSData(0x01, 0xFF, 8, &data->have_cat_data, data->cat_data, sizeof(data->cat_data), &data->cat_data_pos, payloadStart, ++ stream_buf+i+offset, packetSize-offset, ParseCATData, data); ++ continue; ++ } ++ } ++ ++ if(emu_stream_emm_enabled && data->emm_pid && pid == data->emm_pid) ++ { ++ // set to null pid ++ stream_buf[i+1] |= 0x1f; ++ stream_buf[i+2] = 0xff; ++ ++ ParseTSData(0x80, 0xF0, 3, &data->have_emm_data, data->emm_data, sizeof(data->emm_data), &data->emm_data_pos, payloadStart, ++ stream_buf+i+offset, packetSize-offset, ParseEMMData, data); ++ continue; ++ } ++ ++ if(pid == 0 && !data->pmt_pid) ++ { ++ ParseTSData(0x00, 0xFF, 16, &data->have_pat_data, data->pat_data, sizeof(data->pat_data), &data->pat_data_pos, payloadStart, ++ stream_buf+i+offset, packetSize-offset, ParsePATData, data); ++ continue; ++ } ++ ++ if(!data->ecm_pid && pid == data->pmt_pid) ++ { ++ ParseTSData(0x02, 0xFF, 21, &data->have_pmt_data, data->pmt_data, sizeof(data->pmt_data), &data->pmt_data_pos, payloadStart, ++ stream_buf+i+offset, packetSize-offset, ParsePMTData, data); ++ continue; ++ } ++ ++ if(data->ecm_pid && pid == data->ecm_pid) ++ { ++#ifdef WITH_EMU ++ stream_server_has_ecm[data->connid] = 1; ++#endif ++ ++ // set to null pid ++ stream_buf[i+1] |= 0x1f; ++ stream_buf[i+2] = 0xff; ++ ++ ParseTSData(0x80, 0xFE, 3, &data->have_ecm_data, data->ecm_data, sizeof(data->ecm_data), &data->ecm_data_pos, payloadStart, ++ stream_buf+i+offset, packetSize-offset, ParseECMData, data); ++ continue; ++ } ++ ++ if(scramblingControl == 0) ++ { continue; } ++ ++ if(!(stream_buf[i+3] & 0x10)) ++ { ++ stream_buf[i+3] &= 0x3F; ++ continue; ++ } ++ ++ oddKeyUsed = scramblingControl == 0xC0 ? 1 : 0; ++ ++#ifdef WITH_EMU ++ if(!stream_server_has_ecm[data->connid]) ++ { ++ keydata = &emu_fixed_key_data[data->connid]; ++ SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[data->connid]); ++ data->key.pvu_csa_used = keydata->pvu_csa_used; ++ } ++ else ++ { ++#endif ++ keydata = &data->key; ++#ifdef WITH_EMU ++ } ++#endif ++ ++ if(keydata->pvu_csa_used) ++ { ++ oddeven = scramblingControl; // for detecting odd/even switch ++ ++ if(pid == data->video_pid) // start with video pid, since it is most dominant ++ { ++ csakeyV = keydata->pvu_csa_ks[PVU_CW_VID]; ++ ++ if(csakeyV !=NULL) ++ { ++ cs=0; ++ ce=1; ++ packetClusterV[cs] = stream_buf+i; // set first cluster start ++ packetClusterV[ce] = stream_buf+i+packetSize-1; ++ scrambled_packets=1; ++ ++ for(j = i+packetSize; j < bufLength; j += packetSize) // Now iterate through the rest of the packets and create clusters for batch decryption ++ { ++ tsHeader = b2i(4, stream_buf+j); ++ pid = (tsHeader & 0x1fff00) >> 8; ++ if(pid == data->video_pid) ++ { ++ if(oddeven != (tsHeader & 0xc0)) // changed key so stop adding clusters ++ { ++ break; ++ } ++ if(cs > ce) // First video packet for each cluster ++ { ++ packetClusterV[cs] = stream_buf+j; ++ ce = cs+1; ++ } ++ ++ scrambled_packets++; ++ } ++ else ++ { ++ if(cs < ce) // First non-video packet - need to set end of video cluster ++ { ++ packetClusterV[ce] = stream_buf+j-1; ++ cs = ce+1; ++ } ++ ++ if((tsHeader & 0xc0) == 0) { ++ continue; ++ } ++ ++ if(oddeven != (tsHeader & 0xc0)) // changed key so stop adding clusters ++ { ++ j = bufLength; // to break out of outer loop also ++ break; ++ } ++ ++ for(k = 0; k < data->audio_pid_count; k++) // Check for audio tracks and create single packet clusters ++ { ++ if(pid == data->audio_pids[k]) ++ { ++ packetClusterA[k][csa[k]] = stream_buf+j; ++ csa[k]++; ++ packetClusterA[k][csa[k]] = stream_buf+j+packetSize-1; ++ csa[k]++; ++ scrambled_packetsA[k]++; ++ } ++ } ++ } ++ } ++ ++ if( cs > ce ) // last packet was not a video packet, so set null for end of all clusters ++ { packetClusterV[cs] = NULL; } ++ else ++ { ++ if(scrambled_packets > 1) // last packet was a video packet, so set end of cluster to end of last packet ++ { ++ packetClusterV[ce] = stream_buf+j-1; ++ } ++ packetClusterV[ce+1] = NULL; // add null to end of cluster list ++ } ++ ++ while( j >= cluster_size ) ++ { j = decrypt_packets(csakeyV, packetClusterV); } ++ ++ for(k = 0; k < data->audio_pid_count; k++) ++ { ++ if(scrambled_packetsA[k]) // if audio track has scrambled packets, set null to mark end and decrypt ++ { ++ csakeyA[k] = keydata->pvu_csa_ks[PVU_CW_A1+k]; ++ packetClusterA[k][csa[k]] = NULL; ++ decrypt_packets(csakeyA[k], packetClusterA[k]); ++ csa[k]=0; ++ scrambled_packetsA[k] = 0; ++ } ++ } ++ } ++ } ++ else ++ { ++ for(j = 0; j < data->audio_pid_count; j++) ++ if(pid == data->audio_pids[j]) ++ { csakeyA[0] = keydata->pvu_csa_ks[PVU_CW_A1+j]; } ++ ++ if(csakeyA[0] != NULL) ++ { ++ packetClusterA[0][0] = stream_buf+i; ++ packetClusterA[0][1] = stream_buf+i+packetSize -1; ++ packetClusterA[0][2] = NULL; ++ decrypt_packets(csakeyA[0], packetClusterA[0]); ++ } ++ } ++ } ++ else ++ { ++ deskey = NULL; ++ ++ if(pid == data->video_pid) ++ { deskey = keydata->pvu_des_ks[PVU_CW_VID][oddKeyUsed]; } ++ else ++ { ++ for(j = 0; j < data->audio_pid_count; j++) ++ if(pid == data->audio_pids[j]) ++ { deskey = keydata->pvu_des_ks[PVU_CW_A1+j][oddKeyUsed]; } ++ } ++ ++ if(deskey == NULL) ++ { ++ deskey = keydata->pvu_des_ks[PVU_CW_HSD][oddKeyUsed]; ++ } ++ ++ for(j = offset; j+7 < 188; j += 8) ++ { ++ pdata = stream_buf+i+j; ++ des(pdata, deskey, 0); ++ } ++ ++ stream_buf[i+3] &= 0x3F; ++ } ++ ++#ifdef WITH_EMU ++ if(!stream_server_has_ecm[data->connid]) ++ { ++ SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[data->connid]); ++ } ++#endif ++ } ++} ++ ++static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *stream_path) ++{ ++ struct sockaddr_in cservaddr; ++ IN_ADDR_T in_addr; ++ ++ int32_t streamfd = socket(AF_INET, SOCK_STREAM, 0); ++ if(streamfd == -1) ++ { return -1; } ++ ++ struct timeval tv; ++ tv.tv_sec = 2; ++ tv.tv_usec = 0; ++ if(setsockopt(streamfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv)) ++ { ++ cs_log("ERROR: setsockopt() failed for SO_RCVTIMEO"); ++ return -1; ++ } ++ ++ bzero(&cservaddr, sizeof(cservaddr)); ++ cservaddr.sin_family = AF_INET; ++ cs_resolve(emu_stream_source_host, &in_addr, NULL, NULL); ++ SIN_GET_ADDR(cservaddr) = in_addr; ++ cservaddr.sin_port = htons(emu_stream_source_port); ++ ++ if(connect(streamfd, (struct sockaddr *)&cservaddr, sizeof(cservaddr)) == -1) ++ { return -1; } ++ if(emu_stream_source_auth) ++ { ++ snprintf(http_buf, http_buf_len, "GET %s HTTP/1.1\nHost: %s:%u\n" ++ "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0\n" ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n" ++ "Accept-Language: en-US\n" ++ "Authorization: Basic %s\n" ++ "Connection: keep-alive\n\n", stream_path, emu_stream_source_host, emu_stream_source_port, emu_stream_source_auth); ++ } ++ else ++ { ++ snprintf(http_buf, http_buf_len, "GET %s HTTP/1.1\nHost: %s:%u\n" ++ "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0\n" ++ "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n" ++ "Accept-Language: en-US\n" ++ "Connection: keep-alive\n\n", stream_path, emu_stream_source_host, emu_stream_source_port); ++ } ++ ++ if(send(streamfd, http_buf, strlen(http_buf), 0) == -1) ++ { return -1; } ++ ++ return streamfd; ++} ++ ++static void stream_client_disconnect(emu_stream_client_conn_data *conndata) ++{ ++ int32_t i; ++ ++#ifdef WITH_EMU ++ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); ++ emu_stream_cur_srvid[conndata->connid] = NO_SRVID_VALUE; ++ stream_server_has_ecm[conndata->connid] = 0; ++ SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); ++#endif ++ ++ SAFE_MUTEX_LOCK(&emu_stream_server_mutex); ++ for(i=0; iconnfd) ++ { ++ gconnfd[i] = -1; ++ gconncount--; ++ } ++ } ++ SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex); ++ ++ shutdown(conndata->connfd, 2); ++ close(conndata->connfd); ++ ++ cs_log("Stream client %i disconnected",conndata->connid); ++ ++ NULLFREE(conndata); ++} ++ ++static void *stream_client_handler(void *arg) ++{ ++#define EMU_DVB_MAX_TS_PACKETS 278 ++#define EMU_DVB_BUFFER_SIZE_CSA 188*EMU_DVB_MAX_TS_PACKETS ++#define EMU_DVB_BUFFER_WAIT_CSA 188*(EMU_DVB_MAX_TS_PACKETS-128) ++#define EMU_DVB_BUFFER_SIZE_DES 188*32 ++#define EMU_DVB_BUFFER_WAIT_DES 188*29 ++#define EMU_DVB_BUFFER_SIZE EMU_DVB_BUFFER_SIZE_CSA ++ ++ emu_stream_client_conn_data *conndata = (emu_stream_client_conn_data *)arg; ++ char *http_buf, stream_path[255], stream_path_copy[255]; ++ int32_t streamfd; ++ int32_t clientStatus, streamStatus; ++ uint8_t *stream_buf; ++ uint16_t packetCount = 0, packetSize = 0, startOffset = 0; ++ uint32_t remainingDataPos, remainingDataLength; ++ int32_t cur_dvb_buffer_size, cur_dvb_buffer_wait; ++ int32_t bytesRead = 0; ++ emu_stream_client_data *data; ++ int8_t streamConnectErrorCount = 0; ++ int8_t streamDataErrorCount = 0; ++ int32_t i, srvidtmp; ++ char *saveptr, *token; ++ char http_version[4]; ++ int32_t http_status_code = 0; ++ ++ cs_log("Stream client %i connected", conndata->connid); ++ ++ if(!cs_malloc(&http_buf, 1024)) ++ { ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++ if(!cs_malloc(&stream_buf, EMU_DVB_BUFFER_SIZE)) ++ { ++ NULLFREE(http_buf); ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++ if(!cs_malloc(&data, sizeof(emu_stream_client_data))) ++ { ++ NULLFREE(http_buf); ++ NULLFREE(stream_buf); ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++ clientStatus = recv(conndata->connfd, http_buf, 1024, 0); ++ if(clientStatus < 1) ++ { ++ NULLFREE(http_buf); ++ NULLFREE(stream_buf); ++ NULLFREE(data); ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++ http_buf[1023] = '\0'; ++ if(sscanf(http_buf, "GET %254s ", stream_path) < 1) ++ { ++ NULLFREE(http_buf); ++ NULLFREE(stream_buf); ++ NULLFREE(data); ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++ cs_strncpy(stream_path_copy, stream_path, sizeof(stream_path)); ++ ++ token = strtok_r(stream_path_copy, ":", &saveptr); ++ ++ for(i=0; token != NULL && i<3; i++) ++ { ++ token = strtok_r(NULL, ":", &saveptr); ++ if(token == NULL) ++ { break; } ++ } ++ if(token != NULL) ++ { ++ if(sscanf(token, "%x", &srvidtmp) < 1) ++ { ++ token = NULL; ++ } ++ else ++ { ++ data->srvid = srvidtmp & 0xFFFF; ++ } ++ } ++ ++ if(token == NULL) ++ { ++ NULLFREE(http_buf); ++ NULLFREE(stream_buf); ++ NULLFREE(data); ++ stream_client_disconnect(conndata); ++ return NULL; ++ } ++ ++#ifdef WITH_EMU ++ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); ++ emu_stream_cur_srvid[conndata->connid] = data->srvid; ++ stream_server_has_ecm[conndata->connid] = 0; ++ SAFE_MUTEX_UNLOCK(&emu_fixed_key_srvid_mutex); ++#endif ++ ++ cs_log("Stream client %i request %s", conndata->connid, stream_path); ++ ++ snprintf(http_buf, 1024, "HTTP/1.0 200 OK\nConnection: Close\nContent-Type: video/mpeg\nServer: stream_enigma2\n\n"); ++ clientStatus = send(conndata->connfd, http_buf, strlen(http_buf), 0); ++ ++ data->connid = conndata->connid; ++ ++ while(!exit_oscam && clientStatus != -1 && streamConnectErrorCount < 3 && streamDataErrorCount < 15) ++ { ++ streamfd = connect_to_stream(http_buf, 1024, stream_path); ++ if(streamfd == -1) ++ { ++ cs_log("WARNING: stream client %i cannot connect to stream source", conndata->connid); ++ streamConnectErrorCount++; ++ cs_sleepms(500); ++ continue; ++ } ++ ++ streamStatus = 0; ++ bytesRead = 0; ++ ++ while(!exit_oscam && clientStatus != -1 && streamStatus != -1 && streamConnectErrorCount < 3 && streamDataErrorCount < 15) ++ { ++ if(data->key.pvu_csa_used) ++ { ++ cur_dvb_buffer_size = EMU_DVB_BUFFER_SIZE_CSA; ++ cur_dvb_buffer_wait = EMU_DVB_BUFFER_WAIT_CSA; ++ } ++ else ++ { ++ cur_dvb_buffer_size = EMU_DVB_BUFFER_SIZE_DES; ++ cur_dvb_buffer_wait = EMU_DVB_BUFFER_WAIT_DES; ++ } ++ ++ streamStatus = recv(streamfd, stream_buf+bytesRead, cur_dvb_buffer_size-bytesRead, MSG_WAITALL); ++ if(streamStatus == 0) // socket closed ++ { ++ cs_log("WARNING: stream client %i - stream source closed connection", conndata->connid); ++ streamConnectErrorCount++; ++ cs_sleepms(100); ++ break; ++ } ++ ++ if(streamStatus < 0) // error ++ { ++ if ((errno == EWOULDBLOCK) | (errno == EAGAIN)) { ++ cs_log("WARNING: stream client %i no data from stream source", conndata->connid); ++ streamDataErrorCount++; // 2 sec timeout * 15 = 30 seconds no data -> close ++ cs_sleepms(100); ++ continue; ++ } ++ ++ cs_log("WARNING: stream client %i error receiving data from stream source", conndata->connid); ++ streamConnectErrorCount++; ++ cs_sleepms(100); ++ break; ++ } ++ ++ if(streamStatus < cur_dvb_buffer_size-bytesRead) // probably just received header but no stream ++ { ++ if(!bytesRead && streamStatus > 13 && ++ sscanf((const char*)stream_buf, "HTTP/%3s %d ", http_version , &http_status_code) == 2 && ++ http_status_code != 200) ++ { ++ cs_log("ERROR: stream client %i got %d response from stream source", conndata->connid, http_status_code); ++ streamConnectErrorCount++; ++ cs_sleepms(100); ++ break; ++ } ++ else ++ { ++ cs_log_dbg(0, "WARNING: stream client %i non-full buffer from stream source", conndata->connid); ++ streamDataErrorCount++; ++ cs_sleepms(100); ++ } ++ } ++ else ++ { ++ streamDataErrorCount = 0; ++ } ++ ++ streamConnectErrorCount = 0; ++ bytesRead += streamStatus; ++ ++ if(bytesRead >= cur_dvb_buffer_wait) ++ { ++ startOffset = 0; ++ if(stream_buf[0] != 0x47 || packetSize == 0) // only search if not starting on ts packet or unknown packet size ++ { ++ SearchTsPackets(stream_buf, bytesRead, &packetSize, &startOffset); ++ } ++ if(packetSize == 0) ++ { ++ bytesRead = 0; ++ } ++ else ++ { ++ packetCount = ((bytesRead-startOffset) / packetSize); ++ ++ ParseTSPackets(data, stream_buf+startOffset, packetCount*packetSize, packetSize); ++ ++ clientStatus = send(conndata->connfd, stream_buf+startOffset, packetCount*packetSize, 0); ++ ++ remainingDataPos = startOffset+(packetCount*packetSize); ++ remainingDataLength = bytesRead-remainingDataPos; ++ ++ if(remainingDataPos < remainingDataLength) ++ { memmove(stream_buf, stream_buf+remainingDataPos, remainingDataLength); } ++ else ++ { memcpy(stream_buf, stream_buf+remainingDataPos, remainingDataLength); } ++ ++ bytesRead = remainingDataLength; ++ } ++ } ++ } ++ ++ close(streamfd); ++ } ++ ++ NULLFREE(http_buf); ++ NULLFREE(stream_buf); ++ for(i=0; i<8; i++) ++ { ++ if(data->key.pvu_csa_ks[i]) ++ { free_key_struct(data->key.pvu_csa_ks[i]); } ++ } ++ NULLFREE(data); ++ ++ stream_client_disconnect(conndata); ++ return NULL; ++} ++ ++void *stream_server(void *UNUSED(a)) ++{ ++ struct sockaddr_in servaddr, cliaddr; ++ socklen_t clilen; ++ int32_t connfd, reuse = 1, i; ++ int8_t connaccepted; ++ emu_stream_client_conn_data *conndata; ++ ++ cluster_size = get_internal_parallelism(); ++ cs_log("INFO: FFDecsa parallel mode = %d", cluster_size); ++ ++ if(!emu_stream_server_mutex_init) ++ { ++ SAFE_MUTEX_INIT(&emu_stream_server_mutex, NULL); ++ emu_stream_server_mutex_init = 1; ++ } ++ ++#ifdef WITH_EMU ++ SAFE_MUTEX_LOCK(&emu_fixed_key_srvid_mutex); ++ for(i=0; iconnfd = connfd; ++ conndata->connid = i; ++ ++ break; ++ } ++ } ++ } ++ SAFE_MUTEX_UNLOCK(&emu_stream_server_mutex); ++ } ++ ++ if(connaccepted) ++ { ++ int on = 1; ++ if(setsockopt(connfd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) ++ { ++ cs_log("ERROR: stream client %i setsockopt() failed for TCP_NODELAY", conndata->connid); ++ } ++ ++ start_thread("emu stream client", stream_client_handler, (void*)conndata, NULL, 1, 0); ++ } ++ else ++ { ++ shutdown(connfd, 2); ++ close(connfd); ++ cs_log("ERROR: stream server client dropped because of too many connections (%i)", EMU_STREAM_SERVER_MAX_CONNECTIONS); ++ } ++ ++ cs_sleepms(20); ++ } ++ ++ close(glistenfd); ++ ++ return NULL; ++} ++ ++#ifdef WITH_EMU ++void *stream_key_delayer(void *UNUSED(arg)) ++{ ++ int32_t i, j; ++ emu_stream_client_key_data* cdata; ++ LL_ITER it; ++ emu_stream_cw_item *item; ++ struct timeb t_now; ++ ++ while(!exit_oscam) ++ { ++ cs_ftime(&t_now); ++ ++ for(i=0; iwrite_time) < 0) ++ { ++ break; ++ } ++ ++ SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[i]); ++ ++ cdata = &emu_fixed_key_data[i]; ++ ++ for(j=0; j<8; j++) ++ { ++ if(item->csa_used) ++ { ++ if(cdata->pvu_csa_ks[j] == NULL) ++ { cdata->pvu_csa_ks[j] = get_key_struct(); } ++ ++ if(item->is_even) ++ { set_even_control_word(cdata->pvu_csa_ks[j], item->cw[j]); } ++ else ++ { set_odd_control_word(cdata->pvu_csa_ks[j], item->cw[j]); } ++ ++ cdata->pvu_csa_used = 1; ++ } ++ else ++ { ++ if(item->is_even) ++ { des_set_key(item->cw[j], cdata->pvu_des_ks[j][0]); } ++ else ++ { des_set_key(item->cw[j], cdata->pvu_des_ks[j][1]); } ++ ++ cdata->pvu_csa_used = 0; ++ } ++ } ++ ++ SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[i]); ++ ++ ll_iter_remove_data(&it); ++ } ++ } ++ ++ cs_sleepms(25); ++ } ++ ++ return NULL; ++} ++#endif ++ ++void stop_stream_server(void) ++{ ++ int32_t i; ++ ++ SAFE_MUTEX_LOCK(&emu_stream_server_mutex); ++ for(i=0; ityp == R_EMU) ++ { ++ usr_filter = * get_emu_prids_for_caid(aureader, cfg.ncd_ptab.ports[cl->port_idx].ncd->ncd_ftab.filts[0].caid); ++ } ++ else ++#endif + mk_user_au_ftab(aureader, &usr_filter); + } + +@@ -948,6 +955,13 @@ static int8_t newcamd_auth_client(IN_ADD + else + { memset(&mbuf[8], 0, 6); } //mbuf[8] - mbuf[13] + ++#ifdef WITH_EMU ++ if(aureader && aureader->typ == R_EMU && caid_is_dre(pufilt->caid)) ++ { ++ mbuf[10] = aureader->dre36_force_group; ++ } ++#endif ++ + mbuf[14] = pufilt->nprids; + for(j = 0; j < pufilt->nprids; j++) + { +@@ -973,7 +987,7 @@ static int8_t newcamd_auth_client(IN_ADD + int32_t k, found; + uint32_t rprid; + found = 0; +- if(pufilt->caid == aureader->caid) ++ if(pufilt->caid == aureader->caid && aureader->typ != R_EMU) + { + for(k = 0; (k < aureader->nprov); k++) + { +@@ -999,6 +1013,32 @@ static int8_t newcamd_auth_client(IN_ADD + } + } + } ++#ifdef WITH_EMU ++ else if(aureader->typ == R_EMU) ++ { ++ if(caid_is_dre(pufilt->caid)) ++ { ++ found = 1; ++ memset(&mbuf[22 + 11 * j] ,0 ,4); ++ switch((uchar)(pufilt->prids[j])) ++ { ++ case 0x11: ++ mbuf[22 + 11 * j] = aureader->dre36_force_group; ++ break; ++ case 0x14: ++ mbuf[22 + 11 * j] = aureader->dre56_force_group; ++ break; ++ case 0xfe: ++ mbuf[22 + 11 * j] = 0xED; ++ mbuf[25 + 11 * j] = 0x02; ++ break; ++ default: ++ found = 0; ++ } ++ } ++ } ++#endif ++ + if(!found) + { + mbuf[22 + 11 * j] = 0x00; +diff -ruNp trunk.patches/module-newcamd-des.c trunk/module-newcamd-des.c +--- trunk.patches/module-newcamd-des.c 2018-04-03 02:44:10.106269046 +0300 ++++ trunk/module-newcamd-des.c 2018-04-03 03:20:07.662045399 +0300 +@@ -5,10 +5,7 @@ + #define DES_IP 1 + #define DES_IP_1 2 + #define DES_RIGHT 4 +-#define DES_HASH 8 + +-#define DES_ECM_CRYPT 0 +-#define DES_ECM_HASH DES_HASH + #define DES_ECS2_DECRYPT (DES_IP | DES_IP_1 | DES_RIGHT) + #define DES_ECS2_CRYPT (DES_IP | DES_IP_1) + +@@ -356,7 +353,7 @@ static void desRound(unsigned char left[ + swap(data - 4, data); + } + +-static void nc_des(unsigned char key[], unsigned char mode, unsigned char data[]) ++void nc_des(unsigned char key[], unsigned char mode, unsigned char data[]) + { + unsigned char i; + unsigned char left[8]; +diff -ruNp trunk.patches/module-newcamd-des.h trunk/module-newcamd-des.h +--- trunk.patches/module-newcamd-des.h 2018-04-03 02:44:10.214269951 +0300 ++++ trunk/module-newcamd-des.h 2018-04-03 03:20:07.662045399 +0300 +@@ -1,8 +1,15 @@ + #ifndef MODULE_NEWCAMD_DES_H_ + #define MODULE_NEWCAMD_DES_H_ + ++#define DES_HASH 8 ++ ++#define DES_ECM_CRYPT 0 ++#define DES_ECM_HASH DES_HASH ++ + int nc_des_encrypt(unsigned char *buffer, int len, unsigned char *deskey); + int nc_des_decrypt(unsigned char *buffer, int len, unsigned char *deskey); + unsigned char *nc_des_login_key_get(unsigned char *key1, unsigned char *key2, int len, unsigned char *des16); + ++ void nc_des(unsigned char key[], unsigned char mode, unsigned char data[]); ++ + #endif +diff -ruNp trunk.patches/module-stat.c trunk/module-stat.c +--- trunk.patches/module-stat.c 2018-04-03 02:44:09.474263747 +0300 ++++ trunk/module-stat.c 2018-04-03 03:20:07.662045399 +0300 +@@ -903,7 +903,7 @@ void check_lb_auto_betatunnel_mode(ECM_R + + uint16_t get_rdr_caid(struct s_reader *rdr) + { +- if(is_network_reader(rdr)) ++ if(is_network_reader(rdr) || rdr->typ == R_EMU) + { + return 0; //reader caid is not real caid + } +@@ -1301,7 +1301,7 @@ void stat_get_best_reader(ECM_REQUEST *e + for(ea = er->matching_rdr; ea; ea = ea->next) + { + rdr = ea->reader; +- if(is_network_reader(rdr)) //reader caid is not real caid ++ if(is_network_reader(rdr) || rdr->typ == R_EMU) //reader caid is not real caid + { + prv = ea; + continue; // proxy can convert or reject +diff -ruNp trunk.patches/module-webif.c trunk/module-webif.c +--- trunk.patches/module-webif.c 2018-04-03 02:44:08.458255227 +0300 ++++ trunk/module-webif.c 2018-04-03 03:20:07.662045399 +0300 +@@ -101,6 +101,7 @@ static bool use_srvid2 = false; + #define MNU_CFG_LCD 14 + #define MNU_CFG_MONITOR 15 + #define MNU_CFG_WEBIF 16 ++#define MNU_CFG_STREAMRELAY 17 + + /* constants for files.html submenuactivating */ + #define MNU_CFG_FVERSION 0 +@@ -134,8 +135,9 @@ static bool use_srvid2 = false; + #define MNU_GBX_FSTAINF 27 + #define MNU_GBX_FEXPINF 28 + #define MNU_GBX_INFOLOG 29 ++#define MNU_CFG_FSOFTCAMKEY 30 + +-#define MNU_CFG_TOTAL_ITEMS 30 // sum of items above. Use it for "All inactive" in function calls too. ++#define MNU_CFG_TOTAL_ITEMS 31 // sum of config or files items above. Use it for "All inactive" in function calls too. + + static void set_status_info_var(struct templatevars *vars, char *varname, int no_data, char *fmt, double value) { + if (no_data) +@@ -1219,6 +1221,34 @@ static char *send_oscam_config_scam(stru + } + #endif + ++#ifdef WITH_EMU ++#include "module-emulator-stream.h" ++ ++static char *send_oscam_config_streamrelay(struct templatevars *vars, struct uriparams *params) ++{ ++ setActiveSubMenu(vars, MNU_CFG_STREAMRELAY); ++ ++ webif_save_config("streamrelay", vars, params); ++ ++ tpl_printf(vars, TPLADD, "STREAM_SOURCE_HOST", "%s", cfg.emu_stream_source_host); ++ tpl_printf(vars, TPLADD, "STREAM_SOURCE_PORT", "%d", cfg.emu_stream_source_port); ++ if(cfg.emu_stream_source_auth_user) ++ { tpl_printf(vars, TPLADD, "STREAM_SOURCE_AUTH_USER", "%s", cfg.emu_stream_source_auth_user); } ++ if(cfg.emu_stream_source_auth_password) ++ { tpl_printf(vars, TPLADD, "STREAM_SOURCE_AUTH_PASSWORD", "%s", cfg.emu_stream_source_auth_password); } ++ tpl_printf(vars, TPLADD, "STREAM_RELAY_PORT", "%d", cfg.emu_stream_relay_port); ++ tpl_printf(vars, TPLADD, "STREAM_ECM_DELAY", "%d", cfg.emu_stream_ecm_delay); ++ ++ tpl_printf(vars, TPLADD, "TMP", "STREAMRELAYENABLEDSELECTED%d", cfg.emu_stream_relay_enabled); ++ tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); ++ ++ tpl_printf(vars, TPLADD, "TMP", "STREAMEMMENABLEDSELECTED%d", cfg.emu_stream_emm_enabled); ++ tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); ++ ++ return tpl_getTpl(vars, "CONFIGSTREAMRELAY"); ++} ++#endif ++ + #ifdef MODULE_CCCAM + static char *send_oscam_config_cccam(struct templatevars *vars, struct uriparams *params) + { +@@ -1557,6 +1587,10 @@ static char *send_oscam_config_dvbapi(st + tpl_printf(vars, TPLADD, "TMP", "EXTENDEDCWAPISELECTED%d", cfg.dvbapi_extended_cw_api); + tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); + ++ //extended_cw_pids (pid limiter) ++ tpl_printf(vars, TPLADD, "TMP", "EXTENDEDCWPIDSSELECTED%d", cfg.dvbapi_extended_cw_pids); ++ tpl_addVar(vars, TPLADD, tpl_getVar(vars, "TMP"), "selected"); ++ + //write_sdt_prov + if(cfg.dvbapi_write_sdt_prov > 0) + { tpl_addVar(vars, TPLADD, "WRITESDTPROVCHECKED", "checked"); } +@@ -1634,6 +1668,9 @@ static char *send_oscam_config(struct te + #ifdef MODULE_SCAM + else if(!strcmp(part, "scam")) { return send_oscam_config_scam(vars, params); } + #endif ++#ifdef WITH_EMU ++ else if(!strcmp(part, "streamrelay")) { return send_oscam_config_streamrelay(vars, params); } ++#endif + #ifdef MODULE_CCCAM + else if(!strcmp(part, "cccam")) { return send_oscam_config_cccam(vars, params); } + #endif +@@ -2096,7 +2133,7 @@ static char *send_oscam_reader_config(st + chk_reader("services", servicelabels, rdr); + chk_reader("lb_whitelist_services", servicelabelslb, rdr); + +- if(is_network_reader(rdr)) //physical readers make trouble if re-started ++ if(is_network_reader(rdr) || rdr->typ == R_EMU) //physical readers make trouble if re-started + { + restart_cardreader(rdr, 1); + } +@@ -2674,6 +2711,31 @@ static char *send_oscam_reader_config(st + tpl_addVar(vars, TPLADD, "USERSCRIPT", rdr->userscript); + #endif + ++#ifdef WITH_EMU ++ //emu_auproviders ++ value = mk_t_ftab(&rdr->emu_auproviders); ++ tpl_addVar(vars, TPLADD, "EMUAUPROVIDERS", value); ++ free_mk_t(value); ++ ++ // Date-coded BISS keys ++ if(!apicall) ++ { ++ tpl_addVar(vars, TPLADD, "EMUDATECODEDENABLED", (rdr->emu_datecodedenabled == 1) ? "checked" : ""); ++ } ++ else ++ { ++ tpl_addVar(vars, TPLADD, "EMUDATECODEDENABLED", (rdr->emu_datecodedenabled == 1) ? "1" : "0"); ++ } ++ ++ //extee ++ tpl_addVar(vars, TPLADD, "EXTEE36", rdr->extee36); ++ tpl_addVar(vars, TPLADD, "EXTEE56", rdr->extee56); ++ ++ //dre force group ++ tpl_printf(vars, TPLADD, "DRE36FORCEGROUP","%02X", rdr->dre36_force_group); ++ tpl_printf(vars, TPLADD, "DRE56FORCEGROUP","%02X", rdr->dre56_force_group); ++#endif ++ + tpl_addVar(vars, TPLADD, "PROTOCOL", reader_get_type_desc(rdr, 0)); + + // Show only parameters which needed for the reader +@@ -2695,6 +2757,9 @@ static char *send_oscam_reader_config(st + case R_CAMD35 : + tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGCAMD35BIT")); + break; ++ case R_EMU : ++ tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGEMUBIT")); ++ break; + case R_CS378X : + tpl_addVar(vars, TPLAPPEND, "READERDEPENDINGCONFIG", tpl_getTpl(vars, "READERCONFIGCS378XBIT")); + break; +@@ -4417,9 +4482,38 @@ static char *send_oscam_entitlement(stru + + tpl_addVar(vars, TPLAPPEND, "LOGHISTORY", "

New Structure:
"); + char tbuffer[83]; ++#ifdef WITH_EMU ++ char keyBuffer[1024]; ++#endif + int jsondelimiter = 0; + while((item = ll_iter_next(&itr))) + { ++#ifdef WITH_EMU ++ if(item->isKey) { ++ tpl_addVar(vars, TPLADD, "ENTSTARTDATE", ""); ++ tpl_addVar(vars, TPLADD, "ENTENDDATE", ""); ++ cs_hexdump(0, item->key, item->keyLength, keyBuffer, sizeof(keyBuffer)); ++ tpl_addVar(vars, TPLADD, "ENTEXPIERED", "e_valid"); ++ tpl_printf(vars, TPLADD, "ENTCAID", "%04X", item->caid); ++ if(item->caid == 0x2600) { ++ tpl_printf(vars, TPLADD, "ENTPROVID", "%08X", item->provid); ++ } ++ else { ++ tpl_printf(vars, TPLADD, "ENTPROVID", "%06X", item->provid); ++ } ++ tpl_addVar(vars, TPLADD, "ENTID", item->name); ++ tpl_addVar(vars, TPLADD, "ENTCLASS", keyBuffer); ++ if(item->isData) { tpl_addVar(vars, TPLADD, "ENTTYPE", "data"); } ++ else { tpl_addVar(vars, TPLADD, "ENTTYPE", "key"); } ++ tpl_addVar(vars, TPLADD, "ENTRESNAME", ""); ++ ++ if((strcmp(getParam(params, "hideexpired"), "1") != 0) || (item->end > now)) ++ { tpl_addVar(vars, TPLAPPEND, "READERENTENTRY", tpl_getTpl(vars, "ENTITLEMENTITEMBIT")); } ++ ++ continue; ++ } ++#endif ++ + localtime_r(&item->start, &start_t); + localtime_r(&item->end, &end_t); + +@@ -4895,6 +4989,9 @@ static char *send_oscam_status(struct te + #else + filtered = (type == cl->typ); + #endif ++#ifdef WITH_EMU ++ if(type == 'e' && cl->typ == 'r' && cl->reader->typ == R_EMU) filtered = 1; ++#endif + } + } + +@@ -6339,6 +6436,9 @@ static char *send_oscam_files(struct tem + { "expired.info", MNU_GBX_FEXPINF, FTYPE_GBOX }, // id 28 + { "info.log", MNU_GBX_INFOLOG, FTYPE_GBOX }, // id 29 + #endif ++#ifdef WITH_EMU ++ { "SoftCam.Key", MNU_CFG_FSOFTCAMKEY,FTYPE_CONFIG }, // id 30 ++#endif + { NULL, 0, 0 }, + }; + +@@ -6809,7 +6909,7 @@ static char *send_oscam_EMM_running(stru + else if(!proxy && rdr->csystem_active) // local active reader + { + csystem = rdr->csystem; +- caid = rdr->caid; ++ if(rdr->typ != R_EMU) caid = rdr->caid; + } + + if(csystem) +@@ -7816,8 +7916,8 @@ static int32_t readRequest(FILE * f, IN_ + memcpy(*result + bufsize, buf2, n); + bufsize += n; + +- //max request size 100kb +- if(bufsize > 102400) ++ //max request size 200kb ++ if(bufsize > 204800) + { + cs_log("error: too much data received from %s", cs_inet_ntoa(in)); + NULLFREE(*result); +diff -ruNp trunk.patches/module-webif-tpl.c trunk/module-webif-tpl.c +--- trunk.patches/module-webif-tpl.c 2018-04-03 02:44:09.754266095 +0300 ++++ trunk/module-webif-tpl.c 2018-04-03 03:20:07.662045399 +0300 +@@ -457,6 +457,7 @@ char *tpl_getUnparsedTpl(const char *nam + check_conf(WITH_SSL, ptr2); + check_conf(WITH_STAPI, ptr2); + check_conf(WITH_STAPI5, ptr2); ++ check_conf(WITH_EMU, ptr2); + } // for + if(ok == 0) + { +diff -ruNp trunk.patches/oscam-aes.c trunk/oscam-aes.c +--- trunk.patches/oscam-aes.c 2018-04-03 02:44:10.106269046 +0300 ++++ trunk/oscam-aes.c 2018-04-03 03:20:07.662045399 +0300 +@@ -37,6 +37,16 @@ void aes_encrypt_idx(struct aes_keys *ae + } + } + ++void aes_cbc_encrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv) ++{ ++ AES_cbc_encrypt(buf, buf, n, &aes->aeskey_encrypt, iv, AES_ENCRYPT); ++} ++ ++void aes_cbc_decrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv) ++{ ++ AES_cbc_encrypt(buf, buf, n, &aes->aeskey_decrypt, iv, AES_DECRYPT); ++} ++ + /* Creates an AES_ENTRY and adds it to the given linked list. */ + void add_aes_entry(AES_ENTRY **list, uint16_t caid, uint32_t ident, int32_t keyid, uchar *aesKey) + { +diff -ruNp trunk.patches/oscam-aes.h trunk/oscam-aes.h +--- trunk.patches/oscam-aes.h 2018-04-03 02:44:10.110269080 +0300 ++++ trunk/oscam-aes.h 2018-04-03 03:20:07.662045399 +0300 +@@ -5,6 +5,8 @@ void aes_set_key(struct aes_keys *aes, c + bool aes_set_key_alloc(struct aes_keys **aes, char *key); + void aes_decrypt(struct aes_keys *aes, uchar *buf, int32_t n); + void aes_encrypt_idx(struct aes_keys *aes, uchar *buf, int32_t n); ++void aes_cbc_encrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv); ++void aes_cbc_decrypt(struct aes_keys *aes, uchar *buf, int32_t n, uchar *iv); + + void add_aes_entry(AES_ENTRY **list, uint16_t caid, uint32_t ident, int32_t keyid, uchar *aesKey); + void parse_aes_entry(AES_ENTRY **list, char *label, char *value); +diff -ruNp trunk.patches/oscam.c trunk/oscam.c +--- trunk.patches/oscam.c 2018-04-03 03:10:28.813703490 +0300 ++++ trunk/oscam.c 2018-04-03 03:20:07.662045399 +0300 +@@ -41,6 +41,11 @@ + #include "reader-common.h" + #include "module-gbox.h" + ++#ifdef WITH_EMU ++ void add_emu_reader(void); ++ void stop_stream_server(void); ++#endif ++ + #ifdef WITH_SSL + #include + #include +@@ -422,6 +427,7 @@ static void write_versionfile(bool use_s + write_conf(CW_CYCLE_CHECK, "CW Cycle Check support"); + write_conf(LCDSUPPORT, "LCD support"); + write_conf(LEDSUPPORT, "LED support"); ++ write_conf(WITH_EMU, "Emulator support"); + switch (cs_getclocktype()) { + case CLOCK_TYPE_UNKNOWN : write_conf(CLOCKFIX, "Clockfix with UNKNOWN clock"); break; + case CLOCK_TYPE_REALTIME : write_conf(CLOCKFIX, "Clockfix with realtime clock"); break; +@@ -1640,6 +1646,9 @@ const struct s_cardreader *cardreaders[] + #ifdef CARDREADER_STINGER + &cardreader_stinger, + #endif ++#ifdef WITH_EMU ++ &cardreader_emu, ++#endif + NULL + }; + +@@ -1811,6 +1820,9 @@ int32_t main(int32_t argc, char *argv[]) + + init_sidtab(); + init_readerdb(); ++#ifdef WITH_EMU ++ add_emu_reader(); ++#endif + cfg.account = init_userdb(); + init_signal(); + init_provid(); +@@ -1898,6 +1910,9 @@ int32_t main(int32_t argc, char *argv[]) + if(!cfg.gsms_dis) + { stop_sms_sender(); } + #endif ++#ifdef WITH_EMU ++ stop_stream_server(); ++#endif + webif_close(); + azbox_close(); + coolapi_close_all(); +diff -ruNp trunk.patches/oscam-chk.c trunk/oscam-chk.c +--- trunk.patches/oscam-chk.c 2018-04-03 02:44:09.470263713 +0300 ++++ trunk/oscam-chk.c 2018-04-03 03:20:07.662045399 +0300 +@@ -758,7 +758,7 @@ int32_t matching_reader(ECM_REQUEST *er, + return 0; + } + +- if(!is_network_reader(rdr) && ((rdr->caid >> 8) != ((er->caid >> 8) & 0xFF) && (rdr->caid >> 8) != ((er->ocaid >> 8) & 0xFF))) ++ if(!(rdr->typ == R_EMU) && !is_network_reader(rdr) && ((rdr->caid >> 8) != ((er->caid >> 8) & 0xFF) && (rdr->caid >> 8) != ((er->ocaid >> 8) & 0xFF))) + { + if (!rdr->csystem) + return 0; +@@ -794,7 +794,7 @@ int32_t matching_reader(ECM_REQUEST *er, + } + + //Checking ident: +- if(!chk_rfilter(er, rdr)) ++ if(!(rdr->typ == R_EMU && (er->caid>>8 == 0x26 || er->caid == 0xFFFF)) && !chk_rfilter(er, rdr)) + { + cs_log_dbg(D_TRACE, "r-filter reader %s", rdr->label); + return (0); +@@ -853,7 +853,7 @@ int32_t matching_reader(ECM_REQUEST *er, + } + + //Checking entitlements: +- if(ll_count(rdr->ll_entitlements) > 0) ++ if(ll_count(rdr->ll_entitlements) > 0 && !(rdr->typ == R_EMU)) + { + LL_ITER itr = ll_iter_create(rdr->ll_entitlements); + S_ENTITLEMENT *item; +@@ -1024,7 +1024,7 @@ int32_t chk_caid(uint16_t caid, CAIDTAB + + int32_t chk_caid_rdr(struct s_reader *rdr, uint16_t caid) + { +- if(is_network_reader(rdr)) ++ if(is_network_reader(rdr) || rdr->typ == R_EMU) + { + return 1; //reader caid is not real caid + } +diff -ruNp trunk.patches/oscam-config-global.c trunk/oscam-config-global.c +--- trunk.patches/oscam-config-global.c 2018-04-03 02:44:08.394254690 +0300 ++++ trunk/oscam-config-global.c 2018-04-03 03:20:07.662045399 +0300 +@@ -854,6 +854,30 @@ static const struct config_list scam_opt + #else + static const struct config_list scam_opts[] = { DEF_LAST_OPT }; + #endif ++ ++#ifdef WITH_EMU ++static bool streamrelay_should_save_fn(void *UNUSED(var)) ++{ ++ return 1; ++} ++static const struct config_list streamrelay_opts[] = ++{ ++ DEF_OPT_SAVE_FUNC(streamrelay_should_save_fn), ++ DEF_OPT_STR("stream_source_host" , OFS(emu_stream_source_host), "127.0.0.1"), ++ DEF_OPT_INT32("stream_source_port" , OFS(emu_stream_source_port), 8001), ++ DEF_OPT_STR("stream_source_auth_user" , OFS(emu_stream_source_auth_user), NULL), ++ DEF_OPT_STR("stream_source_auth_password" , OFS(emu_stream_source_auth_password), NULL), ++ DEF_OPT_INT32("stream_relay_port" , OFS(emu_stream_relay_port), 17999), ++ DEF_OPT_UINT32("stream_ecm_delay" , OFS(emu_stream_ecm_delay), 600), ++ DEF_OPT_INT8("stream_relay_enabled" , OFS(emu_stream_relay_enabled), 1), ++ DEF_OPT_INT8("stream_emm_enabled" , OFS(emu_stream_emm_enabled), 1), ++ DEF_LAST_OPT ++}; ++#else ++static const struct config_list streamrelay_opts[] = { DEF_LAST_OPT }; ++#endif ++ ++ + #ifdef MODULE_RADEGAST + static bool radegast_should_save_fn(void *UNUSED(var)) + { +@@ -1262,6 +1286,7 @@ static const struct config_list dvbapi_o + DEF_OPT_INT8("read_sdt" , OFS(dvbapi_read_sdt), 0), + DEF_OPT_INT8("write_sdt_prov", OFS(dvbapi_write_sdt_prov), 0), + DEF_OPT_INT8("extended_cw_api", OFS(dvbapi_extended_cw_api), 0), ++ DEF_OPT_INT8("extended_cw_pids", OFS(dvbapi_extended_cw_pids), 64), // pid limiter + DEF_OPT_FUNC("boxtype" , OFS(dvbapi_boxtype), dvbapi_boxtype_fn), + DEF_OPT_FUNC("services" , OFS(dvbapi_sidtabs.ok), dvbapi_services_fn), + // OBSOLETE OPTIONS +@@ -1315,6 +1340,7 @@ static const struct config_sections osca + { "cccam", cccam_opts }, + { "pandora", pandora_opts }, + { "scam", scam_opts }, ++ { "streamrelay", streamrelay_opts }, + { "dvbapi", dvbapi_opts }, + { "monitor", monitor_opts }, + { "webif", webif_opts }, +diff -ruNp trunk.patches/oscam-config.h trunk/oscam-config.h +--- trunk.patches/oscam-config.h 2018-04-03 02:44:09.470263713 +0300 ++++ trunk/oscam-config.h 2018-04-03 03:20:07.662045399 +0300 +@@ -22,6 +22,7 @@ void free_reader(struct s_reader *rdr + int32_t free_readerdb(void); + int32_t write_server(void); + void reload_readerdb(void); ++void reader_fixups_fn(void *var); + + void chk_sidtab(char *token, char *value, struct s_sidtab *sidtab); + int32_t init_sidtab(void); +@@ -63,7 +64,8 @@ enum ftab_fn + FTAB_FBPCAID = 0x10, + FTAB_LOCALCARDS = 0x20, + FTAB_IGNCHKSMCAID = 0x40, +- FTAB_IGNCRCCEX4USERONLYFOR = 0x80 ++ FTAB_IGNCRCCEX4USERONLYFOR = 0x80, ++ FTAB_EMUAU = 0x100 + }; + + void ftab_fn(const char *token, char *value, void *setting, long ftab_type, FILE *f); +diff -ruNp trunk.patches/oscam-config-reader.c trunk/oscam-config-reader.c +--- trunk.patches/oscam-config-reader.c 2018-04-03 02:44:09.758266128 +0300 ++++ trunk/oscam-config-reader.c 2018-04-03 03:20:07.662045399 +0300 +@@ -109,6 +109,7 @@ static void protocol_fn(const char *toke + { "newcamd525", R_NEWCAMD }, + { "newcamd524", R_NEWCAMD }, + { "drecas", R_DRECAS }, ++ { "emu", R_EMU }, + { NULL , 0 } + }, *p; + int i; +@@ -448,6 +449,9 @@ void ftab_fn(const char *token, char *va + if(ftab_type & FTAB_FBPCAID) { rdr = container_of(setting, struct s_reader, fallback_percaid); } + if(ftab_type & FTAB_LOCALCARDS) { rdr = container_of(setting, struct s_reader, localcards); } + if(ftab_type & FTAB_IGNCHKSMCAID){ rdr = container_of(setting, struct s_reader, disablecrccws_only_for); } ++#ifdef WITH_EMU ++ if(ftab_type & FTAB_EMUAU) { rdr = container_of(setting, struct s_reader, emu_auproviders); } ++#endif + if(rdr) + { rdr->changes_since_shareupdate = 1; } + } +@@ -779,7 +783,7 @@ static void cooldowntime_fn(const char * + } + + +-static void reader_fixups_fn(void *var) ++void reader_fixups_fn(void *var) + { + struct s_reader *rdr = var; + #ifdef WITH_LB +@@ -923,6 +927,14 @@ static const struct config_list reader_o + #ifdef READER_DRECAS + DEF_OPT_STR("stmkeys" , OFS(stmkeys), NULL), + #endif ++#ifdef WITH_EMU ++ DEF_OPT_FUNC_X("emu_auproviders" , OFS(emu_auproviders), ftab_fn, FTAB_READER | FTAB_EMUAU), ++ DEF_OPT_INT8("emu_datecodedenabled" , OFS(emu_datecodedenabled), 0), ++ DEF_OPT_STR("extee36" , OFS(extee36), NULL), ++ DEF_OPT_STR("extee56" , OFS(extee56), NULL), ++ DEF_OPT_HEX("dre36_force_group" , OFS(dre36_force_group), 1), ++ DEF_OPT_HEX("dre56_force_group" , OFS(dre56_force_group), 1), ++#endif + DEF_OPT_INT8("deprecated" , OFS(deprecated), 0), + DEF_OPT_INT8("audisabled" , OFS(audisabled), 0), + DEF_OPT_FUNC("auprovid" , 0, auprovid_fn), +diff -ruNp trunk.patches/oscam-ecm.c trunk/oscam-ecm.c +--- trunk.patches/oscam-ecm.c 2018-04-03 02:44:08.174252846 +0300 ++++ trunk/oscam-ecm.c 2018-04-03 03:20:07.662045399 +0300 +@@ -1585,7 +1585,7 @@ int32_t write_ecm_answer(struct s_reader + + if(reader && cw && rc < E_NOTFOUND) + { +- if(cfg.disablecrccws == 0 && reader->disablecrccws == 0) ++ if(cfg.disablecrccws == 0 && reader->disablecrccws == 0 && ((er->caid >> 8) != 0x0E)) + { + uint8_t selectedForIgnChecksum = chk_if_ignore_checksum(er, cfg.disablecrccws, &cfg.disablecrccws_only_for) + + chk_if_ignore_checksum(er, reader->disablecrccws, &reader->disablecrccws_only_for); +diff -ruNp trunk.patches/oscam-emm.c trunk/oscam-emm.c +--- trunk.patches/oscam-emm.c 2018-04-03 02:44:09.758266128 +0300 ++++ trunk/oscam-emm.c 2018-04-03 03:20:07.662045399 +0300 +@@ -50,7 +50,14 @@ static int8_t do_simple_emm_filter(struc + unsigned int j, filter_count = 0; + + // Call cardsystems emm filter +- csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); ++ if(rdr->typ == R_EMU) ++ { ++ return 1; //valid emm ++ } ++ else ++ { ++ csystem->get_emm_filter(rdr, &dmx_filter, &filter_count); ++ } + + // Only check matching emmtypes: + uint8_t org_emmtype; +@@ -209,6 +216,24 @@ int32_t emm_reader_match(struct s_reader + rdr_log_dbg(reader, D_EMM, "reader auprovid = %06X fixup to %06X (ignoring last digit)", reader->auprovid, prid); + } + ++#ifdef WITH_EMU ++ if(reader->typ == R_EMU) ++ { ++ FILTER* emu_provids = get_emu_prids_for_caid(reader, caid); ++ if(emu_provids != NULL) ++ { ++ for(i = 0; i < emu_provids->nprids; i++) ++ { ++ if(provid == emu_provids->prids[i]) ++ { ++ return 1; ++ } ++ } ++ } ++ return 0; ++ } ++#endif ++ + if(prid == provid) + { + rdr_log_dbg(reader, D_EMM, "reader auprovid = %06X matching with emm provid = %06X -> SEND!", prid, provid); +diff -ruNp trunk.patches/oscam-string.c trunk/oscam-string.c +--- trunk.patches/oscam-string.c 2018-04-03 02:44:09.762266162 +0300 ++++ trunk/oscam-string.c 2018-04-03 03:20:07.662045399 +0300 +@@ -510,6 +510,62 @@ uint32_t crc32(uint32_t crc, const uint8 + return crc ^ 0xffffffffL; + } + ++static uint32_t fletcher_crc_table[256] = { ++ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, ++ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, ++ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, ++ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, ++ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, ++ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, ++ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, ++ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, ++ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, ++ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, ++ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, ++ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, ++ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, ++ 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, ++ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, ++ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, ++ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, ++ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, ++ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, ++ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, ++ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, ++ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, ++ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, ++ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, ++ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, ++ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, ++ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, ++ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, ++ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, ++ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, ++ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, ++ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, ++ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, ++ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, ++ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, ++ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, ++ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, ++ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, ++ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, ++ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, ++ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, ++ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, ++ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; ++ ++uint32_t fletcher_crc32(uint8_t *data, uint32_t len) ++{ ++ uint32_t i; ++ uint32_t crc = 0xffffffff; ++ ++ for (i=0; i> 24) ^ *data++) & 0xff]; ++ ++ return crc; ++} ++ + static uint16_t ccitt_crc_table [256] = + { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, +diff -ruNp trunk.patches/oscam-string.h trunk/oscam-string.h +--- trunk.patches/oscam-string.h 2018-04-03 02:44:10.090268912 +0300 ++++ trunk/oscam-string.h 2018-04-03 03:20:07.662045399 +0300 +@@ -37,6 +37,7 @@ void get_random_bytes_init(void); + void get_random_bytes(uint8_t *dst, uint32_t dst_len); + + uint32_t crc32(uint32_t crc, const uint8_t *buf, uint32_t len); ++uint32_t fletcher_crc32(uint8_t *data, uint32_t len); + uint16_t ccitt_crc(uint8_t *data, size_t length, uint16_t seed, uint16_t final); + uint32_t jhash(const char *key, size_t len); + +diff -ruNp trunk.patches/reader-common.c trunk/reader-common.c +--- trunk.patches/reader-common.c 2018-04-03 02:44:09.758266128 +0300 ++++ trunk/reader-common.c 2018-04-03 03:20:07.662045399 +0300 +@@ -15,6 +15,7 @@ + #include "reader-common.h" + //#include "csctapi/atr.h" + #include "csctapi/icc_async.h" ++#include "readers.h" + + extern const struct s_cardsystem *cardsystems[]; + extern char *RDR_CD_TXT[]; +@@ -142,6 +143,19 @@ void cardreader_poll_status(struct s_rea + static int32_t reader_get_cardsystem(struct s_reader *reader, ATR *atr) + { + int32_t i; ++ ++#ifdef WITH_EMU ++ if(reader->typ == R_EMU) ++ { ++ NULLFREE(reader->csystem_data); ++ rdr_log(reader, "found card system %s", reader_emu.desc); ++ reader->csystem = &reader_emu; ++ reader->csystem_active = true; ++ led_status_found_cardsystem(); ++ return (reader->csystem_active); ++ } ++#endif ++ + for(i = 0; cardsystems[i]; i++) + { + NULLFREE(reader->csystem_data); +diff -ruNp trunk.patches/readers.h trunk/readers.h +--- trunk.patches/readers.h 2018-04-03 02:44:09.762266162 +0300 ++++ trunk/readers.h 2018-04-03 03:20:07.662045399 +0300 +@@ -16,5 +16,6 @@ extern const struct s_cardsystem reader_ + extern const struct s_cardsystem reader_bulcrypt; + extern const struct s_cardsystem reader_griffin; + extern const struct s_cardsystem reader_dgcrypt; ++extern const struct s_cardsystem reader_emu; + + #endif +diff -ruNp trunk.patches/webif/config/dvbapi.html trunk/webif/config/dvbapi.html +--- trunk.patches/webif/config/dvbapi.html 2018-04-03 02:44:08.322254087 +0300 ++++ trunk/webif/config/dvbapi.html 2018-04-03 03:20:07.666045429 +0300 +@@ -53,7 +53,7 @@ + + + Write detected prov name to srvid: +- +\ В конце файла нет новой строки ++ ++ ++ Max pids for extended CWs ++ ++ ++ ++ +\ В конце файла нет новой строки +diff -ruNp trunk.patches/webif/config/menu.html trunk/webif/config/menu.html +--- trunk.patches/webif/config/menu.html 2018-04-03 02:44:08.458255227 +0300 ++++ trunk/webif/config/menu.html 2018-04-03 03:20:07.666045429 +0300 +@@ -16,6 +16,7 @@ + ##TPLCONFIGMENUDVBAPI## + ##TPLCONFIGMENULCD## + ##TPLCONFIGMENUMONITOR## ++##TPLCONFIGMENUSTREAMRELAY## +
  • WebIf
  • + + +diff -ruNp trunk.patches/webif/config/menu_streamrelay.html trunk/webif/config/menu_streamrelay.html +--- trunk.patches/webif/config/menu_streamrelay.html 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/webif/config/menu_streamrelay.html 2018-04-03 03:20:07.666045429 +0300 +@@ -0,0 +1 @@ ++
  • Stream Relay
  • +diff -ruNp trunk.patches/webif/config/streamrelay.html trunk/webif/config/streamrelay.html +--- trunk.patches/webif/config/streamrelay.html 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/webif/config/streamrelay.html 2018-04-03 03:20:07.666045429 +0300 +@@ -0,0 +1,25 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +\ В конце файла нет новой строки +diff -ruNp trunk.patches/webif/files/menu.html trunk/webif/files/menu.html +--- trunk.patches/webif/files/menu.html 2018-04-03 02:44:08.458255227 +0300 ++++ trunk/webif/files/menu.html 2018-04-03 03:20:07.666045429 +0300 +@@ -10,7 +10,7 @@ +
  • logfile
  • +
  • userfile
  • + ##TPLFILEMENUGBOX## +-
  • other files ++
  • other files + +
  • + +diff -ruNp trunk.patches/webif/files/menu_softcamkey.html trunk/webif/files/menu_softcamkey.html +--- trunk.patches/webif/files/menu_softcamkey.html 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/webif/files/menu_softcamkey.html 2018-04-03 03:20:07.666045429 +0300 +@@ -0,0 +1 @@ ++
  • SoftCam.Key
  • +diff -ruNp trunk.patches/webif/pages_index.txt trunk/webif/pages_index.txt +--- trunk.patches/webif/pages_index.txt 2018-04-03 02:44:08.678257072 +0300 ++++ trunk/webif/pages_index.txt 2018-04-03 03:20:07.666045429 +0300 +@@ -80,11 +80,13 @@ CONFIGMENUMONITOR config/men + CONFIGMENUNEWCAMD config/menu_newcamd.html MODULE_NEWCAMD + CONFIGMENURADEGAST config/menu_radegast.html MODULE_RADEGAST + CONFIGMENUSCAM config/menu_scam.html MODULE_SCAM ++CONFIGMENUSTREAMRELAY config/menu_streamrelay.html WITH_EMU + CONFIGMENUSERIAL config/menu_serial.html MODULE_SERIAL + CONFIGMONITOR config/monitor.html MODULE_MONITOR + CONFIGNEWCAMD config/newcamd.html MODULE_NEWCAMD + CONFIGRADEGAST config/radegast.html MODULE_RADEGAST + CONFIGSCAM config/scam.html MODULE_SCAM ++CONFIGSTREAMRELAY config/streamrelay.html WITH_EMU + CONFIGSERIAL config/serial.html MODULE_SERIAL + CONFIGSERIALDEVICEBIT config/serial_devices.html MODULE_SERIAL + CONFIGWEBIF config/webif.html +@@ -118,6 +120,7 @@ FILEMENUDVBAPI files/menu + FILEMENUFAKECWS files/menu_fakecws.html CS_CACHEEX + FILEMENUGBOX files/menu_gbox.html MODULE_GBOX + FILEMENUTWIN files/menu_twin.html MODULE_SERIAL ++FILEMENUSOFTCAMKEY files/menu_softcamkey.html WITH_EMU + + AUTOCONF ghttp/autoconf.html MODULE_GHTTP + PREAUTOCONF ghttp/pre_autoconf.html MODULE_GHTTP +@@ -182,6 +185,7 @@ READERCONFIG readerconf + READEREDITCACHEEXBIT readerconfig/readerconfig_cacheexbit.html CS_CACHEEX + READERCONFIGCAMD35BIT readerconfig/readerconfig_camd35bit.html MODULE_CAMD35 + READERCONFIGCCCAMBIT readerconfig/readerconfig_cccambit.html MODULE_CCCAM ++READERCONFIGEMUBIT readerconfig/readerconfig_emubit.html WITH_EMU + READERCONFIGCS378XBIT readerconfig/readerconfig_cs378xbit.html MODULE_CAMD35_TCP + READERCONFIGGBOXBIT readerconfig/readerconfig_gboxbit.html MODULE_GBOX + READERCONFIGGHTTPBIT readerconfig/readerconfig_ghttpbit.html MODULE_GHTTP +diff -ruNp trunk.patches/webif/readerconfig/readerconfig_emubit.html trunk/webif/readerconfig/readerconfig_emubit.html +--- trunk.patches/webif/readerconfig/readerconfig_emubit.html 1970-01-01 03:00:00.000000000 +0300 ++++ trunk/webif/readerconfig/readerconfig_emubit.html 2018-04-03 03:20:07.666045429 +0300 +@@ -0,0 +1,6 @@ ++ ++ ++ ++ ++ ++ diff --git a/package/lean/dvb/tvheadend/Config.in b/package/lean/dvb/tvheadend/Config.in new file mode 100644 index 0000000000..5bc1a18bc6 --- /dev/null +++ b/package/lean/dvb/tvheadend/Config.in @@ -0,0 +1,17 @@ +config TVHEADEND_NDMS_CWC_SUPPORT + bool "NewCamd support" + default y + +config TVHEADEND_NDMS_LINUXDVB_SUPPORT + bool "Linux DVB support" + default y + +config TVHEADEND_NDMS_DVBSCAN_SUPPORT + bool "Fetch DVB-scan data" + depends on TVHEADEND_NDMS_LINUXDVB_SUPPORT + default TVHEADEND_NDMS_LINUXDVB_SUPPORT + +config TVHEADEND_NDMS_AVAHI_SUPPORT + bool "Avahi client support" + select PACKAGE_libavahi-client + default n diff --git a/package/lean/dvb/tvheadend/Makefile b/package/lean/dvb/tvheadend/Makefile new file mode 100644 index 0000000000..491f654736 --- /dev/null +++ b/package/lean/dvb/tvheadend/Makefile @@ -0,0 +1,131 @@ +# +# Copyright (C) 2015 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=tvheadend +PKG_VERSION:=4.2.6 +PKG_RELEASE:=1 + +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=c2a6b61d06ecf8c033f2f5be5746c146eb907d26 +# This is stable git version... +# PKG_SOURCE_VERSION:=1a0262f5870e4fabd6b9c70a7bf2ebe420bc956e +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/tvheadend/tvheadend.git +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +PKG_LICENSE:=GPL-3.0 +PKG_LICENSE_FILES:=LICENSE.md + +PKG_FIXUP:=autoreconf + +PKG_USE_MIPS16:=0 + +SHORT_GIT_VER:=$(shell echo $(PKG_SOURCE_VERSION) | cut -b -7) + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/nls.mk + +define Package/tvheadend + SECTION:=multimedia + CATEGORY:=Multimedia + TITLE:=Tvheadend is a TV streaming server for Linux + DEPENDS:=+libopenssl +librt +zlib +libpcre +libdvbcsa +TVHEADEND_AVAHI_SUPPORT:libavahi-client $(ICONV_DEPENDS) + URL:=https://tvheadend.org + MAINTAINER:=Jan Čermák +endef + +define Package/tvheadend/description + Tvheadend is a TV streaming server and recorder for Linux, FreeBSD and Android + supporting DVB-S, DVB-S2, DVB-C, DVB-T, ATSC, IPTV, SAT>IP and HDHomeRun as input sources. + + Tvheadend offers the HTTP (VLC, MPlayer), HTSP (Kodi, Movian) and SAT>IP streaming. +endef + +define Package/tvheadend/config + menu "Configuration" + depends on PACKAGE_tvheadend + source "$(SOURCE)/Config.in" + endmenu +endef + +ifeq ($(CONFIG_TVHEADEND_CWC_SUPPORT),) + CONFIGURE_ARGS += --disable-cwc +endif + +ifeq ($(CONFIG_TVHEADEND_LINUXDVB_SUPPORT),) + CONFIGURE_ARGS += --disable-linuxdvb +endif + +ifeq ($(CONFIG_TVHEADEND_DVBSCAN_SUPPORT),) + CONFIGURE_ARGS += --disable-dvbscan +endif + +ifeq ($(CONFIG_TVHEADEND_AVAHI_SUPPORT),) + CONFIGURE_ARGS += --disable-avahi +else + CONFIGURE_ARGS += --enable-avahi +endif + +CONFIGURE_ARGS += \ + --arch=$(ARCH) \ + --disable-dbus_1 \ + --disable-libav \ + --enable-bundle \ + --enable-dvben50221 \ + --enable-tvhcsa \ + --enable-dvbcsa \ + --enable-inotify \ + --enable-epoll \ + --enable-trace \ + --nowerror \ + --disable-dvbscan \ + --disable-avahi \ + --disable-hdhomerun_static \ + --disable-pie \ + --disable-imagecache \ + --disable-ffmpeg_static \ + --disable-libx264 \ + --disable-libx264_static \ + --disable-libx265 \ + --disable-libx265_static \ + --disable-libvpx \ + --disable-libvpx_static \ + --disable-libtheora \ + --disable-libtheora_static \ + --disable-libvorbis \ + --disable-libvorbis_static \ + --disable-libfdkaac \ + --disable-libfdkaac_static \ + --disable-nvenc \ + --disable-libmfx_static \ + --disable-timeshift + + +define Build/Prepare + $(call Build/Prepare/Default) + echo 'Tvheadend $(shell echo $(PKG_VERSION)~$(SHORT_GIT_VER)-$(PKG_RELEASE))' \ + > $(PKG_BUILD_DIR)/debian/changelog +endef + +define Package/conffiles +/etc/config/tvheadend +endef + +define Package/tvheadend/install + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) ./files/tvheadend.init $(1)/etc/init.d/tvheadend + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) ./files/tvheadend.config $(1)/etc/config/tvheadend + + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/build.linux/tvheadend $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,tvheadend)) diff --git a/package/lean/dvb/tvheadend/files/tvheadend.config b/package/lean/dvb/tvheadend/files/tvheadend.config new file mode 100644 index 0000000000..62c139de53 --- /dev/null +++ b/package/lean/dvb/tvheadend/files/tvheadend.config @@ -0,0 +1,13 @@ +#config tvheadend service +# option nosyslog '0' +# option use_temp_epgdb '0' +# option config_path '/etc/tvheadend' + +config tvheadend server + option ipv6 '1' +# option bindaddr '0.0.0.0' +# option http_port '9981' +# option http_root '/tvheadend' +# option htsp_port '9982' +# option htsp_port2 '9983' +# option xspf '0' diff --git a/package/lean/dvb/tvheadend/files/tvheadend.init b/package/lean/dvb/tvheadend/files/tvheadend.init new file mode 100644 index 0000000000..07d96a867e --- /dev/null +++ b/package/lean/dvb/tvheadend/files/tvheadend.init @@ -0,0 +1,71 @@ +#!/bin/sh /etc/rc.common + +START=99 +STOP=00 + +USE_PROCD=1 +PROG=/usr/bin/tvheadend + +TEMP_CONFIG=/tmp/tvheadend +PERSISTENT_CONFIG=/etc/tvheadend + +execute_first_run() { + "$PROG" -C "$1" -B -C -A >/dev/null 2>&1 +} + +ensure_config_exists() { + local config_path + + config_load tvheadend + config_get config_path service config_path + + if [ -z "$config_path" ]; then + [ -d "$PERSISTENT_CONFIG" ] || execute_first_run "$PERSISTENT_CONFIG" + else + # if the configuration directory is empty, empty config with grant-all ACL is created + [ -d "$config_path" ] && [ "$(ls -A $config_path)" ] || execute_first_run "$config_path" + fi + + # if use_temp_epgdb is enabled (default), most of the config is put to config_path + # (or /etc/config), except for epgdb.v2, which grows quite large and is write-heavy, + # so it's put into volatile tmpfs + # epgdb.v2 is created and symlinked to main config dir upon each start (if it doesn't exist) + config_get_bool use_temp_epgdb service use_temp_epgdb 1 + if [ "$use_temp_epgdb" == "1" ]; then + TEMP_EPG="${TEMP_CONFIG}/epgdb.v2" + [ ! -f "$TEMP_EPG" ] && mkdir -p "$TEMP_CONFIG" && touch "$TEMP_EPG" && chmod 700 "$TEMP_EPG" + [ -z "$config_path" ] && config_path="$PERSISTENT_CONFIG" + ln -sf "$TEMP_EPG" "${config_path}/epgdb.v2" + fi +} + +load_uci_config() { + config_load tvheadend + config_get config_path service config_path "$PERSISTENT_CONFIG" + [ -n "$config_path" ] && procd_append_param command -c "$config_path" + config_get_bool nosyslog service nosyslog 0 + [ "$nosyslog" -eq 1 ] && procd_append_param command --nosyslog + config_get_bool ipv6 server ipv6 0 + [ "$ipv6" -eq 1 ] && procd_append_param command --ipv6 + config_get bindaddr server bindaddr + [ -n "$bindaddr" ] && procd_append_param command --bindaddr "$bindaddr" + config_get http_port server http_port + [ -n "$http_port" ] && procd_append_param command --http_port "$http_port" + config_get http_root server http_root + [ -n "$http_root" ] && procd_append_param command --http_root "$http_root" + config_get htsp_port server htsp_port + [ -n "$htsp_port" ] && procd_append_param command --htsp_port "$htsp_port" + config_get htsp_port2 server htsp_port2 + [ -n "$htsp_port2" ] && procd_append_param command --htsp_port "$htsp_port2" + config_get xspf server xspf 0 + [ "$xspf" -eq 1 ] && procd_append_param command --xspf +} + +start_service() { + ensure_config_exists + procd_open_instance + procd_set_param file /etc/config/tvheadend + procd_set_param command "$PROG" -B -C + load_uci_config + procd_close_instance +} diff --git a/package/lean/dvb/tvheadend/patches/001-config.patch b/package/lean/dvb/tvheadend/patches/001-config.patch new file mode 100644 index 0000000000..becfe11d9f --- /dev/null +++ b/package/lean/dvb/tvheadend/patches/001-config.patch @@ -0,0 +1,12 @@ +diff -ruN tvheadend.orig/Makefile tvheadend/Makefile +--- tvheadend.orig/Makefile 2017-10-18 16:39:58.000000000 +0300 ++++ tvheadend/Makefile 2017-12-13 00:49:51.314127208 +0300 +@@ -52,7 +52,7 @@ + CFLAGS += -Wmissing-prototypes + CFLAGS += -fms-extensions -funsigned-char -fno-strict-aliasing + CFLAGS += -D_FILE_OFFSET_BITS=64 +-CFLAGS += -I${BUILDDIR} -I${ROOTDIR}/src -I${ROOTDIR} ++CFLAGS += -I ./vendor/dvb-api/5.10 -I${BUILDDIR} -I${ROOTDIR}/src -I${ROOTDIR} + ifeq ($(CONFIG_ANDROID),yes) + LDFLAGS += -ldl -lm + else diff --git a/package/lean/dvb/tvheadend/patches/002-add-cflags.patch b/package/lean/dvb/tvheadend/patches/002-add-cflags.patch new file mode 100755 index 0000000000..cbd72e0ba2 --- /dev/null +++ b/package/lean/dvb/tvheadend/patches/002-add-cflags.patch @@ -0,0 +1,33 @@ +commit 511fddc480c11ba55c9078e54884b584430dc41e +Author: Jaroslav Kysela +Date: Fri Jan 19 10:20:17 2018 +0100 + + Makefile: Add CFLAGS for timestamp and bundle objects, fixes #4870 + +diff --git a/Makefile b/Makefile +index f4b7deb..a6629bd 100644 +--- a/Makefile ++++ b/Makefile +@@ -764,11 +764,11 @@ $(BUILDDIR)/timestamp.c: FORCE + @echo 'const char* build_timestamp = "'$(BUILD_DATE)'";' >> $@ + + $(BUILDDIR)/timestamp.o: $(BUILDDIR)/timestamp.c +- $(pCC) -c -o $@ $< ++ $(pCC) $(CFLAGS) -c -o $@ $< + + $(BUILDDIR)/build.o: $(BUILDDIR)/build.c + @mkdir -p $(dir $@) +- $(pCC) -c -o $@ $< ++ $(pCC) $(CFLAGS) -c -o $@ $< + + # Documentation + $(BUILDDIR)/docs-timestamp: $(I18N-DOCS) support/doc/md_to_c.py +@@ -825,7 +825,7 @@ src/tvh_locale_inc.c: $(PO-FILES) + # Bundle files + $(BUILDDIR)/bundle.o: $(BUILDDIR)/bundle.c + @mkdir -p $(dir $@) +- $(pCC) -I${ROOTDIR}/src -c -o $@ $< ++ $(pCC) $(CFLAGS) -I${ROOTDIR}/src -c -o $@ $< + + $(BUILDDIR)/bundle.c: check_dvb_scan make_webui + @mkdir -p $(dir $@) diff --git a/package/lean/dvb/tvheadend/patches/006-satip_rtsp_fix.patch b/package/lean/dvb/tvheadend/patches/006-satip_rtsp_fix.patch new file mode 100644 index 0000000000..901c252e0e --- /dev/null +++ b/package/lean/dvb/tvheadend/patches/006-satip_rtsp_fix.patch @@ -0,0 +1,314 @@ +diff -ruNp tvheadend.orig/src/http.c tvheadend/src/http.c +--- tvheadend.orig/src/http.c 2018-02-22 22:16:01.000000000 +0300 ++++ tvheadend/src/http.c 2018-02-26 04:03:51.584188821 +0300 +@@ -1273,10 +1273,6 @@ process_request(http_connection_t *hc, h + hc->hc_session = tvh_strdupa(v); + else + hc->hc_session = NULL; +- if(hc->hc_cseq == 0) { +- http_error(hc, HTTP_STATUS_BAD_REQUEST); +- return -1; +- } + break; + + case HTTP_VERSION_1_0: +@@ -1336,10 +1332,7 @@ process_request(http_connection_t *hc, h + case RTSP_VERSION_1_0: + if (tvhtrace_enabled()) + dump_request(hc); +- if (hc->hc_cseq) +- rval = hc->hc_process(hc, spill); +- else +- http_error(hc, HTTP_STATUS_HTTP_VERSION); ++ rval = hc->hc_process(hc, spill); + break; + + case HTTP_VERSION_1_0: +diff -ruNp tvheadend.orig/src/http.h tvheadend/src/http.h +--- tvheadend.orig/src/http.h 2018-02-22 22:16:01.000000000 +0300 ++++ tvheadend/src/http.h 2018-02-26 03:19:40.457467700 +0300 +@@ -162,6 +162,7 @@ typedef struct http_connection { + + int hc_no_output; + int hc_shutdown; ++ int hc_stream; + uint64_t hc_cseq; + char *hc_session; + +diff -ruNp tvheadend.orig/src/satip/rtsp.c tvheadend/src/satip/rtsp.c +--- tvheadend.orig/src/satip/rtsp.c 2018-02-22 22:16:01.000000000 +0300 ++++ tvheadend/src/satip/rtsp.c 2018-02-26 19:07:59.113158089 +0300 +@@ -92,6 +92,13 @@ static pthread_mutex_t rtsp_lock; + static void rtsp_close_session(session_t *rs); + static void rtsp_free_session(session_t *rs); + ++/* ++ * ++ */ ++static inline int rtsp_is_nat_active(void) ++{ ++ return rtsp_nat_ip[0] != '\0'; ++} + + /* + * +@@ -280,9 +287,10 @@ rtsp_check_urlbase(char *u) + if (strcmp(u, rtsp_ip)) { + if (rtsp_nat_ip == NULL) + return NULL; +- if (rtsp_nat_ip[0] != '*') +- if (rtsp_nat_ip[0] == '\0' || strcmp(u, rtsp_nat_ip)) ++ if (rtsp_is_nat_active()) { ++ if (rtsp_nat_ip[0] != '*' && strcmp(u, rtsp_nat_ip)) + return NULL; ++ } + } + return p ? p + 1 : u + strlen(u); + } +@@ -455,8 +463,7 @@ static void + rtsp_manage_descramble(session_t *rs) + { + idnode_set_t *found; +- mpegts_service_t *s, *snext; +- mpegts_service_t *master = (mpegts_service_t *)rs->subs->ths_raw_service; ++ mpegts_service_t *s, *master, *snext; + slave_subscription_t *sub; + mpegts_apids_t pmt_pids; + size_t si; +@@ -470,6 +477,8 @@ rtsp_manage_descramble(session_t *rs) + if (rs->mux == NULL || rs->subs == NULL) + goto end; + ++ master = (mpegts_service_t *)rs->subs->ths_raw_service; ++ + if (rs->pids.all) { + LIST_FOREACH(s, &rs->mux->mm_services, s_dvb_mux_link) + if (rtsp_validate_service(s, NULL)) +@@ -861,7 +870,7 @@ parse_pids(char *p, mpegts_apids_t *pids + while (1) { + if (x == NULL) + break; +- if (strcmp(x, "all") == 0) { ++ if (strcmp(x, "all") == 0 || strcmp(x, "8192") == 0) { + if (satip_server_conf.satip_restrict_pids_all) { + pids->all = 0; + for (pid = 1; pid <= 2; pid++) /* CAT, TSDT */ +@@ -907,7 +916,22 @@ parse_transport(http_connection_t *hc) + if (a + 1 != b) + return -1; + return a; +- } else if ((strncmp(s, "RTP/AVP/TCP;interleaved=0-1", 27) == 0) && ++ } else if (strncmp(s, "RTP/AVP/UDP;unicast;client_port=", 32) == 0) { ++ for (s += 32, u = s; isdigit(*u); u++); ++ if (*u != '-') ++ return -1; ++ a = atoi(s); ++ for (s = ++u; isdigit(*s); s++); ++ if (*s != '\0' && *s != ';') ++ return -1; ++ b = atoi(u); ++ if (a + 1 != b) ++ return -1; ++ return a; ++ } else if ((strncmp(s, "RTP/AVP/TCP;unicast;interleaved=0-1", 27) == 0) && ++ !satip_server_conf.satip_notcp_mode) { ++ return RTSP_TCP_DATA; ++ } else if ((strncmp(s, "RTP/AVP/TCP;interleaved=0-1", 35) == 0) && + !satip_server_conf.satip_notcp_mode) { + return RTSP_TCP_DATA; + } +@@ -983,12 +1007,14 @@ rtsp_parse_cmd + if (cmd == RTSP_CMD_SETUP) { + if (!rs) { + rs = rtsp_new_session(hc->hc_peer_ipstr, msys, 0, -1); ++ if (rs == NULL) goto end; + if (delsys == DVB_SYS_NONE) goto end; + if (msys == DVB_SYS_NONE) goto end; + if (!(*valid)) goto end; + alloc_stream_id = 1; + } else if (stream != rs->stream) { + rs = rtsp_new_session(hc->hc_peer_ipstr, msys, rs->nsession, stream); ++ if (rs == NULL) goto end; + if (delsys == DVB_SYS_NONE) goto end; + if (msys == DVB_SYS_NONE) goto end; + if (!(*valid)) goto end; +@@ -1017,6 +1043,8 @@ rtsp_parse_cmd + rs->rtp_peer_port = r; + rs->frontend = fe > 0 ? fe : 1; + } else { ++ if (!rs && !stream && cmd == RTSP_CMD_DESCRIBE) ++ rs = rtsp_new_session(hc->hc_peer_ipstr, msys, 0, -1); + if (!rs || stream != rs->stream) { + if (rs) + errcode = HTTP_STATUS_NOT_FOUND; +@@ -1187,6 +1215,12 @@ play: + if (mpegts_pid_dump(&rs->pids, buf + r, sizeof(buf) - r, 0, 0) == 0) + tvh_strlcatf(buf, sizeof(buf), r, ""); + ++ if (cmd == RTSP_CMD_DESCRIBE) { ++ hc->hc_session = rs->session; ++ if (!rs->stream) ++ rs->stream = 1; ++ hc->hc_stream = rs->stream; ++ } + tvhdebug(LS_SATIPS, "%i/%s/%d: %s from %s:%d %s", + rs->frontend, rs->session, rs->stream, + caller, hc->hc_peer_ipstr, ntohs(IP_PORT(*hc->hc_peer)), buf); +@@ -1294,7 +1328,8 @@ rtsp_describe_session(session_t *rs, hts + { + char buf[4096]; + +- htsbuf_qprintf(q, "a=control:stream=%d\r\n", rs->stream); ++ if (rs->stream > 0) ++ htsbuf_qprintf(q, "a=control:stream=%d\r\n", rs->stream); + htsbuf_append_str(q, "a=tool:tvheadend\r\n"); + htsbuf_append_str(q, "m=video 0 RTP/AVP 33\r\n"); + if (strchr(rtsp_ip, ':')) +@@ -1311,6 +1346,20 @@ rtsp_describe_session(session_t *rs, hts + } + } + ++static inline const char * ++rtsp_conn_ip(http_connection_t *hc, char *buf, size_t buflen, int *port) ++{ ++ const char *used_ip = rtsp_ip; ++ int used_port = rtsp_port; ++ ++ if (hc && hc->hc_self) ++ used_ip = tcp_get_str_from_ip(hc->hc_self, buf, buflen); ++ ++ *port = used_port > 0 ? used_port : 554; ++ ++ return used_ip; ++} ++ + /* + * + */ +@@ -1322,9 +1371,10 @@ rtsp_process_describe(http_connection_t + char *u = tvh_strdupa(hc->hc_url); + session_t *rs; + htsbuf_queue_t q; +- char buf[96]; ++ char buf[96], buf1[46]; ++ const char *used_ip = NULL; + int r = HTTP_STATUS_BAD_REQUEST; +- int stream, first = 1, valid; ++ int stream, first = 1, valid, used_port; + + htsbuf_queue_init(&q, 0); + +@@ -1381,10 +1431,15 @@ rtsp_process_describe(http_connection_t + http_arg_init(&args); + if (hc->hc_session) + http_arg_set(&args, "Session", hc->hc_session); +- if (stream > 0) +- snprintf(buf, sizeof(buf), "rtsp://%s/stream=%i", rtsp_ip, stream); ++ used_ip = rtsp_conn_ip(hc, buf1, sizeof(buf1), &used_port); ++ if ((stream > 0) && (used_port != 554)) ++ snprintf(buf, sizeof(buf), "rtsp://%s:%d/stream=%i", used_ip, used_port, stream); ++ else if ((stream > 0) && (used_port == 554)) ++ snprintf(buf, sizeof(buf), "rtsp://%s/stream=%i", used_ip, stream); ++ else if (used_port != 554) ++ snprintf(buf, sizeof(buf), "rtsp://%s:%d", used_ip, used_port); + else +- snprintf(buf, sizeof(buf), "rtsp://%s", rtsp_ip); ++ snprintf(buf, sizeof(buf), "rtsp://%s", used_ip); + http_arg_set(&args, "Content-Base", buf); + http_send_begin(hc); + http_send_header(hc, HTTP_STATUS_OK, "application/sdp", q.hq_size, +@@ -1408,8 +1463,9 @@ static int + rtsp_process_play(http_connection_t *hc, int cmd) + { + session_t *rs; +- int errcode = HTTP_STATUS_BAD_REQUEST, valid = 0, i, stream; +- char buf[256], *u = tvh_strdupa(hc->hc_url); ++ int errcode = HTTP_STATUS_BAD_REQUEST, valid = 0, i, stream, used_port; ++ char buf[256], buf1[46], *u = tvh_strdupa(hc->hc_url); ++ const char *used_ip = NULL; + http_arg_list_t args; + + http_arg_init(&args); +@@ -1417,7 +1473,9 @@ rtsp_process_play(http_connection_t *hc, + if ((u = rtsp_check_urlbase(u)) == NULL) + goto error2; + +- if ((stream = rtsp_parse_args(hc, u)) < 0) ++/* if ((stream = rtsp_parse_args(hc, u)) < 0) */ ++ stream = hc->hc_stream; ++ if (stream < 0) + goto error2; + + pthread_mutex_lock(&rtsp_lock); +@@ -1467,10 +1525,11 @@ rtsp_process_play(http_connection_t *hc, + snprintf(buf, sizeof(buf), "%d", rs->stream); + http_arg_set(&args, "com.ses.streamID", buf); + } else { +- if (rtsp_port != 554) +- snprintf(buf, sizeof(buf), "url=rtsp://%s:%d/stream=%d", rtsp_ip, rtsp_port, rs->stream); ++ used_ip = rtsp_conn_ip(hc, buf1, sizeof(buf1), &used_port); ++ if (used_port != 554) ++ snprintf(buf, sizeof(buf), "url=rtsp://%s:%d/stream=%d", used_ip, used_port, rs->stream); + else +- snprintf(buf, sizeof(buf), "url=rtsp://%s/stream=%d", rtsp_ip, rs->stream); ++ snprintf(buf, sizeof(buf), "url=rtsp://%s/stream=%d", used_ip, rs->stream); + http_arg_set(&args, "RTP-Info", buf); + } + +@@ -1587,9 +1646,39 @@ static void + rtsp_stream_status ( void *opaque, htsmsg_t *m ) + { + http_connection_t *hc = opaque; ++ struct session *rs = NULL; ++ htsmsg_t *c, *tcp = NULL, *udp = NULL; ++ int udpport, s32; ++ + htsmsg_add_str(m, "type", "SAT>IP"); ++ + if (hc->hc_username) + htsmsg_add_str(m, "user", hc->hc_username); ++ ++ TAILQ_FOREACH(rs, &rtsp_sessions, link) { ++ if (hc->hc_session && ++ strcmp(rs->session, hc->hc_session) == 0 && ++ strcmp(rs->peer_ipstr, hc->hc_peer_ipstr) == 0 && ++ (udpport = rs->rtp_peer_port) > 0) { ++ if (udpport == RTSP_TCP_DATA) { ++ if (rs->tcp_data == hc) { ++ s32 = htsmsg_get_s32_or_default(m, "peer_port", -1); ++ if (!tcp) tcp = htsmsg_create_list(); ++ htsmsg_add_s32(tcp, NULL, s32); ++ } ++ } else { ++ if (!udp) udp = htsmsg_create_list(); ++ htsmsg_add_s32(udp, NULL, udpport); ++ htsmsg_add_s32(udp, NULL, udpport+1); ++ } ++ } ++ } ++ if (tcp || udp) { ++ c = htsmsg_create_map(); ++ if (tcp) htsmsg_add_msg(c, "tcp", tcp); ++ if (udp) htsmsg_add_msg(c, "udp", udp); ++ htsmsg_add_msg(m, "peer_extra_ports", c); ++ } + } + + /* +@@ -1621,6 +1710,7 @@ rtsp_serve(int fd, void **opaque, struct + hc.hc_peer = peer; + hc.hc_self = self; + hc.hc_process = rtsp_process_request; ++ hc.hc_stream = -1; + hc.hc_cseq = 1; + + http_serve_requests(&hc); +@@ -1655,7 +1745,7 @@ rtsp_close_session(session_t *rs) + rs->tcp_data = NULL; + pthread_mutex_lock(&global_lock); + mpegts_pid_reset(&rs->pids); +- rtsp_clean(rs, 1); ++ rtsp_clean(rs, 0); + mtimer_disarm(&rs->timer); + pthread_mutex_unlock(&global_lock); + } diff --git a/package/lean/dvb/tvheadend/patches/008-delete-docs.patch b/package/lean/dvb/tvheadend/patches/008-delete-docs.patch new file mode 100644 index 0000000000..5823268d47 --- /dev/null +++ b/package/lean/dvb/tvheadend/patches/008-delete-docs.patch @@ -0,0 +1,10 @@ +--- a/Makefile 2018-03-22 02:51:32.000000000 +0800 ++++ b/Makefile 2018-03-23 18:31:08.010773484 +0800 +@@ -834,6 +834,7 @@ + $(pCC) $(CFLAGS) -I${ROOTDIR}/src -c -o $@ $< + + $(BUILDDIR)/bundle.c: $(DVBSCAN-yes) make_webui ++ find src/webui/static/img/doc/ -delete + @mkdir -p $(dir $@) + $(pMKBUNDLE) -o $@ -d ${BUILDDIR}/bundle.d $(BUNDLE_FLAGS) $(BUNDLES:%=$(ROOTDIR)/%) + diff --git a/package/lean/luci-app-oscam/Makefile b/package/lean/luci-app-oscam/Makefile deleted file mode 100644 index 70a12e865a..0000000000 --- a/package/lean/luci-app-oscam/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# -# Copyright (C) 2008-2014 The LuCI Team -# -# This is free software, licensed under the Apache License, Version 2.0 . -# - -include $(TOPDIR)/rules.mk - -LUCI_TITLE:=LuCI for OSCAM -LUCI_DEPENDS:=+oscam -LUCI_PKGARCH:=all -PKG_VERSION:=1.0 -PKG_RELEASE:=1 - -include $(TOPDIR)/feeds/luci/luci.mk - -# call BuildPackage - OpenWrt buildroot signature - - diff --git a/package/lean/luci-app-oscam/luasrc/controller/admin/sattv.lua b/package/lean/luci-app-oscam/luasrc/controller/admin/sattv.lua deleted file mode 100644 index 03f2b172fb..0000000000 --- a/package/lean/luci-app-oscam/luasrc/controller/admin/sattv.lua +++ /dev/null @@ -1,16 +0,0 @@ -module("luci.controller.admin.sattv", package.seeall) - -function index() - --- entry({"admin", "Others"}, cbi("sattv/epg"), i18n("Others"), 70) - - if nixio.fs.access("/etc/config/epg") then - entry({"admin", "Others"}, cbi("sattv/epg"), _("sattv"), 66).index = true - entry({"admin", "Others", "epg"}, cbi("sattv/epg"), _("EPG"), 1).i18n = "diskapply" - end - - if nixio.fs.access("/etc/config/oscam") then - entry({"admin", "Others", "oscam"}, cbi("sattv/oscam"), _("OSCAM"), 12).i18n = "diskapply" - end - -end diff --git a/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/epg.lua b/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/epg.lua deleted file mode 100644 index da46cad90f..0000000000 --- a/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/epg.lua +++ /dev/null @@ -1,50 +0,0 @@ -require("luci.tools.webadmin") - ---[[ -config epg_set - option enable 1 - option time 30 - option src_url http://dm.epg.net.cn/a/epg.xml - option src_url1 http://dm1.epg.net.cn/a/epg.xml - option src_url2 http://epg.xltvrobbs.net/atmosphere/epg/epg.xml - option src_url3 http://epg1.xltvrobbs.net/atmosphere/epg/epg.xml - -]]-- - - -m = Map("epg", translate("epg_title","Set epg download address"),translate("epg_desc", -"Set epg auto download for dm500 atmosphere")) - -s = m:section(TypedSection, "epg_set", translate("epgset","settings")) -s.anonymous = true -s.addremove = false - -enable = s:option(Flag, "enable", translate("enable", "enable")) -enable.default = false -enable.optional = false -enable.rmempty = false - -interval = s:option(Value, "interval", translate("interval","interval")) -interval.default = 30 -interval.optional = false -interval.rmempty = false - - -s = m:section(TypedSection, "downaddress", translate("downaddress","downaddress")) -s.template = "cbi/tblsection" -s.anonymous = false -s.addremove = true - -enable = s:option(Flag, "addr_enable", translate("enable", "enable")) -enable.default = false -enable.optional = false -enable.rmempty = false - - -url = s:option(Value, "address", translate("dowload address","dowload address")) -url.optional = false -url.rmempty = false - - -return m - diff --git a/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/oscam.lua b/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/oscam.lua deleted file mode 100644 index 44a19fcfd4..0000000000 --- a/package/lean/luci-app-oscam/luasrc/model/cbi/sattv/oscam.lua +++ /dev/null @@ -1,67 +0,0 @@ ---[[ -LuCI - Lua Configuration Interface - -Copyright 2011 flyzjhz - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -]]-- - - -local fs = require "nixio.fs" -local uci = require "luci.model.uci".cursor() -local lanipaddr = uci:get("network", "lan", "ipaddr") or "192.168.1.1" ---- Retrieves the output of the "get_oscam_port" command. --- @return String containing the current get_oscam_port -function get_oscam_port() - - local oscam_conf= fs.readfile("/usr/oscam/oscam.conf") - local oscam_conf_port = tonumber(oscam_conf:match("[Hh]ttppor[Tt].-= ([^\n]+)")) or "8899" - return oscam_conf_port -end - -local oscamport = get_oscam_port() - -m = Map("oscam", translate("OSCAM","OSCAM"),translate("oscam desc", -"oscam for openwrt")) - -s = m:section(TypedSection, "setting", translate("set","settings")) -s.anonymous = true -s.addremove = false - -enable = s:option(Flag, "enable", translate("enable", "enable")) -enable.default = false -enable.optional = false -enable.rmempty = false - -interval = s:option(Value, "interval", translate("interval","interval"), -translate("interval_desc","interval_desc")) -interval.optional = false -interval.rmempty = false -interval.default = 30 - -s:option(DummyValue,"oscamweb" ,translate("OSCAM Web Intelface "),translate("Open the oscam Web")) - -tmpl = s:option(Value, "_tmpl", - translate("Edit oscam configuration."), - translate("This is the content of the file '/usr/oscam/oscam.conf'")) - -tmpl.template = "cbi/tvalue" -tmpl.rows = 20 - -function tmpl.cfgvalue(self, section) - return nixio.fs.readfile("/usr/oscam/oscam.conf") -end - -function tmpl.write(self, section, value) - value = value:gsub("\r\n?", "\n") - nixio.fs.writefile("//usr/oscam/oscam.conf", value) -end - -return m - - diff --git a/package/lean/luci-app-oscam/root/etc/config/epg b/package/lean/luci-app-oscam/root/etc/config/epg deleted file mode 100644 index 9c2791f687..0000000000 --- a/package/lean/luci-app-oscam/root/etc/config/epg +++ /dev/null @@ -1,13 +0,0 @@ - -config 'epg_set' - option 'enable' '0' - option 'interval' '30' - -config 'downaddress' 'epg1' - option 'addr_enable' '1' - option 'address' 'http://dm.epg.net.cn/a/epg.xml' - -config 'downaddress' 'epg2' - option 'addr_enable' '1' - option 'address' 'http://epg.xltvrobbs.net/atmosphere/epg/epg.xml' - diff --git a/package/lean/luci-app-oscam/root/etc/config/oscam b/package/lean/luci-app-oscam/root/etc/config/oscam deleted file mode 100644 index 795ea4e3c5..0000000000 --- a/package/lean/luci-app-oscam/root/etc/config/oscam +++ /dev/null @@ -1,4 +0,0 @@ - -config 'setting' - option 'enable' '0' - diff --git a/package/lean/luci-app-oscam/root/etc/init.d/epg b/package/lean/luci-app-oscam/root/etc/init.d/epg deleted file mode 100755 index 9b9014cddb..0000000000 --- a/package/lean/luci-app-oscam/root/etc/init.d/epg +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh /etc/rc.common -# copyrights -# (1)epg dowload Script VER 0.10for openwrt by zjhzzyf - - - -START=96 - - - -start(){ - - - /usr/bin/epg start -} - -stop() { - echo "not implemented yet!" -} - -restart() { - start -} \ No newline at end of file diff --git a/package/lean/luci-app-oscam/root/etc/init.d/oscam b/package/lean/luci-app-oscam/root/etc/init.d/oscam deleted file mode 100755 index ca40a36089..0000000000 --- a/package/lean/luci-app-oscam/root/etc/init.d/oscam +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/sh /etc/rc.common -# oscam Script VER 0.10 for openwrt by zjhzzyf - -START=94 - -. /etc/functions.sh -path="/usr/oscam/" - - -kill_oscam() -{ -local otherpids -local execute -otherpids=$(ps -a 2>&1 | grep "/usr/bin/oscam" | grep -v $$ | awk -F " " '{print $1}') -echo "$otherpids" | while read execute -do -kill -9 ${execute} -done -} - - - -oscam_start() -{ - - /usr/bin/oscam -b -c $path - echo "readdy go....." - -} - - - -start(){ -echo "game start....." - enable=$(uci get oscam.@setting[0].enable) - if [ "$enable" == "" ];then - enable=0 - fi - - [ "$enable" == "1" ]&&oscam_start - -interval=$(uci get oscam.@setting[0].interval) -oscam_cron=`cat /etc/crontabs/root | grep "/etc/init.d/oscam restart"` -if [ "$enable" == "1" -a "$interval" != "0" ]; then - oscam_new="*/${interval} * * * * /etc/init.d/oscam restart" - if [ "z${oscam_cron}" != "z${oscam_new}" ] ; then - cat /etc/crontabs/root | grep -v "/etc/init.d/oscam restart" > /tmp/crontabs_oscam - echo "" >> /tmp/crontabs_oscam - echo "*/${interval} * * * * /etc/init.d/oscam restart" >> /tmp/crontabs_oscam - cat /tmp/crontabs_oscam | grep -v ^$ > /etc/crontabs/root - /etc/init.d/cron restart - fi -else - if [ "z${oscam_cron}" != "z" ] ; then - cat /etc/crontabs/root | grep -v "/etc/init.d/oscam restart" > /tmp/crontabs_oscam - cat /tmp/crontabs_oscam | grep -v ^$ > /etc/crontabs/root - /etc/init.d/cron restart - fi - -fi -rm -f /tmp/crontabs_oscam - -} - -stop() { - kill_oscam - echo "oscam stopped" -} - - diff --git a/package/lean/luci-app-oscam/root/etc/oscam/oscam.conf b/package/lean/luci-app-oscam/root/etc/oscam/oscam.conf deleted file mode 100644 index 51abc783f8..0000000000 --- a/package/lean/luci-app-oscam/root/etc/oscam/oscam.conf +++ /dev/null @@ -1,39 +0,0 @@ -# oscam.conf generated automatically by Streamboard OSCAM 1.00-unstable_svn build #r4503 -# Read more: http://streamboard.gmc.to/oscam/browser/trunk/Distribution/doc/txt/oscam.conf.txt - -[global] -logfile = /dev/shm/oscam.log -disablelog = 1 -clientmaxidle = 36000 -bindwait = 5 -netprio = 9 -nice = 9 -waitforcards = 0 -lb_mode = 1 - -[monitor] -port = 9988 -nocrypt = -aulow = 120 -hideclient_to = 0 -monlevel = 255 -appendchaninfo = 0 - -[dvbapi] -enabled = 1 -au = 1 -boxtype = none -user = user1 -pmt_mode = 0 -request_mode = 0 - -[webif] -httpport = 8899 -httpuser = oscam -httppwd = oscam -httprefresh = 0 -httpallowed = 1.0.0.0-255.255.0.0 -httphideidleclients = 0 -httpreadonly = 0 -httpsavefullcfg = 0 - diff --git a/package/lean/luci-app-oscam/root/etc/oscam/oscam.server b/package/lean/luci-app-oscam/root/etc/oscam/oscam.server deleted file mode 100644 index 876103ba03..0000000000 --- a/package/lean/luci-app-oscam/root/etc/oscam/oscam.server +++ /dev/null @@ -1,28 +0,0 @@ -# oscam.server generated automatically by Streamboard OSCAM 1.00-unstable_svn build #r4503 -# Read more: http://streamboard.gmc.to/oscam/browser/trunk/Distribution/doc/txt/oscam.server.txt - -[reader] -label = reshare1 -enable = 0 -protocol = cccam -device = oscam.3322.org,13111 -user = test01 -password = test01 -inactivitytimeout = 1 -reconnecttimeout = 3 -group = 1 -blockemm-unknown = 1 -blockemm-u = 1 -blockemm-s = 1 -blockemm-g = 1 -lb_weight = 100 -cccversion = 2.1.2 -cccmaxhops = 12 -ccckeepalive = 1 -audisabled = 1 -cccdisableautoblock = 1 - - - - - diff --git a/package/lean/luci-app-oscam/root/etc/oscam/oscam.user b/package/lean/luci-app-oscam/root/etc/oscam/oscam.user deleted file mode 100644 index f02c1bc848..0000000000 --- a/package/lean/luci-app-oscam/root/etc/oscam/oscam.user +++ /dev/null @@ -1,6 +0,0 @@ -[account] -user = 001 -pwd = 001 -group = 1 -keepalive = 1 -uniq = 0 diff --git a/package/lean/luci-app-oscam/root/etc/uci-defaults/luci-sattv b/package/lean/luci-app-oscam/root/etc/uci-defaults/luci-sattv deleted file mode 100644 index a9e7595807..0000000000 --- a/package/lean/luci-app-oscam/root/etc/uci-defaults/luci-sattv +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -uci -q batch <<-EOF >/dev/null - delete ucitrack.@epg[-1] - add ucitrack epg - set ucitrack.@epg[-1].init=epg - delete ucitrack.@oscam[-1] - add ucitrack oscam - set ucitrack.@oscam[-1].init=oscam - add_list ucitrack.@oscam[-1].affects=cron - commit ucitrack -EOF -rm -f /tmp/luci-indexcache -exit 0 diff --git a/package/lean/luci-app-oscam/root/usr/bin/epg b/package/lean/luci-app-oscam/root/usr/bin/epg deleted file mode 100755 index e51b91fc40..0000000000 --- a/package/lean/luci-app-oscam/root/usr/bin/epg +++ /dev/null @@ -1,199 +0,0 @@ -#!/bin/sh -# copyrights -# (1)epg dowload Script VER 0.10for openwrt by zjhzzyf - - -. /lib/functions.sh - - -epg_down() -{ - bsuc=1 - echo "File Path:"$path - filename="epg.xml" - echo "Setup FileName:"$filename - sfullfilename=`echo $path$filename` - echo "sFullFileName:"$sfullfilename - - index=0 - echo "Try Times Max:"$trytimes - while [ "$index" -lt "$trytimes" ] - do - echo "Try Times:"$index - if wget -qO- -t3 $url > $sfullfilename;then - break - fi - index=`expr $index + 1` - done - if [ "$index" -eq "$trytimes" ]; then - ErrMsg=`date` - ErrMsg=$ErrMsg" 下载配置文件失败" - bsuc=0 - return - fi - echo "down $filename completed" -mfullfilename=`echo ${path}store/${filename}.md5` - echo "MD5 File Name:"$mfullfilename - md5old=`cat $mfullfilename` - md5old=`echo $md5old|awk '{print $1}'|tr "[a-z]" "[A-Z]"` - echo "Old File MD5:"$md5old - md5new=`/usr/bin/md5sum $sfullfilename` - md5new=`echo $md5new|awk '{print $1}'|tr "[a-z]" "[A-Z]"` - echo "New File MD5:"$md5new - if [ "$md5old" = "$md5new" ]; then - ErrMsg=`date` - ErrMsg=$ErrMsg" 数据不需要更新" - bsuc=1 - return - else - - counttimes=0 - suctimes=0 - counttimes=`expr $counttimes + 1` - url=$(grep -m 1 "URL" $sfullfilename |awk -F "" '{print $2}'|awk -F "" '{print $1}') - echo "Down Data URL:" $url - -filename=`echo ${url##*/}` - echo "Down File Name:"$filename - - echo "=====" -echo $url - replaces=`echo ${url%/*}` - -replaces=`echo ${replaces#*//}` - - echo replaces: $replaces - echo -e `sed -e "s#$replaces#$replaced#g" $sfullfilename` > `echo $sfullfilename` - echo "=====" - - dfullfilename=`echo $path$filename` - echo "Down Data Save File Name:"$dfullfilename - - index=0 - while [ "$index" -lt "$trytimes" ] - do - echo "Try Times:"$index - if wget -t3 -T120 -qO- $url > $dfullfilename;then - suctimes=`expr $suctimes + 1` - - break - fi - index=`expr $index + 1` - - done - - if [ "$index" -eq "$trytimes" ]; then - bsuc=0 - ErrMsg=`date` - ErrMsg=$ErrMsg" 下载"$url"失败" - - fi - - - if [ "$counttimes" -eq "$suctimes" ]; then - echo $md5new > `echo $mfullfilename` - -mount -o bind /tmp/epg/ /www/atmosphere - rm -rf ${path}/epg/* - -cp ${path}$filename ${path}/epg -cp ${path}epg.xml ${path}/epg - rm -rf ${path}$filename - rm -rf ${path}epg.xml - ErrMsg=`date` - ErrMsg=$ErrMsg" 下载EPG数据成功" - echo $ErrMsg - exit 0 - else - ErrMsg=`date` - ErrMsg= $ErrMsg " 未知原因失败" - fi - fi -} - - -epg_start() { - -config_get enable $1 enable -config_get interval $1 interval -[ "$enable" = "" ]&&enable=0 - -#make scheduler - -epg_cron=`cat /etc/crontabs/root | grep "/usr/bin/epg scheduler"` -if [ "$enable" == "1" -a "${interval}" != "0" ]; then - mkdir -p /tmp/epg/ - mkdir -p /tmp/epg/store - mkdir -p /tmp/epg/epg - mkdir -p /www/atmosphere - epg_new="*/${interval} * * * * /usr/bin/epg scheduler" - if [ "z${epg_cron}" != "z${epg_new}" ] ; then - cat /etc/crontabs/root | grep -v "/etc/init.d/epg scheduler" > /tmp/crontabs_epg - echo "*/${interval} * * * * /etc/init.d/epg scheduler" >> /tmp/crontabs_epg - echo "" >> /tmp/crontabs_epg - cat /tmp/crontabs_epg | grep -v ^$ > /etc/crontabs/root - /etc/init.d/cron restart - fi -else - if [ "z${epg_cron}" != "z" ] ; then - cat /etc/crontabs/root | grep -v "/etc/init.d/epg scheduler" > /tmp/crontabs_epg - cat /tmp/crontabs_epg | grep -v ^$ > /etc/crontabs/root - /etc/init.d/cron restart - fi -rm -f /tmp/crontabs_epg - -fi - -/etc/init.d/cron restart - -} - - -con_get_addr(){ - - config_get addr_enable $1 addr_enable - config_get address $1 address - -[ "$addr_enable" == "1" ]&&{ -url=$address -echo $url -ErrMsg=`date` -ErrMsg=$ErrMsg" 开始从"$url"下载" -echo $ErrMsg >> `echo /tmp/epglog.txt` -rm `echo $path"*"` -epg_down -echo $ErrMsg >> `echo /tmp/epglog.txt` -echo $bsuc -echo "******************************************************************" >> `echo /tmp/epglog.txt` -} -} - - - -epg_scheduler(){ - -path="/tmp/epg/" -trytimes=3 -bsuc=1 -ErrMsg="" -lan_ipaddr=$(uci get network.lan.ipaddr) -replaced="${lan_ipaddr}/atmosphere/epg" - - -} - - -config_load epg -case "$1" in - start) - config_foreach epg_start epg_set - ;; - stop) - echo "stop test " - ;; - scheduler) - epg_scheduler - config_foreach con_get_addr downaddress -;; -esac - diff --git a/package/lean/luci-app-oscam/root/usr/oscam/oscam.conf b/package/lean/luci-app-oscam/root/usr/oscam/oscam.conf deleted file mode 100644 index a552326fe3..0000000000 --- a/package/lean/luci-app-oscam/root/usr/oscam/oscam.conf +++ /dev/null @@ -1,37 +0,0 @@ -[global] -# Prozess -nice = -10 -pidfile = /tmp/oscam.pid -# Logging -logfile = /tmp/oscam.log -disablelog = 0 -maxlogsize = 256 -usrfile = /tmp/oscam_user.log -disableuserfile = 0 -usrfileflag = 1 -# Timeouts - If you have problems adjust or remove rows! -clienttimeout = 2000 -fallbacktimeout = 1000 -serialreadertimeout = 800 -# Sonstiges -clientdyndns = 0 -unlockparental = 1 -saveinithistory = 1 - -[monitor] -port = 15990 -nocrypt = 127.0.0.1,192.168.1.1-192.168.1.255 # "No entry for other IP's!" -aulow = 30 -hideclient_to = 0 -monlevel = 4 -appendchaninfo = 0 - -[camd35] -port = 15991 - -[webif] -httpport = 16000 -httprefresh = 0 -httpallowed = 127.0.0.1,192.168.1.1-192.168.1.255 # "No entry for other IP's!" -httphideidleclients = 0 -httpreadonly = 0 diff --git a/package/lean/oscam/Config.in b/package/lean/oscam/Config.in deleted file mode 100644 index 2a23f71c65..0000000000 --- a/package/lean/oscam/Config.in +++ /dev/null @@ -1,240 +0,0 @@ -menu "OSCam build options" - depends on PACKAGE_oscam - - -config OSCAM_USE_LIBCRYPTO - bool "Build with OpenSSL libcrypto" - help - "Use OpenSSL libcrypto instead of OSCam internal crypto functions" - default n - -config OSCAM_USE_LIBUSB - bool "Build with libusb" - default n - - - menu "Protocols" - depends on PACKAGE_oscam - - config OSCAM_MODULE_CAMD33 - bool "camd 3.3" - default n - - config OSCAM_MODULE_CAMD35 - bool "camd 3.5 UDP" - default n - - config OSCAM_MODULE_CAMD35_TCP - bool "camd 3.5 TCP" - default n - - config OSCAM_MODULE_NEWCAMD - bool "newcamd" - default n - - config OSCAM_MODULE_CCCAM - bool "CCcam" - default n - - config OSCAM_MODULE_CCCSHARE - bool "CCcam share" - default n - - config OSCAM_MODULE_GBOX - bool "gbox" - default n - - config OSCAM_MODULE_RADEGAST - bool "radegast" - default n - - config OSCAM_MODULE_SERIAL - bool "Serial" - default n - - config OSCAM_MODULE_CONSTCW - bool "constant CW" - default n - - config OSCAM_MODULE_PANDORA - bool "Pandora" - default n - - config OSCAM_MODULE_GHTTP - bool "Ghttp" - default n - - config OSCAM_MODULE_SCAM - bool "scam" - default n - - endmenu - - menu "Readers" - depends on PACKAGE_oscam - - config OSCAM_READER_NAGRA - bool "Nagravision" - default n - - config OSCAM_READER_IRDETO - bool "Irdeto" - default n - - config OSCAM_READER_CONAX - bool "Conax" - default n - - config OSCAM_READER_CRYPTOWORKS - bool "Cryptoworks" - default n - - config OSCAM_READER_SECA - bool "Seca" - default n - - config OSCAM_READER_VIACCESS - bool "Viaccess" - default n - - config OSCAM_READER_VIDEOGUARD - bool "NDS Videoguard" - default n - - config OSCAM_READER_DRE - bool "DRE Crypt" - default n - - config OSCAM_READER_TONGFANG - bool "Tongfang" - default n - - config OSCAM_READER_BULCRYPT - bool "Bulcrypt" - default n - - config OSCAM_READER_GRIFFIN - bool "Griffin" - default n - - config OSCAM_READER_DGCRYPT - bool "DGCrypt" - default n - - endmenu - - menu "Card readers" - depends on PACKAGE_oscam - - config OSCAM_USE_PCSC - bool "PCSC" - select OSCAM_USE_LIBUSB - default n - - config OSCAM_CARDREADER_PHOENIX - bool "Phoenix/mouse" - select OSCAM_USE_LIBUSB - default n - - config OSCAM_CARDREADER_SC8IN1 - bool "SC8in1" - select OSCAM_USE_LIBUSB - default n - - config OSCAM_CARDREADER_MP35 - bool "AD-Teknik MP 3.6/USB Phoenix" - select OSCAM_USE_LIBUSB - default n - - config OSCAM_CARDREADER_SMARGO - bool "Argolis Smargo Smartreader" - select OSCAM_USE_LIBUSB - default n - - config OSCAM_CARDREADER_STINGER - bool "STINGER" - select OSCAM_USE_LIBUSB - default n - - endmenu - -comment "Addons" -config OSCAM_HAVE_DVBAPI - bool "DVB API" - default y - -config OSCAM_READ_SDT_CHARSETS - bool "DVB API read-sdt charsets" - default y - -config OSCAM_IRDETO_GUESSING - bool "Irdeto guessing" - default n - -config OSCAM_CS_ANTICASC - bool "Anti cascading" - default y - -config OSCAM_WITH_DEBUG - bool "Debug messages" - default n - -config OSCAM_MODULE_MONITOR - bool "Monitor" - default n - -config OSCAM_WITH_LB - bool "Loadbalancing" - default y - -config OSCAM_S_CACHEEX - bool "Cache exchange" - default y - -config OSCAM_CW_CYCLE_CHECK - bool "CW Cycle Check" - default y - -config OSCAM_LCDSUPPORT - bool "LCD support" - default n - -config OSCAM_LEDSUPPORT - bool "LED support" - default n - -config OSCAM_CLOCKFIX - bool "Clockfix (disable on old systems!)" - default y - -config OSCAM_IPV6SUPPORT - bool "IPv6 support (experimental)" - default n - - -config OSCAM_WEBIF - bool "Web Interface" - default n - - config OSCAM_WEBIF_LIVELOG - bool "LiveLog" - depends on OSCAM_WEBIF - default n - - config OSCAM_WEBIF_JQUERY - bool "Jquery onboard (if disabled webload)" - depends on OSCAM_WEBIF - default n - - config OSCAM_TOUCH - bool "Touch Web Interface" - depends on OSCAM_WEBIF - default n - - config OSCAM_WITH_SSL - bool "SSL support" - depends on OSCAM_WEBIF - select OSCAM_USE_LIBCRYPTO - default n - -endmenu diff --git a/package/lean/oscam/Makefile b/package/lean/oscam/Makefile deleted file mode 100644 index 15b7952446..0000000000 --- a/package/lean/oscam/Makefile +++ /dev/null @@ -1,204 +0,0 @@ -# -# Copyright (C) 2016 OpenWrt.org -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# -# $Id$ - -include $(TOPDIR)/rules.mk - -PKG_NAME:=oscam -PKG_VERSION:=1.20-$(PKG_REV) -PKG_RELEASE:=1 -PKG_REV:=2780c48789c8e1427df4078ea9b06e0b51594bbc - - -PKG_SOURCE_PROTO:=git -PKG_SOURCE_VERSION:=$(PKG_REV) -PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) -PKG_SOURCE_URL:=https://github.com/coolsnowwolf/oscam.git -PKG_SOURCE:=$(PKG_SOURCE_SUBDIR).tar.bz2 -PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) - -PKG_LICENSE:=GPLv3 -PKG_LICENSE_FILES:=COPYING -PKG_MAINTAINER:=tmn505 - -PKG_CONFIG_DEPENDS := \ - OSCAM_USE_LIBCRYPTO \ - OSCAM_USE_LIBUSB \ - OSCAM_USE_PCSC \ - OSCAM_WEBIF \ - OSCAM_WEBIF_LIVELOG \ - OSCAM_WEBIF_JQUERY \ - OSCAM_TOUCH \ - OSCAM_WITH_SSL \ - OSCAM_HAVE_DVBAPI \ - OSCAM_READ_SDT_CHARSETS \ - OSCAM_IRDETO_GUESSING \ - OSCAM_CS_ANTICASC \ - OSCAM_WITH_DEBUG \ - OSCAM_MODULE_MONITOR \ - OSCAM_WITH_LB \ - OSCAM_CS_CACHEEX \ - OSCAM_CW_CYCLE_CHECK \ - OSCAM_LCDSUPPORT \ - OSCAM_LEDSUPPORT \ - OSCAM_CLOCKFIX \ - OSCAM_IPV6SUPPORT \ - OSCAM_MODULE_CAMD33 \ - OSCAM_MODULE_CAMD35 \ - OSCAM_MODULE_CAMD35_TCP \ - OSCAM_MODULE_NEWCAMD \ - OSCAM_MODULE_CCCAM \ - OSCAM_MODULE_CCCSHARE \ - OSCAM_MODULE_GBOX \ - OSCAM_MODULE_RADEGAST \ - OSCAM_MODULE_SCAM \ - OSCAM_MODULE_SERIAL \ - OSCAM_MODULE_CONSTCW \ - OSCAM_MODULE_PANDORA \ - OSCAM_MODULE_GHTTP \ - OSCAM_READER_NAGRA \ - OSCAM_READER_IRDETO \ - OSCAM_READER_CONAX \ - OSCAM_READER_CRYPTOWORKS \ - OSCAM_READER_SECA \ - OSCAM_READER_VIACCESS \ - OSCAM_READER_VIDEOGUARD \ - OSCAM_READER_DRE \ - OSCAM_READER_TONGFANG \ - OSCAM_READER_BULCRYPT \ - OSCAM_READER_GRIFFIN \ - OSCAM_READER_DGCRYPT \ - OSCAM_CARDREADER_PHOENIX \ - OSCAM_CARDREADER_SC8IN1 \ - OSCAM_CARDREADER_MP35 \ - OSCAM_CARDREADER_SMARGO \ - OSCAM_CARDREADER_STINGER - -include $(INCLUDE_DIR)/package.mk - -define Package/oscam/config - source "$(SOURCE)/Config.in" -endef - -config_files=oscam.ac oscam.cacheex oscam.cert oscam.conf oscam.dvbapi oscam.guess oscam.ird oscam.provid oscam.server oscam.services oscam.srvid oscam.tiers oscam.user oscam.whitelist - -define Package/oscam/conffiles -/etc/oscam/ -endef - -define Package/oscam - SECTION:=net - CATEGORY:=Network - TITLE:=Open Source Conditional Access Modul - URL:=http://www.streamboard.tv/oscam - DEPENDS:=+OSCAM_USE_LIBCRYPTO:libopenssl +OSCAM_USE_LIBUSB:libusb-1.0 +OSCAM_USE_PCSC:pcscd -endef - -define Package/list-smargo - $(call Package/oscam) - TITLE:=List smargo readers - DEPENDS:=oscam -endef - -CONFIGURE_CMD = ./config.sh -CONFIGURE_ARGS = \ - --restore \ - $(if $(CONFIG_OSCAM_WEBIF),--enable,--disable) WEBIF \ - $(if $(CONFIG_OSCAM_WEBIF_LIVELOG),--enable,--disable) WEBIF_LIVELOG \ - $(if $(CONFIG_OSCAM_WEBIF_JQUERY),--enable,--disable) WEBIF_JQUERY \ - $(if $(CONFIG_OSCAM_TOUCH),--enable,--disable) TOUCH \ - $(if $(CONFIG_OSCAM_WITH_SSL),--enable,--disable) WITH_SSL \ - $(if $(CONFIG_OSCAM_HAVE_DVBAPI),--enable,--disable) HAVE_DVBAPI \ - $(if $(CONFIG_OSCAM_READ_SDT_CHARSETS),--enable,--disable) READ_SDT_CHARSETS \ - $(if $(CONFIG_OSCAM_IRDETO_GUESSING),--enable,--disable) IRDETO_GUESSING \ - $(if $(CONFIG_OSCAM_CS_ANTICASC),--enable,--disable) CS_ANTICASC \ - $(if $(CONFIG_OSCAM_WITH_DEBUG),--enable,--disable) WITH_DEBUG \ - $(if $(CONFIG_OSCAM_MODULE_MONITOR),--enable,--disable) MODULE_MONITOR \ - $(if $(CONFIG_OSCAM_WITH_LB),--enable,--disable) WITH_LB \ - $(if $(CONFIG_OSCAM_CS_CACHEEX),--enable,--disable) CS_CACHEEX \ - $(if $(CONFIG_OSCAM_CW_CYCLE_CHECK),--enable,--disable) CW_CYCLE_CHECK \ - $(if $(CONFIG_OSCAM_LCDSUPPORT),--enable,--disable) LCDSUPPORT \ - $(if $(CONFIG_OSCAM_LEDSUPPORT),--enable,--disable) LEDSUPPORT \ - $(if $(CONFIG_OSCAM_CLOCKFIX),--enable,--disable) CLOCKFIX \ - $(if $(CONFIG_OSCAM_IPV6SUPPORT),--enable,--disable) IPV6SUPPORT \ - $(if $(CONFIG_OSCAM_MODULE_CAMD33),--enable,--disable) MODULE_CAMD33 \ - $(if $(CONFIG_OSCAM_MODULE_CAMD35),--enable,--disable) MODULE_CAMD35 \ - $(if $(CONFIG_OSCAM_MODULE_CAMD35_TCP),--enable,--disable) MODULE_CAMD35_TCP \ - $(if $(CONFIG_OSCAM_MODULE_NEWCAMD),--enable,--disable) MODULE_NEWCAMD \ - $(if $(CONFIG_OSCAM_MODULE_CCCAM),--enable,--disable) MODULE_CCCAM \ - $(if $(CONFIG_OSCAM_MODULE_CCCSHARE),--enable,--disable) MODULE_CCCSHARE \ - $(if $(CONFIG_OSCAM_MODULE_GBOX),--enable,--disable) MODULE_GBOX \ - $(if $(CONFIG_OSCAM_MODULE_RADEGAST),--enable,--disable) MODULE_RADEGAST \ - $(if $(CONFIG_OSCAM_MODULE_SCAM),--enable,--disable) MODULE_SCAM \ - $(if $(CONFIG_OSCAM_MODULE_SERIAL),--enable,--disable) MODULE_SERIAL \ - $(if $(CONFIG_OSCAM_MODULE_CONSTCW),--enable,--disable) MODULE_CONSTCW \ - $(if $(CONFIG_OSCAM_MODULE_PANDORA),--enable,--disable) MODULE_PANDORA \ - $(if $(CONFIG_OSCAM_MODULE_GHTTP),--enable,--disable) MODULE_GHTTP \ - $(if $(CONFIG_OSCAM_READER_NAGRA),--enable,--disable) READER_NAGRA \ - $(if $(CONFIG_OSCAM_READER_IRDETO),--enable,--disable) READER_IRDETO \ - $(if $(CONFIG_OSCAM_READER_CONAX),--enable,--disable) READER_CONAX \ - $(if $(CONFIG_OSCAM_READER_CRYPTOWORKS),--enable,--disable) READER_CRYPTOWORKS \ - $(if $(CONFIG_OSCAM_READER_SECA),--enable,--disable) READER_SECA \ - $(if $(CONFIG_OSCAM_READER_VIACCESS),--enable,--disable) READER_VIACCESS \ - $(if $(CONFIG_OSCAM_READER_VIDEOGUARD),--enable,--disable) READER_VIDEOGUARD \ - $(if $(CONFIG_OSCAM_READER_DRE),--enable,--disable) READER_DRE \ - $(if $(CONFIG_OSCAM_READER_TONGFANG),--enable,--disable) READER_TONGFANG \ - $(if $(CONFIG_OSCAM_READER_BULCRYPT),--enable,--disable) READER_BULCRYPT \ - $(if $(CONFIG_OSCAM_READER_GRIFFIN),--enable,--disable) READER_GRIFFIN \ - $(if $(CONFIG_OSCAM_READER_DGCRYPT),--enable,--disable) READER_DGCRYPT \ - $(if $(CONFIG_OSCAM_CARDREADER_PHOENIX),--enable,--disable) CARDREADER_PHOENIX \ - $(if $(CONFIG_OSCAM_CARDREADER_SC8IN1),--enable,--disable) CARDREADER_SC8IN1 \ - $(if $(CONFIG_OSCAM_CARDREADER_MP35),--enable,--disable) CARDREADER_MP35 \ - $(if $(CONFIG_OSCAM_CARDREADER_SMARGO),--enable,--disable) CARDREADER_SMARGO \ - $(if $(CONFIG_OSCAM_CARDREADER_STINGER),--enable,--disable) CARDREADER_STINGER \ - --disable CARDREADER_INTERNAL_AZBOX \ - --disable CARDREADER_INTERNAL_COOLAPI \ - --disable CARDREADER_INTERNAL_COOLAPI2 \ - --disable CARDREADER_INTERNAL_SCI \ - --disable CARDREADER_DB2COM \ - --disable CARDREADER_STAPI \ - --disable CARDREADER_STAPI5 - -MAKE_FLAGS += - -ifeq ($(CONFIG_OSCAM_USE_LIBUSB),y) - MAKE_FLAGS += USE_LIBUSB=1 -endif - -ifeq ($(CONFIG_OSCAM_USE_PCSC),y) - MAKE_FLAGS += USE_PCSC=1 -endif - -ifeq ($(CONFIG_OSCAM_USE_LIBCRYPTO),y) - MAKE_FLAGS += USE_LIBCRYPTO=1 -endif - -ifeq ($(CONFIG_OSCAM_WITH_SSL),y) - MAKE_FLAGS += USE_SSL=1 -endif - -MAKE_FLAGS += CONF_DIR=/etc/oscam -MAKE_FLAGS += OSCAM_BIN=Distribution/oscam -MAKE_FLAGS += LIST_SMARGO_BIN=Distribution/list-smargo - - -define Package/oscam/install - $(INSTALL_DIR) $(1)/usr/sbin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/Distribution/oscam $(1)/usr/sbin/oscam - $(INSTALL_DIR) $(1)/etc/oscam - $(INSTALL_DATA) $(addprefix $(PKG_BUILD_DIR)/Distribution/doc/example/,$(config_files)) $(1)/etc/oscam/ - $(INSTALL_DIR) $(1)/etc/init.d - $(INSTALL_BIN) ./files/oscam.init $(1)/etc/init.d/oscam -endef - -define Package/list-smargo/install - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/Distribution/list-smargo $(1)/usr/bin/list-smargo -endef - -$(eval $(call BuildPackage,oscam)) -$(eval $(call BuildPackage,list-smargo)) diff --git a/package/lean/oscam/files/oscam.init b/package/lean/oscam/files/oscam.init deleted file mode 100644 index b0bf41dc51..0000000000 --- a/package/lean/oscam/files/oscam.init +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright (C) 2016 OpenWrt.org - -START=50 -USE_PROCD=1 - -start_service() { - procd_open_instance - procd_set_param command /usr/sbin/oscam - procd_set_param respawn - procd_close_instance -}
    Edit Stream Relay Config
    Mode (requires OSCam restart) ++ ++
    Source Stream Host:
    Source Stream Port:
    Source Stream User:
    Source Stream Password:
    Relay Port:
    ECM fix delay:
    Process EMM from stream: ++ ++
    AU providers:
    [BISS] Enable date-coded keys:
    [Drecrypt] Path to ee36.bin:
    [Drecrypt] Path to ee56.bin:
    [Drecrypt] Center force group:
    [Drecrypt] Siberia force group: