Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/wolfprovider/alg_funcs.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ typedef void (*DFUNC)(void);
#define WP_NAMES_AES_128_WRAP \
"AES-128-WRAP:id-aes128-wrap:AES128-WRAP:2.16.840.1.101.3.4.1.5"

#define WP_NAMES_AES_256_CTS "AES-256-CBC-CTS"
#define WP_NAMES_AES_192_CTS "AES-192-CBC-CTS"
#define WP_NAMES_AES_128_CTS "AES-128-CBC-CTS"

#define WP_NAMES_DES_EDE3_CBC "DES-EDE3-CBC:DES3:1.2.840.113549.3.7"

/* Internal cipher flags. */
Expand Down Expand Up @@ -288,6 +292,10 @@ extern const OSSL_DISPATCH wp_aes256wrap_functions[];
extern const OSSL_DISPATCH wp_aes192wrap_functions[];
extern const OSSL_DISPATCH wp_aes128wrap_functions[];

extern const OSSL_DISPATCH wp_aes256cts_functions[];
extern const OSSL_DISPATCH wp_aes192cts_functions[];
extern const OSSL_DISPATCH wp_aes128cts_functions[];

extern const OSSL_DISPATCH wp_des3cbc_functions[];

/* MAC implementations. */
Expand Down
1 change: 1 addition & 0 deletions include/wolfprovider/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
#endif
#ifndef NO_AES_CBC
#define WP_HAVE_AESCBC
#define WP_HAVE_AESCTS
#endif
#ifndef NO_DES3
#define WP_HAVE_DES3CBC
Expand Down
226 changes: 214 additions & 12 deletions src/wp_aes_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include <wolfprovider/settings.h>
#include <wolfprovider/alg_funcs.h>

#if defined(WP_HAVE_AESCTR) || defined(WP_HAVE_AESCFB)
#if defined(WP_HAVE_AESCTR) || defined(WP_HAVE_AESCFB) || defined(WP_HAVE_AESCTS)

/**
* Data structure for AES ciphers that are streaming.
Expand All @@ -38,7 +38,7 @@ typedef struct wp_AesStreamCtx {
/** wolfSSL AES object. */
Aes aes;

/** Cipher mode - CTR. */
/** Cipher mode - CTR, CFB or CTS. */
int mode;

/** Length of key in bytes. */
Expand All @@ -53,6 +53,11 @@ typedef struct wp_AesStreamCtx {
unsigned char iv[AES_BLOCK_SIZE];
/** Original IV. */
unsigned char oiv[AES_BLOCK_SIZE];

#if defined(WP_HAVE_AESCTS)
/* Only single shot allowed */
unsigned int updated:1;
#endif
} wp_AesStreamCtx;


Expand Down Expand Up @@ -194,6 +199,9 @@ static const OSSL_PARAM* wp_cipher_gettable_ctx_params(wp_AesStreamCtx* ctx,
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_NUM, NULL),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0),
OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_UPDATED_IV, NULL, 0),
#ifdef WP_HAVE_AESCTS
OSSL_PARAM_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE, NULL, 0),
#endif
OSSL_PARAM_END
};
(void)ctx;
Expand All @@ -217,6 +225,9 @@ static const OSSL_PARAM* wp_cipher_settable_ctx_params(wp_AesStreamCtx* ctx,
static const OSSL_PARAM wp_cipher_supported_settable_ctx_params[] = {
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_NUM, NULL),
OSSL_PARAM_uint(OSSL_CIPHER_PARAM_USE_BITS, NULL),
#ifdef WP_HAVE_AESCTS
OSSL_PARAM_utf8_string(OSSL_CIPHER_PARAM_CTS_MODE, NULL, 0),
#endif
OSSL_PARAM_END
};
(void)ctx;
Expand Down Expand Up @@ -270,6 +281,8 @@ static int wp_aes_stream_init(wp_AesStreamCtx *ctx, const unsigned char *key,
const OSSL_PARAM params[], int enc)
{
int ok = 1;
/* Decryption is the same as encryption with CTR mode. */
int dir = AES_ENCRYPTION;

ctx->enc = enc;

Expand All @@ -286,9 +299,13 @@ static int wp_aes_stream_init(wp_AesStreamCtx *ctx, const unsigned char *key,
ok = 0;
}
if (ok) {
/* Decryption is the same as encryption with CTR mode. */
#if defined(WP_HAVE_AESCTS)
if (ctx->mode == EVP_CIPH_CBC_MODE && !enc) {
Comment thread
padelsbach marked this conversation as resolved.
Comment thread
padelsbach marked this conversation as resolved.
dir = AES_DECRYPTION;
}
#endif
int rc = wc_AesSetKey(&ctx->aes, key, (word32)ctx->keyLen, iv,
AES_ENCRYPTION);
dir);
if (rc != 0) {
ok = 0;
}
Expand All @@ -302,6 +319,10 @@ static int wp_aes_stream_init(wp_AesStreamCtx *ctx, const unsigned char *key,
}

if (ok) {
#if defined(WP_HAVE_AESCTS)
/* We only allow one shot, always reset on init */
ctx->updated = 0;
Comment thread
padelsbach marked this conversation as resolved.
#endif
ok = wp_aes_stream_set_ctx_params(ctx, params);
}

Expand Down Expand Up @@ -347,8 +368,121 @@ static int wp_aes_stream_dinit(wp_AesStreamCtx *ctx, const unsigned char *key,
return wp_aes_stream_init(ctx, key, keyLen, iv, ivLen, params, 0);
}

#ifdef WP_HAVE_AESCTS

static int wp_aes_cts_encrypt(wp_AesStreamCtx *ctx, unsigned char *out,
const unsigned char *in, size_t inLen)
{
int ok = 1;
int rc;
int blocks;
byte ctsBlock[AES_BLOCK_SIZE * 2];

/* Since AES-CTS is not a FIPS approved algo, we will never be able to call
* the existing wolfSSL AES_CTS APIs with FIPS, so the implementation is
* effectively copied here from wolfSSL internals. */

blocks = (int)((inLen + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE);
blocks -= 2;
Comment thread
padelsbach marked this conversation as resolved.
XMEMSET(ctsBlock, 0, AES_BLOCK_SIZE * 2);
if (ok && blocks > 0) {
XMEMCPY(&ctx->aes.reg, ctx->iv, ctx->ivLen);
Comment thread
padelsbach marked this conversation as resolved.
rc = wc_AesCbcEncrypt(&ctx->aes, out, in, blocks * AES_BLOCK_SIZE);
if (rc != 0) {
ok = 0;
}
if (ok) {
XMEMCPY(ctx->iv, ctx->aes.reg, ctx->ivLen);
in += blocks * AES_BLOCK_SIZE;
out += blocks * AES_BLOCK_SIZE;
inLen -= blocks * AES_BLOCK_SIZE;
}
}
if (ok) {
XMEMCPY(ctsBlock, in, inLen);
Comment thread
padelsbach marked this conversation as resolved.
rc = wc_AesCbcEncrypt(&ctx->aes, ctsBlock, ctsBlock,
Comment thread
padelsbach marked this conversation as resolved.
AES_BLOCK_SIZE * 2);
if (rc != 0) {
ok = 0;
}
if (ok) {
XMEMCPY(ctx->iv, ctx->aes.reg, ctx->ivLen);
}
}
if (ok) {
XMEMCPY(out, ctsBlock + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
XMEMCPY(out + AES_BLOCK_SIZE, ctsBlock, AES_BLOCK_SIZE);
}

return ok;
}

static int wp_aes_cts_decrypt(wp_AesStreamCtx *ctx, unsigned char *out,
const unsigned char *in, size_t inLen)
{
int ok = 1;
int rc;
int blocks;
byte ctsBlock[AES_BLOCK_SIZE * 2];
byte tmp[AES_BLOCK_SIZE];
word32 partialSz;
word32 padSz;

/* Since AES-CTS is not a FIPS approved algo, we will never be able to call
* the existing wolfSSL AES_CTS APIs with FIPS, so the implementation is
* effectively copied here from wolfSSL internals. */

partialSz = inLen % AES_BLOCK_SIZE;
if (partialSz == 0) {
partialSz = AES_BLOCK_SIZE;
}
padSz = AES_BLOCK_SIZE - partialSz;

blocks = (int)((inLen + (AES_BLOCK_SIZE - 1)) / AES_BLOCK_SIZE);
blocks -= 2;
XMEMSET(ctsBlock, 0, AES_BLOCK_SIZE * 2);
if (ok && blocks > 0) {
XMEMCPY(&ctx->aes.reg, ctx->iv, ctx->ivLen);
rc = wc_AesCbcDecrypt(&ctx->aes, out, in, blocks * AES_BLOCK_SIZE);
Comment thread
douzzer marked this conversation as resolved.
if (rc != 0) {
ok = 0;
}
if (ok) {
XMEMCPY(ctx->iv, ctx->aes.reg, ctx->ivLen);
in += blocks * AES_BLOCK_SIZE;
out += blocks * AES_BLOCK_SIZE;
inLen -= blocks * AES_BLOCK_SIZE;
}
}
if (ok) {
XMEMCPY(ctsBlock, in, inLen);
XMEMCPY(&ctx->aes.reg, ctsBlock + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
rc = wc_AesCbcDecrypt(&ctx->aes, tmp, ctsBlock, AES_BLOCK_SIZE);
Comment thread
padelsbach marked this conversation as resolved.
if (rc != 0) {
ok = 0;
}
}
if (ok) {
XMEMCPY(out + AES_BLOCK_SIZE, tmp, partialSz);
XMEMCPY(ctsBlock + inLen, tmp + partialSz, padSz);
XMEMCPY(&ctx->aes.reg, ctx->iv, AES_BLOCK_SIZE);
rc = wc_AesCbcDecrypt(&ctx->aes, out, ctsBlock + AES_BLOCK_SIZE,
AES_BLOCK_SIZE);
if (rc != 0) {
ok = 0;
}
if (ok) {
XMEMCPY(ctx->iv, ctx->aes.reg, ctx->ivLen);
}
}

return ok;
}

#endif /* ifdef WP_HAVE_AESCTS */

/**
* Encrypt/decrypt using AES-CTR or AES-CFB with wolfSSL.
* Encrypt/decrypt using AES-CTR, AES-CFB or AES-CTS with wolfSSL.
*
* Assumes out has inLen bytes available.
* Assumes whole blocks only.
Expand All @@ -363,17 +497,19 @@ static int wp_aes_stream_dinit(wp_AesStreamCtx *ctx, const unsigned char *key,
static int wp_aes_stream_doit(wp_AesStreamCtx *ctx, unsigned char *out,
const unsigned char *in, size_t inLen)
{
int ok = 0;
int ok = 1;

#ifdef WP_HAVE_AESCTR
if (ctx->mode == EVP_CIPH_CTR_MODE) {
int rc;

XMEMCPY(&ctx->aes.reg, ctx->iv, ctx->ivLen);
rc = wc_AesCtrEncrypt(&ctx->aes, out, in, (word32)inLen);
if (rc == 0) {
if (rc != 0) {
ok = 0;
}
if (ok) {
XMEMCPY(ctx->iv, ctx->aes.reg, ctx->ivLen);
ok = 1;
}
}
else
Expand All @@ -388,9 +524,33 @@ static int wp_aes_stream_doit(wp_AesStreamCtx *ctx, unsigned char *out,
}else {
rc = wc_AesCfbDecrypt(&ctx->aes, out, in, (word32)inLen);
}
if (rc == 0) {
if (rc != 0) {
ok = 0;
}
if (ok) {
XMEMCPY(ctx->iv, ctx->aes.reg, ctx->ivLen);
ok = 1;
}
}
else
#endif
#ifdef WP_HAVE_AESCTS
if (ctx->mode == EVP_CIPH_CBC_MODE) {
if (ctx->updated) {
ok = 0;
}
if (inLen < AES_BLOCK_SIZE) {
ok = 0;
}
if (ok) {
if (ctx->enc) {
ok = wp_aes_cts_encrypt(ctx, out, in, inLen);
}
else {
ok = wp_aes_cts_decrypt(ctx, out, in, inLen);
}
}
if (ok) {
ctx->updated = 1;
}
}
else
Expand Down Expand Up @@ -534,6 +694,14 @@ static int wp_aes_stream_get_ctx_params(wp_AesStreamCtx* ctx,
ok = 0;
}
}
#ifdef WP_HAVE_AESCTS
if (ok && ctx->mode == EVP_CIPH_CBC_MODE) {
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_CTS_MODE);
if ((p != NULL) && (!OSSL_PARAM_set_utf8_string(p, "CS3"))) {
ok = 0;
}
}
#endif

WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
return ok;
Expand Down Expand Up @@ -568,6 +736,25 @@ static int wp_aes_stream_set_ctx_params(wp_AesStreamCtx *ctx,
ok = 0;
}
(void)val;
#ifdef WP_HAVE_AESCTS
if (ok && ctx->mode == EVP_CIPH_CBC_MODE) {
char cts_mode[4];
char *pcts = cts_mode;
const OSSL_PARAM* p = NULL;
XMEMSET(cts_mode, 0, sizeof(cts_mode));

p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_CTS_MODE);
if (p != NULL) {
if (!OSSL_PARAM_get_utf8_string(p, &pcts,
sizeof(cts_mode))) {
ok = 0;
}
if (ok && (XSTRCMP(cts_mode, "CS3") != 0)) {
ok = 0; /* Only CS3 supported */
}
}
}
#endif
}

WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
Expand All @@ -580,7 +767,7 @@ static int wp_aes_stream_set_ctx_params(wp_AesStreamCtx *ctx,
* @param [in, out] ctx AES stream context object.
* @param [in] kBits Number of bits in a valid key.
* @param [in] ivBits Number of bits in a valid IV. 0 indicates no IV.
* @param [in] mode AES stream mode: CTR.
* @param [in] mode AES stream mode: CTR, CFB or CTS.
* @return 1 on success.
* @return 0 on failure.
*/
Expand Down Expand Up @@ -685,5 +872,20 @@ IMPLEMENT_AES_STREAM(cfb, CFB, 192, 128)
IMPLEMENT_AES_STREAM(cfb, CFB, 128, 128)
#endif /* WP_HAVE_AESCFB */

#endif /* WP_HAVE_AESCTR || WP_HAVE_AESCFB */
/*
* AES CTS
*
* Even though AES-CTS is a block cipher, since we will only be supporting a
* single-shot mode it actually behaves more like a stream cipher.
*/
#ifdef WP_HAVE_AESCTS
/** wp_aes256cts_functions */
IMPLEMENT_AES_STREAM(cts, CBC, 256, 128)
Comment thread
SparkiDev marked this conversation as resolved.
/** wp_aes192cts_functions */
IMPLEMENT_AES_STREAM(cts, CBC, 192, 128)
/** wp_aes128cts_functions */
IMPLEMENT_AES_STREAM(cts, CBC, 128, 128)
#endif /* WP_HAVE_AESCTS */

#endif /* WP_HAVE_AESCTR || WP_HAVE_AESCFB || WP_HAVE_AESCTS */

10 changes: 10 additions & 0 deletions src/wp_wolfprov.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,16 @@ static const OSSL_ALGORITHM wolfprov_ciphers[] = {
"" },
#endif

#ifdef WP_HAVE_AESCTS
/* AES-CTS */
{ WP_NAMES_AES_256_CTS, WOLFPROV_PROPERTIES, wp_aes256cts_functions,
"" },
{ WP_NAMES_AES_192_CTS, WOLFPROV_PROPERTIES, wp_aes192cts_functions,
"" },
{ WP_NAMES_AES_128_CTS, WOLFPROV_PROPERTIES, wp_aes128cts_functions,
"" },
#endif

#ifdef HAVE_AES_KEYWRAP
/* AES Kwy Wrap - unpadded */
{ WP_NAMES_AES_256_WRAP, WOLFPROV_PROPERTIES, wp_aes256wrap_functions,
Expand Down
Loading
Loading