diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2013-07-17 15:05:19 +0200 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2013-07-17 22:45:00 +0200 |
commit | 97cf1f6c2854a3a955fd7dd3a1f113deba00c9ef (patch) | |
tree | 900ee64624393d5d9721059b2b62c22c2792190b /crypto/evp/e_des3.c | |
parent | Typo. (diff) | |
download | openssl-97cf1f6c2854a3a955fd7dd3a1f113deba00c9ef.tar.xz openssl-97cf1f6c2854a3a955fd7dd3a1f113deba00c9ef.zip |
EVP support for wrapping algorithms.
Add support for key wrap algorithms via EVP interface.
Generalise AES wrap algorithm and add to modes, making existing
AES wrap algorithm a special case.
Move test code to evptests.txt
Diffstat (limited to 'crypto/evp/e_des3.c')
-rw-r--r-- | crypto/evp/e_des3.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/crypto/evp/e_des3.c b/crypto/evp/e_des3.c index 6b0bd2b367..cfd49bbe7f 100644 --- a/crypto/evp/e_des3.c +++ b/crypto/evp/e_des3.c @@ -374,4 +374,111 @@ const EVP_CIPHER *EVP_des_ede3(void) { return &des_ede3_ecb; } + +#ifndef OPENSSL_NO_SHA + +#include <openssl/sha.h> + +static const unsigned char wrap_iv[8] = {0x4a,0xdd,0xa2,0x2c,0x79,0xe8,0x21,0x05}; + +static int des_ede3_unwrap(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) + { + unsigned char icv[8], iv[8], sha1tmp[SHA_DIGEST_LENGTH]; + int rv = -1; + if (inl < 24) + return -1; + if (!out) + return inl - 16; + memcpy(ctx->iv, wrap_iv, 8); + /* Decrypt first block which will end up as icv */ + des_ede_cbc_cipher(ctx, icv, in, 8); + /* Decrypt central blocks */ + /* If decrypting in place move whole output along a block + * so the next des_ede_cbc_cipher is in place. + */ + if (out == in) + { + memmove(out, out + 8, inl - 8); + in -= 8; + } + des_ede_cbc_cipher(ctx, out, in + 8, inl - 16); + /* Decrypt final block which will be IV */ + des_ede_cbc_cipher(ctx, iv, in + inl - 8, 8); + /* Reverse order of everything */ + BUF_reverse(icv, NULL, 8); + BUF_reverse(out, NULL, inl - 16); + BUF_reverse(ctx->iv, iv, 8); + /* Decrypt again using new IV */ + des_ede_cbc_cipher(ctx, out, out, inl - 16); + des_ede_cbc_cipher(ctx, icv, icv, 8); + /* Work out SHA1 hash of first portion */ + SHA1(out, inl - 16, sha1tmp); + + if (!CRYPTO_memcmp(sha1tmp, icv, 8)) + rv = inl - 16; + OPENSSL_cleanse(icv, 8); + OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH); + OPENSSL_cleanse(iv, 8); + OPENSSL_cleanse(ctx->iv, 8); + if (rv == -1) + OPENSSL_cleanse(out, inl - 16); + + return rv; + } + +static int des_ede3_wrap(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) + { + unsigned char sha1tmp[SHA_DIGEST_LENGTH]; + if (!out) + return inl + 16; + /* Copy input to output buffer + 8 so we have space for IV */ + memmove(out + 8, in, inl); + /* Work out ICV */ + SHA1(in, inl, sha1tmp); + memcpy(out + inl + 8, sha1tmp, 8); + OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH); + /* Generate random IV */ + RAND_bytes(ctx->iv, 8); + memcpy(out, ctx->iv, 8); + /* Encrypt everything after IV in place */ + des_ede_cbc_cipher(ctx, out + 8, out + 8, inl + 8); + BUF_reverse(out, NULL, inl + 16); + memcpy(ctx->iv, wrap_iv, 8); + des_ede_cbc_cipher(ctx, out, out, inl + 16); + return inl + 16; + } + +static int des_ede3_wrap_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inl) + { + /* Sanity check input length: we typically only wrap keys + * so EVP_MAXCHUNK is more than will ever be needed. Also + * input length must be a multiple of 8 bits. + */ + if (inl >= EVP_MAXCHUNK || inl % 8) + return -1; + if (ctx->encrypt) + return des_ede3_wrap(ctx, out, in, inl); + else + return des_ede3_unwrap(ctx, out, in, inl); + } + +static const EVP_CIPHER des3_wrap = { + NID_id_smime_alg_CMS3DESwrap, + 8, 24, 0, + EVP_CIPH_WRAP_MODE|EVP_CIPH_CUSTOM_IV|EVP_CIPH_FLAG_CUSTOM_CIPHER, + des_ede3_init_key, des_ede3_wrap_cipher, + NULL, + sizeof(DES_EDE_KEY), + NULL,NULL,NULL,NULL }; + + +const EVP_CIPHER *EVP_des_ede3_wrap(void) + { + return &des3_wrap; + } + +# endif #endif |