diff --git a/CHANGES b/CHANGES index 42bd6ee7af..311d6c627c 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 e2a6025172..80c58b18aa 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 95fc71a691..049ff21f5c 100644 --- a/INSTALL +++ b/INSTALL @@ -556,9 +556,9 @@ Build without support for the specified algorithm, where 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 437c03e38d..bb8836d81b 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 4a803e6dc6..a97eaa1685 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 09f6598b6c..a882f2170a 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 +#include #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 821340eb90..1820ab26ba 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 0215bbdedd..d042d30016 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 + +#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 0000000000..f4d07d514a --- /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 +#include +#include +#include +#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 9e2d3f0565..86bcfcaee0 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 ad47750f5d..021875d9e4 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 590bbe9a13..851e31e5aa 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 7b588c4c67..c8138382ff 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 ac3189b2da..61c47e099d 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 set to B. + +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 +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 bytes of the tag value to the buffer indicated by B. +This call can only be made when encrypting data and B 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 bytes from B. This call is only legal +when decrypting data and must be made B 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 set to a non-B 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 Is are supported for the ChaCha20-Poly1305 AEAD algorithm. diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 636ed1b680..ede4b1429b 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 bf987cce22..0934482c56 100644 --- a/include/openssl/modes.h +++ b/include/openssl/modes.h @@ -11,6 +11,7 @@ # define HEADER_MODES_H # include +# include # 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 284b3b2381..8ad2728dde 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 a1b5c52d95..f3dd79ba96 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)) - goto err; - donelen += expected->aad_len - 2; - } - if (expected->aad_len > 1 + for (i = 0; expected->aad[i] != NULL; i++) { + if (expected->aad_len[i] > 0) { + if (!EVP_CipherUpdate(ctx, NULL, &chunklen, expected->aad[i], 1)) + goto err; + donelen++; + } + if (expected->aad_len[i] > 2) { + if (!EVP_CipherUpdate(ctx, NULL, &chunklen, + expected->aad[i] + donelen, + expected->aad_len[i] - 2)) + goto err; + donelen += expected->aad_len[i] - 2; + } + if (expected->aad_len[i] > 1 && !EVP_CipherUpdate(ctx, NULL, &chunklen, - expected->aad + donelen, 1)) - goto err; + expected->aad[i] + donelen, 1)) + goto err; + } } } EVP_CIPHER_CTX_set_padding(ctx, 0); @@ -798,10 +812,11 @@ static int cipher_test_run(EVP_TEST *t) if (out_misalign == 1 && frag == 0) { /* - * XTS, CCM and Wrap modes have special requirements about input + * XTS, SIV, CCM and Wrap modes have special requirements about input * lengths so we don't fragment for those */ if (cdat->aead == EVP_CIPH_CCM_MODE + || EVP_CIPHER_mode(cdat->cipher) == EVP_CIPH_SIV_MODE || EVP_CIPHER_mode(cdat->cipher) == EVP_CIPH_XTS_MODE || EVP_CIPHER_mode(cdat->cipher) == EVP_CIPH_WRAP_MODE) break; diff --git a/test/recipes/30-test_evp.t b/test/recipes/30-test_evp.t index d8162bc886..c2079bd6e6 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 0000000000..5419918352 --- /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 27b32b37e4..59fc3470f1 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