Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / file crypt/decrypt for full segment encryption filter
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 : #include <gpac/filters.h>
28 : #include <gpac/constants.h>
29 : #include <gpac/download.h>
30 : #include <gpac/crypt.h>
31 : #include <gpac/network.h>
32 :
33 : enum
34 : {
35 : KEY_STATE_NONE=0,
36 : KEY_STATE_CHANGED,
37 : KEY_STATE_DOWNLOADING,
38 : KEY_STATE_SET_IV,
39 : };
40 :
41 : typedef struct
42 : {
43 : Bool do_crypt;
44 : bin128 key;
45 : bin128 iv;
46 : } KeyInfo;
47 :
48 :
49 : typedef struct
50 : {
51 : //options
52 : char *src, *dst;
53 : Bool fullfile;
54 :
55 : GF_FilterPid *ipid, *opid;
56 : GF_Filter *for_filter;
57 :
58 : u32 reload_key_state;
59 : char *key_url;
60 : bin128 IV;
61 :
62 : GF_DownloadSession *key_sess;
63 : GF_Err in_error;
64 :
65 : u8 key_data[20];
66 : u32 key_size;
67 : GF_Crypt *crypt;
68 :
69 : u8 store[16];
70 : u32 remain;
71 :
72 : bin128 last_key;
73 : Bool use_key;
74 : Bool file_done;
75 : GF_List *keys;
76 : } GF_CryptFileCtx;
77 :
78 0 : static GF_Err cryptfile_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
79 : {
80 0 : GF_CryptFileCtx *ctx = (GF_CryptFileCtx *) gf_filter_get_udta(filter);
81 :
82 0 : if (is_remove) {
83 0 : if (ctx->opid) gf_filter_pid_set_eos(ctx->opid);
84 : return GF_OK;
85 : }
86 0 : if (!ctx->opid)
87 0 : ctx->opid = gf_filter_pid_new(filter);
88 0 : ctx->ipid = pid;
89 0 : gf_filter_pid_copy_properties(ctx->opid, pid);
90 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_ORIG_STREAM_TYPE, NULL);
91 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_STREAM_TYPE, &PROP_UINT(GF_STREAM_FILE));
92 : //the output file is no longer cached
93 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILE_CACHED, NULL);
94 0 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_FILEPATH, NULL);
95 :
96 0 : if (ctx->fullfile)
97 0 : gf_filter_pid_set_framing_mode(pid, GF_TRUE);
98 : return GF_OK;
99 : }
100 :
101 : const char *gf_filter_get_src_args(GF_Filter *filter);
102 :
103 0 : static void cryptfile_on_filter_setup_error(GF_Filter *failed_filter, void *udta, GF_Err err)
104 : {
105 : GF_Filter *f = (GF_Filter *)udta;
106 0 : if (!udta) return;
107 : //forward setup failure
108 0 : gf_filter_setup_failure(f, err);
109 : }
110 :
111 0 : static GF_Err cryptfin_initialize(GF_Filter *filter)
112 : {
113 : GF_Err e;
114 : const char *args;
115 0 : GF_CryptFileCtx *ctx = (GF_CryptFileCtx *) gf_filter_get_udta(filter);
116 0 : if (!ctx || !ctx->src) return GF_BAD_PARAM;
117 :
118 0 : if (strncmp(ctx->src, "gcryp://", 8)) return GF_BAD_PARAM;
119 : //get complete args of filter, strip anything up to (including) gcryp://
120 0 : args = gf_filter_get_src_args(filter);
121 0 : if (args) args = strstr(args, "gcryp://");
122 0 : if (args) args += 8;
123 0 : else args = ctx->src+8;
124 :
125 0 : ctx->for_filter = gf_filter_connect_source(filter, args, NULL, GF_FALSE, &e);
126 0 : if (e) return e;
127 0 : gf_filter_set_setup_failure_callback(filter, ctx->for_filter, cryptfile_on_filter_setup_error, filter);
128 0 : return gf_filter_set_source(filter, ctx->for_filter, NULL);
129 : }
130 :
131 0 : static void cryptfile_finalize(GF_Filter *filter)
132 : {
133 0 : GF_CryptFileCtx *ctx = (GF_CryptFileCtx *) gf_filter_get_udta(filter);
134 0 : if (ctx->crypt) gf_crypt_close(ctx->crypt);
135 0 : if (ctx->key_url) gf_free(ctx->key_url);
136 :
137 0 : if (ctx->keys) {
138 0 : while (gf_list_count(ctx->keys)) {
139 0 : KeyInfo *ki = gf_list_pop_front(ctx->keys);
140 0 : gf_free(ki);
141 : }
142 0 : gf_list_del(ctx->keys);
143 : }
144 0 : }
145 :
146 5137 : static GF_FilterProbeScore cryptfile_probe_url(const char *url, const char *mime_type)
147 : {
148 5137 : if (!strnicmp(url, "gcryp://", 8)) return GF_FPROBE_SUPPORTED;
149 5137 : return GF_FPROBE_NOT_SUPPORTED;
150 : }
151 :
152 0 : static void cryptfile_set_key(GF_CryptFileCtx *ctx)
153 : {
154 0 : if (!ctx->crypt) {
155 0 : ctx->crypt = gf_crypt_open(GF_AES_128, GF_CBC);
156 0 : if (!ctx->crypt) {
157 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[CryptFile] Failed to allocat decryptor\n"))
158 0 : ctx->in_error = GF_OUT_OF_MEM;
159 0 : return;
160 : }
161 0 : ctx->in_error = gf_crypt_init(ctx->crypt, ctx->key_data, ctx->IV);
162 : } else {
163 0 : ctx->in_error = gf_crypt_set_key(ctx->crypt, ctx->key_data);
164 0 : if (!ctx->in_error)
165 0 : ctx->in_error = gf_crypt_set_IV(ctx->crypt, ctx->IV, 16);
166 : }
167 0 : ctx->reload_key_state = KEY_STATE_NONE;
168 : }
169 :
170 0 : static GF_Err cryptfin_process(GF_Filter *filter)
171 : {
172 : GF_Err e;
173 : u32 size, osize, unused;
174 : const u8 *data;
175 : Bool start, end;
176 : u8 *output, pad;
177 : GF_FilterPacket *pck, *pck_out;
178 0 : GF_CryptFileCtx *ctx = (GF_CryptFileCtx *) gf_filter_get_udta(filter);
179 :
180 0 : if (ctx->in_error) return ctx->in_error;
181 :
182 0 : if (!ctx->ipid) return GF_OK;
183 0 : pck = gf_filter_pid_get_packet(ctx->ipid);
184 0 : if (!pck) {
185 0 : if (gf_filter_pid_is_eos(ctx->ipid)) {
186 0 : gf_filter_pid_set_eos(ctx->opid);
187 0 : return GF_EOS;
188 : }
189 : return GF_OK;
190 : }
191 :
192 0 : if (!ctx->key_url) {
193 0 : gf_filter_pck_forward(pck, ctx->opid);
194 0 : gf_filter_pid_drop_packet(ctx->ipid);
195 0 : return GF_OK;
196 : }
197 :
198 0 : if (ctx->reload_key_state) {
199 0 : if (ctx->reload_key_state==KEY_STATE_CHANGED) {
200 0 : if (!ctx->key_sess) {
201 0 : GF_DownloadManager *dm = gf_filter_get_download_manager(filter);
202 0 : ctx->key_sess = gf_dm_sess_new(dm, ctx->key_url, GF_NETIO_SESSION_NOT_THREADED | GF_NETIO_SESSION_NOT_CACHED, NULL, NULL, &e);
203 : } else {
204 0 : e = gf_dm_sess_setup_from_url(ctx->key_sess, ctx->key_url, GF_TRUE);
205 : }
206 0 : if (e) {
207 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[CryptFile] Failed to setup download session for key %s: %s\n", ctx->key_url, gf_error_to_string(e)))
208 0 : return ctx->in_error = e;
209 : }
210 0 : ctx->reload_key_state = KEY_STATE_DOWNLOADING;
211 : }
212 0 : if (ctx->reload_key_state==KEY_STATE_DOWNLOADING) {
213 : u32 nb_read;
214 0 : e = gf_dm_sess_fetch_data(ctx->key_sess, ctx->key_data + ctx->key_size, 100-ctx->key_size, &nb_read);
215 0 : ctx->key_size += nb_read;
216 0 : if (ctx->key_size > 16) {
217 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[CryptFile] Invalid key size, greater than 16 bytes\n"))
218 0 : return ctx->in_error = GF_SERVICE_ERROR;
219 : }
220 :
221 0 : if ((e<0) && (e != GF_IP_NETWORK_EMPTY)) {
222 0 : ctx->in_error = e;
223 0 : ctx->reload_key_state = KEY_STATE_NONE;
224 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[CryptFile] Failed to download key %s: %s\n", ctx->key_url, gf_error_to_string(e)))
225 0 : return e;
226 : }
227 0 : if (e == GF_EOS) {
228 0 : cryptfile_set_key(ctx);
229 0 : if (ctx->in_error) return ctx->in_error;
230 : } else {
231 : return GF_OK;
232 : }
233 : }
234 0 : if (ctx->reload_key_state == KEY_STATE_SET_IV) {
235 0 : gf_crypt_set_IV(ctx->crypt, ctx->IV, 16);
236 0 : ctx->reload_key_state = KEY_STATE_NONE;
237 : }
238 : }
239 :
240 0 : if (ctx->fullfile) {
241 :
242 0 : gf_filter_pck_get_data(pck, &size);
243 0 : pck_out = gf_filter_pck_new_clone(ctx->opid, pck, &output);
244 0 : if (!pck_out) return GF_OUT_OF_MEM;
245 :
246 0 : e = gf_crypt_decrypt(ctx->crypt, output, size);
247 0 : pad = output[size-1];
248 0 : if (!pad || (pad>16)) {
249 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[CryptFile] Invalid PKCS7 padding %d, should be in range [1,16]\n", pad))
250 0 : if (pad) pad = 16;
251 : }
252 0 : size -= pad;
253 0 : gf_filter_pck_truncate(pck_out, size);
254 0 : gf_filter_pck_send(pck_out);
255 :
256 0 : gf_filter_pid_drop_packet(ctx->ipid);
257 0 : return e;
258 : }
259 0 : data = gf_filter_pck_get_data(pck, &size);
260 0 : gf_filter_pck_get_framing(pck, &start, &end);
261 :
262 0 : osize = size + ctx->remain;
263 : unused = 0;
264 0 : if (!end) {
265 0 : while (osize % 16) {
266 0 : osize --;
267 0 : unused++;
268 : }
269 : }
270 0 : pck_out = gf_filter_pck_new_alloc(ctx->opid, osize, &output);
271 0 : if (!pck_out) return GF_OUT_OF_MEM;
272 :
273 0 : if (ctx->remain)
274 0 : memcpy(output, ctx->store, ctx->remain);
275 0 : memcpy(output+ctx->remain, data, osize - ctx->remain);
276 0 : e = gf_crypt_decrypt(ctx->crypt, output, osize);
277 0 : gf_filter_pck_merge_properties(pck, pck_out);
278 0 : gf_filter_pck_set_framing(pck_out, start, end);
279 :
280 0 : if (unused) {
281 0 : memcpy(ctx->store, data + size - unused, unused);
282 : }
283 0 : ctx->remain = unused;
284 0 : if (end) {
285 0 : pad = output[osize-1];
286 0 : if (!pad || (pad>16)) {
287 0 : GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[CryptFile] Invalid PKCS7 padding %d, should be in range [1,16]\n", pad))
288 0 : if (pad) pad = 16;
289 : }
290 0 : osize -= pad;
291 0 : gf_filter_pck_truncate(pck_out, osize);
292 : }
293 0 : gf_filter_pck_send(pck_out);
294 0 : gf_filter_pid_drop_packet(ctx->ipid);
295 0 : return e;
296 : }
297 :
298 :
299 : #define OFFS(_n) #_n, offsetof(GF_CryptFileCtx, _n)
300 :
301 : static const GF_FilterArgs CryptFinArgs[] =
302 : {
303 : { OFFS(src), "location of source file", GF_PROP_NAME, NULL, NULL, 0},
304 : { OFFS(fullfile), "reassemble full file before decryption", GF_PROP_BOOL, "false", NULL, GF_ARG_HINT_ADVANCED},
305 : {0}
306 : };
307 :
308 : static const GF_FilterCapability CryptFileCaps[] =
309 : {
310 : CAP_UINT(GF_CAPS_INPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
311 : CAP_UINT(GF_CAPS_OUTPUT, GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
312 : };
313 :
314 : GF_FilterRegister CryptFinRegister = {
315 : .name = "cryptin",
316 : GF_FS_SET_DESCRIPTION("CryptFile input")
317 : GF_FS_SET_HELP("This filter dispatch raw blocks from encrypted files with AES 128 CBC in PKCS7 to clear input files\n"
318 : "\n"
319 : "The filter accepts URL with scheme `gcryp://URL`, where `URL` is the URL to decrypt.\n"
320 : "\n"
321 : "The filter can process http(s) and local file key URLs, and expects a full key (16 bytes) as result of resource fetching.\n"
322 : "The special URL `urn:gpac:keys:value:VALUE` can also be used, with `VALUE` containing the 16 bytes of the key in hexadecimal.\n"
323 : )
324 : .private_size = sizeof(GF_CryptFileCtx),
325 : .args = CryptFinArgs,
326 : .initialize = cryptfin_initialize,
327 : //GF_FS_REG_ACT_AS_SOURCE needed to prevent GF_FEVT_SOURCE_SWITCH to be canceled
328 : .flags = GF_FS_REG_EXPLICIT_ONLY | GF_FS_REG_ACT_AS_SOURCE,
329 : SETCAPS(CryptFileCaps),
330 : .finalize = cryptfile_finalize,
331 : .configure_pid = cryptfile_configure_pid,
332 : .process = cryptfin_process,
333 : .probe_url = cryptfile_probe_url
334 : };
335 :
336 :
337 2877 : const GF_FilterRegister *cryptfin_register(GF_FilterSession *session)
338 : {
339 2877 : return &CryptFinRegister;
340 : }
341 :
342 0 : void gf_cryptfin_set_kms(GF_Filter *filter, const char *key_url, bin128 key_IV)
343 : {
344 : GF_CryptFileCtx *ctx;
345 0 : if (!gf_filter_is_instance_of(filter, &CryptFinRegister))
346 : return;
347 0 : ctx = (GF_CryptFileCtx *) gf_filter_get_udta(filter);
348 :
349 : //copy IV
350 0 : memcpy(ctx->IV, key_IV, sizeof(bin128));
351 : //switch key if needed IV
352 0 : if (ctx->key_url && key_url && !strcmp(ctx->key_url, key_url)) {
353 0 : ctx->reload_key_state = KEY_STATE_SET_IV;
354 : } else {
355 0 : if (ctx->key_url) gf_free(ctx->key_url);
356 :
357 0 : if (!key_url) {
358 0 : ctx->key_url = NULL;
359 0 : return;
360 : }
361 0 : ctx->key_url = gf_strdup(key_url);
362 0 : if (!ctx->key_url) {
363 0 : ctx->in_error = GF_OUT_OF_MEM;
364 0 : return;
365 : }
366 0 : ctx->reload_key_state = KEY_STATE_CHANGED;
367 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[CryptFile] Switching key to %s\n", key_url))
368 :
369 0 : if (!strncmp(key_url, "urn:gpac:keys:value:", 20)) {
370 : u32 i;
371 : bin128 key_data;
372 0 : key_url += 20;
373 0 : if (!strncmp(key_url, "0x", 2)) key_url += 2;
374 0 : i = (u32) strlen(key_url);
375 0 : if (i != 32) {
376 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[CryptFile] key %s not found\n", key_url))
377 0 : ctx->in_error = GF_BAD_PARAM;
378 0 : return;
379 : }
380 0 : for (i=0; i<16; i++) {
381 : char szV[3];
382 : u32 v;
383 0 : szV[0] = key_url[2*i];
384 0 : szV[1] = key_url[2*i + 1];
385 0 : szV[2] = 0;
386 0 : sscanf(szV, "%X", &v);
387 0 : key_data[i] = v;
388 : }
389 0 : memcpy(ctx->key_data, key_data, sizeof(bin128));
390 0 : cryptfile_set_key(ctx);
391 : }
392 : //key is local, activate right away
393 0 : else if (gf_url_is_local(key_url)) {
394 0 : FILE *fkey = gf_fopen(key_url, "r");
395 0 : if (!fkey) {
396 0 : ctx->in_error = GF_URL_ERROR;
397 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[CryptFile] key %s not found\n", key_url))
398 : } else {
399 0 : u32 read = (u32) gf_fread(ctx->key_data, 16, fkey);
400 0 : if (read != 16) {
401 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[CryptFile] key %s too short, expecting 16 bytes got %d\n", key_url, read))
402 0 : ctx->in_error = GF_BAD_PARAM;
403 : } else {
404 0 : cryptfile_set_key(ctx);
405 : }
406 0 : gf_fclose(fkey);
407 : }
408 : }
409 : }
410 : }
411 :
412 :
413 : void gf_filter_mirror_forced_caps(GF_Filter *filter, GF_Filter *dst_filter);
414 :
415 0 : static GF_Err cryptfout_initialize(GF_Filter *filter)
416 : {
417 : GF_Err e;
418 : const char *args;
419 0 : GF_CryptFileCtx *ctx = (GF_CryptFileCtx *) gf_filter_get_udta(filter);
420 0 : if (!ctx || !ctx->dst) return GF_BAD_PARAM;
421 :
422 0 : if (strncmp(ctx->dst, "gcryp://", 8)) return GF_BAD_PARAM;
423 0 : ctx->keys = gf_list_new();
424 0 : if (!ctx->keys) return GF_OUT_OF_MEM;
425 :
426 : //get complete args of filter, strip anything up to (including) gcryp://
427 0 : args = gf_filter_get_src_args(filter);
428 0 : if (args) args = strstr(args, "gcryp://");
429 0 : if (args) args += 8;
430 0 : else args = ctx->dst+8;
431 :
432 0 : ctx->for_filter = gf_filter_connect_destination(filter, args, &e);
433 0 : if (e) return e;
434 0 : gf_filter_set_source(ctx->for_filter, filter, NULL);
435 : //use same forced cap as the solved destination
436 0 : gf_filter_mirror_forced_caps(filter, ctx->for_filter);
437 0 : ctx->file_done = GF_TRUE;
438 0 : return GF_OK;
439 : }
440 :
441 0 : static GF_Err cryptfout_process(GF_Filter *filter)
442 : {
443 : const u8 *data;
444 : u8 *output;
445 : GF_Err e;
446 : Bool start, end;
447 : u32 size, osize, pad, i, unused;
448 : GF_FilterPacket *pck_out;
449 0 : GF_CryptFileCtx *ctx = (GF_CryptFileCtx *) gf_filter_get_udta(filter);
450 0 : GF_FilterPacket *pck_in = gf_filter_pid_get_packet(ctx->ipid);
451 :
452 0 : if (ctx->in_error)
453 : return ctx->in_error;
454 :
455 0 : if (!pck_in) {
456 0 : if (gf_filter_pid_is_eos(ctx->ipid)) {
457 0 : if (!ctx->remain && ctx->file_done) {
458 0 : gf_filter_pid_set_eos(ctx->opid);
459 0 : return GF_EOS;
460 : }
461 0 : start = GF_TRUE;
462 : } else {
463 : return GF_OK;
464 : }
465 : } else {
466 0 : gf_filter_pck_get_framing(pck_in, &start, &end);
467 : }
468 :
469 0 : if (start) {
470 0 : KeyInfo *ki = gf_list_pop_front(ctx->keys);
471 :
472 0 : if (ctx->remain || !ctx->file_done) {
473 0 : pad = 16 - (ctx->remain % 16);
474 0 : osize = ctx->remain + pad;
475 0 : pck_out = gf_filter_pck_new_alloc(ctx->opid, osize, &output);
476 0 : if (!pck_out) {
477 0 : gf_list_insert(ctx->keys, ki, 0);
478 0 : return GF_OUT_OF_MEM;
479 : }
480 :
481 0 : if (ctx->remain)
482 0 : memcpy(output, ctx->store, ctx->remain);
483 :
484 0 : for (i=0; i<pad; i++) {
485 0 : output[ctx->remain + i] = pad;
486 : }
487 0 : gf_crypt_encrypt(ctx->crypt, output, osize);
488 :
489 0 : gf_filter_pck_set_framing(pck_out, GF_FALSE, GF_TRUE);
490 0 : ctx->remain = 0;
491 0 : ctx->file_done = GF_TRUE;
492 0 : gf_filter_pck_send(pck_out);
493 : }
494 0 : if (!pck_in) {
495 0 : gf_free(ki);
496 0 : return GF_OK;
497 : }
498 0 : ctx->file_done = GF_FALSE;
499 :
500 0 : ctx->use_key = GF_TRUE;
501 : e = GF_OK;
502 0 : if (!ki || !ki->do_crypt) {
503 0 : ctx->use_key = GF_FALSE;
504 0 : ctx->file_done = GF_TRUE;
505 0 : } else if (!ctx->crypt) {
506 0 : ctx->crypt = gf_crypt_open(GF_AES_128, GF_CBC);
507 0 : if (!ctx->crypt) {
508 0 : gf_free(ki);
509 0 : return ctx->in_error = GF_OUT_OF_MEM;
510 : }
511 0 : e = gf_crypt_init(ctx->crypt, ki->key, ki->iv);
512 0 : memcpy(ctx->last_key, ki->key, sizeof(bin128));
513 : } else {
514 0 : if (memcmp(ctx->last_key, ki->key, sizeof(bin128))) {
515 0 : e = gf_crypt_set_key(ctx->crypt, ki->key);
516 : memcpy(ctx->last_key, ki->key, sizeof(bin128));
517 : }
518 0 : if (!e)
519 0 : e = gf_crypt_set_IV(ctx->crypt, ki->iv, 16);
520 : }
521 0 : gf_free(ki);
522 0 : if (e) return ctx->in_error = e;
523 : }
524 :
525 0 : if (!ctx->use_key) {
526 0 : gf_filter_pck_forward(pck_in, ctx->opid);
527 0 : gf_filter_pid_drop_packet(ctx->ipid);
528 0 : return GF_OK;
529 : }
530 :
531 0 : if (ctx->fullfile) {
532 0 : data = gf_filter_pck_get_data(pck_in, &size);
533 0 : pad = 16 - (size % 16);
534 0 : pck_out = gf_filter_pck_new_alloc(ctx->opid, size+pad, &output);
535 0 : if (!pck_out) return GF_OUT_OF_MEM;
536 :
537 0 : memcpy(output, data, size);
538 0 : for (i=0; i<pad; i++) {
539 0 : output[size+i] = (u8) pad;
540 : }
541 0 : gf_crypt_encrypt(ctx->crypt, output, size+pad);
542 :
543 0 : gf_filter_pck_merge_properties(pck_in, pck_out);
544 0 : gf_filter_pck_send(pck_out);
545 0 : gf_filter_pid_drop_packet(ctx->ipid);
546 0 : ctx->file_done = GF_TRUE;
547 0 : return GF_OK;
548 : }
549 :
550 0 : data = gf_filter_pck_get_data(pck_in, &size);
551 :
552 0 : osize = size + ctx->remain;
553 : unused = pad = 0;
554 0 : if (end) {
555 0 : pad = 16 - (osize % 16);
556 0 : osize += pad;
557 0 : ctx->file_done = GF_TRUE;
558 : } else {
559 0 : unused = osize % 16;
560 0 : osize -= unused;
561 : }
562 :
563 0 : pck_out = gf_filter_pck_new_alloc(ctx->opid, osize, &output);
564 0 : if (!pck_out) return GF_OUT_OF_MEM;
565 :
566 0 : if (ctx->remain)
567 0 : memcpy(output, ctx->store, ctx->remain);
568 0 : memcpy(output+ctx->remain, data, osize - ctx->remain - pad);
569 0 : for (i=0; i<pad; i++) {
570 0 : output[osize + i - pad] = pad;
571 : }
572 0 : e = gf_crypt_encrypt(ctx->crypt, output, osize);
573 :
574 0 : gf_filter_pck_merge_properties(pck_in, pck_out);
575 0 : gf_filter_pck_set_framing(pck_out, start, end);
576 :
577 0 : if (unused) {
578 0 : memcpy(ctx->store, data + size - unused, unused);
579 : }
580 0 : ctx->remain = unused;
581 0 : gf_filter_pck_send(pck_out);
582 0 : gf_filter_pid_drop_packet(ctx->ipid);
583 0 : return e;
584 : }
585 :
586 : static const GF_FilterArgs CryptFoutArgs[] =
587 : {
588 : { OFFS(dst), "location of source file", GF_PROP_NAME, NULL, NULL, 0},
589 : { OFFS(fullfile), "reassemble full file before decryption", GF_PROP_BOOL, "false", NULL, GF_ARG_HINT_ADVANCED},
590 : {0}
591 : };
592 :
593 : GF_FilterRegister CryptFoutRegister = {
594 : .name = "cryptout",
595 : GF_FS_SET_DESCRIPTION("CryptFile output")
596 : GF_FS_SET_HELP("This filter dispatch raw blocks from clear input files to encrypted files with AES 128 CBC in PKCS7\n"
597 : "\n"
598 : "The filter accepts URL with scheme `gcryp://URL`, where `URL` is the URL to encrypt.")
599 : .private_size = sizeof(GF_CryptFileCtx),
600 : .args = CryptFoutArgs,
601 : .initialize = cryptfout_initialize,
602 : .flags = GF_FS_REG_EXPLICIT_ONLY,
603 : SETCAPS(CryptFileCaps),
604 : .finalize = cryptfile_finalize,
605 : .configure_pid = cryptfile_configure_pid,
606 : .process = cryptfout_process,
607 : .probe_url = cryptfile_probe_url
608 : };
609 :
610 :
611 2877 : const GF_FilterRegister *cryptfout_register(GF_FilterSession *session)
612 : {
613 2877 : return &CryptFoutRegister;
614 : }
615 :
616 0 : GF_Err gf_cryptfout_push_key(GF_Filter *filter, bin128 *key, bin128 *IV)
617 : {
618 : KeyInfo *key_info;
619 : GF_CryptFileCtx *ctx;
620 0 : if (!gf_filter_is_instance_of(filter, &CryptFoutRegister))
621 : return GF_BAD_PARAM;
622 :
623 0 : ctx = (GF_CryptFileCtx *) gf_filter_get_udta(filter);
624 0 : GF_SAFEALLOC(key_info, KeyInfo);
625 0 : if (!key_info) return GF_OUT_OF_MEM;
626 :
627 0 : if (key && IV) {
628 0 : memcpy(key_info->key, *key, sizeof(bin128));
629 0 : memcpy(key_info->iv, *IV, sizeof(bin128));
630 0 : key_info->do_crypt = GF_TRUE;
631 : }
632 0 : return gf_list_add(ctx->keys, key_info);
633 : }
|