• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer gstreamer-aesdec
3  *
4  * Copyright, LCC (C) 2015 RidgeRun, LCC <carsten.behling@ridgerun.com>
5  * Copyright, LCC (C) 2016 RidgeRun, LCC <jose.jimenez@ridgerun.com>
6  * Copyright (C) 2020 Nice, Contact: Rabindra Harlalka <Rabindra.Harlalka@nice.com>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  *
26  * Alternatively, the contents of this file may be used under the
27  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
28  * which case the following provisions apply instead of the ones
29  * mentioned above:
30  *
31  * This library is free software; you can redistribute it and/or
32  * modify it under the terms of the GNU Library General Public
33  * License as published by the Free Software Foundation; either
34  * version 2 of the License, or (at your option) any later version.
35  *
36  * This library is distributed in the hope that it will be useful,
37  * but WITHOUT ANY WARRANTY; without even the implied warranty of
38  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
39  * Library General Public License for more details.
40  *
41  * You should have received a copy of the GNU Library General Public
42  * License along with this library; if not, write to the
43  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
44  * Boston, MA 02110-1335, USA.
45  */
46 
47 /**
48  * SECTION:element-aesdec
49  *
50  * AES decryption
51  *
52  * ## Example
53  *
54  * |[
55  * echo "This is an AES crypto test ... " > plain.txt && \
56  *       gst-launch-1.0 filesrc location=plain.txt ! \
57  *       aesenc key=1f9423681beb9a79215820f6bda73d0f iv=e9aa8e834d8d70b7e0d254ff670dd718 ! \
58  *       aesdec key=1f9423681beb9a79215820f6bda73d0f iv=e9aa8e834d8d70b7e0d254ff670dd718 ! \
59  *       filesink location=dec.txt && \
60  *       cat dec.txt
61  *
62  * ]|
63  *
64  * Since: 1.20
65  */
66 
67 #ifdef HAVE_CONFIG_H
68 #  include <config.h>
69 #endif
70 
71 #include <gst/gst.h>
72 #include <gst/base/gstbasetransform.h>
73 #include <string.h>
74 #include "gstaeshelper.h"
75 #include "gstaesdec.h"
76 
77 GST_DEBUG_CATEGORY_STATIC (gst_aes_dec_debug);
78 #define GST_CAT_DEFAULT gst_aes_dec_debug
79 G_DEFINE_TYPE_WITH_CODE (GstAesDec, gst_aes_dec, GST_TYPE_BASE_TRANSFORM,
80     GST_DEBUG_CATEGORY_INIT (gst_aes_dec_debug, "aesdec", 0,
81         "aesdec AES decryption element")
82     );
83 GST_ELEMENT_REGISTER_DEFINE (aesdec, "aesdec", GST_RANK_PRIMARY,
84     GST_TYPE_AES_DEC);
85 
86 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
87     GST_PAD_SINK,
88     GST_PAD_ALWAYS,
89     GST_STATIC_CAPS ("ANY")
90     );
91 
92 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
93     GST_PAD_SRC,
94     GST_PAD_ALWAYS,
95     GST_STATIC_CAPS ("ANY")
96     );
97 
98 static void gst_aes_dec_set_property (GObject * object, guint prop_id,
99     const GValue * value, GParamSpec * pspec);
100 static void gst_aes_dec_get_property (GObject * object, guint prop_id,
101     GValue * value, GParamSpec * pspec);
102 
103 static GstFlowReturn gst_aes_dec_transform (GstBaseTransform * base,
104     GstBuffer * inbuf, GstBuffer * outbuf);
105 static GstFlowReturn gst_aes_dec_prepare_output_buffer (GstBaseTransform * base,
106     GstBuffer * inbuf, GstBuffer ** outbuf);
107 static gboolean
108 gst_aes_dec_sink_event (GstBaseTransform * base, GstEvent * event);
109 
110 static gboolean gst_aes_dec_start (GstBaseTransform * base);
111 static gboolean gst_aes_dec_stop (GstBaseTransform * base);
112 
113 /* aes_dec helper functions */
114 static gboolean gst_aes_dec_openssl_init (GstAesDec * filter);
115 static gboolean gst_aes_dec_init_cipher (GstAesDec * filter);
116 static void gst_aes_dec_finalize (GObject * object);
117 
118 /* GObject vmethod implementations */
119 
120 /* initialize class */
121 static void
gst_aes_dec_class_init(GstAesDecClass * klass)122 gst_aes_dec_class_init (GstAesDecClass * klass)
123 {
124   GObjectClass *gobject_class;
125   GstElementClass *gstelement_class;
126 
127   gobject_class = (GObjectClass *) klass;
128   gstelement_class = (GstElementClass *) klass;
129 
130   gobject_class->set_property = gst_aes_dec_set_property;
131   gobject_class->get_property = gst_aes_dec_get_property;
132   gobject_class->finalize = gst_aes_dec_finalize;
133 
134   gst_type_mark_as_plugin_api (GST_TYPE_AES_CIPHER, 0);
135 
136   /**
137    * GstAesDec:cipher
138    *
139    * AES cipher mode (key length and mode)
140    * Currently, 128 and 256 bit keys are supported,
141    * in "cipher block chaining" (CBC) mode
142    *
143    * Since: 1.20
144    */
145   g_object_class_install_property (gobject_class, PROP_CIPHER,
146       g_param_spec_enum ("cipher",
147           "Cipher",
148           "cipher mode",
149           GST_TYPE_AES_CIPHER, GST_AES_DEFAULT_CIPHER_MODE,
150           (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
151               GST_PARAM_MUTABLE_READY)));
152 
153   /**
154    * GstAesDec:serialize-iv
155    *
156    * If true, read initialization vector from first 16 bytes of first buffer
157    *
158    * Since: 1.20
159    */
160   g_object_class_install_property (gobject_class, PROP_SERIALIZE_IV,
161       g_param_spec_boolean ("serialize-iv", "Serialize IV",
162           "Read initialization vector from first 16 bytes of first buffer",
163           GST_AES_DEFAULT_SERIALIZE_IV,
164           G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY));
165 
166   /**
167    * GstAesDec:per-buffer-padding
168    *
169    * If true, each buffer will be padded using PKCS7 padding
170    * If false, only the final buffer in the stream will be padded
171    * (by OpenSSL) using PKCS7
172    *
173    * Since: 1.20
174    */
175   g_object_class_install_property (gobject_class, PROP_PER_BUFFER_PADDING,
176       g_param_spec_boolean ("per-buffer-padding", "Per buffer padding",
177           "If true, pad each buffer using PKCS7 padding scheme. Otherwise, only"
178           "pad final buffer",
179           GST_AES_PER_BUFFER_PADDING_DEFAULT,
180           G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY));
181 
182   /**
183    * GstAesDec:key
184    *
185    * AES encryption key (hexadecimal)
186    *
187    * Since: 1.20
188    */
189   g_object_class_install_property (gobject_class, PROP_KEY,
190       g_param_spec_string ("key", "Key",
191           "AES encryption key (in hexadecimal). Length (in bytes) must be equivalent to "
192           "the number of bits in the key length : "
193           "16 bytes for AES 128 and 32 bytes for AES 256",
194           (gchar *) GST_AES_DEFAULT_KEY,
195           G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY));
196   /**
197    * GstAesDec:iv
198    *
199    * AES encryption initialization vector (hexadecimal)
200    *
201    * Since: 1.20
202    */
203   g_object_class_install_property (gobject_class, PROP_IV,
204       g_param_spec_string ("iv", "Iv",
205           "AES encryption initialization vector (in hexadecimal). "
206           "Length must equal AES block length (16 bytes)",
207           (gchar *) GST_AES_DEFAULT_IV,
208           G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY));
209 
210   gst_element_class_set_details_simple (gstelement_class,
211       "aesdec",
212       "Generic/Filter",
213       "AES buffer decryption",
214       "Rabindra Harlalka <Rabindra.Harlalka@nice.com>");
215 
216   gst_element_class_add_pad_template (gstelement_class,
217       gst_static_pad_template_get (&src_template));
218   gst_element_class_add_pad_template (gstelement_class,
219       gst_static_pad_template_get (&sink_template));
220 
221   GST_BASE_TRANSFORM_CLASS (klass)->transform =
222       GST_DEBUG_FUNCPTR (gst_aes_dec_transform);
223   GST_BASE_TRANSFORM_CLASS (klass)->prepare_output_buffer =
224       GST_DEBUG_FUNCPTR (gst_aes_dec_prepare_output_buffer);
225   GST_BASE_TRANSFORM_CLASS (klass)->start =
226       GST_DEBUG_FUNCPTR (gst_aes_dec_start);
227   GST_BASE_TRANSFORM_CLASS (klass)->sink_event =
228       GST_DEBUG_FUNCPTR (gst_aes_dec_sink_event);
229   GST_BASE_TRANSFORM_CLASS (klass)->stop = GST_DEBUG_FUNCPTR (gst_aes_dec_stop);
230 }
231 
232 /* Initialize element
233  */
234 static void
gst_aes_dec_init(GstAesDec * filter)235 gst_aes_dec_init (GstAesDec * filter)
236 {
237   GST_INFO_OBJECT (filter, "Initializing plugin");
238   filter->cipher = GST_AES_DEFAULT_CIPHER_MODE;
239   filter->awaiting_first_buffer = TRUE;
240   filter->per_buffer_padding = GST_AES_PER_BUFFER_PADDING_DEFAULT;
241   g_mutex_init (&filter->decoder_lock);
242 }
243 
244 static void
gst_aes_dec_finalize(GObject * object)245 gst_aes_dec_finalize (GObject * object)
246 {
247   GstAesDec *filter = GST_AES_DEC (object);
248 
249   g_mutex_clear (&filter->decoder_lock);
250   G_OBJECT_CLASS (gst_aes_dec_parent_class)->finalize (object);
251 }
252 
253 
254 static void
gst_aes_dec_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)255 gst_aes_dec_set_property (GObject * object, guint prop_id,
256     const GValue * value, GParamSpec * pspec)
257 {
258   GstAesDec *filter = GST_AES_DEC (object);
259 
260   g_mutex_lock (&filter->decoder_lock);
261   /* no property may be set after first output buffer is prepared */
262   if (filter->locked_properties) {
263     GST_WARNING_OBJECT (filter,
264         "Properties cannot be set once buffers begin flowing in element. Ignored");
265     goto cleanup;
266   }
267 
268   switch (prop_id) {
269     case PROP_CIPHER:
270       filter->cipher = g_value_get_enum (value);
271       filter->evp_cipher =
272           EVP_get_cipherbyname (gst_aes_cipher_enum_to_string (filter->cipher));
273       GST_DEBUG_OBJECT (filter, "cipher: %s",
274           gst_aes_cipher_enum_to_string (filter->cipher));
275       break;
276     case PROP_SERIALIZE_IV:
277       filter->serialize_iv = g_value_get_boolean (value);
278       GST_DEBUG_OBJECT (filter, "serialize iv: %s",
279           filter->serialize_iv ? "TRUE" : "FALSE");
280       break;
281     case PROP_PER_BUFFER_PADDING:
282       filter->per_buffer_padding = g_value_get_boolean (value);
283       GST_DEBUG_OBJECT (filter, "Per buffer padding: %s",
284           filter->per_buffer_padding ? "TRUE" : "FALSE");
285       break;
286     case PROP_KEY:
287     {
288       guint hex_len = gst_aes_hexstring2bytearray (GST_ELEMENT (filter),
289           g_value_get_string (value), filter->key);
290 
291       if (!hex_len) {
292         GST_ERROR_OBJECT (filter, "invalid key");
293         goto cleanup;
294       }
295       GST_DEBUG_OBJECT (filter, "key: %s", g_value_get_string (value));
296     }
297       break;
298     case PROP_IV:
299     {
300       gchar iv_string[2 * GST_AES_BLOCK_SIZE + 1];
301       guint hex_len = gst_aes_hexstring2bytearray (GST_ELEMENT (filter),
302           g_value_get_string (value), filter->iv);
303 
304       if (hex_len != GST_AES_BLOCK_SIZE) {
305         GST_ERROR_OBJECT (filter, "invalid initialization vector");
306         goto cleanup;
307       }
308       GST_DEBUG_OBJECT (filter, "iv: %s",
309           gst_aes_bytearray2hexstring (filter->iv, iv_string,
310               GST_AES_BLOCK_SIZE));
311     }
312       break;
313     default:
314       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
315       break;
316   }
317 
318 cleanup:
319   g_mutex_unlock (&filter->decoder_lock);
320 }
321 
322 static void
gst_aes_dec_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)323 gst_aes_dec_get_property (GObject * object, guint prop_id,
324     GValue * value, GParamSpec * pspec)
325 {
326   GstAesDec *filter = GST_AES_DEC (object);
327 
328   switch (prop_id) {
329     case PROP_CIPHER:
330       g_value_set_enum (value, filter->cipher);
331       break;
332     case PROP_SERIALIZE_IV:
333       g_value_set_boolean (value, filter->serialize_iv);
334       break;
335     case PROP_PER_BUFFER_PADDING:
336       g_value_set_boolean (value, filter->per_buffer_padding);
337       break;
338     case PROP_KEY:
339       g_value_set_string (value, (gchar *) filter->key);
340       break;
341     case PROP_IV:
342       g_value_set_string (value, (gchar *) filter->iv);
343       break;
344     default:
345       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
346       break;
347   }
348 }
349 
350 static gboolean
gst_aes_dec_sink_event(GstBaseTransform * base,GstEvent * event)351 gst_aes_dec_sink_event (GstBaseTransform * base, GstEvent * event)
352 {
353   GstAesDec *filter = GST_AES_DEC (base);
354 
355   g_mutex_lock (&filter->decoder_lock);
356 
357   if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
358     GST_DEBUG_OBJECT (filter, "Received EOS on sink pad");
359     if (!filter->per_buffer_padding && !filter->awaiting_first_buffer) {
360       GstBuffer *outbuf = NULL;
361       gint len;
362       GstMapInfo outmap;
363 
364       outbuf = gst_buffer_new_allocate (NULL, EVP_MAX_BLOCK_LENGTH, NULL);
365       if (outbuf == NULL) {
366         GST_DEBUG_OBJECT (filter,
367             "Failed to allocate a new buffer of length %d",
368             EVP_MAX_BLOCK_LENGTH);
369         goto buffer_fail;
370       }
371       if (!gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE)) {
372         GST_DEBUG_OBJECT (filter,
373             "gst_buffer_map on outbuf failed for final buffer.");
374         gst_buffer_unref (outbuf);
375         goto buffer_fail;
376       }
377       if (1 != EVP_CipherFinal_ex (filter->evp_ctx, outmap.data, &len)) {
378         GST_DEBUG_OBJECT (filter, "Could not finalize openssl encryption");
379         gst_buffer_unmap (outbuf, &outmap);
380         gst_buffer_unref (outbuf);
381         goto cipher_fail;
382       }
383       if (len == 0) {
384         GST_DEBUG_OBJECT (filter, "Not pushing final buffer as length is 0");
385         gst_buffer_unmap (outbuf, &outmap);
386         gst_buffer_unref (outbuf);
387         goto out;
388       }
389       GST_DEBUG_OBJECT (filter, "Pushing final buffer of length: %d", len);
390       gst_buffer_unmap (outbuf, &outmap);
391       gst_buffer_set_size (outbuf, len);
392       if (gst_pad_push (base->srcpad, outbuf) != GST_FLOW_OK) {
393         GST_DEBUG_OBJECT (filter, "Failed to push the final buffer");
394         goto push_fail;
395       }
396     } else {
397       GST_DEBUG_OBJECT (filter,
398           "Not pushing final buffer as we didn't have any input");
399     }
400   }
401 
402 out:
403   g_mutex_unlock (&filter->decoder_lock);
404 
405   return GST_BASE_TRANSFORM_CLASS (gst_aes_dec_parent_class)->sink_event (base,
406       event);
407 
408   /* ERROR */
409 buffer_fail:
410   GST_ELEMENT_ERROR (filter, RESOURCE, FAILED, (NULL),
411       ("Failed to allocate or map buffer for writing"));
412   g_mutex_unlock (&filter->decoder_lock);
413 
414   return FALSE;
415 cipher_fail:
416   GST_ELEMENT_ERROR (filter, STREAM, FAILED, ("Cipher finalization failed."),
417       ("Error while finalizing the stream"));
418   g_mutex_unlock (&filter->decoder_lock);
419 
420   return FALSE;
421 push_fail:
422   GST_ELEMENT_ERROR (filter, CORE, PAD, (NULL),
423       ("Failed to push the final buffer"));
424   g_mutex_unlock (&filter->decoder_lock);
425 
426   return FALSE;
427 }
428 
429 /* GstBaseTransform vmethod implementations */
430 static GstFlowReturn
gst_aes_dec_transform(GstBaseTransform * base,GstBuffer * inbuf,GstBuffer * outbuf)431 gst_aes_dec_transform (GstBaseTransform * base,
432     GstBuffer * inbuf, GstBuffer * outbuf)
433 {
434   GstAesDec *filter = GST_AES_DEC (base);
435   GstFlowReturn ret = GST_FLOW_ERROR;
436   GstMapInfo inmap, outmap;
437   guchar *ciphertext;
438   gint ciphertext_len;
439   guchar *plaintext;
440   gint plaintext_len;
441   guint padding = 0;
442 
443   if (!gst_buffer_map (inbuf, &inmap, GST_MAP_READ)) {
444     GST_ELEMENT_ERROR (filter, RESOURCE, FAILED, (NULL),
445         ("Failed to map buffer for reading"));
446     goto cleanup;
447   }
448   if (!gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE)) {
449     gst_buffer_unmap (inbuf, &inmap);
450     GST_ELEMENT_ERROR (filter, RESOURCE, FAILED, (NULL),
451         ("Failed to map buffer for writing"));
452     goto cleanup;
453   }
454   /* DECRYPTING */
455   ciphertext = inmap.data;
456   ciphertext_len = gst_buffer_get_size (inbuf);
457   if (filter->awaiting_first_buffer) {
458     if (filter->serialize_iv) {
459       gchar iv_string[2 * GST_AES_BLOCK_SIZE + 1];
460 
461       if (ciphertext_len < GST_AES_BLOCK_SIZE) {
462         GST_ELEMENT_ERROR (filter, RESOURCE, FAILED, (NULL),
463             ("Cipher text too short"));
464         goto cleanup;
465       }
466       memcpy (filter->iv, ciphertext, GST_AES_BLOCK_SIZE);
467       GST_DEBUG_OBJECT (filter, "read serialized iv: %s",
468           gst_aes_bytearray2hexstring (filter->iv, iv_string,
469               GST_AES_BLOCK_SIZE));
470       ciphertext += GST_AES_BLOCK_SIZE;
471       ciphertext_len -= GST_AES_BLOCK_SIZE;
472     }
473     if (!gst_aes_dec_init_cipher (filter)) {
474       GST_ELEMENT_ERROR (filter, RESOURCE, FAILED, (NULL),
475           ("Failed to initialize cipher"));
476       goto cleanup;
477     }
478   }
479   plaintext = outmap.data;
480 
481   if (!EVP_CipherUpdate (filter->evp_ctx, plaintext,
482           &plaintext_len, ciphertext, ciphertext_len)) {
483     GST_ELEMENT_ERROR (filter, STREAM, FAILED, ("Cipher update failed."),
484         ("Error while updating openssl cipher"));
485     goto cleanup;
486   } else {
487     if (filter->per_buffer_padding) {
488       gint k;
489 
490       /* sanity check on padding value */
491       padding = plaintext[plaintext_len - 1];
492       if (padding == 0 || padding > GST_AES_BLOCK_SIZE) {
493         GST_ELEMENT_ERROR (filter, STREAM, FAILED, ("Corrupt cipher text."),
494             ("Illegal PKCS7 padding value %d", padding));
495         goto cleanup;
496       }
497       for (k = 1; k < padding; ++k) {
498         if (plaintext[plaintext_len - 1 - k] != padding) {
499           GST_ELEMENT_ERROR (filter, STREAM, FAILED, ("Corrupt cipher text."),
500               ("PKCS7 padding values must all be equal"));
501           goto cleanup;
502         }
503       }
504       /* remove padding (final block padding) */
505       plaintext_len -= padding;
506     }
507     if (plaintext_len > 2 * GST_AES_BLOCK_SIZE)
508       GST_MEMDUMP ("First 32 bytes of plain text", plaintext,
509           2 * GST_AES_BLOCK_SIZE);
510   }
511   gst_buffer_unmap (inbuf, &inmap);
512   gst_buffer_unmap (outbuf, &outmap);
513 
514   GST_LOG_OBJECT (filter,
515       "Ciphertext len: %d, Plaintext len: %d, Padding: %d",
516       ciphertext_len, plaintext_len, padding);
517   gst_buffer_set_size (outbuf, plaintext_len);
518   ret = GST_FLOW_OK;
519 
520 cleanup:
521   filter->awaiting_first_buffer = FALSE;
522 
523   return ret;
524 }
525 
526 static GstFlowReturn
gst_aes_dec_prepare_output_buffer(GstBaseTransform * base,GstBuffer * inbuf,GstBuffer ** outbuf)527 gst_aes_dec_prepare_output_buffer (GstBaseTransform * base,
528     GstBuffer * inbuf, GstBuffer ** outbuf)
529 {
530   GstAesDec *filter = GST_AES_DEC (base);
531   GstBaseTransformClass *bclass = GST_BASE_TRANSFORM_GET_CLASS (base);
532   guint out_size;
533 
534   g_mutex_lock (&filter->decoder_lock);
535   filter->locked_properties = TRUE;
536   /* we need extra space at end of output buffer
537    * when we let OpenSSL handle PKCS7 padding  */
538   out_size = (gint) gst_buffer_get_size (inbuf) +
539       (!filter->per_buffer_padding ? GST_AES_BLOCK_SIZE : 0);
540 
541   /* Since serialized IV is stripped from first buffer,
542    * reduce output buffer size by GST_AES_BLOCK_SIZE in this case */
543   if (filter->serialize_iv && filter->awaiting_first_buffer) {
544     g_assert (gst_buffer_get_size (inbuf) > GST_AES_BLOCK_SIZE);
545     out_size -= GST_AES_BLOCK_SIZE;
546   }
547   g_mutex_unlock (&filter->decoder_lock);
548 
549   *outbuf = gst_buffer_new_allocate (NULL, out_size, NULL);
550   GST_LOG_OBJECT (filter,
551       "Input buffer size %d,\nAllocating output buffer size: %d",
552       (gint) gst_buffer_get_size (inbuf), out_size);
553   bclass->copy_metadata (base, inbuf, *outbuf);
554 
555   return GST_FLOW_OK;
556 }
557 
558 static gboolean
gst_aes_dec_start(GstBaseTransform * base)559 gst_aes_dec_start (GstBaseTransform * base)
560 {
561   GstAesDec *filter = GST_AES_DEC (base);
562 
563   GST_INFO_OBJECT (filter, "Starting");
564   if (!gst_aes_dec_openssl_init (filter)) {
565     GST_ERROR_OBJECT (filter, "OpenSSL initialization failed");
566     return FALSE;
567   }
568 
569   if (!filter->serialize_iv) {
570     if (!gst_aes_dec_init_cipher (filter))
571       return FALSE;
572   }
573   GST_INFO_OBJECT (filter, "Start successful");
574 
575   return TRUE;
576 }
577 
578 static gboolean
gst_aes_dec_init_cipher(GstAesDec * filter)579 gst_aes_dec_init_cipher (GstAesDec * filter)
580 {
581   if (!EVP_CipherInit_ex (filter->evp_ctx, filter->evp_cipher, NULL,
582           filter->key, filter->iv, FALSE)) {
583     GST_ERROR_OBJECT (filter, "Could not initialize openssl cipher");
584     return FALSE;
585   }
586   if (filter->per_buffer_padding) {
587     if (!EVP_CIPHER_CTX_set_padding (filter->evp_ctx, 0)) {
588       GST_ERROR_OBJECT (filter, "Could not set padding");
589       return FALSE;
590     }
591   }
592 
593   return TRUE;
594 }
595 
596 static gboolean
gst_aes_dec_stop(GstBaseTransform * base)597 gst_aes_dec_stop (GstBaseTransform * base)
598 {
599   GstAesDec *filter = GST_AES_DEC (base);
600 
601   GST_INFO_OBJECT (filter, "Stopping");
602   EVP_CIPHER_CTX_free (filter->evp_ctx);
603 
604   return TRUE;
605 }
606 
607 /* AesDec helper  functions */
608 static gboolean
gst_aes_dec_openssl_init(GstAesDec * filter)609 gst_aes_dec_openssl_init (GstAesDec * filter)
610 {
611   GST_DEBUG_OBJECT (filter, "Initializing with %s",
612       OpenSSL_version (OPENSSL_VERSION));
613 
614   filter->evp_cipher =
615       EVP_get_cipherbyname (gst_aes_cipher_enum_to_string (filter->cipher));
616   if (!filter->evp_cipher) {
617     GST_ERROR_OBJECT (filter, "Could not get cipher by name from openssl");
618     return FALSE;
619   }
620   if (!(filter->evp_ctx = EVP_CIPHER_CTX_new ()))
621     return FALSE;
622   GST_LOG_OBJECT (filter, "Initialization successful");
623 
624   return TRUE;
625 }
626