cipher.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  * $Id: cipher.c,v 1.11 2007/10/26 08:57:59 tho Exp $
00009  */
00010 
00011 #include "klone_conf.h"
00012 #include <u/libu.h>
00013 #include <klone/codec.h>
00014 #include <klone/ccipher.h>
00015 #include <klone/utils.h>
00016 
00017 enum { CODEC_CIPHER_MAX_INPUT = 4096 /* max src block size for transform() */ };
00018 
00019 typedef int (*EVP_Update_t)(EVP_CIPHER_CTX *ctx, unsigned char *out,
00020     int *outl, const unsigned char *in, int inl);
00021 typedef int (*EVP_Final_ex_t)(EVP_CIPHER_CTX *ctx, unsigned char *out,
00022     int *outl);
00023 
00024 struct codec_cipher_s
00025 {
00026     codec_t codec;
00027     const EVP_CIPHER *cipher;   /* encryption cipher algorithm */
00028     EVP_CIPHER_CTX cipher_ctx;  /* encrypt context */
00029     char *cbuf;
00030     size_t coff, ccount, cbuf_size;
00031     EVP_Update_t update;        /* EVP_{Encrypt,Decrypt}Update func ptr */
00032     EVP_Final_ex_t final;       /* EVP_{Encrypt,Decrypt}Final_ex func ptr */
00033 };
00034 
00035 typedef struct codec_cipher_s codec_cipher_t;
00036 
00037 static void codec_cbufcpy(codec_cipher_t *cc, char *dst, size_t *dcount)
00038 {
00039     size_t count;
00040 
00041     count = U_MIN(*dcount, cc->ccount);
00042 
00043     memcpy(dst, cc->cbuf + cc->coff, count);
00044     cc->ccount -= count;
00045     if(cc->ccount)
00046         cc->coff += count;
00047     else
00048         cc->coff = 0;
00049     *dcount = count;
00050 }
00051 
00052 static ssize_t cipher_flush(codec_t *codec, char *dst, size_t *dcount)
00053 {
00054     codec_cipher_t *cc;
00055     int wr;
00056 
00057     dbg_err_if (codec == NULL);
00058     dbg_err_if (dst == NULL);
00059     dbg_err_if (dcount == NULL);
00060 
00061     cc = (codec_cipher_t*)codec;
00062     
00063     for(;;)
00064     {
00065         if(cc->ccount)
00066         {
00067             codec_cbufcpy(cc, dst, dcount);
00068             return CODEC_FLUSH_CHUNK; /* call flush again */
00069         }
00070 
00071         if(cc->final)
00072         {
00073             wr = -1; /* just used to return an int value */
00074             dbg_err_if(!cc->final(&cc->cipher_ctx, cc->cbuf, &wr));
00075 
00076             cc->ccount += wr;
00077             cc->final = NULL; /* can be called just once */
00078 
00079             if(wr)
00080                 continue;
00081         }
00082         break;
00083     }
00084 
00085     *dcount = 0;
00086     return CODEC_FLUSH_COMPLETE;
00087 err:
00088     return -1;
00089 }
00090 
00091 static ssize_t cipher_transform(codec_t *codec, char *dst, size_t *dcount, 
00092         const char *src, size_t src_sz)
00093 {
00094     codec_cipher_t *cc;
00095     ssize_t c;
00096     int wr;
00097 
00098     dbg_err_if (codec == NULL);
00099     dbg_err_if (src == NULL);
00100     dbg_err_if (dst == NULL); 
00101     dbg_err_if (dcount == NULL || *dcount == 0); 
00102     dbg_err_if (src_sz == 0);
00103 
00104     cc = (codec_cipher_t*)codec;
00105 
00106     c = 0;
00107     for(;;)
00108     {
00109         if(cc->ccount)
00110         {
00111             codec_cbufcpy(cc, dst, dcount);
00112             return c; /* consumed */
00113         }
00114 
00115         /* the cbuf must be empty because we need the whole buffer to be sure to
00116            have enough output space for EVP_{Encrypt,Decrypt}Update */
00117 
00118         c = U_MIN(src_sz, CODEC_CIPHER_MAX_INPUT);
00119 
00120         wr = -1; /* just used to return an int value */
00121         dbg_err_if(!cc->update(&cc->cipher_ctx, cc->cbuf, &wr, src, c));
00122         cc->ccount += wr;
00123 
00124         if(wr == 0)
00125         {
00126             *dcount = 0;
00127             break; /* cipher need more input to produce any output */
00128         }
00129     }
00130 
00131     dbg_err_if(c == 0 && *dcount == 0);
00132     return c;
00133 err:
00134     return -1;
00135 }
00136 
00137 static int cipher_free(codec_t *codec)
00138 {
00139     codec_cipher_t *cc;
00140        
00141     nop_return_if (codec == NULL, 0);   
00142         
00143     cc = (codec_cipher_t*)codec;
00144 
00145     U_FREE(cc->cbuf);
00146     U_FREE(cc);
00147 
00148     return 0;
00149 }
00150 
00172 int codec_cipher_create(int op, const EVP_CIPHER *cipher, 
00173     unsigned char *key, unsigned char *iv, codec_t **pcc)
00174 {
00175     codec_cipher_t *cc = NULL;
00176 
00177     dbg_return_if (cipher == NULL, ~0);
00178     dbg_return_if (key == NULL, ~0);
00179     /* iv can be NULL */
00180     dbg_return_if (pcc == NULL, ~0);
00181 
00182     cc = u_zalloc(sizeof(codec_cipher_t));
00183     dbg_err_if(cc == NULL);
00184 
00185     cc->codec.transform = cipher_transform;
00186     cc->codec.flush = cipher_flush;
00187     cc->codec.free = cipher_free;      
00188 
00189     cc->cipher = cipher;
00190 
00191     /* be sure that the cipher stuff is loaded */
00192     EVP_add_cipher(cc->cipher);
00193 
00194     EVP_CIPHER_CTX_init(&cc->cipher_ctx);
00195 
00196     cc->cbuf_size = CODEC_CIPHER_MAX_INPUT + 
00197         EVP_CIPHER_block_size(cc->cipher) -1;
00198 
00199     cc->cbuf = u_malloc(cc->cbuf_size);
00200     dbg_err_if(cc->cbuf == NULL);
00201 
00202     switch(op)
00203     {
00204     case CIPHER_ENCRYPT:
00205         dbg_err_if(!EVP_EncryptInit_ex(&cc->cipher_ctx, cc->cipher, NULL, 
00206             key, iv));
00207         cc->update = EVP_EncryptUpdate;
00208         cc->final = EVP_EncryptFinal_ex;
00209         break;
00210     case CIPHER_DECRYPT:
00211         dbg_err_if(!EVP_DecryptInit_ex(&cc->cipher_ctx, cc->cipher, NULL, 
00212             key, iv));
00213         cc->update = EVP_DecryptUpdate;
00214         cc->final = EVP_DecryptFinal_ex;
00215         break;
00216     default:
00217         dbg_err_if("bad cipher op");
00218     }
00219 
00220 
00221     *pcc = (codec_t*)cc;
00222 
00223     return 0;
00224 err:
00225     U_FREE(cc);
00226     return ~0;
00227 }
00228 

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