LCOV - code coverage report
Current view: top level - src/base - pdf-stm-f-aesv2.c (source / functions) Hit Total Coverage
Test: libgnupdf.info Lines: 82 104 78.8 %
Date: 2011-12-09 Functions: 7 7 100.0 %
Branches: 47 79 59.5 %

           Branch data     Line data    Source code
       1                 :            : /* -*- mode: C -*-
       2                 :            :  *
       3                 :            :  *       File:         pdf-stm-f-aesv2.c
       4                 :            :  *       Date:         Sun Dec 14 20:13:53 2008
       5                 :            :  *
       6                 :            :  *       GNU PDF Library - AESV2 stream filter
       7                 :            :  *
       8                 :            :  */
       9                 :            : 
      10                 :            : /* Copyright (C) 2008, 2009 Free Software Foundation, Inc. */
      11                 :            : 
      12                 :            : /* This program is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU General Public License as published by
      14                 :            :  * the Free Software Foundation, either version 3 of the License, or
      15                 :            :  * (at your option) any later version.
      16                 :            :  *
      17                 :            :  * This program is distributed in the hope that it will be useful,
      18                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      19                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20                 :            :  * GNU General Public License for more details.
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU General Public License
      23                 :            :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24                 :            :  */
      25                 :            : 
      26                 :            : #include <config.h>
      27                 :            : 
      28                 :            : #include <stdlib.h>
      29                 :            : #include <string.h>
      30                 :            : 
      31                 :            : #include <pdf-types.h>
      32                 :            : #include <pdf-types-buffer.h>
      33                 :            : #include <pdf-hash.h>
      34                 :            : #include <pdf-alloc.h>
      35                 :            : #include <pdf-crypt.h>
      36                 :            : #include <pdf-stm-f-aesv2.h>
      37                 :            : #include <pdf-hash-helper.h>
      38                 :            : 
      39                 :            : /* Define AESv2 encoder */
      40                 :         10 : PDF_STM_FILTER_DEFINE (pdf_stm_f_aesv2enc_get,
      41                 :            :                        stm_f_aesv2_init,
      42                 :            :                        stm_f_aesv2enc_apply,
      43                 :            :                        stm_f_aesv2_deinit);
      44                 :            : 
      45                 :            : /* Define AESv2 decoder */
      46                 :         10 : PDF_STM_FILTER_DEFINE (pdf_stm_f_aesv2dec_get,
      47                 :            :                        stm_f_aesv2_init,
      48                 :            :                        stm_f_aesv2dec_apply,
      49                 :            :                        stm_f_aesv2_deinit);
      50                 :            : 
      51                 :            : #define AESV2_CACHE_SIZE     16
      52                 :            : #define AESv2_PARAM_KEY      "Key"
      53                 :            : #define AESv2_PARAM_KEY_SIZE "KeySize"
      54                 :            : 
      55                 :            : /* Encryption and decryption  */
      56                 :            : typedef enum {
      57                 :            :     PDF_STM_F_AESV2_MODE_ENCODE,
      58                 :            :     PDF_STM_F_AESV2_MODE_DECODE
      59                 :            : } pdf_stm_f_aesv2_mode_e;
      60                 :            : 
      61                 :            : /* Internal state */
      62                 :            : struct pdf_stm_f_aesv2_s
      63                 :            : {
      64                 :            :   pdf_crypt_cipher_t *cipher;
      65                 :            : 
      66                 :            :   pdf_buffer_t *in_cache;
      67                 :            :   pdf_buffer_t *out_cache;
      68                 :            : 
      69                 :            :   pdf_char_t *key;
      70                 :            :   pdf_size_t keysize;
      71                 :            : };
      72                 :            : 
      73                 :            : /* Common implementation */
      74                 :            : 
      75                 :            : static pdf_bool_t
      76                 :         20 : stm_f_aesv2_init (const pdf_hash_t  *params,
      77                 :            :                   void             **state,
      78                 :            :                   pdf_error_t      **error)
      79                 :            : {
      80                 :            :   struct pdf_stm_f_aesv2_s *filter_state;
      81                 :            :   const pdf_char_t *key;
      82                 :            :   pdf_size_t keysize;
      83                 :            : 
      84                 :            :   /* We demand all parameters are present */
      85 [ +  - ][ +  - ]:         20 :   if (!params ||
                 [ -  + ]
      86                 :            :       !pdf_hash_key_p (params, AESv2_PARAM_KEY) ||
      87                 :            :       !pdf_hash_key_p (params, AESv2_PARAM_KEY))
      88                 :            :     {
      89 [ #  # ][ #  # ]:          0 :       pdf_set_error (error,
         [ #  # ][ #  # ]
      90                 :            :                      PDF_EDOMAIN_BASE_STM,
      91                 :            :                      PDF_EBADDATA,
      92                 :            :                      "cannot initialize AESv2 encoder/decoder: "
      93                 :            :                      "parameters missing ('Key': %s, 'KeySize': %s)",
      94                 :            :                      ((params && pdf_hash_key_p (params, AESv2_PARAM_KEY)) ?
      95                 :            :                       "available" : "missing"),
      96                 :            :                      ((params && pdf_hash_key_p (params, AESv2_PARAM_KEY_SIZE)) ?
      97                 :            :                       "available" : "missing"));
      98                 :          0 :       return PDF_FALSE;
      99                 :            :     }
     100                 :            : 
     101                 :         20 :   filter_state = pdf_alloc (sizeof (struct pdf_stm_f_aesv2_s));
     102         [ -  + ]:         20 :   if (!filter_state)
     103                 :            :     {
     104                 :          0 :       pdf_set_error (error,
     105                 :            :                      PDF_EDOMAIN_BASE_STM,
     106                 :            :                      PDF_ENOMEM,
     107                 :            :                      "cannot create AESv2 encoder/decoder internal state: "
     108                 :            :                      "couldn't allocate %lu bytes",
     109                 :            :                      (unsigned long)sizeof (struct pdf_stm_f_aesv2_s));
     110                 :          0 :       return PDF_FALSE;
     111                 :            :     }
     112                 :            : 
     113                 :            :   /* Initialize cache buffers */
     114                 :         20 :   filter_state->in_cache = pdf_buffer_new (AESV2_CACHE_SIZE, error);
     115         [ -  + ]:         20 :   if (!(filter_state->in_cache))
     116                 :            :     {
     117                 :          0 :       stm_f_aesv2_deinit (filter_state);
     118                 :          0 :       return PDF_FALSE;
     119                 :            :     }
     120                 :         20 :   filter_state->out_cache = pdf_buffer_new (AESV2_CACHE_SIZE, error);
     121         [ -  + ]:         20 :   if (!(filter_state->out_cache))
     122                 :            :     {
     123                 :          0 :       stm_f_aesv2_deinit (filter_state);
     124                 :          0 :       return PDF_FALSE;
     125                 :            :     }
     126                 :            : 
     127                 :            :   /* Note that Key may NOT be NUL-terminated */
     128                 :         20 :   key = pdf_hash_get_value (params, AESv2_PARAM_KEY);
     129                 :         20 :   keysize = pdf_hash_get_size (params, AESv2_PARAM_KEY_SIZE);
     130                 :            : 
     131                 :            :   /* Keep a copy of the key in the filter */
     132                 :         20 :   filter_state->key = (pdf_char_t *)pdf_alloc (keysize);
     133         [ -  + ]:         20 :   if (!filter_state->key)
     134                 :            :     {
     135                 :          0 :       pdf_set_error (error,
     136                 :            :                      PDF_EDOMAIN_BASE_STM,
     137                 :            :                      PDF_ENOMEM,
     138                 :            :                      "cannot copy AESv2 key: "
     139                 :            :                      "couldn't allocate %lu bytes",
     140                 :            :                      (unsigned long)keysize);
     141                 :          0 :       stm_f_aesv2_deinit (filter_state);
     142                 :          0 :       return PDF_FALSE;
     143                 :            :     }
     144                 :         20 :   filter_state->keysize = keysize;
     145                 :         20 :   memcpy (filter_state->key, key, keysize);
     146                 :            : 
     147                 :         20 :   filter_state->cipher = pdf_crypt_cipher_new (PDF_CRYPT_CIPHER_ALGO_AESV2, error);
     148         [ -  + ]:         20 :   if (!filter_state->cipher)
     149                 :            :     {
     150                 :          0 :       stm_f_aesv2_deinit (filter_state);
     151                 :          0 :       return PDF_FALSE;
     152                 :            :     }
     153                 :            : 
     154         [ -  + ]:         20 :   if (!pdf_crypt_cipher_set_key (filter_state->cipher,
     155                 :            :                                  filter_state->key,
     156                 :            :                                  filter_state->keysize,
     157                 :            :                                  error))
     158                 :            :     {
     159                 :          0 :       stm_f_aesv2_deinit (filter_state);
     160                 :          0 :       return PDF_FALSE;
     161                 :            :     }
     162                 :            : 
     163                 :         20 :   *state = filter_state;
     164                 :         20 :   return PDF_TRUE;
     165                 :            : }
     166                 :            : 
     167                 :            : static void
     168                 :         20 : stm_f_aesv2_deinit (void *state)
     169                 :            : {
     170                 :         20 :   struct pdf_stm_f_aesv2_s *filter_state = state;
     171                 :            : 
     172         [ +  - ]:         20 :   if (filter_state->cipher)
     173                 :         20 :     pdf_crypt_cipher_destroy (filter_state->cipher);
     174         [ +  - ]:         20 :   if (filter_state->in_cache)
     175                 :         20 :     pdf_buffer_destroy (filter_state->in_cache);
     176         [ +  - ]:         20 :   if (filter_state->out_cache)
     177                 :         20 :     pdf_buffer_destroy (filter_state->out_cache);
     178         [ +  - ]:         20 :   if (filter_state->key)
     179                 :         20 :     pdf_dealloc (filter_state->key);
     180                 :         20 :   pdf_dealloc (state);
     181                 :         20 : }
     182                 :            : 
     183                 :            : static enum pdf_stm_filter_apply_status_e
     184                 :         60 : stm_f_aesv2_apply (pdf_stm_f_aesv2_mode_e   mode,
     185                 :            :                    void                    *state,
     186                 :            :                    pdf_buffer_t            *in,
     187                 :            :                    pdf_buffer_t            *out,
     188                 :            :                    pdf_bool_t               finish,
     189                 :            :                    pdf_error_t            **error)
     190                 :            : {
     191                 :         60 :   struct pdf_stm_f_aesv2_s *filter_state = state;
     192                 :         60 :   pdf_crypt_cipher_t *cipher = filter_state->cipher;
     193                 :         60 :   pdf_buffer_t *in_cache = filter_state->in_cache;
     194                 :         60 :   pdf_buffer_t *out_cache = filter_state->out_cache;
     195                 :            : 
     196                 :            :   while (PDF_TRUE)
     197                 :            :     {
     198                 :            :       pdf_size_t in_size;
     199                 :            :       pdf_size_t out_size;
     200                 :            :       pdf_size_t in_cache_size;
     201                 :            :       pdf_size_t out_cache_size;
     202                 :            :       pdf_size_t bytes_to_read;
     203                 :            :       pdf_size_t bytes_to_write;
     204                 :            : 
     205         [ -  + ]:        100 :       PDF_ASSERT (in->wp >= in->rp);
     206         [ -  + ]:        100 :       PDF_ASSERT (out->size >= out->wp);
     207                 :            : 
     208                 :            :       /* TODO: Shouldn't this be like this?
     209                 :            :        *   in_size = in->size - in->rp;
     210                 :            :        */
     211                 :        100 :       in_size = in->wp - in->rp;
     212                 :        100 :       in_cache_size = in_cache->size - in_cache->wp;
     213                 :        100 :       bytes_to_read = PDF_MIN (in_size, in_cache_size);
     214                 :            : 
     215                 :            :       /* Read bytes from IN and fill IN_CACHE */
     216                 :        100 :       memcpy (in_cache->data + in_cache->wp,
     217                 :            :               in->data       + in->rp,
     218                 :            :               bytes_to_read);
     219                 :            : 
     220                 :        100 :       in_cache->wp += bytes_to_read;
     221                 :        100 :       in->rp       += bytes_to_read;
     222                 :            : 
     223                 :            :       /* If we cannot fill all IN_CACHE... */
     224         [ +  + ]:        100 :       if (!pdf_buffer_full_p (in_cache))
     225                 :            :         {
     226 [ +  + ][ +  + ]:         50 :           if (finish &&
                 [ -  + ]
     227                 :            :               mode == PDF_STM_F_AESV2_MODE_DECODE &&
     228                 :         10 :               in_cache->wp > 0)
     229                 :            :             {
     230                 :            :               /* TODO: Better error explanation */
     231                 :          0 :               pdf_set_error (error,
     232                 :            :                              PDF_EDOMAIN_BASE_STM,
     233                 :            :                              PDF_ERROR,
     234                 :            :                              "");
     235                 :          0 :               return PDF_STM_FILTER_APPLY_STATUS_ERROR;
     236                 :            :             }
     237                 :            : 
     238                 :            :           /* ...pad the cache if we have reached EOD */
     239 [ +  + ][ +  + ]:         50 :           if (finish &&
                 [ +  - ]
     240                 :            :               mode == PDF_STM_F_AESV2_MODE_ENCODE &&
     241                 :            :               !pdf_buffer_full_p (in_cache))
     242                 :            :             {
     243                 :            :               pdf_size_t padding;
     244                 :            : 
     245                 :         10 :               padding = in_cache->size - in_cache->wp;
     246                 :         10 :               memset (in_cache->data + in_cache->wp,
     247                 :            :                       padding,
     248                 :            :                       padding);
     249                 :            : 
     250                 :         10 :               in_cache->wp += padding;
     251                 :            :             }
     252                 :            :           else
     253                 :            :             {
     254         [ +  + ]:         40 :               if (pdf_buffer_eob_p (out_cache))
     255                 :         30 :                 return PDF_STM_FILTER_APPLY_STATUS_NO_INPUT; /* ...ask more input */
     256                 :            :             }
     257                 :            :         }
     258                 :            : 
     259                 :            :       /* If OUT_CACHE is empty and IN_CACHE is full, then it is ready
     260                 :            :        * to be processed. */
     261 [ +  + ][ +  - ]:         70 :       if (pdf_buffer_full_p (in_cache) &&
     262                 :            :           pdf_buffer_eob_p (out_cache))
     263                 :            :         {
     264      [ +  +  - ]:         60 :           switch (mode)
     265                 :            :             {
     266                 :            :             case PDF_STM_F_AESV2_MODE_ENCODE:
     267         [ -  + ]:         30 :               if (!pdf_crypt_cipher_encrypt (cipher,
     268                 :            :                                              (pdf_char_t *)out_cache->data,
     269                 :            :                                              out_cache->size,
     270                 :            :                                              (const pdf_char_t *)in_cache->data,
     271                 :            :                                              in_cache->size,
     272                 :            :                                              NULL,
     273                 :            :                                              error))
     274                 :          0 :                 return PDF_STM_FILTER_APPLY_STATUS_ERROR;
     275                 :            :               break;
     276                 :            : 
     277                 :            :             case PDF_STM_F_AESV2_MODE_DECODE:
     278         [ -  + ]:         30 :               if (!pdf_crypt_cipher_decrypt (cipher,
     279                 :            :                                              (pdf_char_t *)out_cache->data,
     280                 :            :                                              out_cache->size,
     281                 :            :                                              (const pdf_char_t *)in_cache->data,
     282                 :            :                                              in_cache->size,
     283                 :            :                                              NULL,
     284                 :            :                                              error))
     285                 :          0 :                 return PDF_STM_FILTER_APPLY_STATUS_ERROR;
     286                 :            :               break;
     287                 :            :             }
     288                 :            : 
     289                 :            :           /* Both cache are full now */
     290                 :         60 :           pdf_buffer_rewind (in_cache);
     291                 :         60 :           out_cache->wp = out_cache->size;
     292                 :            :         }
     293                 :            : 
     294                 :            :       /* When we are decrypting data, we need know what block is the
     295                 :            :        * last. If both IN and IN_CACHE are empty, then OUT_CACHE could
     296                 :            :        * hold it. So, we ask more input to we make sure.*/
     297 [ +  + ][ +  + ]:         70 :       if (mode == PDF_STM_F_AESV2_MODE_DECODE &&
                 [ +  - ]
     298                 :            :           pdf_buffer_eob_p (in) &&
     299                 :            :           pdf_buffer_eob_p (in_cache))
     300                 :            :         {
     301                 :            :           /* When we know it is the last, remove the padding. */
     302         [ +  + ]:         20 :           if (finish)
     303                 :            :             {
     304                 :            :               pdf_size_t padding;
     305                 :            : 
     306                 :         10 :               padding = out_cache->data[out_cache->size - 1];
     307         [ -  + ]:         10 :               if (padding > AESV2_CACHE_SIZE)
     308                 :            :                 {
     309                 :          0 :                   pdf_set_error (error,
     310                 :            :                                  PDF_EDOMAIN_BASE_STM,
     311                 :            :                                  PDF_ERROR,
     312                 :            :                                  "Padding longer than AESv2 cache (%lu > %lu)",
     313                 :            :                                  (unsigned long)padding,
     314                 :            :                                  (unsigned long)AESV2_CACHE_SIZE);
     315                 :          0 :                   return PDF_STM_FILTER_APPLY_STATUS_ERROR;
     316                 :            :                 }
     317                 :            : 
     318                 :         10 :               out_cache->wp = out_cache->size - padding;
     319                 :            :             }
     320                 :            :           else /* Ask for more input */
     321                 :         10 :             return PDF_STM_FILTER_APPLY_STATUS_NO_INPUT;
     322                 :            :         }
     323                 :            : 
     324                 :            :       /* Finally, we fill the OUT buffer */
     325                 :         60 :       out_size = out->size - out->wp;
     326                 :         60 :       out_cache_size = out_cache->wp - out_cache->rp;
     327                 :         60 :       bytes_to_write = PDF_MIN (out_size, out_cache_size);
     328                 :            : 
     329                 :         60 :       memcpy (out->data + out->wp,
     330                 :            :               out_cache->data + out_cache->rp,
     331                 :            :               bytes_to_write);
     332                 :            : 
     333                 :         60 :       out_cache->rp += bytes_to_write;
     334                 :         60 :       out->wp       += bytes_to_write;
     335                 :            : 
     336         [ +  + ]:         60 :       if (finish)
     337                 :         20 :         return PDF_STM_FILTER_APPLY_STATUS_EOF;
     338                 :            : 
     339         [ -  + ]:         40 :       if (pdf_buffer_full_p (out))
     340                 :          0 :         return PDF_STM_FILTER_APPLY_STATUS_NO_OUTPUT;
     341                 :            : 
     342                 :            :       /* Continue loop */
     343                 :         40 :       pdf_buffer_rewind (out_cache);
     344                 :        100 :     }
     345                 :            : }
     346                 :            : 
     347                 :            : /* Encode filter */
     348                 :            : 
     349                 :            : static enum pdf_stm_filter_apply_status_e
     350                 :         30 : stm_f_aesv2enc_apply (void          *state,
     351                 :            :                       pdf_buffer_t  *in,
     352                 :            :                       pdf_buffer_t  *out,
     353                 :            :                       pdf_bool_t     finish,
     354                 :            :                       pdf_error_t  **error)
     355                 :            : {
     356                 :         30 :   return stm_f_aesv2_apply (PDF_STM_F_AESV2_MODE_ENCODE,
     357                 :            :                             state,
     358                 :            :                             in,
     359                 :            :                             out,
     360                 :            :                             finish,
     361                 :            :                             error);
     362                 :            : }
     363                 :            : 
     364                 :            : /* Decode filter  */
     365                 :            : 
     366                 :            : static enum pdf_stm_filter_apply_status_e
     367                 :         30 : stm_f_aesv2dec_apply (void          *state,
     368                 :            :                       pdf_buffer_t  *in,
     369                 :            :                       pdf_buffer_t  *out,
     370                 :            :                       pdf_bool_t     finish,
     371                 :            :                       pdf_error_t  **error)
     372                 :            : {
     373                 :         30 :   return stm_f_aesv2_apply (PDF_STM_F_AESV2_MODE_DECODE,
     374                 :            :                             state,
     375                 :            :                             in,
     376                 :            :                             out,
     377                 :            :                             finish,
     378                 :            :                             error);
     379                 :            : }
     380                 :            : 
     381                 :            : /* End of pdf_stm_f_aesv2.c */

Generated by: LCOV version 1.8