From: Shane Lontis Date: Mon, 8 Jun 2020 04:33:27 +0000 (+1000) Subject: Add AES_CBC_CTS ciphers to providers X-Git-Tag: openssl-3.0.0-alpha5~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7cc355c2e4e081dca3c6c345a75a2ab16800c807;p=thirdparty%2Fopenssl.git 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 (Merged from https://github.com/openssl/openssl/pull/12094) --- diff --git a/CHANGES.md b/CHANGES.md index 4e0002f668c..68d269cb5d5 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 272e80115c8..92ce1d902f8 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 36efb4090d2..d40402ba1dc 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 bb8df17514b..83f17683020 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) + +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 9ad81337c3e..702ee6a6ed4 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 644a214a6e6..85a939b5c3a 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 c92736e5473..d404585afd1 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 f7289ad75ea..a998e392d7b 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 a952c21638d..9199ae0a92d 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 decc27517ca..b0c716e3b71 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 00000000000..6b0dfdd2c10 --- /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 00000000000..5b33e972c58 --- /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 00000000000..81e81ad5f2d --- /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 +#include +#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 a5ffbc48a1a..7e8143fae0e 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 ee942e94e1c..0b32f3727c2 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 c0b7b6f50fa..7e93b41f324 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 3855d8a3b9f..32639b77a5c 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 00000000000..83bac2c5c81 --- /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