cipher_cyassl.c

00001 /*
00002  * Copyright (c) 2005-2012 by KoanLogic s.r.l. <http://www.koanlogic.com>
00003  * All rights reserved.
00004  *
00005  * This file is part of KLone, and as such it is subject to the license stated
00006  * in the LICENSE file which you have received as part of this distribution.
00007  *
00008  */
00009 
00010 #include "klone_conf.h"
00011 #include <u/libu.h>
00012 #include <klone/codec.h>
00013 #include <klone/ccipher.h>
00014 #include <klone/utils.h>
00015 #include <config.h>
00016 #include <types.h>
00017 #include <ctc_aes.h>
00018 
00019 typedef void (*aes_op_t)(Aes*, byte*, const byte*, word32);
00020 
00021 struct codec_cipher_s
00022 {
00023     codec_t codec;
00024     const EVP_CIPHER *cipher;   /* encryption cipher algorithm */
00025     u_buf_t *ubuf;
00026     Aes aes;
00027     aes_op_t op;
00028     int outready;
00029     size_t off;
00030 };
00031 
00032 
00033 typedef struct codec_cipher_s codec_cipher_t;
00034 
00035 static ssize_t cipher_flush(codec_t *codec, char *dst, size_t *dcount)
00036 {
00037     codec_cipher_t *cc;
00038     size_t sz, len, orig_len, c;
00039     char *ptr, pad;
00040     char padding[AES_BLOCK_SIZE];
00041        
00042     cc = (codec_cipher_t*)codec;
00043 
00044     if(cc->outready == 0)
00045     {
00046         if(cc->op == AesCbcEncrypt)
00047         {
00048             len = (u_buf_len(cc->ubuf)/AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE;
00049             u_buf_reserve(cc->ubuf, len);
00050 
00051             pad = len - u_buf_len(cc->ubuf);
00052 
00053             /* PKCS padding */
00054             memset(padding, pad, AES_BLOCK_SIZE);
00055             dbg_err_if(u_buf_append(cc->ubuf, padding, 
00056                         len-u_buf_len(cc->ubuf)));
00057 
00058             cc->op(&cc->aes, u_buf_ptr(cc->ubuf),
00059                 u_buf_ptr(cc->ubuf), u_buf_len(cc->ubuf));
00060 
00061         } else {
00062 
00063             crit_err_if(u_buf_len(cc->ubuf) % AES_BLOCK_SIZE != 0);
00064 
00065             cc->op(&cc->aes, u_buf_ptr(cc->ubuf),
00066                 u_buf_ptr(cc->ubuf), u_buf_len(cc->ubuf));
00067 
00068             ptr = u_buf_ptr(cc->ubuf);
00069 
00070             pad = ptr[u_buf_len(cc->ubuf) -1];
00071 
00072             /* wrong key? */
00073             dbg_err_if(pad < 1 || pad > 16);
00074 
00075             /* length of the buffer without padding */
00076             len = u_buf_len(cc->ubuf) - pad;
00077 
00078             /* verify that the padding data is what we expect; if not
00079              * then the packet has been corrupted or the key is wrong */
00080             for(c = len; c < u_buf_len(cc->ubuf); c++) 
00081                 dbg_err_if(ptr[c] != pad);
00082 
00083             dbg_err_if(u_buf_shrink(cc->ubuf, len));
00084         }
00085 
00086         cc->outready++;
00087     }
00088 
00089     sz = U_MIN(*dcount, u_buf_len(cc->ubuf) - cc->off);
00090     if(sz)
00091     {
00092         ptr = (char*)u_buf_ptr(cc->ubuf) + cc->off; 
00093         memcpy(dst, ptr, sz);
00094         cc->off += sz;
00095     }
00096 
00097     *dcount = sz;
00098 
00099     return *dcount == 0 ? CODEC_FLUSH_COMPLETE : CODEC_FLUSH_CHUNK;
00100 err:
00101     if(dcount)
00102         *dcount = 0;
00103     return -1;
00104 }
00105 
00106 static ssize_t cipher_transform(codec_t *codec, char *dst, size_t *dcount, 
00107         const char *src, size_t src_sz)
00108 {
00109     codec_cipher_t *cc;
00110        
00111     cc = (codec_cipher_t*)codec;
00112     
00113     dbg_err_if (src == NULL);
00114     dbg_err_if (dst == NULL);
00115     dbg_err_if (dcount == NULL || *dcount == 0);
00116     dbg_err_if (src_sz == 0);
00117 
00118     *dcount = 0; /* zero bytes written out */
00119 
00120     /* stream functions aren't available in cyassl so we must buffer all data
00121      * and emit the ciphertext on cipher_flush() */
00122     dbg_err_if(u_buf_append(cc->ubuf, src, src_sz));
00123 
00124     return src_sz; /* all input bytes consumed */
00125 err:
00126     return -1;
00127 }
00128 
00129 static int cipher_free(codec_t *codec)
00130 {
00131     codec_cipher_t *cc;
00132        
00133     nop_return_if (codec == NULL, 0);   
00134         
00135     cc = (codec_cipher_t*)codec;
00136 
00137     if(cc->ubuf)
00138         u_buf_free(cc->ubuf);
00139 
00140     U_FREE(cc);
00141 
00142     return 0;
00143 }
00144 
00166 int codec_cipher_create(int op, const EVP_CIPHER *cipher, 
00167     unsigned char *key, unsigned char *iv, codec_t **pcc)
00168 {
00169     static unsigned char zero_iv[CODEC_CIPHER_IV_LEN]; /* all zeros */
00170     codec_cipher_t *cc = NULL;
00171 
00172     dbg_return_if (cipher == NULL, ~0);
00173     dbg_return_if (key == NULL, ~0);
00174     /* iv can be NULL */
00175     dbg_return_if (pcc == NULL, ~0);
00176 
00177     if(iv == NULL)
00178         iv = zero_iv; /* iv must be set in AesSetKey */
00179 
00180     cc = u_zalloc(sizeof(codec_cipher_t));
00181     dbg_err_if(cc == NULL);
00182 
00183     cc->codec.transform = cipher_transform;
00184     cc->codec.flush = cipher_flush;
00185     cc->codec.free = cipher_free;      
00186 
00187     cc->cipher = cipher;
00188 
00189     dbg_err_if(u_buf_create(&cc->ubuf));
00190 
00191     /* key lentgh is 256 bits so aes256 will be used */
00192     switch(op)
00193     {
00194     case CIPHER_ENCRYPT:
00195         dbg_err_if(AesSetKey(&cc->aes, key, CODEC_CIPHER_KEY_LEN, iv, 
00196                     AES_ENCRYPTION));
00197 
00198         cc->op = AesCbcEncrypt;
00199         break;
00200     case CIPHER_DECRYPT:
00201         dbg_err_if(AesSetKey(&cc->aes, key, CODEC_CIPHER_KEY_LEN, iv, 
00202                     AES_DECRYPTION));
00203         cc->op = AesCbcDecrypt;
00204         break;
00205     default:
00206         dbg_err_if("bad cipher op");
00207     }
00208 
00209 
00210     *pcc = (codec_t*)cc;
00211 
00212     return 0;
00213 err:
00214     U_FREE(cc);
00215     return ~0;
00216 }
00217 

←Products
Copyright © 2005-2012 - KoanLogic S.r.l. - All rights reserved