LCOV - code coverage report
Current view: top level - filters - io_fcryp.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 7 301 2.3 %
Date: 2021-04-29 23:48:07 Functions: 3 13 23.1 %

          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             : }

Generated by: LCOV version 1.13