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

Initial *very* experimental EVP support for AES-GCM. Note: probably very

broken and subject to change.
parent fd3dbc1d
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -4,6 +4,15 @@

 Changes between 1.0.1 and 1.1.0  [xx XXX xxxx]

  *) 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
     can be set or retrieved with a ctrl. The IV length is by default 12
     bytes (96 bits) but can be set to an alternative value. If the IV
     length exceeds the maximum IV length (currently 16 bytes) it cannot be
     set before the key. 
     [Steve Henson]

  *) New flag in ciphers: EVP_CIPH_FLAG_CUSTOM_CIPHER. This means the
     underlying do_cipher function handles all cipher semantics itself
     including padding and finalisation. This is useful if (for example)
+209 −1
Original line number Diff line number Diff line
@@ -57,8 +57,8 @@
#include <string.h>
#include <assert.h>
#include <openssl/aes.h>
#include <openssl/modes.h>
#include "evp_locl.h"
#include <openssl/modes.h>

static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
					const unsigned char *iv, int enc);
@@ -187,4 +187,212 @@ static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
	return 1;
	}

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;
	/* Pointer to GCM128_CTX: FIXME actual structure later */
	GCM128_CONTEXT *gcm;
	/* IV length */
	int ivlen;
	/* Tag to verify */
	unsigned char tag[16];
	int taglen;
	} EVP_AES_GCM_CTX;

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);
	return 1;
	}

static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
	{
	EVP_AES_GCM_CTX *gctx = c->cipher_data;
	switch (type)
		{
	case EVP_CTRL_INIT:
		gctx->gcm = NULL;
		gctx->key_set = 0;
		gctx->iv_set = 0;
		gctx->ivlen = c->cipher->iv_len;
		gctx->taglen = -1;
		return 1;

	case EVP_CTRL_GCM_SET_IVLEN:
		if (arg <= 0)
			return 0;
		gctx->ivlen = arg;
		return 1;

	case EVP_CTRL_GCM_SET_TAG:
		if (arg <= 0 || arg > 16 || c->encrypt)
			return 0;
		memcpy(gctx->tag, ptr, arg);
		gctx->taglen = arg;
		return 1;

	case EVP_CTRL_GCM_GET_TAG:
		if (arg <= 0 || arg > 16 || !c->encrypt || gctx->taglen < 0)
			return 0;
		memcpy(ptr, gctx->tag, arg);
		return 1;

	default:
		return -1;

		}
	}

static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
                        const unsigned char *iv, int enc)
	{
	EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
	if (!iv && !key)
		return 1;
	if (key)
		{
		AES_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks);
		if (!gctx->gcm)
			{
			gctx->gcm =
				CRYPTO_gcm128_new(&gctx->ks, (block128_f)AES_encrypt);
			if (!gctx->gcm)
				return 0;
			}
		else
			CRYPTO_gcm128_init(gctx->gcm, &gctx->ks, (block128_f)AES_encrypt);
		/* If we have an iv can set it directly, otherwise use
		 * saved IV.
		 */
		if (iv == NULL && gctx->iv_set)
			iv = ctx->iv;
		if (iv)
			{
			CRYPTO_gcm128_setiv(gctx->gcm, iv, gctx->ivlen);
			gctx->iv_set = 1;
			}
		gctx->key_set = 1;
		}
	else
		{
		/* If key set use IV, otherwise copy */
		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);
			}
		gctx->iv_set = 1;
		}
	return 1;
	}

static int aes_gcm(EVP_CIPHER_CTX *ctx, unsigned char *out,
		const unsigned char *in, size_t len)
	{
	EVP_AES_GCM_CTX *gctx = ctx->cipher_data;
	/* If not set up, return error */
	if (!gctx->iv_set && !gctx->key_set)
		return -1;
	if (!ctx->encrypt && gctx->taglen < 0)
		return -1;
	if (in)
		{
		if (out == NULL)
			CRYPTO_gcm128_aad(gctx->gcm, in, len);
		else if (ctx->encrypt)
			CRYPTO_gcm128_encrypt(gctx->gcm, in, out, len);
		else
			CRYPTO_gcm128_decrypt(gctx->gcm, in, out, len);
		return len;
		}
	else
		{
		if (!ctx->encrypt)
			{
			if (CRYPTO_gcm128_finish(gctx->gcm,
					gctx->tag, gctx->taglen) != 0)
				return -1;
			gctx->iv_set = 0;
			return 0;
			}
		CRYPTO_gcm128_tag(gctx->gcm, gctx->tag, 16);
		gctx->taglen = 16;
		/* Don't reuse the IV */
		gctx->iv_set = 0;
		return 0;
		}

	}

static const EVP_CIPHER aes_128_gcm_cipher=
	{
	NID_aes_128_gcm,1,16,12,
	EVP_CIPH_GCM_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_gcm_init_key,
	aes_gcm,
	aes_gcm_cleanup,
	sizeof(EVP_AES_GCM_CTX),
	NULL,
	NULL,
	aes_gcm_ctrl,
	NULL
	};

const EVP_CIPHER *EVP_aes_128_gcm (void)
{	return &aes_128_gcm_cipher;	}

static const EVP_CIPHER aes_192_gcm_cipher=
	{
	NID_aes_128_gcm,1,24,12,
	EVP_CIPH_GCM_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_gcm_init_key,
	aes_gcm,
	aes_gcm_cleanup,
	sizeof(EVP_AES_GCM_CTX),
	NULL,
	NULL,
	aes_gcm_ctrl,
	NULL
	};

const EVP_CIPHER *EVP_aes_192_gcm (void)
{	return &aes_192_gcm_cipher;	}

static const EVP_CIPHER aes_256_gcm_cipher=
	{
	NID_aes_128_gcm,1,32,12,
	EVP_CIPH_GCM_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_gcm_init_key,
	aes_gcm,
	aes_gcm_cleanup,
	sizeof(EVP_AES_GCM_CTX),
	NULL,
	NULL,
	aes_gcm_ctrl,
	NULL
	};

const EVP_CIPHER *EVP_aes_256_gcm (void)
{	return &aes_256_gcm_cipher;	}
		
#endif
+7 −0
Original line number Diff line number Diff line
@@ -329,6 +329,7 @@ struct evp_cipher_st
#define		EVP_CIPH_CFB_MODE		0x3
#define		EVP_CIPH_OFB_MODE		0x4
#define		EVP_CIPH_CTR_MODE		0x5
#define		EVP_CIPH_GCM_MODE		0x6
#define 	EVP_CIPH_MODE			0xF0007
/* Set if variable length cipher */
#define 	EVP_CIPH_VARIABLE_LENGTH	0x8
@@ -370,6 +371,9 @@ struct evp_cipher_st
#define 	EVP_CTRL_RAND_KEY		0x6
#define 	EVP_CTRL_PBE_PRF_NID		0x7
#define 	EVP_CTRL_COPY			0x8
#define 	EVP_CTRL_GCM_SET_IVLEN		0x9
#define 	EVP_CTRL_GCM_GET_TAG		0x10
#define 	EVP_CTRL_GCM_SET_TAG		0x11

typedef struct evp_cipher_info_st
	{
@@ -770,6 +774,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_gcm(void);
const EVP_CIPHER *EVP_aes_192_ecb(void);
const EVP_CIPHER *EVP_aes_192_cbc(void);
const EVP_CIPHER *EVP_aes_192_cfb1(void);
@@ -778,6 +783,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_gcm(void);
const EVP_CIPHER *EVP_aes_256_ecb(void);
const EVP_CIPHER *EVP_aes_256_cbc(void);
const EVP_CIPHER *EVP_aes_256_cfb1(void);
@@ -786,6 +792,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_gcm(void);
#endif
#ifndef OPENSSL_NO_CAMELLIA
const EVP_CIPHER *EVP_camellia_128_ecb(void);