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.
"seed",
"shared",
"siphash",
+ "siv",
"sm2",
"sm3",
"sm4",
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
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
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);
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());
#include "internal/evp_int.h"
#include "modes_lcl.h"
#include <openssl/rand.h>
+#include <openssl/cmac.h>
#include "evp_locl.h"
typedef struct {
# 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, \
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, \
# 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, \
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, \
# 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, \
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
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]=..
} 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 */
--- /dev/null
+/*
+ * 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 */
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]},
{"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" */
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" */
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" */
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" */
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" */
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" */
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" */
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" */
gmac 1195
kmac128 1196
kmac256 1197
+aes_128_siv 1198
+aes_192_siv 1199
+aes_256_siv 1200
: Poly1305 : poly1305
# NID for SipHash
: SipHash : siphash
-
# NIDs for RFC7919 DH parameters
: ffdhe2048
: ffdhe3072
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
=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.
=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.
# 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
# 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
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);
# define HEADER_MODES_H
# include <stddef.h>
+# include <openssl/ossl_typ.h>
# ifdef __cplusplus
extern "C" {
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
#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
#include "testutil.h"
#include "evp_test.h"
+#define AAD_NUM 4
typedef struct evp_test_method_st EVP_TEST_METHOD;
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;
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)
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);
}
const char *value)
{
CIPHER_DATA *cdat = t->data;
+ int i;
if (strcmp(keyword, "Key") == 0)
return parse_bin(value, &cdat->key, &cdat->key_len);
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);
}
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";
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))
+ 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[i] + donelen, 1))
goto err;
- donelen += expected->aad_len - 2;
}
- if (expected->aad_len > 1
- && !EVP_CipherUpdate(ctx, NULL, &chunklen,
- expected->aad + donelen, 1))
- goto err;
}
}
EVP_CIPHER_CTX_set_padding(ctx, 0);
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;
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);
--- /dev/null
+#
+# 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
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