Commit b3d8022e authored by Dr. Stephen Henson's avatar Dr. Stephen Henson
Browse files

Add GCM IV generator. Add some FIPS restrictions to GCM. Update fips_gcmtest.

parent 632d83f0
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -4,6 +4,10 @@

 Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]

  *) Add some FIPS mode restrictions to GCM. Add internal IV generator.
     Update fips_gcmtest to use IV generator.
     [Steve Henson]

  *) Initial, experimental EVP support for AES-GCM. AAD can be input by
     setting output buffer to NULL. The *Final function must be
     called although it will not retrieve any additional data. The tag
+73 −10
Original line number Diff line number Diff line
@@ -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;
	}
+2 −0
Original line number Diff line number Diff line
@@ -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
	{
+23 −3
Original line number Diff line number Diff line
@@ -172,14 +172,32 @@ static void gcmtest(int encrypt)
				exit(1);
				}
			}
		/* FIXME: need intenal IV generation */
		if (encrypt && iv && pt && aad)
		if (encrypt && pt && aad && (iv || encrypt==1))
			{
			tag = OPENSSL_malloc(taglen);
			EVP_CipherInit_ex(&ctx, gcm, NULL, NULL, NULL, 1);
			EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, ivlen, 0);
			if (encrypt == 1)
				{
				static unsigned char iv_fixed[4] = {1,2,3,4};
				if (!iv)
					iv = OPENSSL_malloc(ivlen);
				EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1);
				EVP_CIPHER_CTX_ctrl(&ctx,
						EVP_CTRL_GCM_SET_IV_FIXED,
						4, iv_fixed);
				if (!EVP_CIPHER_CTX_ctrl(&ctx,
					EVP_CTRL_GCM_IV_GEN, 0, iv))
					{
					fprintf(stderr, "IV gen error\n");
					exit(1);
					}
				OutputValue("IV", iv, ivlen, stdout, 0);
				}
			else
				EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, 1);


			if (aadlen)
				EVP_Cipher(&ctx, NULL, aad, aadlen);
			if (ptlen)
@@ -254,6 +272,8 @@ int main(int argc,char **argv)
		exit(1);
	if(!strcmp(argv[1],"-encrypt"))
		encrypt = 1;
	else if(!strcmp(argv[1],"-encryptIVext"))
		encrypt = 2;
	else if(!strcmp(argv[1],"-decrypt"))
		encrypt = 0;
	else