1 | //
|
---|
2 | // Common videoguard functions.
|
---|
3 | //
|
---|
4 | #include "globals.h"
|
---|
5 | #include "reader-common.h"
|
---|
6 | #include "reader-videoguard-common.h"
|
---|
7 |
|
---|
8 | void set_known_card_info(struct s_reader * reader, const unsigned char * atr, const unsigned int *atr_size)
|
---|
9 | {
|
---|
10 | /* Set to sensible default values */
|
---|
11 | reader->card_baseyear = 1997;
|
---|
12 | reader->card_tierstart = 0;
|
---|
13 | reader->card_system_version = NDSUNKNOWN;
|
---|
14 | reader->card_desc = "VideoGuard Unknown Card";
|
---|
15 |
|
---|
16 | NDS_ATR_ENTRY nds_atr_table[]={ // {atr}, atr len, base year, tier start, nds version, description
|
---|
17 | /* known NDS1 atrs */
|
---|
18 | {{ 0x3F, 0x78, 0x13, 0x25, 0x04, 0x40, 0xB0, 0x09, 0x4A, 0x50, 0x01, 0x4E, 0x5A },
|
---|
19 | 13, 1992, 0, NDS1, "VideoGuard Sky New Zealand (0969)"}, //160E
|
---|
20 | {{ 0x3F, 0x78, 0x12, 0x25, 0x01, 0x40, 0xB0, 0x14, 0x4A, 0x50, 0x01, 0x53, 0x44 },
|
---|
21 | 13, 1997, 0, NDS1, "VideoGuard StarTV India (caid unknown)"}, //105.5E
|
---|
22 | /* known NDS1+ atrs */
|
---|
23 | {{ 0x3F, 0x7F, 0x13, 0x25, 0x04, 0x33, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0xE0, 0x00, 0x00, 0x54,
|
---|
24 | 0x42, 0x00, 0x00, 0x00 },
|
---|
25 | 20, 1997, 0, NDS12, "VideoGuard China (0988)"},
|
---|
26 | {{ 0x3F, 0x78, 0x13, 0x25, 0x03, 0x40, 0xB0, 0x20, 0xFF, 0xFF, 0x4A, 0x50, 0x00 },
|
---|
27 | 13, 1997, 0, NDS12, "VideoGuard DirecTV"},
|
---|
28 | /* known NDS2 atrs */
|
---|
29 | {{ 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x33, 0xB0, 0x08, 0xFF, 0xFF, 0x4A, 0x50, 0x90,
|
---|
30 | 0x00, 0x00, 0x47, 0x4C, 0x01 },
|
---|
31 | 21, 2004, 0, NDS2, "VideoGuard Sky Brasil GL39 (0907)"},
|
---|
32 | {{ 0x3F, 0x7F, 0x11, 0x25, 0x03, 0x33, 0xB0, 0x09, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x46,
|
---|
33 | 0x44, 0x01, 0x00, 0x00 },
|
---|
34 | 20, 2000, 0, NDS2, "VideoGuard Foxtel Australia (090B)"}, //156E
|
---|
35 | {{ 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x0E, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00,
|
---|
36 | 0x00, 0x49, 0x54, 0x02, 0x00, 0x00 },
|
---|
37 | 22, 1997, 0, NDS2, "VideoGuard Sky Italia (0919)"},
|
---|
38 | {{ 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00,
|
---|
39 | 0x00, 0x5A, 0x4A, 0x01, 0x00, 0x00 },
|
---|
40 | 22, 2004, 0, NDS2, "VideoGuard Dolce Romania (092F)"},
|
---|
41 | {{ 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x54, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00,
|
---|
42 | 0x00, 0x41, 0x55, 0x01, 0x00, 0x00 },
|
---|
43 | 22, 1997, 0, NDS2, "VideoGuard OnoCable Espana (093A)"},
|
---|
44 | {{ 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x33, 0xB0, 0x13, 0x69, 0xFF, 0x4A, 0x50, 0xD0,
|
---|
45 | 0x80, 0x00, 0x49, 0x54, 0x03 },
|
---|
46 | 21, 1997, 0, NDS2, "VideoGuard Sky Italia (093B)"},
|
---|
47 | {{ 0x3F, 0x7D, 0x11, 0x25, 0x02, 0x41, 0xB0, 0x03, 0x69, 0xFF, 0x4A, 0x50, 0xF0, 0x80, 0x00, 0x56,
|
---|
48 | 0x54, 0x03 },
|
---|
49 | 18, 2000, 0, NDS2, "VideoGuard Viasat (093E)"},
|
---|
50 | {{ 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x40, 0xB0, 0x12, 0x69, 0xFF, 0x4A, 0x50, 0x90, 0x47, 0x4C, 0x00,
|
---|
51 | 0x00, 0x00, 0x00, 0x00 },
|
---|
52 | 20, 2000, 0, NDS2, "VideoGuard Sky Brasil GL23 (0942)"},
|
---|
53 | {{ 0x3F, 0xFF, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x03, 0xFF, 0xFF, 0x4A, 0x50, 0x80,
|
---|
54 | 0x00, 0x00, 0x00, 0x00, 0x47, 0x4C, 0x05 },
|
---|
55 | 23, 2009, 0, NDS2, "VideoGuard Sky Brasil GL54 (0943)"},
|
---|
56 | {{ 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x00, 0x0F, 0x33, 0xB0, 0x0F, 0x69, 0xFF, 0x4A, 0x50, 0xD0,
|
---|
57 | 0x00, 0x00, 0x53, 0x59, 0x02 },
|
---|
58 | 21, 1997, 0, NDS2, "VideoGuard BSkyB (0963)"},
|
---|
59 | {{ 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00,
|
---|
60 | 0x00, 0x4E, 0x5A, 0x01, 0x00, 0x00 },
|
---|
61 | 22, 1992, 0, NDS2, "VideoGuard Sky New Zealand (096A)"}, //160E
|
---|
62 | {{ 0x3F, 0xFD, 0x11, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x41, 0xB0, 0x03, 0x69, 0xFF, 0x4A, 0x50, 0xF0,
|
---|
63 | 0x80, 0x00, 0x46, 0x44, 0x03 },
|
---|
64 | 20, 2000, 0, NDS2, "VideoGuard Foxtel Australia (096C)"}, //156E
|
---|
65 | {{ 0x3F, 0xFF, 0x11, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x06, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00,
|
---|
66 | 0x00, 0x41, 0x5A, 0x01, 0x00, 0x11 },
|
---|
67 | 22, 2004, 50, NDS2, "VideoGuard Astro Malaysia (09AC)"},
|
---|
68 | {{ 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80,
|
---|
69 | 0x00, 0x58, 0x34, 0x01, 0x00, 0x14 },
|
---|
70 | 22, 1997, 0, NDS2, "VideoGuard Cingal Philippines (09B4)"},
|
---|
71 | {{ 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x02, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80,
|
---|
72 | 0x00, 0x58, 0x38, 0x01, 0x00, 0x14 },
|
---|
73 | 22, 1997, 0, NDS2, "VideoGuard TopTV (09B8)"},
|
---|
74 | {{ 0x3F, 0xFD, 0x13, 0x25, 0x02, 0x50, 0x80, 0x0F, 0x54, 0xB0, 0x04, 0x69, 0xFF, 0x4A, 0x50, 0xD0,
|
---|
75 | 0x80, 0x00, 0x49, 0x54, 0x03 },
|
---|
76 | 21, 1997, 0, NDS2, "VideoGuard Sky Italia (09CD)"},
|
---|
77 | {{ 0x3F, 0xFF, 0x13, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x11, 0x69, 0xFF, 0x4A, 0x50, 0x50, 0x00,
|
---|
78 | 0x00, 0x47, 0x54, 0x01, 0x00, 0x00 },
|
---|
79 | 22, 1997, 0, NDS2, "VideoGuard YES DBS Israel"},
|
---|
80 | {{ 0x3F, 0x7F, 0x11, 0x25, 0x03, 0x33, 0xB0, 0x09, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00, 0x00, 0x56,
|
---|
81 | 0x54, 0x01, 0x00, 0x00 },
|
---|
82 | 20, 2000, 0, NDS2, "VideoGuard Viasat Scandinavia"},
|
---|
83 | {{ 0x3F, 0xFF, 0x11, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00,
|
---|
84 | 0x00, 0x50, 0x31, 0x01, 0x00, 0x11 },
|
---|
85 | 22, 1997, 0, NDS2, "VideoGuard Sky Germany"},
|
---|
86 | {{ 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00,
|
---|
87 | 0x00, 0x5A, 0x48, 0x01, 0x00, 0x00 },
|
---|
88 | 22, 2004, 0, NDS2, "VideoGuard DSMART Turkey"},
|
---|
89 | {{ 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x54, 0xB0, 0x01, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00,
|
---|
90 | 0x00, 0x4B, 0x57, 0x01, 0x00, 0x00 },
|
---|
91 | 22, 1997, 0, NDS2, "VideoGuard Kabel BW"},
|
---|
92 | {{ 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x33, 0xB0, 0x10, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x00,
|
---|
93 | 0x00, 0x5A, 0x45, 0x01, 0x00, 0x00 },
|
---|
94 | 22 , 2004, 0, NDS2, "VideoGuard Get Kabel Norway"},
|
---|
95 | // NDS Version Unknown as Yet
|
---|
96 | {{ 0x3F, 0x7F, 0x13, 0x25, 0x02, 0x40, 0xB0, 0x12, 0x69, 0xFF, 0x4A, 0x50, 0x90, 0x41, 0x55, 0x00,
|
---|
97 | 0x00, 0x00, 0x00, 0x00 },
|
---|
98 | 20, 1997, 0, NDSUNKNOWN, "VideoGuard OnoCable Espana (0915)"},
|
---|
99 | {{ 0x3F, 0xFF, 0x14, 0x25, 0x03, 0x10, 0x80, 0x41, 0xB0, 0x07, 0x69, 0xFF, 0x4A, 0x50, 0x70, 0x80,
|
---|
100 | 0x00, 0x58, 0x44, 0x01, 0x00, 0x14 },
|
---|
101 | 22, 1997, 0, NDSUNKNOWN, "VideoGuard Sky Vivacom (09BD)"}, //45E
|
---|
102 | {{ 0x3F, 0x7F, 0x13, 0x25, 0x05, 0x40, 0xB0, 0x11, 0x69, 0xFF, 0x4A, 0x50, 0x00, 0x00, 0x00, 0x48,
|
---|
103 | 0x4B, 0x00, 0x01, 0x00 },
|
---|
104 | 20, 1997, 0, NDSUNKNOWN, "VideoGuard StarTV India (caid unknown)"}, //105.5E
|
---|
105 | {{ 0 }, 0, 0, 0, 0, NULL}
|
---|
106 | };
|
---|
107 |
|
---|
108 | int i=0;
|
---|
109 | while(nds_atr_table[i].desc) {
|
---|
110 | if ((*atr_size == nds_atr_table[i].atr_len)
|
---|
111 | && (memcmp (atr, nds_atr_table[i].atr, nds_atr_table[i].atr_len) == 0)) {
|
---|
112 | reader->card_baseyear=nds_atr_table[i].base_year;
|
---|
113 | reader->card_tierstart=nds_atr_table[i].tier_start;
|
---|
114 | reader->card_system_version = nds_atr_table[i].nds_version;
|
---|
115 | reader->card_desc = nds_atr_table[i].desc;
|
---|
116 | break;
|
---|
117 | }
|
---|
118 | i++;
|
---|
119 | }
|
---|
120 | }
|
---|
121 |
|
---|
122 | static void cCamCryptVG_LongMult(unsigned short *pData, unsigned short *pLen, unsigned int mult, unsigned int carry);
|
---|
123 | static void cCamCryptVG_PartialMod(unsigned short val, unsigned int count, unsigned short *outkey, const unsigned short *inkey);
|
---|
124 | static void cCamCryptVG_RotateRightAndHash(unsigned char *p);
|
---|
125 | static void cCamCryptVG_Reorder16A(unsigned char *dest, const unsigned char *src);
|
---|
126 | static void cCamCryptVG_ReorderAndEncrypt(struct s_reader * reader, unsigned char *p);
|
---|
127 | static void cCamCryptVG_Process_D0(struct s_reader * reader, const unsigned char *ins, unsigned char *data);
|
---|
128 | static void cCamCryptVG_Process_D1(struct s_reader * reader, const unsigned char *ins, unsigned char *data, const unsigned char *status);
|
---|
129 | static void cCamCryptVG_Decrypt_D3(struct s_reader * reader, unsigned char *ins, unsigned char *data, const unsigned char *status);
|
---|
130 | static void cCamCryptVG_PostProcess_Decrypt(struct s_reader * reader, unsigned char *rxbuff);
|
---|
131 | static int cAES_Encrypt(struct s_reader * reader, const unsigned char *data, int len, unsigned char *crypt);
|
---|
132 | static void swap_lb (const unsigned char *buff, int len);
|
---|
133 |
|
---|
134 | int cw_is_valid(unsigned char *cw, int start) //returns 1 if cw_is_valid, returns 0 if cw is all zeros
|
---|
135 | {
|
---|
136 | int i;
|
---|
137 | for (i = start; i < start+8; i++)
|
---|
138 | if (cw[i] != 0) { //test if cw = 00
|
---|
139 | return OK;
|
---|
140 | }
|
---|
141 | return ERROR;
|
---|
142 | }
|
---|
143 |
|
---|
144 | void cAES_SetKey(struct s_reader * reader, const unsigned char *key)
|
---|
145 | {
|
---|
146 | AES_set_encrypt_key(key,128,&(reader->ekey));
|
---|
147 | }
|
---|
148 |
|
---|
149 | int cAES_Encrypt(struct s_reader * reader, const unsigned char *data, int len, unsigned char *crypt)
|
---|
150 | {
|
---|
151 | len=(len+15)&(~15); // pad up to a multiple of 16
|
---|
152 | int i;
|
---|
153 | for(i=0; i<len; i+=16) AES_encrypt(data+i,crypt+i,&(reader->ekey));
|
---|
154 | return len;
|
---|
155 | }
|
---|
156 |
|
---|
157 | static void swap_lb (const unsigned char *buff, int len)
|
---|
158 | {
|
---|
159 |
|
---|
160 | #if __BYTE_ORDER != __BIG_ENDIAN
|
---|
161 | return;
|
---|
162 |
|
---|
163 | #endif /* */
|
---|
164 | int i;
|
---|
165 | unsigned short *tmp;
|
---|
166 | for (i = 0; i < len / 2; i++) {
|
---|
167 | tmp = (unsigned short *) buff + i;
|
---|
168 | *tmp = ((*tmp << 8) & 0xff00) | ((*tmp >> 8) & 0x00ff);
|
---|
169 | }
|
---|
170 | }
|
---|
171 |
|
---|
172 | inline void __xxor(unsigned char *data, int len, const unsigned char *v1, const unsigned char *v2)
|
---|
173 | {
|
---|
174 | switch(len) { // looks ugly, but the compiler can optimize it very well ;)
|
---|
175 | case 16:
|
---|
176 | *((unsigned int *)data+3) = *((unsigned int *)v1+3) ^ *((unsigned int *)v2+3);
|
---|
177 | *((unsigned int *)data+2) = *((unsigned int *)v1+2) ^ *((unsigned int *)v2+2);
|
---|
178 | case 8:
|
---|
179 | *((unsigned int *)data+1) = *((unsigned int *)v1+1) ^ *((unsigned int *)v2+1);
|
---|
180 | case 4:
|
---|
181 | *((unsigned int *)data+0) = *((unsigned int *)v1+0) ^ *((unsigned int *)v2+0);
|
---|
182 | break;
|
---|
183 | default:
|
---|
184 | while(len--) *data++ = *v1++ ^ *v2++;
|
---|
185 | break;
|
---|
186 | }
|
---|
187 | }
|
---|
188 |
|
---|
189 | void cCamCryptVG_SetSeed(struct s_reader * reader)
|
---|
190 | {
|
---|
191 | #if __BYTE_ORDER != __BIG_ENDIAN
|
---|
192 | static const unsigned char key1[] = {
|
---|
193 | 0xb9, 0xd5, 0xef, 0xd5, 0xf5, 0xd5, 0xfb, 0xd5, 0x31, 0xd6, 0x43, 0xd6, 0x55, 0xd6, 0x61, 0xd6,
|
---|
194 | 0x85, 0xd6, 0x9d, 0xd6, 0xaf, 0xd6, 0xc7, 0xd6, 0xd9, 0xd6, 0x09, 0xd7, 0x15, 0xd7, 0x21, 0xd7,
|
---|
195 | 0x27, 0xd7, 0x3f, 0xd7, 0x45, 0xd7, 0xb1, 0xd7, 0xbd, 0xd7, 0xdb, 0xd7, 0x11, 0xd8, 0x23, 0xd8,
|
---|
196 | 0x29, 0xd8, 0x2f, 0xd8, 0x4d, 0xd8, 0x8f, 0xd8, 0xa1, 0xd8, 0xad, 0xd8, 0xbf, 0xd8, 0xd7, 0xd8
|
---|
197 | };
|
---|
198 | static const unsigned char key2[] = {
|
---|
199 | 0x01, 0x00, 0xcf, 0x13, 0xe0, 0x60, 0x54, 0xac, 0xab, 0x99, 0xe6, 0x0c, 0x9f, 0x5b, 0x91, 0xb9,
|
---|
200 | 0x72, 0x72, 0x4d, 0x5b, 0x5f, 0xd3, 0xb7, 0x5b, 0x01, 0x4d, 0xef, 0x9e, 0x6b, 0x8a, 0xb9, 0xd1,
|
---|
201 | 0xc9, 0x9f, 0xa1, 0x2a, 0x8d, 0x86, 0xb6, 0xd6, 0x39, 0xb4, 0x64, 0x65, 0x13, 0x77, 0xa1, 0x0a,
|
---|
202 | 0x0c, 0xcf, 0xb4, 0x2b, 0x3a, 0x2f, 0xd2, 0x09, 0x92, 0x15, 0x40, 0x47, 0x66, 0x5c, 0xda, 0xc9
|
---|
203 | };
|
---|
204 | #else
|
---|
205 | static const unsigned char key1[] = {
|
---|
206 | 0xd5, 0xb9, 0xd5, 0xef, 0xd5, 0xf5, 0xd5, 0xfb, 0xd6, 0x31, 0xd6, 0x43, 0xd6, 0x55, 0xd6, 0x61,
|
---|
207 | 0xd6, 0x85, 0xd6, 0x9d, 0xd6, 0xaf, 0xd6, 0xc7, 0xd6, 0xd9, 0xd7, 0x09, 0xd7, 0x15, 0xd7, 0x21,
|
---|
208 | 0xd7, 0x27, 0xd7, 0x3f, 0xd7, 0x45, 0xd7, 0xb1, 0xd7, 0xbd, 0xd7, 0xdb, 0xd8, 0x11, 0xd8, 0x23,
|
---|
209 | 0xd8, 0x29, 0xd8, 0x2f, 0xd8, 0x4d, 0xd8, 0x8f, 0xd8, 0xa1, 0xd8, 0xad, 0xd8, 0xbf, 0xd8, 0xd7
|
---|
210 | };
|
---|
211 | static const unsigned char key2[] = {
|
---|
212 | 0x00, 0x01, 0x13, 0xcf, 0x60, 0xe0, 0xac, 0x54, 0x99, 0xab, 0x0c, 0xe6, 0x5b, 0x9f, 0xb9, 0x91,
|
---|
213 | 0x72, 0x72, 0x5b, 0x4d, 0xd3, 0x5f, 0x5b, 0xb7, 0x4d, 0x01, 0x9e, 0xef, 0x8a, 0x6b, 0xd1, 0xb9,
|
---|
214 | 0x9f, 0xc9, 0x2a, 0xa1, 0x86, 0x8d, 0xd6, 0xb6, 0xb4, 0x39, 0x65, 0x64, 0x77, 0x13, 0x0a, 0xa1,
|
---|
215 | 0xcf, 0x0c, 0x2b, 0xb4, 0x2f, 0x3a, 0x09, 0xd2, 0x15, 0x92, 0x47, 0x40, 0x5c, 0x66, 0xc9, 0xda
|
---|
216 | };
|
---|
217 | #endif
|
---|
218 | memcpy(reader->cardkeys[1],key1,sizeof(reader->cardkeys[1]));
|
---|
219 | memcpy(reader->cardkeys[2],key2,sizeof(reader->cardkeys[2]));
|
---|
220 | }
|
---|
221 |
|
---|
222 | void cCamCryptVG_GetCamKey(struct s_reader * reader, unsigned char *buff)
|
---|
223 | {
|
---|
224 | unsigned short *tb2=(unsigned short *)buff, c=1;
|
---|
225 | memset(tb2,0,64);
|
---|
226 | tb2[0]=1;
|
---|
227 | int i;
|
---|
228 | for(i=0; i<32; i++) cCamCryptVG_LongMult(tb2,&c,reader->cardkeys[1][i],0);
|
---|
229 | swap_lb (buff, 64);
|
---|
230 | }
|
---|
231 |
|
---|
232 | static void cCamCryptVG_PostProcess_Decrypt(struct s_reader * reader, unsigned char *rxbuff)
|
---|
233 | {
|
---|
234 | switch(rxbuff[0]) {
|
---|
235 | case 0xD0:
|
---|
236 | cCamCryptVG_Process_D0(reader,rxbuff,rxbuff+5);
|
---|
237 | break;
|
---|
238 | case 0xD1:
|
---|
239 | cCamCryptVG_Process_D1(reader,rxbuff,rxbuff+5,rxbuff+rxbuff[4]+5);
|
---|
240 | break;
|
---|
241 | case 0xD3:
|
---|
242 | cCamCryptVG_Decrypt_D3(reader,rxbuff,rxbuff+5,rxbuff+rxbuff[4]+5);
|
---|
243 | break;
|
---|
244 | }
|
---|
245 | }
|
---|
246 |
|
---|
247 | static void cCamCryptVG_Process_D0(struct s_reader * reader, const unsigned char *ins, unsigned char *data)
|
---|
248 | {
|
---|
249 | switch(ins[1]) {
|
---|
250 | case 0xb4:
|
---|
251 | swap_lb (data, 64);
|
---|
252 | memcpy(reader->cardkeys[0],data,sizeof(reader->cardkeys[0]));
|
---|
253 | break;
|
---|
254 | case 0xbc:
|
---|
255 | {
|
---|
256 | swap_lb (data, 64);
|
---|
257 | unsigned short *idata=(unsigned short *)data;
|
---|
258 | const unsigned short *key1=(const unsigned short *)reader->cardkeys[1];
|
---|
259 | unsigned short key2[32];
|
---|
260 | memcpy(key2,reader->cardkeys[2],sizeof(key2));
|
---|
261 | int count2;
|
---|
262 | for(count2=0; count2<32; count2++) {
|
---|
263 | unsigned int rem=0, div=key1[count2];
|
---|
264 | int i;
|
---|
265 | for(i=31; i>=0; i--) {
|
---|
266 | unsigned int x=idata[i] | (rem<<16);
|
---|
267 | rem=(x%div)&0xffff;
|
---|
268 | }
|
---|
269 | unsigned int carry=1, t=val_by2on3(div) | 1;
|
---|
270 | while(t) {
|
---|
271 | if(t&1) carry=((carry*rem)%div)&0xffff;
|
---|
272 | rem=((rem*rem)%div)&0xffff;
|
---|
273 | t>>=1;
|
---|
274 | }
|
---|
275 | cCamCryptVG_PartialMod(carry,count2,key2,key1);
|
---|
276 | }
|
---|
277 | unsigned short idatacount=0;
|
---|
278 | int i;
|
---|
279 | for(i=31; i>=0; i--) cCamCryptVG_LongMult(idata,&idatacount,key1[i],key2[i]);
|
---|
280 | swap_lb (data, 64);
|
---|
281 | unsigned char stateD1[16];
|
---|
282 | cCamCryptVG_Reorder16A(stateD1,data);
|
---|
283 | cAES_SetKey(reader,stateD1);
|
---|
284 | break;
|
---|
285 | }
|
---|
286 | }
|
---|
287 | }
|
---|
288 |
|
---|
289 | static void cCamCryptVG_Process_D1(struct s_reader * reader, const unsigned char *ins, unsigned char *data, const unsigned char *status)
|
---|
290 | {
|
---|
291 | unsigned char iter[16], tmp[16];
|
---|
292 | memset(iter,0,sizeof(iter));
|
---|
293 | memcpy(iter,ins,5);
|
---|
294 | xor16(iter,reader->stateD3A,iter);
|
---|
295 | memcpy(reader->stateD3A,iter,sizeof(iter));
|
---|
296 |
|
---|
297 | int datalen=status-data;
|
---|
298 | int datalen1=datalen;
|
---|
299 | if(datalen<0) datalen1+=15;
|
---|
300 | int blocklen=datalen1>>4;
|
---|
301 | int i;
|
---|
302 | int iblock;
|
---|
303 | for(i=0,iblock=0; i<blocklen+2; i++,iblock+=16) {
|
---|
304 | unsigned char in[16];
|
---|
305 | int docalc=1;
|
---|
306 | if(blocklen==i && (docalc=datalen&0xf)) {
|
---|
307 | memset(in,0,sizeof(in));
|
---|
308 | memcpy(in,&data[iblock],datalen-(datalen1&~0xf));
|
---|
309 | }
|
---|
310 | else if(blocklen+1==i) {
|
---|
311 | memset(in,0,sizeof(in));
|
---|
312 | memcpy(&in[5],status,2);
|
---|
313 | }
|
---|
314 | else
|
---|
315 | memcpy(in,&data[iblock],sizeof(in));
|
---|
316 |
|
---|
317 | if(docalc) {
|
---|
318 | xor16(iter,in,tmp);
|
---|
319 | cCamCryptVG_ReorderAndEncrypt(reader,tmp);
|
---|
320 | xor16(tmp,reader->stateD3A,iter);
|
---|
321 | }
|
---|
322 | }
|
---|
323 | memcpy(reader->stateD3A,tmp,16);
|
---|
324 | }
|
---|
325 |
|
---|
326 | static void cCamCryptVG_Decrypt_D3(struct s_reader * reader, unsigned char *ins, unsigned char *data, const unsigned char *status)
|
---|
327 | {
|
---|
328 | if(ins[4]>16) ins[4]-=16;
|
---|
329 | if(ins[1]==0xbe) memset(reader->stateD3A,0,sizeof(reader->stateD3A));
|
---|
330 |
|
---|
331 | unsigned char tmp[16];
|
---|
332 | memset(tmp,0,sizeof(tmp));
|
---|
333 | memcpy(tmp,ins,5);
|
---|
334 | xor16(tmp,reader->stateD3A,reader->stateD3A);
|
---|
335 |
|
---|
336 | int len1=ins[4];
|
---|
337 | int blocklen=len1>>4;
|
---|
338 | if(ins[1]!=0xbe) blocklen++;
|
---|
339 |
|
---|
340 | unsigned char iter[16], states[16][16];
|
---|
341 | memset(iter,0,sizeof(iter));
|
---|
342 | int blockindex;
|
---|
343 | for(blockindex=0; blockindex<blocklen; blockindex++) {
|
---|
344 | iter[0]+=blockindex;
|
---|
345 | xor16(iter,reader->stateD3A,iter);
|
---|
346 | cCamCryptVG_ReorderAndEncrypt(reader,iter);
|
---|
347 | xor16(iter,&data[blockindex*16],states[blockindex]);
|
---|
348 | if(blockindex==(len1>>4)) {
|
---|
349 | int c=len1-(blockindex*16);
|
---|
350 | if(c<16) memset(&states[blockindex][c],0,16-c);
|
---|
351 | }
|
---|
352 | xor16(states[blockindex],reader->stateD3A,reader->stateD3A);
|
---|
353 | cCamCryptVG_RotateRightAndHash(reader->stateD3A);
|
---|
354 | }
|
---|
355 | memset(tmp,0,sizeof(tmp));
|
---|
356 | memcpy(tmp+5,status,2);
|
---|
357 | xor16(tmp,reader->stateD3A,reader->stateD3A);
|
---|
358 | cCamCryptVG_ReorderAndEncrypt(reader,reader->stateD3A);
|
---|
359 |
|
---|
360 | memcpy(reader->stateD3A,status-16,sizeof(reader->stateD3A));
|
---|
361 | cCamCryptVG_ReorderAndEncrypt(reader,reader->stateD3A);
|
---|
362 |
|
---|
363 | memcpy(data,states[0],len1);
|
---|
364 | if(ins[1]==0xbe) {
|
---|
365 | cCamCryptVG_Reorder16A(tmp,states[0]);
|
---|
366 | cAES_SetKey(reader,tmp);
|
---|
367 | }
|
---|
368 | }
|
---|
369 |
|
---|
370 | static void cCamCryptVG_ReorderAndEncrypt(struct s_reader * reader, unsigned char *p)
|
---|
371 | {
|
---|
372 | unsigned char tmp[16];
|
---|
373 | cCamCryptVG_Reorder16A(tmp,p);
|
---|
374 | cAES_Encrypt(reader,tmp,16,tmp);
|
---|
375 | cCamCryptVG_Reorder16A(p,tmp);
|
---|
376 | }
|
---|
377 |
|
---|
378 | // reorder AAAABBBBCCCCDDDD to ABCDABCDABCDABCD
|
---|
379 | static void cCamCryptVG_Reorder16A(unsigned char *dest, const unsigned char *src)
|
---|
380 | {
|
---|
381 | int i;
|
---|
382 | int j;
|
---|
383 | int k;
|
---|
384 | for(i=0,k=0; i<4; i++)
|
---|
385 | for(j=i; j<16; j+=4,k++)
|
---|
386 | dest[k]=src[j];
|
---|
387 | }
|
---|
388 |
|
---|
389 | static void cCamCryptVG_LongMult(unsigned short *pData, unsigned short *pLen, unsigned int mult, unsigned int carry)
|
---|
390 | {
|
---|
391 | int i;
|
---|
392 | for(i=0; i<*pLen; i++) {
|
---|
393 | carry+=pData[i]*mult;
|
---|
394 | pData[i]=(unsigned short)carry;
|
---|
395 | carry>>=16;
|
---|
396 | }
|
---|
397 | if(carry) pData[(*pLen)++]=carry;
|
---|
398 | }
|
---|
399 |
|
---|
400 | static void cCamCryptVG_PartialMod(unsigned short val, unsigned int count, unsigned short *outkey, const unsigned short *inkey)
|
---|
401 | {
|
---|
402 | if(count) {
|
---|
403 | unsigned int mod=inkey[count];
|
---|
404 | unsigned short mult=(inkey[count]-outkey[count-1])&0xffff;
|
---|
405 | unsigned int i;
|
---|
406 | unsigned int ib1;
|
---|
407 | for(i=0,ib1=count-2; i<count-1; i++,ib1--) {
|
---|
408 | unsigned int t=(inkey[ib1]*mult)%mod;
|
---|
409 | mult=t-outkey[ib1];
|
---|
410 | if(mult>t) mult+=mod;
|
---|
411 | }
|
---|
412 | mult+=val;
|
---|
413 | if((val>mult) || (mod<mult)) mult-=mod;
|
---|
414 | outkey[count]=(outkey[count]*mult)%mod;
|
---|
415 | }
|
---|
416 | else
|
---|
417 | outkey[0]=val;
|
---|
418 | }
|
---|
419 |
|
---|
420 | static void cCamCryptVG_RotateRightAndHash(unsigned char *p)
|
---|
421 | {
|
---|
422 | static const unsigned char table1[256] = {
|
---|
423 | 0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5, 0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
|
---|
424 | 0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0, 0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
|
---|
425 | 0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc, 0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
|
---|
426 | 0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a, 0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
|
---|
427 | 0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0, 0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
|
---|
428 | 0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b, 0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
|
---|
429 | 0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85, 0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
|
---|
430 | 0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5, 0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
|
---|
431 | 0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17, 0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
|
---|
432 | 0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88, 0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
|
---|
433 | 0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c, 0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
|
---|
434 | 0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9, 0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
|
---|
435 | 0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6, 0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
|
---|
436 | 0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e, 0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
|
---|
437 | 0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94, 0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
|
---|
438 | 0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68, 0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16,
|
---|
439 | };
|
---|
440 | unsigned char t1=p[15];
|
---|
441 | int i;
|
---|
442 | for(i=0; i<16; i++) {
|
---|
443 | unsigned char t2=t1;
|
---|
444 | t1=p[i]; p[i]=table1[(t1>>1)|((t2&1)<<7)];
|
---|
445 | }
|
---|
446 | }
|
---|
447 |
|
---|
448 | int status_ok(const unsigned char *status)
|
---|
449 | {
|
---|
450 | //cs_log("[videoguard-reader] check status %02x%02x", status[0],status[1]);
|
---|
451 | return (status[0] == 0x90 || status[0] == 0x91)
|
---|
452 | && (status[1] == 0x00 || status[1] == 0x01
|
---|
453 | || status[1] == 0x20 || status[1] == 0x21
|
---|
454 | || status[1] == 0x80 || status[1] == 0x81
|
---|
455 | || status[1] == 0xa0 || status[1] == 0xa1);
|
---|
456 | }
|
---|
457 |
|
---|
458 | void memorize_cmd_table (struct s_reader * reader, const unsigned char *mem, int size){
|
---|
459 | reader->cmd_table=(struct s_CmdTab *)malloc(sizeof(unsigned char) * size);
|
---|
460 | memcpy(reader->cmd_table,mem,size);
|
---|
461 | }
|
---|
462 |
|
---|
463 | int cmd_table_get_info(struct s_reader * reader, const unsigned char *cmd, unsigned char *rlen, unsigned char *rmode)
|
---|
464 | {
|
---|
465 | struct s_CmdTabEntry *pcte=reader->cmd_table->e;
|
---|
466 | int i;
|
---|
467 | for(i=0; i< reader->cmd_table->Nentries; i++,pcte++)
|
---|
468 | if(cmd[1]==pcte->cmd) {
|
---|
469 | *rlen=pcte->len;
|
---|
470 | *rmode=pcte->mode;
|
---|
471 | return 1;
|
---|
472 | }
|
---|
473 | return 0;
|
---|
474 | }
|
---|
475 |
|
---|
476 | int cmd_exists(struct s_reader * reader, const unsigned char *cmd)
|
---|
477 | {
|
---|
478 | struct s_CmdTabEntry *pcte=reader->cmd_table->e;
|
---|
479 | int i;
|
---|
480 | for(i=0; i< reader->cmd_table->Nentries; i++,pcte++)
|
---|
481 | if(cmd[1]==pcte->cmd) {
|
---|
482 | return 1;
|
---|
483 | }
|
---|
484 | return 0;
|
---|
485 | }
|
---|
486 |
|
---|
487 | int read_cmd_len(struct s_reader * reader, const unsigned char *cmd)
|
---|
488 | {
|
---|
489 | def_resp;
|
---|
490 | unsigned char cmd2[5];
|
---|
491 | memcpy(cmd2,cmd,5);
|
---|
492 | cmd2[3]=0x80;
|
---|
493 | cmd2[4]=1;
|
---|
494 | // some card reply with L 91 00 (L being the command length).
|
---|
495 |
|
---|
496 | if(!write_cmd_vg(cmd2,NULL) || !status_ok(cta_res+1)) {
|
---|
497 | cs_debug_mask(D_READER, "[videoguard-reader] failed to read %02x%02x cmd length (%02x %02x)",cmd[1],cmd[2],cta_res[1],cta_res[2]);
|
---|
498 | return -1;
|
---|
499 | }
|
---|
500 | return cta_res[0];
|
---|
501 | }
|
---|
502 |
|
---|
503 | int do_cmd(struct s_reader * reader, const unsigned char *ins, const unsigned char *txbuff, unsigned char *rxbuff,
|
---|
504 | unsigned char * cta_res)
|
---|
505 | {
|
---|
506 | ushort cta_lr;
|
---|
507 | unsigned char ins2[5];
|
---|
508 | memcpy(ins2,ins,5);
|
---|
509 | unsigned char len=0, mode=0;
|
---|
510 | if(cmd_table_get_info(reader,ins2,&len,&mode)) {
|
---|
511 | if(len==0xFF && mode==2) {
|
---|
512 | if(ins2[4]==0) ins2[4]=len=read_cmd_len(reader,ins2);
|
---|
513 | }
|
---|
514 | else if(mode!=0) ins2[4]=len;
|
---|
515 | }
|
---|
516 | if(ins2[0]==0xd3) ins2[4]=len+16;
|
---|
517 | len=ins2[4];
|
---|
518 |
|
---|
519 | unsigned char tmp[264];
|
---|
520 | if(!rxbuff) rxbuff=tmp;
|
---|
521 | if(mode>1) {
|
---|
522 | if(!write_cmd_vg(ins2,NULL) || !status_ok(cta_res+len)) return -1;
|
---|
523 | memcpy(rxbuff,ins2,5);
|
---|
524 | memcpy(rxbuff+5,cta_res,len);
|
---|
525 | memcpy(rxbuff+5+len,cta_res+len,2);
|
---|
526 | }
|
---|
527 | else {
|
---|
528 | if(!write_cmd_vg(ins2,(uchar *)txbuff) || !status_ok(cta_res)) return -2;
|
---|
529 | memcpy(rxbuff,ins2,5);
|
---|
530 | memcpy(rxbuff+5,txbuff,len);
|
---|
531 | memcpy(rxbuff+5+len,cta_res,2);
|
---|
532 | }
|
---|
533 |
|
---|
534 | cCamCryptVG_PostProcess_Decrypt(reader,rxbuff);
|
---|
535 |
|
---|
536 | return len;
|
---|
537 | }
|
---|
538 |
|
---|
539 | void rev_date_calc(const unsigned char *Date, int *year, int *mon, int *day, int *hh, int *mm, int *ss, int base_year)
|
---|
540 | {
|
---|
541 | *year=(Date[0]/12)+base_year;
|
---|
542 | *mon=(Date[0]%12)+1;
|
---|
543 | *day=Date[1] & 0x1f;
|
---|
544 | *hh=Date[2]/8;
|
---|
545 | *mm=(0x100*(Date[2]-*hh*8)+Date[3])/32;
|
---|
546 | *ss=(Date[3]-*mm*32)*2;
|
---|
547 | }
|
---|
548 |
|
---|
549 | void do_post_dw_hash(unsigned char *cw, unsigned char *ecm_header_data)
|
---|
550 | {
|
---|
551 | int i, ecmi, ecm_header_count;
|
---|
552 | unsigned char buffer[0x80];
|
---|
553 | unsigned char md5_digest[0x10];
|
---|
554 | static const unsigned short Hash3[] = {0x0123,0x4567,0x89AB,0xCDEF,0xF861,0xCB52};
|
---|
555 | static const unsigned char Hash4[] = {0x0B,0x04,0x07,0x08,0x05,0x09,0x0B,0x0A,0x07,0x02,0x0A,0x05,0x04,0x08,0x0D,0x0F};
|
---|
556 | static const unsigned short NdTabB001[0x15][0x20] = {
|
---|
557 | {0xEAF1, 0x0237, 0x29D0, 0xBAD2, 0xE9D3, 0x8BAE, 0x2D6D, 0xCD1B,
|
---|
558 | 0x538D, 0xDE6B, 0xA634, 0xF81A, 0x18B5, 0x5087, 0x14EA, 0x672E,
|
---|
559 | 0xF0FC, 0x055E, 0x62E5, 0xB78F, 0x5D09, 0x0003, 0xE4E8, 0x2DCE,
|
---|
560 | 0x6BE0, 0xAC4E, 0xF485, 0x6967, 0xF28C, 0x97A0, 0x01EF, 0x0100},
|
---|
561 | {0xC539, 0xF5B9, 0x9099, 0x013A, 0xD4B9, 0x6AB5, 0xEA67, 0x7EB4,
|
---|
562 | 0x6C30, 0x4BF0, 0xB810, 0xB0B5, 0xB76D, 0xA751, 0x1AE7, 0x14CA,
|
---|
563 | 0x4F4F, 0x1586, 0x2608, 0x10B1, 0xE7E1, 0x48BE, 0x7DDD, 0x5ECB,
|
---|
564 | 0xCFBF, 0x323B, 0x8B31, 0xB131, 0x0F1A, 0x664B, 0x0140, 0x0100},
|
---|
565 | {0x3C7D, 0xBDC4, 0xFEC7, 0x26A6, 0xB0A0, 0x6E55, 0xF710, 0xF9BF,
|
---|
566 | 0x0023, 0xE81F, 0x41CA, 0xBE32, 0xB461, 0xE92D, 0xF1AF, 0x409F,
|
---|
567 | 0xFC85, 0xFE5B, 0x7FCE, 0x17F5, 0x01AB, 0x4A46, 0xEB05, 0xA251,
|
---|
568 | 0xDC6F, 0xF0C0, 0x10F0, 0x1D51, 0xEFAA, 0xE9BF, 0x0100, 0x0100},
|
---|
569 | {0x1819, 0x0CAA, 0x9067, 0x607A, 0x7576, 0x1CBC, 0xE51D, 0xBF77,
|
---|
570 | 0x7EC6, 0x839E, 0xB695, 0xF096, 0xDC10, 0xCB69, 0x4654, 0x8E68,
|
---|
571 | 0xD62D, 0x4F1A, 0x4227, 0x92AC, 0x9064, 0x6BD1, 0x1E75, 0x2747,
|
---|
572 | 0x00DA, 0xA6A6, 0x6CF1, 0xD151, 0xBE56, 0x3E33, 0x0128, 0x0100},
|
---|
573 | {0x4091, 0x09ED, 0xD494, 0x6054, 0x1869, 0x71D5, 0xB572, 0x7BF1,
|
---|
574 | 0xE925, 0xEE2D, 0xEEDE, 0xA13C, 0x6613, 0x9BAB, 0x122D, 0x7AE4,
|
---|
575 | 0x5268, 0xE6C9, 0x50CB, 0x79A1, 0xF212, 0xA062, 0x6B48, 0x70B3,
|
---|
576 | 0xF6B0, 0x06D5, 0xF8AB, 0xECF5, 0x6255, 0xEDD8, 0x79D2, 0x290A},
|
---|
577 | {0xD3CF, 0x014E, 0xACB3, 0x8F6B, 0x0F2C, 0xA5D8, 0xE8E0, 0x863D,
|
---|
578 | 0x80D5, 0x5705, 0x658A, 0x8BC2, 0xEE46, 0xD3AE, 0x0199, 0x0100,
|
---|
579 | 0x4A35, 0xABE4, 0xF976, 0x935A, 0xA8A5, 0xBAE9, 0x24D0, 0x71AA,
|
---|
580 | 0xB3FE, 0x095E, 0xAB06, 0x4CD5, 0x2F0D, 0x1ACB, 0x59F3, 0x4C50},
|
---|
581 | {0xFD27, 0x0F8E, 0x191A, 0xEEE7, 0x2F49, 0x3A05, 0x3267, 0x4F88,
|
---|
582 | 0x38AE, 0xFCE9, 0x9476, 0x18C6, 0xF961, 0x4EF0, 0x39D0, 0x42E6,
|
---|
583 | 0xB747, 0xE625, 0xB68E, 0x5100, 0xF92A, 0x86FE, 0xE79B, 0xEE91,
|
---|
584 | 0x21D5, 0x4C3C, 0x683D, 0x5AD1, 0x1B49, 0xF407, 0x0194, 0x0100},
|
---|
585 | {0x4BF9, 0xDC0D, 0x9478, 0x5174, 0xCB4A, 0x8A89, 0x4D6A, 0xFED8,
|
---|
586 | 0xF123, 0xA8CD, 0xEEE7, 0xA6D1, 0xB763, 0xF5E2, 0xE085, 0x01EF,
|
---|
587 | 0xE466, 0x9FA3, 0x2F68, 0x2190, 0x423F, 0x287F, 0x7F3F, 0x09F6,
|
---|
588 | 0x2111, 0xA963, 0xD0BB, 0x674A, 0xBA72, 0x45F9, 0xF186, 0xB8F5},
|
---|
589 | {0x0010, 0xD1B9, 0xB164, 0x9E87, 0x1F49, 0x6950, 0x2DBF, 0x38D3,
|
---|
590 | 0x2EB0, 0x3E8E, 0x91E6, 0xF688, 0x7E41, 0x566E, 0x01B0, 0x0100,
|
---|
591 | 0x24A1, 0x73D8, 0xA0C3, 0xF71B, 0xA0A5, 0x2A06, 0xBA46, 0xFEC3,
|
---|
592 | 0xDD4C, 0x52CC, 0xF9BC, 0x3B7E, 0x3812, 0x0666, 0xB74B, 0x40F8},
|
---|
593 | {0x28F2, 0x7C81, 0xFC92, 0x6FBD, 0x53D6, 0x72A3, 0xBBDF, 0xB6FC,
|
---|
594 | 0x9CE5, 0x2331, 0xD4F6, 0xC5BB, 0xE8BB, 0x6676, 0x02D9, 0x2F0E,
|
---|
595 | 0xD009, 0xD136, 0xCD09, 0x7551, 0x1826, 0x9D9B, 0x63EA, 0xFC63,
|
---|
596 | 0x68CD, 0x3672, 0xCB95, 0xD28E, 0xF1CD, 0x20CA, 0x014C, 0x0100},
|
---|
597 | {0xE539, 0x55B7, 0x989D, 0x21C4, 0x463A, 0xE68F, 0xF8B5, 0xE5C5,
|
---|
598 | 0x662B, 0x35BF, 0x3C50, 0x0131, 0xF4BF, 0x38B2, 0x41BC, 0xB829,
|
---|
599 | 0x02B7, 0x6B8F, 0xA25C, 0xAFD2, 0xD84A, 0x2243, 0x53EB, 0xC6C9,
|
---|
600 | 0x2E14, 0x181F, 0x8F96, 0xDF0E, 0x0D4C, 0x30F6, 0xFFE1, 0x9DDA},
|
---|
601 | {0x30B6, 0x777E, 0xDA3D, 0xAF77, 0x205E, 0xC90B, 0x856B, 0xB451,
|
---|
602 | 0x3BCC, 0x76C2, 0x8ACF, 0xDCB1, 0xA5E5, 0xDD64, 0x0197, 0x0100,
|
---|
603 | 0xE751, 0xB661, 0x0404, 0xDB4A, 0xE9DD, 0xA400, 0xAF26, 0x3F5E,
|
---|
604 | 0x904B, 0xA924, 0x09E0, 0xE72B, 0x825B, 0x2C50, 0x6FD0, 0x0D52},
|
---|
605 | {0x2730, 0xC2BA, 0x9E44, 0x5815, 0xFC47, 0xB21D, 0x67B8, 0xF8B9,
|
---|
606 | 0x047D, 0xB0AF, 0x9F14, 0x741B, 0x4668, 0xBE54, 0xDE16, 0xDB14,
|
---|
607 | 0x7CB7, 0xF2B8, 0x0683, 0x762C, 0x09A0, 0x9507, 0x7F92, 0x022C,
|
---|
608 | 0xBA6A, 0x7D52, 0x0AF4, 0x1BC3, 0xB46A, 0xC4FD, 0x01C2, 0x0100},
|
---|
609 | {0x7611, 0x66F3, 0xEE87, 0xEDD3, 0xC559, 0xEFD4, 0xDC59, 0xF86B,
|
---|
610 | 0x6D1C, 0x1C85, 0x9BB1, 0x3373, 0x763F, 0x4EBE, 0x1BF3, 0x99B5,
|
---|
611 | 0xD721, 0x978F, 0xCF5C, 0xAC51, 0x0984, 0x7462, 0x8F0C, 0x2817,
|
---|
612 | 0x4AD9, 0xFD41, 0x6678, 0x7C85, 0xD330, 0xC9F8, 0x1D9A, 0xC622},
|
---|
613 | {0x5AE4, 0xE16A, 0x60F6, 0xFD45, 0x668C, 0x29D6, 0x0285, 0x6B92,
|
---|
614 | 0x92C2, 0x21DE, 0x45E0, 0xEF3D, 0x8B0D, 0x02CD, 0x0198, 0x0100,
|
---|
615 | 0x9E6D, 0x4D38, 0xDEF9, 0xE6F2, 0xF72E, 0xB313, 0x14F2, 0x390A,
|
---|
616 | 0x2D67, 0xC71E, 0xCB69, 0x7F66, 0xD3CF, 0x7F8A, 0x81D9, 0x9DDE},
|
---|
617 | {0x85E3, 0x8F29, 0x36EB, 0xC968, 0x3696, 0x59F6, 0x7832, 0xA78B,
|
---|
618 | 0xA1D8, 0xF5CF, 0xAB64, 0x646D, 0x7A2A, 0xBAF8, 0xAA87, 0x41C7,
|
---|
619 | 0x5120, 0xDE78, 0x738D, 0xDC1A, 0x268D, 0x5DF8, 0xED69, 0x1C8A,
|
---|
620 | 0xBC85, 0x3DCD, 0xAE30, 0x0F8D, 0xEC89, 0x3ABD, 0x0166, 0x0100},
|
---|
621 | {0xB8BD, 0x643B, 0x748E, 0xBD63, 0xEC6F, 0xE23A, 0x9493, 0xDD76,
|
---|
622 | 0x0A62, 0x774F, 0xCD68, 0xA67A, 0x9A23, 0xC8A8, 0xBDE5, 0x9D1B,
|
---|
623 | 0x2B86, 0x8B36, 0x5428, 0x1DFB, 0xCD1D, 0x0713, 0x29C2, 0x8E8E,
|
---|
624 | 0x5207, 0xA13F, 0x6005, 0x4F5E, 0x52E0, 0xE7C8, 0x6D1C, 0x3E34},
|
---|
625 | {0x581D, 0x2BFA, 0x5E1D, 0xA891, 0x1069, 0x1DA4, 0x39A0, 0xBE45,
|
---|
626 | 0x5B9A, 0x7333, 0x6F3E, 0x8637, 0xA550, 0xC9E9, 0x5C6C, 0x42BA,
|
---|
627 | 0xA712, 0xC3EA, 0x3808, 0x0910, 0xAA4D, 0x5B25, 0xABCD, 0xE680,
|
---|
628 | 0x96AD, 0x2CEC, 0x8EBB, 0xA47D, 0x1690, 0xE8FB, 0x01C8, 0x0100},
|
---|
629 | {0x73B9, 0x82BC, 0x9EBC, 0xB130, 0x0DA5, 0x8617, 0x9F7B, 0x9766,
|
---|
630 | 0x205D, 0x752D, 0xB05C, 0x2A17, 0xA75C, 0x18EF, 0x8339, 0xFD34,
|
---|
631 | 0x8DA2, 0x7970, 0xD0B4, 0x70F1, 0x3765, 0x7380, 0x7CAF, 0x570E,
|
---|
632 | 0x6440, 0xBC44, 0x0743, 0x2D02, 0x0419, 0xA240, 0x2113, 0x1AD4},
|
---|
633 | {0x1EB5, 0xBBFF, 0x39B1, 0x3209, 0x705F, 0x15F4, 0xD7AD, 0x340B,
|
---|
634 | 0xC2A6, 0x25CA, 0xF412, 0x9570, 0x0F4F, 0xE4D5, 0x1614, 0xE464,
|
---|
635 | 0x911A, 0x0F0E, 0x07DA, 0xA929, 0x2379, 0xD988, 0x0AA6, 0x3B57,
|
---|
636 | 0xBF63, 0x71FB, 0x72D5, 0x26CE, 0xB0AF, 0xCF45, 0x011B, 0x0100},
|
---|
637 | {0x9999, 0x98FE, 0xA108, 0x6588, 0xF90B, 0x4554, 0xFF38, 0x4642,
|
---|
638 | 0x8F5F, 0x6CC3, 0x4E8E, 0xFF7E, 0x64C2, 0x50CA, 0x0E7F, 0xAD7D,
|
---|
639 | 0x6AAB, 0x33C1, 0xE1F4, 0x6165, 0x7894, 0x83B9, 0x0A0C, 0x38AF,
|
---|
640 | 0x5803, 0x18C0, 0xFA36, 0x592C, 0x4548, 0xABB8, 0x1527, 0xAEE9}
|
---|
641 | };
|
---|
642 |
|
---|
643 |
|
---|
644 | //ecm_header_data = 01 03 b0 01 01
|
---|
645 | if (!cw_is_valid(cw,0)) //if cw is all zero, keep it that way
|
---|
646 | {
|
---|
647 | return;
|
---|
648 | }
|
---|
649 | ecm_header_count = ecm_header_data[0];
|
---|
650 | for (i = 0, ecmi = 1; i < ecm_header_count; i++)
|
---|
651 | {
|
---|
652 | if (ecm_header_data[ecmi + 1] != 0xb0)
|
---|
653 | {
|
---|
654 | ecmi += ecm_header_data[ecmi] + 1;
|
---|
655 | }
|
---|
656 | else
|
---|
657 | {
|
---|
658 | switch (ecm_header_data[ecmi + 2])
|
---|
659 | { //b0 01
|
---|
660 | case 1:
|
---|
661 | {
|
---|
662 | unsigned short hk[8], i, j, m = 0;
|
---|
663 | for (i = 0; i < 6; i++)
|
---|
664 | hk[2 + i] = Hash3[i];
|
---|
665 | for (i = 0; i < 2; i++)
|
---|
666 | {
|
---|
667 | for (j = 0; j < 0x48; j += 2)
|
---|
668 | {
|
---|
669 | if (i)
|
---|
670 | {
|
---|
671 | hk[0] = ((hk[3] & hk[5]) | ((~hk[5]) & hk[4]));
|
---|
672 | }
|
---|
673 | else
|
---|
674 | {
|
---|
675 | hk[0] = ((hk[3] & hk[4]) | ((~hk[3]) & hk[5]));
|
---|
676 | }
|
---|
677 | if (j < 8)
|
---|
678 | {
|
---|
679 | hk[0] = (hk[0] + ((cw[j + 1] << 8) | cw[j]));
|
---|
680 | }
|
---|
681 | if (j == 8)
|
---|
682 | {
|
---|
683 | hk[0] = (hk[0] + 0x80);
|
---|
684 | }
|
---|
685 | hk[0] = (hk[0] + hk[2] + (0xFF & NdTabB001[ecm_header_data[ecmi + 3]][m >> 1] >> ((m & 1) << 3)));
|
---|
686 | hk[1] = hk[2];
|
---|
687 | hk[2] = hk[3];
|
---|
688 | hk[3] = hk[4];
|
---|
689 | hk[4] = hk[5];
|
---|
690 | hk[5] = hk[6];
|
---|
691 | hk[6] = hk[7];
|
---|
692 | hk[7] = hk[2] + (((hk[0] << Hash4[m & 0xF]) | (hk[0] >> (0x10 - Hash4[m & 0xF]))));
|
---|
693 | m = (m + 1) & 0x3F;
|
---|
694 | }
|
---|
695 | }
|
---|
696 | for (i = 0; i < 6; i++)
|
---|
697 | {
|
---|
698 | hk[2 + i] += Hash3[i];
|
---|
699 | }
|
---|
700 | for (i = 0; i < 7; i++)
|
---|
701 | {
|
---|
702 | cw[i] = hk[2 + (i >> 1)] >> ((i & 1) << 3);
|
---|
703 | }
|
---|
704 | cw[3] = (cw[0] + cw[1] + cw[2]) & 0xFF;
|
---|
705 | cw[7] = (cw[4] + cw[5] + cw[6]) & 0xFF;
|
---|
706 | cs_ddump_mask(D_READER, cw, 8, "Postprocessed Case 1 DW:");
|
---|
707 | break;
|
---|
708 | }
|
---|
709 | case 3:
|
---|
710 | {
|
---|
711 | memset(buffer, 0, sizeof(buffer));
|
---|
712 | memcpy(buffer, cw, 8);
|
---|
713 | memcpy(buffer + 8, &ecm_header_data[ecmi + 3], ecm_header_data[ecmi] - 2);
|
---|
714 | MD5(buffer, 8 + ecm_header_data[ecmi] - 2, md5_digest);
|
---|
715 | memcpy(cw, md5_digest, 8);
|
---|
716 | cs_ddump_mask(D_READER, cw, 8, "Postprocessed Case 3 DW:");
|
---|
717 | break;
|
---|
718 | }
|
---|
719 | case 2:
|
---|
720 | {
|
---|
721 | /* Method 2 left out */
|
---|
722 | //memcpy(DW_OUTPUT, DW_INPUT, 8);
|
---|
723 | break;
|
---|
724 | }
|
---|
725 | }
|
---|
726 | }
|
---|
727 | }
|
---|
728 | }
|
---|
729 |
|
---|
730 | int num_addr(const unsigned char *data)
|
---|
731 | {
|
---|
732 | return ((data[3] & 0x30) >> 4) + 1;
|
---|
733 | }
|
---|
734 |
|
---|
735 | /*
|
---|
736 | Example of GLOBAL EMM's
|
---|
737 | This one has IRD-EMM + Card-EMM
|
---|
738 | 82 70 20 00 02 06 02 7D 0E 89 53 71 16 90 14 40
|
---|
739 | 01 ED 17 7D 9E 1F 28 CF 09 97 54 F1 8E 72 06 E7
|
---|
740 | 51 AF F5
|
---|
741 | This one has only IRD-EMM
|
---|
742 | 82 70 6D 00 07 69 01 30 07 14 5E 0F FF FF 00 06
|
---|
743 | 00 0D 01 00 03 01 00 00 00 0F 00 00 00 5E 01 00
|
---|
744 | 01 0C 2E 70 E4 55 B6 D2 34 F7 44 86 9E 5C 91 14
|
---|
745 | 81 FC DF CB D0 86 65 77 DF A9 E1 6B A8 9F 9B DE
|
---|
746 | 90 92 B9 AA 6C B3 4E 87 D2 EC 92 DA FC 71 EF 27
|
---|
747 | B3 C3 D0 17 CF 0B D6 5E 8C DB EB B3 37 55 6E 09
|
---|
748 | 7F 27 3C F1 85 29 C9 4E 0B EE DF 68 BE 00 C9 00
|
---|
749 | */
|
---|
750 | const unsigned char *payload_addr(uchar emmtype, const unsigned char *data, const unsigned char *a)
|
---|
751 | {
|
---|
752 | int s;
|
---|
753 | int l;
|
---|
754 | const unsigned char *ptr = NULL;
|
---|
755 | int position = -1;
|
---|
756 | int numAddrs = 0;
|
---|
757 | switch (emmtype) {
|
---|
758 | case SHARED:
|
---|
759 | {
|
---|
760 | s = 3;
|
---|
761 | break;
|
---|
762 | }
|
---|
763 | case UNIQUE:
|
---|
764 | {
|
---|
765 | s = 4;
|
---|
766 | break;
|
---|
767 | }
|
---|
768 | default:
|
---|
769 | {
|
---|
770 | s = 0;
|
---|
771 | }
|
---|
772 | }
|
---|
773 |
|
---|
774 | numAddrs = num_addr(data);
|
---|
775 | if (s > 0) {
|
---|
776 | for (l = 0; l < numAddrs; l++) {
|
---|
777 | if (!memcmp(&data[l * 4 + 4], a + 2, s)) {
|
---|
778 | position = l;
|
---|
779 | break;
|
---|
780 | }
|
---|
781 | }
|
---|
782 | }
|
---|
783 |
|
---|
784 | int num_filter = (position == -1) ? 0 : numAddrs;
|
---|
785 | /* skip header and the filter list */
|
---|
786 | ptr = data + 4 + 4 * num_filter;
|
---|
787 | if (*ptr != 0x02 && *ptr != 0x07) // some clients omit 00 00 separator */
|
---|
788 | {
|
---|
789 | ptr += 2; // skip 00 00 separator
|
---|
790 | if (*ptr == 0x00)
|
---|
791 | ptr++; // skip optional 00
|
---|
792 | ptr++; // skip the 1st bitmap len
|
---|
793 | }
|
---|
794 |
|
---|
795 | /* check for IRD-EMM */
|
---|
796 | if (*ptr != 0x02 && *ptr != 0x07) {
|
---|
797 | return NULL;
|
---|
798 | }
|
---|
799 |
|
---|
800 | /* skip IRD-EMM part, 02 00 or 02 06 xx aabbccdd yy */
|
---|
801 | ptr += 2 + ptr[1];
|
---|
802 | /* check for EMM boundaries - ptr should not exceed EMM length */
|
---|
803 | if ((int) (ptr - (data + 3)) >= data[2]) {
|
---|
804 | return NULL;
|
---|
805 | }
|
---|
806 |
|
---|
807 | for (l = 0; l < position; l++) {
|
---|
808 | /* skip the payload of the previous sub-EMM */
|
---|
809 | ptr += 1 + ptr[0];
|
---|
810 | /* check for EMM boundaries - ptr should not exceed EMM length */
|
---|
811 | if ((int) (ptr - (data + 3)) >= data[2]) {
|
---|
812 | return NULL;
|
---|
813 | }
|
---|
814 |
|
---|
815 | /* skip optional 00 */
|
---|
816 | if (*ptr == 0x00) {
|
---|
817 | ptr++;
|
---|
818 | }
|
---|
819 |
|
---|
820 | /* skip the bitmap len */
|
---|
821 | ptr++;
|
---|
822 | /* check for IRD-EMM */
|
---|
823 | if (*ptr != 0x02 && *ptr != 0x07) {
|
---|
824 | return NULL;
|
---|
825 | }
|
---|
826 |
|
---|
827 | /* skip IRD-EMM part, 02 00 or 02 06 xx aabbccdd yy */
|
---|
828 | ptr += 2 + ptr[1];
|
---|
829 | }
|
---|
830 |
|
---|
831 | return ptr;
|
---|
832 | }
|
---|
833 |
|
---|
834 |
|
---|
835 |
|
---|
836 | int videoguard_get_emm_type(EMM_PACKET *ep, struct s_reader * rdr)
|
---|
837 | {
|
---|
838 |
|
---|
839 | /*
|
---|
840 | 82 30 ad 70 00 XX XX XX 00 XX XX XX 00 XX XX XX 00 XX XX XX 00 00
|
---|
841 | d3 02 00 22 90 20 44 02 4a 50 1d 88 ab 02 ac 79 16 6c df a1 b1 b7 77 00 ba eb 63 b5 c9 a9 30 2b 43 e9 16 a9 d5 14 00
|
---|
842 | d3 02 00 22 90 20 44 02 13 e3 40 bd 29 e4 90 97 c3 aa 93 db 8d f5 6b e4 92 dd 00 9b 51 03 c9 3d d0 e2 37 44 d3 bf 00
|
---|
843 | d3 02 00 22 90 20 44 02 97 79 5d 18 96 5f 3a 67 70 55 bb b9 d2 49 31 bd 18 17 2a e9 6f eb d8 76 ec c3 c9 cc 53 39 00
|
---|
844 | d2 02 00 21 90 1f 44 02 99 6d df 36 54 9c 7c 78 1b 21 54 d9 d4 9f c1 80 3c 46 10 76 aa 75 ef d6 82 27 2e 44 7b 00
|
---|
845 | */
|
---|
846 |
|
---|
847 | int i, pos;
|
---|
848 | int serial_count = ((ep->emm[3] >> 4) & 3) + 1;
|
---|
849 | int serial_len = (ep->emm[3] & 0x80) ? 3 : 4;
|
---|
850 | uchar emmtype = (ep->emm[3] & VG_EMMTYPE_MASK) >> 6;
|
---|
851 |
|
---|
852 | pos = 4 + (serial_len * serial_count) + 2;
|
---|
853 |
|
---|
854 | switch(emmtype) {
|
---|
855 | case VG_EMMTYPE_G:
|
---|
856 | ep->type=GLOBAL;
|
---|
857 | cs_debug_mask(D_EMM, "EMM: GLOBAL");
|
---|
858 | return TRUE;
|
---|
859 |
|
---|
860 | case VG_EMMTYPE_U:
|
---|
861 | cs_debug_mask(D_EMM, "EMM: UNIQUE");
|
---|
862 | ep->type=UNIQUE;
|
---|
863 | if (ep->emm[1] == 0) // detected UNIQUE EMM from cccam (there is no serial)
|
---|
864 | return TRUE;
|
---|
865 |
|
---|
866 | for (i = 1;i <= serial_count;i++) {
|
---|
867 | if (!memcmp (rdr->hexserial + 2, ep->emm + (serial_len * i), serial_len)) {
|
---|
868 | memcpy(ep->hexserial, ep->emm + (serial_len * i), serial_len);
|
---|
869 | return TRUE;
|
---|
870 | }
|
---|
871 |
|
---|
872 | pos = pos + ep->emm[pos+5] + 5;
|
---|
873 | }
|
---|
874 | return FALSE; // if UNIQUE but no serial match return FALSE
|
---|
875 |
|
---|
876 | case VG_EMMTYPE_S:
|
---|
877 | ep->type=SHARED;
|
---|
878 | cs_debug_mask(D_EMM, "EMM: SHARED");
|
---|
879 |
|
---|
880 | for (i = 0; i < serial_count; i++) {
|
---|
881 | if (!memcmp(&ep->emm[i * 4 + 4], rdr->hexserial + 2, serial_len)) {
|
---|
882 | memcpy(ep->hexserial, &ep->emm[i * 4 + 4], serial_len);
|
---|
883 | return TRUE;
|
---|
884 | }
|
---|
885 | }
|
---|
886 |
|
---|
887 | return FALSE;
|
---|
888 |
|
---|
889 | default:
|
---|
890 | if (ep->emm[pos-2] != 0x00 && ep->emm[pos-1] != 0x00 && ep->emm[pos-1] != 0x01) {
|
---|
891 | //remote emm without serial
|
---|
892 | ep->type=UNKNOWN;
|
---|
893 | return TRUE;
|
---|
894 | }
|
---|
895 | return FALSE;
|
---|
896 | }
|
---|
897 | }
|
---|
898 |
|
---|
899 | void videoguard_get_emm_filter(struct s_reader * rdr, uchar *filter)
|
---|
900 | {
|
---|
901 | filter[0]=0xFF;
|
---|
902 | filter[1]=5;
|
---|
903 |
|
---|
904 | //ToDo videoguard_get_emm_filter basic construction
|
---|
905 | filter[2]=UNIQUE;
|
---|
906 | filter[3]=0;
|
---|
907 |
|
---|
908 | filter[4+0] = 0x82;
|
---|
909 | filter[4+0+16] = 0xFF;
|
---|
910 | filter[4+1] = 0x40;
|
---|
911 | filter[4+1+16] = 0xC0;
|
---|
912 | memcpy(filter+4+2, rdr->hexserial+2, 4);
|
---|
913 | memset(filter+4+2+16, 0xFF, 4);
|
---|
914 |
|
---|
915 | filter[36]=UNIQUE;
|
---|
916 | filter[37]=0;
|
---|
917 |
|
---|
918 | filter[38+0] = 0x82;
|
---|
919 | filter[38+0+16] = 0xFF;
|
---|
920 | filter[38+1] = 0x40;
|
---|
921 | filter[38+1+16] = 0xC0;
|
---|
922 | memcpy(filter+38+6, rdr->hexserial+2, 4);
|
---|
923 | memset(filter+38+6+16, 0xFF, 4);
|
---|
924 |
|
---|
925 | filter[70]=UNIQUE;
|
---|
926 | filter[71]=0;
|
---|
927 |
|
---|
928 | filter[72+0] = 0x82;
|
---|
929 | filter[72+0+16] = 0xFF;
|
---|
930 | filter[72+1] = 0x40;
|
---|
931 | filter[72+1+16] = 0xC0;
|
---|
932 | memcpy(filter+72+10, rdr->hexserial+2, 4);
|
---|
933 | memset(filter+72+10+16, 0xFF, 4);
|
---|
934 |
|
---|
935 | // fourth serial position does not fit within the 16bytes demux filter
|
---|
936 |
|
---|
937 |
|
---|
938 | filter[104]=SHARED;
|
---|
939 | filter[105]=0;
|
---|
940 |
|
---|
941 | filter[106+0] = 0x82;
|
---|
942 | filter[106+0+16] = 0xFF;
|
---|
943 | filter[106+1] = 0x80;
|
---|
944 | filter[106+1+16] = 0xC0;
|
---|
945 | memcpy(filter+106+2, rdr->hexserial+2, 3);
|
---|
946 | memset(filter+106+2+16, 0xFF, 3);
|
---|
947 |
|
---|
948 |
|
---|
949 | filter[138]=GLOBAL;
|
---|
950 | filter[139]=0;
|
---|
951 |
|
---|
952 | filter[140+0] = 0x82;
|
---|
953 | filter[140+0+16] = 0xFF;
|
---|
954 | filter[140+1] = 0x00;
|
---|
955 | filter[140+1+16] = 0xC0;
|
---|
956 |
|
---|
957 |
|
---|
958 | return;
|
---|
959 | }
|
---|
960 |
|
---|