Add RFC5297 AES-SIV support

Based originally on github.com/dfoxfranke/libaes_siv

This creates an SIV128 mode that uses EVP interfaces for the CBC, CTR
and CMAC code to reduce complexity at the cost of perfomance. The
expected use is for short inputs, not TLS-sized records.

Add multiple AAD input capacity in the EVP tests.

Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de>
(Merged from https://github.com/openssl/openssl/pull/3540)
This commit is contained in:
Todd Short 2017-05-19 10:27:28 -04:00 committed by Pauli
parent 6de98b4fb6
commit b1ceb439f2
21 changed files with 726 additions and 43 deletions

View File

@ -36,6 +36,9 @@
and retain API/ABI compatibility.
[Richard Levitte]
*) Add support for RFC5297 SIV mode (siv128), including AES-SIV.
[Todd Short]
*) Remove the 'dist' target and add a tarball building script. The
'dist' target has fallen out of use, and it shouldn't be
necessary to configure just to create a source distribution.

View File

@ -391,6 +391,7 @@ my @disablables = (
"seed",
"shared",
"siphash",
"siv",
"sm2",
"sm3",
"sm4",
@ -498,6 +499,8 @@ my @disable_cascades = (
sub { !$disabled{"unit-test"} } => [ "heartbeats" ],
sub { !$disabled{"msan"} } => [ "asm" ],
sub { $disabled{cmac}; } => [ "siv" ],
);
# Avoid protocol support holes. Also disable all versions below N, if version

View File

@ -556,9 +556,9 @@
Build without support for the specified algorithm, where
<alg> is one of: aria, bf, blake2, camellia, cast, chacha,
cmac, des, dh, dsa, ecdh, ecdsa, idea, md4, mdc2, ocb,
poly1305, rc2, rc4, rmd160, scrypt, seed, siphash, sm2, sm3,
sm4 or whirlpool. The "ripemd" algorithm is deprecated and
if used is synonymous with rmd160.
poly1305, rc2, rc4, rmd160, scrypt, seed, siphash, siv, sm2,
sm3, sm4 or whirlpool. The "ripemd" algorithm is deprecated
and if used is synonymous with rmd160.
-Dxxx, -Ixxx, -Wp, -lxxx, -Lxxx, -Wl, -rpath, -R, -framework, -static
These system specific options will be recognised and

View File

@ -2657,6 +2657,10 @@ int speed_main(int argc, char **argv)
EVP_CipherInit_ex(loopargs[k].ctx, NULL, NULL,
loopargs[k].key, NULL, -1);
OPENSSL_clear_free(loopargs[k].key, keylen);
/* SIV mode only allows for a single Update operation */
if (EVP_CIPHER_mode(evp_cipher) == EVP_CIPH_SIV_MODE)
EVP_CIPHER_CTX_ctrl(loopargs[k].ctx, EVP_CTRL_SET_SPEED, 1, NULL);
}
Time_F(START);

View File

@ -190,7 +190,11 @@ void openssl_add_all_ciphers_int(void)
EVP_add_cipher(EVP_aes_256_cbc_hmac_sha1());
EVP_add_cipher(EVP_aes_128_cbc_hmac_sha256());
EVP_add_cipher(EVP_aes_256_cbc_hmac_sha256());
#ifndef OPENSSL_NO_SIV
EVP_add_cipher(EVP_aes_128_siv());
EVP_add_cipher(EVP_aes_192_siv());
EVP_add_cipher(EVP_aes_256_siv());
#endif
#ifndef OPENSSL_NO_ARIA
EVP_add_cipher(EVP_aria_128_ecb());
EVP_add_cipher(EVP_aria_128_cbc());

View File

@ -17,6 +17,7 @@
#include "internal/evp_int.h"
#include "modes_lcl.h"
#include <openssl/rand.h>
#include <openssl/cmac.h>
#include "evp_locl.h"
typedef struct {
@ -540,7 +541,8 @@ const EVP_CIPHER *EVP_aes_##keylen##_##mode(void) \
# define BLOCK_CIPHER_custom(nid,keylen,blocksize,ivlen,mode,MODE,flags) \
static const EVP_CIPHER aesni_##keylen##_##mode = { \
nid##_##keylen##_##mode,blocksize, \
(EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE?2:1)*keylen/8, ivlen, \
(EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE||EVP_CIPH_##MODE##_MODE==EVP_CIPH_SIV_MODE?2:1)*keylen/8, \
ivlen, \
flags|EVP_CIPH_##MODE##_MODE, \
aesni_##mode##_init_key, \
aesni_##mode##_cipher, \
@ -549,7 +551,8 @@ static const EVP_CIPHER aesni_##keylen##_##mode = { \
NULL,NULL,aes_##mode##_ctrl,NULL }; \
static const EVP_CIPHER aes_##keylen##_##mode = { \
nid##_##keylen##_##mode,blocksize, \
(EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE?2:1)*keylen/8, ivlen, \
(EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE||EVP_CIPH_##MODE##_MODE==EVP_CIPH_SIV_MODE?2:1)*keylen/8, \
ivlen, \
flags|EVP_CIPH_##MODE##_MODE, \
aes_##mode##_init_key, \
aes_##mode##_cipher, \
@ -948,7 +951,8 @@ const EVP_CIPHER *EVP_aes_##keylen##_##mode(void) \
# define BLOCK_CIPHER_custom(nid,keylen,blocksize,ivlen,mode,MODE,flags) \
static const EVP_CIPHER aes_t4_##keylen##_##mode = { \
nid##_##keylen##_##mode,blocksize, \
(EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE?2:1)*keylen/8, ivlen, \
(EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE||EVP_CIPH_##MODE##_MODE==EVP_CIPH_SIV_MODE?2:1)*keylen/8, \
ivlen, \
flags|EVP_CIPH_##MODE##_MODE, \
aes_t4_##mode##_init_key, \
aes_t4_##mode##_cipher, \
@ -957,7 +961,8 @@ static const EVP_CIPHER aes_t4_##keylen##_##mode = { \
NULL,NULL,aes_##mode##_ctrl,NULL }; \
static const EVP_CIPHER aes_##keylen##_##mode = { \
nid##_##keylen##_##mode,blocksize, \
(EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE?2:1)*keylen/8, ivlen, \
(EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE||EVP_CIPH_##MODE##_MODE==EVP_CIPH_SIV_MODE?2:1)*keylen/8, \
ivlen, \
flags|EVP_CIPH_##MODE##_MODE, \
aes_##mode##_init_key, \
aes_##mode##_cipher, \
@ -2512,7 +2517,8 @@ const EVP_CIPHER *EVP_aes_##keylen##_##mode(void) \
# define BLOCK_CIPHER_custom(nid,keylen,blocksize,ivlen,mode,MODE,flags) \
static const EVP_CIPHER aes_##keylen##_##mode = { \
nid##_##keylen##_##mode,blocksize, \
(EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE?2:1)*keylen/8, ivlen, \
(EVP_CIPH_##MODE##_MODE==EVP_CIPH_XTS_MODE||EVP_CIPH_##MODE##_MODE==EVP_CIPH_SIV_MODE?2:1)*keylen/8, \
ivlen, \
flags|EVP_CIPH_##MODE##_MODE, \
aes_##mode##_init_key, \
aes_##mode##_cipher, \
@ -4263,3 +4269,114 @@ BLOCK_CIPHER_custom(NID_aes, 192, 16, 12, ocb, OCB,
BLOCK_CIPHER_custom(NID_aes, 256, 16, 12, ocb, OCB,
EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS)
#endif /* OPENSSL_NO_OCB */
/* AES-SIV mode */
#ifndef OPENSSL_NO_SIV
typedef SIV128_CONTEXT EVP_AES_SIV_CTX;
#define aesni_siv_init_key aes_siv_init_key
static int aes_siv_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
const unsigned char *iv, int enc)
{
const EVP_CIPHER *ctr;
const EVP_CIPHER *cbc;
SIV128_CONTEXT *sctx = EVP_C_DATA(SIV128_CONTEXT, ctx);
int klen = EVP_CIPHER_CTX_key_length(ctx) / 2;
if (key == NULL)
return 1;
switch (klen) {
case 16:
cbc = EVP_aes_128_cbc();
ctr = EVP_aes_128_ctr();
break;
case 24:
cbc = EVP_aes_192_cbc();
ctr = EVP_aes_192_ctr();
break;
case 32:
cbc = EVP_aes_256_cbc();
ctr = EVP_aes_256_ctr();
break;
default:
return 0;
}
/* klen is the length of the underlying cipher, not the input key,
which should be twice as long */
return CRYPTO_siv128_init(sctx, key, klen, cbc, ctr);
}
#define aesni_siv_cipher aes_siv_cipher
static int aes_siv_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
const unsigned char *in, size_t len)
{
SIV128_CONTEXT *sctx = EVP_C_DATA(SIV128_CONTEXT, ctx);
/* EncryptFinal or DecryptFinal */
if (in == NULL)
return CRYPTO_siv128_finish(sctx);
/* Deal with associated data */
if (out == NULL)
return CRYPTO_siv128_aad(sctx, in, len);
if (EVP_CIPHER_CTX_encrypting(ctx))
return CRYPTO_siv128_encrypt(sctx, in, out, len);
return CRYPTO_siv128_decrypt(sctx, in, out, len);
}
#define aesni_siv_cleanup aes_siv_cleanup
static int aes_siv_cleanup(EVP_CIPHER_CTX *c)
{
SIV128_CONTEXT *sctx = EVP_C_DATA(SIV128_CONTEXT, c);
return CRYPTO_siv128_cleanup(sctx);
}
#define aesni_siv_ctrl aes_siv_ctrl
static int aes_siv_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr)
{
SIV128_CONTEXT *sctx = EVP_C_DATA(SIV128_CONTEXT, c);
SIV128_CONTEXT *sctx_out;
switch (type) {
case EVP_CTRL_INIT:
return CRYPTO_siv128_cleanup(sctx);
case EVP_CTRL_SET_SPEED:
return CRYPTO_siv128_speed(sctx, arg);
case EVP_CTRL_AEAD_SET_TAG:
if (!EVP_CIPHER_CTX_encrypting(c))
return CRYPTO_siv128_set_tag(sctx, ptr, arg);
return 1;
case EVP_CTRL_AEAD_GET_TAG:
if (!EVP_CIPHER_CTX_encrypting(c))
return 0;
return CRYPTO_siv128_get_tag(sctx, ptr, arg);
case EVP_CTRL_COPY:
sctx_out = EVP_C_DATA(SIV128_CONTEXT, (EVP_CIPHER_CTX*)ptr);
return CRYPTO_siv128_copy_ctx(sctx_out, sctx);
default:
return -1;
}
}
#define SIV_FLAGS (EVP_CIPH_FLAG_AEAD_CIPHER | EVP_CIPH_FLAG_DEFAULT_ASN1 \
| EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER \
| EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_COPY \
| EVP_CIPH_CTRL_INIT)
BLOCK_CIPHER_custom(NID_aes, 128, 1, 0, siv, SIV, SIV_FLAGS)
BLOCK_CIPHER_custom(NID_aes, 192, 1, 0, siv, SIV, SIV_FLAGS)
BLOCK_CIPHER_custom(NID_aes, 256, 1, 0, siv, SIV, SIV_FLAGS)
#endif

View File

@ -1,7 +1,7 @@
LIBS=../../libcrypto
SOURCE[../../libcrypto]=\
cbc128.c ctr128.c cts128.c cfb128.c ofb128.c gcm128.c \
ccm128.c xts128.c wrap128.c ocb128.c \
ccm128.c xts128.c wrap128.c ocb128.c siv128.c \
{- $target{modes_asm_src} -}
INCLUDE[gcm128.o]=..

View File

@ -188,3 +188,28 @@ struct ocb128_context {
} sess;
};
#endif /* OPENSSL_NO_OCB */
#ifndef OPENSSL_NO_SIV
#include <openssl/cmac.h>
#define SIV_LEN 16
typedef union siv_block_u {
uint64_t word[SIV_LEN/sizeof(uint64_t)];
unsigned char byte[SIV_LEN];
} SIV_BLOCK;
struct siv128_context {
/* d stores intermediate results of S2V; it corresponds to D from the
pseudocode in section 2.4 of RFC 5297. */
SIV_BLOCK d;
SIV_BLOCK tag;
EVP_CIPHER_CTX *cipher_ctx;
CMAC_CTX *cmac_ctx_init;
CMAC_CTX *cmac_ctx;
int final_ret;
int crypto_ok;
};
#endif /* OPENSSL_NO_SIV */

349
crypto/modes/siv128.c Normal file
View File

@ -0,0 +1,349 @@
/*
* Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <string.h>
#include <stdlib.h>
#include <openssl/crypto.h>
#include <openssl/cmac.h>
#include "modes_lcl.h"
#ifndef OPENSSL_NO_SIV
__owur static ossl_inline uint32_t rotl8(uint32_t x)
{
return (x << 8) | (x >> 24);
}
__owur static ossl_inline uint32_t rotr8(uint32_t x)
{
return (x >> 8) | (x << 24);
}
__owur static ossl_inline uint64_t byteswap8(uint64_t x)
{
uint32_t high = (uint32_t)(x >> 32);
uint32_t low = (uint32_t)x;
high = (rotl8(high) & 0x00ff00ff) | (rotr8(high) & 0xff00ff00);
low = (rotl8(low) & 0x00ff00ff) | (rotr8(low) & 0xff00ff00);
return ((uint64_t)low) << 32 | (uint64_t)high;
}
__owur static ossl_inline uint64_t siv128_getword(SIV_BLOCK const *b, size_t i)
{
const union {
long one;
char little;
} is_endian = { 1 };
if (is_endian.little)
return byteswap8(b->word[i]);
return b->word[i];
}
static ossl_inline void siv128_putword(SIV_BLOCK *b, size_t i, uint64_t x)
{
const union {
long one;
char little;
} is_endian = { 1 };
if (is_endian.little)
b->word[i] = byteswap8(x);
else
b->word[i] = x;
}
static ossl_inline void siv128_xorblock(SIV_BLOCK *x,
SIV_BLOCK const *y)
{
x->word[0] ^= y->word[0];
x->word[1] ^= y->word[1];
}
/*
* Doubles |b|, which is 16 bytes representing an element
* of GF(2**128) modulo the irreducible polynomial
* x**128 + x**7 + x**2 + x + 1.
* Assumes two's-complement arithmetic
*/
static ossl_inline void siv128_dbl(SIV_BLOCK *b)
{
uint64_t high = siv128_getword(b, 0);
uint64_t low = siv128_getword(b, 1);
uint64_t high_carry = high & (((uint64_t)1) << 63);
uint64_t low_carry = low & (((uint64_t)1) << 63);
int64_t low_mask = -((int64_t)(high_carry >> 63)) & 0x87;
uint64_t high_mask = low_carry >> 63;
high = (high << 1) | high_mask;
low = (low << 1) ^ (uint64_t)low_mask;
siv128_putword(b, 0, high);
siv128_putword(b, 1, low);
}
__owur static ossl_inline int siv128_do_s2v_p(SIV128_CONTEXT *ctx, SIV_BLOCK *out,
unsigned char const* in, size_t len)
{
SIV_BLOCK t;
size_t out_len = sizeof(out->byte);
if (!CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init))
return 0;
if (len >= SIV_LEN) {
if (!CMAC_Update(ctx->cmac_ctx, in, len - SIV_LEN))
return 0;
memcpy(&t, in + (len-SIV_LEN), SIV_LEN);
siv128_xorblock(&t, &ctx->d);
if (!CMAC_Update(ctx->cmac_ctx, t.byte, SIV_LEN))
return 0;
} else {
memset(&t, 0, sizeof(t));
memcpy(&t, in, len);
t.byte[len] = 0x80;
siv128_dbl(&ctx->d);
siv128_xorblock(&t, &ctx->d);
if (!CMAC_Update(ctx->cmac_ctx, t.byte, SIV_LEN))
return 0;
}
if (!CMAC_Final(ctx->cmac_ctx, out->byte, &out_len)
|| out_len != SIV_LEN)
return 0;
return 1;
}
__owur static ossl_inline int siv128_do_encrypt(EVP_CIPHER_CTX *ctx, unsigned char *out,
unsigned char const *in, size_t len,
SIV_BLOCK *icv)
{
int out_len = (int)len;
if (!EVP_CipherInit_ex(ctx, NULL, NULL, NULL, icv->byte, 1))
return 0;
return EVP_EncryptUpdate(ctx, out, &out_len, in, out_len);
}
/*
* Create a new SIV128_CONTEXT
*/
SIV128_CONTEXT *CRYPTO_siv128_new(const unsigned char *key, int klen, EVP_CIPHER* cbc, EVP_CIPHER* ctr)
{
SIV128_CONTEXT *ctx;
int ret;
if ((ctx = OPENSSL_malloc(sizeof(*ctx))) != NULL) {
ret = CRYPTO_siv128_init(ctx, key, klen, cbc, ctr);
if (ret)
return ctx;
OPENSSL_free(ctx);
}
return NULL;
}
/*
* Initialise an existing SIV128_CONTEXT
*/
int CRYPTO_siv128_init(SIV128_CONTEXT *ctx, const unsigned char *key, int klen,
const EVP_CIPHER* cbc, const EVP_CIPHER* ctr)
{
static const unsigned char zero[SIV_LEN] = { 0 };
size_t out_len = SIV_LEN;
memset(&ctx->d, 0, sizeof(ctx->d));
ctx->cipher_ctx = NULL;
ctx->cmac_ctx = NULL;
ctx->cmac_ctx_init = NULL;
if (key == NULL || cbc == NULL || ctr == NULL
|| (ctx->cipher_ctx = EVP_CIPHER_CTX_new()) == NULL
|| (ctx->cmac_ctx_init = CMAC_CTX_new()) == NULL
|| (ctx->cmac_ctx = CMAC_CTX_new()) == NULL
|| !CMAC_Init(ctx->cmac_ctx_init, key, klen, cbc, NULL)
|| !EVP_EncryptInit_ex(ctx->cipher_ctx, ctr, NULL, key + klen, NULL)
|| !CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init)
|| !CMAC_Update(ctx->cmac_ctx, zero, sizeof(zero))
|| !CMAC_Final(ctx->cmac_ctx, ctx->d.byte, &out_len)) {
EVP_CIPHER_CTX_free(ctx->cipher_ctx);
CMAC_CTX_free(ctx->cmac_ctx_init);
CMAC_CTX_free(ctx->cmac_ctx);
return 0;
}
ctx->final_ret = -1;
ctx->crypto_ok = 1;
return 1;
}
/*
* Copy an SIV128_CONTEXT object
*/
int CRYPTO_siv128_copy_ctx(SIV128_CONTEXT *dest, SIV128_CONTEXT *src)
{
memcpy(&dest->d, &src->d, sizeof(src->d));
if (!EVP_CIPHER_CTX_copy(dest->cipher_ctx, src->cipher_ctx))
return 0;
if (!CMAC_CTX_copy(dest->cmac_ctx_init, src->cmac_ctx_init))
return 0;
/* no need to copy cmac_ctx since it's temp storage */
return 1;
}
/*
* Provide any AAD. This can be called multiple times.
* Per RFC5297, the last piece of associated data
* is the nonce, but it's not treated special
*/
int CRYPTO_siv128_aad(SIV128_CONTEXT *ctx, const unsigned char *aad,
size_t len)
{
SIV_BLOCK cmac_out;
size_t out_len = SIV_LEN;
siv128_dbl(&ctx->d);
if (!CMAC_CTX_copy(ctx->cmac_ctx, ctx->cmac_ctx_init)
|| !CMAC_Update(ctx->cmac_ctx, aad, len)
|| !CMAC_Final(ctx->cmac_ctx, cmac_out.byte, &out_len)
|| out_len != SIV_LEN)
return 0;
siv128_xorblock(&ctx->d, &cmac_out);
return 1;
}
/*
* Provide any data to be encrypted. This can be called once.
*/
int CRYPTO_siv128_encrypt(SIV128_CONTEXT *ctx,
const unsigned char *in, unsigned char *out,
size_t len)
{
SIV_BLOCK q;
/* can only do one crypto operation */
if (ctx->crypto_ok == 0)
return 0;
ctx->crypto_ok--;
if (!siv128_do_s2v_p(ctx, &q, in, len))
return 0;
memcpy(ctx->tag.byte, &q, SIV_LEN);
q.byte[8] &= 0x7f;
q.byte[12] &= 0x7f;
if (!siv128_do_encrypt(ctx->cipher_ctx, out, in, len, &q))
return 0;
ctx->final_ret = 0;
return len;
}
/*
* Provide any data to be decrypted. This can be called once.
*/
int CRYPTO_siv128_decrypt(SIV128_CONTEXT *ctx,
const unsigned char *in, unsigned char *out,
size_t len)
{
unsigned char* p;
SIV_BLOCK t, q;
int i;
/* can only do one crypto operation */
if (ctx->crypto_ok == 0)
return 0;
ctx->crypto_ok--;
memcpy(&q, ctx->tag.byte, SIV_LEN);
q.byte[8] &= 0x7f;
q.byte[12] &= 0x7f;
if (!siv128_do_encrypt(ctx->cipher_ctx, out, in, len, &q)
|| !siv128_do_s2v_p(ctx, &t, out, len))
return 0;
p = ctx->tag.byte;
for (i = 0; i < SIV_LEN; i++)
t.byte[i] ^= p[i];
if ((t.word[0] | t.word[1]) != 0) {
OPENSSL_cleanse(out, len);
return 0;
}
ctx->final_ret = 0;
return len;
}
/*
* Return the already calculated final result.
*/
int CRYPTO_siv128_finish(SIV128_CONTEXT *ctx)
{
return ctx->final_ret;
}
/*
* Set the tag
*/
int CRYPTO_siv128_set_tag(SIV128_CONTEXT *ctx, const unsigned char *tag, size_t len)
{
if (len != SIV_LEN)
return 0;
/* Copy the tag from the supplied buffer */
memcpy(ctx->tag.byte, tag, len);
return 1;
}
/*
* Retrieve the calculated tag
*/
int CRYPTO_siv128_get_tag(SIV128_CONTEXT *ctx, unsigned char *tag, size_t len)
{
if (len != SIV_LEN)
return 0;
/* Copy the tag into the supplied buffer */
memcpy(tag, ctx->tag.byte, len);
return 1;
}
/*
* Release all resources
*/
int CRYPTO_siv128_cleanup(SIV128_CONTEXT *ctx)
{
if (ctx != NULL) {
EVP_CIPHER_CTX_free(ctx->cipher_ctx);
ctx->cipher_ctx = NULL;
CMAC_CTX_free(ctx->cmac_ctx_init);
ctx->cmac_ctx_init = NULL;
CMAC_CTX_free(ctx->cmac_ctx);
ctx->cmac_ctx = NULL;
OPENSSL_cleanse(&ctx->d, sizeof(ctx->d));
OPENSSL_cleanse(&ctx->tag, sizeof(ctx->tag));
ctx->final_ret = -1;
ctx->crypto_ok = 1;
}
return 1;
}
int CRYPTO_siv128_speed(SIV128_CONTEXT *ctx, int arg)
{
ctx->crypto_ok = (arg == 1) ? -1 : 1;
return 1;
}
#endif /* OPENSSL_NO_SIV */

View File

@ -1079,7 +1079,7 @@ static const unsigned char so[7767] = {
0x28,0xCC,0x45,0x03,0x04, /* [ 7761] OBJ_gmac */
};
#define NUM_NID 1198
#define NUM_NID 1201
static const ASN1_OBJECT nid_objs[NUM_NID] = {
{"UNDEF", "undefined", NID_undef},
{"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &so[0]},
@ -2279,9 +2279,12 @@ static const ASN1_OBJECT nid_objs[NUM_NID] = {
{"GMAC", "gmac", NID_gmac, 5, &so[7761]},
{"KMAC128", "kmac128", NID_kmac128},
{"KMAC256", "kmac256", NID_kmac256},
{"AES-128-SIV", "aes-128-siv", NID_aes_128_siv},
{"AES-192-SIV", "aes-192-siv", NID_aes_192_siv},
{"AES-256-SIV", "aes-256-siv", NID_aes_256_siv},
};
#define NUM_SN 1189
#define NUM_SN 1192
static const unsigned int sn_objs[NUM_SN] = {
364, /* "AD_DVCS" */
419, /* "AES-128-CBC" */
@ -2294,6 +2297,7 @@ static const unsigned int sn_objs[NUM_SN] = {
418, /* "AES-128-ECB" */
958, /* "AES-128-OCB" */
420, /* "AES-128-OFB" */
1198, /* "AES-128-SIV" */
913, /* "AES-128-XTS" */
423, /* "AES-192-CBC" */
917, /* "AES-192-CBC-HMAC-SHA1" */
@ -2305,6 +2309,7 @@ static const unsigned int sn_objs[NUM_SN] = {
422, /* "AES-192-ECB" */
959, /* "AES-192-OCB" */
424, /* "AES-192-OFB" */
1199, /* "AES-192-SIV" */
427, /* "AES-256-CBC" */
918, /* "AES-256-CBC-HMAC-SHA1" */
950, /* "AES-256-CBC-HMAC-SHA256" */
@ -2315,6 +2320,7 @@ static const unsigned int sn_objs[NUM_SN] = {
426, /* "AES-256-ECB" */
960, /* "AES-256-OCB" */
428, /* "AES-256-OFB" */
1200, /* "AES-256-SIV" */
914, /* "AES-256-XTS" */
1066, /* "ARIA-128-CBC" */
1120, /* "ARIA-128-CCM" */
@ -3474,7 +3480,7 @@ static const unsigned int sn_objs[NUM_SN] = {
1093, /* "x509ExtAdmission" */
};
#define NUM_LN 1189
#define NUM_LN 1192
static const unsigned int ln_objs[NUM_LN] = {
363, /* "AD Time Stamping" */
405, /* "ANSI X9.62" */
@ -3701,6 +3707,7 @@ static const unsigned int ln_objs[NUM_LN] = {
895, /* "aes-128-gcm" */
958, /* "aes-128-ocb" */
420, /* "aes-128-ofb" */
1198, /* "aes-128-siv" */
913, /* "aes-128-xts" */
423, /* "aes-192-cbc" */
917, /* "aes-192-cbc-hmac-sha1" */
@ -3714,6 +3721,7 @@ static const unsigned int ln_objs[NUM_LN] = {
898, /* "aes-192-gcm" */
959, /* "aes-192-ocb" */
424, /* "aes-192-ofb" */
1199, /* "aes-192-siv" */
427, /* "aes-256-cbc" */
918, /* "aes-256-cbc-hmac-sha1" */
950, /* "aes-256-cbc-hmac-sha256" */
@ -3726,6 +3734,7 @@ static const unsigned int ln_objs[NUM_LN] = {
901, /* "aes-256-gcm" */
960, /* "aes-256-ocb" */
428, /* "aes-256-ofb" */
1200, /* "aes-256-siv" */
914, /* "aes-256-xts" */
376, /* "algorithm" */
1066, /* "aria-128-cbc" */

View File

@ -1195,3 +1195,6 @@ hmacWithSHA512_256 1194
gmac 1195
kmac128 1196
kmac256 1197
aes_128_siv 1198
aes_192_siv 1199
aes_256_siv 1200

View File

@ -1645,7 +1645,6 @@ id-pkinit 5 : pkInitKDC : Signing KDC Response
: Poly1305 : poly1305
# NID for SipHash
: SipHash : siphash
# NIDs for RFC7919 DH parameters
: ffdhe2048
: ffdhe3072
@ -1682,3 +1681,7 @@ dstu4145le 2 6 : uacurve6 : DSTU curve 6
dstu4145le 2 7 : uacurve7 : DSTU curve 7
dstu4145le 2 8 : uacurve8 : DSTU curve 8
dstu4145le 2 9 : uacurve9 : DSTU curve 9
# NID for AES-SIV
: AES-128-SIV : aes-128-siv
: AES-192-SIV : aes-192-siv
: AES-256-SIV : aes-256-siv

View File

@ -87,7 +87,7 @@ The available flags are:
=item EVP_CIPH_STREAM_CIPHER, EVP_CIPH_ECB_MODE EVP_CIPH_CBC_MODE,
EVP_CIPH_CFB_MODE, EVP_CIPH_OFB_MODE, EVP_CIPH_CTR_MODE, EVP_CIPH_GCM_MODE,
EVP_CIPH_CCM_MODE, EVP_CIPH_XTS_MODE, EVP_CIPH_WRAP_MODE,
EVP_CIPH_OCB_MODE
EVP_CIPH_OCB_MODE, EVP_CIPH_SIV_MODE
The cipher mode.

View File

@ -426,6 +426,49 @@ AES.
=back
=head2 SIV Mode
For SIV mode ciphers the behaviour of the EVP interface is subtly
altered and several additional ctrl operations are supported.
To specify any additional authenticated data (AAD) and/or a Nonce, a call to
EVP_CipherUpdate(), EVP_EncryptUpdate() or EVP_DecryptUpdate() should be made
with the output parameter B<out> set to B<NULL>.
RFC5297 states that the Nonce is the last piece of AAD before the actual
encrypt/decrypt takes place. The API does not differentiate the Nonce from
other AAD.
When decrypting the return value of EVP_DecryptFinal() or EVP_CipherFinal()
indicates if the operation was successful. If it does not indicate success
the authentication operation has failed and any output data B<MUST NOT>
be used as it is corrupted.
The following ctrls are supported in both SIV modes.
=over 4
=item EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, taglen, tag);
Writes B<taglen> bytes of the tag value to the buffer indicated by B<tag>.
This call can only be made when encrypting data and B<after> all data has been
processed (e.g. after an EVP_EncryptFinal() call). For SIV mode the taglen must
be 16.
=item EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, taglen, tag);
Sets the expected tag to B<taglen> bytes from B<tag>. This call is only legal
when decrypting data and must be made B<before> any data is processed (e.g.
before any EVP_DecryptUpdate() call). For SIV mode the taglen must be 16.
=back
SIV mode makes two passes over the input data, thus, only one call to
EVP_CipherUpdate(), EVP_EncryptUpdate() or EVP_DecryptUpdate() should be made
with B<out> set to a non-B<NULL> value. A call to EVP_Decrypt_Final() or
EVP_CipherFinal() is not required, but will indicate if the update
operation succeeded.
=head2 ChaCha20-Poly1305
The following I<ctrl>s are supported for the ChaCha20-Poly1305 AEAD algorithm.

View File

@ -245,6 +245,7 @@ int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
# define EVP_CIPH_XTS_MODE 0x10001
# define EVP_CIPH_WRAP_MODE 0x10002
# define EVP_CIPH_OCB_MODE 0x10003
# define EVP_CIPH_SIV_MODE 0x10004
# define EVP_CIPH_MODE 0xF0007
/* Set if variable length cipher */
# define EVP_CIPH_VARIABLE_LENGTH 0x8
@ -352,6 +353,8 @@ int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
# define EVP_CTRL_SET_PIPELINE_INPUT_LENS 0x24
/* Get the IV used by the cipher */
# define EVP_CTRL_GET_IV 0x25
/* Tell the cipher it's doing a speed test (SIV disallows multiple ops) */
# define EVP_CTRL_SET_SPEED 0x26
/* Padding modes */
#define EVP_PADDING_PKCS7 1
@ -858,6 +861,11 @@ const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha1(void);
const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha1(void);
const EVP_CIPHER *EVP_aes_128_cbc_hmac_sha256(void);
const EVP_CIPHER *EVP_aes_256_cbc_hmac_sha256(void);
# ifndef OPENSSL_NO_SIV
const EVP_CIPHER *EVP_aes_128_siv(void);
const EVP_CIPHER *EVP_aes_192_siv(void);
const EVP_CIPHER *EVP_aes_256_siv(void);
# endif
# ifndef OPENSSL_NO_ARIA
const EVP_CIPHER *EVP_aria_128_ecb(void);
const EVP_CIPHER *EVP_aria_128_cbc(void);

View File

@ -11,6 +11,7 @@
# define HEADER_MODES_H
# include <stddef.h>
# include <openssl/ossl_typ.h>
# ifdef __cplusplus
extern "C" {
@ -201,6 +202,32 @@ int CRYPTO_ocb128_tag(OCB128_CONTEXT *ctx, unsigned char *tag, size_t len);
void CRYPTO_ocb128_cleanup(OCB128_CONTEXT *ctx);
# endif /* OPENSSL_NO_OCB */
# ifndef OPENSSL_NO_SIV
typedef struct siv128_context SIV128_CONTEXT;
# define SIV_LEN 16
SIV128_CONTEXT *CRYPTO_siv128_new(const unsigned char *key, int klen, EVP_CIPHER* cbc, EVP_CIPHER* ctr);
int CRYPTO_siv128_init(SIV128_CONTEXT *ctx, const unsigned char *key, int klen,
const EVP_CIPHER* cbc, const EVP_CIPHER* ctr);
int CRYPTO_siv128_copy_ctx(SIV128_CONTEXT *dest, SIV128_CONTEXT *src);
int CRYPTO_siv128_aad(SIV128_CONTEXT *ctx, const unsigned char *aad,
size_t len);
int CRYPTO_siv128_encrypt(SIV128_CONTEXT *ctx,
const unsigned char *in, unsigned char *out,
size_t len);
int CRYPTO_siv128_decrypt(SIV128_CONTEXT *ctx,
const unsigned char *in, unsigned char *out,
size_t len);
int CRYPTO_siv128_finish(SIV128_CONTEXT *ctx);
int CRYPTO_siv128_set_tag(SIV128_CONTEXT *ctx, const unsigned char *tag, size_t len);
int CRYPTO_siv128_get_tag(SIV128_CONTEXT *ctx, unsigned char *tag, size_t len);
int CRYPTO_siv128_cleanup(SIV128_CONTEXT *ctx);
int CRYPTO_siv128_speed(SIV128_CONTEXT *ctx, int arg);
# endif /* OPENSSL_NO_SIV */
# ifdef __cplusplus
}
# endif

View File

@ -5209,3 +5209,15 @@
#define LN_uacurve9 "DSTU curve 9"
#define NID_uacurve9 1169
#define OBJ_uacurve9 OBJ_dstu4145le,2L,9L
#define SN_aes_128_siv "AES-128-SIV"
#define LN_aes_128_siv "aes-128-siv"
#define NID_aes_128_siv 1198
#define SN_aes_192_siv "AES-192-SIV"
#define LN_aes_192_siv "aes-192-siv"
#define NID_aes_192_siv 1199
#define SN_aes_256_siv "AES-256-SIV"
#define LN_aes_256_siv "aes-256-siv"
#define NID_aes_256_siv 1200

View File

@ -21,6 +21,7 @@
#include "testutil.h"
#include "evp_test.h"
#define AAD_NUM 4
typedef struct evp_test_method_st EVP_TEST_METHOD;
@ -457,9 +458,9 @@ typedef struct cipher_data_st {
size_t plaintext_len;
unsigned char *ciphertext;
size_t ciphertext_len;
/* GCM, CCM and OCB only */
unsigned char *aad;
size_t aad_len;
/* GCM, CCM, OCB and SIV only */
unsigned char *aad[AAD_NUM];
size_t aad_len[AAD_NUM];
unsigned char *tag;
size_t tag_len;
} CIPHER_DATA;
@ -484,6 +485,7 @@ static int cipher_test_init(EVP_TEST *t, const char *alg)
m = EVP_CIPHER_mode(cipher);
if (m == EVP_CIPH_GCM_MODE
|| m == EVP_CIPH_OCB_MODE
|| m == EVP_CIPH_SIV_MODE
|| m == EVP_CIPH_CCM_MODE)
cdat->aead = m;
else if (EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)
@ -497,13 +499,15 @@ static int cipher_test_init(EVP_TEST *t, const char *alg)
static void cipher_test_cleanup(EVP_TEST *t)
{
int i;
CIPHER_DATA *cdat = t->data;
OPENSSL_free(cdat->key);
OPENSSL_free(cdat->iv);
OPENSSL_free(cdat->ciphertext);
OPENSSL_free(cdat->plaintext);
OPENSSL_free(cdat->aad);
for (i = 0; i < AAD_NUM; i++)
OPENSSL_free(cdat->aad[i]);
OPENSSL_free(cdat->tag);
}
@ -511,6 +515,7 @@ static int cipher_test_parse(EVP_TEST *t, const char *keyword,
const char *value)
{
CIPHER_DATA *cdat = t->data;
int i;
if (strcmp(keyword, "Key") == 0)
return parse_bin(value, &cdat->key, &cdat->key_len);
@ -521,8 +526,13 @@ static int cipher_test_parse(EVP_TEST *t, const char *keyword,
if (strcmp(keyword, "Ciphertext") == 0)
return parse_bin(value, &cdat->ciphertext, &cdat->ciphertext_len);
if (cdat->aead) {
if (strcmp(keyword, "AAD") == 0)
return parse_bin(value, &cdat->aad, &cdat->aad_len);
if (strcmp(keyword, "AAD") == 0) {
for (i = 0; i < AAD_NUM; i++) {
if (cdat->aad[i] == NULL)
return parse_bin(value, &cdat->aad[i], &cdat->aad_len[i]);
}
return 0;
}
if (strcmp(keyword, "Tag") == 0)
return parse_bin(value, &cdat->tag, &cdat->tag_len);
}
@ -545,7 +555,7 @@ static int cipher_test_enc(EVP_TEST *t, int enc,
CIPHER_DATA *expected = t->data;
unsigned char *in, *expected_out, *tmp = NULL;
size_t in_len, out_len, donelen = 0;
int ok = 0, tmplen, chunklen, tmpflen;
int ok = 0, tmplen, chunklen, tmpflen, i;
EVP_CIPHER_CTX *ctx = NULL;
t->err = "TEST_FAILURE";
@ -647,32 +657,36 @@ static int cipher_test_enc(EVP_TEST *t, int enc,
goto err;
}
}
if (expected->aad) {
if (expected->aad[0] != NULL) {
t->err = "AAD_SET_ERROR";
if (!frag) {
if (!EVP_CipherUpdate(ctx, NULL, &chunklen, expected->aad,
expected->aad_len))
goto err;
for (i = 0; expected->aad[i] != NULL; i++) {
if (!EVP_CipherUpdate(ctx, NULL, &chunklen, expected->aad[i],
expected->aad_len[i]))
goto err;
}
} else {
/*
* Supply the AAD in chunks less than the block size where possible
*/
if (expected->aad_len > 0) {
if (!EVP_CipherUpdate(ctx, NULL, &chunklen, expected->aad, 1))
goto err;
donelen++;
}
if (expected->aad_len > 2) {
if (!EVP_CipherUpdate(ctx, NULL, &chunklen,
expected->aad + donelen,
expected->aad_len - 2))
goto err;
donelen += expected->aad_len - 2;
}
if (expected->aad_len > 1
for (i = 0; expected->aad[i] != NULL; i++) {
if (expected->aad_len[i] > 0) {
if (!EVP_CipherUpdate(ctx, NULL, &chunklen, expected->aad[i], 1))
goto err;
donelen++;
}
if (expected->aad_len[i] > 2) {
if (!EVP_CipherUpdate(ctx, NULL, &chunklen,
expected->aad[i] + donelen,
expected->aad_len[i] - 2))
goto err;
donelen += expected->aad_len[i] - 2;
}
if (expected->aad_len[i] > 1
&& !EVP_CipherUpdate(ctx, NULL, &chunklen,
expected->aad + donelen, 1))
goto err;
expected->aad[i] + donelen, 1))
goto err;
}
}
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
@ -798,10 +812,11 @@ static int cipher_test_run(EVP_TEST *t)
if (out_misalign == 1 && frag == 0) {
/*
* XTS, CCM and Wrap modes have special requirements about input
* XTS, SIV, CCM and Wrap modes have special requirements about input
* lengths so we don't fragment for those
*/
if (cdat->aead == EVP_CIPH_CCM_MODE
|| EVP_CIPHER_mode(cdat->cipher) == EVP_CIPH_SIV_MODE
|| EVP_CIPHER_mode(cdat->cipher) == EVP_CIPH_XTS_MODE
|| EVP_CIPHER_mode(cdat->cipher) == EVP_CIPH_WRAP_MODE)
break;

View File

@ -16,7 +16,7 @@ setup("test_evp");
my @files = ( "evpciph.txt", "evpdigest.txt", "evpencod.txt", "evpkdf.txt",
"evpmac.txt", "evppbe.txt", "evppkey.txt", "evppkey_ecc.txt",
"evpcase.txt" );
"evpcase.txt", "evpaessiv.txt" );
plan tests => scalar(@files);

View File

@ -0,0 +1,44 @@
#
# Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License"). You may not use
# this file except in compliance with the License. You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html
# Tests start with one of these keywords
# Cipher Decrypt Derive Digest Encoding KDF MAC PBE
# PrivPubKeyPair Sign Verify VerifyRecover
# and continue until a blank line. Lines starting with a pound sign,
# like this prolog, are ignored.
Title = RFC5297 AES-SIV
Cipher = aes-128-siv
Key = fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
AAD = 101112131415161718191a1b1c1d1e1f2021222324252627
Tag = 85632d07c6e8f37f950acd320a2ecc93
Plaintext = 112233445566778899aabbccddee
Ciphertext = 40c02b9690c4dc04daef7f6afe5c
Cipher = aes-128-siv
Key = 7f7e7d7c7b7a79787776757473727170404142434445464748494a4b4c4d4e4f
AAD = 00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddccbbaa99887766554433221100
AAD = 102030405060708090a0
AAD = 09f911029d74e35bd84156c5635688c0
Tag = 7bdb6e3b432667eb06f4d14bff2fbd0f
Plaintext = 7468697320697320736f6d6520706c61696e7465787420746f20656e6372797074207573696e67205349562d414553
Ciphertext = cb900f2fddbe404326601965c889bf17dba77ceb094fa663b7a3f748ba8af829ea64ad544a272e9c485b62a3fd5c0d
Cipher = aes-192-siv
Key = fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfefffffefdfcfbfaf9f8f7f6f5f4f3f2f1f0
AAD = 101112131415161718191a1b1c1d1e1f2021222324252627
Tag = 89e869b93256785154f0963962fe0740
Plaintext = 112233445566778899aabbccddee
Ciphertext = eff356e42dec1f4febded36642f2
Cipher = aes-256-siv
Key = fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfefff0f1f2f3f4f5f6f7f8f9fafbfcfdfefffffefdfcfbfaf9f8f7f6f5f4f3f2f1f0
AAD = 101112131415161718191a1b1c1d1e1f2021222324252627
Tag = 724dfb2eaf94dbb19b0ba3a299a0801e
Plaintext = 112233445566778899aabbccddee
Ciphertext = f3b05a55498ec2552690b89810e4

View File

@ -4606,3 +4606,17 @@ OPENSSL_version_minor 4561 3_0_0 EXIST::FUNCTION:
OPENSSL_version_patch 4562 3_0_0 EXIST::FUNCTION:
OPENSSL_version_pre_release 4563 3_0_0 EXIST::FUNCTION:
OPENSSL_version_build_metadata 4564 3_0_0 EXIST::FUNCTION:
EVP_aes_128_siv 4565 3_0_0 EXIST::FUNCTION:SIV
EVP_aes_192_siv 4566 3_0_0 EXIST::FUNCTION:SIV
EVP_aes_256_siv 4567 3_0_0 EXIST::FUNCTION:SIV
CRYPTO_siv128_new 4568 3_0_0 EXIST::FUNCTION:SIV
CRYPTO_siv128_init 4569 3_0_0 EXIST::FUNCTION:SIV
CRYPTO_siv128_copy_ctx 4570 3_0_0 EXIST::FUNCTION:SIV
CRYPTO_siv128_aad 4571 3_0_0 EXIST::FUNCTION:SIV
CRYPTO_siv128_encrypt 4572 3_0_0 EXIST::FUNCTION:SIV
CRYPTO_siv128_decrypt 4573 3_0_0 EXIST::FUNCTION:SIV
CRYPTO_siv128_finish 4574 3_0_0 EXIST::FUNCTION:SIV
CRYPTO_siv128_set_tag 4575 3_0_0 EXIST::FUNCTION:SIV
CRYPTO_siv128_get_tag 4576 3_0_0 EXIST::FUNCTION:SIV
CRYPTO_siv128_cleanup 4577 3_0_0 EXIST::FUNCTION:SIV
CRYPTO_siv128_speed 4578 3_0_0 EXIST::FUNCTION:SIV