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 Dolce Romania (092F)" },
69 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x4B, 0x01, 0x00, 0x00 },
70 22, 2004, 0, NDS2
, "VideoGuard Viasat Ukraine (0931)" },
72 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x54, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x55, 0x01, 0x00, 0x00 },
73 22, 1997, 0, NDS2
, "VideoGuard OnoCable Espana (093A)" },
75 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x33, 0xB0, 0x13, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x49, 0x54, 0x03 },
76 21, 1997, 0, NDS2
, "VideoGuard Sky Italia (093B)" },
78 { { 0x3F, 0x7D, 0x11, 0x25, 0x02, 0x41, 0xB0, 0x03, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x56, 0x54, 0x03 },
79 18, 2000, 0, NDS2
, "VideoGuard Viasat (093E)" },
81 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0D, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x56, 0x54, 0x03 },
82 21, 2000, 0, NDS2
, "VideoGuard Viasat (0940)" },
84 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x5A, 0x45, 0x03},
85 21, 2004, 0, NDS2
, "VideoGuard Get Norway (0941)" },
87 { { 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x03, 0xFF, 0xFF, 0x4A, 0x50, 0x80, 0x00, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x05 },
88 23, 2009, 0, NDS2
, "VideoGuard Sky Brasil GL54 (0943)" },
90 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x4E, 0x5A, 0x03 },
91 21, 1997, 0, NDS2
, "VideoGuard Sky NZ (0958)" },
93 { { 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x03, 0xFF, 0xFF, 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0 },
94 23, 2004, 0, NDS2
, "VideoGuard Sky Mexico (095B)" },
96 { { 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x03, 0xFF, 0xFF, 0x4A, 0x50, 0x80, 0x00, 0x00, 0x00, 0x00, 0x54, 0x56, 0x05 },
97 23, 2004, 0, NDS2
, "VideoGuard Sky Mexico (095B)" },
99 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x00, 0x0F, 0x33, 0xB0, 0x16, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x53, 0x59, 0x03 },
100 21, 2009, 0, NDS2
, "VideoGuard BSkyB (0960)" },
102 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x00, 0x0F, 0x33, 0xB0, 0x0F, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x00, 0x00, 0x53, 0x59, 0x02 },
103 21, 2009, 0, NDS2
, "VideoGuard BSkyB (0963)" },
105 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x4E, 0x5A, 0x01, 0x00, 0x00 },
106 22, 1992, 0, NDS2
, "VideoGuard Sky New Zealand (096A)" }, // 160E
108 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x03, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x46, 0x44, 0x03 },
109 21, 2000, 0, NDS2
, "VideoGuard Foxtel Australia (096C)" }, // 156E
111 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
112 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0910)" },
114 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x05, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x41, 0x5A, 0x03 },
115 21, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (0910)" },
117 { { 0x3F, 0xFF, 0x11, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x11 },
118 22, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (09AC)" },
120 { { 0x3F, 0xFF, 0x12, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x12 },
121 22, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (09AC) FastMode" },
123 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x13 },
124 22, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (09AC) FastMode" },
126 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x14 },
127 22, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (09AC) FastMode" },
129 { { 0x3F, 0xFF, 0x15, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x41, 0x5A, 0x01, 0x00, 0x15 },
130 22, 2004, 50, NDS2
, "VideoGuard Astro Malaysia (09AC) FastMode" },
132 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x34, 0x01, 0x00, 0x14 },
133 22, 1997, 0, NDS2
, "VideoGuard Cingal Philippines (09B4)" },
135 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x15 },
136 22, 2004, 0, NDS2
, "VideoGuard Teleclub (09B6)" },
138 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x15 },
139 22, 2004, 0, NDS2
, "VideoGuard Teleclub (09B6) FastMode" },
141 { { 0x3F, 0xFF, 0x15, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x15 },
142 22, 2004, 0, NDS2
, "VideoGuard Teleclub (09B6) FastMode" },
144 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x38, 0x01, 0x00, 0x14 },
145 22, 1997, 0, NDS2
, "VideoGuard TopTV (09B8)" },
147 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x04, 0x69, 0xFF, 0x4A, 0x50, 0xD0, 0x80, 0x00, 0x49, 0x54, 0x03 },
148 21, 1997, 0, NDS2
, "VideoGuard Sky Italia (09CD)" },
150 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x11, 0x69, 0xFF, 0x4A, 0x50, 0x50, 0x00, 0x00, 0x47, 0x54, 0x01, 0x00, 0x00 },
151 22, 1997, 0, NDS2
, "VideoGuard YES DBS Israel" },
153 { { 0x3F, 0x7F, 0x11, 0x25, 0x03, 0x33, 0xB0, 0x09, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x56, 0x54, 0x01, 0x00, 0x00 },
154 20, 2000, 0, NDS2
, "VideoGuard Viasat Scandinavia" },
156 { { 0x3F, 0xFF, 0x11, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x11 },
157 22, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (09C4)" },
159 { { 0x3F, 0xFF, 0x12, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x12 },
160 22, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
162 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x13 },
163 22, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
165 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x14 },
166 22, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
168 { { 0x3F, 0xFF, 0x15, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x50, 0x31, 0x01, 0x00, 0x15 },
169 22, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (09C4) FastMode" },
171 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x50, 0x31, 0x03 },
172 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098C)" },
174 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x50, 0x31, 0x03 },
175 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098C) FastMode" },
177 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x0A, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x00, 0x00, 0x50, 0x31, 0x03 },
178 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098C) FastMode" },
180 { { 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x50, 0x31, 0x03 },
181 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098D)" },
183 { { 0x3F, 0xFD, 0x14, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x50, 0x31, 0x03 },
184 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098D) FastMode" },
186 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x55, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x50, 0x31, 0x03 },
187 21, 2004, 0, NDS2
, "VideoGuard Sky Austria/Germany (098D) FastMode" },
189 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x48, 0x01, 0x00, 0x00 },
190 22, 2004, 0, NDS2
, "VideoGuard DSMART Turkey" },
192 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x54, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x4B, 0x57, 0x01, 0x00, 0x00 },
193 22, 2004, 0, NDS2
, "VideoGuard Kabel BW (098E)" },
195 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x43, 0x01, 0x00, 0x00 },
196 22, 2004, 0, NDS2
, "VideoGuard totalTV Serbia (091F)" },
198 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x45, 0x01, 0x00, 0x00 },
199 22, 2004, 0, NDS2
, "VideoGuard Get Kabel Norway" },
201 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x36, 0x01, 0x00, 0x14 },
202 22, 2004, 0, NDS2
, "VideoGuard Teleclub (09B6)" },
204 { { 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x00, 0x03, 0x33, 0xB0, 0x15, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x03, 0x4B, 0x4C, 0x03 },
205 21, 2004, 0, NDS2
, "VideoGuard Kabel Deutschland G02/G09 (09C7)" },
207 { { 0x3F, 0xFD, 0x15, 0x25, 0x02, 0x50, 0x00, 0x03, 0x33, 0xB0, 0x15, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x03, 0x4B, 0x4C, 0x03 },
208 21, 2004, 0, NDS2
, "VideoGuard Kabel Deutschland G02/G09 (09C7) FastMode" },
210 { { 0x3F, 0x7D, 0x13, 0x25, 0x02, 0x41, 0xB0, 0x03, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x54, 0x37, 0x03 },
211 18, 2004, 0, NDS2
, "VideoGuard Telecolumbus (09AF)" },
213 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x5A, 0x49, 0x01, 0x00, 0x00 },
214 22, 2004, 0, NDS2
, "VideoGuard Cyprus (092E)" },
216 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x45, 0x01, 0x00, 0x14 },
217 22, 2004, 0, NDS2
, "VideoGuard OTE TV Sat (09BE)" },
219 // NDS Version Unknown as Yet
220 { { 0x3F, 0x7F, 0x13, 0x25, 0x02, 0x40, 0xB0, 0x12, 0x69, 0xFF, 0x4A, 0x50, 0x90, 0x41, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00 },
221 20, 1997, 0, NDSUNKNOWN
, "VideoGuard OnoCable Espana (0915)" },
223 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x58, 0x44, 0x01, 0x00, 0x14 },
224 22, 1997, 0, NDSUNKNOWN
, "VideoGuard Sky Vivacom (09BD)" }, // 45E
226 { { 0x3F, 0x7F, 0x13, 0x25, 0x05, 0x40, 0xB0, 0x11, 0x69, 0xFF, 0x4A, 0x50, 0x00, 0x00, 0x00, 0x48, 0x4B, 0x00, 0x01, 0x00 },
227 20, 1997, 0, NDSUNKNOWN
, "VideoGuard StarTV India (caid unknown)" }, // 105.5E
229 { { 0x3F, 0x7F, 0x13, 0x25, 0x03, 0x33, 0xB0, 0x11, 0x69, 0xFF, 0x4A, 0x50, 0x50, 0x00, 0x00, 0x49, 0x56, 0x01, 0x00, 0x00 },
230 22, 2004, 50, NDS2
, "VideoGuard Indovision (09C1)" },
232 { { 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x09, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80, 0x00, 0x4A, 0x32, 0x03, 0x00, 0x00 },
233 22, 1997, 0, NDS2
, "VideoGuard Otau TV (09D2)" },
235 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x42, 0x52, 0x01, 0x00, 0x00 },
236 22, 2004, 0, NDS2
, "VideoGuard Cignal India (09AA)" },
238 { { 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x53, 0x56, 0x01, 0x00, 0x00 },
239 22, 2000, 0, NDS2
, "Tata Sky India (0944)" }, // 83.5 East
247 ATR
*newatr
= &atrdata
;
248 ATR_InitFromArray(newatr
, atr
, *atr_size
);
252 uint8_t table_hist
[ATR_MAX_HISTORICAL
];
253 uint32_t table_hist_size
;
255 while(nds_atr_table
[i
].desc
)
257 ATR_InitFromArray(&tableatr
, nds_atr_table
[i
].atr
, nds_atr_table
[i
].atr_len
);
258 ATR_GetHistoricalBytes(&tableatr
, table_hist
, &table_hist_size
);
260 if((hist_size
== table_hist_size
) && (memcmp(hist
, table_hist
, hist_size
) == 0))
262 csystem_data
->card_baseyear
= nds_atr_table
[i
].base_year
;
263 csystem_data
->card_tierstart
= nds_atr_table
[i
].tier_start
;
264 csystem_data
->card_system_version
= nds_atr_table
[i
].nds_version
;
265 csystem_data
->card_desc
= nds_atr_table
[i
].desc
;
272 static void cCamCryptVG_LongMult(uint16_t *pData
, uint16_t *pLen
, uint32_t mult
, uint32_t carry
);
273 static void cCamCryptVG_PartialMod(uint16_t val
, uint32_t count
, uint16_t *outkey
, const uint16_t *inkey
);
274 static void cCamCryptVG_RotateRightAndHash(uint8_t *p
);
275 static void cCamCryptVG_Reorder16A(uint8_t *dest
, const uint8_t *src
);
276 static void cCamCryptVG_ReorderAndEncrypt(struct s_reader
*reader
, uint8_t *p
);
277 static void cCamCryptVG_Process_D0(struct s_reader
*reader
, const uint8_t *ins
, uint8_t *data
);
278 static void cCamCryptVG_Process_D1(struct s_reader
*reader
, const uint8_t *ins
, uint8_t *data
, const uint8_t *status
);
279 static void cCamCryptVG_Decrypt_D3(struct s_reader
*reader
, uint8_t *ins
, uint8_t *data
, const uint8_t *status
);
280 static void cCamCryptVG_PostProcess_Decrypt(struct s_reader
*reader
, uint8_t *rxbuff
);
281 static int32_t cAES_Encrypt(struct s_reader
*reader
, const uint8_t *data
, int32_t len
, uint8_t *crypted
);
282 static void swap_lb(uint8_t *buff
, int32_t len
);
284 // returns 1 if cw_is_valid, returns 0 if cw is all zeros
285 int32_t cw_is_valid(uint8_t *cw
)
289 for(i
= 0; i
< 8; i
++)
291 if(cw
[i
] != 0) // test if cw = 00
299 void cAES_SetKey(struct s_reader
*reader
, const uint8_t *key
)
301 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
302 AES_set_encrypt_key(key
, 128, &(csystem_data
->ekey
));
305 int32_t cAES_Encrypt(struct s_reader
*reader
, const uint8_t *data
, int32_t len
, uint8_t *crypted
)
307 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
308 len
= (len
+ 15) & (~15); // pad up to a multiple of 16
310 for(i
= 0; i
< len
; i
+= 16) { AES_encrypt(data
+ i
, crypted
+ i
, &(csystem_data
->ekey
)); }
314 static void swap_lb(uint8_t *buff
, int32_t len
)
316 #if __BYTE_ORDER != __BIG_ENDIAN
322 for(i
= 0; i
< len
/ 2; i
++)
325 buff
[i
* 2] = buff
[(i
* 2) + 1];
326 buff
[(i
* 2) + 1] = tmp
;
330 void __xxor(uint8_t *data
, int32_t len
, const uint8_t *v1
, const uint8_t *v2
)
336 for(i
= 0; i
< 16; ++i
)
338 data
[i
] = v1
[i
] ^ v2
[i
];
343 for(i
= 0; i
< 8; ++i
)
345 data
[i
] = v1
[i
] ^ v2
[i
];
350 for(i
= 0; i
< 4; ++i
)
352 data
[i
] = v1
[i
] ^ v2
[i
];
357 while(len
--) { *data
++ = *v1
++ ^ *v2
++; }
361 void cCamCryptVG_SetSeed(struct s_reader
*reader
)
363 #if __BYTE_ORDER != __BIG_ENDIAN
364 static const uint8_t key1
[] =
366 0xb9, 0xd5, 0xef, 0xd5, 0xf5, 0xd5, 0xfb, 0xd5, 0x31, 0xd6, 0x43, 0xd6, 0x55, 0xd6, 0x61, 0xd6,
367 0x85, 0xd6, 0x9d, 0xd6, 0xaf, 0xd6, 0xc7, 0xd6, 0xd9, 0xd6, 0x09, 0xd7, 0x15, 0xd7, 0x21, 0xd7,
368 0x27, 0xd7, 0x3f, 0xd7, 0x45, 0xd7, 0xb1, 0xd7, 0xbd, 0xd7, 0xdb, 0xd7, 0x11, 0xd8, 0x23, 0xd8,
369 0x29, 0xd8, 0x2f, 0xd8, 0x4d, 0xd8, 0x8f, 0xd8, 0xa1, 0xd8, 0xad, 0xd8, 0xbf, 0xd8, 0xd7, 0xd8
371 static const uint8_t key2
[] =
373 0x01, 0x00, 0xcf, 0x13, 0xe0, 0x60, 0x54, 0xac, 0xab, 0x99, 0xe6, 0x0c, 0x9f, 0x5b, 0x91, 0xb9,
374 0x72, 0x72, 0x4d, 0x5b, 0x5f, 0xd3, 0xb7, 0x5b, 0x01, 0x4d, 0xef, 0x9e, 0x6b, 0x8a, 0xb9, 0xd1,
375 0xc9, 0x9f, 0xa1, 0x2a, 0x8d, 0x86, 0xb6, 0xd6, 0x39, 0xb4, 0x64, 0x65, 0x13, 0x77, 0xa1, 0x0a,
376 0x0c, 0xcf, 0xb4, 0x2b, 0x3a, 0x2f, 0xd2, 0x09, 0x92, 0x15, 0x40, 0x47, 0x66, 0x5c, 0xda, 0xc9
379 static const uint8_t key1
[] =
381 0xd5, 0xb9, 0xd5, 0xef, 0xd5, 0xf5, 0xd5, 0xfb, 0xd6, 0x31, 0xd6, 0x43, 0xd6, 0x55, 0xd6, 0x61,
382 0xd6, 0x85, 0xd6, 0x9d, 0xd6, 0xaf, 0xd6, 0xc7, 0xd6, 0xd9, 0xd7, 0x09, 0xd7, 0x15, 0xd7, 0x21,
383 0xd7, 0x27, 0xd7, 0x3f, 0xd7, 0x45, 0xd7, 0xb1, 0xd7, 0xbd, 0xd7, 0xdb, 0xd8, 0x11, 0xd8, 0x23,
384 0xd8, 0x29, 0xd8, 0x2f, 0xd8, 0x4d, 0xd8, 0x8f, 0xd8, 0xa1, 0xd8, 0xad, 0xd8, 0xbf, 0xd8, 0xd7
386 static const uint8_t key2
[] =
388 0x00, 0x01, 0x13, 0xcf, 0x60, 0xe0, 0xac, 0x54, 0x99, 0xab, 0x0c, 0xe6, 0x5b, 0x9f, 0xb9, 0x91,
389 0x72, 0x72, 0x5b, 0x4d, 0xd3, 0x5f, 0x5b, 0xb7, 0x4d, 0x01, 0x9e, 0xef, 0x8a, 0x6b, 0xd1, 0xb9,
390 0x9f, 0xc9, 0x2a, 0xa1, 0x86, 0x8d, 0xd6, 0xb6, 0xb4, 0x39, 0x65, 0x64, 0x77, 0x13, 0x0a, 0xa1,
391 0xcf, 0x0c, 0x2b, 0xb4, 0x2f, 0x3a, 0x09, 0xd2, 0x15, 0x92, 0x47, 0x40, 0x5c, 0x66, 0xc9, 0xda
394 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
395 memcpy(csystem_data
->cardkeys
[1], key1
, sizeof(csystem_data
->cardkeys
[1]));
396 memcpy(csystem_data
->cardkeys
[2], key2
, sizeof(csystem_data
->cardkeys
[2]));
399 void cCamCryptVG_GetCamKey(struct s_reader
*reader
, uint16_t *tb2
)
401 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
407 for(i
= 0; i
< 32; i
++)
409 cCamCryptVG_LongMult(tb2
, &c
, csystem_data
->cardkeys
[1][i
], 0);
411 swap_lb((uint8_t *)tb2
, 64);
414 static void cCamCryptVG_PostProcess_Decrypt(struct s_reader
*reader
, uint8_t *rxbuff
)
419 cCamCryptVG_Process_D0(reader
, rxbuff
, rxbuff
+ 5);
423 cCamCryptVG_Process_D1(reader
, rxbuff
, rxbuff
+ 5, rxbuff
+ rxbuff
[4] + 5);
427 cCamCryptVG_Decrypt_D3(reader
, rxbuff
, rxbuff
+ 5, rxbuff
+ rxbuff
[4] + 5);
432 static void cCamCryptVG_Process_D0(struct s_reader
*reader
, const uint8_t *ins
, uint8_t *data
)
434 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
440 memcpy(csystem_data
->cardkeys
[0], data
, sizeof(csystem_data
->cardkeys
[0]));
446 const uint16_t *key1
= (const uint16_t *)csystem_data
->cardkeys
[1];
448 memcpy(key2
, csystem_data
->cardkeys
[2], sizeof(key2
));
451 memcpy((uint8_t *)&iidata
, data
, 64);
453 for(count2
= 0; count2
< 32; count2
++)
455 uint32_t rem
= 0, divisor
= key1
[count2
];
458 for(i
= 31; i
>= 0; i
--)
460 uint32_t x
= iidata
[i
] | (rem
<< 16);
461 rem
= (x
% divisor
) & 0xffff;
464 uint32_t carry
= 1, t
= val_by2on3(divisor
) | 1;
468 if(t
& 1) { carry
= ((carry
* rem
) % divisor
) & 0xffff; }
469 rem
= ((rem
* rem
) % divisor
) & 0xffff;
472 cCamCryptVG_PartialMod(carry
, count2
, key2
, key1
);
475 uint16_t idatacount
= 0;
478 for(i
= 31; i
>= 0; i
--)
480 cCamCryptVG_LongMult(iidata
, &idatacount
, key1
[i
], key2
[i
]);
483 memcpy(data
, iidata
, 64);
486 cCamCryptVG_Reorder16A(stateD1
, data
);
487 cAES_SetKey(reader
, stateD1
);
493 static void cCamCryptVG_Process_D1(struct s_reader
*reader
, const uint8_t *ins
, uint8_t *data
, const uint8_t *status
)
495 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
496 uint8_t iter
[16], tmp
[16];
498 memset(iter
, 0, sizeof(iter
));
499 memcpy(iter
, ins
, 5);
500 xor16(iter
, csystem_data
->stateD3A
, iter
);
501 memcpy(csystem_data
->stateD3A
, iter
, sizeof(iter
));
503 int32_t datalen
= status
- data
;
504 int32_t datalen1
= datalen
;
511 int32_t blocklen
= datalen1
>> 4;
515 for(i
= 0, iblock
= 0; i
< blocklen
+ 2; i
++, iblock
+= 16)
520 if(blocklen
== i
&& (docalc
= datalen
& 0xf))
522 memset(in
, 0, sizeof(in
));
523 memcpy(in
, &data
[iblock
], datalen
- (datalen1
& ~0xf));
525 else if(blocklen
+ 1 == i
)
527 memset(in
, 0, sizeof(in
));
528 memcpy(&in
[5], status
, 2);
532 memcpy(in
, &data
[iblock
], sizeof(in
));
537 xor16(iter
, in
, tmp
);
538 cCamCryptVG_ReorderAndEncrypt(reader
, tmp
);
539 xor16(tmp
, csystem_data
->stateD3A
, iter
);
542 memcpy(csystem_data
->stateD3A
, tmp
, 16);
545 static void cCamCryptVG_Decrypt_D3(struct s_reader
*reader
, uint8_t *ins
, uint8_t *data
, const uint8_t *status
)
547 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
556 memset(csystem_data
->stateD3A
, 0, sizeof(csystem_data
->stateD3A
));
560 memset(tmp
, 0, sizeof(tmp
));
562 xor16(tmp
, csystem_data
->stateD3A
, csystem_data
->stateD3A
);
564 int32_t len1
= ins
[4];
565 int32_t blocklen
= len1
>> 4;
572 uint8_t iter
[16], states
[16][16];
573 memset(iter
, 0, sizeof(iter
));
576 for(blockindex
= 0; blockindex
< blocklen
; blockindex
++)
578 iter
[0] += blockindex
;
579 xor16(iter
, csystem_data
->stateD3A
, iter
);
580 cCamCryptVG_ReorderAndEncrypt(reader
, iter
);
581 xor16(iter
, &data
[blockindex
* 16], states
[blockindex
]);
583 if(blockindex
== (len1
>> 4))
585 int32_t c
= len1
- (blockindex
* 16);
588 memset(&states
[blockindex
][c
], 0, 16 - c
);
591 xor16(states
[blockindex
], csystem_data
->stateD3A
, csystem_data
->stateD3A
);
592 cCamCryptVG_RotateRightAndHash(csystem_data
->stateD3A
);
595 memset(tmp
, 0, sizeof(tmp
));
596 memcpy(tmp
+ 5, status
, 2);
597 xor16(tmp
, csystem_data
->stateD3A
, csystem_data
->stateD3A
);
598 cCamCryptVG_ReorderAndEncrypt(reader
, csystem_data
->stateD3A
);
600 memcpy(csystem_data
->stateD3A
, status
- 16, sizeof(csystem_data
->stateD3A
));
601 cCamCryptVG_ReorderAndEncrypt(reader
, csystem_data
->stateD3A
);
603 memcpy(data
, states
[0], len1
);
607 cCamCryptVG_Reorder16A(tmp
, states
[0]);
608 cAES_SetKey(reader
, tmp
);
612 static void cCamCryptVG_ReorderAndEncrypt(struct s_reader
*reader
, uint8_t *p
)
615 cCamCryptVG_Reorder16A(tmp
, p
);
616 cAES_Encrypt(reader
, tmp
, 16, tmp
);
617 cCamCryptVG_Reorder16A(p
, tmp
);
620 // reorder AAAABBBBCCCCDDDD to ABCDABCDABCDABCD
621 static void cCamCryptVG_Reorder16A(uint8_t *dest
, const uint8_t *src
)
626 for(i
= 0, k
= 0; i
< 4; i
++)
628 for(j
= i
; j
< 16; j
+= 4, k
++)
635 static void cCamCryptVG_LongMult(uint16_t *pData
, uint16_t *pLen
, uint32_t mult
, uint32_t carry
)
638 for(i
= 0; i
< *pLen
; i
++)
640 carry
+= pData
[i
] * mult
;
641 pData
[i
] = (uint16_t)carry
;
645 if(carry
) { pData
[(*pLen
)++] = carry
; }
648 static void cCamCryptVG_PartialMod(uint16_t val
, uint32_t count
, uint16_t *outkey
, const uint16_t *inkey
)
652 uint32_t mod
= inkey
[count
];
653 uint16_t mult
= (inkey
[count
] - outkey
[count
- 1]) & 0xffff;
657 for(i
= 0, ib1
= count
- 2; i
< count
- 1; i
++, ib1
--)
659 uint32_t t
= (inkey
[ib1
] * mult
) % mod
;
660 mult
= t
- outkey
[ib1
];
669 if((val
> mult
) || (mod
< mult
))
673 outkey
[count
] = (outkey
[count
] * mult
) % mod
;
681 static void cCamCryptVG_RotateRightAndHash(uint8_t *p
)
683 static const uint8_t table1
[256] =
685 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
686 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
687 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
688 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
689 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
690 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
691 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
692 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
693 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
694 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
695 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
696 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
697 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
698 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
699 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
700 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
706 for(i
= 0; i
< 16; i
++)
710 p
[i
] = table1
[(t1
>> 1) | ((t2
& 1) << 7)];
714 int32_t status_ok(const uint8_t *status
)
716 //rdr_log(reader, "check status %02x%02x", status[0],status[1]);
717 return (status
[0] == 0x90 || status
[0] == 0x91) &&
718 (status
[1] == 0x00 || status
[1] == 0x01 || status
[1] == 0x20 || status
[1] == 0x21 ||
719 status
[1] == 0x80 || status
[1] == 0x81 || status
[1] == 0xa0 || status
[1] == 0xa1);
722 /*checksum for precam datas*/
723 int32_t checksum_ok(const uint8_t *ird_payload
)
725 int32_t b
, check
= 0;
727 for (b
= 0; b
<= ird_payload
[1]; b
++)
729 check
= (check
+ ird_payload
[b
]) & 0xFF;
732 if (ird_payload
[ird_payload
[1] + 1] == check
)
738 return 0; // Checksum error
742 void memorize_cmd_table(struct s_reader
*reader
, const uint8_t *mem
, int32_t size
)
744 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
745 NULLFREE(csystem_data
->cmd_table
);
746 if(cs_malloc(&csystem_data
->cmd_table
, size
))
748 memcpy(csystem_data
->cmd_table
, mem
, size
);
752 int32_t cmd_table_get_info(struct s_reader
*reader
, const uint8_t *cmd
, uint8_t *rlen
, uint8_t *rmode
)
754 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
755 struct s_CmdTabEntry
*pcte
= csystem_data
->cmd_table
->e
;
758 for(i
= 0; i
< csystem_data
->cmd_table
->Nentries
; i
++, pcte
++)
760 if(cmd
[1] == pcte
->cmd
)
770 int32_t cmd_exists(struct s_reader
*reader
, const uint8_t *cmd
)
772 struct videoguard_data
*csystem_data
= reader
->csystem_data
;
773 struct s_CmdTabEntry
*pcte
= csystem_data
->cmd_table
->e
;
776 for(i
= 0; i
< csystem_data
->cmd_table
->Nentries
; i
++, pcte
++)
778 if(cmd
[1] == pcte
->cmd
)
786 int32_t read_cmd_len(struct s_reader
*reader
, const uint8_t *cmd
)
790 memcpy(cmd2
, cmd
, 5);
792 if(cmd2
[0] == 0xD3) // use classD1 for length request of classD3
800 memcpy(rxbuff
, cmd2
, 5);
802 // some card reply with L 91 00 (L being the command length).
803 if(!write_cmd_vg(cmd2
, NULL
) || !status_ok(cta_res
+ 1) || cta_res
[0] == 0)
805 if(cta_res
[0] == 0) // some cards reply len=0x00 for not supported ins
807 rdr_log_dbg(reader
, D_READER
, "failed to read %02x%02x cmd length (%02x %02x)",
808 cmd
[1], cmd
[2], cta_res
[1], cta_res
[2]);
810 else // others reply only status byte
812 rdr_log_dbg(reader
, D_READER
, "failed to read %02x%02x cmd length (%02x %02x)",
813 cmd
[1], cmd
[2], cta_res
[0], cta_res
[1]);
816 memcpy(rxbuff
+ 5, cta_res
, 3);
817 cCamCryptVG_PostProcess_Decrypt(reader
, rxbuff
);
822 memcpy(rxbuff
+ 5, cta_res
, 3);
823 cCamCryptVG_PostProcess_Decrypt(reader
, rxbuff
);
828 int32_t do_cmd(struct s_reader
*reader
, const uint8_t *ins
, const uint8_t *txbuff
, uint8_t *rxbuff
, uint8_t *cta_res
)
832 memcpy(ins2
, ins
, 5);
833 uint8_t len
= 0, mode
= 0;
835 if(cmd_table_get_info(reader
, ins2
, &len
, &mode
))
837 if(len
== 0xFF && mode
== 2)
841 ins2
[4] = len
= read_cmd_len(reader
, ins2
);
848 else if((mode
!= 0) && ((ins2
[3] != 0x7f) && (ins2
[4] != 0x02)))
873 if(!write_cmd_vg(ins2
, NULL
) || !status_ok(cta_res
+ len
))
878 memcpy(rxbuff
, ins2
, 5);
879 memcpy(rxbuff
+ 5, cta_res
, len
);
880 memcpy(rxbuff
+ 5 + len
, cta_res
+ len
, 2);
884 if(!write_cmd_vg(ins2
, txbuff
) || !status_ok(cta_res
))
889 memcpy(rxbuff
, ins2
, 5);
890 memcpy(rxbuff
+ 5, txbuff
, len
);
891 memcpy(rxbuff
+ 5 + len
, cta_res
, 2);
893 cCamCryptVG_PostProcess_Decrypt(reader
, rxbuff
);
897 rdr_log_dump_dbg(reader
, D_READER
, rxbuff
+ 5, rxbuff
[4], "Decrypted payload");
903 void rev_date_calc_tm(const uint8_t *Date
, struct tm
*timeinfo
, int32_t base_year
)
905 timeinfo
->tm_year
= Date
[0] / 12 + base_year
- 1900; // tm year starts at 1900
906 timeinfo
->tm_mon
= Date
[0] % 12; // tm month starts with 0
907 timeinfo
->tm_mday
= Date
[1] & 0x1f;
908 timeinfo
->tm_hour
= Date
[2] / 8;
909 timeinfo
->tm_min
= (0x100 * (Date
[2] - timeinfo
->tm_hour
* 8) + Date
[3]) / 32;
910 timeinfo
->tm_sec
= (Date
[3] - timeinfo
->tm_min
* 32) * 2;
913 int32_t videoguard_get_emm_type(EMM_PACKET
*ep
, struct s_reader
*rdr
)
916 int32_t serial_count
= ((ep
->emm
[3] >> 4) & 3) + 1;
917 int32_t serial_len
= (ep
->emm
[3] & 0x80) ? 3 : 4;
918 uint8_t emmtype
= (ep
->emm
[3] & VG_EMMTYPE_MASK
) >> 6;
923 rdr_log_dbg(rdr
, D_EMM
, "GLOBAL");
929 rdr_log_dbg(rdr
, D_EMM
, "%s", (emmtype
== VG_EMMTYPE_U
) ? "UNIQUE" : "SHARED");
931 if(ep
->emm
[1] == 0) // detected UNIQUE EMM from cccam (there is no serial)
933 rdr_log_dbg(rdr
, D_EMM
, "CCCam unique EMM detected, no serial available, skipping filter check");
934 ep
->skip_filter_check
= 1;
937 for(i
= 0; i
< serial_count
; i
++)
939 if(!memcmp(&ep
->emm
[i
* 4 + 4], rdr
->hexserial
+ 2, serial_len
))
941 memcpy(ep
->hexserial
, &ep
->emm
[i
* 4 + 4], serial_len
);
945 return 0; // if UNIQUE or SHARED but no serial match return FALSE
948 // remote emm without serial
949 rdr_log_dbg(rdr
, D_EMM
, "UNKNOWN");
955 int32_t videoguard_do_emm(struct s_reader
*reader
, EMM_PACKET
*ep
, uint8_t CLA
, void (*read_tiers
)(struct s_reader
*),
956 int32_t (*docmd
)(struct s_reader
*, const uint8_t *ins
, const uint8_t *txbuff
, uint8_t *rxbuff
, uint8_t *cta_res
))
958 uint8_t cta_res
[CTA_RES_LEN
];
959 uint8_t ins42
[5] = { CLA
, 0x42, 0x00, 0x00, 0xFF };
960 uint8_t *EmmIrdHeader
;
961 int32_t rc
= SKIPPED
;
962 int32_t nsubs
= ((ep
->emm
[3] & 0x30) >> 4) + 1;
965 int32_t position
, ua_position
= -1;
966 int32_t serial_len
= (ep
->type
== SHARED
) ? 3 : 4;
967 int32_t vdrsc_fix
= 0;
969 if(ep
->type
== UNIQUE
|| ep
->type
== SHARED
)
971 if(ep
->emm
[1] == 0x00) // cccam sends emm-u without UA
979 for(i
= 0; i
< nsubs
; ++i
)
981 if(memcmp(&ep
->emm
[4 + i
* 4], &reader
->hexserial
[2], serial_len
) == 0)
990 if(ua_position
== -1)
996 if(ep
->emm
[offs
] == 0x00 && (ep
->emm
[offs
+ 1] == 0x00 || ep
->emm
[offs
+ 1] == 0x01)) // unmodified emm from dvbapi
998 emmv2
= ep
->emm
[offs
+ 1];
999 offs
+= 2 + 1 + emmv2
; // skip sub-emm len (2 bytes sub-emm len if 0x01);
1002 for(position
= 0; position
< nsubs
&& offs
+ 2 < ep
->emmlen
; ++position
)
1004 if(ep
->emm
[offs
] > 0x07) // workaround for mgcamd and emmv2
1009 if(ep
->emm
[offs
] == 0x02 || ep
->emm
[offs
] == 0x03 || ep
->emm
[offs
] == 0x07)
1011 if(ep
->emm
[offs
+1] != 0) // Checksum test for sub-packets emm:
1013 EmmIrdHeader
= ep
->emm
+ offs
; // example:
1014 int32_t chk
; // 827097300000
1015 chk
= checksum_ok(EmmIrdHeader
); // D002 0602C317ABA02F 1690144004A6... chk=2F
1016 if (chk
!= 1) // D607 0E03A3010325070102810002000778 1B90154004A9... chk=78
1017 { // D607 0E03A301032507010281000200097A 1B9015400441... chk=7A
1022 if(ep
->emm
[offs
] == 0x03)
1024 if(position
== ua_position
|| vdrsc_fix
)
1026 videoguard_mail_msg(reader
, &ep
->emm
[offs
+ 2]);
1031 offs
+= ep
->emm
[offs
+ 1] + 2;
1032 if(!(offs
+ 1 < ep
->emmlen
))
1037 if(ep
->emm
[offs
] == 0x00 && (ep
->emm
[offs
+ 1] == 0x00 || ep
->emm
[offs
+ 1] == 0x01))
1039 offs
+= 2 + 1 + emmv2
;
1045 offs
+= ep
->emm
[offs
+ 1] + 2;
1046 if(!(offs
+ 1 < ep
->emmlen
))
1051 if(ep
->emm
[offs
] != 0)
1053 if(ep
->type
== GLOBAL
|| vdrsc_fix
|| position
== ua_position
)
1055 ins42
[4] = ep
->emm
[offs
];
1056 int32_t l
= (*docmd
)(reader
, ins42
, &ep
->emm
[offs
+ 1], NULL
, cta_res
);
1057 rc
= (l
> 0 && status_ok(cta_res
)) ? OK
: ERROR
;
1058 rdr_log_dbg(reader
, D_EMM
, "request return code : %02X%02X", cta_res
[0], cta_res
[1]);
1060 if(status_ok(cta_res
) && (cta_res
[1] & 0x01))
1062 (*read_tiers
)(reader
);
1066 offs
+= ep
->emm
[offs
] + 1;
1067 if(offs
< ep
->emmlen
&& ep
->emm
[offs
] == 0x00)
1087 uint8_t videoguard_get_emm_filter_address_byte(uint8_t isUnique
, uint32_t n
)
1094 // do not filter by sub-emm count
1100 // here we would need two filters,
1101 // one with sub-emm count 1x, and one with 01
1106 // filter sub-emm count with 1x
1111 // filter sub-emm count with 11
1128 uint8_t videoguard_get_emm_filter_address_mask(uint32_t n
)
1135 // at least 1 sub-emm is always present, so we do not care
1139 // must have 2 sub-emms or more (01, 10, 11, but not 00)
1140 // we could create a 1x and 01 filter here,
1141 // but atm we do not care, to keep the filter number low
1145 // must have 3 sub-emms or more (10, 11, but not 00, 01)
1150 // must have 4 sub-emms (11)
1158 int32_t videoguard_get_emm_filter(struct s_reader
*rdr
, struct s_csystem_emm_filter
**emm_filters
, unsigned int *filter_count
)
1160 if(*emm_filters
== NULL
)
1162 const unsigned int max_filter_count
= 7;
1163 if(!cs_malloc(emm_filters
, max_filter_count
* sizeof(struct s_csystem_emm_filter
)))
1168 struct s_csystem_emm_filter
*filters
= *emm_filters
;
1173 for(n
= 0; n
< 3; ++n
)
1175 filters
[idx
].type
= EMM_UNIQUE
;
1176 filters
[idx
].enabled
= 1;
1177 filters
[idx
].filter
[0] = 0x82;
1178 filters
[idx
].mask
[0] = 0xFF;
1179 filters
[idx
].filter
[1] = videoguard_get_emm_filter_address_byte(1, n
);
1180 filters
[idx
].mask
[1] = videoguard_get_emm_filter_address_mask(n
);
1181 memcpy(&filters
[idx
].filter
[2 + 4 * n
], rdr
->hexserial
+ 2, 4);
1182 memset(&filters
[idx
].mask
[2 + 4 * n
], 0xFF, 4);
1186 // fourth serial position does not fit within the 16bytes demux filter
1187 for(n
= 0; n
< 3; ++n
)
1189 filters
[idx
].type
= EMM_SHARED
;
1190 filters
[idx
].enabled
= 1;
1191 filters
[idx
].filter
[0] = 0x82;
1192 filters
[idx
].mask
[0] = 0xFF;
1193 filters
[idx
].filter
[1] = videoguard_get_emm_filter_address_byte(0, n
);
1194 filters
[idx
].mask
[1] = videoguard_get_emm_filter_address_mask(n
);
1195 memcpy(&filters
[idx
].filter
[2 + 4 * n
], rdr
->hexserial
+ 2, 3);
1196 memset(&filters
[idx
].mask
[2 + 4 * n
], 0xFF, 3);
1200 // fourth serial position does not fit within the 16bytes demux filter
1201 filters
[idx
].type
= EMM_GLOBAL
;
1202 filters
[idx
].enabled
= 1;
1203 filters
[idx
].filter
[0] = 0x82;
1204 filters
[idx
].mask
[0] = 0xFF;
1205 filters
[idx
].filter
[1] = 0x00;
1206 filters
[idx
].mask
[1] = 0xC0;
1208 *filter_count
= idx
;
1213 static MAILMSG
*find_msg(uint16_t caid
, uint32_t serial
, uint16_t date
, uint16_t msg_id
)
1216 LL_ITER it
= ll_iter_create(vg_msgs
);
1217 while((msg
= (MAILMSG
*)ll_iter_next(&it
)))
1219 if(msg
->caid
== caid
&& msg
->serial
== serial
&& msg
->date
== date
&& msg
->id
== msg_id
)
1227 static void write_msg(struct s_reader
*reader
, MAILMSG
*msg
, uint32_t baseyear
)
1229 FILE *fp
= fopen(cfg
.mailfile
, "a");
1232 rdr_log(reader
, "Cannot open mailfile %s", cfg
.mailfile
);
1237 for(i
= 0; i
< msg
->len
- 1; ++i
)
1239 if(msg
->message
[i
] == 0x00 && msg
->message
[i
+ 1] == 0x32)
1241 msg
->subject
= &msg
->message
[i
+ 3];
1246 int32_t year
= (msg
->date
>> 8) / 12 + baseyear
;
1247 int32_t mon
= (msg
->date
>> 8) % 12 + 1;
1248 int32_t day
= msg
->date
& 0x1f;
1250 fprintf(fp
, "%04X:%08X:%02d/%02d/%04d:%04X:\"%s\":\"%s\"\n",
1261 NULLFREE(msg
->message
);
1262 msg
->message
= msg
->subject
= 0;
1266 static void msgs_init(uint32_t baseyear
)
1268 vg_msgs
= ll_create("vg_msgs");
1269 FILE *fp
= fopen(cfg
.mailfile
, "r");
1275 int32_t year
, mon
, day
;
1278 while(fgets(buffer
, sizeof(buffer
), fp
))
1281 if(!cs_malloc(&msg
, sizeof(MAILMSG
)))
1287 sscanf(buffer
, "%04hX:%08X:%02d/%02d/%04d:%04hX", &msg
->caid
, &msg
->serial
, &day
, &mon
, &year
, &msg
->id
);
1289 msg
->date
= ((year
* 12) + mon
- 1) << 8 | day
;
1290 msg
->message
= msg
->subject
= 0;
1292 ll_append(vg_msgs
, msg
);
1297 void videoguard_mail_msg(struct s_reader
*rdr
, uint8_t *data
)
1304 struct videoguard_data
*csystem_data
= rdr
->csystem_data
;
1308 msgs_init(csystem_data
->card_baseyear
);
1311 if(data
[0] != 0xFF || data
[1] != 0xFF)
1316 uint16_t msg_id
= (data
[2] << 8) | data
[3];
1317 uint8_t idx
= data
[4] & 0x0F;
1318 int32_t msg_size
= data
[5] * 10 + 2;
1319 uint16_t date
= (data
[9] << 8) | data
[10];
1320 int32_t submsg_len
= data
[12] - 2;
1321 uint16_t submsg_idx
= (data
[13] << 8) | data
[14];
1322 uint32_t serial
= (rdr
->hexserial
[2] << 24) | (rdr
->hexserial
[3] << 16) | (rdr
->hexserial
[4] << 8) | rdr
->hexserial
[5];
1323 MAILMSG
*msg
= find_msg(rdr
->caid
, serial
, date
, msg_id
);
1327 if(!cs_malloc(&msg
, sizeof(MAILMSG
)))
1331 msg
->caid
= rdr
->caid
;
1332 msg
->serial
= serial
;
1335 msg
->nsubs
= (data
[4] & 0xF0) >> 4;
1336 msg
->mask
= 1 << idx
;
1338 msg
->len
= submsg_len
;
1340 if(!cs_malloc(&msg
->message
, msg_size
))
1346 memset(msg
->message
, 0, msg_size
);
1347 memcpy(&msg
->message
[submsg_idx
], &data
[15], submsg_len
);
1349 ll_append(vg_msgs
, msg
);
1353 if(msg
->written
== 1 || msg
->mask
& (1 << idx
))
1358 msg
->mask
|= 1 << idx
;
1359 msg
->len
+= submsg_len
;
1360 memcpy(&msg
->message
[submsg_idx
], &data
[15], submsg_len
);
1363 if(msg
->mask
== (1 << msg
->nsubs
) - 1)
1365 write_msg(rdr
, msg
, csystem_data
->card_baseyear
);