Add AES Key Wrap mode.
This is needed in order to support Web Crypto. https://code.google.com/p/chromium/issues/detail?id=396407 Change-Id: I900d8cad2716c2e3341eeae153659502326c9173 Reviewed-on: https://boringssl-review.googlesource.com/1335 Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
committed by
Adam Langley
parent
7e3305eebd
commit
93a3dcd572
@@ -168,6 +168,10 @@ int main(int argc, char **argv) {
|
||||
aead = EVP_aead_chacha20_poly1305();
|
||||
} else if (strcmp(argv[1], "rc4-md5") == 0) {
|
||||
aead = EVP_aead_rc4_md5_tls();
|
||||
} else if (strcmp(argv[1], "aes-128-key-wrap") == 0) {
|
||||
aead = EVP_aead_aes_128_key_wrap();
|
||||
} else if (strcmp(argv[1], "aes-256-key-wrap") == 0) {
|
||||
aead = EVP_aead_aes_256_key_wrap();
|
||||
} else {
|
||||
fprintf(stderr, "Unknown AEAD: %s\n", argv[1]);
|
||||
return 2;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# These test vectors have been taken from
|
||||
# http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf
|
||||
|
||||
KEY: 000102030405060708090A0B0C0D0E0F
|
||||
NONCE:
|
||||
IN: 00112233445566778899AABBCCDDEEFF
|
||||
AD:
|
||||
CT: 1FA68B0A8112B447AEF34BD8FB5A7B82
|
||||
TAG: 9D3E862371D2CFE5
|
||||
@@ -0,0 +1,23 @@
|
||||
# These test vectors have been taken from
|
||||
# http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf
|
||||
|
||||
KEY: 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
|
||||
NONCE:
|
||||
IN: 00112233445566778899AABBCCDDEEFF
|
||||
AD:
|
||||
CT: 64E8C3F9CE0F5BA263E9777905818A2A
|
||||
TAG: 93C8191E7D6E8AE7
|
||||
|
||||
KEY: 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
|
||||
NONCE:
|
||||
IN: 00112233445566778899AABBCCDDEEFF0001020304050607
|
||||
AD:
|
||||
CT: A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB895
|
||||
TAG: 8CD5D17D6B254DA1
|
||||
|
||||
KEY: 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F
|
||||
NONCE:
|
||||
IN: 00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F
|
||||
AD:
|
||||
CT: 28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43B
|
||||
TAG: FB988B9B7A02DD21
|
||||
@@ -28,6 +28,9 @@ const ERR_STRING_DATA CIPHER_error_string_data[] = {
|
||||
{ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_aes_gcm_init, 0), "aead_aes_gcm_init"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_aes_gcm_open, 0), "aead_aes_gcm_open"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_aes_gcm_seal, 0), "aead_aes_gcm_seal"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_aes_key_wrap_init, 0), "aead_aes_key_wrap_init"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_aes_key_wrap_open, 0), "aead_aes_key_wrap_open"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_aes_key_wrap_seal, 0), "aead_aes_key_wrap_seal"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_chacha20_poly1305_init, 0), "aead_chacha20_poly1305_init"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_chacha20_poly1305_open, 0), "aead_chacha20_poly1305_open"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, CIPHER_F_aead_chacha20_poly1305_seal, 0), "aead_chacha20_poly1305_seal"},
|
||||
@@ -52,7 +55,11 @@ const ERR_STRING_DATA CIPHER_error_string_data[] = {
|
||||
{ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_OUTPUT_ALIASES_INPUT), "OUTPUT_ALIASES_INPUT"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_TAG_TOO_LARGE), "TAG_TOO_LARGE"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_TOO_LARGE), "TOO_LARGE"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_UNSUPPORTED_AD_SIZE), "UNSUPPORTED_AD_SIZE"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_UNSUPPORTED_INPUT_SIZE), "UNSUPPORTED_INPUT_SIZE"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_UNSUPPORTED_KEY_SIZE), "UNSUPPORTED_KEY_SIZE"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_UNSUPPORTED_NONCE_SIZE), "UNSUPPORTED_NONCE_SIZE"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_UNSUPPORTED_TAG_SIZE), "UNSUPPORTED_TAG_SIZE"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_WRAP_MODE_NOT_ALLOWED), "WRAP_MODE_NOT_ALLOWED"},
|
||||
{ERR_PACK(ERR_LIB_CIPHER, 0, CIPHER_R_WRONG_FINAL_BLOCK_LENGTH), "WRONG_FINAL_BLOCK_LENGTH"},
|
||||
{0, NULL},
|
||||
|
||||
@@ -986,3 +986,267 @@ static const EVP_AEAD aead_aes_256_gcm = {
|
||||
const EVP_AEAD *EVP_aead_aes_128_gcm() { return &aead_aes_128_gcm; }
|
||||
|
||||
const EVP_AEAD *EVP_aead_aes_256_gcm() { return &aead_aes_256_gcm; }
|
||||
|
||||
|
||||
/* AES Key Wrap is specified in
|
||||
* http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf
|
||||
* or https://tools.ietf.org/html/rfc3394 */
|
||||
|
||||
struct aead_aes_key_wrap_ctx {
|
||||
uint8_t key[32];
|
||||
unsigned key_bits;
|
||||
};
|
||||
|
||||
static int aead_aes_key_wrap_init(EVP_AEAD_CTX *ctx, const uint8_t *key,
|
||||
size_t key_len, size_t tag_len) {
|
||||
struct aead_aes_key_wrap_ctx *kw_ctx;
|
||||
const size_t key_bits = key_len * 8;
|
||||
|
||||
if (key_bits != 128 && key_bits != 256) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_init, CIPHER_R_BAD_KEY_LENGTH);
|
||||
return 0; /* EVP_AEAD_CTX_init should catch this. */
|
||||
}
|
||||
|
||||
if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) {
|
||||
tag_len = 8;
|
||||
}
|
||||
|
||||
if (tag_len != 8) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_init,
|
||||
CIPHER_R_UNSUPPORTED_TAG_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
kw_ctx = OPENSSL_malloc(sizeof(struct aead_aes_key_wrap_ctx));
|
||||
if (kw_ctx == NULL) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_init, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(kw_ctx->key, key, key_len);
|
||||
kw_ctx->key_bits = key_bits;
|
||||
|
||||
ctx->aead_state = kw_ctx;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void aead_aes_key_wrap_cleanup(EVP_AEAD_CTX *ctx) {
|
||||
struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state;
|
||||
OPENSSL_cleanse(kw_ctx, sizeof(struct aead_aes_key_wrap_ctx));
|
||||
OPENSSL_free(kw_ctx);
|
||||
}
|
||||
|
||||
/* kDefaultAESKeyWrapNonce is the default nonce value given in 2.2.3.1. */
|
||||
static const uint8_t kDefaultAESKeyWrapNonce[8] = {0xa6, 0xa6, 0xa6, 0xa6,
|
||||
0xa6, 0xa6, 0xa6, 0xa6};
|
||||
|
||||
|
||||
static int aead_aes_key_wrap_seal(const EVP_AEAD_CTX *ctx, uint8_t *out,
|
||||
size_t *out_len, size_t max_out_len,
|
||||
const uint8_t *nonce, size_t nonce_len,
|
||||
const uint8_t *in, size_t in_len,
|
||||
const uint8_t *ad, size_t ad_len) {
|
||||
const struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state;
|
||||
union {
|
||||
double align;
|
||||
AES_KEY ks;
|
||||
} ks;
|
||||
/* Variables in this function match up with the variables in the second half
|
||||
* of section 2.2.1. */
|
||||
unsigned i, j, n;
|
||||
uint8_t A[AES_BLOCK_SIZE];
|
||||
|
||||
if (ad_len != 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
|
||||
CIPHER_R_UNSUPPORTED_AD_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nonce_len == 0) {
|
||||
nonce = kDefaultAESKeyWrapNonce;
|
||||
nonce_len = sizeof(kDefaultAESKeyWrapNonce);
|
||||
}
|
||||
|
||||
if (nonce_len != 8) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
|
||||
CIPHER_R_UNSUPPORTED_NONCE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_len % 8 != 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
|
||||
CIPHER_R_UNSUPPORTED_INPUT_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The code below only handles a 32-bit |t| thus 6*|n| must be less than
|
||||
* 2^32, where |n| is |in_len| / 8. So in_len < 4/3 * 2^32 and we
|
||||
* conservatively cap it to 2^32-16 to stop 32-bit platforms complaining that
|
||||
* a comparision is always true. */
|
||||
if (in_len > 0xfffffff0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal, CIPHER_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = in_len / 8;
|
||||
|
||||
if (n < 2) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
|
||||
CIPHER_R_UNSUPPORTED_INPUT_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_len + 8 < in_len) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal, CIPHER_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (max_out_len < in_len + 8) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
|
||||
CIPHER_R_BUFFER_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (AES_set_encrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_seal,
|
||||
CIPHER_R_AES_KEY_SETUP_FAILED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memmove(out + 8, in, in_len);
|
||||
memcpy(A, nonce, 8);
|
||||
|
||||
for (j = 0; j < 6; j++) {
|
||||
for (i = 1; i <= n; i++) {
|
||||
uint32_t t;
|
||||
|
||||
memcpy(A + 8, out + 8 * i, 8);
|
||||
AES_encrypt(A, A, &ks.ks);
|
||||
t = n * j + i;
|
||||
A[7] ^= t & 0xff;
|
||||
A[6] ^= (t >> 8) & 0xff;
|
||||
A[5] ^= (t >> 16) & 0xff;
|
||||
A[4] ^= (t >> 24) & 0xff;
|
||||
memcpy(out + 8 * i, A + 8, 8);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(out, A, 8);
|
||||
*out_len = in_len + 8;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aead_aes_key_wrap_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
|
||||
size_t *out_len, size_t max_out_len,
|
||||
const uint8_t *nonce, size_t nonce_len,
|
||||
const uint8_t *in, size_t in_len,
|
||||
const uint8_t *ad, size_t ad_len) {
|
||||
const struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state;
|
||||
union {
|
||||
double align;
|
||||
AES_KEY ks;
|
||||
} ks;
|
||||
/* Variables in this function match up with the variables in the second half
|
||||
* of section 2.2.1. */
|
||||
unsigned i, j, n;
|
||||
uint8_t A[AES_BLOCK_SIZE];
|
||||
|
||||
if (ad_len != 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open,
|
||||
CIPHER_R_UNSUPPORTED_AD_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nonce_len == 0) {
|
||||
nonce = kDefaultAESKeyWrapNonce;
|
||||
nonce_len = sizeof(kDefaultAESKeyWrapNonce);
|
||||
}
|
||||
|
||||
if (nonce_len != 8) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open,
|
||||
CIPHER_R_UNSUPPORTED_NONCE_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_len % 8 != 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open,
|
||||
CIPHER_R_UNSUPPORTED_INPUT_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The code below only handles a 32-bit |t| thus 6*|n| must be less than
|
||||
* 2^32, where |n| is |in_len| / 8. So in_len < 4/3 * 2^32 and we
|
||||
* conservatively cap it to 2^32-8 to stop 32-bit platforms complaining that
|
||||
* a comparision is always true. */
|
||||
if (in_len > 0xfffffff8) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open, CIPHER_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_len < 24) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_gcm_open, CIPHER_R_BAD_DECRYPT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = (in_len / 8) - 1;
|
||||
|
||||
if (max_out_len < in_len - 8) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open,
|
||||
CIPHER_R_BUFFER_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (AES_set_decrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_key_wrap_open,
|
||||
CIPHER_R_AES_KEY_SETUP_FAILED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(A, in, 8);
|
||||
memmove(out, in + 8, in_len);
|
||||
|
||||
for (j = 5; j < 6; j--) {
|
||||
for (i = n; i > 0; i--) {
|
||||
uint32_t t;
|
||||
|
||||
t = n * j + i;
|
||||
A[7] ^= t & 0xff;
|
||||
A[6] ^= (t >> 8) & 0xff;
|
||||
A[5] ^= (t >> 16) & 0xff;
|
||||
A[4] ^= (t >> 24) & 0xff;
|
||||
memcpy(A + 8, out + 8 * (i - 1), 8);
|
||||
AES_decrypt(A, A, &ks.ks);
|
||||
memcpy(out + 8 * (i - 1), A + 8, 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (CRYPTO_memcmp(A, nonce, 8) != 0) {
|
||||
OPENSSL_PUT_ERROR(CIPHER, aead_aes_gcm_open, CIPHER_R_BAD_DECRYPT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_len = in_len - 8;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const EVP_AEAD aead_aes_128_key_wrap = {
|
||||
16, /* key len */
|
||||
8, /* nonce len */
|
||||
8, /* overhead */
|
||||
8, /* max tag length */
|
||||
aead_aes_key_wrap_init, aead_aes_key_wrap_cleanup,
|
||||
aead_aes_key_wrap_seal, aead_aes_key_wrap_open,
|
||||
};
|
||||
|
||||
static const EVP_AEAD aead_aes_256_key_wrap = {
|
||||
32, /* key len */
|
||||
8, /* nonce len */
|
||||
8, /* overhead */
|
||||
8, /* max tag length */
|
||||
aead_aes_key_wrap_init, aead_aes_key_wrap_cleanup,
|
||||
aead_aes_key_wrap_seal, aead_aes_key_wrap_open,
|
||||
};
|
||||
|
||||
const EVP_AEAD *EVP_aead_aes_128_key_wrap() { return &aead_aes_128_key_wrap; }
|
||||
|
||||
const EVP_AEAD *EVP_aead_aes_256_key_wrap() { return &aead_aes_256_key_wrap; }
|
||||
|
||||
@@ -101,6 +101,20 @@ const EVP_AEAD *EVP_aead_aes_256_gcm(void);
|
||||
/* EVP_aead_chacha20_poly1305 is an AEAD built from ChaCha20 and Poly1305. */
|
||||
const EVP_AEAD *EVP_aead_chacha20_poly1305();
|
||||
|
||||
/* EVP_aead_aes_128_key_wrap is AES-128 Key Wrap mode. This should never be
|
||||
* used except to interoperate with existing systems that use this mode.
|
||||
*
|
||||
* If the nonce is emtpy then the default nonce will be used, otherwise it must
|
||||
* be eight bytes long. The input must be a multiple of eight bytes long. No
|
||||
* additional data can be given to this mode. */
|
||||
const EVP_AEAD *EVP_aead_aes_128_key_wrap();
|
||||
|
||||
/* EVP_aead_aes_256_key_wrap is AES-256 in Key Wrap mode. This should never be
|
||||
* used except to interoperate with existing systems that use this mode.
|
||||
*
|
||||
* See |EVP_aead_aes_128_key_wrap| for details. */
|
||||
const EVP_AEAD *EVP_aead_aes_256_key_wrap();
|
||||
|
||||
|
||||
/* TLS specific AEAD algorithms.
|
||||
*
|
||||
|
||||
@@ -439,6 +439,9 @@ typedef struct evp_cipher_info_st {
|
||||
#define CIPHER_F_aead_rc4_md5_tls_init 116
|
||||
#define CIPHER_F_aead_rc4_md5_tls_seal 117
|
||||
#define CIPHER_F_aead_rc4_md5_tls_open 118
|
||||
#define CIPHER_F_aead_aes_key_wrap_seal 119
|
||||
#define CIPHER_F_aead_aes_key_wrap_init 120
|
||||
#define CIPHER_F_aead_aes_key_wrap_open 121
|
||||
#define CIPHER_R_WRAP_MODE_NOT_ALLOWED 100
|
||||
#define CIPHER_R_AES_KEY_SETUP_FAILED 101
|
||||
#define CIPHER_R_INPUT_NOT_INITIALIZED 102
|
||||
@@ -458,5 +461,9 @@ typedef struct evp_cipher_info_st {
|
||||
#define CIPHER_R_IV_TOO_LARGE 116
|
||||
#define CIPHER_R_INVALID_AD_SIZE 117
|
||||
#define CIPHER_R_INVALID_AD 118
|
||||
#define CIPHER_R_UNSUPPORTED_TAG_SIZE 119
|
||||
#define CIPHER_R_UNSUPPORTED_INPUT_SIZE 120
|
||||
#define CIPHER_R_UNSUPPORTED_AD_SIZE 121
|
||||
#define CIPHER_R_UNSUPPORTED_NONCE_SIZE 122
|
||||
|
||||
#endif /* OPENSSL_HEADER_CIPHER_H */
|
||||
|
||||
@@ -19,6 +19,8 @@ TESTS="
|
||||
./crypto/cipher/aead_test aes-256-gcm ../crypto/cipher/aes_256_gcm_tests.txt
|
||||
./crypto/cipher/aead_test chacha20-poly1305 ../crypto/cipher/chacha20_poly1305_tests.txt
|
||||
./crypto/cipher/aead_test rc4-md5 ../crypto/cipher/rc4_md5_tests.txt
|
||||
./crypto/cipher/aead_test aes-128-key-wrap ../crypto/cipher/aes_128_key_wrap_tests.txt
|
||||
./crypto/cipher/aead_test aes-256-key-wrap ../crypto/cipher/aes_256_key_wrap_tests.txt
|
||||
./crypto/base64/base64_test
|
||||
./crypto/bio/bio_test
|
||||
./crypto/bn/bn_test
|
||||
|
||||
Reference in New Issue
Block a user