diff options
author | Dr. Stephen Henson <steve@openssl.org> | 2011-02-09 16:21:43 +0000 |
---|---|---|
committer | Dr. Stephen Henson <steve@openssl.org> | 2011-02-09 16:21:43 +0000 |
commit | b3d8022eddb3c6c3e840054fcf3dcd77d1c3c2be (patch) | |
tree | ac71caa838796bc99cf591ed113f3694e66d6c0c /crypto | |
parent | 632d83f0a3fbda2e7f4e556183792597b7db88fc (diff) |
Add GCM IV generator. Add some FIPS restrictions to GCM. Update fips_gcmtest.
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/evp/e_aes.c | 83 | ||||
-rw-r--r-- | crypto/evp/evp.h | 2 |
2 files changed, 75 insertions, 10 deletions
diff --git a/crypto/evp/e_aes.c b/crypto/evp/e_aes.c index ed21d0a923..4206fd0da4 100644 --- a/crypto/evp/e_aes.c +++ b/crypto/evp/e_aes.c @@ -59,6 +59,7 @@ #include <openssl/aes.h> #include "evp_locl.h" #include <openssl/modes.h> +#include <openssl/rand.h> static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, const unsigned char *iv, int enc); @@ -197,11 +198,15 @@ typedef struct int iv_set; /* Pointer to GCM128_CTX: FIXME actual structure later */ GCM128_CONTEXT *gcm; + /* Temporary IV store */ + unsigned char *iv; /* IV length */ int ivlen; /* Tag to verify */ unsigned char tag[16]; int taglen; + /* It is OK to generate IVs */ + int iv_gen; } EVP_AES_GCM_CTX; static int aes_gcm_cleanup(EVP_CIPHER_CTX *c) @@ -209,9 +214,25 @@ static int aes_gcm_cleanup(EVP_CIPHER_CTX *c) EVP_AES_GCM_CTX *gctx = c->cipher_data; if (gctx->gcm) CRYPTO_gcm128_release(gctx->gcm); + if (gctx->iv != c->iv) + OPENSSL_free(gctx->iv); return 1; } +/* increment counter (64-bit int) by 1 */ +static void ctr64_inc(unsigned char *counter) { + int n=8; + unsigned char c; + + do { + --n; + c = counter[n]; + ++c; + counter[n] = c; + if (c) return; + } while (n); +} + static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { EVP_AES_GCM_CTX *gctx = c->cipher_data; @@ -222,12 +243,28 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) gctx->key_set = 0; gctx->iv_set = 0; gctx->ivlen = c->cipher->iv_len; + gctx->iv = c->iv; gctx->taglen = -1; + gctx->iv_gen = 0; return 1; case EVP_CTRL_GCM_SET_IVLEN: if (arg <= 0) return 0; +#ifdef OPENSSL_FIPS + if (FIPS_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)) + { + if (gctx->iv != c->iv) + OPENSSL_free(gctx->iv); + gctx->iv = OPENSSL_malloc(arg); + if (!gctx->iv) + return 0; + } gctx->ivlen = arg; return 1; @@ -244,6 +281,39 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) memcpy(ptr, gctx->tag, arg); return 1; + case EVP_CTRL_GCM_SET_IV_FIXED: + /* Special case: -1 length restores whole IV */ + if (arg == -1) + { + memcpy(gctx->iv, ptr, gctx->ivlen); + gctx->iv_gen = 1; + return 1; + } + /* Fixed field must be at least 4 bytes and invocation field + * at least 8. + */ + if ((arg < 4) || (gctx->ivlen - arg) < 8) + return 0; + if (arg) + memcpy(gctx->iv, ptr, arg); + if (RAND_bytes(gctx->iv + arg, gctx->ivlen - arg) <= 0) + return 0; + gctx->iv_gen = 1; + return 1; + + case EVP_CTRL_GCM_IV_GEN: + if (gctx->iv_gen == 0 || gctx->key_set == 0) + return 0; + CRYPTO_gcm128_setiv(gctx->gcm, gctx->iv, gctx->ivlen); + memcpy(ptr, gctx->iv, gctx->ivlen); + /* Invocation field will be at least 8 bytes in size and + * so no need to check wrap around or increment more than + * last 8 bytes. + */ + ctr64_inc(gctx->iv + gctx->ivlen - 8); + gctx->iv_set = 1; + return 1; + default: return -1; @@ -272,7 +342,7 @@ static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, * saved IV. */ if (iv == NULL && gctx->iv_set) - iv = ctx->iv; + iv = gctx->iv; if (iv) { CRYPTO_gcm128_setiv(gctx->gcm, iv, gctx->ivlen); @@ -286,16 +356,9 @@ static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, if (gctx->key_set) CRYPTO_gcm128_setiv(gctx->gcm, iv, gctx->ivlen); else - { - /* If IV is too large for EVP_CIPHER_CTX buffer - * return an error. This can be avoided by either - * setting the key first or key and iv simultaneously. - */ - if (gctx->ivlen > EVP_MAX_IV_LENGTH) - return 0; - memcpy(ctx->iv, iv, gctx->ivlen); - } + memcpy(gctx->iv, iv, gctx->ivlen); gctx->iv_set = 1; + gctx->iv_gen = 0; } return 1; } diff --git a/crypto/evp/evp.h b/crypto/evp/evp.h index f42bc2687a..042dc1c577 100644 --- a/crypto/evp/evp.h +++ b/crypto/evp/evp.h @@ -374,6 +374,8 @@ struct evp_cipher_st #define EVP_CTRL_GCM_SET_IVLEN 0x9 #define EVP_CTRL_GCM_GET_TAG 0x10 #define EVP_CTRL_GCM_SET_TAG 0x11 +#define EVP_CTRL_GCM_SET_IV_FIXED 0x12 +#define EVP_CTRL_GCM_IV_GEN 0x13 typedef struct evp_cipher_info_st { |