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

EVP support for wrapping algorithms.

Add support for key wrap algorithms via EVP interface.

Generalise AES wrap algorithm and add to modes, making existing
AES wrap algorithm a special case.

Move test code to evptests.txt
parent 415ece73
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -4,6 +4,12 @@

 Changes between 1.0.x and 1.1.0  [xx XXX xxxx]

  *) Add EVP support for key wrapping algorithms, to avoid problems with
     existing code the flag EVP_CIPHER_CTX_WRAP_ALLOW has to be set in
     the EVP_CIPHER_CTX or an error is returned. Add AES and DES3 wrap
     algorithms and include tests cases.
     [Steve Henson]

  *) Extend CMS code to support RSA-PSS signatures and RSA-OAEP for
     enveloped data.
     [Steve Henson]
+3 −192
Original line number Diff line number Diff line
@@ -53,207 +53,18 @@

#include "cryptlib.h"
#include <openssl/aes.h>
#include <openssl/bio.h>

static const unsigned char default_iv[] = {
  0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
};
#include <openssl/modes.h>

int AES_wrap_key(AES_KEY *key, const unsigned char *iv,
		unsigned char *out,
		const unsigned char *in, unsigned int inlen)
	{
	unsigned char *A, B[16], *R;
	unsigned int i, j, t;
	if ((inlen & 0x7) || (inlen < 8))
		return -1;
	A = B;
	t = 1;
	memcpy(out + 8, in, inlen);
	if (!iv)
		iv = default_iv;

	memcpy(A, iv, 8);

	for (j = 0; j < 6; j++)
		{
		R = out + 8;
		for (i = 0; i < inlen; i += 8, t++, R += 8)
			{
			memcpy(B + 8, R, 8);
			AES_encrypt(B, B, key);
			A[7] ^= (unsigned char)(t & 0xff);
			if (t > 0xff)	
				{
				A[6] ^= (unsigned char)((t >> 8) & 0xff);
				A[5] ^= (unsigned char)((t >> 16) & 0xff);
				A[4] ^= (unsigned char)((t >> 24) & 0xff);
				}
			memcpy(R, B + 8, 8);
			}
		}
	memcpy(out, A, 8);
	return inlen + 8;
	return CRYPTO_128_wrap(key, iv, out, in, inlen, (block128_f)AES_encrypt);
	}

int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
		unsigned char *out,
		const unsigned char *in, unsigned int inlen)
	{
	unsigned char *A, B[16], *R;
	unsigned int i, j, t;
	inlen -= 8;
	if (inlen & 0x7)
		return -1;
	if (inlen < 8)
		return -1;
	A = B;
	t =  6 * (inlen >> 3);
	memcpy(A, in, 8);
	memcpy(out, in + 8, inlen);
	for (j = 0; j < 6; j++)
		{
		R = out + inlen - 8;
		for (i = 0; i < inlen; i += 8, t--, R -= 8)
			{
			A[7] ^= (unsigned char)(t & 0xff);
			if (t > 0xff)	
				{
				A[6] ^= (unsigned char)((t >> 8) & 0xff);
				A[5] ^= (unsigned char)((t >> 16) & 0xff);
				A[4] ^= (unsigned char)((t >> 24) & 0xff);
				}
			memcpy(B + 8, R, 8);
			AES_decrypt(B, B, key);
			memcpy(R, B + 8, 8);
			}
		}
	if (!iv)
		iv = default_iv;
	if (memcmp(A, iv, 8))
		{
		OPENSSL_cleanse(out, inlen);
		return 0;
		}
	return inlen;
	}

#ifdef AES_WRAP_TEST

int AES_wrap_unwrap_test(const unsigned char *kek, int keybits,
			 const unsigned char *iv,
			 const unsigned char *eout,
			 const unsigned char *key, int keylen)
	{
	unsigned char *otmp = NULL, *ptmp = NULL;
	int r, ret = 0;
	AES_KEY wctx;
	otmp = OPENSSL_malloc(keylen + 8);
	ptmp = OPENSSL_malloc(keylen);
	if (!otmp || !ptmp)
		return 0;
	if (AES_set_encrypt_key(kek, keybits, &wctx))
		goto err;
	r = AES_wrap_key(&wctx, iv, otmp, key, keylen);
	if (r <= 0)
		goto err;

	if (eout && memcmp(eout, otmp, keylen))
		goto err;
		
	if (AES_set_decrypt_key(kek, keybits, &wctx))
		goto err;
	r = AES_unwrap_key(&wctx, iv, ptmp, otmp, r);

	if (memcmp(key, ptmp, keylen))
		goto err;

	ret = 1;

	err:
	if (otmp)
		OPENSSL_free(otmp);
	if (ptmp)
		OPENSSL_free(ptmp);

	return ret;

	}



int main(int argc, char **argv)
{

static const unsigned char kek[] = {
  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
};

static const unsigned char key[] = {
  0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
  0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};

static const unsigned char e1[] = {
  0x1f, 0xa6, 0x8b, 0x0a, 0x81, 0x12, 0xb4, 0x47,
  0xae, 0xf3, 0x4b, 0xd8, 0xfb, 0x5a, 0x7b, 0x82,
  0x9d, 0x3e, 0x86, 0x23, 0x71, 0xd2, 0xcf, 0xe5
};

static const unsigned char e2[] = {
  0x96, 0x77, 0x8b, 0x25, 0xae, 0x6c, 0xa4, 0x35,
  0xf9, 0x2b, 0x5b, 0x97, 0xc0, 0x50, 0xae, 0xd2,
  0x46, 0x8a, 0xb8, 0xa1, 0x7a, 0xd8, 0x4e, 0x5d
};

static const unsigned char e3[] = {
  0x64, 0xe8, 0xc3, 0xf9, 0xce, 0x0f, 0x5b, 0xa2,
  0x63, 0xe9, 0x77, 0x79, 0x05, 0x81, 0x8a, 0x2a,
  0x93, 0xc8, 0x19, 0x1e, 0x7d, 0x6e, 0x8a, 0xe7
};

static const unsigned char e4[] = {
  0x03, 0x1d, 0x33, 0x26, 0x4e, 0x15, 0xd3, 0x32,
  0x68, 0xf2, 0x4e, 0xc2, 0x60, 0x74, 0x3e, 0xdc,
  0xe1, 0xc6, 0xc7, 0xdd, 0xee, 0x72, 0x5a, 0x93,
  0x6b, 0xa8, 0x14, 0x91, 0x5c, 0x67, 0x62, 0xd2
};

static const unsigned char e5[] = {
  0xa8, 0xf9, 0xbc, 0x16, 0x12, 0xc6, 0x8b, 0x3f,
  0xf6, 0xe6, 0xf4, 0xfb, 0xe3, 0x0e, 0x71, 0xe4,
  0x76, 0x9c, 0x8b, 0x80, 0xa3, 0x2c, 0xb8, 0x95,
  0x8c, 0xd5, 0xd1, 0x7d, 0x6b, 0x25, 0x4d, 0xa1
};

static const unsigned char e6[] = {
  0x28, 0xc9, 0xf4, 0x04, 0xc4, 0xb8, 0x10, 0xf4,
  0xcb, 0xcc, 0xb3, 0x5c, 0xfb, 0x87, 0xf8, 0x26,
  0x3f, 0x57, 0x86, 0xe2, 0xd8, 0x0e, 0xd3, 0x26,
  0xcb, 0xc7, 0xf0, 0xe7, 0x1a, 0x99, 0xf4, 0x3b,
  0xfb, 0x98, 0x8b, 0x9b, 0x7a, 0x02, 0xdd, 0x21
};

	AES_KEY wctx, xctx;
	int ret;
	ret = AES_wrap_unwrap_test(kek, 128, NULL, e1, key, 16);
	fprintf(stderr, "Key test result %d\n", ret);
	ret = AES_wrap_unwrap_test(kek, 192, NULL, e2, key, 16);
	fprintf(stderr, "Key test result %d\n", ret);
	ret = AES_wrap_unwrap_test(kek, 256, NULL, e3, key, 16);
	fprintf(stderr, "Key test result %d\n", ret);
	ret = AES_wrap_unwrap_test(kek, 192, NULL, e4, key, 24);
	fprintf(stderr, "Key test result %d\n", ret);
	ret = AES_wrap_unwrap_test(kek, 256, NULL, e5, key, 24);
	fprintf(stderr, "Key test result %d\n", ret);
	ret = AES_wrap_unwrap_test(kek, 256, NULL, e6, key, 32);
	fprintf(stderr, "Key test result %d\n", ret);
	return CRYPTO_128_unwrap(key, iv, out, in, inlen, (block128_f)AES_decrypt);
	}
	
	
#endif
+4 −0
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ void OpenSSL_add_all_ciphers(void)
	EVP_add_cipher(EVP_des_ecb());
	EVP_add_cipher(EVP_des_ede());
	EVP_add_cipher(EVP_des_ede3());
	EVP_add_cipher(EVP_des_ede3_wrap());
#endif

#ifndef OPENSSL_NO_RC4
@@ -173,6 +174,7 @@ void OpenSSL_add_all_ciphers(void)
	EVP_add_cipher(EVP_aes_128_gcm());
	EVP_add_cipher(EVP_aes_128_xts());
	EVP_add_cipher(EVP_aes_128_ccm());
	EVP_add_cipher(EVP_aes_128_wrap());
	EVP_add_cipher_alias(SN_aes_128_cbc,"AES128");
	EVP_add_cipher_alias(SN_aes_128_cbc,"aes128");
	EVP_add_cipher(EVP_aes_192_ecb());
@@ -184,6 +186,7 @@ void OpenSSL_add_all_ciphers(void)
	EVP_add_cipher(EVP_aes_192_ctr());
	EVP_add_cipher(EVP_aes_192_gcm());
	EVP_add_cipher(EVP_aes_192_ccm());
	EVP_add_cipher(EVP_aes_192_wrap());
	EVP_add_cipher_alias(SN_aes_192_cbc,"AES192");
	EVP_add_cipher_alias(SN_aes_192_cbc,"aes192");
	EVP_add_cipher(EVP_aes_256_ecb());
@@ -196,6 +199,7 @@ void OpenSSL_add_all_ciphers(void)
	EVP_add_cipher(EVP_aes_256_gcm());
	EVP_add_cipher(EVP_aes_256_xts());
	EVP_add_cipher(EVP_aes_256_ccm());
	EVP_add_cipher(EVP_aes_256_wrap());
	EVP_add_cipher_alias(SN_aes_256_cbc,"AES256");
	EVP_add_cipher_alias(SN_aes_256_cbc,"aes256");
#if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA1)
+98 −0
Original line number Diff line number Diff line
@@ -1880,4 +1880,102 @@ 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)

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, 8);
		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;
	if (inlen % 8)
		return 0;
	if (!out)
		{
		if (ctx->encrypt)
			return inlen + 8;
		else
			return inlen - 8;
		}
	if (!in)
		return 0;
	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)

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;
	}

#endif
+107 −0
Original line number Diff line number Diff line
@@ -374,4 +374,111 @@ const EVP_CIPHER *EVP_des_ede3(void)
{
	return &des_ede3_ecb;
}

#ifndef OPENSSL_NO_SHA

#include <openssl/sha.h>

static const unsigned char wrap_iv[8] = {0x4a,0xdd,0xa2,0x2c,0x79,0xe8,0x21,0x05};

static int des_ede3_unwrap(EVP_CIPHER_CTX *ctx, unsigned char *out,
				const unsigned char *in, size_t inl)
	{
	unsigned char icv[8], iv[8], sha1tmp[SHA_DIGEST_LENGTH];
	int rv = -1;
	if (inl < 24)
		return -1;
	if (!out)
		return inl - 16;
	memcpy(ctx->iv, wrap_iv, 8);
	/* Decrypt first block which will end up as icv */
	des_ede_cbc_cipher(ctx, icv, in, 8);
	/* Decrypt central blocks */
	/* If decrypting in place move whole output along a block
	 * so the next des_ede_cbc_cipher is in place.
	 */
	if (out == in)
		{
		memmove(out, out + 8, inl - 8);
		in -= 8;
		}
	des_ede_cbc_cipher(ctx, out, in + 8, inl - 16);
	/* Decrypt final block which will be IV */
	des_ede_cbc_cipher(ctx, iv, in + inl - 8, 8);
	/* Reverse order of everything */
	BUF_reverse(icv, NULL, 8);
	BUF_reverse(out, NULL, inl - 16);
	BUF_reverse(ctx->iv, iv, 8);
	/* Decrypt again using new IV */
	des_ede_cbc_cipher(ctx, out, out, inl - 16);
	des_ede_cbc_cipher(ctx, icv, icv, 8);
	/* Work out SHA1 hash of first portion */
	SHA1(out, inl - 16, sha1tmp);

	if (!CRYPTO_memcmp(sha1tmp, icv, 8))
		rv = inl - 16;
	OPENSSL_cleanse(icv, 8);
	OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH);
	OPENSSL_cleanse(iv, 8);
	OPENSSL_cleanse(ctx->iv, 8);
	if (rv == -1)
		OPENSSL_cleanse(out, inl - 16);
	
	return rv;
	}

static int des_ede3_wrap(EVP_CIPHER_CTX *ctx, unsigned char *out,
				const unsigned char *in, size_t inl)
	{
	unsigned char sha1tmp[SHA_DIGEST_LENGTH];
	if (!out)
		return inl + 16;
	/* Copy input to output buffer + 8 so we have space for IV */
	memmove(out + 8, in, inl);
	/* Work out ICV */
	SHA1(in, inl, sha1tmp);
	memcpy(out + inl + 8, sha1tmp, 8);
	OPENSSL_cleanse(sha1tmp, SHA_DIGEST_LENGTH);
	/* Generate random IV */
	RAND_bytes(ctx->iv, 8);
	memcpy(out, ctx->iv, 8);
	/* Encrypt everything after IV in place */
	des_ede_cbc_cipher(ctx, out + 8, out + 8, inl + 8);
	BUF_reverse(out, NULL, inl + 16);
	memcpy(ctx->iv, wrap_iv, 8);
	des_ede_cbc_cipher(ctx, out, out, inl + 16);
	return inl + 16;
	}

static int des_ede3_wrap_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
				const unsigned char *in, size_t inl)
	{
	/* Sanity check input length: we typically only wrap keys
	 * so EVP_MAXCHUNK is more than will ever be needed. Also
	 * input length must be a multiple of 8 bits.
	 */
	if (inl >= EVP_MAXCHUNK || inl % 8)
		return -1;
	if (ctx->encrypt)
		return des_ede3_wrap(ctx, out, in, inl);
	else
		return des_ede3_unwrap(ctx, out, in, inl);
	}

static const EVP_CIPHER des3_wrap = {
	NID_id_smime_alg_CMS3DESwrap,
	8, 24, 0,
	EVP_CIPH_WRAP_MODE|EVP_CIPH_CUSTOM_IV|EVP_CIPH_FLAG_CUSTOM_CIPHER,
	des_ede3_init_key, des_ede3_wrap_cipher,
	NULL,	
	sizeof(DES_EDE_KEY),
	NULL,NULL,NULL,NULL };


const EVP_CIPHER *EVP_des_ede3_wrap(void)
	{
	return &des3_wrap;
	}

# endif
#endif
Loading