Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Media Tools sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 :
28 : #include <gpac/crypt_tools.h>
29 : #include <gpac/xml.h>
30 : #include <gpac/base_coding.h>
31 : #include <gpac/constants.h>
32 : #include <gpac/filters.h>
33 : #include <gpac/network.h>
34 :
35 :
36 : #if !defined(GPAC_DISABLE_CRYPTO)
37 :
38 230 : static u32 cryptinfo_get_crypt_type(char *cr_type)
39 : {
40 230 : if (!stricmp(cr_type, "ISMA") || !stricmp(cr_type, "iAEC"))
41 : return GF_CRYPT_TYPE_ISMA;
42 219 : else if (!stricmp(cr_type, "CENC AES-CTR") || !stricmp(cr_type, "cenc"))
43 : return GF_CRYPT_TYPE_CENC;
44 80 : else if (!stricmp(cr_type, "piff"))
45 : return GF_CRYPT_TYPE_PIFF;
46 80 : else if (!stricmp(cr_type, "CENC AES-CBC") || !stricmp(cr_type, "cbc1"))
47 : return GF_CRYPT_TYPE_CBC1;
48 66 : else if (!stricmp(cr_type, "ADOBE") || !stricmp(cr_type, "adkm"))
49 : return GF_CRYPT_TYPE_ADOBE;
50 56 : else if (!stricmp(cr_type, "CENC AES-CTR Pattern") || !stricmp(cr_type, "cens"))
51 : return GF_CRYPT_TYPE_CENS;
52 30 : else if (!stricmp(cr_type, "CENC AES-CBC Pattern") || !stricmp(cr_type, "cbcs"))
53 : return GF_CRYPT_TYPE_CBCS;
54 0 : else if (!stricmp(cr_type, "OMA"))
55 : return GF_ISOM_OMADRM_SCHEME;
56 :
57 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Unrecognized crypto type %s\n", cr_type));
58 : return 0;
59 : }
60 :
61 2429 : static void cryptinfo_node_start(void *sax_cbck, const char *node_name, const char *name_space, const GF_XMLAttribute *attributes, u32 nb_attributes)
62 : {
63 : GF_XMLAttribute *att;
64 : GF_TrackCryptInfo *tkc;
65 : u32 i;
66 : GF_CryptInfo *info = (GF_CryptInfo *)sax_cbck;
67 :
68 2429 : if (!strcmp(node_name, "OMATextHeader")) {
69 0 : info->in_text_header = 1;
70 0 : return;
71 : }
72 2429 : if (!strcmp(node_name, "GPACDRM")) {
73 230 : for (i=0; i<nb_attributes; i++) {
74 230 : att = (GF_XMLAttribute *) &attributes[i];
75 230 : if (!stricmp(att->name, "type")) {
76 230 : info->def_crypt_type = cryptinfo_get_crypt_type(att->value);
77 : }
78 : }
79 : return;
80 : }
81 :
82 :
83 2199 : if (!strcmp(node_name, "CrypTrack")) {
84 : Bool has_key = GF_FALSE;
85 : Bool has_common_key = GF_TRUE;
86 230 : GF_SAFEALLOC(tkc, GF_TrackCryptInfo);
87 230 : if (!tkc) {
88 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Cannnot allocate crypt track, skipping\n"));
89 0 : info->last_parse_error = GF_OUT_OF_MEM;
90 0 : return;
91 : }
92 : //by default track is encrypted
93 230 : tkc->IsEncrypted = 1;
94 230 : tkc->sai_saved_box_type = GF_ISOM_BOX_TYPE_SENC;
95 230 : tkc->scheme_type = info->def_crypt_type;
96 :
97 : //allocate a key to store the default values in single-key mode
98 230 : tkc->keys = gf_malloc(sizeof(GF_CryptKeyInfo));
99 230 : if (!tkc->keys) {
100 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Cannnot allocate key IDs\n"));
101 0 : gf_free(tkc);
102 0 : info->last_parse_error = GF_OUT_OF_MEM;
103 0 : return;
104 : }
105 : memset(tkc->keys, 0, sizeof(GF_CryptKeyInfo));
106 230 : gf_list_add(info->tcis, tkc);
107 :
108 1550 : for (i=0; i<nb_attributes; i++) {
109 1320 : att = (GF_XMLAttribute *) &attributes[i];
110 1320 : if (!stricmp(att->name, "trackID") || !stricmp(att->name, "ID")) {
111 230 : if (!strcmp(att->value, "*")) info->has_common_key = 1;
112 : else {
113 230 : tkc->trackID = atoi(att->value);
114 : has_common_key = GF_FALSE;
115 : }
116 : }
117 1090 : else if (!stricmp(att->name, "type")) {
118 0 : tkc->scheme_type = cryptinfo_get_crypt_type(att->value);
119 : }
120 1090 : else if (!stricmp(att->name, "forceType")) {
121 0 : tkc->force_type = GF_TRUE;
122 : }
123 1090 : else if (!stricmp(att->name, "key")) {
124 : GF_Err e;
125 : has_key = GF_TRUE;
126 11 : e = gf_bin128_parse(att->value, tkc->keys[0].key );
127 11 : if (e != GF_OK) {
128 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannnot parse key value in CrypTrack\n"));
129 0 : info->last_parse_error = GF_BAD_PARAM;
130 0 : return;
131 : }
132 : }
133 1079 : else if (!stricmp(att->name, "salt")) {
134 : u32 len, j;
135 11 : char *sKey = att->value;
136 11 : if (!strnicmp(sKey, "0x", 2)) sKey += 2;
137 11 : len = (u32) strlen(sKey);
138 99 : for (j=0; j<len; j+=2) {
139 : char szV[5];
140 : u32 v;
141 88 : sprintf(szV, "%c%c", sKey[j], sKey[j+1]);
142 88 : sscanf(szV, "%x", &v);
143 88 : tkc->keys[0].IV[j/2] = v;
144 88 : if (j>=30) break;
145 : }
146 : }
147 1068 : else if (!stricmp(att->name, "kms_URI") || !stricmp(att->name, "rightsIssuerURL")) {
148 11 : if (tkc->KMS_URI) gf_free(tkc->KMS_URI);
149 11 : tkc->KMS_URI = gf_strdup(att->value);
150 : }
151 1057 : else if (!stricmp(att->name, "scheme_URI") || !stricmp(att->name, "contentID")) {
152 0 : if (tkc->Scheme_URI) gf_free(tkc->Scheme_URI);
153 0 : tkc->Scheme_URI = gf_strdup(att->value);
154 : }
155 1057 : else if (!stricmp(att->name, "selectiveType")) {
156 44 : if (!stricmp(att->value, "Rap")) tkc->sel_enc_type = GF_CRYPT_SELENC_RAP;
157 8 : else if (!stricmp(att->value, "Non-Rap")) tkc->sel_enc_type = GF_CRYPT_SELENC_NON_RAP;
158 8 : else if (!stricmp(att->value, "Rand")) tkc->sel_enc_type = GF_CRYPT_SELENC_RAND;
159 8 : else if (!strnicmp(att->value, "Rand", 4)) {
160 0 : tkc->sel_enc_type = GF_CRYPT_SELENC_RAND_RANGE;
161 0 : tkc->sel_enc_range = atoi(&att->value[4]);
162 : }
163 8 : else if (sscanf(att->value, "%u", &tkc->sel_enc_range)==1) {
164 0 : if (tkc->sel_enc_range==1) tkc->sel_enc_range = 0;
165 0 : else tkc->sel_enc_type = GF_CRYPT_SELENC_RANGE;
166 : }
167 8 : else if (!strnicmp(att->value, "Preview", 7)) {
168 0 : tkc->sel_enc_type = GF_CRYPT_SELENC_PREVIEW;
169 : }
170 8 : else if (!strnicmp(att->value, "Clear", 5)) {
171 0 : tkc->sel_enc_type = GF_CRYPT_SELENC_CLEAR;
172 : }
173 8 : else if (!strnicmp(att->value, "ForceClear", 10)) {
174 8 : char *sep = strchr(att->value, '=');
175 16 : if (sep) tkc->sel_enc_range = atoi(sep+1);
176 8 : tkc->sel_enc_type = GF_CRYPT_SELENC_CLEAR_FORCED;
177 : }
178 0 : else if (!stricmp(att->value, "None")) {
179 : } else {
180 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized selective mode %s, ignoring\n", att->value));
181 : }
182 : }
183 1013 : else if (!stricmp(att->name, "clearStsd")) {
184 6 : if (!strcmp(att->value, "none")) tkc->force_clear_stsd_idx = 0;
185 6 : else if (!strcmp(att->value, "before")) tkc->force_clear_stsd_idx = 1;
186 4 : else if (!strcmp(att->value, "after")) tkc->force_clear_stsd_idx = 2;
187 : else {
188 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized clear stsd type %s, defaulting to no stsd for clear samples\n", att->value));
189 : }
190 : }
191 1007 : else if (!stricmp(att->name, "Preview")) {
192 0 : tkc->sel_enc_type = GF_CRYPT_SELENC_PREVIEW;
193 0 : sscanf(att->value, "%u", &tkc->sel_enc_range);
194 : }
195 1007 : else if (!stricmp(att->name, "ipmpType")) {
196 0 : if (!stricmp(att->value, "None")) tkc->ipmp_type = 0;
197 0 : else if (!stricmp(att->value, "IPMP")) tkc->sel_enc_type = 1;
198 0 : else if (!stricmp(att->value, "IPMPX")) tkc->sel_enc_type = 2;
199 : }
200 1007 : else if (!stricmp(att->name, "ipmpDescriptorID")) tkc->ipmp_desc_id = atoi(att->value);
201 1007 : else if (!stricmp(att->name, "encryptionMethod")) {
202 0 : if (!strcmp(att->value, "AES_128_CBC")) tkc->encryption = 1;
203 0 : else if (!strcmp(att->value, "None")) tkc->encryption = 0;
204 0 : else if (!strcmp(att->value, "AES_128_CTR") || !strcmp(att->value, "default")) tkc->encryption = 2;
205 : else {
206 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized encryption algo %s, ignoring\n", att->value));
207 : }
208 : }
209 1007 : else if (!stricmp(att->name, "transactionID")) {
210 0 : if (strlen(att->value)<=16) strcpy(tkc->TransactionID, att->value);
211 : }
212 1007 : else if (!stricmp(att->name, "textualHeaders")) {
213 : }
214 1007 : else if (!stricmp(att->name, "IsEncrypted")) {
215 219 : if (!stricmp(att->value, "1"))
216 219 : tkc->IsEncrypted = 1;
217 : else
218 0 : tkc->IsEncrypted = 0;
219 : }
220 788 : else if (!stricmp(att->name, "IV_size")) {
221 388 : tkc->keys[0].IV_size = atoi(att->value);
222 : }
223 594 : else if (!stricmp(att->name, "first_IV")) {
224 204 : char *sKey = att->value;
225 204 : if (!strnicmp(sKey, "0x", 2)) sKey += 2;
226 204 : if ((strlen(sKey) == 16) || (strlen(sKey) == 32)) {
227 : u32 j;
228 3024 : for (j=0; j<strlen(sKey); j+=2) {
229 : u32 v;
230 : char szV[5];
231 3024 : sprintf(szV, "%c%c", sKey[j], sKey[j+1]);
232 3024 : sscanf(szV, "%x", &v);
233 3024 : tkc->keys[0].IV[j/2] = v;
234 : }
235 204 : if (!tkc->keys[0].IV_size) tkc->keys[0].IV_size = (u8) strlen(sKey) / 2;
236 : }
237 : }
238 390 : else if (!stricmp(att->name, "saiSavedBox")) {
239 206 : if (!stricmp(att->value, "uuid_psec")) tkc->sai_saved_box_type = GF_ISOM_BOX_UUID_PSEC;
240 194 : else if (!stricmp(att->value, "senc")) tkc->sai_saved_box_type = GF_ISOM_BOX_TYPE_SENC;
241 : else {
242 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized SAI location %s, ignoring\n", att->value));
243 : }
244 : }
245 184 : else if (!stricmp(att->name, "keyRoll")) {
246 27 : if (!strncmp(att->value, "idx=", 4))
247 0 : tkc->defaultKeyIdx = atoi(att->value+4);
248 27 : else if (!strncmp(att->value, "roll=", 5))
249 26 : tkc->keyRoll = atoi(att->value+5);
250 14 : else if (!strcmp(att->value, "rap"))
251 0 : tkc->roll_rap = GF_TRUE;
252 : else {
253 14 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized roll parameter %s, ignoring\n", att->value));
254 : }
255 : }
256 157 : else if (!stricmp(att->name, "metadata")) {
257 10 : u32 l = 2 * (u32) strlen(att->value);
258 10 : tkc->metadata = gf_malloc(sizeof(char) * l);
259 10 : l = gf_base64_encode(att->value, (u32) strlen(att->value), tkc->metadata, l);
260 10 : tkc->metadata[l] = 0;
261 : }
262 147 : else if (!stricmp(att->name, "crypt_byte_block")) {
263 52 : tkc->crypt_byte_block = atoi(att->value);
264 : }
265 121 : else if (!stricmp(att->name, "skip_byte_block")) {
266 52 : tkc->skip_byte_block = atoi(att->value);
267 : }
268 95 : else if (!stricmp(att->name, "clear_bytes")) {
269 4 : tkc->clear_bytes = atoi(att->value);
270 : }
271 93 : else if (!stricmp(att->name, "constant_IV_size")) {
272 30 : tkc->keys[0].constant_IV_size = atoi(att->value);
273 15 : if ((tkc->keys[0].constant_IV_size != 8) && (tkc->keys[0].constant_IV_size != 16)) {
274 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Constant IV size %d is not 8 or 16\n", att->value));
275 : }
276 : }
277 78 : else if (!stricmp(att->name, "constant_IV")) {
278 15 : char *sKey = att->value;
279 15 : if (!strnicmp(sKey, "0x", 2)) sKey += 2;
280 15 : if ((strlen(sKey) == 16) || (strlen(sKey) == 32)) {
281 : u32 j;
282 240 : for (j=0; j<strlen(sKey); j+=2) {
283 : u32 v;
284 : char szV[5];
285 240 : sprintf(szV, "%c%c", sKey[j], sKey[j+1]);
286 240 : sscanf(szV, "%x", &v);
287 240 : tkc->keys[0].IV[j/2] = v;
288 : }
289 15 : if (!tkc->keys[0].constant_IV_size) tkc->keys[0].constant_IV_size = (u8) strlen(sKey) / 2;
290 : }
291 : }
292 63 : else if (!stricmp(att->name, "encryptSliceHeader")) {
293 17 : tkc->allow_encrypted_slice_header = !strcmp(att->value, "yes") ? GF_TRUE : GF_FALSE;
294 : }
295 46 : else if (!stricmp(att->name, "blockAlign")) {
296 32 : if (!strcmp(att->value, "disable")) tkc->block_align = 1;
297 15 : else if (!strcmp(att->value, "always")) tkc->block_align = 2;
298 0 : else tkc->block_align = 0;
299 : }
300 14 : else if (!stricmp(att->name, "subsamples")) {
301 1 : char *val = att->value;
302 2 : while (val) {
303 1 : char *sep = strchr(val, ';');
304 1 : if (sep) sep[0] = 0;
305 1 : if (!strncmp(val, "subs=", 5)) {
306 1 : if (tkc->subs_crypt) gf_free(tkc->subs_crypt);
307 1 : tkc->subs_crypt = gf_strdup(val+4);
308 : }
309 0 : else if (!strncmp(val, "rand", 4)) {
310 0 : tkc->subs_rand = 2;
311 0 : if (val[4]=='=')
312 0 : tkc->subs_rand = atoi(val+5);
313 : }
314 : else {
315 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] unrecognized attribute value %s for `subsamples`, ignoring\n", val));
316 : }
317 1 : if (!sep) break;
318 0 : sep[0] = ';';
319 0 : val = sep+1;
320 : }
321 : }
322 13 : else if (!stricmp(att->name, "multiKey")) {
323 3 : if (!strcmp(att->value, "all") || !strcmp(att->value, "on")) tkc->multi_key = GF_TRUE;
324 2 : else if (!strcmp(att->value, "no")) tkc->multi_key = GF_FALSE;
325 : else {
326 : char *val = att->value;
327 2 : tkc->multi_key = GF_TRUE;
328 4 : while (val) {
329 2 : char *sep = strchr(val, ';');
330 2 : if (sep) sep[0] = 0;
331 2 : if (!strncmp(val, "roll=", 5)) {
332 2 : tkc->mkey_roll_plus_one = 1 + atoi(val+5);
333 : }
334 1 : else if (!strncmp(val, "subs=", 5)) {
335 1 : if (tkc->mkey_subs) gf_free(tkc->mkey_subs);
336 1 : tkc->mkey_subs = gf_strdup(val+5);
337 : }
338 : else {
339 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] unrecognized attribute value %s for `multiKey`, ignoring\n", val));
340 0 : tkc->multi_key = GF_FALSE;
341 0 : if (sep) sep[0] = ';';
342 : break;
343 : }
344 2 : if (!sep) break;
345 0 : sep[0] = ';';
346 0 : val = sep+1;
347 : }
348 : }
349 : }
350 : }
351 230 : if (tkc->scheme_type==GF_CRYPT_TYPE_PIFF) {
352 0 : tkc->sai_saved_box_type = GF_ISOM_BOX_UUID_PSEC;
353 : }
354 230 : if (has_common_key) info->has_common_key = 1;
355 :
356 230 : if ((tkc->keys[0].IV_size != 0) && (tkc->keys[0].IV_size != 8) && (tkc->keys[0].IV_size != 16)) {
357 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] wrong IV size %d for AES-128, using 16\n", (u32) tkc->keys[0].IV_size));
358 0 : tkc->keys[0].IV_size = 16;
359 : }
360 :
361 230 : if ((tkc->scheme_type == GF_CRYPT_TYPE_CENC) || (tkc->scheme_type == GF_CRYPT_TYPE_CBC1)) {
362 153 : if (tkc->crypt_byte_block || tkc->skip_byte_block) {
363 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Using scheme type %s, crypt_byte_block and skip_byte_block shall be 0\n", gf_4cc_to_str(tkc->scheme_type) ));
364 0 : tkc->crypt_byte_block = tkc->skip_byte_block = 0;
365 : }
366 : }
367 :
368 230 : if ((tkc->scheme_type == GF_CRYPT_TYPE_CENC) || (tkc->scheme_type == GF_CRYPT_TYPE_CBC1) || (tkc->scheme_type == GF_CRYPT_TYPE_CENS)) {
369 179 : if (tkc->keys[0].constant_IV_size) {
370 0 : if (!tkc->keys[0].IV_size) {
371 0 : tkc->keys[0].IV_size = tkc->keys[0].constant_IV_size;
372 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Using scheme type %s, constant IV shall not be used, using constant IV as first IV\n", gf_4cc_to_str(tkc->scheme_type)));
373 0 : tkc->keys[0].constant_IV_size = 0;
374 : } else {
375 0 : tkc->keys[0].constant_IV_size = 0;
376 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Using scheme type %s, constant IV shall not be used, ignoring\n", gf_4cc_to_str(tkc->scheme_type)));
377 : }
378 : }
379 : }
380 230 : if (tkc->scheme_type == GF_ISOM_OMADRM_SCHEME) {
381 : /*default to AES 128 in OMA*/
382 0 : tkc->encryption = 2;
383 : }
384 :
385 230 : if (has_key) tkc->nb_keys = 1;
386 : }
387 :
388 2199 : if (!strcmp(node_name, "key")) {
389 : u32 IV_size, const_IV_size;
390 : Bool kas_civ = GF_FALSE;
391 275 : tkc = (GF_TrackCryptInfo *)gf_list_last(info->tcis);
392 275 : if (!tkc) return;
393 : //only realloc for 2nd and more
394 275 : if (tkc->nb_keys) {
395 56 : tkc->keys = (GF_CryptKeyInfo *)gf_realloc(tkc->keys, sizeof(GF_CryptKeyInfo)*(tkc->nb_keys+1));
396 56 : memset(&tkc->keys[tkc->nb_keys], 0, sizeof(GF_CryptKeyInfo));
397 : }
398 275 : IV_size = tkc->keys[0].IV_size;
399 275 : const_IV_size = tkc->keys[0].constant_IV_size;
400 :
401 854 : for (i=0; i<nb_attributes; i++) {
402 579 : att = (GF_XMLAttribute *) &attributes[i];
403 :
404 579 : if (!stricmp(att->name, "KID")) {
405 265 : GF_Err e = gf_bin128_parse(att->value, tkc->keys[tkc->nb_keys].KID);
406 265 : if (e != GF_OK) {
407 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannnot parse KID\n"));
408 : return;
409 : }
410 : }
411 314 : else if (!stricmp(att->name, "value")) {
412 275 : GF_Err e = gf_bin128_parse(att->value, tkc->keys[tkc->nb_keys].key);
413 275 : if (e != GF_OK) {
414 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannnot parse key value\n"));
415 : return;
416 : }
417 : }
418 39 : else if (!stricmp(att->name, "hlsInfo")) {
419 39 : if (!strstr(att->value, "URI=\"")) {
420 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Missing URI in HLS info %s\n", att->value));
421 : return;
422 : }
423 39 : tkc->keys[tkc->nb_keys].hls_info = gf_strdup(att->value);
424 : }
425 0 : else if (!stricmp(att->name, "IV_size")) {
426 0 : IV_size = atoi(att->value);
427 : }
428 0 : else if (!stricmp(att->name, "constant_IV")) {
429 0 : char *sKey = att->value;
430 0 : if (!strnicmp(sKey, "0x", 2)) sKey += 2;
431 0 : if ((strlen(sKey) == 16) || (strlen(sKey) == 32)) {
432 : u32 j;
433 0 : for (j=0; j<strlen(sKey); j+=2) {
434 : u32 v;
435 : char szV[5];
436 0 : sprintf(szV, "%c%c", sKey[j], sKey[j+1]);
437 0 : sscanf(szV, "%x", &v);
438 0 : tkc->keys[tkc->nb_keys].IV[j/2] = v;
439 : }
440 0 : const_IV_size = (u8) strlen(sKey) / 2;
441 : kas_civ = GF_TRUE;
442 : }
443 : }
444 : }
445 275 : tkc->keys[tkc->nb_keys].IV_size = IV_size;
446 275 : tkc->keys[tkc->nb_keys].constant_IV_size = const_IV_size;
447 275 : if (!kas_civ && tkc->nb_keys)
448 56 : memcpy(tkc->keys[tkc->nb_keys].IV, tkc->keys[0].IV, 16);
449 275 : tkc->nb_keys++;
450 : }
451 : }
452 :
453 2429 : static void cryptinfo_node_end(void *sax_cbck, const char *node_name, const char *name_space)
454 : {
455 : GF_CryptInfo *info = (GF_CryptInfo *)sax_cbck;
456 2429 : if (!strcmp(node_name, "OMATextHeader")) {
457 0 : info->in_text_header = 0;
458 0 : return;
459 : }
460 : }
461 :
462 3230 : static void cryptinfo_text(void *sax_cbck, const char *text, Bool is_cdata)
463 : {
464 : u32 len, len2;
465 : GF_TrackCryptInfo *tkc;
466 : GF_CryptInfo *info = (GF_CryptInfo *)sax_cbck;
467 :
468 3230 : if (!info->in_text_header) return;
469 :
470 0 : tkc = (GF_TrackCryptInfo *) gf_list_last(info->tcis);
471 0 : len = (u32) strlen(text);
472 0 : len2 = tkc->TextualHeaders ? (u32) strlen(tkc->TextualHeaders) : 0;
473 :
474 0 : tkc->TextualHeaders = gf_realloc(tkc->TextualHeaders, sizeof(char) * (len+len2+1));
475 0 : if (!len2) strcpy(tkc->TextualHeaders, "");
476 0 : strcat(tkc->TextualHeaders, text);
477 : }
478 :
479 230 : void gf_crypt_info_del(GF_CryptInfo *info)
480 : {
481 690 : while (gf_list_count(info->tcis)) {
482 : u32 i;
483 230 : GF_TrackCryptInfo *tci = (GF_TrackCryptInfo *)gf_list_last(info->tcis);
484 516 : for (i=0; i<tci->nb_keys; i++) {
485 286 : if (tci->keys[i].hls_info)
486 39 : gf_free(tci->keys[i].hls_info);
487 : }
488 230 : if (tci->keys) gf_free(tci->keys);
489 230 : if (tci->metadata) gf_free(tci->metadata);
490 230 : if (tci->KMS_URI) gf_free(tci->KMS_URI);
491 230 : if (tci->Scheme_URI) gf_free(tci->Scheme_URI);
492 230 : if (tci->TextualHeaders) gf_free(tci->TextualHeaders);
493 230 : if (tci->subs_crypt) gf_free(tci->subs_crypt);
494 230 : if (tci->mkey_subs) gf_free(tci->mkey_subs);
495 230 : gf_list_rem_last(info->tcis);
496 230 : gf_free(tci);
497 : }
498 230 : gf_list_del(info->tcis);
499 230 : gf_free(info);
500 230 : }
501 :
502 230 : GF_CryptInfo *gf_crypt_info_load(const char *file, GF_Err *out_err)
503 : {
504 : GF_Err e;
505 : GF_CryptInfo *info;
506 : GF_SAXParser *sax;
507 230 : GF_SAFEALLOC(info, GF_CryptInfo);
508 230 : if (!info) {
509 0 : if (out_err) *out_err = GF_OUT_OF_MEM;
510 : return NULL;
511 : }
512 230 : info->tcis = gf_list_new();
513 230 : sax = gf_xml_sax_new(cryptinfo_node_start, cryptinfo_node_end, cryptinfo_text, info);
514 230 : e = gf_xml_sax_parse_file(sax, file, NULL);
515 230 : if (e<0) {
516 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[DRM] Failed to parse DRM config file: %s", gf_xml_sax_get_error(sax) ));
517 0 : if (out_err) *out_err = e;
518 0 : gf_crypt_info_del(info);
519 : info = NULL;
520 230 : } else if (info->last_parse_error) {
521 0 : if (out_err) *out_err = info->last_parse_error;
522 0 : gf_crypt_info_del(info);
523 : info = NULL;
524 : } else {
525 230 : if (out_err) *out_err = GF_OK;
526 : }
527 230 : gf_xml_sax_del(sax);
528 230 : return info;
529 : }
530 :
531 : extern char gf_prog_lf;
532 :
533 0 : static Bool on_decrypt_event(void *_udta, GF_Event *evt)
534 : {
535 : Double progress;
536 : u32 *prev_progress = (u32 *)_udta;
537 0 : if (!_udta) return GF_FALSE;
538 0 : if (evt->type != GF_EVENT_PROGRESS) return GF_FALSE;
539 0 : if (!evt->progress.total) return GF_FALSE;
540 :
541 0 : progress = (Double) (100*evt->progress.done) / evt->progress.total;
542 0 : if ((u32) progress==*prev_progress)
543 : return GF_FALSE;
544 :
545 0 : *prev_progress = (u32) progress;
546 : #ifndef GPAC_DISABLE_LOG
547 0 : GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Decrypting: % 2.2f %%%c", progress, gf_prog_lf));
548 : #else
549 : fprintf(stderr, "Decrypting: % 2.2f %%%c", progress, gf_prog_lf);
550 : #endif
551 : return GF_FALSE;
552 : }
553 :
554 107 : static GF_Err gf_decrypt_file_ex(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, const char *fragment_name, u32 fs_dump_flags)
555 : {
556 107 : char *szArgs = NULL;
557 : char an_arg[100];
558 : GF_Filter *src, *dst, *dcrypt;
559 : GF_FilterSession *fsess;
560 107 : GF_Err e = GF_OK;
561 107 : u32 progress = (u32) -1;
562 :
563 107 : fsess = gf_fs_new_defaults(0);
564 107 : if (!fsess) {
565 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Failed to create filter session\n"));
566 : return GF_OUT_OF_MEM;
567 : }
568 :
569 : sprintf(an_arg, "mp4dmx:mov=%p", mp4);
570 107 : gf_dynstrcat(&szArgs, an_arg, NULL);
571 107 : if (fragment_name) {
572 1 : gf_dynstrcat(&szArgs, ":sigfrag:catseg=", NULL);
573 1 : gf_dynstrcat(&szArgs, fragment_name, NULL);
574 : }
575 107 : src = gf_fs_load_filter(fsess, szArgs, &e);
576 107 : gf_free(szArgs);
577 107 : szArgs = NULL;
578 :
579 107 : if (!src) {
580 0 : gf_fs_del(fsess);
581 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Cannot load demux filter for source file\n"));
582 0 : return e;
583 : }
584 :
585 107 : gf_dynstrcat(&szArgs, "cdcrypt:FID=1", NULL);
586 107 : if (drm_file) {
587 100 : gf_dynstrcat(&szArgs, ":cfile=", NULL);
588 100 : gf_dynstrcat(&szArgs, drm_file, NULL);
589 : }
590 107 : dcrypt = gf_fs_load_filter(fsess, szArgs, &e);
591 107 : gf_free(szArgs);
592 107 : szArgs = NULL;
593 107 : if (!dcrypt) {
594 0 : gf_fs_del(fsess);
595 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Cannot load decryptor filter\n"));
596 0 : return e;
597 : }
598 :
599 107 : gf_dynstrcat(&szArgs, "SID=1", NULL);
600 107 : if (fragment_name) {
601 1 : gf_dynstrcat(&szArgs, ":sseg:noinit:store=frag:refrag:cdur=1000000000", NULL);
602 : } else {
603 106 : if (interleave_time) {
604 : sprintf(an_arg, ":cdur=%g", interleave_time);
605 106 : gf_dynstrcat(&szArgs, an_arg, NULL);
606 : } else {
607 0 : gf_dynstrcat(&szArgs, ":store=flat", NULL);
608 : }
609 : }
610 107 : if (gf_isom_has_keep_utc_times(mp4))
611 0 : gf_dynstrcat(&szArgs, ":keep_utc", NULL);
612 :
613 107 : dst = gf_fs_load_destination(fsess, dst_file, szArgs, NULL, &e);
614 107 : gf_free(szArgs);
615 107 : szArgs = NULL;
616 :
617 107 : if (!dst) {
618 0 : gf_fs_del(fsess);
619 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Cannot load destination muxer\n"));
620 : return GF_FILTER_NOT_FOUND;
621 : }
622 :
623 107 : if (!gf_sys_is_test_mode()
624 : #ifndef GPAC_DISABLE_LOG
625 0 : && (gf_log_get_tool_level(GF_LOG_APP)!=GF_LOG_QUIET)
626 : #endif
627 0 : && !gf_sys_is_quiet()
628 : ) {
629 0 : gf_fs_enable_reporting(fsess, GF_TRUE);
630 0 : gf_fs_set_ui_callback(fsess, on_decrypt_event, &progress);
631 : }
632 : #ifdef GPAC_ENABLE_COVERAGE
633 107 : else if (gf_sys_is_cov_mode()) {
634 : on_decrypt_event(NULL, NULL);
635 : }
636 : #endif //GPAC_ENABLE_COVERAGE
637 :
638 107 : e = gf_fs_run(fsess);
639 107 : if (e>GF_OK) e = GF_OK;
640 107 : if (!e) e = gf_fs_get_last_connect_error(fsess);
641 107 : if (!e) e = gf_fs_get_last_process_error(fsess);
642 :
643 107 : if (!e) gf_fs_print_unused_args(fsess, NULL);
644 107 : gf_fs_print_non_connected(fsess);
645 107 : if (fs_dump_flags & 1) gf_fs_print_stats(fsess);
646 107 : if (fs_dump_flags & 2) gf_fs_print_connections(fsess);
647 :
648 107 : gf_fs_del(fsess);
649 107 : return e;
650 : }
651 :
652 : GF_EXPORT
653 1 : GF_Err gf_decrypt_fragment(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, const char *fragment_name, u32 fs_dump_flags)
654 : {
655 1 : return gf_decrypt_file_ex(mp4, drm_file, dst_file, 0, fragment_name, fs_dump_flags);
656 : }
657 : GF_EXPORT
658 106 : GF_Err gf_decrypt_file(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, u32 fs_dump_flags)
659 : {
660 106 : return gf_decrypt_file_ex(mp4, drm_file, dst_file, interleave_time, NULL, fs_dump_flags);
661 : }
662 0 : static Bool on_crypt_event(void *_udta, GF_Event *evt)
663 : {
664 : Double progress;
665 : u32 *prev_progress = (u32 *)_udta;
666 0 : if (!_udta) return GF_FALSE;
667 0 : if (evt->type != GF_EVENT_PROGRESS) return GF_FALSE;
668 0 : if (!evt->progress.total) return GF_FALSE;
669 :
670 0 : progress = (Double) (100*evt->progress.done) / evt->progress.total;
671 0 : if ((u32) progress==*prev_progress)
672 : return GF_FALSE;
673 :
674 0 : *prev_progress = (u32) progress;
675 : #ifndef GPAC_DISABLE_LOG
676 0 : GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Encrypting: % 2.2f %%%c", progress, gf_prog_lf));
677 : #else
678 : fprintf(stderr, "Encrypting: % 2.2f %%%c", progress, gf_prog_lf);
679 : #endif
680 : return GF_FALSE;
681 : }
682 :
683 115 : static GF_Err gf_crypt_file_ex(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, const char *fragment_name, u32 fs_dump_flags)
684 : {
685 115 : char *szArgs=NULL;
686 : char an_arg[100];
687 : char *arg_dst=NULL;
688 115 : u32 progress = (u32) -1;
689 : GF_Filter *src, *dst, *crypt;
690 : GF_FilterSession *fsess;
691 115 : GF_Err e = GF_OK;
692 :
693 115 : fsess = gf_fs_new_defaults(0);
694 115 : if (!fsess) {
695 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Failed to create filter session\n"));
696 : return GF_OUT_OF_MEM;
697 : }
698 :
699 : sprintf(an_arg, "mp4dmx:mov=%p", mp4);
700 115 : gf_dynstrcat(&szArgs, an_arg, NULL);
701 115 : if (fragment_name) {
702 2 : gf_dynstrcat(&szArgs, ":sigfrag:catseg=", NULL);
703 2 : gf_dynstrcat(&szArgs, fragment_name, NULL);
704 : }
705 115 : src = gf_fs_load_filter(fsess, szArgs, &e);
706 :
707 115 : gf_free(szArgs);
708 115 : szArgs = NULL;
709 :
710 115 : if (!src) {
711 0 : gf_fs_del(fsess);
712 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Cannot load demux for source file: %s\n", gf_error_to_string(e)));
713 0 : return e;
714 : }
715 :
716 115 : gf_dynstrcat(&szArgs, "cecrypt:FID=1:cfile=", NULL);
717 115 : gf_dynstrcat(&szArgs, drm_file, NULL);
718 115 : crypt = gf_fs_load_filter(fsess, szArgs, &e);
719 :
720 115 : gf_free(szArgs);
721 115 : szArgs = NULL;
722 :
723 115 : if (!crypt) {
724 0 : gf_fs_del(fsess);
725 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Cannot load encryptor: %s\n", gf_error_to_string(e) ));
726 0 : return e;
727 : }
728 :
729 115 : gf_dynstrcat(&szArgs, "SID=1", NULL);
730 115 : if (fragment_name) {
731 2 : gf_dynstrcat(&szArgs, ":sseg:noinit:store=frag:refrag:cdur=1000000000", NULL);
732 : } else {
733 113 : if (interleave_time) {
734 : sprintf(an_arg, ":cdur=%g", interleave_time);
735 113 : gf_dynstrcat(&szArgs, an_arg, NULL);
736 : } else {
737 0 : gf_dynstrcat(&szArgs, ":store=flat", NULL);
738 : }
739 : }
740 :
741 115 : if (gf_isom_has_keep_utc_times(mp4))
742 0 : gf_dynstrcat(&szArgs, ":keep_utc", NULL);
743 :
744 115 : arg_dst = gf_url_colon_suffix(dst_file);
745 115 : if (arg_dst) {
746 0 : gf_dynstrcat(&szArgs, arg_dst, NULL);
747 0 : arg_dst[0]=0;
748 : }
749 115 : dst = gf_fs_load_destination(fsess, dst_file, szArgs, NULL, &e);
750 :
751 115 : gf_free(szArgs);
752 115 : szArgs = NULL;
753 115 : if (!dst) {
754 0 : gf_fs_del(fsess);
755 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Cannot load destination muxer\n"));
756 : return GF_FILTER_NOT_FOUND;
757 : }
758 :
759 115 : if (!gf_sys_is_test_mode()
760 : #ifndef GPAC_DISABLE_LOG
761 0 : && (gf_log_get_tool_level(GF_LOG_APP)!=GF_LOG_QUIET)
762 : #endif
763 0 : && !gf_sys_is_quiet()
764 : ) {
765 0 : gf_fs_enable_reporting(fsess, GF_TRUE);
766 0 : gf_fs_set_ui_callback(fsess, on_crypt_event, &progress);
767 : }
768 : #ifdef GPAC_ENABLE_COVERAGE
769 115 : else if (gf_sys_is_cov_mode()) {
770 : on_crypt_event(NULL, NULL);
771 : }
772 : #endif //GPAC_ENABLE_COVERAGE
773 115 : e = gf_fs_run(fsess);
774 115 : if (e>GF_OK) e = GF_OK;
775 115 : if (!e) e = gf_fs_get_last_connect_error(fsess);
776 115 : if (!e) e = gf_fs_get_last_process_error(fsess);
777 :
778 115 : if (!e) gf_fs_print_unused_args(fsess, NULL);
779 115 : gf_fs_print_non_connected(fsess);
780 115 : if (fs_dump_flags & 1) gf_fs_print_stats(fsess);
781 115 : if (fs_dump_flags & 2) gf_fs_print_connections(fsess);
782 115 : gf_fs_del(fsess);
783 115 : return e;
784 : }
785 :
786 : GF_EXPORT
787 2 : GF_Err gf_crypt_fragment(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, const char *fragment_name, u32 fs_dump_flags)
788 : {
789 2 : return gf_crypt_file_ex(mp4, drm_file, dst_file, 0, fragment_name, fs_dump_flags);
790 : }
791 :
792 : GF_EXPORT
793 113 : GF_Err gf_crypt_file(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, u32 fs_dump_flags)
794 : {
795 113 : return gf_crypt_file_ex(mp4, drm_file, dst_file, interleave_time, NULL, fs_dump_flags);
796 :
797 : }
798 : #endif /* !defined(GPAC_DISABLE_ISOM_WRITE)*/
799 :
|