- fix Building without Nagra not possible at Nagra_Merlin https://trac.streamboard...
[oscam.git] / reader-videoguard-common.c
blob5ebf755a750bccad8a96557efcf35944a2462e04
1 //
2 // Common videoguard functions.
3 //
5 #include "globals.h"
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
17 uint16_t caid;
18 uint32_t serial;
19 uint16_t date;
20 uint16_t id;
21 uint8_t nsubs;
22 uint16_t len;
23 uint8_t mask;
24 uint8_t written;
25 char *message;
26 char *subject;
27 } MAILMSG;
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
42 /* known NDS1 atrs */
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" },
56 /* known NDS2 atrs */
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
358 { { 0 },
359 0, 0, 0, 0, NULL}
362 int32_t i = 0;
363 ATR atrdata;
364 ATR *newatr = &atrdata;
365 ATR_InitFromArray(newatr, atr, *atr_size);
366 get_hist;
368 ATR tableatr;
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;
383 break;
385 i++;
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)
404 int32_t i;
406 for(i = 0; i < 8; i++)
408 if(cw[i] != 0) // test if cw = 00
410 return OK;
413 return ERROR;
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
426 int32_t i;
427 for(i = 0; i < len; i += 16) { AES_encrypt(data + i, crypted + i, &(csystem_data->ekey)); }
428 return len;
431 static void swap_lb(uint8_t *buff, int32_t len)
433 #if __BYTE_ORDER != __BIG_ENDIAN
434 return;
435 #endif
436 int32_t i;
437 uint8_t tmp;
439 for(i = 0; i < len / 2; i++)
441 tmp = buff[i * 2];
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)
449 uint32_t i;
450 switch(len)
452 case 16:
453 for(i = 0; i < 16; ++i)
455 data[i] = v1[i] ^ v2[i];
457 break;
459 case 8:
460 for(i = 0; i < 8; ++i)
462 data[i] = v1[i] ^ v2[i];
464 break;
466 case 4:
467 for(i = 0; i < 4; ++i)
469 data[i] = v1[i] ^ v2[i];
471 break;
473 default:
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
495 #else
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
510 #endif
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;
519 uint16_t c = 1;
520 memset(tb2, 0, 64);
521 tb2[0] = 1;
522 int32_t i;
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)
533 switch(rxbuff[0])
535 case 0xD0:
536 cCamCryptVG_Process_D0(reader, rxbuff, rxbuff + 5);
537 break;
539 case 0xD1:
540 cCamCryptVG_Process_D1(reader, rxbuff, rxbuff + 5, rxbuff + rxbuff[4] + 5);
541 break;
543 case 0xD3:
544 cCamCryptVG_Decrypt_D3(reader, rxbuff, rxbuff + 5, rxbuff + rxbuff[4] + 5);
545 break;
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;
553 switch(ins[1])
555 case 0xb4:
556 swap_lb(data, 64);
557 memcpy(csystem_data->cardkeys[0], data, sizeof(csystem_data->cardkeys[0]));
558 break;
560 case 0xbc:
562 swap_lb(data, 64);
563 const uint16_t *key1 = (const uint16_t *)csystem_data->cardkeys[1];
564 uint16_t key2[32];
565 memcpy(key2, csystem_data->cardkeys[2], sizeof(key2));
566 int32_t count2;
567 uint16_t iidata[32];
568 memcpy((uint8_t *)&iidata, data, 64);
570 for(count2 = 0; count2 < 32; count2++)
572 uint32_t rem = 0, divisor = key1[count2];
573 int8_t i;
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;
583 while(t)
585 if(t & 1) { carry = ((carry * rem) % divisor) & 0xffff; }
586 rem = ((rem * rem) % divisor) & 0xffff;
587 t >>= 1;
589 cCamCryptVG_PartialMod(carry, count2, key2, key1);
592 uint16_t idatacount = 0;
593 int32_t i;
595 for(i = 31; i >= 0; i--)
597 cCamCryptVG_LongMult(iidata, &idatacount, key1[i], key2[i]);
600 memcpy(data, iidata, 64);
601 swap_lb(data, 64);
602 uint8_t stateD1[16];
603 cCamCryptVG_Reorder16A(stateD1, data);
604 cAES_SetKey(reader, stateD1);
605 break;
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;
623 if(datalen < 0)
625 datalen1 += 15;
628 int32_t blocklen = datalen1 >> 4;
629 int32_t i;
630 int32_t iblock;
632 for(i = 0, iblock = 0; i < blocklen + 2; i++, iblock += 16)
634 uint8_t in[16];
635 int32_t docalc = 1;
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);
647 else
649 memcpy(in, &data[iblock], sizeof(in));
652 if(docalc)
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;
666 if(ins[4] > 16)
668 ins[4] -= 16;
671 if(ins[1] == 0xbe)
673 memset(csystem_data->stateD3A, 0, sizeof(csystem_data->stateD3A));
676 uint8_t tmp[16];
677 memset(tmp, 0, sizeof(tmp));
678 memcpy(tmp, ins, 5);
679 xor16(tmp, csystem_data->stateD3A, csystem_data->stateD3A);
681 int32_t len1 = ins[4];
682 int32_t blocklen = len1 >> 4;
684 if(ins[1] != 0xbe)
686 blocklen++;
689 uint8_t iter[16], states[16][16];
690 memset(iter, 0, sizeof(iter));
692 int32_t blockindex;
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);
703 if(c < 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);
722 if(ins[1] == 0xbe)
724 cCamCryptVG_Reorder16A(tmp, states[0]);
725 cAES_SetKey(reader, tmp);
729 static void cCamCryptVG_ReorderAndEncrypt(struct s_reader *reader, uint8_t *p)
731 uint8_t tmp[16];
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)
740 int32_t i;
741 int32_t j;
742 int32_t k;
743 for(i = 0, k = 0; i < 4; i++)
745 for(j = i; j < 16; j += 4, k++)
747 dest[k] = src[j];
752 static void cCamCryptVG_LongMult(uint16_t *pData, uint16_t *pLen, uint32_t mult, uint32_t carry)
754 int32_t i;
755 for(i = 0; i < *pLen; i++)
757 carry += pData[i] * mult;
758 pData[i] = (uint16_t)carry;
759 carry >>= 16;
762 if(carry) { pData[(*pLen)++] = carry; }
765 static void cCamCryptVG_PartialMod(uint16_t val, uint32_t count, uint16_t *outkey, const uint16_t *inkey)
767 if(count)
769 uint32_t mod = inkey[count];
770 uint16_t mult = (inkey[count] - outkey[count - 1]) & 0xffff;
771 uint32_t i;
772 uint32_t ib1;
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];
779 if(mult > t)
781 mult += mod;
784 mult += val;
786 if((val > mult) || (mod < mult))
788 mult -= mod;
790 outkey[count] = (outkey[count] * mult) % mod;
792 else
794 outkey[0] = val;
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,
820 uint8_t t1 = p[15];
821 int32_t i;
823 for(i = 0; i < 16; i++)
825 uint8_t t2 = t1;
826 t1 = p[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)
851 return 1;
853 else
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;
873 int32_t i;
875 for(i = 0; i < csystem_data->cmd_table->Nentries; i++, pcte++)
877 if(cmd[1] == pcte->cmd)
879 *rlen = pcte->len;
880 *rmode = pcte->mode;
881 return 1;
884 return 0;
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;
891 int32_t i;
893 for(i = 0; i < csystem_data->cmd_table->Nentries; i++, pcte++)
895 if(cmd[1] == pcte->cmd)
897 return 1;
900 return 0;
903 int32_t read_cmd_len(struct s_reader *reader, const uint8_t *cmd)
905 def_resp;
906 uint8_t cmd2[5];
907 memcpy(cmd2, cmd, 5);
909 if(cmd2[0] == 0xD3) // use classD1 for length request of classD3
911 cmd2[0] = 0xD1;
913 cmd2[3] |= 0x80;
914 cmd2[4] = 1;
916 uint8_t rxbuff[8];
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);
936 return -1;
939 memcpy(rxbuff + 5, cta_res, 3);
940 cCamCryptVG_PostProcess_Decrypt(reader, rxbuff);
942 return cta_res[0];
945 int32_t do_cmd(struct s_reader *reader, const uint8_t *ins, const uint8_t *txbuff, uint8_t *rxbuff, uint8_t *cta_res)
947 uint16_t cta_lr;
948 uint8_t ins2[5];
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)
956 if(ins2[4] == 0)
958 ins2[4] = len = read_cmd_len(reader, ins2);
959 if(len == 0xFF)
961 return -1;
965 else if((mode != 0) && ((ins2[3] != 0x7f) && (ins2[4] != 0x02)))
967 ins2[4] = len;
971 if(ins2[0] == 0xd3)
973 if(ins2[4] == 0)
975 return 0;
977 ins2[4] += 16;
980 len = ins2[4];
981 uint8_t tmp[264];
983 if(rxbuff == NULL)
985 rxbuff = tmp;
988 if(mode > 1)
990 if(!write_cmd_vg(ins2, NULL) || !status_ok(cta_res + len))
992 return -1;
995 memcpy(rxbuff, ins2, 5);
996 memcpy(rxbuff + 5, cta_res, len);
997 memcpy(rxbuff + 5 + len, cta_res + len, 2);
999 else
1001 if(!write_cmd_vg(ins2, txbuff) || !status_ok(cta_res))
1003 return -2;
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);
1012 if(ins2[0] == 0xd3)
1014 rdr_log_dump_dbg(reader, D_READER, rxbuff + 5, rxbuff[4], "Decrypted payload");
1017 return len;
1020 int32_t videoguard_do_rawcmd(struct s_reader *reader, CMD_PACKET *cp)
1022 int32_t rc;
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);
1030 return rc;
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)
1045 int32_t i;
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;
1050 switch(emmtype)
1052 case VG_EMMTYPE_G:
1053 rdr_log_dbg(rdr, D_EMM, "GLOBAL");
1054 ep->type = GLOBAL;
1055 return 1;
1057 case VG_EMMTYPE_U:
1058 case VG_EMMTYPE_S:
1059 rdr_log_dbg(rdr, D_EMM, "%s", (emmtype == VG_EMMTYPE_U) ? "UNIQUE" : "SHARED");
1060 ep->type = emmtype;
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;
1065 return 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);
1072 return 1;
1075 return 0; // if UNIQUE or SHARED but no serial match return FALSE
1077 default:
1078 // remote emm without serial
1079 rdr_log_dbg(rdr, D_EMM, "UNKNOWN");
1080 ep->type = UNKNOWN;
1081 return 1;
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;
1093 int32_t offs = 4;
1094 int32_t emmv2 = 0;
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
1103 nsubs = 1;
1104 ua_position = 0;
1106 else
1108 int32_t i;
1109 for(i = 0; i < nsubs; ++i)
1111 if(memcmp(&ep->emm[4 + i * 4], &reader->hexserial[2], serial_len) == 0)
1113 ua_position = i;
1114 break;
1117 offs += nsubs * 4;
1120 if(ua_position == -1)
1122 return ERROR;
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
1136 ++offs;
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
1148 return rc;
1152 if(ep->emm[offs] == 0x03)
1154 if(position == ua_position || vdrsc_fix)
1156 videoguard_mail_msg(reader, &ep->emm[offs + 2]);
1157 return rc;
1159 else
1161 offs += ep->emm[offs + 1] + 2;
1162 if(!(offs + 1 < ep->emmlen))
1164 return rc;
1167 if(ep->emm[offs] == 0x00 && (ep->emm[offs + 1] == 0x00 || ep->emm[offs + 1] == 0x01))
1169 offs += 2 + 1 + emmv2;
1171 continue;
1175 offs += ep->emm[offs + 1] + 2;
1176 if(!(offs + 1 < ep->emmlen))
1178 return rc;
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)
1199 ++offs;
1203 offs += 1 + emmv2;
1204 if(vdrsc_fix)
1206 --position;
1209 else
1211 return rc;
1214 return rc;
1217 uint8_t videoguard_get_emm_filter_address_byte(uint8_t isUnique, uint32_t n)
1219 uint8_t ret;
1220 switch(n)
1222 default:
1223 case 0:
1224 // do not filter by sub-emm count
1225 ret = 0;
1226 break;
1228 case 1:
1229 // unused
1230 // here we would need two filters,
1231 // one with sub-emm count 1x, and one with 01
1232 ret = 0x10;
1233 break;
1235 case 2:
1236 // filter sub-emm count with 1x
1237 ret = 0x20;
1238 break;
1240 case 3:
1241 // filter sub-emm count with 11
1242 ret = 0x30;
1243 break;
1246 if(isUnique)
1248 ret |= 0x40;
1250 else //shared
1252 ret |= 0x80;
1255 return ret;
1258 uint8_t videoguard_get_emm_filter_address_mask(uint32_t n)
1260 uint8_t ret = 0xC0;
1261 switch(n)
1263 default:
1264 case 0:
1265 // at least 1 sub-emm is always present, so we do not care
1266 break;
1268 case 1:
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
1272 break;
1274 case 2:
1275 // must have 3 sub-emms or more (10, 11, but not 00, 01)
1276 ret |= 0x20;
1277 break;
1279 case 3:
1280 // must have 4 sub-emms (11)
1281 ret |= 0x30;
1282 break;
1285 return ret;
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)))
1295 return ERROR;
1298 struct s_csystem_emm_filter *filters = *emm_filters;
1299 *filter_count = 0;
1300 int32_t idx = 0;
1301 uint32_t n;
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);
1313 idx++;
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);
1327 idx++;
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;
1337 idx++;
1338 *filter_count = idx;
1340 return OK;
1343 static MAILMSG *find_msg(uint16_t caid, uint32_t serial, uint16_t date, uint16_t msg_id)
1345 MAILMSG *msg;
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)
1351 return msg;
1354 return 0;
1357 static void write_msg(struct s_reader *reader, MAILMSG *msg, uint32_t baseyear)
1359 FILE *fp = fopen(cfg.mailfile, "a");
1360 if(fp == 0)
1362 rdr_log(reader, "Cannot open mailfile %s", cfg.mailfile);
1363 return;
1366 uint16_t i;
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];
1372 break;
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",
1381 msg->caid,
1382 msg->serial,
1383 day,
1384 mon,
1385 year,
1386 msg->id,
1387 msg->subject,
1388 msg->message);
1390 fclose(fp);
1391 NULLFREE(msg->message);
1392 msg->message = msg->subject = 0;
1393 msg->written = 1;
1396 static void msgs_init(uint32_t baseyear)
1398 vg_msgs = ll_create("vg_msgs");
1399 FILE *fp = fopen(cfg.mailfile, "r");
1400 if(fp == 0)
1402 return;
1405 int32_t year, mon, day;
1406 char buffer[2048];
1408 while(fgets(buffer, sizeof(buffer), fp))
1410 MAILMSG *msg;
1411 if(!cs_malloc(&msg, sizeof(MAILMSG)))
1413 fclose(fp);
1414 return;
1417 sscanf(buffer, "%04hX:%08X:%02d/%02d/%04d:%04hX", &msg->caid, &msg->serial, &day, &mon, &year, &msg->id);
1418 year -= baseyear;
1419 msg->date = ((year * 12) + mon - 1) << 8 | day;
1420 msg->message = msg->subject = 0;
1421 msg->written = 1;
1422 ll_append(vg_msgs, msg);
1424 fclose(fp);
1427 void videoguard_mail_msg(struct s_reader *rdr, uint8_t *data)
1429 if(cfg.disablemail)
1431 return;
1434 struct videoguard_data *csystem_data = rdr->csystem_data;
1436 if(vg_msgs == 0)
1438 msgs_init(csystem_data->card_baseyear);
1441 if(data[0] != 0xFF || data[1] != 0xFF)
1443 return;
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);
1455 if(msg == 0)
1457 if(!cs_malloc(&msg, sizeof(MAILMSG)))
1459 return;
1461 msg->caid = rdr->caid;
1462 msg->serial = serial;
1463 msg->date = date;
1464 msg->id = msg_id;
1465 msg->nsubs = (data[4] & 0xF0) >> 4;
1466 msg->mask = 1 << idx;
1467 msg->written = 0;
1468 msg->len = submsg_len;
1470 if(!cs_malloc(&msg->message, msg_size))
1472 NULLFREE(msg);
1473 return;
1476 memset(msg->message, 0, msg_size);
1477 memcpy(&msg->message[submsg_idx], &data[15], submsg_len);
1478 msg->subject = 0;
1479 ll_append(vg_msgs, msg);
1481 else
1483 if(msg->written == 1 || msg->mask & (1 << idx))
1485 return;
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);
1498 #endif