Main Page Modules Data Structures File List Data Fields Globals Related Pages

# beecrypt/dhaes.c

Go to the documentation of this file.

    00001
    00030 /*
    00031  * Copyright (c) 2000, 2001 Virtual Unlimited, B.V.
    00032  *
    00033  * Author: Bob Deblier <bob@virtualunlimited.com>
    00034  *
    00035  * This library is free software; you can redistribute it and/or
    00036  * modify it under the terms of the GNU Lesser General Public
    00037  * License as published by the Free Software Foundation; either
    00038  * version 2.1 of the License, or (at your option) any later version.
    00039  *
    00040  * This library is distributed in the hope that it will be useful,
    00041  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    00042  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00043  * Lesser General Public License for more details.
    00044  *
    00045  * You should have received a copy of the GNU Lesser General Public
    00046  * License along with this library; if not, write to the Free Software
    00047  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00048  *
    00049  */
    00050
    00051 #include "system.h"
    00052 #include "dhaes.h"
    00053 #include "dlsvdp-dh.h"
    00054 #include "blockmode.h"
    00055 #include "blockpad.h"
    00056 #include "debug.h"
    00057
    00058 int dhaes_pUsable(const dhaes_pParameters* params)
    00059 {
    00060         int keybits = (params->hash->digestsize << 3); /* digestsize in bytes times 8 bits */
    00061         int cipherkeybits = params->cipherkeybits;
    00062         int mackeybits = params->mackeybits;
    00063
    00064         /* test if keybits is a multiple of 32 */
    00065         if ((keybits & 31) != 0)
    00066                 return 0;
    00067
    00068         /* test if cipherkeybits + mackeybits < keybits */
    00069         if ((cipherkeybits + mackeybits) > keybits)
    00070                 return 0;
    00071
    00072         if (mackeybits == 0)
    00073         {
    00074                 if (cipherkeybits == 0)
    00075                         cipherkeybits = mackeybits = (((uint32)keybits) >> 1);
    00076                 else
    00077                         mackeybits = keybits - cipherkeybits;
    00078         }
    00079
    00080         /* test if keybits length is appropriate for cipher */
    00081         if ((cipherkeybits < params->cipher->keybitsmin) ||
    00082                         (cipherkeybits > params->cipher->keybitsmax))
    00083                 return 0;
    00084
    00085         if (((cipherkeybits - params->cipher->keybitsmin) % params->cipher->keybitsinc) != 0)
    00086                 return 0;
    00087
    00088         /* test if keybits length is appropriate for mac */
    00089         if ((mackeybits < params->mac->keybitsmin) ||
    00090                         (params->mackeybits > params->mac->keybitsmax))
    00091                 return 0;
    00092
    00093         if (((mackeybits - params->mac->keybitsmin) % params->mac->keybitsinc) != 0)
    00094                 return 0;
    00095
    00096         return 1;
    00097 }
    00098
    00099 int dhaes_pContextInit(dhaes_pContext* ctxt, const dhaes_pParameters* params)
    00100 {
    00101         if (ctxt == (dhaes_pContext*) 0)
    00102                 return -1;
    00103
    00104         if (params == (dhaes_pParameters*) 0)
    00105                 return -1;
    00106
    00107         if (params->param == (dldp_p*) 0)
    00108                 return -1;
    00109
    00110         if (params->hash == (hashFunction*) 0)
    00111                 return -1;
    00112
    00113         if (params->cipher == (blockCipher*) 0)
    00114                 return -1;
    00115
    00116         if (params->mac == (keyedHashFunction*) 0)
    00117                 return -1;
    00118
    00119         if (!dhaes_pUsable(params))
    00120                 return -1;
    00121
    00122         (void) dldp_pInit(&ctxt->param);
    00123         (void) dldp_pCopy(&ctxt->param, params->param);
    00124
    00125         mp32nzero(&ctxt->pub);
    00126         mp32nzero(&ctxt->pri);
    00127
    00128         /*@-modobserver@*/
    00129         if (hashFunctionContextInit(&ctxt->hash, params->hash))
    00130                 return -1;
    00131
    00132         if (blockCipherContextInit(&ctxt->cipher, params->cipher))
    00133                 return -1;
    00134
    00135         if (keyedHashFunctionContextInit(&ctxt->mac, params->mac))
    00136                 return -1;
    00137         /*@=modobserver@*/
    00138
    00139         ctxt->cipherkeybits = params->cipherkeybits;
    00140         ctxt->mackeybits = params->mackeybits;
    00141
    00142         return 0;
    00143 }
    00144
    00145 int dhaes_pContextInitDecrypt(dhaes_pContext* ctxt, const dhaes_pParameters* params, const mp32number* pri)
    00146 {
    00147         if (dhaes_pContextInit(ctxt, params))
    00148                 return -1;
    00149
    00150         mp32ncopy(&ctxt->pri, pri);
    00151
    00152         return 0;
    00153 }
    00154
    00155 int dhaes_pContextInitEncrypt(dhaes_pContext* ctxt, const dhaes_pParameters* params, const mp32number* pub)
    00156 {
    00157         if (dhaes_pContextInit(ctxt, params))
    00158                 return -1;
    00159
    00160         mp32ncopy(&ctxt->pub, pub);
    00161
    00162         return 0;
    00163 }
    00164
    00165 int dhaes_pContextFree(dhaes_pContext* ctxt)
    00166 {
    00167         (void) dldp_pFree(&ctxt->param);
    00168
    00169         mp32nfree(&ctxt->pub);
    00170         mp32nfree(&ctxt->pri);
    00171
    00172         /*@-mustfree -modobserver @*/ /* ctxt is OK */
    00173         if (hashFunctionContextFree(&ctxt->hash))
    00174                 return -1;
    00175
    00176         if (blockCipherContextFree(&ctxt->cipher))
    00177                 return -1;
    00178
    00179         if (keyedHashFunctionContextFree(&ctxt->mac))
    00180                 return -1;
    00181
    00182         return 0;
    00183         /*@=mustfree =modobserver @*/
    00184 }
    00185
    00188 static int dhaes_pContextSetup(dhaes_pContext* ctxt, const mp32number* privkey, const mp32number* pubkey, const mp32number* message, cipherOperation op)
    00189         /*@modifies ctxt @*/
    00190 {
    00191         register int rc;
    00192
    00193         mp32number secret;
    00194         mp32number digest;
    00195
    00196         /* compute the shared secret, Diffie-Hellman style */
    00197         mp32nzero(&secret);
    00198         if (dlsvdp_pDHSecret(&ctxt->param, privkey, pubkey, &secret))
    00199                 /*@-mustfree@*/ /* FIX: secret.data leak? */
    00200                 return -1;
    00201                 /*@=mustfree@*/
    00202
    00203         /* compute the hash of the message (ephemeral public) key and the shared secret */
    00204         mp32nzero(&digest);
    00205         (void) hashFunctionContextReset     (&ctxt->hash);
    00206         (void) hashFunctionContextUpdateMP32(&ctxt->hash, message);
    00207         (void) hashFunctionContextUpdateMP32(&ctxt->hash, &secret);
    00208         (void) hashFunctionContextDigest    (&ctxt->hash, &digest);
    00209
    00210         /* we don't need the secret anymore */
    00211         mp32nwipe(&secret);
    00212         mp32nfree(&secret);
    00213
    00225         /*@-usedef@*/   /* LCL: digest already set */
    00226         if (digest.size > 0)
    00227         {
    00228                 uint32* mackey = digest.data;
    00229                 uint32* cipherkey = digest.data + (((uint32)(ctxt->mackeybits + 31)) >> 5);
    00230
    00231                 if ((rc = keyedHashFunctionContextSetup(&ctxt->mac, mackey, ctxt->mackeybits)))
    00232                         goto setup_end;
    00233
    00234                 if ((rc = blockCipherContextSetup(&ctxt->cipher, cipherkey, ctxt->cipherkeybits, op)))
    00235                         goto setup_end;
    00236
    00237                 rc = 0;
    00238         }
    00239         else
    00240                 rc = -1;
    00241         /*@=usedef@*/
    00242
    00243 setup_end:
    00244         mp32nwipe(&digest);
    00245         mp32nfree(&digest);
    00246
    00247         /*@-mustfree@*/ /* {secret,digest}.data are OK */
    00248         return rc;
    00249         /*@=mustfree@*/
    00250 }
    00251
    00252 memchunk* dhaes_pContextEncrypt(dhaes_pContext* ctxt, mp32number* ephemeralPublicKey, mp32number* mac, const memchunk* cleartext, randomGeneratorContext* rng)
    00253 {
    00254         memchunk* ciphertext = (memchunk*) 0;
    00255         memchunk* paddedtext;
    00256
    00257         mp32number ephemeralPrivateKey;
    00258
    00259         /* make the ephemeral keypair */
    00260         mp32nzero(&ephemeralPrivateKey);
    00261         (void) dldp_pPair(&ctxt->param, rng, &ephemeralPrivateKey, ephemeralPublicKey);
    00262
    00263         /* Setup the key and initialize the mac and the blockcipher */
    00264         if (dhaes_pContextSetup(ctxt, &ephemeralPrivateKey, &ctxt->pub, ephemeralPublicKey, ENCRYPT))
    00265                 goto encrypt_end;
    00266
    00267         /* add pkcs-5 padding */
    00268         paddedtext = pkcs5PadCopy(ctxt->cipher.algo->blocksize, cleartext);
    00269         if (paddedtext == (memchunk*) 0)
    00270                 goto encrypt_end;
    00271
    00272         /* encrypt the memchunk in CBC mode */
    00273         if (blockEncrypt(ctxt->cipher.algo, ctxt->cipher.param, CBC, paddedtext->size / ctxt->cipher.algo->blocksize, (uint32*) paddedtext->data, (const uint32*) paddedtext->data))
    00274         {
    00275                 free(paddedtext->data);
    00276                 free(paddedtext);
    00277                 goto encrypt_end;
    00278         }
    00279
    00280         /* Compute the mac */
    00281         if (keyedHashFunctionContextUpdateMC(&ctxt->mac, paddedtext))
    00282         {
    00283                 free(paddedtext->data);
    00284                 free(paddedtext);
    00285                 goto encrypt_end;
    00286         }
    00287
    00288         if (keyedHashFunctionContextDigest(&ctxt->mac, mac))
    00289         {
    00290                 free(paddedtext->data);
    00291                 free(paddedtext);
    00292                 goto encrypt_end;
    00293         }
    00294
    00295         ciphertext = paddedtext;
    00296
    00297 encrypt_end:
    00298         mp32nwipe(&ephemeralPrivateKey);
    00299         mp32nfree(&ephemeralPrivateKey);
    00300
    00301         /*@-mustfree@*/ /* ephemeralPrivateKey.data is OK */
    00302         return ciphertext;
    00303         /*@=mustfree@*/
    00304 }
    00305
    00306 memchunk* dhaes_pContextDecrypt(dhaes_pContext* ctxt, const mp32number* ephemeralPublicKey, const mp32number* mac, const memchunk* ciphertext)
    00307 {
    00308         memchunk* cleartext = (memchunk*) 0;
    00309         memchunk* paddedtext;
    00310
    00311         /* Setup the key and initialize the mac and the blockcipher */
    00312         if (dhaes_pContextSetup(ctxt, &ctxt->pri, ephemeralPublicKey, ephemeralPublicKey, DECRYPT))
    00313                 goto decrypt_end;
    00314
    00315         /* Verify the mac */
    00316         if (keyedHashFunctionContextUpdateMC(&ctxt->mac, ciphertext))
    00317                 goto decrypt_end;
    00318
    00319         if (keyedHashFunctionContextDigestMatch(&ctxt->mac, mac) == 0)
    00320                 goto decrypt_end;
    00321
    00322         /* decrypt the memchunk with CBC mode */
    00323         /*@-sizeoftype@*/
    00324         paddedtext = (memchunk*) calloc(1, sizeof(memchunk));
    00325         /*@=sizeoftype@*/
    00326
    00327         if (paddedtext == (memchunk*) 0)
    00328                 goto decrypt_end;
    00329
    00330         paddedtext->size = ciphertext->size;
    00331         /*@-mustfree@*/ /* paddedtext->data is OK */
    00332         paddedtext->data = (byte*) malloc(ciphertext->size);
    00333         /*@=mustfree@*/
    00334
    00335         if (paddedtext->data == (byte*) 0)
    00336         {
    00337                 free(paddedtext);
    00338                 goto decrypt_end;
    00339         }
    00340
    00341         if (blockDecrypt(ctxt->cipher.algo, ctxt->cipher.param, CBC, paddedtext->size / ctxt->cipher.algo->blocksize, (uint32*) paddedtext->data, (const uint32*) ciphertext->data))
    00342         {
    00343                 free(paddedtext->data);
    00344                 free(paddedtext);
    00345                 goto decrypt_end;
    00346         }
    00347
    00348         /* remove pkcs-5 padding */
    00349         cleartext = pkcs5Unpad(ctxt->cipher.algo->blocksize, paddedtext);
    00350
    00351         if (cleartext == (memchunk*) 0)
    00352         {
    00353                 free(paddedtext->data);
    00354                 free(paddedtext);
    00355         }
    00356
    00357 decrypt_end:
    00358
    00359         /*@-usereleased@*/ /* LCL: cleartext released??? */
    00360         return cleartext;
    00361         /*@=usereleased@*/
    00362 }