summaryrefslogtreecommitdiffstats
path: root/providers/implementations/ciphers
diff options
context:
space:
mode:
authorShane Lontis <shane.lontis@oracle.com>2020-06-08 14:33:27 +1000
committerRichard Levitte <levitte@openssl.org>2020-07-15 23:11:50 +0200
commit7cc355c2e4e081dca3c6c345a75a2ab16800c807 (patch)
treeaf03550512bc59ca961934e9009c6c8fd4be5656 /providers/implementations/ciphers
parentc35b8535768e22cd3b7743f4887a72e53a621a5f (diff)
Add AES_CBC_CTS ciphers to providers
Added Algorithm names AES-128-CBC-CTS, AES-192-CBC-CTS and AES-256-CBC-CTS. CS1, CS2 and CS3 variants are supported. Only single shot updates are supported. The cipher returns the mode EVP_CIPH_CBC_MODE (Internally it shares the aes_cbc cipher code). This would allow existing code that uses AES_CBC to switch to the CTS variant without breaking code that tests for this mode. Because it shares the aes_cbc code the cts128.c functions could not be used directly. The cipher returns the flag EVP_CIPH_FLAG_CTS. EVP_CIPH_FLAG_FIPS & EVP_CIPH_FLAG_NON_FIPS_ALLOW have been deprecated. Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/12094)
Diffstat (limited to 'providers/implementations/ciphers')
-rw-r--r--providers/implementations/ciphers/build.info6
-rw-r--r--providers/implementations/ciphers/cipher_aes.c2
-rw-r--r--providers/implementations/ciphers/cipher_aes_cts.h16
-rw-r--r--providers/implementations/ciphers/cipher_aes_cts.inc108
-rw-r--r--providers/implementations/ciphers/cipher_aes_cts_fips.c368
5 files changed, 497 insertions, 3 deletions
diff --git a/providers/implementations/ciphers/build.info b/providers/implementations/ciphers/build.info
index a952c21638..9199ae0a92 100644
--- a/providers/implementations/ciphers/build.info
+++ b/providers/implementations/ciphers/build.info
@@ -49,9 +49,9 @@ SOURCE[$AES_GOAL]=\
cipher_aes_cbc_hmac_sha256_hw.c cipher_aes_cbc_hmac_sha1_hw.c
# Extra code to satisfy the FIPS and non-FIPS separation.
-# When the AES-xxx-XTS moves to legacy, this can be removed.
-SOURCE[../../libfips.a]=cipher_aes_xts_fips.c
-SOURCE[../../libnonfips.a]=cipher_aes_xts_fips.c
+# When the AES-xxx-XTS moves to legacy, cipher_aes_xts_fips.c can be removed.
+SOURCE[../../libfips.a]=cipher_aes_xts_fips.c cipher_aes_cts_fips.c
+SOURCE[../../libnonfips.a]=cipher_aes_xts_fips.c cipher_aes_cts_fips.c
IF[{- !$disabled{siv} -}]
SOURCE[$SIV_GOAL]=\
diff --git a/providers/implementations/ciphers/cipher_aes.c b/providers/implementations/ciphers/cipher_aes.c
index decc27517c..b0c716e3b7 100644
--- a/providers/implementations/ciphers/cipher_aes.c
+++ b/providers/implementations/ciphers/cipher_aes.c
@@ -86,3 +86,5 @@ IMPLEMENT_generic_cipher(aes, AES, ctr, CTR, 0, 256, 8, 128, stream)
IMPLEMENT_generic_cipher(aes, AES, ctr, CTR, 0, 192, 8, 128, stream)
/* aes128ctr_functions */
IMPLEMENT_generic_cipher(aes, AES, ctr, CTR, 0, 128, 8, 128, stream)
+
+#include "cipher_aes_cts.inc"
diff --git a/providers/implementations/ciphers/cipher_aes_cts.h b/providers/implementations/ciphers/cipher_aes_cts.h
new file mode 100644
index 0000000000..6b0dfdd2c1
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_cts.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (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 "crypto/evp.h"
+
+OSSL_FUNC_cipher_update_fn aes_cbc_cts_block_update;
+OSSL_FUNC_cipher_final_fn aes_cbc_cts_block_final;
+
+const char *aes_cbc_cts_mode_id2name(unsigned int id);
+int aes_cbc_cts_mode_name2id(const char *name);
diff --git a/providers/implementations/ciphers/cipher_aes_cts.inc b/providers/implementations/ciphers/cipher_aes_cts.inc
new file mode 100644
index 0000000000..5b33e972c5
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_cts.inc
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (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
+ */
+
+/* Dispatch functions for AES CBC CTS ciphers */
+
+#include "cipher_aes_cts.h"
+#include "prov/providercommonerr.h"
+
+static OSSL_FUNC_cipher_get_ctx_params_fn aes_cbc_cts_get_ctx_params;
+static OSSL_FUNC_cipher_set_ctx_params_fn aes_cbc_cts_set_ctx_params;
+static OSSL_FUNC_cipher_gettable_ctx_params_fn aes_cbc_cts_gettable_ctx_params;
+static OSSL_FUNC_cipher_settable_ctx_params_fn aes_cbc_cts_settable_ctx_params;
+
+CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_START(aes_cbc_cts)
+OSSL_PARAM_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE, NULL, 0),
+CIPHER_DEFAULT_GETTABLE_CTX_PARAMS_END(aes_cbc_cts)
+
+static int aes_cbc_cts_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_CTS_MODE);
+ if (p != NULL) {
+ const char *name = aes_cbc_cts_mode_id2name(ctx->cts_mode);
+
+ if (name == NULL || !OSSL_PARAM_set_utf8_string(p, name)) {
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+ }
+ }
+ return cipher_generic_get_ctx_params(vctx, params);
+}
+
+CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_START(aes_cbc_cts)
+OSSL_PARAM_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE, NULL, 0),
+CIPHER_DEFAULT_SETTABLE_CTX_PARAMS_END(aes_cbc_cts)
+
+static int aes_cbc_cts_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ const OSSL_PARAM *p;
+ int id;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_CTS_MODE);
+ if (p != NULL) {
+ if (p->data_type != OSSL_PARAM_UTF8_STRING)
+ goto err;
+ id = aes_cbc_cts_mode_name2id(p->data);
+ if (id < 0)
+ goto err;
+
+ ctx->cts_mode = (unsigned int)id;
+ }
+ return cipher_generic_set_ctx_params(vctx, params);
+err:
+ ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+ return 0;
+}
+
+/* NOTE: The underlying block cipher is AES CBC so we reuse most of the code */
+#define IMPLEMENT_cts_cipher(alg, UCALG, lcmode, UCMODE, flags, kbits, \
+ blkbits, ivbits, typ) \
+static OSSL_FUNC_cipher_get_params_fn alg##_##kbits##_##lcmode##_get_params; \
+static int alg##_cts_##kbits##_##lcmode##_get_params(OSSL_PARAM params[]) \
+{ \
+ return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, flags, \
+ kbits, blkbits, ivbits); \
+} \
+const OSSL_DISPATCH alg##kbits##lcmode##_cts_functions[] = { \
+ { OSSL_FUNC_CIPHER_NEWCTX, \
+ (void (*)(void)) alg##_##kbits##_##lcmode##_newctx }, \
+ { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void)) alg##_freectx }, \
+ { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void)) alg##_dupctx }, \
+ { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void))cipher_generic_einit }, \
+ { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void))cipher_generic_dinit }, \
+ { OSSL_FUNC_CIPHER_UPDATE, \
+ (void (*)(void)) alg##_##lcmode##_cts_block_update }, \
+ { OSSL_FUNC_CIPHER_FINAL, \
+ (void (*)(void)) alg##_##lcmode##_cts_block_final }, \
+ { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))cipher_generic_cipher }, \
+ { OSSL_FUNC_CIPHER_GET_PARAMS, \
+ (void (*)(void)) alg##_cts_##kbits##_##lcmode##_get_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \
+ (void (*)(void))cipher_generic_gettable_params }, \
+ { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \
+ (void (*)(void))aes_cbc_cts_get_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \
+ (void (*)(void))aes_cbc_cts_set_ctx_params }, \
+ { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \
+ (void (*)(void))aes_cbc_cts_gettable_ctx_params }, \
+ { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \
+ (void (*)(void))aes_cbc_cts_settable_ctx_params }, \
+ { 0, NULL } \
+};
+
+/* aes256cbc_cts_functions */
+IMPLEMENT_cts_cipher(aes, AES, cbc, CBC, EVP_CIPH_FLAG_CTS, 256, 128, 128, block)
+/* aes192cbc_cts_functions */
+IMPLEMENT_cts_cipher(aes, AES, cbc, CBC, EVP_CIPH_FLAG_CTS, 192, 128, 128, block)
+/* aes128cbc_cts_functions */
+IMPLEMENT_cts_cipher(aes, AES, cbc, CBC, EVP_CIPH_FLAG_CTS, 128, 128, 128, block)
diff --git a/providers/implementations/ciphers/cipher_aes_cts_fips.c b/providers/implementations/ciphers/cipher_aes_cts_fips.c
new file mode 100644
index 0000000000..81e81ad5f2
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_cts_fips.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (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
+ */
+
+/* Helper functions for AES CBC CTS ciphers related to fips */
+
+/*
+ * Refer to SP800-38A-Addendum
+ *
+ * Ciphertext stealing encrypts plaintext using a block cipher, without padding
+ * the message to a multiple of the block size, so the ciphertext is the same
+ * size as the plaintext.
+ * It does this by altering processing of the last two blocks of the message.
+ * The processing of all but the last two blocks is unchanged, but a portion of
+ * the second-last block's ciphertext is "stolen" to pad the last plaintext
+ * block. The padded final block is then encrypted as usual.
+ * The final ciphertext for the last two blocks, consists of the partial block
+ * (with the "stolen" portion omitted) plus the full final block,
+ * which are the same size as the original plaintext.
+ * Decryption requires decrypting the final block first, then restoring the
+ * stolen ciphertext to the partial block, which can then be decrypted as usual.
+
+ * AES_CBC_CTS has 3 variants:
+ * (1) CS1 The NIST variant.
+ * If the length is a multiple of the blocksize it is the same as CBC mode.
+ * otherwise it produces C1||C2||(C(n-1))*||Cn.
+ * Where C(n-1)* is a partial block.
+ * (2) CS2
+ * If the length is a multiple of the blocksize it is the same as CBC mode.
+ * otherwise it produces C1||C2||Cn||(C(n-1))*.
+ * Where C(n-1)* is a partial block.
+ * (3) CS3 The Kerberos5 variant.
+ * Produces C1||C2||Cn||(C(n-1))* regardless of the length.
+ * If the length is a multiple of the blocksize it looks similar to CBC mode
+ * with the last 2 blocks swapped.
+ * Otherwise it is the same as CS2.
+ */
+
+#include "e_os.h" /* strcasecmp */
+#include <openssl/core_names.h>
+#include <openssl/aes.h>
+#include "prov/ciphercommon.h"
+#include "internal/nelem.h"
+#include "cipher_aes_cts.h"
+
+/* The value assigned to 0 is the default */
+#define CTS_CS1 0
+#define CTS_CS2 1
+#define CTS_CS3 2
+
+typedef union {
+ size_t align;
+ unsigned char c[AES_BLOCK_SIZE];
+} aligned_16bytes;
+
+typedef struct cts_mode_name2id_st {
+ unsigned int id;
+ const char *name;
+} CTS_MODE_NAME2ID;
+
+static CTS_MODE_NAME2ID cts_modes[] =
+{
+ { CTS_CS1, OSSL_CIPHER_CTS_MODE_CS1 },
+#ifndef FIPS_MODULE
+ { CTS_CS2, OSSL_CIPHER_CTS_MODE_CS2 },
+ { CTS_CS3, OSSL_CIPHER_CTS_MODE_CS3 },
+#endif
+};
+
+const char *aes_cbc_cts_mode_id2name(unsigned int id)
+{
+ size_t i;
+
+ for (i = 0; i < OSSL_NELEM(cts_modes); ++i) {
+ if (cts_modes[i].id == id)
+ return cts_modes[i].name;
+ }
+ return NULL;
+}
+
+int aes_cbc_cts_mode_name2id(const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < OSSL_NELEM(cts_modes); ++i) {
+ if (strcasecmp(name, cts_modes[i].name) == 0)
+ return (int)cts_modes[i].id;
+ }
+ return -1;
+}
+
+static size_t cts128_cs1_encrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in,
+ unsigned char *out, size_t len)
+{
+ aligned_16bytes tmp_in;
+ size_t residue;
+
+ residue = len % AES_BLOCK_SIZE;
+ len -= residue;
+ if (!ctx->hw->cipher(ctx, out, in, len))
+ return 0;
+
+ if (residue == 0)
+ return len;
+
+ in += len;
+ out += len;
+
+ memset(tmp_in.c, 0, sizeof(tmp_in));
+ memcpy(tmp_in.c, in, residue);
+ if (!ctx->hw->cipher(ctx, out - AES_BLOCK_SIZE + residue, tmp_in.c,
+ AES_BLOCK_SIZE))
+ return 0;
+ return len + residue;
+}
+
+static void do_xor(const unsigned char *in1, const unsigned char *in2,
+ size_t len, unsigned char *out)
+{
+ size_t i;
+
+ for (i = 0; i < len; ++i)
+ out[i] = in1[i] ^ in2[i];
+}
+
+static size_t cts128_cs1_decrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in,
+ unsigned char *out, size_t len)
+{
+ aligned_16bytes mid_iv, ct_mid, pt_last;
+ size_t residue;
+
+ residue = len % AES_BLOCK_SIZE;
+ if (residue == 0) {
+ /* If there are no partial blocks then it is the same as CBC mode */
+ if (!ctx->hw->cipher(ctx, out, in, len))
+ return 0;
+ return len;
+ }
+ /* Process blocks at the start - but leave the last 2 blocks */
+ len -= AES_BLOCK_SIZE + residue;
+ if (len > 0) {
+ if (!ctx->hw->cipher(ctx, out, in, len))
+ return 0;
+ in += len;
+ out += len;
+ }
+ /* Save the iv that will be used by the second last block */
+ memcpy(mid_iv.c, ctx->iv, AES_BLOCK_SIZE);
+
+ /* Decrypt the last block first using an iv of zero */
+ memset(ctx->iv, 0, AES_BLOCK_SIZE);
+ if (!ctx->hw->cipher(ctx, pt_last.c, in + residue, AES_BLOCK_SIZE))
+ return 0;
+
+ /*
+ * Rebuild the ciphertext of the second last block as a combination of
+ * the decrypted last block + replace the start with the ciphertext bytes
+ * of the partial second last block.
+ */
+ memcpy(ct_mid.c, in, residue);
+ memcpy(ct_mid.c + residue, pt_last.c + residue, AES_BLOCK_SIZE - residue);
+ /*
+ * Restore the last partial ciphertext block.
+ * Now that we have the cipher text of the second last block, apply
+ * that to the partial plaintext end block. We have already decrypted the
+ * block using an IV of zero. For decryption the IV is just XORed after
+ * doing an AES block - so just XOR in the cipher text.
+ */
+ do_xor(ct_mid.c, pt_last.c, residue, out + AES_BLOCK_SIZE);
+
+ /* Restore the iv needed by the second last block */
+ memcpy(ctx->iv, mid_iv.c, AES_BLOCK_SIZE);
+ /*
+ * Decrypt the second last plaintext block now that we have rebuilt the
+ * ciphertext.
+ */
+ if (!ctx->hw->cipher(ctx, out, ct_mid.c, AES_BLOCK_SIZE))
+ return 0;
+
+ return len + AES_BLOCK_SIZE + residue;
+}
+
+#ifndef FIPS_MODULE
+static size_t cts128_cs3_encrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in,
+ unsigned char *out, size_t len)
+{
+ aligned_16bytes tmp_in;
+ size_t residue;
+
+ if (len <= AES_BLOCK_SIZE) /* CS3 requires 2 blocks */
+ return 0;
+
+ residue = len % AES_BLOCK_SIZE;
+ if (residue == 0)
+ residue = AES_BLOCK_SIZE;
+ len -= residue;
+
+ if (!ctx->hw->cipher(ctx, out, in, len))
+ return 0;
+
+ in += len;
+ out += len;
+
+ memset(tmp_in.c, 0, sizeof(tmp_in));
+ memcpy(tmp_in.c, in, residue);
+ memcpy(out, out - AES_BLOCK_SIZE, residue);
+ if (!ctx->hw->cipher(ctx, out - AES_BLOCK_SIZE, tmp_in.c, AES_BLOCK_SIZE))
+ return 0;
+ return len + residue;
+}
+
+/*
+ * Note:
+ * The cipher text (in) is of the form C(0), C(1), ., C(n), C(n-1)* where
+ * C(n) is a full block and C(n-1)* can be a partial block
+ * (but could be a full block).
+ * This means that the output plaintext (out) needs to swap the plaintext of
+ * the last two decoded ciphertext blocks.
+ */
+static size_t cts128_cs3_decrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in,
+ unsigned char *out, size_t len)
+{
+ aligned_16bytes mid_iv, ct_mid, pt_last;
+ size_t residue;
+
+ if (len <= AES_BLOCK_SIZE) /* CS3 requires 2 blocks */
+ return 0;
+
+ /* Process blocks at the start - but leave the last 2 blocks */
+ residue = len % AES_BLOCK_SIZE;
+ if (residue == 0)
+ residue = AES_BLOCK_SIZE;
+ len -= AES_BLOCK_SIZE + residue;
+
+ if (len > 0) {
+ if (!ctx->hw->cipher(ctx, out, in, len))
+ return 0;
+ in += len;
+ out += len;
+ }
+ /* Save the iv that will be used by the second last block */
+ memcpy(mid_iv.c, ctx->iv, AES_BLOCK_SIZE);
+
+ /* Decrypt the Cn block first using an iv of zero */
+ memset(ctx->iv, 0, AES_BLOCK_SIZE);
+ if (!ctx->hw->cipher(ctx, pt_last.c, in, AES_BLOCK_SIZE))
+ return 0;
+
+ /*
+ * Rebuild the ciphertext of C(n-1) as a combination of
+ * the decrypted C(n) block + replace the start with the ciphertext bytes
+ * of the partial last block.
+ */
+ memcpy(ct_mid.c, in + AES_BLOCK_SIZE, residue);
+ if (residue != AES_BLOCK_SIZE)
+ memcpy(ct_mid.c + residue, pt_last.c + residue, AES_BLOCK_SIZE - residue);
+ /*
+ * Restore the last partial ciphertext block.
+ * Now that we have the cipher text of the second last block, apply
+ * that to the partial plaintext end block. We have already decrypted the
+ * block using an IV of zero. For decryption the IV is just XORed after
+ * doing an AES block - so just XOR in the ciphertext.
+ */
+ do_xor(ct_mid.c, pt_last.c, residue, out + AES_BLOCK_SIZE);
+
+ /* Restore the iv needed by the second last block */
+ memcpy(ctx->iv, mid_iv.c, AES_BLOCK_SIZE);
+ /*
+ * Decrypt the second last plaintext block now that we have rebuilt the
+ * ciphertext.
+ */
+ if (!ctx->hw->cipher(ctx, out, ct_mid.c, AES_BLOCK_SIZE))
+ return 0;
+
+ return len + AES_BLOCK_SIZE + residue;
+}
+
+static size_t cts128_cs2_encrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in,
+ unsigned char *out, size_t len)
+{
+ if (len % AES_BLOCK_SIZE == 0) {
+ /* If there are no partial blocks then it is the same as CBC mode */
+ if (!ctx->hw->cipher(ctx, out, in, len))
+ return 0;
+ return len;
+ }
+ /* For partial blocks CS2 is equivalent to CS3 */
+ return cts128_cs3_encrypt(ctx, in, out, len);
+}
+
+static size_t cts128_cs2_decrypt(PROV_CIPHER_CTX *ctx, const unsigned char *in,
+ unsigned char *out, size_t len)
+{
+ if (len % AES_BLOCK_SIZE == 0) {
+ /* If there are no partial blocks then it is the same as CBC mode */
+ if (!ctx->hw->cipher(ctx, out, in, len))
+ return 0;
+ return len;
+ }
+ /* For partial blocks CS2 is equivalent to CS3 */
+ return cts128_cs3_decrypt(ctx, in, out, len);
+}
+#endif
+
+int aes_cbc_cts_block_update(void *vctx, unsigned char *out, size_t *outl,
+ size_t outsize, const unsigned char *in,
+ size_t inl)
+{
+ PROV_CIPHER_CTX *ctx = (PROV_CIPHER_CTX *)vctx;
+ size_t sz = 0;
+
+ if (inl < AES_BLOCK_SIZE) /* There must be at least one block for CTS mode */
+ return 0;
+ if (outsize < inl)
+ return 0;
+ if (out == NULL) {
+ *outl = inl;
+ return 1;
+ }
+
+ /*
+ * Return an error if the update is called multiple times, only one shot
+ * is supported.
+ */
+ if (ctx->updated == 1)
+ return 0;
+
+ if (ctx->enc) {
+#ifdef FIPS_MODULE
+ sz = cts128_cs1_encrypt(ctx, in, out, inl);
+#else
+ if (ctx->cts_mode == CTS_CS1)
+ sz = cts128_cs1_encrypt(ctx, in, out, inl);
+ else if (ctx->cts_mode == CTS_CS2)
+ sz = cts128_cs2_encrypt(ctx, in, out, inl);
+ else if (ctx->cts_mode == CTS_CS3)
+ sz = cts128_cs3_encrypt(ctx, in, out, inl);
+#endif
+ } else {
+#ifdef FIPS_MODULE
+ sz = cts128_cs1_decrypt(ctx, in, out, inl);
+#else
+ if (ctx->cts_mode == CTS_CS1)
+ sz = cts128_cs1_decrypt(ctx, in, out, inl);
+ else if (ctx->cts_mode == CTS_CS2)
+ sz = cts128_cs2_decrypt(ctx, in, out, inl);
+ else if (ctx->cts_mode == CTS_CS3)
+ sz = cts128_cs3_decrypt(ctx, in, out, inl);
+#endif
+ }
+ if (sz == 0)
+ return 0;
+ ctx->updated = 1; /* Stop multiple updates being allowed */
+ *outl = sz;
+ return 1;
+}
+
+int aes_cbc_cts_block_final(void *vctx, unsigned char *out, size_t *outl,
+ size_t outsize)
+{
+ *outl = 0;
+ return 1;
+}