[openssl-commits] [openssl] master update

Paul I. Dale pauli at openssl.org
Tue Dec 11 22:17:10 UTC 2018


The branch master has been updated
       via  b1ceb439f234a998db84f27a3a245dab95d322ab (commit)
      from  6de98b4fb6265f8a4b2e5b599d6714ff937dca6b (commit)


- Log -----------------------------------------------------------------
commit b1ceb439f234a998db84f27a3a245dab95d322ab
Author: Todd Short <tshort at akamai.com>
Date:   Fri May 19 10:27:28 2017 -0400

    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 at oracle.com>
    Reviewed-by: Bernd Edlinger <bernd.edlinger at hotmail.de>
    (Merged from https://github.com/openssl/openssl/pull/3540)

-----------------------------------------------------------------------

Summary of changes:
 CHANGES                                     |   3 +
 Configure                                   |   3 +
 INSTALL                                     |   6 +-
 apps/speed.c                                |   4 +
 crypto/evp/c_allc.c                         |   6 +-
 crypto/evp/e_aes.c                          | 127 +++++++++-
 crypto/modes/build.info                     |   2 +-
 crypto/modes/modes_lcl.h                    |  25 ++
 crypto/modes/siv128.c                       | 349 ++++++++++++++++++++++++++++
 crypto/objects/obj_dat.h                    |  15 +-
 crypto/objects/obj_mac.num                  |   3 +
 crypto/objects/objects.txt                  |   5 +-
 doc/man3/EVP_CIPHER_meth_new.pod            |   2 +-
 doc/man3/EVP_EncryptInit.pod                |  43 ++++
 include/openssl/evp.h                       |   8 +
 include/openssl/modes.h                     |  27 +++
 include/openssl/obj_mac.h                   |  12 +
 test/evp_test.c                             |  67 +++---
 test/recipes/30-test_evp.t                  |   2 +-
 test/recipes/30-test_evp_data/evpaessiv.txt |  44 ++++
 util/libcrypto.num                          |  14 ++
 21 files changed, 725 insertions(+), 42 deletions(-)
 create mode 100644 crypto/modes/siv128.c
 create mode 100644 test/recipes/30-test_evp_data/evpaessiv.txt

diff --git a/CHANGES b/CHANGES
index 42bd6ee..311d6c6 100644
--- 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.
diff --git a/Configure b/Configure
index e2a6025..80c58b1 100755
--- 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 95fc71a..049ff21 100644
--- a/INSTALL
+++ b/INSTALL
@@ -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
diff --git a/apps/speed.c b/apps/speed.c
index 437c03e..bb8836d 100644
--- a/apps/speed.c
+++ b/apps/speed.c
@@ -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);
diff --git a/crypto/evp/c_allc.c b/crypto/evp/c_allc.c
index 4a803e6..a97eaa1 100644
--- a/crypto/evp/c_allc.c
+++ b/crypto/evp/c_allc.c
@@ -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());
diff --git a/crypto/evp/e_aes.c b/crypto/evp/e_aes.c
index 09f6598..a882f21 100644
--- a/crypto/evp/e_aes.c
+++ b/crypto/evp/e_aes.c
@@ -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
diff --git a/crypto/modes/build.info b/crypto/modes/build.info
index 821340e..1820ab2 100644
--- a/crypto/modes/build.info
+++ b/crypto/modes/build.info
@@ -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]=..
diff --git a/crypto/modes/modes_lcl.h b/crypto/modes/modes_lcl.h
index 0215bbd..d042d30 100644
--- a/crypto/modes/modes_lcl.h
+++ b/crypto/modes/modes_lcl.h
@@ -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
index 0000000..f4d07d5
--- /dev/null
+++ b/crypto/modes/siv128.c
@@ -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 */
diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h
index 9e2d3f0..86bcfca 100644
--- a/crypto/objects/obj_dat.h
+++ b/crypto/objects/obj_dat.h
@@ -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" */
diff --git a/crypto/objects/obj_mac.num b/crypto/objects/obj_mac.num
index ad47750..021875d 100644
--- a/crypto/objects/obj_mac.num
+++ b/crypto/objects/obj_mac.num
@@ -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
diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt
index 590bbe9..851e31e 100644
--- a/crypto/objects/objects.txt
+++ b/crypto/objects/objects.txt
@@ -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
diff --git a/doc/man3/EVP_CIPHER_meth_new.pod b/doc/man3/EVP_CIPHER_meth_new.pod
index 7b588c4..c813838 100644
--- a/doc/man3/EVP_CIPHER_meth_new.pod
+++ b/doc/man3/EVP_CIPHER_meth_new.pod
@@ -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.
 
diff --git a/doc/man3/EVP_EncryptInit.pod b/doc/man3/EVP_EncryptInit.pod
index ac3189b..61c47e0 100644
--- a/doc/man3/EVP_EncryptInit.pod
+++ b/doc/man3/EVP_EncryptInit.pod
@@ -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.
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 636ed1b..ede4b14 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -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);
diff --git a/include/openssl/modes.h b/include/openssl/modes.h
index bf987cc..0934482 100644
--- a/include/openssl/modes.h
+++ b/include/openssl/modes.h
@@ -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
diff --git a/include/openssl/obj_mac.h b/include/openssl/obj_mac.h
index 284b3b2..8ad2728 100644
--- a/include/openssl/obj_mac.h
+++ b/include/openssl/obj_mac.h
@@ -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
diff --git a/test/evp_test.c b/test/evp_test.c
index a1b5c52..f3dd79b 100644
--- a/test/evp_test.c
+++ b/test/evp_test.c
@@ -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;
diff --git a/test/recipes/30-test_evp.t b/test/recipes/30-test_evp.t
index d8162bc..c2079bd 100644
--- a/test/recipes/30-test_evp.t
+++ b/test/recipes/30-test_evp.t
@@ -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
index 0000000..5419918
--- /dev/null
+++ b/test/recipes/30-test_evp_data/evpaessiv.txt
@@ -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
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 27b32b3..59fc347 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -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


More information about the openssl-commits mailing list