From: Dr. Stephen Henson Date: Mon, 18 Apr 2011 14:25:11 +0000 (+0000) Subject: Initial untested CCM support via EVP. X-Git-Tag: OpenSSL-fips-2_0-rc1~538 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=2391681082e70ccc8da23365801ac58713af67c7;hp=6386b1b34d955178ff8bf6fe5247667ff63a5dee Initial untested CCM support via EVP. --- diff --git a/CHANGES b/CHANGES index fd59e9d7db..e7a232e978 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,11 @@ Changes between 1.0.1 and 1.1.0 [xx XXX xxxx] + *) Initial untested CCM support via EVP. Interface is very similar to GCM + case except we must supply all data in one chunk (i.e. no update, final) + and the message length must be supplied if AAD is used. + [Steve Henson] + *) Initial version of POST overhaul. Add POST callback to allow the status of POST to be monitored and/or failures induced. Modify fips_test_suite to use callback. Always run all selftests even if one fails. diff --git a/Makefile.fips b/Makefile.fips index e4092537f3..198e6a5a1b 100644 --- a/Makefile.fips +++ b/Makefile.fips @@ -334,6 +334,7 @@ FIPS_EX_OBJ= ../crypto/aes/aes_cfb.o \ ../crypto/evp/m_sha1.o \ ../crypto/hmac/hmac.o \ ../crypto/modes/cbc128.o \ + ../crypto/modes/ccm128.o \ ../crypto/modes/cfb128.o \ ../crypto/modes/ctr128.o \ ../crypto/modes/gcm128.o \ diff --git a/Makefile.org b/Makefile.org index c3353f1b64..83ed4c93aa 100644 --- a/Makefile.org +++ b/Makefile.org @@ -328,6 +328,7 @@ FIPS_EX_OBJ= ../crypto/aes/aes_cfb.o \ ../crypto/evp/m_sha1.o \ ../crypto/hmac/hmac.o \ ../crypto/modes/cbc128.o \ + ../crypto/modes/ccm128.o \ ../crypto/modes/cfb128.o \ ../crypto/modes/ctr128.o \ ../crypto/modes/gcm128.o \ diff --git a/crypto/evp/e_aes.c b/crypto/evp/e_aes.c index 0a980fe82e..9b2f2a7441 100644 --- a/crypto/evp/e_aes.c +++ b/crypto/evp/e_aes.c @@ -568,5 +568,215 @@ static const EVP_CIPHER aes_256_xts_cipher= const EVP_CIPHER *EVP_aes_256_xts (void) { return &aes_256_xts_cipher; } - + +typedef struct + { + /* AES key schedule to use */ + AES_KEY ks; + /* Set if key initialised */ + int key_set; + /* Set if an iv is set */ + int iv_set; + /* Set if tag is valid */ + int tag_set; + /* Set if message length set */ + int len_set; + /* L and M parameters from RFC3610 */ + int L, M; + CCM128_CONTEXT ccm; + } EVP_AES_CCM_CTX; + +static int aes_ccm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) + { + EVP_AES_CCM_CTX *cctx = c->cipher_data; + switch (type) + { + case EVP_CTRL_INIT: + cctx->key_set = 0; + cctx->iv_set = 0; + cctx->L = 8; + cctx->M = 12; + cctx->tag_set = 0; + cctx->len_set = 0; + return 1; + + case EVP_CTRL_CCM_SET_IVLEN: + arg = 15 - arg; + case EVP_CTRL_CCM_SET_L: + if (arg < 2 || arg > 8) + return 0; + cctx->L = arg; + return 1; + + case EVP_CTRL_CCM_SET_TAG: + if ((arg & 1) || arg < 4 || arg > 16) + return 0; + if ((c->encrypt && ptr) || (!c->encrypt && !ptr)) + return 0; + if (ptr) + { + cctx->tag_set = 1; + memcpy(c->buf, ptr, arg); + } + cctx->M = arg; + return 1; + + case EVP_CTRL_CCM_GET_TAG: + if (!c->encrypt || !cctx->tag_set) + return 0; + if(CRYPTO_ccm128_tag(&cctx->ccm, ptr, (size_t)arg)) + return 0; + cctx->tag_set = 0; + cctx->iv_set = 0; + cctx->len_set = 0; + return 1; + + default: + return -1; + + } + } + +static int aes_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) + { + EVP_AES_CCM_CTX *cctx = ctx->cipher_data; + if (!iv && !key) + return 1; + if (key) + { + AES_set_encrypt_key(key, ctx->key_len * 8, &cctx->ks); + CRYPTO_ccm128_init(&cctx->ccm, cctx->M, cctx->L, + &cctx->ks, (block128_f)AES_encrypt); + cctx->key_set = 1; + } + if (iv) + { + memcpy(ctx->iv, iv, 15 - cctx->L); + cctx->iv_set = 1; + } + return 1; + } + +static int aes_ccm(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, size_t len) + { + EVP_AES_CCM_CTX *cctx = ctx->cipher_data; + CCM128_CONTEXT *ccm = &cctx->ccm; + /* If not set up, return error */ + if (!cctx->iv_set && !cctx->key_set) + return -1; + if (!ctx->encrypt && !cctx->tag_set) + return -1; + if (!out) + { + if (!in) + { + if (CRYPTO_ccm128_setiv(ccm, ctx->iv, 15 - cctx->L,len)) + return -1; + cctx->len_set = 1; + return len; + } + /* If have AAD need message length */ + if (!cctx->len_set && len) + return -1; + CRYPTO_ccm128_aad(ccm, in, len); + return len; + } + /* EVP_*Final() doesn't return any data */ + if (!in) + return 0; + /* If not set length yet do it */ + if (!cctx->len_set) + { + if (CRYPTO_ccm128_setiv(ccm, ctx->iv, 15 - cctx->L, len)) + return -1; + cctx->len_set = 1; + } + if (ctx->encrypt) + { + if (CRYPTO_ccm128_encrypt(ccm, in, out, len)) + return -1; + cctx->tag_set = 1; + return len; + } + else + { + int rv = -1; + if (!CRYPTO_ccm128_decrypt(ccm, in, out, len)) + { + unsigned char tag[16]; + if (!CRYPTO_ccm128_tag(ccm, tag, cctx->M)) + { + if (!memcmp(tag, ctx->buf, cctx->M)) + rv = len; + } + } + if (rv == -1) + OPENSSL_cleanse(out, len); + cctx->iv_set = 0; + cctx->tag_set = 0; + cctx->len_set = 0; + return rv; + } + + } + +static const EVP_CIPHER aes_128_ccm_cipher= + { + NID_aes_128_ccm,1,16,12, + EVP_CIPH_CCM_MODE|EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_DEFAULT_ASN1 + | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER + | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT, + aes_ccm_init_key, + aes_ccm, + 0, + sizeof(EVP_AES_CCM_CTX), + NULL, + NULL, + aes_ccm_ctrl, + NULL + }; + +const EVP_CIPHER *EVP_aes_128_ccm (void) +{ return &aes_128_ccm_cipher; } + +static const EVP_CIPHER aes_192_ccm_cipher= + { + NID_aes_128_ccm,1,24,12, + EVP_CIPH_CCM_MODE|EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_DEFAULT_ASN1 + | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER + | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT, + aes_ccm_init_key, + aes_ccm, + 0, + sizeof(EVP_AES_CCM_CTX), + NULL, + NULL, + aes_ccm_ctrl, + NULL + }; + +const EVP_CIPHER *EVP_aes_192_ccm (void) +{ return &aes_192_ccm_cipher; } + +static const EVP_CIPHER aes_256_ccm_cipher= + { + NID_aes_128_ccm,1,32,12, + EVP_CIPH_CCM_MODE|EVP_CIPH_FLAG_FIPS|EVP_CIPH_FLAG_DEFAULT_ASN1 + | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER + | EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT, + aes_ccm_init_key, + aes_ccm, + 0, + sizeof(EVP_AES_CCM_CTX), + NULL, + NULL, + aes_ccm_ctrl, + NULL + }; + +const EVP_CIPHER *EVP_aes_256_ccm (void) +{ return &aes_256_ccm_cipher; } + #endif diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h index 74ca64bc99..6301917fa7 100644 --- a/crypto/evp/evp.h +++ b/crypto/evp/evp.h @@ -378,6 +378,11 @@ struct evp_cipher_st #define EVP_CTRL_GCM_SET_TAG 0x11 #define EVP_CTRL_GCM_SET_IV_FIXED 0x12 #define EVP_CTRL_GCM_IV_GEN 0x13 +#define EVP_CTRL_CCM_SET_IVLEN EVP_CTRL_GCM_SET_IVLEN +#define EVP_CTRL_CCM_GET_TAG EVP_CTRL_GCM_GET_TAG +#define EVP_CTRL_CCM_SET_TAG EVP_CTRL_GCM_SET_TAG +#define EVP_CTRL_CCM_SET_L 0x14 +#define EVP_CTRL_CCM_SET_MSGLEN 0x15 typedef struct evp_cipher_info_st { @@ -790,6 +795,7 @@ const EVP_CIPHER *EVP_aes_128_cfb128(void); # define EVP_aes_128_cfb EVP_aes_128_cfb128 const EVP_CIPHER *EVP_aes_128_ofb(void); const EVP_CIPHER *EVP_aes_128_ctr(void); +const EVP_CIPHER *EVP_aes_128_ccm(void); const EVP_CIPHER *EVP_aes_128_gcm(void); const EVP_CIPHER *EVP_aes_128_xts(void); const EVP_CIPHER *EVP_aes_192_ecb(void); @@ -800,6 +806,7 @@ const EVP_CIPHER *EVP_aes_192_cfb128(void); # define EVP_aes_192_cfb EVP_aes_192_cfb128 const EVP_CIPHER *EVP_aes_192_ofb(void); const EVP_CIPHER *EVP_aes_192_ctr(void); +const EVP_CIPHER *EVP_aes_192_ccm(void); const EVP_CIPHER *EVP_aes_192_gcm(void); const EVP_CIPHER *EVP_aes_256_ecb(void); const EVP_CIPHER *EVP_aes_256_cbc(void); @@ -809,6 +816,7 @@ const EVP_CIPHER *EVP_aes_256_cfb128(void); # define EVP_aes_256_cfb EVP_aes_256_cfb128 const EVP_CIPHER *EVP_aes_256_ofb(void); const EVP_CIPHER *EVP_aes_256_ctr(void); +const EVP_CIPHER *EVP_aes_256_ccm(void); const EVP_CIPHER *EVP_aes_256_gcm(void); const EVP_CIPHER *EVP_aes_256_xts(void); #endif diff --git a/crypto/modes/modes.h b/crypto/modes/modes.h index c65e7815dd..feacfb77ed 100644 --- a/crypto/modes/modes.h +++ b/crypto/modes/modes.h @@ -108,21 +108,18 @@ void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx); typedef struct ccm128_context CCM128_CONTEXT; void CRYPTO_ccm128_init(CCM128_CONTEXT *ctx, - unsigned int M,unsigned int L,void *key,block128_f block); + unsigned int M, unsigned int L, void *key,block128_f block); int CRYPTO_ccm128_setiv(CCM128_CONTEXT *ctx, - const unsigned char *nonce,size_t nlen,size_t mlen); + const unsigned char *nonce, size_t nlen, size_t mlen); void CRYPTO_ccm128_aad(CCM128_CONTEXT *ctx, - const unsigned char *aad,size_t alen); + const unsigned char *aad, size_t alen); int CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx, - const unsigned char *inp, unsigned char *out, - size_t len); + const unsigned char *inp, unsigned char *out, size_t len); int CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx, - const unsigned char *inp, unsigned char *out, - size_t len); -size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx,unsigned char *tag,size_t len); + const unsigned char *inp, unsigned char *out, size_t len); +size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx, unsigned char *tag, size_t len); typedef struct xts128_context XTS128_CONTEXT; int CRYPTO_xts128_encrypt(const XTS128_CONTEXT *ctx, const unsigned char *iv, - const unsigned char *inp, unsigned char *out, - size_t len, int enc); + const unsigned char *inp, unsigned char *out, size_t len, int enc);