Add RFC5297 AES-SIV support
authorTodd Short <tshort@akamai.com>
Fri, 19 May 2017 14:27:28 +0000 (10:27 -0400)
committerPauli <paul.dale@oracle.com>
Tue, 11 Dec 2018 22:16:10 +0000 (08:16 +1000)
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)

21 files changed:
CHANGES
Configure
INSTALL
apps/speed.c
crypto/evp/c_allc.c
crypto/evp/e_aes.c
crypto/modes/build.info
crypto/modes/modes_lcl.h
crypto/modes/siv128.c [new file with mode: 0644]
crypto/objects/obj_dat.h
crypto/objects/obj_mac.num
crypto/objects/objects.txt
doc/man3/EVP_CIPHER_meth_new.pod
doc/man3/EVP_EncryptInit.pod
include/openssl/evp.h
include/openssl/modes.h
include/openssl/obj_mac.h
test/evp_test.c
test/recipes/30-test_evp.t
test/recipes/30-test_evp_data/evpaessiv.txt [new file with mode: 0644]
util/libcrypto.num

diff --git a/CHANGES b/CHANGES
index 42bd6ee7afb87fe53617d364289ee7ca0f9099a6..311d6c627cdd39d2506556c9608890c9d1358387 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -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.
index e2a60251724c08d25192267b54ec6094517cffb1..80c58b18aaf32d14d44b66a39e52b43725eb46b5 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -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
diff --git a/INSTALL b/INSTALL
index 95fc71a6919e2417133b2c8c49f65c25d7f4d417..049ff21f5cc8697d755572c0a6555349aa99e2ae 100644 (file)
--- a/INSTALL
+++ b/INSTALL
                    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
index 437c03e38d65a610d3d8cbe80dab3c51437b2910..bb8836d81b9054eaf949dfdfd2c4cfbbc81d89bd 100644 (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);
index 4a803e6dc6d620989e49434a3ba4d3160d76c4d0..a97eaa168514e41974b96917f637ac9f81e5f969 100644 (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());
index 09f6598b6c96cc74e4b47f77cded8b036fe872e9..a882f2170af4bcad89da3bb551f0831589eb885d 100644 (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
index 821340eb909a298fae6c006368e2317a215fde13..1820ab26ba1b2d88cdad36567060e9bb05378671 100644 (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]=..
index 0215bbdeddef82b13996de0cac8da6123aa81413..d042d30016a7aee5e014e9c6666d77cff1e4d993 100644 (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 */
diff --git a/crypto/modes/siv128.c b/crypto/modes/siv128.c
new file mode 100644 (file)
index 0000000..f4d07d5
--- /dev/null
@@ -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 */
index 9e2d3f05658b6dff1b09a015dedeb7ae7b4bc11b..86bcfcaee07dfe711c0cd07e921b12d92474fa3a 100644 (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" */
index ad47750f5d587ebda5132974fab19a22a0c7a317..021875d9e42297dd9e0a5a1d09d2e4dfcb0e256b 100644 (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
index 590bbe9a1309230c34822942bdc33b01437c9791..851e31e5aab536de4014f9a03be1e51b382b4c1e 100644 (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
index 7b588c4c67747751375909230bf0a06a0cfe231d..c8138382ff444b40b94f9c97ec598242f4d43bc1 100644 (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.
 
index ac3189b2da93cdbb503fd88da18ee72ea4c1aa88..61c47e099d95989d130574a05d42e26d29b20067 100644 (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.
index 636ed1b680ac7da78eacfe4f3e8ffc4699e3d6d0..ede4b1429b9f31e34795342aee56e5eb6a27e69f 100644 (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);
index bf987cce22f2aaec34fd38b9a5d667fbdd22bfb2..0934482c5682cac606cdb1c77acf40e6f8b94ce2 100644 (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
index 284b3b2381cd5d5af81d3cccc0ee5d6fe4f29ad8..8ad2728ddedd1cb395560f0f6fff7dd731b9bc5b 100644 (file)
 #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
index a1b5c52d951cf44ef33210edbc0e1c564cce0cc5..f3dd79ba967f42b1185ffa83e7c089c1cb645034 100644 (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))
+            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);
@@ -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;
index d8162bc886ae03a824120fdaf1435705b5f98c7c..c2079bd6e6097b0b06b6d9323d85b41fff79ed73 100644 (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);
 
diff --git a/test/recipes/30-test_evp_data/evpaessiv.txt b/test/recipes/30-test_evp_data/evpaessiv.txt
new file mode 100644 (file)
index 0000000..5419918
--- /dev/null
@@ -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
index 27b32b37e44dc884def6179e1b562ce88882e50d..59fc3470f16fc54ca5892136136be3a370e28d6b 100644 (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