X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fevp%2Fe_aes.c;h=ba3d43b9fa9492a9dae19cde4375386624d553dc;hp=a7d4ce4420399ecb3bcb0925e5419de0f0fd2972;hb=68c29f61a404db3d620278878d77ca90ad853b8d;hpb=a42abde6993849f82945dc55af5bc1de413f7393 diff --git a/crypto/evp/e_aes.c b/crypto/evp/e_aes.c index a7d4ce4420..ba3d43b9fa 100644 --- a/crypto/evp/e_aes.c +++ b/crypto/evp/e_aes.c @@ -1,5 +1,5 @@ /* ==================================================================== - * Copyright (c) 2001-2011 The OpenSSL Project. All rights reserved. + * Copyright (c) 2001-2014 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,7 +48,7 @@ * */ -#define OPENSSL_FIPSAPI + #include #ifndef OPENSSL_NO_AES @@ -107,6 +107,25 @@ typedef struct ccm128_f str; } EVP_AES_CCM_CTX; +#ifndef OPENSSL_NO_OCB +typedef struct + { + AES_KEY ksenc; /* AES key schedule to use for encryption */ + AES_KEY ksdec; /* AES key schedule to use for decryption */ + int key_set; /* Set if key initialised */ + int iv_set; /* Set if an iv is set */ + OCB128_CONTEXT ocb; + unsigned char *iv; /* Temporary IV store */ + unsigned char tag[16]; + unsigned char data_buf[16]; /* Store partial data blocks */ + unsigned char aad_buf[16]; /* Store partial AAD blocks */ + int data_buf_len; + int aad_buf_len; + int ivlen; /* IV length */ + int taglen; + } EVP_AES_OCB_CTX; +#endif + #define MAXBITCHUNK ((size_t)1<<(sizeof(size_t)*8-4)) #ifdef VPAES_ASM @@ -154,6 +173,20 @@ void AES_xts_decrypt(const char *inp,char *out,size_t len, const unsigned char iv[16]); #endif +#if defined(OPENSSL_CPUID_OBJ) && (defined(__powerpc__) || defined(__ppc__) || defined(_ARCH_PPC)) +# include "ppc_arch.h" +# ifdef VPAES_ASM +# define VPAES_CAPABLE (OPENSSL_ppccap_P & PPC_ALTIVEC) +# endif +# define HWAES_CAPABLE (OPENSSL_ppccap_P & PPC_CRYPTO207) +# define HWAES_set_encrypt_key aes_p8_set_encrypt_key +# define HWAES_set_decrypt_key aes_p8_set_decrypt_key +# define HWAES_encrypt aes_p8_encrypt +# define HWAES_decrypt aes_p8_decrypt +# define HWAES_cbc_encrypt aes_p8_cbc_encrypt +# define HWAES_ctr32_encrypt_blocks aes_p8_ctr32_encrypt_blocks +#endif + #if defined(AES_ASM) && !defined(I386_ONLY) && ( \ ((defined(__i386) || defined(__i386__) || \ defined(_M_IX86)) && defined(OPENSSL_IA32_SSE2))|| \ @@ -167,7 +200,7 @@ extern unsigned int OPENSSL_ia32cap_P[]; #define VPAES_CAPABLE (OPENSSL_ia32cap_P[1]&(1<<(41-32))) #endif #ifdef BSAES_ASM -#define BSAES_CAPABLE VPAES_CAPABLE +#define BSAES_CAPABLE (OPENSSL_ia32cap_P[1]&(1<<(41-32))) #endif /* * AES-NI section @@ -437,6 +470,59 @@ static int aesni_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, static int aesni_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t len); +#ifndef OPENSSL_NO_OCB +static int aesni_ocb_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) + { + EVP_AES_OCB_CTX *octx = ctx->cipher_data; + if (!iv && !key) + return 1; + if (key) + { + do + { + /* We set both the encrypt and decrypt key here because decrypt + * needs both. We could possibly optimise to remove setting the + * decrypt for an encryption operation. + */ + aesni_set_encrypt_key(key, ctx->key_len * 8, &octx->ksenc); + aesni_set_decrypt_key(key, ctx->key_len * 8, &octx->ksdec); + if(!CRYPTO_ocb128_init(&octx->ocb, &octx->ksenc, &octx->ksdec, + (block128_f)aesni_encrypt, (block128_f)aesni_decrypt)) + return 0; + } + while (0); + + /* If we have an iv we can set it directly, otherwise use + * saved IV. + */ + if (iv == NULL && octx->iv_set) + iv = octx->iv; + if (iv) + { + if(CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen) != 1) + return 0; + octx->iv_set = 1; + } + octx->key_set = 1; + } + else + { + /* If key set use IV, otherwise copy */ + if (octx->key_set) + CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen); + else + memcpy(octx->iv, iv, octx->ivlen); + octx->iv_set = 1; + } + return 1; + } + +#define aesni_ocb_cipher aes_ocb_cipher +static int aesni_ocb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len); +#endif /* OPENSSL_NO_OCB */ + #define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \ static const EVP_CIPHER aesni_##keylen##_##mode = { \ nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \ @@ -823,6 +909,59 @@ static int aes_t4_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, static int aes_t4_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t len); +#ifndef OPENSSL_NO_OCB +static int aes_t4_ocb_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) + { + EVP_AES_OCB_CTX *octx = ctx->cipher_data; + if (!iv && !key) + return 1; + if (key) + { + do + { + /* We set both the encrypt and decrypt key here because decrypt + * needs both. We could possibly optimise to remove setting the + * decrypt for an encryption operation. + */ + aes_t4_set_encrypt_key(key, ctx->key_len * 8, &octx->ksenc); + aes_t4_set_decrypt_key(key, ctx->key_len * 8, &octx->ksdec); + if(!CRYPTO_ocb128_init(&octx->ocb, &octx->ksenc, &octx->ksdec, + (block128_f)aes_t4_encrypt, (block128_f)aes_t4_decrypt)) + return 0; + } + while (0); + + /* If we have an iv we can set it directly, otherwise use + * saved IV. + */ + if (iv == NULL && octx->iv_set) + iv = octx->iv; + if (iv) + { + if(CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen) != 1) + return 0; + octx->iv_set = 1; + } + octx->key_set = 1; + } + else + { + /* If key set use IV, otherwise copy */ + if (octx->key_set) + CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen); + else + memcpy(octx->iv, iv, octx->ivlen); + octx->iv_set = 1; + } + return 1; + } + +#define aes_t4_ocb_cipher aes_ocb_cipher +static int aes_t4_ocb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len); +#endif /* OPENSSL_NO_OCB */ + #define BLOCK_CIPHER_generic(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \ static const EVP_CIPHER aes_t4_##keylen##_##mode = { \ nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \ @@ -892,6 +1031,39 @@ static const EVP_CIPHER aes_##keylen##_##mode = { \ NULL,NULL,aes_##mode##_ctrl,NULL }; \ const EVP_CIPHER *EVP_aes_##keylen##_##mode(void) \ { return &aes_##keylen##_##mode; } + +#endif + +#if defined(OPENSSL_CPUID_OBJ) && (defined(__arm__) || defined(__arm) || defined(__aarch64__)) +#include "arm_arch.h" +#if __ARM_ARCH__>=7 +# if defined(BSAES_ASM) +# define BSAES_CAPABLE (OPENSSL_armcap_P & ARMV7_NEON) +# endif +# define HWAES_CAPABLE (OPENSSL_armcap_P & ARMV8_AES) +# define HWAES_set_encrypt_key aes_v8_set_encrypt_key +# define HWAES_set_decrypt_key aes_v8_set_decrypt_key +# define HWAES_encrypt aes_v8_encrypt +# define HWAES_decrypt aes_v8_decrypt +# define HWAES_cbc_encrypt aes_v8_cbc_encrypt +# define HWAES_ctr32_encrypt_blocks aes_v8_ctr32_encrypt_blocks +#endif +#endif + +#if defined(HWAES_CAPABLE) +int HWAES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +int HWAES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +void HWAES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void HWAES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void HWAES_cbc_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, const int enc); +void HWAES_ctr32_encrypt_blocks(const unsigned char *in, unsigned char *out, + size_t len, const AES_KEY *key, const unsigned char ivec[16]); #endif #define BLOCK_CIPHER_generic_pack(nid,keylen,flags) \ @@ -912,6 +1084,19 @@ static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, mode = ctx->cipher->flags & EVP_CIPH_MODE; if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) +#ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) + { + ret = HWAES_set_decrypt_key(key,ctx->key_len*8,&dat->ks.ks); + dat->block = (block128_f)HWAES_decrypt; + dat->stream.cbc = NULL; +#ifdef HWAES_cbc_encrypt + if (mode==EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)HWAES_cbc_encrypt; +#endif + } + else +#endif #ifdef BSAES_CAPABLE if (BSAES_CAPABLE && mode==EVP_CIPH_CBC_MODE) { @@ -940,6 +1125,26 @@ static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, NULL; } else +#ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) + { + ret = HWAES_set_encrypt_key(key,ctx->key_len*8,&dat->ks.ks); + dat->block = (block128_f)HWAES_encrypt; + dat->stream.cbc = NULL; +#ifdef HWAES_cbc_encrypt + if (mode==EVP_CIPH_CBC_MODE) + dat->stream.cbc = (cbc128_f)HWAES_cbc_encrypt; + else +#endif +#ifdef HWAES_ctr32_encrypt_blocks + if (mode==EVP_CIPH_CTR_MODE) + dat->stream.ctr = (ctr128_f)HWAES_ctr32_encrypt_blocks; + else +#endif + (void)0; /* terminate potentially open 'else' */ + } + else +#endif #ifdef BSAES_CAPABLE if (BSAES_CAPABLE && mode==EVP_CIPH_CTR_MODE) { @@ -991,7 +1196,7 @@ static int aes_cbc_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out, else if (ctx->encrypt) CRYPTO_cbc128_encrypt(in,out,len,&dat->ks,ctx->iv,dat->block); else - CRYPTO_cbc128_encrypt(in,out,len,&dat->ks,ctx->iv,dat->block); + CRYPTO_cbc128_decrypt(in,out,len,&dat->ks,ctx->iv,dat->block); return 1; } @@ -1080,9 +1285,9 @@ static int aes_ctr_cipher (EVP_CIPHER_CTX *ctx, unsigned char *out, return 1; } -BLOCK_CIPHER_generic_pack(NID_aes,128,EVP_CIPH_FLAG_FIPS) -BLOCK_CIPHER_generic_pack(NID_aes,192,EVP_CIPH_FLAG_FIPS) -BLOCK_CIPHER_generic_pack(NID_aes,256,EVP_CIPH_FLAG_FIPS) +BLOCK_CIPHER_generic_pack(NID_aes,128,0) +BLOCK_CIPHER_generic_pack(NID_aes,192,0) +BLOCK_CIPHER_generic_pack(NID_aes,256,0) static int aes_gcm_cleanup(EVP_CIPHER_CTX *c) { @@ -1125,11 +1330,6 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) case EVP_CTRL_GCM_SET_IVLEN: if (arg <= 0) return 0; -#ifdef OPENSSL_FIPS - if (FIPS_module_mode() && !(c->flags & EVP_CIPH_FLAG_NON_FIPS_ALLOW) - && arg < 12) - return 0; -#endif /* Allocate memory for IV if needed */ if ((arg > EVP_MAX_IV_LENGTH) && (arg > gctx->ivlen)) { @@ -1218,6 +1418,28 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) /* Extra padding: tag appended to record */ return EVP_GCM_TLS_TAG_LEN; + case EVP_CTRL_COPY: + { + EVP_CIPHER_CTX *out = ptr; + EVP_AES_GCM_CTX *gctx_out = out->cipher_data; + if (gctx->gcm.key) + { + if (gctx->gcm.key != &gctx->ks) + return 0; + gctx_out->gcm.key = &gctx_out->ks; + } + if (gctx->iv == c->iv) + gctx_out->iv = out->iv; + else + { + gctx_out->iv = OPENSSL_malloc(gctx->ivlen); + if (!gctx_out->iv) + return 0; + memcpy(gctx_out->iv, gctx->iv, gctx->ivlen); + } + return 1; + } + default: return -1; @@ -1232,6 +1454,21 @@ static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, return 1; if (key) { do { +#ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) + { + HWAES_set_encrypt_key(key,ctx->key_len*8,&gctx->ks.ks); + CRYPTO_gcm128_init(&gctx->gcm,&gctx->ks, + (block128_f)HWAES_encrypt); +#ifdef HWAES_ctr32_encrypt_blocks + gctx->ctr = (ctr128_f)HWAES_ctr32_encrypt_blocks; +#else + gctx->ctr = NULL; +#endif + break; + } + else +#endif #ifdef BSAES_CAPABLE if (BSAES_CAPABLE) { @@ -1252,7 +1489,10 @@ static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, gctx->ctr = NULL; break; } + else #endif + (void)0; /* terminate potentially open 'else' */ + AES_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks.ks); CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)AES_encrypt); #ifdef AES_CTR_ASM @@ -1589,19 +1829,38 @@ static int aes_gcm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, #define CUSTOM_FLAGS (EVP_CIPH_FLAG_DEFAULT_ASN1 \ | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER \ - | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT) + | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT \ + | EVP_CIPH_CUSTOM_COPY) BLOCK_CIPHER_custom(NID_aes,128,1,12,gcm,GCM, - EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_AEAD_CIPHER|CUSTOM_FLAGS) + EVP_CIPH_FLAG_AEAD_CIPHER|CUSTOM_FLAGS) BLOCK_CIPHER_custom(NID_aes,192,1,12,gcm,GCM, - EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_AEAD_CIPHER|CUSTOM_FLAGS) + EVP_CIPH_FLAG_AEAD_CIPHER|CUSTOM_FLAGS) BLOCK_CIPHER_custom(NID_aes,256,1,12,gcm,GCM, - EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_AEAD_CIPHER|CUSTOM_FLAGS) + EVP_CIPH_FLAG_AEAD_CIPHER|CUSTOM_FLAGS) static int aes_xts_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { EVP_AES_XTS_CTX *xctx = c->cipher_data; - if (type != EVP_CTRL_INIT) + if (type == EVP_CTRL_COPY) + { + EVP_CIPHER_CTX *out = ptr; + EVP_AES_XTS_CTX *xctx_out = out->cipher_data; + if (xctx->xts.key1) + { + if (xctx->xts.key1 != &xctx->ks1) + return 0; + xctx_out->xts.key1 = &xctx_out->ks1; + } + if (xctx->xts.key2) + { + if (xctx->xts.key2 != &xctx->ks2) + return 0; + xctx_out->xts.key2 = &xctx_out->ks2; + } + return 1; + } + else if (type != EVP_CTRL_INIT) return -1; /* key1 and key2 are used as an indicator both key and IV are set */ xctx->xts.key1 = NULL; @@ -1624,6 +1883,29 @@ static int aes_xts_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, xctx->stream = NULL; #endif /* key_len is two AES keys */ +#ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) + { + if (enc) + { + HWAES_set_encrypt_key(key, ctx->key_len * 4, &xctx->ks1.ks); + xctx->xts.block1 = (block128_f)HWAES_encrypt; + } + else + { + HWAES_set_decrypt_key(key, ctx->key_len * 4, &xctx->ks1.ks); + xctx->xts.block1 = (block128_f)HWAES_decrypt; + } + + HWAES_set_encrypt_key(key + ctx->key_len/2, + ctx->key_len * 4, &xctx->ks2.ks); + xctx->xts.block2 = (block128_f)HWAES_encrypt; + + xctx->xts.key1 = &xctx->ks1; + break; + } + else +#endif #ifdef BSAES_CAPABLE if (BSAES_CAPABLE) xctx->stream = enc ? bsaes_xts_encrypt : bsaes_xts_decrypt; @@ -1643,14 +1925,17 @@ static int aes_xts_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, xctx->xts.block1 = (block128_f)vpaes_decrypt; } - vpaes_set_encrypt_key(key + ctx->key_len/2, + vpaes_set_encrypt_key(key + ctx->key_len/2, ctx->key_len * 4, &xctx->ks2.ks); - xctx->xts.block2 = (block128_f)vpaes_encrypt; + xctx->xts.block2 = (block128_f)vpaes_encrypt; - xctx->xts.key1 = &xctx->ks1; - break; - } + xctx->xts.key1 = &xctx->ks1; + break; + } + else #endif + (void)0; /* terminate potentially open 'else' */ + if (enc) { AES_set_encrypt_key(key, ctx->key_len * 4, &xctx->ks1.ks); @@ -1686,15 +1971,6 @@ static int aes_xts_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, return 0; if (!out || !in || lenflags & EVP_CIPH_FLAG_NON_FIPS_ALLOW) && - (len > (1UL<<20)*16)) - { - EVPerr(EVP_F_AES_XTS_CIPHER, EVP_R_TOO_LARGE); - return 0; - } -#endif if (xctx->stream) (*xctx->stream)(in, out, len, xctx->xts.key1, xctx->xts.key2, ctx->iv); @@ -1707,10 +1983,11 @@ static int aes_xts_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, #define aes_xts_cleanup NULL #define XTS_FLAGS (EVP_CIPH_FLAG_DEFAULT_ASN1 | EVP_CIPH_CUSTOM_IV \ - | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT) + | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT \ + | EVP_CIPH_CUSTOM_COPY) -BLOCK_CIPHER_custom(NID_aes,128,1,16,xts,XTS,EVP_CIPH_FLAG_FIPS|XTS_FLAGS) -BLOCK_CIPHER_custom(NID_aes,256,1,16,xts,XTS,EVP_CIPH_FLAG_FIPS|XTS_FLAGS) +BLOCK_CIPHER_custom(NID_aes,128,1,16,xts,XTS,XTS_FLAGS) +BLOCK_CIPHER_custom(NID_aes,256,1,16,xts,XTS,XTS_FLAGS) static int aes_ccm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { @@ -1757,6 +2034,19 @@ static int aes_ccm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) cctx->len_set = 0; return 1; + case EVP_CTRL_COPY: + { + EVP_CIPHER_CTX *out = ptr; + EVP_AES_CCM_CTX *cctx_out = out->cipher_data; + if (cctx->ccm.key) + { + if (cctx->ccm.key != &cctx->ks) + return 0; + cctx_out->ccm.key = &cctx_out->ks; + } + return 1; + } + default: return -1; @@ -1771,6 +2061,19 @@ static int aes_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, return 1; if (key) do { +#ifdef HWAES_CAPABLE + if (HWAES_CAPABLE) + { + HWAES_set_encrypt_key(key,ctx->key_len*8,&cctx->ks.ks); + + CRYPTO_ccm128_init(&cctx->ccm, cctx->M, cctx->L, + &cctx->ks, (block128_f)HWAES_encrypt); + cctx->str = NULL; + cctx->key_set = 1; + break; + } + else +#endif #ifdef VPAES_CAPABLE if (VPAES_CAPABLE) { @@ -1866,8 +2169,471 @@ static int aes_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, #define aes_ccm_cleanup NULL -BLOCK_CIPHER_custom(NID_aes,128,1,12,ccm,CCM,EVP_CIPH_FLAG_FIPS|CUSTOM_FLAGS) -BLOCK_CIPHER_custom(NID_aes,192,1,12,ccm,CCM,EVP_CIPH_FLAG_FIPS|CUSTOM_FLAGS) -BLOCK_CIPHER_custom(NID_aes,256,1,12,ccm,CCM,EVP_CIPH_FLAG_FIPS|CUSTOM_FLAGS) +BLOCK_CIPHER_custom(NID_aes,128,1,12,ccm,CCM,CUSTOM_FLAGS) +BLOCK_CIPHER_custom(NID_aes,192,1,12,ccm,CCM,CUSTOM_FLAGS) +BLOCK_CIPHER_custom(NID_aes,256,1,12,ccm,CCM,CUSTOM_FLAGS) + +typedef struct + { + union { double align; AES_KEY ks; } ks; + /* Indicates if IV has been set */ + unsigned char *iv; + } EVP_AES_WRAP_CTX; + +static int aes_wrap_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) + { + EVP_AES_WRAP_CTX *wctx = ctx->cipher_data; + if (!iv && !key) + return 1; + if (key) + { + if (ctx->encrypt) + AES_set_encrypt_key(key, ctx->key_len * 8, &wctx->ks.ks); + else + AES_set_decrypt_key(key, ctx->key_len * 8, &wctx->ks.ks); + if (!iv) + wctx->iv = NULL; + } + if (iv) + { + memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + wctx->iv = ctx->iv; + } + return 1; + } + +static int aes_wrap_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t inlen) + { + EVP_AES_WRAP_CTX *wctx = ctx->cipher_data; + size_t rv; + /* AES wrap with padding has IV length of 4, without padding 8 */ + int pad = EVP_CIPHER_CTX_iv_length(ctx) == 4; + /* No final operation so always return zero length */ + if (!in) + return 0; + /* Input length must always be non-zero */ + if (!inlen) + return -1; + /* If decrypting need at least 16 bytes and multiple of 8 */ + if (!ctx->encrypt && (inlen < 16 || inlen & 0x7)) + return -1; + /* If not padding input must be multiple of 8 */ + if (!pad && inlen & 0x7) + return -1; + if (!out) + { + if (ctx->encrypt) + { + /* If padding round up to multiple of 8 */ + if (pad) + inlen = (inlen + 7)/8 * 8; + /* 8 byte prefix */ + return inlen + 8; + } + else + { + /* If not padding output will be exactly 8 bytes + * smaller than input. If padding it will be at + * least 8 bytes smaller but we don't know how + * much. + */ + return inlen - 8; + } + } + if (pad) + { + if (ctx->encrypt) + rv = CRYPTO_128_wrap_pad(&wctx->ks.ks, wctx->iv, + out, in, inlen, + (block128_f)AES_encrypt); + else + rv = CRYPTO_128_unwrap_pad(&wctx->ks.ks, wctx->iv, + out, in, inlen, + (block128_f)AES_decrypt); + } + else + { + if (ctx->encrypt) + rv = CRYPTO_128_wrap(&wctx->ks.ks, wctx->iv, + out, in, inlen, + (block128_f)AES_encrypt); + else + rv = CRYPTO_128_unwrap(&wctx->ks.ks, wctx->iv, + out, in, inlen, + (block128_f)AES_decrypt); + } + return rv ? (int)rv : -1; + } + +#define WRAP_FLAGS (EVP_CIPH_WRAP_MODE \ + | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER \ + | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_FLAG_DEFAULT_ASN1) + +static const EVP_CIPHER aes_128_wrap = { + NID_id_aes128_wrap, + 8, 16, 8, WRAP_FLAGS, + aes_wrap_init_key, aes_wrap_cipher, + NULL, + sizeof(EVP_AES_WRAP_CTX), + NULL,NULL,NULL,NULL }; + +const EVP_CIPHER *EVP_aes_128_wrap(void) + { + return &aes_128_wrap; + } + +static const EVP_CIPHER aes_192_wrap = { + NID_id_aes192_wrap, + 8, 24, 8, WRAP_FLAGS, + aes_wrap_init_key, aes_wrap_cipher, + NULL, + sizeof(EVP_AES_WRAP_CTX), + NULL,NULL,NULL,NULL }; + +const EVP_CIPHER *EVP_aes_192_wrap(void) + { + return &aes_192_wrap; + } + +static const EVP_CIPHER aes_256_wrap = { + NID_id_aes256_wrap, + 8, 32, 8, WRAP_FLAGS, + aes_wrap_init_key, aes_wrap_cipher, + NULL, + sizeof(EVP_AES_WRAP_CTX), + NULL,NULL,NULL,NULL }; + +const EVP_CIPHER *EVP_aes_256_wrap(void) + { + return &aes_256_wrap; + } + +static const EVP_CIPHER aes_128_wrap_pad = { + NID_id_aes128_wrap_pad, + 8, 16, 4, WRAP_FLAGS, + aes_wrap_init_key, aes_wrap_cipher, + NULL, + sizeof(EVP_AES_WRAP_CTX), + NULL,NULL,NULL,NULL }; + +const EVP_CIPHER *EVP_aes_128_wrap_pad(void) + { + return &aes_128_wrap_pad; + } + +static const EVP_CIPHER aes_192_wrap_pad = { + NID_id_aes192_wrap_pad, + 8, 24, 4, WRAP_FLAGS, + aes_wrap_init_key, aes_wrap_cipher, + NULL, + sizeof(EVP_AES_WRAP_CTX), + NULL,NULL,NULL,NULL }; + +const EVP_CIPHER *EVP_aes_192_wrap_pad(void) + { + return &aes_192_wrap_pad; + } + +static const EVP_CIPHER aes_256_wrap_pad = { + NID_id_aes256_wrap_pad, + 8, 32, 4, WRAP_FLAGS, + aes_wrap_init_key, aes_wrap_cipher, + NULL, + sizeof(EVP_AES_WRAP_CTX), + NULL,NULL,NULL,NULL }; + +const EVP_CIPHER *EVP_aes_256_wrap_pad(void) + { + return &aes_256_wrap_pad; + } + +#ifndef OPENSSL_NO_OCB +static int aes_ocb_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) + { + EVP_AES_OCB_CTX *octx = c->cipher_data; + EVP_CIPHER_CTX *newc; + EVP_AES_OCB_CTX *new_octx; + + switch (type) + { + case EVP_CTRL_INIT: + octx->key_set = 0; + octx->iv_set = 0; + octx->ivlen = c->cipher->iv_len; + octx->iv = c->iv; + octx->taglen = 16; + octx->data_buf_len = 0; + octx->aad_buf_len = 0; + return 1; + + case EVP_CTRL_SET_IVLEN: + /* IV len must be 1 to 15 */ + if (arg <= 0 || arg > 15) + return 0; + + octx->ivlen = arg; + return 1; + + case EVP_CTRL_OCB_SET_TAGLEN: + /* Tag len must be 0 to 16 */ + if (arg < 0 || arg > 16) + return 0; + + octx->taglen = arg; + return 1; + + case EVP_CTRL_SET_TAG: + if (arg != octx->taglen || c->encrypt) + return 0; + memcpy(octx->tag, ptr, arg); + return 1; + + case EVP_CTRL_GET_TAG: + if (arg != octx->taglen || !c->encrypt) + return 0; + + memcpy(ptr, octx->tag, arg); + return 1; + + case EVP_CTRL_COPY: + newc = (EVP_CIPHER_CTX *)ptr; + new_octx = newc->cipher_data; + return CRYPTO_ocb128_copy_ctx(&new_octx->ocb, &octx->ocb, + &new_octx->ksenc, &new_octx->ksdec); + + default: + return -1; + + } + } + + +static int aes_ocb_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) + { + EVP_AES_OCB_CTX *octx = ctx->cipher_data; + if (!iv && !key) + return 1; + if (key) + { + do + { + /* We set both the encrypt and decrypt key here because decrypt + * needs both. We could possibly optimise to remove setting the + * decrypt for an encryption operation. + */ +#ifdef VPAES_CAPABLE + if (VPAES_CAPABLE) + { + vpaes_set_encrypt_key(key,ctx->key_len*8,&octx->ksenc); + vpaes_set_decrypt_key(key,ctx->key_len*8,&octx->ksdec); + if(!CRYPTO_ocb128_init(&octx->ocb,&octx->ksenc,&octx->ksdec, + (block128_f)vpaes_encrypt,(block128_f)vpaes_decrypt)) + return 0; + break; + } +#endif + AES_set_encrypt_key(key, ctx->key_len * 8, &octx->ksenc); + AES_set_decrypt_key(key, ctx->key_len * 8, &octx->ksdec); + if(!CRYPTO_ocb128_init(&octx->ocb, &octx->ksenc, &octx->ksdec, + (block128_f)AES_encrypt, (block128_f)AES_decrypt)) + return 0; + } + while (0); + + /* If we have an iv we can set it directly, otherwise use + * saved IV. + */ + if (iv == NULL && octx->iv_set) + iv = octx->iv; + if (iv) + { + if(CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen) != 1) + return 0; + octx->iv_set = 1; + } + octx->key_set = 1; + } + else + { + /* If key set use IV, otherwise copy */ + if (octx->key_set) + CRYPTO_ocb128_setiv(&octx->ocb, iv, octx->ivlen, octx->taglen); + else + memcpy(octx->iv, iv, octx->ivlen); + octx->iv_set = 1; + } + return 1; + } + +static int aes_ocb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) + { + unsigned char *buf; + int *buf_len; + int written_len = 0; + size_t trailing_len; + EVP_AES_OCB_CTX *octx = ctx->cipher_data; + + /* If IV or Key not set then return error */ + if (!octx->iv_set) + return -1; + + if (!octx->key_set) + return -1; + + if (in) + { + /* Need to ensure we are only passing full blocks to low level OCB + * routines. We do it here rather than in EVP_EncryptUpdate/ + * EVP_DecryptUpdate because we need to pass full blocks of AAD too + * and those routines don't support that + */ + + /* Are we dealing with AAD or normal data here? */ + if (out == NULL) + { + buf = octx->aad_buf; + buf_len = &(octx->aad_buf_len); + } + else + { + buf = octx->data_buf; + buf_len = &(octx->data_buf_len); + } + + /* If we've got a partially filled buffer from a previous call then use + * that data first + */ + if(*buf_len) + { + unsigned int remaining; + + remaining = 16 - (*buf_len); + if(remaining > len) + { + memcpy(buf+(*buf_len), in, len); + *(buf_len)+=len; + return 0; + } + memcpy(buf+(*buf_len), in, remaining); + + /* If we get here we've filled the buffer, so process it */ + len -= remaining; + in += remaining; + if (out == NULL) + { + if(!CRYPTO_ocb128_aad(&octx->ocb, buf, 16)) + return -1; + } + else if (ctx->encrypt) + { + if(!CRYPTO_ocb128_encrypt(&octx->ocb, buf, out, 16)) + return -1; + } + else + { + if(!CRYPTO_ocb128_decrypt(&octx->ocb, buf, out, 16)) + return -1; + } + written_len = 16; + *buf_len = 0; + } + + /* Do we have a partial block to handle at the end? */ + trailing_len = len % 16; + + /* If we've got some full blocks to handle, then process these first */ + if(len != trailing_len) + { + if (out == NULL) + { + if(!CRYPTO_ocb128_aad(&octx->ocb, in, len-trailing_len)) + return -1; + } + else if (ctx->encrypt) + { + if(!CRYPTO_ocb128_encrypt(&octx->ocb, in, out, len-trailing_len)) + return -1; + } + else + { + if(!CRYPTO_ocb128_decrypt(&octx->ocb, in, out, len-trailing_len)) + return -1; + } + written_len += len-trailing_len; + in += len-trailing_len; + } + + /* Handle any trailing partial block */ + if(trailing_len) + { + memcpy(buf, in, trailing_len); + *buf_len = trailing_len; + } + + return written_len; + } + else + { + /* First of all empty the buffer of any partial block that we might + * have been provided - both for data and AAD + */ + if(octx->data_buf_len) + { + if (ctx->encrypt) + { + if(!CRYPTO_ocb128_encrypt(&octx->ocb, octx->data_buf, out, + octx->data_buf_len)) + return -1; + } + else + { + if(!CRYPTO_ocb128_decrypt(&octx->ocb, octx->data_buf, out, + octx->data_buf_len)) + return -1; + } + written_len = octx->data_buf_len; + octx->data_buf_len = 0; + } + if(octx->aad_buf_len) + { + if(!CRYPTO_ocb128_aad(&octx->ocb, octx->aad_buf, octx->aad_buf_len)) + return -1; + octx->aad_buf_len = 0; + } + /* If decrypting then verify */ + if (!ctx->encrypt) + { + if (octx->taglen < 0) + return -1; + if (CRYPTO_ocb128_finish(&octx->ocb, + octx->tag, octx->taglen) != 0) + return -1; + octx->iv_set = 0; + return written_len; + } + /* If encrypting then just get the tag */ + if(CRYPTO_ocb128_tag(&octx->ocb, octx->tag, 16) != 1) + return -1; + /* Don't reuse the IV */ + octx->iv_set = 0; + return written_len; + } + } + +static int aes_ocb_cleanup(EVP_CIPHER_CTX *c) + { + EVP_AES_OCB_CTX *octx = c->cipher_data; + CRYPTO_ocb128_cleanup(&octx->ocb); + return 1; + } + +BLOCK_CIPHER_custom(NID_aes,128,16,12,ocb,OCB,CUSTOM_FLAGS) +BLOCK_CIPHER_custom(NID_aes,192,16,12,ocb,OCB,CUSTOM_FLAGS) +BLOCK_CIPHER_custom(NID_aes,256,16,12,ocb,OCB,CUSTOM_FLAGS) +#endif /* OPENSSL_NO_OCB */ #endif