static AesCtrState * setup_aes_decrypt() { /* NIST SP800-38a section F.5.2; CTR-AES128 Decrypt */ const guint8 Key[]={ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }; const guint8 IV[] = { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; AesCtrState *state; GstBuffer *gkey; GBytes *giv; gkey = gst_buffer_new_allocate (NULL,sizeof(Key),NULL); fail_if(gkey==NULL); gst_buffer_fill(gkey,0,Key,sizeof(Key)); giv = g_bytes_new_static(IV,sizeof(IV)); fail_if(giv==NULL); state = gst_aes_ctr_decrypt_new(gkey, giv); fail_if(state==NULL); g_bytes_unref(giv); gst_buffer_unref(gkey); return state; }
static GstFlowReturn gst_cenc_decrypt_transform_ip (GstBaseTransform * base, GstBuffer * buf) { GstCencDecrypt *self = GST_CENC_DECRYPT (base); GstFlowReturn ret = GST_FLOW_OK; GstMapInfo map, iv_map; const GstCencKeyPair *keypair; const GstProtectionMeta *prot_meta = NULL; guint pos = 0; gint sample_index = 0; guint subsample_count; AesCtrState *state = NULL; guint iv_size; gboolean encrypted; const GValue *value; GstBuffer *key_id = NULL; GstBuffer *iv_buf = NULL; GBytes *iv_bytes = NULL; GstBuffer *subsamples_buf = NULL; GstMapInfo subsamples_map; GstByteReader *reader=NULL; GST_TRACE_OBJECT (self, "decrypt in-place"); prot_meta = (GstProtectionMeta*) gst_buffer_get_protection_meta (buf); if (!prot_meta || !buf) { if (!prot_meta) { GST_ERROR_OBJECT (self, "Failed to get GstProtection metadata from buffer"); } if (!buf) { GST_ERROR_OBJECT (self, "Failed to get writable buffer"); } ret = GST_FLOW_NOT_SUPPORTED; goto out; } if (!gst_buffer_map (buf, &map, GST_MAP_READWRITE)) { GST_ERROR_OBJECT (self, "Failed to map buffer"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } GST_TRACE_OBJECT (self, "decrypt sample %d", (gint)map.size); if(!gst_structure_get_uint(prot_meta->info,"iv_size",&iv_size)){ GST_ERROR_OBJECT (self, "failed to get iv_size"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } if(!gst_structure_get_boolean(prot_meta->info,"encrypted",&encrypted)){ GST_ERROR_OBJECT (self, "failed to get encrypted flag"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } if (iv_size == 0 || !encrypted) { /* sample is not encrypted */ goto beach; } GST_DEBUG_OBJECT (base, "protection meta: %" GST_PTR_FORMAT, prot_meta->info); if(!gst_structure_get_uint(prot_meta->info,"subsample_count",&subsample_count)){ GST_ERROR_OBJECT (self, "failed to get subsample_count"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } value = gst_structure_get_value (prot_meta->info, "kid"); if(!value){ GST_ERROR_OBJECT (self, "Failed to get KID for sample"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } key_id = gst_value_get_buffer (value); value = gst_structure_get_value (prot_meta->info, "iv"); if(!value){ GST_ERROR_OBJECT (self, "Failed to get IV for sample"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } iv_buf = gst_value_get_buffer (value); if(!gst_buffer_map (iv_buf, &iv_map, GST_MAP_READ)){ GST_ERROR_OBJECT (self, "Failed to map IV"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } iv_bytes = g_bytes_new (iv_map.data, iv_map.size); gst_buffer_unmap (iv_buf, &iv_map); if(subsample_count){ value = gst_structure_get_value (prot_meta->info, "subsamples"); if(!value){ GST_ERROR_OBJECT (self, "Failed to get subsamples"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } subsamples_buf = gst_value_get_buffer (value); if(!gst_buffer_map (subsamples_buf, &subsamples_map, GST_MAP_READ)){ GST_ERROR_OBJECT (self, "Failed to map subsample buffer"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } } keypair = gst_cenc_decrypt_lookup_key (self,key_id); if (!keypair) { gsize sz; GST_ERROR_OBJECT (self, "Failed to lookup key"); GST_MEMDUMP_OBJECT (self, "Key ID:", g_bytes_get_data (keypair->key_id, &sz), sz); ret = GST_FLOW_NOT_SUPPORTED; goto release; } state = gst_aes_ctr_decrypt_new (keypair->key, iv_bytes); if (!state) { GST_ERROR_OBJECT (self, "Failed to init AES cipher"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } if (subsample_count) { reader = gst_byte_reader_new (subsamples_map.data, subsamples_map.size); if(!reader){ GST_ERROR_OBJECT (self, "Failed to allocate subsample reader"); ret = GST_FLOW_NOT_SUPPORTED; goto release; } } while (pos < map.size) { guint16 n_bytes_clear = 0; guint32 n_bytes_encrypted = 0; if (sample_index < subsample_count) { if (!gst_byte_reader_get_uint16_be (reader, &n_bytes_clear) || !gst_byte_reader_get_uint32_be (reader, &n_bytes_encrypted)) { ret = GST_FLOW_NOT_SUPPORTED; goto release; } sample_index++; } else { n_bytes_clear = 0; n_bytes_encrypted = map.size - pos; } GST_TRACE_OBJECT (self, "%u bytes clear (todo=%d)", n_bytes_clear, (gint)map.size - pos); pos += n_bytes_clear; if (n_bytes_encrypted) { GST_TRACE_OBJECT (self, "%u bytes encrypted (todo=%d)", n_bytes_encrypted, (gint)map.size - pos); gst_aes_ctr_decrypt_ip (state, map.data + pos, n_bytes_encrypted); pos += n_bytes_encrypted; } } beach: gst_buffer_unmap (buf, &map); if (state) { gst_aes_ctr_decrypt_unref (state); } release: if (reader){ gst_byte_reader_free (reader); } if(subsamples_buf){ gst_buffer_unmap (subsamples_buf, &subsamples_map); } if (prot_meta) { gst_buffer_remove_meta (buf, (GstMeta *) prot_meta); } if (iv_bytes) { g_bytes_unref (iv_bytes); } out: return ret; }