Implement CTS

Ciphertext stealing on top of CBC is implemented with `wolfSSL_CRYPTO_cts128_encrypt` and `wolfSSL_CRYPTO_cts128_decrypt` APIs
This commit is contained in:
Juliusz Sosinowicz
2021-09-13 14:50:34 +02:00
parent fa662c2ab1
commit ccbe184434
5 changed files with 210 additions and 2 deletions

View File

@ -6815,7 +6815,7 @@ then
AM_CFLAGS="-DOPENSSL_EXTRA -DWOLFSSL_ALWAYS_VERIFY_CB $AM_CFLAGS"
AM_CFLAGS="-DWOLFSSL_VERIFY_CB_ALL_CERTS -DWOLFSSL_EXTRA_ALERTS $AM_CFLAGS"
AM_CFLAGS="-DHAVE_EXT_CACHE -DWOLFSSL_FORCE_CACHE_ON_TICKET $AM_CFLAGS"
AM_CFLAGS="-DWOLFSSL_AKID_NAME $AM_CFLAGS"
AM_CFLAGS="-DWOLFSSL_AKID_NAME -DHAVE_CTS $AM_CFLAGS"
fi
if test "$ENABLED_OPENSSLEXTRA" = "x509small"

View File

@ -99,6 +99,7 @@
#include <wolfssl/openssl/ecdsa.h>
#include <wolfssl/openssl/ecdh.h>
#include <wolfssl/openssl/err.h>
#include <wolfssl/openssl/modes.h>
#include <wolfssl/openssl/opensslv.h>
#include <wolfssl/openssl/rc4.h>
#include <wolfssl/openssl/stack.h>
@ -30511,7 +30512,84 @@ int wolfSSL_AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
#endif /* HAVE_AES_KEYWRAP && !HAVE_FIPS && !HAVE_SELFTEST */
#endif /* NO_AES */
#ifndef NO_ASN_TIME
#ifdef HAVE_CTS
/*
* Ciphertext stealing interface compatible with RFC2040 and RFC3962.
*/
size_t wolfSSL_CRYPTO_cts128_encrypt(const unsigned char *in,
unsigned char *out, size_t len, const void *key,
unsigned char *iv, WOLFSSL_CBC128_CB cbc)
{
byte lastBlk[WOLFSSL_CTS128_BLOCK_SZ] = {0};
int lastBlkLen = len % WOLFSSL_CTS128_BLOCK_SZ;
WOLFSSL_ENTER("wolfSSL_CRYPTO_cts128_encrypt");
if (in == NULL || out == NULL || len < WOLFSSL_CTS128_BLOCK_SZ ||
cbc == NULL) {
WOLFSSL_MSG("Bad parameter");
return WOLFSSL_FAILURE;
}
if (lastBlkLen == 0)
lastBlkLen = WOLFSSL_CTS128_BLOCK_SZ;
/* Encrypt data up to last block */
(*cbc)(in, out, len - lastBlkLen, key, iv, 1);
/* Move to last block */
in += len - lastBlkLen;
out += len - lastBlkLen;
/* RFC2040: Pad Pn with zeros at the end to create P of length BB. */
XMEMCPY(lastBlk, in, lastBlkLen);
/* RFC2040: Select the first Ln bytes of En-1 to create Cn */
XMEMCPY(out, out - WOLFSSL_CTS128_BLOCK_SZ, lastBlkLen);
(*cbc)(lastBlk, out - WOLFSSL_CTS128_BLOCK_SZ, WOLFSSL_CTS128_BLOCK_SZ,
key, iv, 1);
return len;
}
size_t wolfSSL_CRYPTO_cts128_decrypt(const unsigned char *in,
unsigned char *out, size_t len, const void *key,
unsigned char *iv, WOLFSSL_CBC128_CB cbc)
{
byte lastBlk[WOLFSSL_CTS128_BLOCK_SZ] = {0};
byte prevBlk[WOLFSSL_CTS128_BLOCK_SZ] = {0};
int lastBlkLen = len % WOLFSSL_CTS128_BLOCK_SZ;
WOLFSSL_ENTER("wolfSSL_CRYPTO_cts128_decrypt");
if (in == NULL || out == NULL || len <= WOLFSSL_CTS128_BLOCK_SZ ||
cbc == NULL) {
WOLFSSL_MSG("Bad parameter");
return WOLFSSL_FAILURE;
}
if (lastBlkLen == 0)
lastBlkLen = WOLFSSL_CTS128_BLOCK_SZ;
/* Decrypt up to last two blocks */
(*cbc)(in, out, len - lastBlkLen - WOLFSSL_CTS128_BLOCK_SZ, key, iv, 0);
/* Move to last two blocks */
in += len - lastBlkLen - WOLFSSL_CTS128_BLOCK_SZ;
out += len - lastBlkLen - WOLFSSL_CTS128_BLOCK_SZ;
/* RFC2040: Decrypt Cn-1 to create Dn.
* Use 0 buffer as IV to do straight decryption.
* This places the Cn-1 block at lastBlk */
(*cbc)(in, prevBlk, WOLFSSL_CTS128_BLOCK_SZ, key, lastBlk, 0);
/* RFC2040: Append the tail (BB minus Ln) bytes of Xn to Cn
* to create En. */
XMEMCPY(prevBlk, in + WOLFSSL_CTS128_BLOCK_SZ, lastBlkLen);
/* Cn and Cn-1 can now be decrypted */
(*cbc)(prevBlk, out, WOLFSSL_CTS128_BLOCK_SZ, key, iv, 0);
(*cbc)(lastBlk, lastBlk, WOLFSSL_CTS128_BLOCK_SZ, key, iv, 0);
XMEMCPY(out + WOLFSSL_CTS128_BLOCK_SZ, lastBlk, lastBlkLen);
return len;
}
#endif /* HAVE_CTS */
#ifndef NO_BIO
int wolfSSL_ASN1_UTCTIME_print(WOLFSSL_BIO* bio, const WOLFSSL_ASN1_UTCTIME* a)
{

View File

@ -313,6 +313,7 @@
#include <wolfssl/openssl/hmac.h>
#include <wolfssl/openssl/objects.h>
#include <wolfssl/openssl/rand.h>
#include <wolfssl/openssl/modes.h>
#ifdef OPENSSL_ALL
#include <wolfssl/openssl/txt_db.h>
#include <wolfssl/openssl/lhash.h>
@ -41975,6 +41976,88 @@ static void test_wolfSSL_AES_cbc_encrypt(void)
#endif
}
static void test_wolfSSL_CRYPTO_cts128(void)
{
#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(OPENSSL_EXTRA) \
&& defined(HAVE_CTS)
byte tmp[64] = {0}; /* Largest vector size */
/* Test vectors taken form RFC3962 Appendix B */
const testVector vects[] = {
{
"\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
"\x20",
"\xc6\x35\x35\x68\xf2\xbf\x8c\xb4\xd8\xa5\x80\x36\x2d\xa7\xff\x7f"
"\x97",
17, 17
},
{
"\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
"\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20",
"\xfc\x00\x78\x3e\x0e\xfd\xb2\xc1\xd4\x45\xd4\xc8\xef\xf7\xed\x22"
"\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5",
31, 31
},
{
"\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
"\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43",
"\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
"\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84",
32, 32
},
{
"\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
"\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43"
"\x68\x69\x63\x6b\x65\x6e\x2c\x20\x70\x6c\x65\x61\x73\x65\x2c",
"\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
"\xb3\xff\xfd\x94\x0c\x16\xa1\x8c\x1b\x55\x49\xd2\xf8\x38\x02\x9e"
"\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5",
47, 47
},
{
"\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
"\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43"
"\x68\x69\x63\x6b\x65\x6e\x2c\x20\x70\x6c\x65\x61\x73\x65\x2c\x20",
"\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
"\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8"
"\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8",
48, 48
},
{
"\x49\x20\x77\x6f\x75\x6c\x64\x20\x6c\x69\x6b\x65\x20\x74\x68\x65"
"\x20\x47\x65\x6e\x65\x72\x61\x6c\x20\x47\x61\x75\x27\x73\x20\x43"
"\x68\x69\x63\x6b\x65\x6e\x2c\x20\x70\x6c\x65\x61\x73\x65\x2c\x20"
"\x61\x6e\x64\x20\x77\x6f\x6e\x74\x6f\x6e\x20\x73\x6f\x75\x70\x2e",
"\x97\x68\x72\x68\xd6\xec\xcc\xc0\xc0\x7b\x25\xe2\x5e\xcf\xe5\x84"
"\x39\x31\x25\x23\xa7\x86\x62\xd5\xbe\x7f\xcb\xcc\x98\xeb\xf5\xa8"
"\x48\x07\xef\xe8\x36\xee\x89\xa5\x26\x73\x0d\xbc\x2f\x7b\xc8\x40"
"\x9d\xad\x8b\xbb\x96\xc4\xcd\xc0\x3b\xc1\x03\xe1\xa1\x94\xbb\xd8",
64, 64
}
};
byte keyBytes[AES_128_KEY_SIZE] = {
0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20,
0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69
};
size_t i;
for (i = 0; i < sizeof(vects)/sizeof(vects[0]); i++) {
AES_KEY encKey;
AES_KEY decKey;
byte iv[AES_IV_SIZE] = {0}; /* All-zero IV for all cases */
AssertIntEQ(AES_set_encrypt_key(keyBytes, AES_128_KEY_SIZE * 8, &encKey), 0);
AssertIntEQ(AES_set_decrypt_key(keyBytes, AES_128_KEY_SIZE * 8, &decKey), 0);
AssertIntEQ(CRYPTO_cts128_encrypt((const unsigned char*)vects[i].input,
tmp, vects[i].inLen, &encKey, iv, (cbc128_f)AES_cbc_encrypt),
vects[i].outLen);
AssertIntEQ(XMEMCMP(tmp, vects[i].output, vects[i].outLen), 0);
XMEMSET(iv, 0, sizeof(iv));
AssertIntEQ(CRYPTO_cts128_decrypt((const unsigned char*)vects[i].output,
tmp, vects[i].outLen, &decKey, iv, (cbc128_f)AES_cbc_encrypt),
vects[i].inLen);
AssertIntEQ(XMEMCMP(tmp, vects[i].input, vects[i].inLen), 0);
}
#endif /* !NO_AES && HAVE_AES_CBC && OPENSSL_EXTRA && HAVE_CTS */
}
#if defined(OPENSSL_ALL)
#if !defined(NO_ASN)
static void test_wolfSSL_ASN1_STRING_to_UTF8(void)
@ -51945,6 +52028,7 @@ void ApiTest(void)
test_wolfSSL_DC_cert();
test_wolfSSL_DES_ncbc();
test_wolfSSL_AES_cbc_encrypt();
test_wolfSSL_CRYPTO_cts128();
test_wolfssl_EVP_aes_gcm_AAD_2_parts();
test_wolfssl_EVP_aes_gcm();
test_wolfSSL_PKEY_up_ref();

View File

@ -30,6 +30,7 @@ nobase_include_HEADERS+= \
wolfssl/openssl/lhash.h \
wolfssl/openssl/md4.h \
wolfssl/openssl/md5.h \
wolfssl/openssl/modes.h \
wolfssl/openssl/ripemd.h \
wolfssl/openssl/obj_mac.h \
wolfssl/openssl/objects.h \

45
wolfssl/openssl/modes.h Normal file
View File

@ -0,0 +1,45 @@
/* modes.h
*
* Copyright (C) 2006-2021 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#ifndef WOLFSSL_OPENSSL_MODES_H
#define WOLFSSL_OPENSSL_MODES_H
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/openssl/ssl.h>
typedef void (*WOLFSSL_CBC128_CB) (const unsigned char *in,
unsigned char *out, size_t len, const void *key,
unsigned char *iv, int enc);
WOLFSSL_API size_t wolfSSL_CRYPTO_cts128_encrypt(const unsigned char *in,
unsigned char *out, size_t len, const void *key,
unsigned char *iv, WOLFSSL_CBC128_CB cbc);
WOLFSSL_API size_t wolfSSL_CRYPTO_cts128_decrypt(const unsigned char *in,
unsigned char *out, size_t len, const void *key,
unsigned char *iv, WOLFSSL_CBC128_CB cbc);
#define WOLFSSL_CTS128_BLOCK_SZ 16
/* Compatibility layer defines */
#define CRYPTO_cts128_encrypt wolfSSL_CRYPTO_cts128_encrypt
#define CRYPTO_cts128_decrypt wolfSSL_CRYPTO_cts128_decrypt
#define cbc128_f WOLFSSL_CBC128_CB
#endif /* WOLFSSL_OPENSSL_MODES_H */