1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2000-2020
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 
cryptinfo_get_crypt_type(char * cr_type)38 static u32 cryptinfo_get_crypt_type(char *cr_type)
39 {
40 	if (!stricmp(cr_type, "ISMA") || !stricmp(cr_type, "iAEC"))
41 		return GF_CRYPT_TYPE_ISMA;
42 	else if (!stricmp(cr_type, "CENC AES-CTR") || !stricmp(cr_type, "cenc"))
43 		return GF_CRYPT_TYPE_CENC;
44 	else if (!stricmp(cr_type, "piff"))
45 		return GF_CRYPT_TYPE_PIFF;
46 	else if (!stricmp(cr_type, "CENC AES-CBC") || !stricmp(cr_type, "cbc1"))
47 		return GF_CRYPT_TYPE_CBC1;
48 	else if (!stricmp(cr_type, "ADOBE") || !stricmp(cr_type, "adkm"))
49 		return GF_CRYPT_TYPE_ADOBE;
50 	else if (!stricmp(cr_type, "CENC AES-CTR Pattern") || !stricmp(cr_type, "cens"))
51 		return GF_CRYPT_TYPE_CENS;
52 	else if (!stricmp(cr_type, "CENC AES-CBC Pattern") || !stricmp(cr_type, "cbcs"))
53 		return GF_CRYPT_TYPE_CBCS;
54 	else if (!stricmp(cr_type, "OMA"))
55 		return GF_ISOM_OMADRM_SCHEME;
56 
57 	GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Unrecognized crypto type %s\n", cr_type));
58 	return 0;
59 }
60 
cryptinfo_node_start(void * sax_cbck,const char * node_name,const char * name_space,const GF_XMLAttribute * attributes,u32 nb_attributes)61 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 	if (!strcmp(node_name, "OMATextHeader")) {
69 		info->in_text_header = 1;
70 		return;
71 	}
72 	if (!strcmp(node_name, "GPACDRM")) {
73 		for (i=0; i<nb_attributes; i++) {
74 			att = (GF_XMLAttribute *) &attributes[i];
75 			if (!stricmp(att->name, "type")) {
76 				info->def_crypt_type = cryptinfo_get_crypt_type(att->value);
77 			}
78 		}
79 		return;
80 	}
81 	if (!strcmp(node_name, "CrypTrack")) {
82 		Bool has_common_key = GF_TRUE;
83 		GF_SAFEALLOC(tkc, GF_TrackCryptInfo);
84 		if (!tkc) {
85 			GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] Cannnot allocate crypt track, skipping\n"));
86 			return;
87 		}
88 		//by default track is encrypted
89 		tkc->IsEncrypted = 1;
90 		tkc->sai_saved_box_type = GF_ISOM_BOX_TYPE_SENC;
91 		tkc->scheme_type = info->def_crypt_type;
92 		gf_list_add(info->tcis, tkc);
93 
94 		for (i=0; i<nb_attributes; i++) {
95 			att = (GF_XMLAttribute *) &attributes[i];
96 			if (!stricmp(att->name, "trackID") || !stricmp(att->name, "ID")) {
97 				if (!strcmp(att->value, "*")) info->has_common_key = 1;
98 				else {
99 					tkc->trackID = atoi(att->value);
100 					has_common_key = GF_FALSE;
101 				}
102 			}
103 			else if (!stricmp(att->name, "type")) {
104 				tkc->scheme_type = cryptinfo_get_crypt_type(att->value);
105 			}
106 			else if (!stricmp(att->name, "forceType")) {
107 				tkc->force_type = GF_TRUE;
108 			}
109 			else if (!stricmp(att->name, "key")) {
110 				GF_Err e;
111 				if (!tkc->keys) {
112 					tkc->KID_count = 1;
113 					tkc->keys = gf_malloc(sizeof(bin128));
114 				}
115 				e = gf_bin128_parse(att->value, tkc->keys[0] );
116                 if (e != GF_OK) {
117                     GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannnot parse key value in CrypTrack\n"));
118                     return;
119                 }
120 			}
121 			else if (!stricmp(att->name, "salt")) {
122 				u32 len, j;
123 				char *sKey = att->value;
124 				if (!strnicmp(sKey, "0x", 2)) sKey += 2;
125 				len = (u32) strlen(sKey);
126 				for (j=0; j<len; j+=2) {
127 					char szV[5];
128 					u32 v;
129 					sprintf(szV, "%c%c", sKey[j], sKey[j+1]);
130 					sscanf(szV, "%x", &v);
131 					tkc->first_IV[j/2] = v;
132 					if (j>=30) break;
133 				}
134 			}
135 			else if (!stricmp(att->name, "kms_URI") || !stricmp(att->name, "rightsIssuerURL")) {
136 				if (tkc->KMS_URI) gf_free(tkc->KMS_URI);
137 				tkc->KMS_URI = gf_strdup(att->value);
138 			}
139 			else if (!stricmp(att->name, "scheme_URI") || !stricmp(att->name, "contentID")) {
140 				if (tkc->Scheme_URI) gf_free(tkc->Scheme_URI);
141 				tkc->Scheme_URI = gf_strdup(att->value);
142 			}
143 			else if (!stricmp(att->name, "selectiveType")) {
144 				if (!stricmp(att->value, "Rap")) tkc->sel_enc_type = GF_CRYPT_SELENC_RAP;
145 				else if (!stricmp(att->value, "Non-Rap")) tkc->sel_enc_type = GF_CRYPT_SELENC_NON_RAP;
146 				else if (!stricmp(att->value, "Rand")) tkc->sel_enc_type = GF_CRYPT_SELENC_RAND;
147 				else if (!strnicmp(att->value, "Rand", 4)) {
148 					tkc->sel_enc_type = GF_CRYPT_SELENC_RAND_RANGE;
149 					tkc->sel_enc_range = atoi(&att->value[4]);
150 				}
151 				else if (sscanf(att->value, "%u", &tkc->sel_enc_range)==1) {
152 					if (tkc->sel_enc_range==1) tkc->sel_enc_range = 0;
153 					else tkc->sel_enc_type = GF_CRYPT_SELENC_RANGE;
154 				}
155 				else if (!strnicmp(att->value, "Preview", 7)) {
156 					tkc->sel_enc_type = GF_CRYPT_SELENC_PREVIEW;
157 				}
158 				else if (!strnicmp(att->value, "Clear", 5)) {
159 					tkc->sel_enc_type = GF_CRYPT_SELENC_CLEAR;
160 				}
161 				else if (!strnicmp(att->value, "ForceClear", 10)) {
162 					char *sep = strchr(att->value, '=');
163 					if (sep) tkc->sel_enc_range = atoi(sep+1);
164 					tkc->sel_enc_type = GF_CRYPT_SELENC_CLEAR_FORCED;
165 				}
166 				else if (!stricmp(att->value, "None")) {
167 				} else {
168 					GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized selective mode %s, ignoring\n", att->value));
169 				}
170 			}
171 			else if (!stricmp(att->name, "clearStsd")) {
172 				if (!strcmp(att->value, "none")) tkc->force_clear_stsd_idx = 0;
173 				else if (!strcmp(att->value, "before")) tkc->force_clear_stsd_idx = 1;
174 				else if (!strcmp(att->value, "after")) tkc->force_clear_stsd_idx = 2;
175 				else {
176 					GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized clear stsd type %s, defaulting to no stsd for clear samples\n", att->value));
177 				}
178 			}
179 			else if (!stricmp(att->name, "Preview")) {
180 				tkc->sel_enc_type = GF_CRYPT_SELENC_PREVIEW;
181 				sscanf(att->value, "%u", &tkc->sel_enc_range);
182 			}
183 			else if (!stricmp(att->name, "ipmpType")) {
184 				if (!stricmp(att->value, "None")) tkc->ipmp_type = 0;
185 				else if (!stricmp(att->value, "IPMP")) tkc->sel_enc_type = 1;
186 				else if (!stricmp(att->value, "IPMPX")) tkc->sel_enc_type = 2;
187 			}
188 			else if (!stricmp(att->name, "ipmpDescriptorID")) tkc->ipmp_desc_id = atoi(att->value);
189 			else if (!stricmp(att->name, "encryptionMethod")) {
190 				if (!strcmp(att->value, "AES_128_CBC")) tkc->encryption = 1;
191 				else if (!strcmp(att->value, "None")) tkc->encryption = 0;
192 				else if (!strcmp(att->value, "AES_128_CTR") || !strcmp(att->value, "default")) tkc->encryption = 2;
193 				else {
194 					GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized encryption algo %s, ignoring\n", att->value));
195 				}
196 			}
197 			else if (!stricmp(att->name, "transactionID")) {
198 				if (strlen(att->value)<=16) strcpy(tkc->TransactionID, att->value);
199 			}
200 			else if (!stricmp(att->name, "textualHeaders")) {
201 			}
202 			else if (!stricmp(att->name, "IsEncrypted")) {
203 				if (!stricmp(att->value, "1"))
204 					tkc->IsEncrypted = 1;
205 				else
206 					tkc->IsEncrypted = 0;
207 			}
208 			else if (!stricmp(att->name, "IV_size")) {
209 				tkc->IV_size = atoi(att->value);
210 			}
211 			else if (!stricmp(att->name, "first_IV")) {
212 				char *sKey = att->value;
213 				if (!strnicmp(sKey, "0x", 2)) sKey += 2;
214 				if ((strlen(sKey) == 16) || (strlen(sKey) == 32)) {
215 					u32 j;
216 					for (j=0; j<strlen(sKey); j+=2) {
217 						u32 v;
218 						char szV[5];
219 						sprintf(szV, "%c%c", sKey[j], sKey[j+1]);
220 						sscanf(szV, "%x", &v);
221 						tkc->first_IV[j/2] = v;
222 					}
223 					if (!tkc->IV_size) tkc->IV_size = (u8) strlen(sKey) / 2;
224 				}
225 			}
226 			else if (!stricmp(att->name, "saiSavedBox")) {
227 				if (!stricmp(att->value, "uuid_psec")) tkc->sai_saved_box_type = GF_ISOM_BOX_UUID_PSEC;
228 				else if (!stricmp(att->value, "senc")) tkc->sai_saved_box_type = GF_ISOM_BOX_TYPE_SENC;
229 				else {
230 					GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized SAI location %s, ignoring\n", att->value));
231 				}
232 			}
233 			else if (!stricmp(att->name, "keyRoll")) {
234 				if (!strncmp(att->value, "idx=", 4))
235 					tkc->defaultKeyIdx = atoi(att->value+4);
236 				else if (!strncmp(att->value, "roll=", 5))
237 					tkc->keyRoll = atoi(att->value+5);
238 				else {
239 					GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Unrecognized roll parameter %s, ignoring\n", att->value));
240 				}
241 			}
242 			else if (!stricmp(att->name, "metadata")) {
243 				u32 l = 2 * (u32) strlen(att->value);
244 				tkc->metadata = gf_malloc(sizeof(char) * l);
245 				l = gf_base64_encode(att->value, (u32) strlen(att->value), tkc->metadata, l);
246 				tkc->metadata[l] = 0;
247 			}
248 			else if (!stricmp(att->name, "crypt_byte_block")) {
249 				tkc->crypt_byte_block = atoi(att->value);
250 			}
251 			else if (!stricmp(att->name, "skip_byte_block")) {
252 				tkc->skip_byte_block = atoi(att->value);
253 			}
254 			else if (!stricmp(att->name, "clear_bytes")) {
255 				tkc->clear_bytes = atoi(att->value);
256 			}
257 			else if (!stricmp(att->name, "constant_IV_size")) {
258 				tkc->constant_IV_size = atoi(att->value);
259 				assert((tkc->constant_IV_size == 8) || (tkc->constant_IV_size == 16));
260 			}
261 			else if (!stricmp(att->name, "constant_IV")) {
262 				char *sKey = att->value;
263 				if (!strnicmp(sKey, "0x", 2)) sKey += 2;
264 				if ((strlen(sKey) == 16) || (strlen(sKey) == 32)) {
265 					u32 j;
266 					for (j=0; j<strlen(sKey); j+=2) {
267 						u32 v;
268 						char szV[5];
269 						sprintf(szV, "%c%c", sKey[j], sKey[j+1]);
270 						sscanf(szV, "%x", &v);
271 						tkc->constant_IV[j/2] = v;
272 					}
273 				}
274 				if (!tkc->constant_IV_size) tkc->constant_IV_size = (u8) strlen(sKey) / 2;
275 			}
276 			else if (!stricmp(att->name, "encryptSliceHeader")) {
277 				tkc->allow_encrypted_slice_header = !strcmp(att->value, "yes") ? GF_TRUE : GF_FALSE;
278 			}
279 			else if (!stricmp(att->name, "blockAlign")) {
280 				if (!strcmp(att->value, "disable")) tkc->block_align = 1;
281 				else if (!strcmp(att->value, "always")) tkc->block_align = 2;
282 				else tkc->block_align = 0;
283 			}
284 		}
285 		if (tkc->scheme_type==GF_CRYPT_TYPE_PIFF) {
286 			tkc->sai_saved_box_type = GF_ISOM_BOX_UUID_PSEC;
287 		}
288 		if (has_common_key) info->has_common_key = 1;
289 
290 		if ((tkc->IV_size != 0) && (tkc->IV_size != 8) && (tkc->IV_size != 16)) {
291 			GF_LOG(GF_LOG_WARNING, GF_LOG_AUTHOR, ("[CENC] wrong IV size %d for AES-128, using 16\n", (u32) tkc->IV_size));
292 			tkc->IV_size = 16;
293 		}
294 
295 		if ((tkc->scheme_type == GF_CRYPT_TYPE_CENC) || (tkc->scheme_type == GF_CRYPT_TYPE_CBC1)) {
296 			if (tkc->crypt_byte_block || tkc->skip_byte_block) {
297 				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) ));
298 				tkc->crypt_byte_block = tkc->skip_byte_block = 0;
299 			}
300 		}
301 
302 		if ((tkc->scheme_type == GF_CRYPT_TYPE_CENC) || (tkc->scheme_type == GF_CRYPT_TYPE_CBC1) || (tkc->scheme_type == GF_CRYPT_TYPE_CENS)) {
303 			if (tkc->constant_IV_size) {
304 				if (!tkc->IV_size) {
305 					tkc->IV_size = tkc->constant_IV_size;
306 					memcpy(tkc->first_IV, tkc->constant_IV, 16);
307 					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)));
308 					tkc->constant_IV_size = 0;
309 				} else {
310 					tkc->constant_IV_size = 0;
311 					memset(tkc->constant_IV, 0, 16);
312 					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)));
313 				}
314 			}
315 		}
316 		if (tkc->scheme_type == GF_ISOM_OMADRM_SCHEME) {
317 			/*default to AES 128 in OMA*/
318 			tkc->encryption = 2;
319 		}
320 
321 	}
322 
323 	if (!strcmp(node_name, "key")) {
324 		tkc = (GF_TrackCryptInfo *)gf_list_last(info->tcis);
325 		tkc->KIDs = (bin128 *)gf_realloc(tkc->KIDs, sizeof(bin128)*(tkc->KID_count+1));
326 		tkc->keys = (bin128 *)gf_realloc(tkc->keys, sizeof(bin128)*(tkc->KID_count+1));
327 
328 		for (i=0; i<nb_attributes; i++) {
329 			att = (GF_XMLAttribute *) &attributes[i];
330 
331 			if (!stricmp(att->name, "KID")) {
332 				GF_Err e = gf_bin128_parse(att->value, tkc->KIDs[tkc->KID_count]);
333                 if (e != GF_OK) {
334                     GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannnot parse KID\n"));
335                     return;
336                 }
337 			}
338 			else if (!stricmp(att->name, "value")) {
339 				GF_Err e = gf_bin128_parse(att->value, tkc->keys[tkc->KID_count]);
340                 if (e != GF_OK) {
341                     GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannnot parse key value\n"));
342                     return;
343                 }
344 			}
345 		}
346 		tkc->KID_count++;
347 	}
348 }
349 
cryptinfo_node_end(void * sax_cbck,const char * node_name,const char * name_space)350 static void cryptinfo_node_end(void *sax_cbck, const char *node_name, const char *name_space)
351 {
352 	GF_CryptInfo *info = (GF_CryptInfo *)sax_cbck;
353 	if (!strcmp(node_name, "OMATextHeader")) {
354 		info->in_text_header = 0;
355 		return;
356 	}
357 }
358 
cryptinfo_text(void * sax_cbck,const char * text,Bool is_cdata)359 static void cryptinfo_text(void *sax_cbck, const char *text, Bool is_cdata)
360 {
361 	u32 len, len2;
362 	GF_TrackCryptInfo *tkc;
363 	GF_CryptInfo *info = (GF_CryptInfo *)sax_cbck;
364 
365 	if (!info->in_text_header) return;
366 
367 	tkc = (GF_TrackCryptInfo *) gf_list_last(info->tcis);
368 	len = (u32) strlen(text);
369 	len2 = tkc->TextualHeaders ? (u32) strlen(tkc->TextualHeaders) : 0;
370 
371 	tkc->TextualHeaders = gf_realloc(tkc->TextualHeaders, sizeof(char) * (len+len2+1));
372 	if (!len2) strcpy(tkc->TextualHeaders, "");
373 	strcat(tkc->TextualHeaders, text);
374 }
375 
gf_crypt_info_del(GF_CryptInfo * info)376 void gf_crypt_info_del(GF_CryptInfo *info)
377 {
378 	while (gf_list_count(info->tcis)) {
379 		GF_TrackCryptInfo *tci = (GF_TrackCryptInfo *)gf_list_last(info->tcis);
380 		if (tci->KIDs) gf_free(tci->KIDs);
381 		if (tci->keys) gf_free(tci->keys);
382 		if (tci->metadata) gf_free(tci->metadata);
383 		if (tci->KMS_URI) gf_free(tci->KMS_URI);
384 		if (tci->Scheme_URI) gf_free(tci->Scheme_URI);
385 		if (tci->TextualHeaders) gf_free(tci->TextualHeaders);
386 		gf_list_rem_last(info->tcis);
387 		gf_free(tci);
388 	}
389 	gf_list_del(info->tcis);
390 	gf_free(info);
391 }
392 
gf_crypt_info_load(const char * file,GF_Err * out_err)393 GF_CryptInfo *gf_crypt_info_load(const char *file, GF_Err *out_err)
394 {
395 	GF_Err e;
396 	GF_CryptInfo *info;
397 	GF_SAXParser *sax;
398 	GF_SAFEALLOC(info, GF_CryptInfo);
399 	if (!info) {
400 		if (out_err) *out_err = GF_OUT_OF_MEM;
401 		return NULL;
402 	}
403 	info->tcis = gf_list_new();
404 	sax = gf_xml_sax_new(cryptinfo_node_start, cryptinfo_node_end, cryptinfo_text, info);
405 	e = gf_xml_sax_parse_file(sax, file, NULL);
406 	if (e<0) {
407 		GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[DRM] Failed to parse DRM config file: %s", gf_xml_sax_get_error(sax) ));
408 		if (out_err) *out_err = e;
409 		gf_crypt_info_del(info);
410 		info = NULL;
411 	} else {
412 		if (out_err) *out_err = GF_OK;
413 	}
414 	gf_xml_sax_del(sax);
415 	return info;
416 }
417 
on_decrypt_event(void * _udta,GF_Event * evt)418 static Bool on_decrypt_event(void *_udta, GF_Event *evt)
419 {
420 	Double progress;
421 	u32 *prev_progress = (u32 *)_udta;
422 	if (!_udta) return GF_FALSE;
423 	if (evt->type != GF_EVENT_PROGRESS) return GF_FALSE;
424 	if (!evt->progress.total) return GF_FALSE;
425 
426 	progress = (Double) (100*evt->progress.done) / evt->progress.total;
427 	if ((u32) progress==*prev_progress)
428 		return GF_FALSE;
429 
430 	*prev_progress = (u32) progress;
431 #ifndef GPAC_DISABLE_LOG
432 	GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Decrypting: % 2.2f %%\r", progress));
433 #else
434 	fprintf(stderr, "Decrypting: % 2.2f %%\r", progress);
435 #endif
436 	return GF_FALSE;
437 }
438 
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)439 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)
440 {
441 	char szArgs[4096];
442 	GF_Filter *src, *dst, *dcrypt;
443 	GF_FilterSession *fsess;
444 	GF_Err e = GF_OK;
445 	u32 progress = (u32) -1;
446 
447 	fsess = gf_fs_new_defaults(0);
448 	if (!fsess) {
449 		GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Failed to create filter session\n"));
450 		return GF_OUT_OF_MEM;
451 	}
452 	sprintf(szArgs, "mp4dmx:mov=%p", mp4);
453 	if (fragment_name) {
454 		strcat(szArgs, ":sigfrag:catseg=");
455 		strcat(szArgs, fragment_name);
456 	}
457 	src = gf_fs_load_filter(fsess, szArgs, &e);
458 	if (!src) {
459 		gf_fs_del(fsess);
460 		GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Cannot load demux filter for source file\n"));
461 		return e;
462 	}
463 
464 	sprintf(szArgs, "cdcrypt:FID=1:cfile=%s", drm_file);
465 	dcrypt = gf_fs_load_filter(fsess, szArgs, &e);
466 	if (!dcrypt) {
467 		gf_fs_del(fsess);
468 		GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Cannot load decryptor filter\n"));
469 		return e;
470 	}
471 
472 	sprintf(szArgs, "SID=1");
473 	if (fragment_name) {
474 		strcat(szArgs, ":sseg:noinit:store=frag:cdur=1000000000");
475 	} else {
476 		if (interleave_time) {
477 			char an_arg[100];
478 			sprintf(an_arg, ":cdur=%g", interleave_time);
479 			strcat(szArgs, an_arg);
480 		} else {
481 			strcat(szArgs, ":store=flat");
482 		}
483 	}
484 
485 	dst = gf_fs_load_destination(fsess, dst_file, szArgs, NULL, &e);
486 	if (!dst) {
487 		gf_fs_del(fsess);
488 		GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Decrypter] Cannot load destination muxer\n"));
489 		return GF_FILTER_NOT_FOUND;
490 	}
491 
492 	if (!gf_sys_is_test_mode()
493 #ifndef GPAC_DISABLE_LOG
494 		&& (gf_log_get_tool_level(GF_LOG_APP)!=GF_LOG_QUIET)
495 #endif
496 		&& !gf_sys_is_quiet()
497 	) {
498 		gf_fs_enable_reporting(fsess, GF_TRUE);
499 		gf_fs_set_ui_callback(fsess, on_decrypt_event, &progress);
500 	}
501 #ifdef GPAC_ENABLE_COVERAGE
502 	else if (gf_sys_is_cov_mode()) {
503 		on_decrypt_event(NULL, NULL);
504 	}
505 #endif //GPAC_ENABLE_COVERAGE
506 
507 	e = gf_fs_run(fsess);
508 	if (e>GF_OK) e = GF_OK;
509 	if (!e) e = gf_fs_get_last_connect_error(fsess);
510 	if (!e) e = gf_fs_get_last_process_error(fsess);
511 
512 	if (fs_dump_flags & 1) gf_fs_print_stats(fsess);
513 	if (fs_dump_flags & 2) gf_fs_print_connections(fsess);
514 
515 	gf_fs_del(fsess);
516 	return e;
517 }
518 
519 GF_EXPORT
gf_decrypt_fragment(GF_ISOFile * mp4,const char * drm_file,const char * dst_file,const char * fragment_name,u32 fs_dump_flags)520 GF_Err gf_decrypt_fragment(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, const char *fragment_name, u32 fs_dump_flags)
521 {
522 	return gf_decrypt_file_ex(mp4, drm_file, dst_file, 0, fragment_name, fs_dump_flags);
523 }
524 GF_EXPORT
gf_decrypt_file(GF_ISOFile * mp4,const char * drm_file,const char * dst_file,Double interleave_time,u32 fs_dump_flags)525 GF_Err gf_decrypt_file(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, u32 fs_dump_flags)
526 {
527 	return gf_decrypt_file_ex(mp4, drm_file, dst_file, interleave_time, NULL, fs_dump_flags);
528 }
on_crypt_event(void * _udta,GF_Event * evt)529 static Bool on_crypt_event(void *_udta, GF_Event *evt)
530 {
531 	Double progress;
532 	u32 *prev_progress = (u32 *)_udta;
533 	if (!_udta) return GF_FALSE;
534 	if (evt->type != GF_EVENT_PROGRESS) return GF_FALSE;
535 	if (!evt->progress.total) return GF_FALSE;
536 
537 	progress = (Double) (100*evt->progress.done) / evt->progress.total;
538 	if ((u32) progress==*prev_progress)
539 		return GF_FALSE;
540 
541 	*prev_progress = (u32) progress;
542 #ifndef GPAC_DISABLE_LOG
543 	GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("Encrypting: % 2.2f %%\r", progress));
544 #else
545 	fprintf(stderr, "Encrypting: % 2.2f %%\r", progress);
546 #endif
547 	return GF_FALSE;
548 }
549 
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)550 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)
551 {
552 	char *szArgs=NULL;
553 	char an_arg[100];
554 	char *arg_dst=NULL;
555 	u32 progress = (u32) -1;
556 	GF_Filter *src, *dst, *crypt;
557 	GF_FilterSession *fsess;
558 	GF_Err e = GF_OK;
559 
560 	fsess = gf_fs_new_defaults(0);
561 	if (!fsess) {
562 		GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Failed to create filter session\n"));
563 		return GF_OUT_OF_MEM;
564 	}
565 
566 	sprintf(an_arg, "mp4dmx:mov=%p", mp4);
567 	gf_dynstrcat(&szArgs, an_arg, NULL);
568 	if (fragment_name) {
569 		gf_dynstrcat(&szArgs, ":sigfrag:catseg=", NULL);
570 		gf_dynstrcat(&szArgs, fragment_name, NULL);
571 	}
572 	src = gf_fs_load_filter(fsess, szArgs, &e);
573 
574 	gf_free(szArgs);
575 	szArgs = NULL;
576 
577 	if (!src) {
578 		gf_fs_del(fsess);
579 		GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Cannot load demux for source file: %s\n", gf_error_to_string(e)));
580 		return e;
581 	}
582 
583 	gf_dynstrcat(&szArgs, "cecrypt:FID=1:cfile=", NULL);
584 	gf_dynstrcat(&szArgs, drm_file, NULL);
585 	crypt = gf_fs_load_filter(fsess, szArgs, &e);
586 
587 	gf_free(szArgs);
588 	szArgs = NULL;
589 
590 	if (!crypt) {
591 		gf_fs_del(fsess);
592 		GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Cannot load encryptor: %s\n", gf_error_to_string(e) ));
593 		return e;
594 	}
595 
596 	gf_dynstrcat(&szArgs, "SID=1", NULL);
597 	if (fragment_name) {
598 		gf_dynstrcat(&szArgs, ":sseg:noinit:store=frag:cdur=1000000000", NULL);
599 	} else {
600 		if (interleave_time) {
601 			sprintf(an_arg, ":cdur=%g", interleave_time);
602 			gf_dynstrcat(&szArgs, an_arg, NULL);
603 		} else {
604 			gf_dynstrcat(&szArgs, ":store=flat", NULL);
605 		}
606 	}
607 
608 	arg_dst = gf_url_colon_suffix(dst_file);
609 	if (arg_dst) {
610 		gf_dynstrcat(&szArgs, arg_dst, NULL);
611 		arg_dst[0]=0;
612 	}
613 	dst = gf_fs_load_destination(fsess, dst_file, szArgs, NULL, &e);
614 
615 	gf_free(szArgs);
616 	szArgs = NULL;
617 	if (!dst) {
618 		gf_fs_del(fsess);
619 		GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[Encrypter] Cannot load destination muxer\n"));
620 		return GF_FILTER_NOT_FOUND;
621 	}
622 
623 	if (!gf_sys_is_test_mode()
624 #ifndef GPAC_DISABLE_LOG
625 		&& (gf_log_get_tool_level(GF_LOG_APP)!=GF_LOG_QUIET)
626 #endif
627 		&& !gf_sys_is_quiet()
628 	) {
629 		gf_fs_enable_reporting(fsess, GF_TRUE);
630 		gf_fs_set_ui_callback(fsess, on_crypt_event, &progress);
631 	}
632 #ifdef GPAC_ENABLE_COVERAGE
633 	else if (gf_sys_is_cov_mode()) {
634 		on_crypt_event(NULL, NULL);
635 	}
636 #endif //GPAC_ENABLE_COVERAGE
637 	e = gf_fs_run(fsess);
638 	if (e>GF_OK) e = GF_OK;
639 	if (!e) e = gf_fs_get_last_connect_error(fsess);
640 	if (!e) e = gf_fs_get_last_process_error(fsess);
641 
642 	if (fs_dump_flags & 1) gf_fs_print_stats(fsess);
643 	if (fs_dump_flags & 2) gf_fs_print_connections(fsess);
644 	gf_fs_del(fsess);
645 	return e;
646 }
647 
648 GF_EXPORT
gf_crypt_fragment(GF_ISOFile * mp4,const char * drm_file,const char * dst_file,const char * fragment_name,u32 fs_dump_flags)649 GF_Err gf_crypt_fragment(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, const char *fragment_name, u32 fs_dump_flags)
650 {
651 	return gf_crypt_file_ex(mp4, drm_file, dst_file, 0, fragment_name, fs_dump_flags);
652 }
653 
654 GF_EXPORT
gf_crypt_file(GF_ISOFile * mp4,const char * drm_file,const char * dst_file,Double interleave_time,u32 fs_dump_flags)655 GF_Err gf_crypt_file(GF_ISOFile *mp4, const char *drm_file, const char *dst_file, Double interleave_time, u32 fs_dump_flags)
656 {
657 	return gf_crypt_file_ex(mp4, drm_file, dst_file, interleave_time, NULL, fs_dump_flags);
658 
659 }
660 #endif /* !defined(GPAC_DISABLE_ISOM_WRITE)*/
661 
662