[openssl] master update
Richard Levitte
levitte at openssl.org
Wed Jul 15 21:12:41 UTC 2020
The branch master has been updated
via 7cc355c2e4e081dca3c6c345a75a2ab16800c807 (commit)
from c35b8535768e22cd3b7743f4887a72e53a621a5f (commit)
- Log -----------------------------------------------------------------
commit 7cc355c2e4e081dca3c6c345a75a2ab16800c807
Author: Shane Lontis <shane.lontis at oracle.com>
Date: Mon Jun 8 14:33:27 2020 +1000
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 at openssl.org>
(Merged from https://github.com/openssl/openssl/pull/12094)
-----------------------------------------------------------------------
Summary of changes:
CHANGES.md | 5 +
doc/man3/EVP_CIPHER_meth_new.pod | 12 +-
doc/man3/EVP_EncryptInit.pod | 44 +++
doc/man7/provider-cipher.pod | 32 ++
include/openssl/core_names.h | 6 +
include/openssl/evp.h | 10 +-
providers/defltprov.c | 3 +
providers/fips/fipsprov.c | 3 +
providers/implementations/ciphers/build.info | 6 +-
providers/implementations/ciphers/cipher_aes.c | 2 +
.../ciphers/cipher_aes_cts.h} | 13 +-
.../implementations/ciphers/cipher_aes_cts.inc | 108 ++++++
.../implementations/ciphers/cipher_aes_cts_fips.c | 368 +++++++++++++++++++++
.../implementations/include/prov/ciphercommon.h | 3 +
.../implementations/include/prov/implementations.h | 3 +
test/evp_test.c | 18 +
test/recipes/30-test_evp.t | 3 +-
test/recipes/30-test_evp_data/evpciph_aes_cts.txt | 362 ++++++++++++++++++++
18 files changed, 978 insertions(+), 23 deletions(-)
copy providers/{common/der/der_ec_gen.c.in => implementations/ciphers/cipher_aes_cts.h} (54%)
create mode 100644 providers/implementations/ciphers/cipher_aes_cts.inc
create mode 100644 providers/implementations/ciphers/cipher_aes_cts_fips.c
create mode 100644 test/recipes/30-test_evp_data/evpciph_aes_cts.txt
diff --git a/CHANGES.md b/CHANGES.md
index 4e0002f668..68d269cb5d 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -23,6 +23,11 @@ OpenSSL 3.0
### Changes between 1.1.1 and 3.0 [xx XXX xxxx]
+ * Added ciphertext stealing algorithms AES-128-CBC-CTS, AES-192-CBC-CTS and
+ AES-256-CBC-CTS to the providers. CS1, CS2 and CS3 variants are supported.
+
+ *Shane Lontis*
+
* 'Configure' has been changed to figure out the configuration target if
none is given on the command line. Consequently, the 'config' script is
now only a mere wrapper. All documentation is changed to only mention
diff --git a/doc/man3/EVP_CIPHER_meth_new.pod b/doc/man3/EVP_CIPHER_meth_new.pod
index 272e80115c..92ce1d902f 100644
--- a/doc/man3/EVP_CIPHER_meth_new.pod
+++ b/doc/man3/EVP_CIPHER_meth_new.pod
@@ -153,15 +153,11 @@ decryption is to be understood as the number of bits instead of
bytes for this implementation.
This is only useful for CFB1 ciphers.
-=begin comment
-The FIPS flags seem to be unused, so I'm hiding them until I get an
-explanation or they get removed. /RL
+=item EVP_CIPH_FLAG_CTS
-=item EVP_CIPH_FLAG_FIPS
-
-=item EVP_CIPH_FLAG_NON_FIPS_ALLOW
-
-=end comment
+Indicates that the cipher uses ciphertext stealing. This is currently
+used to indicate that the cipher is a one shot that only allows a single call to
+EVP_CipherUpdate().
=item EVP_CIPH_FLAG_CUSTOM_CIPHER
diff --git a/doc/man3/EVP_EncryptInit.pod b/doc/man3/EVP_EncryptInit.pod
index 36efb4090d..d40402ba1d 100644
--- a/doc/man3/EVP_EncryptInit.pod
+++ b/doc/man3/EVP_EncryptInit.pod
@@ -800,6 +800,50 @@ with a 128-bit key:
return 1;
}
+Encryption using AES-CBC with a 256-bit key with "CS1" ciphertext stealing.
+
+ int encrypt(const unsigned char *key, const unsigned char *iv,
+ const unsigned char *msg, size_t msg_len, unsigned char *out)
+ {
+ /*
+ * This assumes that key size is 32 bytes and the iv is 16 bytes.
+ * For ciphertext stealing mode the length of the ciphertext "out" will be
+ * the same size as the plaintext size "msg_len".
+ * The "msg_len" can be any size >= 16.
+ */
+ int ret = 0, encrypt = 1, outlen, len;
+ EVP_CIPHER_CTX *ctx = NULL;
+ EVP_CIPHER *cipher = NULL;
+ OSSL_PARAM params[2];
+
+ ctx = EVP_CIPHER_CTX_new();
+ cipher = EVP_CIPHER_fetch(NULL, "AES-256-CBC-CTS", NULL);
+ if (ctx == NULL || cipher == NULL)
+ goto err;
+
+ if (!EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, encrypt))
+ goto err;
+ /*
+ * The default is "CS1" so this is not really needed,
+ * but would be needed to set either "CS2" or "CS3".
+ */
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE,
+ "CS1", 0);
+ params[1] = OSSL_PARAM_construct_end();
+ if (!EVP_CIPHER_CTX_set_params(ctx, params))
+ goto err;
+
+ /* NOTE: CTS mode does not support multiple calls to EVP_CipherUpdate() */
+ if (!EVP_CipherUpdate(ctx, encrypted, &outlen, msg, msglen))
+ goto err;
+ if (!EVP_CipherFinal_ex(ctx, encrypted + outlen, &len))
+ goto err;
+ ret = 1;
+ err:
+ EVP_CIPHER_free(cipher);
+ EVP_CIPHER_CTX_free(ctx);
+ return ret;
+ }
=head1 SEE ALSO
diff --git a/doc/man7/provider-cipher.pod b/doc/man7/provider-cipher.pod
index bb8df17514..83f1768302 100644
--- a/doc/man7/provider-cipher.pod
+++ b/doc/man7/provider-cipher.pod
@@ -410,6 +410,38 @@ Byte 11-12: Input length (Always 0)
Gets the result of running the "tls1multi_aad" operation.
+=item "cts_mode" (B<OSSL_CIPHER_PARAM_CTS_MODE>) <utf8 string>
+
+Sets the cipher text stealing mode. For all modes the output size is the same as
+the input size.
+
+Valid values for the mode are:
+
+=over 4
+
+=item "CS1"
+
+The NIST variant of cipher text stealing.
+For message lengths that are multiples of the block size it is equivalent to
+using a "AES-CBC" cipher otherwise the second last cipher text block is a
+partial block.
+
+=item "CS2"
+
+For message lengths that are multiples of the block size it is equivalent to
+using a "AES-CBC" cipher, otherwise it is the same as "CS3".
+
+=item "CS3"
+
+The Kerberos5 variant of cipher text stealing which always swaps the last
+cipher text block with the previous block (which may be a partial or full block
+depending on the input length).
+
+=back
+
+The default is "CS1".
+This is only supported for "AES-128-CBC-CTS", "AES-192-CBC-CTS" and "AES-256-CBC-CTS".
+
=back
=head1 RETURN VALUES
diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h
index 9ad81337c3..702ee6a6ed 100644
--- a/include/openssl/core_names.h
+++ b/include/openssl/core_names.h
@@ -66,6 +66,7 @@ extern "C" {
#define OSSL_CIPHER_PARAM_RANDOM_KEY "randkey" /* octet_string */
#define OSSL_CIPHER_PARAM_RC2_KEYBITS "keybits" /* size_t */
#define OSSL_CIPHER_PARAM_SPEED "speed" /* uint */
+#define OSSL_CIPHER_PARAM_CTS_MODE "cts_mode" /* utf8_string */
/* For passing the AlgorithmIdentifier parameter in DER form */
#define OSSL_CIPHER_PARAM_ALG_ID "alg_id_param" /* octet_string */
@@ -86,6 +87,11 @@ extern "C" {
#define OSSL_CIPHER_PARAM_TLS1_MULTIBLOCK_ENC_LEN \
"tls1multi_enclen" /* size_t */
+/* OSSL_CIPHER_PARAM_CTS_MODE Values */
+#define OSSL_CIPHER_CTS_MODE_CS1 "CS1"
+#define OSSL_CIPHER_CTS_MODE_CS2 "CS2"
+#define OSSL_CIPHER_CTS_MODE_CS3 "CS3"
+
/* digest parameters */
#define OSSL_DIGEST_PARAM_XOFLEN "xoflen" /* size_t */
#define OSSL_DIGEST_PARAM_SSL3_MS "ssl3-ms" /* octet string */
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 644a214a6e..85a939b5c3 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -287,13 +287,15 @@ int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
/* Free: 0x1000 */
/* Buffer length in bits not bytes: CFB1 mode only */
# define EVP_CIPH_FLAG_LENGTH_BITS 0x2000
-/* Note if suitable for use in FIPS mode */
-# define EVP_CIPH_FLAG_FIPS 0x4000
-/* Allow non FIPS cipher in FIPS mode */
-# define EVP_CIPH_FLAG_NON_FIPS_ALLOW 0x8000
+/* Deprecated FIPS flag: was 0x4000 */
+# define EVP_CIPH_FLAG_FIPS 0
+/* Deprecated FIPS flag: was 0x8000 */
+# define EVP_CIPH_FLAG_NON_FIPS_ALLOW 0
+
/*
* Cipher handles any and all padding logic as well as finalisation.
*/
+# define EVP_CIPH_FLAG_CTS 0x4000
# define EVP_CIPH_FLAG_CUSTOM_CIPHER 0x100000
# define EVP_CIPH_FLAG_AEAD_CIPHER 0x200000
# define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0x400000
diff --git a/providers/defltprov.c b/providers/defltprov.c
index c92736e547..d404585afd 100644
--- a/providers/defltprov.c
+++ b/providers/defltprov.c
@@ -154,6 +154,9 @@ static const OSSL_ALGORITHM_CAPABLE deflt_ciphers[] = {
ALG("AES-256-CBC", aes256cbc_functions),
ALG("AES-192-CBC", aes192cbc_functions),
ALG("AES-128-CBC", aes128cbc_functions),
+ ALG("AES-128-CBC-CTS", aes128cbc_cts_functions),
+ ALG("AES-192-CBC-CTS", aes192cbc_cts_functions),
+ ALG("AES-256-CBC-CTS", aes256cbc_cts_functions),
ALG("AES-256-OFB", aes256ofb_functions),
ALG("AES-192-OFB", aes192ofb_functions),
ALG("AES-128-OFB", aes128ofb_functions),
diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c
index f7289ad75e..a998e392d7 100644
--- a/providers/fips/fipsprov.c
+++ b/providers/fips/fipsprov.c
@@ -399,6 +399,9 @@ static const OSSL_ALGORITHM_CAPABLE fips_ciphers[] = {
ALG("AES-256-CBC", aes256cbc_functions),
ALG("AES-192-CBC", aes192cbc_functions),
ALG("AES-128-CBC", aes128cbc_functions),
+ ALG("AES-256-CBC-CTS", aes256cbc_cts_functions),
+ ALG("AES-192-CBC-CTS", aes192cbc_cts_functions),
+ ALG("AES-128-CBC-CTS", aes128cbc_cts_functions),
ALG("AES-256-OFB", aes256ofb_functions),
ALG("AES-192-OFB", aes192ofb_functions),
ALG("AES-128-OFB", aes128ofb_functions),
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/common/der/der_ec_gen.c.in b/providers/implementations/ciphers/cipher_aes_cts.h
similarity index 54%
copy from providers/common/der/der_ec_gen.c.in
copy to providers/implementations/ciphers/cipher_aes_cts.h
index 40acf9a31c..6b0dfdd2c1 100644
--- a/providers/common/der/der_ec_gen.c.in
+++ b/providers/implementations/ciphers/cipher_aes_cts.h
@@ -7,11 +7,10 @@
* https://www.openssl.org/source/license.html
*/
-#include "prov/der_ec.h"
+#include "crypto/evp.h"
-/* Well known OIDs precompiled */
-{-
- $OUT = oids_to_c::process_leaves('providers/common/der/EC.asn1',
- { dir => $config{sourcedir},
- filter => \&oids_to_c::filter_to_C });
--}
+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;
+}
diff --git a/providers/implementations/include/prov/ciphercommon.h b/providers/implementations/include/prov/ciphercommon.h
index a5ffbc48a1..7e8143fae0 100644
--- a/providers/implementations/include/prov/ciphercommon.h
+++ b/providers/implementations/include/prov/ciphercommon.h
@@ -47,9 +47,12 @@ struct prov_cipher_ctx_st {
size_t ivlen;
size_t blocksize;
size_t bufsz; /* Number of bytes in buf */
+ unsigned int cts_mode; /* Use to set the type for CTS modes */
unsigned int pad : 1; /* Whether padding should be used or not */
unsigned int enc : 1; /* Set to 1 for encrypt, or 0 otherwise */
unsigned int iv_set : 1; /* Set when the iv is copied to the iv/oiv buffers */
+ unsigned int updated : 1; /* Set to 1 during update for one shot ciphers */
+
unsigned int tlsversion; /* If TLS padding is in use the TLS version number */
unsigned char *tlsmac; /* tls MAC extracted from the last record */
diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h
index ee942e94e1..0b32f3727c 100644
--- a/providers/implementations/include/prov/implementations.h
+++ b/providers/implementations/include/prov/implementations.h
@@ -45,6 +45,9 @@ extern const OSSL_DISPATCH aes128ecb_functions[];
extern const OSSL_DISPATCH aes256cbc_functions[];
extern const OSSL_DISPATCH aes192cbc_functions[];
extern const OSSL_DISPATCH aes128cbc_functions[];
+extern const OSSL_DISPATCH aes256cbc_cts_functions[];
+extern const OSSL_DISPATCH aes192cbc_cts_functions[];
+extern const OSSL_DISPATCH aes128cbc_cts_functions[];
extern const OSSL_DISPATCH aes256ofb_functions[];
extern const OSSL_DISPATCH aes192ofb_functions[];
extern const OSSL_DISPATCH aes128ofb_functions[];
diff --git a/test/evp_test.c b/test/evp_test.c
index c0b7b6f50f..7e93b41f32 100644
--- a/test/evp_test.c
+++ b/test/evp_test.c
@@ -514,6 +514,7 @@ typedef struct cipher_data_st {
unsigned char *aad[AAD_NUM];
size_t aad_len[AAD_NUM];
unsigned char *tag;
+ const char *cts_mode;
size_t tag_len;
int tag_late;
} CIPHER_DATA;
@@ -628,6 +629,10 @@ static int cipher_test_parse(EVP_TEST *t, const char *keyword,
return -1;
return 1;
}
+ if (strcmp(keyword, "CTSMode") == 0) {
+ cdat->cts_mode = value;
+ return 1;
+ }
return 0;
}
@@ -687,6 +692,18 @@ static int cipher_test_enc(EVP_TEST *t, int enc,
t->err = "CIPHERINIT_ERROR";
goto err;
}
+ if (expected->cts_mode != NULL) {
+ OSSL_PARAM params[2];
+
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE,
+ (char *)expected->cts_mode,
+ 0);
+ params[1] = OSSL_PARAM_construct_end();
+ if (!EVP_CIPHER_CTX_set_params(ctx_base, params)) {
+ t->err = "INVALID_CTS_MODE";
+ goto err;
+ }
+ }
if (expected->iv) {
if (expected->aead) {
if (!EVP_CIPHER_CTX_ctrl(ctx_base, EVP_CTRL_AEAD_SET_IVLEN,
@@ -939,6 +956,7 @@ static int cipher_test_run(EVP_TEST *t)
* lengths so we don't fragment for those
*/
if (cdat->aead == EVP_CIPH_CCM_MODE
+ || ((EVP_CIPHER_flags(cdat->cipher) & EVP_CIPH_FLAG_CTS) != 0)
|| 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)
diff --git a/test/recipes/30-test_evp.t b/test/recipes/30-test_evp.t
index 3855d8a3b9..32639b77a5 100644
--- a/test/recipes/30-test_evp.t
+++ b/test/recipes/30-test_evp.t
@@ -32,7 +32,8 @@ my @configs = ( $defaultcnf );
push @configs, 'fips.cnf' unless $no_fips;
my @files = qw( evprand.txt evpciph.txt evpdigest.txt evppkey.txt
- evppkey_ecc.txt );
+ evppkey_ecc.txt evpciph_aes_cts.txt);
+
my @defltfiles = qw( evpencod.txt evpkdf.txt evppkey_kdf.txt evpmac.txt
evppbe.txt evpcase.txt evpccmcavs.txt );
my @ideafiles = qw( evpciph_idea.txt );
diff --git a/test/recipes/30-test_evp_data/evpciph_aes_cts.txt b/test/recipes/30-test_evp_data/evpciph_aes_cts.txt
new file mode 100644
index 0000000000..83bac2c5c8
--- /dev/null
+++ b/test/recipes/30-test_evp_data/evpciph_aes_cts.txt
@@ -0,0 +1,362 @@
+#
+# 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
+
+# Original test vectors were taken from https://www.ietf.org/rfc/rfc3962.txt for CS3
+# These have an IV of all zeros, for a 128 bit AES key.
+
+# 17 bytes Input
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b652074686520
+Ciphertext = c6353568f2bf8cb4d8a580362da7ff7f97
+
+# 31 bytes input
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320
+Ciphertext = fc00783e0efdb2c1d445d4c8eff7ed2297687268d6ecccc0c07b25e25ecfe5
+
+# 32 bytes input (CS3 always swaps the last 2 byte blocks - so it is not equivalent to CBC for a full block)
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c2047617527732043
+Ciphertext = 39312523a78662d5be7fcbcc98ebf5a897687268d6ecccc0c07b25e25ecfe584
+
+# 47 bytes input
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe584b3fffd940c16a18c1b5549d2f838029e39312523a78662d5be7fcbcc98ebf5
+
+# 48 bytes input
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe5849dad8bbb96c4cdc03bc103e1a194bbd839312523a78662d5be7fcbcc98ebf5a8
+
+# 64 bytes input (CS3 always swaps the last 2 byte blocks - so it is not equivalent to CBC for a full block)
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20616e6420776f6e746f6e20736f75702e
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a84807efe836ee89a526730dbc2f7bc8409dad8bbb96c4cdc03bc103e1a194bbd8
+
+#------------------------------------------------------
+# AES_CBC results for aligned block lengths. (Result should be the same as 32 byte CTS1 & CTS2)
+
+# 32 bytes input
+Cipher = AES-128-CBC
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c2047617527732043
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a8
+
+# 48 bytes input
+Cipher = AES-128-CBC
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a89dad8bbb96c4cdc03bc103e1a194bbd8
+
+# 64 bytes input
+Cipher = AES-128-CBC
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20616e6420776f6e746f6e20736f75702e
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a89dad8bbb96c4cdc03bc103e1a194bbd84807efe836ee89a526730dbc2f7bc840
+
+#------------------------------------------------------
+# Manually edited using the same inputs to also produce CS2 ciphertext
+# where aligned blocks are the same as CBC mode, and partial lengths
+# are the same as CS3.
+
+# 17 bytes Input (For partial blocks the output should match CS3)
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS2
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b652074686520
+Ciphertext = c6353568f2bf8cb4d8a580362da7ff7f97
+
+# 31 bytes input (For partial blocks the output should match CS3)
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS2
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320
+Ciphertext = fc00783e0efdb2c1d445d4c8eff7ed2297687268d6ecccc0c07b25e25ecfe5
+
+# 32 bytes input (Aligned blocks should match normal CBC mode)
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS2
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c2047617527732043
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a8
+
+# 47 bytes input
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS2
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe584b3fffd940c16a18c1b5549d2f838029e39312523a78662d5be7fcbcc98ebf5
+
+# 64 bytes input (CS2 is equivalent to CBC when the last block in full)
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS2
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20616e6420776f6e746f6e20736f75702e
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a89dad8bbb96c4cdc03bc103e1a194bbd84807efe836ee89a526730dbc2f7bc840
+
+#------------------------------------------------------
+# Manually edited using the same inputs to also produce CS1 ciphertext
+# where aligned blocks are the same as CBC mode, and partial lengths
+# have the last 2 blocks swapped compared to CS3.
+
+# 17 bytes Input((Default is CS1 if CTSMode is not specified)
+Cipher = AES-128-CBC-CTS
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b652074686520
+Ciphertext = 97c6353568f2bf8cb4d8a580362da7ff7f
+
+# 31 bytes input
+Cipher = AES-128-CBC-CTS
+CTSMode = CS1
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe5fc00783e0efdb2c1d445d4c8eff7ed22
+
+# 32 bytes input
+Cipher = AES-128-CBC-CTS
+CTSMode = CS1
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c2047617527732043
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a8
+
+# 47 bytes input
+Cipher = AES-128-CBC-CTS
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5b3fffd940c16a18c1b5549d2f838029e
+
+# 64 bytes input (CS1 is equivalent to CBC when the last block in full)
+Cipher = AES-128-CBC-CTS
+CTSMode = CS1
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20616e6420776f6e746f6e20736f75702e
+Ciphertext = 97687268d6ecccc0c07b25e25ecfe58439312523a78662d5be7fcbcc98ebf5a89dad8bbb96c4cdc03bc103e1a194bbd84807efe836ee89a526730dbc2f7bc840
+
+#-------------------------------------------------------------------------------
+# Generated test values using an IV.
+
+# 47 bytes input
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c
+Ciphertext = 5432a630742dee7beb70f9f1400ee6a0426da5c54a9990f5ae0b7825f51f0060b557cfb581949a4bdf3bb67dedd472
+
+# 47 bytes input
+Cipher = AES-128-CBC-CTS
+CTSMode = CS1
+Key = 636869636b656e207465726979616b69
+IV =000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c
+Ciphertext = 5432a630742dee7beb70f9f1400ee6a0b557cfb581949a4bdf3bb67dedd472426da5c54a9990f5ae0b7825f51f0060
+
+# 127 bytes
+Cipher = AES-128-CBC-CTS
+CTSMode = CS1
+Key = 636869636b656e207465726979616b69
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20616e6420776f6e746f6e20736f75702e4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20616e6420776f6e746f6e20736f7570
+Ciphertext = 5432a630742dee7beb70f9f1400ee6a0b557cfb581949a4bdf3bb67dedd472b9fc50e4e7dacf9e3d94b6cc031f9997a22d2fea7e6ef4aba2b717b0fa3f150e5e86e46b9e51c6ea5091a92aa791ce826b2e4fbaaf0e0314939625434b9530ce56f299891a48d26bdc287f54b230340d652a4721bf0f082ede80b6399800a92f
+
+# 129 bytes
+Cipher = AES-128-CBC-CTS
+CTSMode = CS1
+Key = 636869636b656e207465726979616b69
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20616e6420776f6e746f6e20736f75702e4920776f756c64206c696b65207468652047656e6572616c20476175277320436869636b656e2c20706c656173652c20616e6420776f6e746f6e20736f75702e49
+Ciphertext = 5432a630742dee7beb70f9f1400ee6a0b557cfb581949a4bdf3bb67dedd472b9fc50e4e7dacf9e3d94b6cc031f9997a22d2fea7e6ef4aba2b717b0fa3f150e5e86e46b9e51c6ea5091a92aa791ce826b2e4fbaaf0e0314939625434b9530ce56f299891a48d26bdc287f54b230340d14fde9fd1098b9b1db788b5868a8d009eeef
+
+#-------------------------------------------------------------------------------
+# 17 Bytes
+Cipher = AES-192-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69636869636b656e20
+IV =000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b652074686520
+Ciphertext = de1b402de8f79f947cc6b5880588d9b6e9
+
+# 31 Bytes
+Cipher = AES-192-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69636869636b656e20
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320
+Ciphertext = dea2b610546f3b1e1d231821e283e153e9de17d6248fb492bdea1fb2e09c8e
+
+# 32 Bytes
+Cipher = AES-192-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69636869636b656e20
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c2047617527732043
+Ciphertext = 31d005cc9fea948fed1ba6308dad9dd1e9de17d6248fb492bdea1fb2e09c8e8e
+
+# 17 Bytes
+Cipher = AES-192-CBC-CTS
+Availablein = default
+CTSMode = CS2
+Key = 636869636b656e207465726979616b69636869636b656e20
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b652074686520
+Ciphertext = de1b402de8f79f947cc6b5880588d9b6e9
+
+# 31 Bytes
+Cipher = AES-192-CBC-CTS
+Availablein = default
+CTSMode = CS2
+Key = 636869636b656e207465726979616b69636869636b656e20
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320
+Ciphertext = dea2b610546f3b1e1d231821e283e153e9de17d6248fb492bdea1fb2e09c8e
+
+# 32 Bytes
+Cipher = AES-192-CBC-CTS
+Availablein = default
+CTSMode = CS2
+Key = 636869636b656e207465726979616b69636869636b656e20
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c2047617527732043
+Ciphertext = e9de17d6248fb492bdea1fb2e09c8e8e31d005cc9fea948fed1ba6308dad9dd1
+
+# 17 Bytes
+Cipher = AES-192-CBC-CTS
+CTSMode = CS1
+Key = 636869636b656e207465726979616b69636869636b656e20
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b652074686520
+Ciphertext = e9de1b402de8f79f947cc6b5880588d9b6
+
+# 31 Bytes
+Cipher = AES-192-CBC-CTS
+CTSMode = CS1
+Key = 636869636b656e207465726979616b69636869636b656e20
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320
+Ciphertext = e9de17d6248fb492bdea1fb2e09c8edea2b610546f3b1e1d231821e283e153
+
+# 32 Bytes
+Cipher = AES-192-CBC-CTS
+CTSMode = CS1
+Key = 636869636b656e207465726979616b69636869636b656e20
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c2047617527732043
+Ciphertext = e9de17d6248fb492bdea1fb2e09c8e8e31d005cc9fea948fed1ba6308dad9dd1
+
+#-------------------------------------------------------------------------------
+# 17 Bytes
+Cipher = AES-256-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69636869636b656e207465726979616b69
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b652074686520
+Ciphertext = 6b5f5abc21c4d04156c73850da3bba29e9
+
+# 31 Bytes
+Cipher = AES-256-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69636869636b656e207465726979616b69
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c20476175277320
+Ciphertext = f22553af78ee4f468f02fbe6f0f2168ee954e79fae9310dc75b6070e1d6253
+
+# 32 Bytes
+Cipher = AES-256-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69636869636b656e207465726979616b69
+IV = 000102030405060708090A0B0C0D0E0F
+Plaintext = 4920776f756c64206c696b65207468652047656e6572616c2047617527732043
+Ciphertext = 2c0463982174df10baa9d8f782c5a5b3e954e79fae9310dc75b6070e1d625346
+
+#------------------------------------------------------------------------------
+# Failure tests
+
+# 15 bytes should fail for CS1
+Cipher = AES-128-CBC-CTS
+CTSMode = CS1
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 0102030405060708090A0B0C0D0E0F
+Result = CIPHERUPDATE_ERROR
+
+# 15 bytes should fail for CS2
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS2
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 0102030405060708090A0B0C0D0E0F
+Result = CIPHERUPDATE_ERROR
+
+# 15 bytes should fail for CS3
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 0102030405060708090A0B0C0D0E0F
+Result = CIPHERUPDATE_ERROR
+
+# 16 bytes should fail for CS3 (since it always needs 2 blocks).
+Cipher = AES-128-CBC-CTS
+Availablein = default
+CTSMode = CS3
+Key = 636869636b656e207465726979616b69
+IV = 00000000000000000000000000000000
+Plaintext = 0102030405060708090A0B0C0D0E0F00
+Result = CIPHERUPDATE_ERROR
More information about the openssl-commits
mailing list