2 // Common videoguard functions.
6 #ifdef READER_VIDEOGUARD
7 #include "reader-common.h"
8 #include "reader-videoguard-common.h"
10 #define VG_EMMTYPE_MASK 0xC0
11 #define VG_EMMTYPE_G 0
12 #define VG_EMMTYPE_U 1
13 #define VG_EMMTYPE_S 2
15 typedef struct mailmsg_s
29 static LLIST
*vg_msgs
;
31 void set_known_card_info(struct s_reader
*reader
, const uint8_t *atr
, const uint32_t *atr_size
)
33 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
34 /* Set to sensible default values */
35 csystem_data
->card_baseyear
= 1997;
36 csystem_data
->card_tierstart
= 0;
37 csystem_data
->card_system_version
= NDSUNKNOWN
;
38 csystem_data
->card_desc
= "VideoGuard Unknown Card";
40 static const NDS_ATR_ENTRY nds_atr_table
[] = // {atr}, atr len, base year, tier start, nds version, description
43 { { 0x3F, 0x78, 0x13, 0x25, 0x04, 0x40, 0xB0, 0x09, 0x4A, 0x50, 0x01, 0x4E, 0x5A },
44 13, 1992, 0, NDS1
, "VideoGuard Sky New Zealand (0969)" }, // 160E
46 { { 0x3F, 0x78, 0x12, 0x25, 0x01, 0x40, 0xB0, 0x14, 0x4A, 0x50, 0x01, 0x53, 0x44 },
47 13, 1997, 0, NDS1
, "VideoGuard StarTV India (caid unknown)" }, // 105.5E
49 /* known NDS1+ atrs */
50 { { 0x3F, 0x7F, 0x13, 0x25, 0x04, 0x33, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xE0, 0x00, 0x00, 0x54, 0x42, 0x00, 0x00, 0x00 },
51 20, 1997, 0, NDS12
, "VideoGuard China (0988)" },
53 { { 0x3F, 0x78, 0x13, 0x25, 0x03, 0x40, 0xB0, 0x20, 0xFF, 0xFF, 0x4A, 0x50, 0x00 },
54 13, 1997, 0, NDS12
, "VideoGuard DirecTV" },
57 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x33, 0xB0, 0x08, 0xFF, 0xFF, 0x4A, 0x50, 0x90, 0x00, 0x00, 0x47, 0x4C, 0x01 },
58 21, 2004, 0, NDS2
, "VideoGuard Sky Brasil GL39 (0907)" },
60 { { 0x3F, 0x7F, 0x11, 0x25, 0x03, 0x33, 0xB0, 0x09, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x46, 0x44, 0x01, 0x00, 0x00 },
61 20, 2000, 0, NDS2
, "VideoGuard Foxtel Australia (090B)" }, // 156E
63 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x0E, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x49, 0x54, 0x02, 0x00, 0x00 },
64 22, 1997, 0, NDS2
, "VideoGuard Sky Italia (0919)" },
66 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x4A, 0x01, 0x00, 0x00 },
67 22, 2004, 0, NDS2
, "VideoGuard Telekom (Dolce TV) Romania (092F)" },
69 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0F, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x5A, 0x4A, 0x03 },
70 21, 2004, 0, NDS2
, "VideoGuard Telekom (Dolce TV) Romania (0952)" },
72 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x4B, 0x01, 0x00, 0x00 },
73 22, 2004, 0, NDS2
, "VideoGuard Viasat Ukraine (0931)" },
75 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x54, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x55, 0x01, 0x00, 0x00 },
76 22, 1997, 0, NDS2
, "VideoGuard OnoCable Espana (093A)" },
78 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x33, 0xB0, 0x13, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x49, 0x54, 0x03 },
79 21, 1997, 0, NDS2
, "VideoGuard Sky Italia (093B)" },
81 { { 0x3F, 0x7D, 0x11, 0x25, 0x02, 0x41, 0xB0, 0x03, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x56, 0x54, 0x03 },
82 18, 2000, 0, NDS2
, "VideoGuard Viasat (093E)" },
84 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0D, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x56, 0x54, 0x03 },
85 21, 2000, 0, NDS2
, "VideoGuard Viasat (0940)" },
87 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x5A, 0x45, 0x03},
88 21, 2004, 0, NDS2
, "VideoGuard Get Norway (0941)" },
90 { { 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x03, 0xFF, 0xFF, 0x4A, 0x50, 0x80, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x05 },
91 23, 2009, 0, NDS2
, "VideoGuard Sky Brasil GL54 (0943)" },
93 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x4E, 0x5A, 0x03 },
94 21, 1997, 0, NDS2
, "VideoGuard Sky NZ (0958)" },
96 { { 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x03, 0xFF, 0xFF, 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0 },
97 23, 2004, 0, NDS2
, "VideoGuard Sky Mexico (095B)" },
99 { { 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x03, 0xFF, 0xFF, 0x4A, 0x50, 0x80, 0x00, 0x00, 0x00, 0x00, 0x54, 0x56, 0x05 },
100 23, 2004, 0, NDS2
, "VideoGuard Sky Mexico (095B)" },
102 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x00, 0x0F, 0x33, 0xB0, 0x16, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x53, 0x59, 0x03 },
103 21, 2009, 0, NDS2
, "VideoGuard BSkyB (0960)" },
105 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x0D, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x53, 0x59, 0x03 },
106 21, 2009, 0, NDS2
, "VideoGuard BSkyB (0961)" },
108 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x0D, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x53, 0x59, 0x03 },
109 21, 2009, 0, NDS2
, "VideoGuard BSkyB (0961) FastMode" },
111 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x0D, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x53, 0x59, 0x03 },
112 21, 2009, 0, NDS2
, "VideoGuard BSkyB (0961) FastMode" },
114 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x00, 0x0F, 0x33, 0xB0, 0x0F, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x00, 0x00, 0x53, 0x59, 0x02 },
115 21, 2009, 0, NDS2
, "VideoGuard BSkyB (0963)" },
117 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x4E, 0x5A, 0x01, 0x00, 0x00 },
118 22, 1992, 0, NDS2
, "VideoGuard Sky New Zealand (096A)" }, // 160E
120 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x03, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x46, 0x44, 0x03 },
121 21, 2000, 0, NDS2
, "VideoGuard Foxtel Australia (096C)" }, // 156E
123 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
124 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0910)" },
126 { { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
127 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0910) FastMode" },
129 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
130 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0910) FastMode" },
132 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
133 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0910) FastMode" },
135 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
136 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0910) FastMode" },
138 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x41, 0x5A, 0x03 },
139 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0913)"},
141 { { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x41, 0x5A, 0x03 },
142 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0913) FastMode"},
144 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x41, 0x5A, 0x03 },
145 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0913) FastMode"},
147 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x41, 0x5A, 0x03 },
148 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0913) FastMode"},
150 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x41, 0x5A, 0x03 },
151 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0913) FastMode"},
153 { { 0x3F, 0xFF, 0x11, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x11 },
154 22, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (09AC)" },
156 { { 0x3F, 0xFF, 0x12, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x12 },
157 22, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (09AC) FastMode" },
159 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x13 },
160 22, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (09AC) FastMode" },
162 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x14 },
163 22, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (09AC) FastMode" },
165 { { 0x3F, 0xFF, 0x15, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x15 },
166 22, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (09AC) FastMode" },
168 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x34, 0x01, 0x00, 0x14 },
169 22, 1997, 0, NDS2
, "VideoGuard Cingal Philippines (09B4)" },
171 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x15 },
172 22, 2004, 0, NDS2
, "VideoGuard Teleclub (09B6)" },
174 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x15 },
175 22, 2004, 0, NDS2
, "VideoGuard Teleclub (09B6) FastMode" },
177 { { 0x3F, 0xFF, 0x15, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x15 },
178 22, 2004, 0, NDS2
, "VideoGuard Teleclub (09B6) FastMode" },
180 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x38, 0x01, 0x00, 0x14 },
181 22, 1997, 0, NDS2
, "VideoGuard TopTV (09B8)" },
183 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0D, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x42, 0x52, 0x03 },
184 21, 2004, 0, NDS2
, "VideoGuard Airtel India (09BB)" },
186 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0D, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x42, 0x52, 0x03 },
187 21, 2004, 0, NDS2
, "VideoGuard Airtel India (09BB) FastMode" },
189 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0D, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x42, 0x52, 0x03 },
190 21, 2004, 0, NDS2
, "VideoGuard Airtel India (09BB) FastMode" },
192 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x04, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x49, 0x54, 0x03 },
193 21, 1997, 0, NDS2
, "VideoGuard Sky Italia (09CD)" },
195 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x11, 0x69, 0xFF, 0x4A, 0x50, 0x50, 0x00, 0x00, 0x47, 0x54, 0x01, 0x00, 0x00 },
196 22, 1997, 0, NDS2
, "VideoGuard YES DBS Israel" },
198 { { 0x3F, 0x7F, 0x11, 0x25, 0x03, 0x33, 0xB0, 0x09, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x56, 0x54, 0x01, 0x00, 0x00 },
199 20, 2000, 0, NDS2
, "VideoGuard Viasat Scandinavia" },
201 { { 0x3F, 0xFF, 0x11, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x11 },
202 22, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (09C4)" },
204 { { 0x3F, 0xFF, 0x12, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x12 },
205 22, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
207 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x13 },
208 22, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
210 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x14 },
211 22, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
213 { { 0x3F, 0xFF, 0x15, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x15 },
214 22, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
216 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x50, 0x31, 0x03 },
217 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098C)" },
219 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x50, 0x31, 0x03 },
220 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098C) FastMode" },
222 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x50, 0x31, 0x03 },
223 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098C) FastMode" },
225 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x50, 0x31, 0x03 },
226 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098D)" },
228 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x50, 0x31, 0x03 },
229 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098D) FastMode" },
231 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x50, 0x31, 0x03 },
232 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098D) FastMode" },
234 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x48, 0x01, 0x00, 0x00 },
235 22, 2004, 0, NDS2
, "VideoGuard DSMART Turkey" },
237 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x54, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x4B, 0x57, 0x01, 0x00, 0x00 },
238 22, 2020, 0, NDS2
, "VideoGuard Vodafone Germany (098E)" },
240 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x43, 0x01, 0x00, 0x00 },
241 22, 2004, 0, NDS2
, "VideoGuard totalTV Serbia (091F)" },
243 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0F, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x21, 0x5A, 0x43, 0x03 },
244 21, 2004, 0, NDS2
, "VideoGuard totalTV Serbia (0911)" },
246 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x45, 0x01, 0x00, 0x00 },
247 22, 2004, 0, NDS2
, "VideoGuard Get Kabel Norway" },
249 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x14 },
250 22, 2004, 0, NDS2
, "VideoGuard Teleclub (09B6)" },
252 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x00, 0x03, 0x33, 0xB0, 0x15, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x03, 0x4B, 0x4C, 0x03 },
253 21, 2020, 0, NDS2
, "VideoGuard Vodafone Germany G02/G09 (09C7)" },
255 { { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x00, 0x03, 0x33, 0xB0, 0x15, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x03, 0x4B, 0x4C, 0x03 },
256 21, 2020, 0, NDS2
, "VideoGuard Vodafone Germany G02/G09 (09C7) FastMode" },
258 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x00, 0x03, 0x33, 0xB0, 0x15, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x03, 0x4B, 0x4C, 0x03 },
259 21, 2020, 0, NDS2
, "VideoGuard Vodafone Germany G02/G09 (09C7) FastMode" },
261 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x00, 0x03, 0x33, 0xB0, 0x15, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x03, 0x4B, 0x4C, 0x03 },
262 21, 2020, 0, NDS2
, "VideoGuard Vodafone Germany G02/G09 (09C7) FastMode" },
264 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x00, 0x03, 0x33, 0xB0, 0x15, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x03, 0x4B, 0x4C, 0x03 },
265 21, 2020, 0, NDS2
, "VideoGuard Vodafone Germany G02/G09 (09C7) FastMode" },
267 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x47, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x4B, 0x4C, 0x03 },
268 21, 2020, 0, NDS2
, "VideoGuard Vodafone Germany G02/G09 (09EF)" },
270 { { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x47, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x4B, 0x4C, 0x03 },
271 21, 2020, 0, NDS2
, "VideoGuard Vodafone Germany G02/G09 (09EF) FastMode" },
273 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x47, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x4B, 0x4C, 0x03 },
274 21, 2020, 0, NDS2
, "VideoGuard Vodafone Germany G02/G09 (09EF) FastMode" },
276 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x47, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x4B, 0x4C, 0x03 },
277 21, 2020, 0, NDS2
, "VideoGuard Vodafone Germany G02/G09 (09EF) FastMode" },
279 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x47, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x4B, 0x4C, 0x03 },
280 21, 2020, 0, NDS2
, "VideoGuard Vodafone Germany G02/G09 (09EF) FastMode" },
282 { { 0x3F, 0x7D, 0x13, 0x25, 0x02, 0x41, 0xB0, 0x03, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x54, 0x37, 0x03 },
283 18, 2004, 0, NDS2
, "VideoGuard Telecolumbus (09AF)" },
285 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x49, 0x01, 0x00, 0x00 },
286 22, 2004, 0, NDS2
, "VideoGuard Cyprus (092E)" },
288 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x45, 0x01, 0x00, 0x14 },
289 22, 2004, 0, NDS2
, "VideoGuard OTE TV Sat (09BE)" },
291 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x33, 0x54, 0x83 },
292 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0002 Card (0927)" },
294 { { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x33, 0x54, 0x83 },
295 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0002 Card (0927) FastMode" },
297 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x33, 0x54, 0x83 },
298 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0002 Card (0927) FastMode" },
300 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x33, 0x54, 0x83 },
301 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0002 Card (0927) FastMode" },
303 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x33, 0x54, 0x83 },
304 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0002 Card (0927) FastMode" },
306 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x54, 0x33, 0x03 },
307 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0001 Card (0927)" },
309 { { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x54, 0x33, 0x03 },
310 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0001 Card (0927) FastMode" },
312 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x54, 0x33, 0x03 },
313 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0001 Card (0927) FastMode" },
315 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x54, 0x33, 0x03 },
316 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0001 Card (0927) FastMode" },
318 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0B, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x54, 0x33, 0x03 },
319 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0001 Card (0927) FastMode" },
321 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x33, 0x54, 0x83 },
322 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0004 Card (09BF)" },
324 { { 0x3F, 0xFD, 0x12, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x33, 0x54, 0x83 },
325 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0004 Card (09BF) FastMode" },
327 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x33, 0x54, 0x83 },
328 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0004 Card (09BF) FastMode" },
330 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x33, 0x54, 0x83 },
331 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0004 Card (09BF) FastMode" },
333 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x33, 0x54, 0x83 },
334 21, 2008, 0, NDS2
, "VideoGuard TrueVisions 0004 Card (09BF) FastMode" },
336 // NDS Version Unknown as Yet
337 { { 0x3F, 0x7F, 0x13, 0x25, 0x02, 0x40, 0xB0, 0x12, 0x69, 0xFF, 0x4A, 0x50, 0x90, 0x41, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00 },
338 20, 1997, 0, NDSUNKNOWN
, "VideoGuard OnoCable Espana (0915)" },
340 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x44, 0x01, 0x00, 0x14 },
341 22, 1997, 0, NDSUNKNOWN
, "VideoGuard Sky Vivacom (09BD)" }, // 45E
343 { { 0x3F, 0x7F, 0x13, 0x25, 0x05, 0x40, 0xB0, 0x11, 0x69, 0xFF, 0x4A, 0x50, 0x00, 0x00, 0x00, 0x48, 0x4B, 0x00, 0x01, 0x00 },
344 20, 1997, 0, NDSUNKNOWN
, "VideoGuard StarTV India (caid unknown)" }, // 105.5E
346 { { 0x3F, 0x7F, 0x13, 0x25, 0x03, 0x33, 0xB0, 0x11, 0x69, 0xFF, 0x4A, 0x50, 0x50, 0x00, 0x00, 0x49, 0x56, 0x01, 0x00, 0x00 },
347 22, 2004, 50, NDS2
, "VideoGuard Indovision (09C1)" },
349 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x09, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x4A, 0x32, 0x03, 0x00, 0x00 },
350 22, 1997, 0, NDS2
, "VideoGuard Otau TV (09D2)" },
352 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x42, 0x52, 0x01, 0x00, 0x00 },
353 22, 2004, 0, NDS2
, "VideoGuard Cignal India (09AA)" },
355 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x53, 0x56, 0x01, 0x00, 0x00 },
356 22, 2000, 0, NDS2
, "Tata Sky India (0944)" }, // 83.5 East
364 ATR
*newatr
= &atrdata
;
365 ATR_InitFromArray(newatr
, atr
, *atr_size
);
369 uint8_t table_hist
[ATR_MAX_HISTORICAL
];
370 uint32_t table_hist_size
;
372 while(nds_atr_table
[i
].desc
)
374 ATR_InitFromArray(&tableatr
, nds_atr_table
[i
].atr
, nds_atr_table
[i
].atr_len
);
375 ATR_GetHistoricalBytes(&tableatr
, table_hist
, &table_hist_size
);
377 if((hist_size
== table_hist_size
) && (memcmp(hist
, table_hist
, hist_size
) == 0))
379 csystem_data
->card_baseyear
= nds_atr_table
[i
].base_year
;
380 csystem_data
->card_tierstart
= nds_atr_table
[i
].tier_start
;
381 csystem_data
->card_system_version
= nds_atr_table
[i
].nds_version
;
382 csystem_data
->card_desc
= nds_atr_table
[i
].desc
;
389 static void cCamCryptVG_LongMult(uint16_t *pData
, uint16_t *pLen
, uint32_t mult
, uint32_t carry
);
390 static void cCamCryptVG_PartialMod(uint16_t val
, uint32_t count
, uint16_t *outkey
, const uint16_t *inkey
);
391 static void cCamCryptVG_RotateRightAndHash(uint8_t *p
);
392 static void cCamCryptVG_Reorder16A(uint8_t *dest
, const uint8_t *src
);
393 static void cCamCryptVG_ReorderAndEncrypt(struct s_reader
*reader
, uint8_t *p
);
394 static void cCamCryptVG_Process_D0(struct s_reader
*reader
, const uint8_t *ins
, uint8_t *data
);
395 static void cCamCryptVG_Process_D1(struct s_reader
*reader
, const uint8_t *ins
, uint8_t *data
, const uint8_t *status
);
396 static void cCamCryptVG_Decrypt_D3(struct s_reader
*reader
, uint8_t *ins
, uint8_t *data
, const uint8_t *status
);
397 static void cCamCryptVG_PostProcess_Decrypt(struct s_reader
*reader
, uint8_t *rxbuff
);
398 static int32_t cAES_Encrypt(struct s_reader
*reader
, const uint8_t *data
, int32_t len
, uint8_t *crypted
);
399 static void swap_lb(uint8_t *buff
, int32_t len
);
401 // returns 1 if cw_is_valid, returns 0 if cw is all zeros
402 int32_t cw_is_valid(uint8_t *cw
)
406 for(i
= 0; i
< 8; i
++)
408 if(cw
[i
] != 0) // test if cw = 00
416 void cAES_SetKey(struct s_reader
*reader
, const uint8_t *key
)
418 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
419 AES_set_encrypt_key(key
, 128, &(csystem_data
->ekey
));
422 int32_t cAES_Encrypt(struct s_reader
*reader
, const uint8_t *data
, int32_t len
, uint8_t *crypted
)
424 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
425 len
= (len
+ 15) & (~15); // pad up to a multiple of 16
427 for(i
= 0; i
< len
; i
+= 16) { AES_encrypt(data
+ i
, crypted
+ i
, &(csystem_data
->ekey
)); }
431 static void swap_lb(uint8_t *buff
, int32_t len
)
433 #if __BYTE_ORDER != __BIG_ENDIAN
439 for(i
= 0; i
< len
/ 2; i
++)
442 buff
[i
* 2] = buff
[(i
* 2) + 1];
443 buff
[(i
* 2) + 1] = tmp
;
447 void __xxor(uint8_t *data
, int32_t len
, const uint8_t *v1
, const uint8_t *v2
)
453 for(i
= 0; i
< 16; ++i
)
455 data
[i
] = v1
[i
] ^ v2
[i
];
460 for(i
= 0; i
< 8; ++i
)
462 data
[i
] = v1
[i
] ^ v2
[i
];
467 for(i
= 0; i
< 4; ++i
)
469 data
[i
] = v1
[i
] ^ v2
[i
];
474 while(len
--) { *data
++ = *v1
++ ^ *v2
++; }
478 void cCamCryptVG_SetSeed(struct s_reader
*reader
)
480 #if __BYTE_ORDER != __BIG_ENDIAN
481 static const uint8_t key1
[] =
483 0xb9, 0xd5, 0xef, 0xd5, 0xf5, 0xd5, 0xfb, 0xd5, 0x31, 0xd6, 0x43, 0xd6, 0x55, 0xd6, 0x61, 0xd6,
484 0x85, 0xd6, 0x9d, 0xd6, 0xaf, 0xd6, 0xc7, 0xd6, 0xd9, 0xd6, 0x09, 0xd7, 0x15, 0xd7, 0x21, 0xd7,
485 0x27, 0xd7, 0x3f, 0xd7, 0x45, 0xd7, 0xb1, 0xd7, 0xbd, 0xd7, 0xdb, 0xd7, 0x11, 0xd8, 0x23, 0xd8,
486 0x29, 0xd8, 0x2f, 0xd8, 0x4d, 0xd8, 0x8f, 0xd8, 0xa1, 0xd8, 0xad, 0xd8, 0xbf, 0xd8, 0xd7, 0xd8
488 static const uint8_t key2
[] =
490 0x01, 0x00, 0xcf, 0x13, 0xe0, 0x60, 0x54, 0xac, 0xab, 0x99, 0xe6, 0x0c, 0x9f, 0x5b, 0x91, 0xb9,
491 0x72, 0x72, 0x4d, 0x5b, 0x5f, 0xd3, 0xb7, 0x5b, 0x01, 0x4d, 0xef, 0x9e, 0x6b, 0x8a, 0xb9, 0xd1,
492 0xc9, 0x9f, 0xa1, 0x2a, 0x8d, 0x86, 0xb6, 0xd6, 0x39, 0xb4, 0x64, 0x65, 0x13, 0x77, 0xa1, 0x0a,
493 0x0c, 0xcf, 0xb4, 0x2b, 0x3a, 0x2f, 0xd2, 0x09, 0x92, 0x15, 0x40, 0x47, 0x66, 0x5c, 0xda, 0xc9
496 static const uint8_t key1
[] =
498 0xd5, 0xb9, 0xd5, 0xef, 0xd5, 0xf5, 0xd5, 0xfb, 0xd6, 0x31, 0xd6, 0x43, 0xd6, 0x55, 0xd6, 0x61,
499 0xd6, 0x85, 0xd6, 0x9d, 0xd6, 0xaf, 0xd6, 0xc7, 0xd6, 0xd9, 0xd7, 0x09, 0xd7, 0x15, 0xd7, 0x21,
500 0xd7, 0x27, 0xd7, 0x3f, 0xd7, 0x45, 0xd7, 0xb1, 0xd7, 0xbd, 0xd7, 0xdb, 0xd8, 0x11, 0xd8, 0x23,
501 0xd8, 0x29, 0xd8, 0x2f, 0xd8, 0x4d, 0xd8, 0x8f, 0xd8, 0xa1, 0xd8, 0xad, 0xd8, 0xbf, 0xd8, 0xd7
503 static const uint8_t key2
[] =
505 0x00, 0x01, 0x13, 0xcf, 0x60, 0xe0, 0xac, 0x54, 0x99, 0xab, 0x0c, 0xe6, 0x5b, 0x9f, 0xb9, 0x91,
506 0x72, 0x72, 0x5b, 0x4d, 0xd3, 0x5f, 0x5b, 0xb7, 0x4d, 0x01, 0x9e, 0xef, 0x8a, 0x6b, 0xd1, 0xb9,
507 0x9f, 0xc9, 0x2a, 0xa1, 0x86, 0x8d, 0xd6, 0xb6, 0xb4, 0x39, 0x65, 0x64, 0x77, 0x13, 0x0a, 0xa1,
508 0xcf, 0x0c, 0x2b, 0xb4, 0x2f, 0x3a, 0x09, 0xd2, 0x15, 0x92, 0x47, 0x40, 0x5c, 0x66, 0xc9, 0xda
511 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
512 memcpy(csystem_data
->cardkeys
[1], key1
, sizeof(csystem_data
->cardkeys
[1]));
513 memcpy(csystem_data
->cardkeys
[2], key2
, sizeof(csystem_data
->cardkeys
[2]));
516 void cCamCryptVG_GetCamKey(struct s_reader
*reader
, uint16_t *tb2
)
518 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
524 for(i
= 0; i
< 32; i
++)
526 cCamCryptVG_LongMult(tb2
, &c
, csystem_data
->cardkeys
[1][i
], 0);
528 swap_lb((uint8_t *)tb2
, 64);
531 static void cCamCryptVG_PostProcess_Decrypt(struct s_reader
*reader
, uint8_t *rxbuff
)
536 cCamCryptVG_Process_D0(reader
, rxbuff
, rxbuff
+ 5);
540 cCamCryptVG_Process_D1(reader
, rxbuff
, rxbuff
+ 5, rxbuff
+ rxbuff
[4] + 5);
544 cCamCryptVG_Decrypt_D3(reader
, rxbuff
, rxbuff
+ 5, rxbuff
+ rxbuff
[4] + 5);
549 static void cCamCryptVG_Process_D0(struct s_reader
*reader
, const uint8_t *ins
, uint8_t *data
)
551 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
557 memcpy(csystem_data
->cardkeys
[0], data
, sizeof(csystem_data
->cardkeys
[0]));
563 const uint16_t *key1
= (const uint16_t *)csystem_data
->cardkeys
[1];
565 memcpy(key2
, csystem_data
->cardkeys
[2], sizeof(key2
));
568 memcpy((uint8_t *)&iidata
, data
, 64);
570 for(count2
= 0; count2
< 32; count2
++)
572 uint32_t rem
= 0, divisor
= key1
[count2
];
575 for(i
= 31; i
>= 0; i
--)
577 uint32_t x
= iidata
[i
] | (rem
<< 16);
578 rem
= (x
% divisor
) & 0xffff;
581 uint32_t carry
= 1, t
= val_by2on3(divisor
) | 1;
585 if(t
& 1) { carry
= ((carry
* rem
) % divisor
) & 0xffff; }
586 rem
= ((rem
* rem
) % divisor
) & 0xffff;
589 cCamCryptVG_PartialMod(carry
, count2
, key2
, key1
);
592 uint16_t idatacount
= 0;
595 for(i
= 31; i
>= 0; i
--)
597 cCamCryptVG_LongMult(iidata
, &idatacount
, key1
[i
], key2
[i
]);
600 memcpy(data
, iidata
, 64);
603 cCamCryptVG_Reorder16A(stateD1
, data
);
604 cAES_SetKey(reader
, stateD1
);
610 static void cCamCryptVG_Process_D1(struct s_reader
*reader
, const uint8_t *ins
, uint8_t *data
, const uint8_t *status
)
612 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
613 uint8_t iter
[16], tmp
[16];
615 memset(iter
, 0, sizeof(iter
));
616 memcpy(iter
, ins
, 5);
617 xor16(iter
, csystem_data
->stateD3A
, iter
);
618 memcpy(csystem_data
->stateD3A
, iter
, sizeof(iter
));
620 int32_t datalen
= status
- data
;
621 int32_t datalen1
= datalen
;
628 int32_t blocklen
= datalen1
>> 4;
632 for(i
= 0, iblock
= 0; i
< blocklen
+ 2; i
++, iblock
+= 16)
637 if(blocklen
== i
&& (docalc
= datalen
& 0xf))
639 memset(in
, 0, sizeof(in
));
640 memcpy(in
, &data
[iblock
], datalen
- (datalen1
& ~0xf));
642 else if(blocklen
+ 1 == i
)
644 memset(in
, 0, sizeof(in
));
645 memcpy(&in
[5], status
, 2);
649 memcpy(in
, &data
[iblock
], sizeof(in
));
654 xor16(iter
, in
, tmp
);
655 cCamCryptVG_ReorderAndEncrypt(reader
, tmp
);
656 xor16(tmp
, csystem_data
->stateD3A
, iter
);
659 memcpy(csystem_data
->stateD3A
, tmp
, 16);
662 static void cCamCryptVG_Decrypt_D3(struct s_reader
*reader
, uint8_t *ins
, uint8_t *data
, const uint8_t *status
)
664 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
673 memset(csystem_data
->stateD3A
, 0, sizeof(csystem_data
->stateD3A
));
677 memset(tmp
, 0, sizeof(tmp
));
679 xor16(tmp
, csystem_data
->stateD3A
, csystem_data
->stateD3A
);
681 int32_t len1
= ins
[4];
682 int32_t blocklen
= len1
>> 4;
689 uint8_t iter
[16], states
[16][16];
690 memset(iter
, 0, sizeof(iter
));
693 for(blockindex
= 0; blockindex
< blocklen
; blockindex
++)
695 iter
[0] += blockindex
;
696 xor16(iter
, csystem_data
->stateD3A
, iter
);
697 cCamCryptVG_ReorderAndEncrypt(reader
, iter
);
698 xor16(iter
, &data
[blockindex
* 16], states
[blockindex
]);
700 if(blockindex
== (len1
>> 4))
702 int32_t c
= len1
- (blockindex
* 16);
705 memset(&states
[blockindex
][c
], 0, 16 - c
);
708 xor16(states
[blockindex
], csystem_data
->stateD3A
, csystem_data
->stateD3A
);
709 cCamCryptVG_RotateRightAndHash(csystem_data
->stateD3A
);
712 memset(tmp
, 0, sizeof(tmp
));
713 memcpy(tmp
+ 5, status
, 2);
714 xor16(tmp
, csystem_data
->stateD3A
, csystem_data
->stateD3A
);
715 cCamCryptVG_ReorderAndEncrypt(reader
, csystem_data
->stateD3A
);
717 memcpy(csystem_data
->stateD3A
, status
- 16, sizeof(csystem_data
->stateD3A
));
718 cCamCryptVG_ReorderAndEncrypt(reader
, csystem_data
->stateD3A
);
720 memcpy(data
, states
[0], len1
);
724 cCamCryptVG_Reorder16A(tmp
, states
[0]);
725 cAES_SetKey(reader
, tmp
);
729 static void cCamCryptVG_ReorderAndEncrypt(struct s_reader
*reader
, uint8_t *p
)
732 cCamCryptVG_Reorder16A(tmp
, p
);
733 cAES_Encrypt(reader
, tmp
, 16, tmp
);
734 cCamCryptVG_Reorder16A(p
, tmp
);
737 // reorder AAAABBBBCCCCDDDD to ABCDABCDABCDABCD
738 static void cCamCryptVG_Reorder16A(uint8_t *dest
, const uint8_t *src
)
743 for(i
= 0, k
= 0; i
< 4; i
++)
745 for(j
= i
; j
< 16; j
+= 4, k
++)
752 static void cCamCryptVG_LongMult(uint16_t *pData
, uint16_t *pLen
, uint32_t mult
, uint32_t carry
)
755 for(i
= 0; i
< *pLen
; i
++)
757 carry
+= pData
[i
] * mult
;
758 pData
[i
] = (uint16_t)carry
;
762 if(carry
) { pData
[(*pLen
)++] = carry
; }
765 static void cCamCryptVG_PartialMod(uint16_t val
, uint32_t count
, uint16_t *outkey
, const uint16_t *inkey
)
769 uint32_t mod
= inkey
[count
];
770 uint16_t mult
= (inkey
[count
] - outkey
[count
- 1]) & 0xffff;
774 for(i
= 0, ib1
= count
- 2; i
< count
- 1; i
++, ib1
--)
776 uint32_t t
= (inkey
[ib1
] * mult
) % mod
;
777 mult
= t
- outkey
[ib1
];
786 if((val
> mult
) || (mod
< mult
))
790 outkey
[count
] = (outkey
[count
] * mult
) % mod
;
798 static void cCamCryptVG_RotateRightAndHash(uint8_t *p
)
800 static const uint8_t table1
[256] =
802 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
803 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
804 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
805 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
806 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
807 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
808 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
809 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
810 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
811 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
812 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
813 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
814 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
815 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
816 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
817 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
823 for(i
= 0; i
< 16; i
++)
827 p
[i
] = table1
[(t1
>> 1) | ((t2
& 1) << 7)];
831 int32_t status_ok(const uint8_t *status
)
833 //rdr_log(reader, "check status %02x%02x", status[0],status[1]);
834 return (status
[0] == 0x90 || status
[0] == 0x91) &&
835 (status
[1] == 0x00 || status
[1] == 0x01 || status
[1] == 0x20 || status
[1] == 0x21 ||
836 status
[1] == 0x80 || status
[1] == 0x81 || status
[1] == 0xa0 || status
[1] == 0xa1);
839 /*checksum for precam datas*/
840 int32_t checksum_ok(const uint8_t *ird_payload
)
842 int32_t b
, check
= 0;
844 for (b
= 0; b
<= ird_payload
[1]; b
++)
846 check
= (check
+ ird_payload
[b
]) & 0xFF;
849 if (ird_payload
[ird_payload
[1] + 1] == check
)
855 return 0; // Checksum error
859 void memorize_cmd_table(struct s_reader
*reader
, const uint8_t *mem
, int32_t size
)
861 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
862 NULLFREE(csystem_data
->cmd_table
);
863 if(cs_malloc(&csystem_data
->cmd_table
, size
))
865 memcpy(csystem_data
->cmd_table
, mem
, size
);
869 int32_t cmd_table_get_info(struct s_reader
*reader
, const uint8_t *cmd
, uint8_t *rlen
, uint8_t *rmode
)
871 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
872 struct s_CmdTabEntry
*pcte
= csystem_data
->cmd_table
->e
;
875 for(i
= 0; i
< csystem_data
->cmd_table
->Nentries
; i
++, pcte
++)
877 if(cmd
[1] == pcte
->cmd
)
887 int32_t cmd_exists(struct s_reader
*reader
, const uint8_t *cmd
)
889 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
890 struct s_CmdTabEntry
*pcte
= csystem_data
->cmd_table
->e
;
893 for(i
= 0; i
< csystem_data
->cmd_table
->Nentries
; i
++, pcte
++)
895 if(cmd
[1] == pcte
->cmd
)
903 int32_t read_cmd_len(struct s_reader
*reader
, const uint8_t *cmd
)
907 memcpy(cmd2
, cmd
, 5);
909 if(cmd2
[0] == 0xD3) // use classD1 for length request of classD3
917 memcpy(rxbuff
, cmd2
, 5);
919 // some card reply with L 91 00 (L being the command length).
920 if(!write_cmd_vg(cmd2
, NULL
) || !status_ok(cta_res
+ 1) || cta_res
[0] == 0)
922 if(cta_res
[0] == 0) // some cards reply len=0x00 for not supported ins
924 rdr_log_dbg(reader
, D_READER
, "failed to read %02x%02x cmd length (%02x %02x)",
925 cmd
[1], cmd
[2], cta_res
[1], cta_res
[2]);
927 else // others reply only status byte
929 rdr_log_dbg(reader
, D_READER
, "failed to read %02x%02x cmd length (%02x %02x)",
930 cmd
[1], cmd
[2], cta_res
[0], cta_res
[1]);
933 memcpy(rxbuff
+ 5, cta_res
, 3);
934 cCamCryptVG_PostProcess_Decrypt(reader
, rxbuff
);
939 memcpy(rxbuff
+ 5, cta_res
, 3);
940 cCamCryptVG_PostProcess_Decrypt(reader
, rxbuff
);
945 int32_t do_cmd(struct s_reader
*reader
, const uint8_t *ins
, const uint8_t *txbuff
, uint8_t *rxbuff
, uint8_t *cta_res
)
949 memcpy(ins2
, ins
, 5);
950 uint8_t len
= 0, mode
= 0;
952 if(cmd_table_get_info(reader
, ins2
, &len
, &mode
))
954 if(len
== 0xFF && mode
== 2)
958 ins2
[4] = len
= read_cmd_len(reader
, ins2
);
965 else if((mode
!= 0) && ((ins2
[3] != 0x7f) && (ins2
[4] != 0x02)))
990 if(!write_cmd_vg(ins2
, NULL
) || !status_ok(cta_res
+ len
))
995 memcpy(rxbuff
, ins2
, 5);
996 memcpy(rxbuff
+ 5, cta_res
, len
);
997 memcpy(rxbuff
+ 5 + len
, cta_res
+ len
, 2);
1001 if(!write_cmd_vg(ins2
, txbuff
) || !status_ok(cta_res
))
1006 memcpy(rxbuff
, ins2
, 5);
1007 memcpy(rxbuff
+ 5, txbuff
, len
);
1008 memcpy(rxbuff
+ 5 + len
, cta_res
, 2);
1010 cCamCryptVG_PostProcess_Decrypt(reader
, rxbuff
);
1014 rdr_log_dump_dbg(reader
, D_READER
, rxbuff
+ 5, rxbuff
[4], "Decrypted payload");
1020 int32_t videoguard_do_rawcmd(struct s_reader
*reader
, CMD_PACKET
*cp
)
1023 unsigned char cta_res
[CTA_RES_LEN
];
1024 memset(cta_res
, 0, sizeof(cta_res
));
1026 reader
->last_poll
= time(0); // keep videoguard2_poll_status at bay, because it hurts consecutive commands
1028 rc
= do_cmd(reader
, cp
->cmd
, &cp
->cmd
[5], NULL
, cta_res
);
1033 void rev_date_calc_tm(const uint8_t *Date
, struct tm
*timeinfo
, int32_t base_year
)
1035 timeinfo
->tm_year
= Date
[0] / 12 + base_year
- 1900; // tm year starts at 1900
1036 timeinfo
->tm_mon
= Date
[0] % 12; // tm month starts with 0
1037 timeinfo
->tm_mday
= Date
[1] & 0x1f;
1038 timeinfo
->tm_hour
= Date
[2] / 8;
1039 timeinfo
->tm_min
= (0x100 * (Date
[2] - timeinfo
->tm_hour
* 8) + Date
[3]) / 32;
1040 timeinfo
->tm_sec
= (Date
[3] - timeinfo
->tm_min
* 32) * 2;
1043 int32_t videoguard_get_emm_type(EMM_PACKET
*ep
, struct s_reader
*rdr
)
1046 int32_t serial_count
= ((ep
->emm
[3] >> 4) & 3) + 1;
1047 int32_t serial_len
= (ep
->emm
[3] & 0x80) ? 3 : 4;
1048 uint8_t emmtype
= (ep
->emm
[3] & VG_EMMTYPE_MASK
) >> 6;
1053 rdr_log_dbg(rdr
, D_EMM
, "GLOBAL");
1059 rdr_log_dbg(rdr
, D_EMM
, "%s", (emmtype
== VG_EMMTYPE_U
) ? "UNIQUE" : "SHARED");
1061 if(ep
->emm
[1] == 0) // detected UNIQUE EMM from cccam (there is no serial)
1063 rdr_log_dbg(rdr
, D_EMM
, "CCCam unique EMM detected, no serial available, skipping filter check");
1064 ep
->skip_filter_check
= 1;
1067 for(i
= 0; i
< serial_count
; i
++)
1069 if(!memcmp(&ep
->emm
[i
* 4 + 4], rdr
->hexserial
+ 2, serial_len
))
1071 memcpy(ep
->hexserial
, &ep
->emm
[i
* 4 + 4], serial_len
);
1075 return 0; // if UNIQUE or SHARED but no serial match return FALSE
1078 // remote emm without serial
1079 rdr_log_dbg(rdr
, D_EMM
, "UNKNOWN");
1085 int32_t videoguard_do_emm(struct s_reader
*reader
, EMM_PACKET
*ep
, uint8_t CLA
, void (*read_tiers
)(struct s_reader
*),
1086 int32_t (*docmd
)(struct s_reader
*, const uint8_t *ins
, const uint8_t *txbuff
, uint8_t *rxbuff
, uint8_t *cta_res
))
1088 uint8_t cta_res
[CTA_RES_LEN
];
1089 uint8_t ins42
[5] = { CLA
, 0x42, 0x00, 0x00, 0xFF };
1090 uint8_t *EmmIrdHeader
;
1091 int32_t rc
= SKIPPED
;
1092 int32_t nsubs
= ((ep
->emm
[3] & 0x30) >> 4) + 1;
1095 int32_t position
, ua_position
= -1;
1096 int32_t serial_len
= (ep
->type
== SHARED
) ? 3 : 4;
1097 int32_t vdrsc_fix
= 0;
1099 if(ep
->type
== UNIQUE
|| ep
->type
== SHARED
)
1101 if(ep
->emm
[1] == 0x00) // cccam sends emm-u without UA
1109 for(i
= 0; i
< nsubs
; ++i
)
1111 if(memcmp(&ep
->emm
[4 + i
* 4], &reader
->hexserial
[2], serial_len
) == 0)
1120 if(ua_position
== -1)
1126 if(ep
->emm
[offs
] == 0x00 && (ep
->emm
[offs
+ 1] == 0x00 || ep
->emm
[offs
+ 1] == 0x01)) // unmodified emm from dvbapi
1128 emmv2
= ep
->emm
[offs
+ 1];
1129 offs
+= 2 + 1 + emmv2
; // skip sub-emm len (2 bytes sub-emm len if 0x01);
1132 for(position
= 0; position
< nsubs
&& offs
+ 2 < ep
->emmlen
; ++position
)
1134 if(ep
->emm
[offs
] > 0x07) // workaround for mgcamd and emmv2
1139 if(ep
->emm
[offs
] == 0x02 || ep
->emm
[offs
] == 0x03 || ep
->emm
[offs
] == 0x07)
1141 if(ep
->emm
[offs
+1] != 0) // Checksum test for sub-packets emm:
1143 EmmIrdHeader
= ep
->emm
+ offs
; // example:
1144 int32_t chk
; // 827097300000
1145 chk
= checksum_ok(EmmIrdHeader
); // D002 0602C317ABA02F 1690144004A6... chk=2F
1146 if (chk
!= 1) // D607 0E03A3010325070102810002000778 1B90154004A9... chk=78
1147 { // D607 0E03A301032507010281000200097A 1B9015400441... chk=7A
1152 if(ep
->emm
[offs
] == 0x03)
1154 if(position
== ua_position
|| vdrsc_fix
)
1156 videoguard_mail_msg(reader
, &ep
->emm
[offs
+ 2]);
1161 offs
+= ep
->emm
[offs
+ 1] + 2;
1162 if(!(offs
+ 1 < ep
->emmlen
))
1167 if(ep
->emm
[offs
] == 0x00 && (ep
->emm
[offs
+ 1] == 0x00 || ep
->emm
[offs
+ 1] == 0x01))
1169 offs
+= 2 + 1 + emmv2
;
1175 offs
+= ep
->emm
[offs
+ 1] + 2;
1176 if(!(offs
+ 1 < ep
->emmlen
))
1181 if(ep
->emm
[offs
] != 0)
1183 if(ep
->type
== GLOBAL
|| vdrsc_fix
|| position
== ua_position
)
1185 ins42
[4] = ep
->emm
[offs
];
1186 int32_t l
= (*docmd
)(reader
, ins42
, &ep
->emm
[offs
+ 1], NULL
, cta_res
);
1187 rc
= (l
> 0 && status_ok(cta_res
)) ? OK
: ERROR
;
1188 rdr_log_dbg(reader
, D_EMM
, "request return code : %02X%02X", cta_res
[0], cta_res
[1]);
1190 if(status_ok(cta_res
) && (cta_res
[1] & 0x01))
1192 (*read_tiers
)(reader
);
1196 offs
+= ep
->emm
[offs
] + 1;
1197 if(offs
< ep
->emmlen
&& ep
->emm
[offs
] == 0x00)
1217 uint8_t videoguard_get_emm_filter_address_byte(uint8_t isUnique
, uint32_t n
)
1224 // do not filter by sub-emm count
1230 // here we would need two filters,
1231 // one with sub-emm count 1x, and one with 01
1236 // filter sub-emm count with 1x
1241 // filter sub-emm count with 11
1258 uint8_t videoguard_get_emm_filter_address_mask(uint32_t n
)
1265 // at least 1 sub-emm is always present, so we do not care
1269 // must have 2 sub-emms or more (01, 10, 11, but not 00)
1270 // we could create a 1x and 01 filter here,
1271 // but atm we do not care, to keep the filter number low
1275 // must have 3 sub-emms or more (10, 11, but not 00, 01)
1280 // must have 4 sub-emms (11)
1288 int32_t videoguard_get_emm_filter(struct s_reader
*rdr
, struct s_csystem_emm_filter
**emm_filters
, unsigned int *filter_count
)
1290 if(*emm_filters
== NULL
)
1292 const unsigned int max_filter_count
= 7;
1293 if(!cs_malloc(emm_filters
, max_filter_count
* sizeof(struct s_csystem_emm_filter
)))
1298 struct s_csystem_emm_filter
*filters
= *emm_filters
;
1303 for(n
= 0; n
< 3; ++n
)
1305 filters
[idx
].type
= EMM_UNIQUE
;
1306 filters
[idx
].enabled
= 1;
1307 filters
[idx
].filter
[0] = 0x82;
1308 filters
[idx
].mask
[0] = 0xFF;
1309 filters
[idx
].filter
[1] = videoguard_get_emm_filter_address_byte(1, n
);
1310 filters
[idx
].mask
[1] = videoguard_get_emm_filter_address_mask(n
);
1311 memcpy(&filters
[idx
].filter
[2 + 4 * n
], rdr
->hexserial
+ 2, 4);
1312 memset(&filters
[idx
].mask
[2 + 4 * n
], 0xFF, 4);
1316 // fourth serial position does not fit within the 16bytes demux filter
1317 for(n
= 0; n
< 3; ++n
)
1319 filters
[idx
].type
= EMM_SHARED
;
1320 filters
[idx
].enabled
= 1;
1321 filters
[idx
].filter
[0] = 0x82;
1322 filters
[idx
].mask
[0] = 0xFF;
1323 filters
[idx
].filter
[1] = videoguard_get_emm_filter_address_byte(0, n
);
1324 filters
[idx
].mask
[1] = videoguard_get_emm_filter_address_mask(n
);
1325 memcpy(&filters
[idx
].filter
[2 + 4 * n
], rdr
->hexserial
+ 2, 3);
1326 memset(&filters
[idx
].mask
[2 + 4 * n
], 0xFF, 3);
1330 // fourth serial position does not fit within the 16bytes demux filter
1331 filters
[idx
].type
= EMM_GLOBAL
;
1332 filters
[idx
].enabled
= 1;
1333 filters
[idx
].filter
[0] = 0x82;
1334 filters
[idx
].mask
[0] = 0xFF;
1335 filters
[idx
].filter
[1] = 0x00;
1336 filters
[idx
].mask
[1] = 0xC0;
1338 *filter_count
= idx
;
1343 static MAILMSG
*find_msg(uint16_t caid
, uint32_t serial
, uint16_t date
, uint16_t msg_id
)
1346 LL_ITER it
= ll_iter_create(vg_msgs
);
1347 while((msg
= (MAILMSG
*)ll_iter_next(&it
)))
1349 if(msg
->caid
== caid
&& msg
->serial
== serial
&& msg
->date
== date
&& msg
->id
== msg_id
)
1357 static void write_msg(struct s_reader
*reader
, MAILMSG
*msg
, uint32_t baseyear
)
1359 FILE *fp
= fopen(cfg
.mailfile
, "a");
1362 rdr_log(reader
, "Cannot open mailfile %s", cfg
.mailfile
);
1367 for(i
= 0; i
< msg
->len
- 1; ++i
)
1369 if(msg
->message
[i
] == 0x00 && msg
->message
[i
+ 1] == 0x32)
1371 msg
->subject
= &msg
->message
[i
+ 3];
1376 int32_t year
= (msg
->date
>> 8) / 12 + baseyear
;
1377 int32_t mon
= (msg
->date
>> 8) % 12 + 1;
1378 int32_t day
= msg
->date
& 0x1f;
1380 fprintf(fp
, "%04X:%08X:%02d/%02d/%04d:%04X:\"%s\":\"%s\"\n",
1391 NULLFREE(msg
->message
);
1392 msg
->message
= msg
->subject
= 0;
1396 static void msgs_init(uint32_t baseyear
)
1398 vg_msgs
= ll_create("vg_msgs");
1399 FILE *fp
= fopen(cfg
.mailfile
, "r");
1405 int32_t year
, mon
, day
;
1408 while(fgets(buffer
, sizeof(buffer
), fp
))
1411 if(!cs_malloc(&msg
, sizeof(MAILMSG
)))
1417 sscanf(buffer
, "%04hX:%08X:%02d/%02d/%04d:%04hX", &msg
->caid
, &msg
->serial
, &day
, &mon
, &year
, &msg
->id
);
1419 msg
->date
= ((year
* 12) + mon
- 1) << 8 | day
;
1420 msg
->message
= msg
->subject
= 0;
1422 ll_append(vg_msgs
, msg
);
1427 void videoguard_mail_msg(struct s_reader
*rdr
, uint8_t *data
)
1434 struct videoguard_data
*csystem_data
= rdr
->csystem_data
;
1438 msgs_init(csystem_data
->card_baseyear
);
1441 if(data
[0] != 0xFF || data
[1] != 0xFF)
1446 uint16_t msg_id
= (data
[2] << 8) | data
[3];
1447 uint8_t idx
= data
[4] & 0x0F;
1448 int32_t msg_size
= data
[5] * 10 + 2;
1449 uint16_t date
= (data
[9] << 8) | data
[10];
1450 int32_t submsg_len
= data
[12] - 2;
1451 uint16_t submsg_idx
= (data
[13] << 8) | data
[14];
1452 uint32_t serial
= (rdr
->hexserial
[2] << 24) | (rdr
->hexserial
[3] << 16) | (rdr
->hexserial
[4] << 8) | rdr
->hexserial
[5];
1453 MAILMSG
*msg
= find_msg(rdr
->caid
, serial
, date
, msg_id
);
1457 if(!cs_malloc(&msg
, sizeof(MAILMSG
)))
1461 msg
->caid
= rdr
->caid
;
1462 msg
->serial
= serial
;
1465 msg
->nsubs
= (data
[4] & 0xF0) >> 4;
1466 msg
->mask
= 1 << idx
;
1468 msg
->len
= submsg_len
;
1470 if(!cs_malloc(&msg
->message
, msg_size
))
1476 memset(msg
->message
, 0, msg_size
);
1477 memcpy(&msg
->message
[submsg_idx
], &data
[15], submsg_len
);
1479 ll_append(vg_msgs
, msg
);
1483 if(msg
->written
== 1 || msg
->mask
& (1 << idx
))
1488 msg
->mask
|= 1 << idx
;
1489 msg
->len
+= submsg_len
;
1490 memcpy(&msg
->message
[submsg_idx
], &data
[15], submsg_len
);
1493 if(msg
->mask
== (1 << msg
->nsubs
) - 1)
1495 write_msg(rdr
, msg
, csystem_data
->card_baseyear
);