From 6ef6013459e33623eff8d008e2db70bacb81e060 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Wed, 18 Dec 2024 13:40:25 -0800 Subject: [PATCH] Initial implementation of DES3 for wolfprovider --- include/wolfprovider/alg_funcs.h | 4 + include/wolfprovider/settings.h | 3 + src/include.am | 1 + src/wp_des.c | 871 +++++++++++++++++++++++++++++++ src/wp_wolfprov.c | 5 + 5 files changed, 884 insertions(+) create mode 100644 src/wp_des.c diff --git a/include/wolfprovider/alg_funcs.h b/include/wolfprovider/alg_funcs.h index f05f732..2e3978a 100644 --- a/include/wolfprovider/alg_funcs.h +++ b/include/wolfprovider/alg_funcs.h @@ -120,6 +120,8 @@ 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_DES_EDE3_CBC "DES-EDE3-CBC:DES3:1.2.840.113549.3.7" + /* Internal cipher flags. */ #define WP_CIPHER_FLAG_AEAD 0x0001 #define WP_CIPHER_FLAG_CUSTOM_IV 0x0002 @@ -277,6 +279,8 @@ 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_des3cbc_functions[]; + /* MAC implementations. */ extern const OSSL_DISPATCH wp_hmac_functions[]; extern const OSSL_DISPATCH wp_cmac_functions[]; diff --git a/include/wolfprovider/settings.h b/include/wolfprovider/settings.h index d90ea50..79bd6c9 100644 --- a/include/wolfprovider/settings.h +++ b/include/wolfprovider/settings.h @@ -82,6 +82,9 @@ #ifndef NO_AES_CBC #define WP_HAVE_AESCBC #endif +#ifndef NO_DES3 + #define WP_HAVE_DES3 +#endif #ifdef WOLFSSL_AES_COUNTER #define WP_HAVE_AESCTR #endif diff --git a/src/include.am b/src/include.am index 03b86c4..e472901 100644 --- a/src/include.am +++ b/src/include.am @@ -10,6 +10,7 @@ libwolfprov_la_SOURCES += src/wp_aes_block.c libwolfprov_la_SOURCES += src/wp_aes_stream.c libwolfprov_la_SOURCES += src/wp_aes_aead.c libwolfprov_la_SOURCES += src/wp_aes_wrap.c +libwolfprov_la_SOURCES += src/wp_des.c libwolfprov_la_SOURCES += src/wp_hmac.c libwolfprov_la_SOURCES += src/wp_cmac.c libwolfprov_la_SOURCES += src/wp_gmac.c diff --git a/src/wp_des.c b/src/wp_des.c new file mode 100644 index 0000000..6088219 --- /dev/null +++ b/src/wp_des.c @@ -0,0 +1,871 @@ +/* wp_des.c + * + * Copyright (C) 2006-2024 wolfSSL Inc. + * + * This file is part of wolfProvider. + * + * wolfProvider 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 3 of the License, or + * (at your option) any later version. + * + * wolfProvider 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 wolfProvider. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#if defined(WP_HAVE_DES3) + +/** + * Data structure for DES3 ciphers that are block based. + */ +typedef struct wp_Des3BlockCtx { + /** wolfSSL DES object. */ + Des3 des3; + + /** Cipher mode - CBC or ECB. */ + int mode; + + unsigned int tls_version; + + /** Length of key in bytes. */ + size_t keyLen; + /** Length of IV in bytes */ + size_t ivLen; + + /** Operation being performed is encryption. */ + unsigned int enc:1; + /** Pad data to complete the last block. */ + unsigned int pad:1; + /** IV has been set. */ + unsigned int ivSet:1; + + /** Number of cached bytes. */ + size_t bufSz; + /** Cached bytes that didn't fill a block. */ + unsigned char buf[DES_BLOCK_SIZE]; + /** Current IV. */ + unsigned char iv[DES_BLOCK_SIZE]; + /** Original IV. */ + unsigned char oiv[DES_BLOCK_SIZE]; +} wp_Des3BlockCtx; + + +/* Prototype for initialization to call. */ +static int wp_des3_block_set_ctx_params(wp_Des3BlockCtx *ctx, + const OSSL_PARAM params[]); + + +/** + * Free the DES3 block context object. + * + * @param [in, out] ctx DES3 block context object. + */ +static void wp_des3_block_freectx(wp_Des3BlockCtx *ctx) +{ + wc_Des3Free(&ctx->des3); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +/** + * Duplicate the DES3 block context object. + * + * @param [in] src DES3 block context object to copy. + * @return NULL on failure. + * @return DES3 block context object. + */ +static void *wp_des3_block_dupctx(wp_Des3BlockCtx *src) +{ + wp_Des3BlockCtx *dst = NULL; + + if (wolfssl_prov_is_running()) { + dst = OPENSSL_malloc(sizeof(*dst)); + } + if (dst != NULL) { + /* TODO: copying des3 may not work if it has pointers in it. */ + XMEMCPY(dst, src, sizeof(*src)); + } + + return dst; +} + +/** + * Returns the parameters that can be retrieved. + * + * @param [in] provCtx wolfProvider context object. Unused. + * @return Array of parameters. + */ +static const OSSL_PARAM *wp_cipher_gettable_params( + WOLFPROV_CTX *provCtx) +{ + /** + * Parameters able to be retrieved for a cipher. + */ + static const OSSL_PARAM cipher_supported_gettable_params[] = { + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_MODE, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_END + }; + (void)provCtx; + return cipher_supported_gettable_params; +} + +/** + * Get the values from the DES3 block context for the parameters. + * + * @param [in, out] params Array of parameters to retrieve. + * @param [in] mode DES3 cipher mode. + * @param [in] kBits Number of bits in key. + * @param [in] ivBits Number of bits in IV. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_get_params(OSSL_PARAM params[], unsigned int mode, + size_t kBits, size_t ivBits) +{ + int ok = 1; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_MODE); + if ((p != NULL) && (!OSSL_PARAM_set_uint(p, mode))) { + ok = 0; + } + if (ok) { + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if ((p != NULL) && (!OSSL_PARAM_set_size_t(p, kBits / 8))) { + ok = 0; + } + } + if (ok) { + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_BLOCK_SIZE); + if ((p != NULL) && (!OSSL_PARAM_set_size_t(p, DES_BLOCK_SIZE))) { + ok = 0; + } + } + if (ok) { + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if ((p != NULL) && (!OSSL_PARAM_set_size_t(p, ivBits / 8))) { + ok = 0; + } + } + + WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} + +/** + * Returns the parameters of a cipher context that can be retrieved. + * + * @param [in] ctx DES3 block context object. Unused. + * @param [in] provCtx wolfProvider context object. Unused. + * @return Array of parameters. + */ +static const OSSL_PARAM* wp_cipher_gettable_ctx_params(wp_Des3BlockCtx* ctx, + WOLFPROV_CTX* provCtx) +{ + /** + * Parameters able to be retrieved for a cipher context. + */ + static const OSSL_PARAM wp_cipher_supported_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_PADDING, NULL), + 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), + OSSL_PARAM_END + }; + (void)ctx; + (void)provCtx; + return wp_cipher_supported_gettable_ctx_params; +} + +/** + * Returns the parameters of a cipher context that can be set. + * + * @param [in] ctx DES3 block context object. Unused. + * @param [in] provCtx wolfProvider context object. Unused. + * @return Array of parameters. + */ +static const OSSL_PARAM* wp_cipher_settable_ctx_params(wp_Des3BlockCtx* ctx, + WOLFPROV_CTX *provCtx) +{ + /* + * Parameters able to be set into a cipher context. + */ + static const OSSL_PARAM wp_cipher_supported_settable_ctx_params[] = { + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_PADDING, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_NUM, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_USE_BITS, NULL), + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_TLS_VERSION, NULL), + OSSL_PARAM_END + }; + (void)ctx; + (void)provCtx; + return wp_cipher_supported_settable_ctx_params; +} + +/** + * Set the IV against the DES3 block context object. + * + * @param [in, out] ctx DES3 block context object. + * @param [in] iv IV data. + * @param [in] ivlen Length of IV data in bytes. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_init_iv(wp_Des3BlockCtx *ctx, const unsigned char *iv, + size_t ivLen) +{ + int ok = 1; + + if (ivLen != ctx->ivLen) { + ok = 0; + } + if (ok) { + int rc; + + ctx->ivSet = 1; + XMEMCPY(ctx->iv, iv, ivLen); + XMEMCPY(ctx->oiv, iv, ivLen); + rc = wc_Des3_SetIV(&ctx->des3, iv); + if (rc != 0) { + ok = 0; + } + } + + WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} + +/** + * Initialization of an DES3 block cipher. + * + * Internal. Handles both encrypt and decrypt. + * + * @param [in, out] ctx DES3 block context object. + * @param [in] key Private key data. May be NULL. + * @param [in] keyLen Length of private key in bytes. + * @param [in] iv IV data. May be NULL. + * @param [in] ivLen Length of IV in bytes. + * @param [in] params Parameters to set against DES3 block context object. + * @param [in] enc Initializing for encryption. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_init(wp_Des3BlockCtx *ctx, const unsigned char *key, + size_t keyLen, const unsigned char *iv, size_t ivLen, + const OSSL_PARAM params[], int enc) +{ + int ok = 1; + + ctx->bufSz = 0; + ctx->enc = enc; + + if (!wolfssl_prov_is_running()) { + ok = 0; + } + + if (ok && (iv != NULL) && (ctx->mode != EVP_CIPH_ECB_MODE) && + (!wp_des3_init_iv(ctx, iv, ivLen))) { + ok = 0; + } + if (ok && (iv == NULL) && ctx->ivSet && (ctx->mode == EVP_CIPH_CBC_MODE)) { + XMEMCPY(ctx->iv, ctx->oiv, ctx->ivLen); + } + + if (ok && (key != NULL)) { + if (keyLen != ctx->keyLen) { + ok = 0; + } + if (ok) { + int rc = wc_Des3_SetKey(&ctx->des3, key, iv, + enc ? DES_ENCRYPTION : DES_DECRYPTION); + if (rc != 0) { + ok = 0; + } + } + } + + if (ok) { + ok = wp_des3_block_set_ctx_params(ctx, params); + } + + WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} + +/** + * Initialization of an DES3 block cipher for encryption. + * + * @param [in, out] ctx DES3 block context object. + * @param [in] key Private key data. May be NULL. + * @param [in] keyLen Length of private key in bytes. + * @param [in] iv IV data. May be NULL. + * @param [in] ivLen Length of IV in bytes. + * @param [in] params Parameters to set against DES3 block context object. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_einit(wp_Des3BlockCtx *ctx, const unsigned char *key, + size_t keyLen, const unsigned char *iv, size_t ivLen, + const OSSL_PARAM params[]) +{ + return wp_des3_block_init(ctx, key, keyLen, iv, ivLen, params, 1); +} + +/** + * Initialization of an DES3 block cipher for decryption. + * + * @param [in, out] ctx DES3 block context object. + * @param [in] key Private key data. May be NULL. + * @param [in] keyLen Length of private key in bytes. + * @param [in] iv IV data. May be NULL. + * @param [in] ivLen Length of IV in bytes. + * @param [in] params Parameters to set against DES3 block context object. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_dinit(wp_Des3BlockCtx *ctx, const unsigned char *key, + size_t keyLen, const unsigned char *iv, size_t ivLen, + const OSSL_PARAM params[]) +{ + return wp_des3_block_init(ctx, key, keyLen, iv, ivLen, params, 0); +} + +/** + * Encrypt/decrypt using DES3-CBC with wolfSSL. + * + * Assumes out has inLen bytes available. + * Assumes whole blocks only. + * + * @param [in] ctx DES3 block context object. + * @param [out] out Buffer to hold encrypted/decrypted result. + * @param [in] in Data to encrypt/decrypt. + * @param [in] inLen Length of data to encrypt/decrypt in bytes. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_doit(wp_Des3BlockCtx *ctx, unsigned char *out, + const unsigned char *in, size_t inLen) +{ + int rc; + + if (ctx->mode == EVP_CIPH_CBC_MODE) { + if (ctx->enc) { + rc = wc_Des3_CbcEncrypt(&ctx->des3, out, in, (word32)inLen); + } + else { + rc = wc_Des3_CbcDecrypt(&ctx->des3, out, in, (word32)inLen); + } + XMEMCPY(ctx->iv, ctx->des3.reg, ctx->ivLen); + } + else + { + rc = -1; + } + + return rc == 0; +} + +/** + * Update encryption/decryption with more data. + * + * @param [in] ctx DES3 block context object. + * @param [out] out Buffer to hold encrypted/decrypted result. + * @param [out] outLen Length of encrypted/decrypted data in bytes. + * @param [in] outSize Size of output buffer in bytes. + * @param [in] in Data to encrypt/decrypt. + * @param [in] inLen Length of data in bytes. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_update(wp_Des3BlockCtx *ctx, unsigned char *out, + size_t *outLen, size_t outSize, const unsigned char *in, size_t inLen) +{ + int ok = 1; + size_t oLen = 0; + size_t nextBlocks; + + if ((ctx->tls_version > 0) && (ctx->enc)) { + int i; + unsigned char off = inLen % DES_BLOCK_SIZE; + unsigned char pad = DES_BLOCK_SIZE - off - 1; + for (i = off; i < DES_BLOCK_SIZE; i++) { + out[inLen - off + i] = pad; + } + inLen += pad + 1; + } + if (ctx->bufSz != 0) { + size_t len = DES_BLOCK_SIZE - ctx->bufSz; + + if (inLen < len) { + len = inLen; + } + XMEMCPY(ctx->buf + ctx->bufSz, in, len); + in += len; + inLen -= len; + ctx->bufSz += len; + } + nextBlocks = inLen & (~(DES_BLOCK_SIZE - 1)); + + if ((!ctx->enc) && inLen == 0 && ctx->pad) { + /* Keep last block for final call. */ + } + else if (ctx->bufSz == DES_BLOCK_SIZE) { + if (outSize < DES_BLOCK_SIZE) { + ok = 0; + } + if (ok && (!wp_des3_block_doit(ctx, out, ctx->buf, DES_BLOCK_SIZE))) { + ok = 0; + } + if (ok) { + ctx->bufSz = 0; + oLen = DES_BLOCK_SIZE; + out += DES_BLOCK_SIZE; + } + } + if (ok && (nextBlocks > 0)) { + if ((!ctx->enc) && ctx->pad && (nextBlocks == inLen) && + (ctx->tls_version == 0)) { + nextBlocks -= DES_BLOCK_SIZE; + } + if (outSize < oLen) { + ok = 0; + } + } + if (ok && (nextBlocks > 0)) { + if (!wp_des3_block_doit(ctx, out, in, nextBlocks)) { + ok = 0; + } + if (ok) { + in += nextBlocks; + inLen -= nextBlocks; + oLen += nextBlocks; + } + } + if (ok) { + if (inLen != 0) { + XMEMCPY(ctx->buf, in, inLen); + ctx->bufSz = inLen; + } + *outLen = oLen; + } + if (ok && (ctx->tls_version > 0) && (!ctx->enc)) { + unsigned char pad = out[oLen-1]; + int padStart = DES_BLOCK_SIZE - pad - 1; + unsigned char invalid = (pad < DES_BLOCK_SIZE) - 1; + int i; + + for (i = DES_BLOCK_SIZE - 1; i >= 0; i--) { + byte check = wp_ct_int_mask_gte(i, padStart); + check &= wp_ct_byte_mask_ne(out[oLen - DES_BLOCK_SIZE + i], pad); + invalid |= check; + } + *outLen = oLen - pad - 1 - DES_BLOCK_SIZE; + ok = invalid == 0; + } + + WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} + +/** + * Finalize DES3 block encryption. + * + * @param [in] ctx DES3 block context object. + * @param [out] out Buffer to hold encrypted data. + * @param [out] outLen Length of data encrypted in bytes. + * @param [in] outSize Size of buffer. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_final_enc(wp_Des3BlockCtx* ctx, unsigned char *out, + size_t *outLen, size_t outSize) +{ + int ok = 1; + size_t oLen = 0; + + if (ctx->pad) { + size_t i; + unsigned char pad = (unsigned char)(DES_BLOCK_SIZE - ctx->bufSz); + + for (i = ctx->bufSz; i < DES_BLOCK_SIZE; i++) { + ctx->buf[i] = pad; + } + ctx->bufSz = DES_BLOCK_SIZE; + } + else if (ctx->bufSz != 0) { + ok = 0; + } + + if (ok && (ctx->bufSz == DES_BLOCK_SIZE)) { + if (outSize < DES_BLOCK_SIZE) { + ok = 0; + } + if (ok && !wp_des3_block_doit(ctx, out, ctx->buf, DES_BLOCK_SIZE)) { + ok = 0; + } + if (ok) { + oLen = DES_BLOCK_SIZE; + } + } + + if (ok) { + ctx->bufSz = 0; + *outLen = oLen; + } + WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} + +/** + * Finalize DES3 block decryption. + * + * @param [in] ctx DES3 block context object. + * @param [out] out Buffer to hold decrypted data. + * @param [out] outLen Length of data decrypted in bytes. + * @param [in] outSize Size of buffer. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_final_dec(wp_Des3BlockCtx* ctx, unsigned char *out, + size_t *outLen, size_t outSize) +{ + int ok = 1; + + if (ctx->pad) { + if (ctx->bufSz != DES_BLOCK_SIZE) { + ok = 0; + } + } + else if (ctx->bufSz != 0) { + ok = 0; + } + + if (ok && (ctx->bufSz > 0) && + (!wp_des3_block_doit(ctx, ctx->buf, ctx->buf, DES_BLOCK_SIZE))) { + ok = 0; + } + + if (ok && ctx->pad) { + unsigned char pad; + + pad = ctx->buf[DES_BLOCK_SIZE - 1]; + if ((pad == 0) || (pad > DES_BLOCK_SIZE)) { + ok = 0; + } + if (ok) { + unsigned char len = DES_BLOCK_SIZE; + unsigned char i; + + for (i = 0; i < pad; i++) { + if (ctx->buf[--len] != pad) { + return 0; + } + } + ctx->bufSz = len; + } + } + + if (ok && (outSize < ctx->bufSz)) { + ok = 0; + } + if (ok && (ctx->bufSz > 0)) { + XMEMCPY(out, ctx->buf, ctx->bufSz); + XMEMSET(ctx->buf, 0, DES_BLOCK_SIZE); + *outLen = ctx->bufSz; + ctx->bufSz = 0; + } + else { + *outLen = 0; + } + + WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} + +/** + * Finalize DES3 block encryption/decryption. + * + * @param [in] ctx DES3 block context object. + * @param [out] out Buffer to hold encrypted/decrypted data. + * @param [out] outLen Length of data encrypted/decrypted in bytes. + * @param [in] outSize Size of buffer. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_final(wp_Des3BlockCtx* ctx, unsigned char *out, + size_t *outLen, size_t outSize) +{ + int ok = 1; + + if (!wolfssl_prov_is_running()) { + ok = 0; + } + + if (ok) { + if (ctx->enc) { + ok = wp_des3_block_final_enc(ctx, out, outLen, outSize); + } + else { + ok = wp_des3_block_final_dec(ctx, out, outLen, outSize); + } + } + + WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} + +/** + * One-shot encryption/decryption operation. + * + * @param [in] ctx DES3 block context object. + * @param [out] out Buffer to hold encrypted/decrypted result. + * @param [out] outLen Length of encrypted/decrypted data in bytes. + * @param [in] outSize Size of output buffer in bytes. + * @param [in] in Data to encrypt/decrypt. + * @param [in] inLen Length of data in bytes. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_cipher(wp_Des3BlockCtx* ctx, unsigned char* out, + size_t* outLen, size_t outSize, const unsigned char* in, size_t inLen) +{ + int ok = 1; + + if (!wolfssl_prov_is_running()) { + ok = 0; + } + if (ok && (outSize < inLen)) { + ok = 0; + } + if (ok && !wp_des3_block_doit(ctx, out, in, inLen)) { + ok = 0; + } + if (ok) { + *outLen = inLen; + } + + WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} + +/** + * Put values from the DES3 block context object into parameters objects. + * + * @param [in] ctx DES3 block context object. + * @param [in, out] params Array of parameters objects. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_get_ctx_params(wp_Des3BlockCtx* ctx, OSSL_PARAM params[]) +{ + int ok = 1; + OSSL_PARAM* p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if ((p != NULL) && (!OSSL_PARAM_set_size_t(p, ctx->ivLen))) { + ok = 0; + } + if (ok) { + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_PADDING); + if ((p != NULL) && (!OSSL_PARAM_set_uint(p, ctx->pad))) { + ok = 0; + } + } + if (ok) { + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); + if ((p != NULL) && + (!OSSL_PARAM_set_octet_ptr(p, &ctx->oiv, ctx->ivLen)) && + (!OSSL_PARAM_set_octet_string(p, &ctx->oiv, ctx->ivLen))) { + ok = 0; + } + } + if (ok) { + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV); + if ((p != NULL) && + (!OSSL_PARAM_set_octet_ptr(p, &ctx->iv, ctx->ivLen)) && + (!OSSL_PARAM_set_octet_string(p, &ctx->iv, ctx->ivLen))) { + ok = 0; + } + } + if (ok) { + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_NUM); + if ((p != NULL) && (!OSSL_PARAM_set_uint(p, 0))) { + ok = 0; + } + } + if (ok) { + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if ((p != NULL) && (!OSSL_PARAM_set_size_t(p, ctx->keyLen))) { + ok = 0; + } + } + + WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} + +/** + * Sets the parameters to use into DES3 block context object. + * + * @param [in, out] ctx DES3 block context object. + * @param [in] params Array of parameter objects. + * @return 1 on success. + * @return 0 on failure. + */ +static int wp_des3_block_set_ctx_params(wp_Des3BlockCtx *ctx, + const OSSL_PARAM params[]) +{ + int ok = 1; + + if (params != NULL) { + unsigned int val; + int set; + + if (!wp_params_get_uint(params, OSSL_CIPHER_PARAM_PADDING, &val, + &set)) { + ok = 0; + } + if (set) { + ctx->pad = val != 0; + } + /* TODO: can these be left out? */ + if (ok && (!wp_params_get_uint(params, OSSL_CIPHER_PARAM_USE_BITS, + &val, &set))) { + ok = 0; + } + (void)val; + (void)set; + if (ok && (!wp_params_get_uint(params, OSSL_CIPHER_PARAM_NUM, + &val, &set))) { + ok = 0; + } + (void)val; + (void)set; + if (ok && (!wp_params_get_uint(params, OSSL_CIPHER_PARAM_TLS_VERSION, + &ctx->tls_version, NULL))) { + ok = 0; + } + } + + WOLFPROV_LEAVE(WP_LOG_CIPHER, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok); + return ok; +} + +/** + * Initialize the DES3 block context object. + * + * @param [in, out] ctx DES3 block 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. + * @parma [in] mode DES3 block mode: ECB or CBC. + * @return 1 on success. + * @return 0 on failure. + */ +static void wp_des3_block_init_ctx(wp_Des3BlockCtx* ctx, size_t kBits, + size_t ivBits, unsigned int mode) +{ + ctx->pad = 1; + ctx->keyLen = ((kBits) / 8); + ctx->ivLen = ((ivBits) / 8); + ctx->mode = mode; +} + +/** Implement the get params API for a block cipher. */ +#define IMPLEMENT_DES3_BLOCK_GET_PARAMS(lcmode, UCMODE, kBits, ivBits) \ +/** \ + * Get the values from the DES3 block context for the parameters. \ + * \ + * @param [in, out] params Array of parameters to retrieve. \ + * @return 1 on success. \ + * @return 0 on failure. \ + */ \ +static int wp_des3_##lcmode##_get_params(OSSL_PARAM params[]) \ +{ \ + return wp_des3_block_get_params(params, EVP_CIPH_##UCMODE##_MODE, kBits, \ + ivBits); \ +} + +/** Implement the new context API for a block cipher. */ +#define IMPLEMENT_DES3_BLOCK_NEWCTX(lcmode, UCMODE, kBits, ivBits) \ +/** \ + * Create a new block cipher context object. \ + * \ + * @param [in] provCtx Provider context object. \ + * @return NULL on failure. \ + * @return AEAD context object on success. \ + */ \ +static wp_Des3BlockCtx* wp_des3_block_##lcmode##_newctx( \ + WOLFPROV_CTX *provCtx) \ +{ \ + wp_Des3BlockCtx *ctx = NULL; \ + (void)provCtx; \ + if (wolfssl_prov_is_running()) { \ + ctx = OPENSSL_zalloc(sizeof(*ctx)); \ + } \ + if (ctx != NULL) { \ + wp_des3_block_init_ctx(ctx, kBits, ivBits, EVP_CIPH_##UCMODE##_MODE); \ + } \ + return ctx; \ +} + +/** Implement the dispatch table for a block cipher. */ +#define IMPLEMENT_DES3_BLOCK_DISPATCH(mode, kBits, ivBits) \ +const OSSL_DISPATCH wp_des3##mode##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, \ + (DFUNC)wp_des3_block_##mode##_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (DFUNC)wp_des3_block_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (DFUNC)wp_des3_block_dupctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (DFUNC)wp_des3_block_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (DFUNC)wp_des3_block_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (DFUNC)wp_des3_block_update }, \ + { OSSL_FUNC_CIPHER_FINAL, (DFUNC)wp_des3_block_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (DFUNC)wp_des3_block_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (DFUNC)wp_des3_##mode##_get_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, (DFUNC)wp_des3_block_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, (DFUNC)wp_des3_block_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, (DFUNC)wp_cipher_gettable_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (DFUNC)wp_cipher_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (DFUNC)wp_cipher_settable_ctx_params }, \ + { 0, NULL } \ +}; + +/** Implements the functions calling base functions for a block cipher. */ +#define IMPLEMENT_DES3_BLOCK(lcmode, UCMODE, kBits, ivBits) \ +IMPLEMENT_DES3_BLOCK_GET_PARAMS(lcmode, UCMODE, kBits, ivBits) \ +IMPLEMENT_DES3_BLOCK_NEWCTX(lcmode, UCMODE, kBits, ivBits) \ +IMPLEMENT_DES3_BLOCK_DISPATCH(lcmode, kBits, ivBits) + +/* + * DES3 CBC + */ + +/** wp_des3cbc_functions_functions */ +IMPLEMENT_DES3_BLOCK(cbc, CBC, 192, 64) + + +#endif /* WP_HAVE_AESCBC || WP_HAVE_AESECB */ + diff --git a/src/wp_wolfprov.c b/src/wp_wolfprov.c index 4d5abfb..e6e34ea 100644 --- a/src/wp_wolfprov.c +++ b/src/wp_wolfprov.c @@ -482,6 +482,11 @@ static const OSSL_ALGORITHM wolfprov_ciphers[] = { "" }, #endif +#ifdef WP_HAVE_DES3 + { WP_NAMES_DES_EDE3_CBC, WOLFPROV_PROPERTIES, wp_des3cbc_functions, + "" }, +#endif + { NULL, NULL, NULL, NULL } };