Skip to content
Open
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
59 changes: 49 additions & 10 deletions doc/dox_comments/header_files/wc_encrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,11 +259,20 @@ int wc_AesCbcEncryptWithKey(byte* out, const byte* in, word32 inSz,
/*!
\ingroup Crypto
\brief This function decrypts an encrypted key buffer using the
provided password. It supports various encryption algorithms
including DES, 3DES, and AES. The encryption information is
provided password. It supports encryption algorithms
DES, 3DES, and AES. The encryption information is
provided in the EncryptedInfo structure.

\return Length of decrypted key on success
\return 0 on success
\return BAD_FUNC_ARG if der is NULL
\return BAD_FUNC_ARG if password is NULL
\return BAD_FUNC_ARG if info is NULL
\return BAD_FUNC_ARG if info->keySz is 0
\return BAD_FUNC_ARG if info->keySz > WC_MAX_SYM_KEY_SIZE
\return ALGO_ID_E if info->cipherType is not one of the cipher types
this function handles
\return NOT_COMPILED_IN if info->cipherType is a cipher type this
function handles, but support for it was disabled in this build
\return Negative value on error

\param info pointer to EncryptedInfo structure containing encryption
Expand All @@ -277,13 +286,24 @@ int wc_AesCbcEncryptWithKey(byte* out, const byte* in, word32 inSz,
_Example_
\code
EncryptedInfo info;
byte encryptedKey[]; // encrypted key data
byte encryptedKey[32]; // encrypted key data, decrypted in place
byte password[] = "mypassword";

XMEMSET(&info, 0, sizeof(info));
info.cipherType = WC_CIPHER_AES_CBC;
info.keySz = 16; // size of the key derived from the password

// info.iv holds the IV as hex characters, the way it appears in a PEM
// DEK-Info header. It is Base16-decoded in place, and must decode to
// at least PKCS5_SALT_SZ bytes. The decoded bytes are used both as the
// key derivation salt and as the cipher IV.
XMEMCPY(info.iv, "0123456789ABCDEF0123456789ABCDEF", 32);
info.ivSz = 32; // length of the hex string, not the decoded IV

int ret = wc_BufferKeyDecrypt(&info, encryptedKey,
sizeof(encryptedKey), password,
sizeof(password)-1, WC_SHA256);
if (ret < 0) {
if (ret != 0) {
// decryption error
}
\endcode
Expand All @@ -297,11 +317,21 @@ int wc_BufferKeyDecrypt(struct EncryptedInfo* info, byte* der,
/*!
\ingroup Crypto
\brief This function encrypts a key buffer using the provided
password. It supports various encryption algorithms including DES,
password. It supports encryption algorithms DES,
3DES, and AES. The encryption information is provided in the
EncryptedInfo structure.

\return Length of encrypted key on success
\return 0 on success
\return BAD_FUNC_ARG if der is NULL
\return BAD_FUNC_ARG if password is NULL
\return BAD_FUNC_ARG if info is NULL
\return BAD_FUNC_ARG if info->keySz is 0
\return BAD_FUNC_ARG if info->keySz > WC_MAX_SYM_KEY_SIZE
\return BAD_FUNC_ARG if info->ivSz < PKCS5_SALT_SZ
\return ALGO_ID_E if info->cipherType is not one of the cipher types
this function handles
\return NOT_COMPILED_IN if info->cipherType is a cipher type this
function handles, but support for it was disabled in this build
\return Negative value on error

\param info pointer to EncryptedInfo structure containing encryption
Expand All @@ -315,13 +345,22 @@ int wc_BufferKeyDecrypt(struct EncryptedInfo* info, byte* der,
_Example_
\code
EncryptedInfo info;
byte key[]; // key data to encrypt
byte key[32]; // key data to encrypt, encrypted in place
byte password[] = "mypassword";

info.algo = AES256CBCb;
XMEMSET(&info, 0, sizeof(info));
info.cipherType = WC_CIPHER_AES_CBC;
info.keySz = 16; // size of the key derived from the password
info.ivSz = 16; // must be at least PKCS5_SALT_SZ

// Unlike wc_BufferKeyDecrypt, info.iv holds raw bytes here. Fill it
// with info.ivSz random bytes; the first PKCS5_SALT_SZ of them are used
// as the key derivation salt, and the buffer is also used as the
// cipher IV.

int ret = wc_BufferKeyEncrypt(&info, key, sizeof(key), password,
sizeof(password)-1, WC_SHA256);
if (ret < 0) {
if (ret != 0) {
// encryption error
}
\endcode
Expand Down
90 changes: 90 additions & 0 deletions tests/api/test_wc_encrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,11 @@ int test_wc_BufferKeyEncryptDecryptDecisionCoverage(void)
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* info->keySz == 0 */
info.keySz = 0;
ExpectIntEQ(wc_BufferKeyEncrypt(&info, der, (word32)sizeof(der),
pw, (int)sizeof(pw), WC_HASH_TYPE_SHA),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
/* info->keySz > WC_MAX_SYM_KEY_SIZE */
info.keySz = 128;
ExpectIntEQ(wc_BufferKeyEncrypt(&info, der, (word32)sizeof(der),
pw, (int)sizeof(pw), WC_HASH_TYPE_SHA),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
Expand All @@ -272,6 +277,10 @@ int test_wc_BufferKeyEncryptDecryptDecisionCoverage(void)
pw, (int)sizeof(pw), WC_HASH_TYPE_SHA),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
info.keySz = 0;
ExpectIntEQ(wc_BufferKeyDecrypt(&info, der, (word32)sizeof(der),
pw, (int)sizeof(pw), WC_HASH_TYPE_SHA),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
info.keySz = 128;
ExpectIntEQ(wc_BufferKeyDecrypt(&info, der, (word32)sizeof(der),
pw, (int)sizeof(pw), WC_HASH_TYPE_SHA),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
Expand Down Expand Up @@ -311,6 +320,28 @@ int test_wc_BufferKeyEncryptDecryptDecisionCoverage(void)
ExpectIntEQ(wc_BufferKeyEncrypt(&info, der, 24,
pw, (int)sizeof(pw), WC_HASH_TYPE_SHA), 0);
}
#else
{
XMEMSET(&info, 0, sizeof(info));
info.cipherType = WC_CIPHER_DES3;
info.keySz = 16;
info.ivSz = PKCS5_SALT_SZ;
XMEMSET(info.iv, 0x25, PKCS5_SALT_SZ);
XMEMSET(der, 0x33, 24);
ExpectIntEQ(wc_BufferKeyEncrypt(&info, der, 16,
pw, (int)sizeof(pw), WC_HASH_TYPE_SHA),
WC_NO_ERR_TRACE(NOT_COMPILED_IN));

XMEMSET(&info, 0, sizeof(info));
info.cipherType = WC_CIPHER_DES;
info.keySz = 8;
info.ivSz = PKCS5_SALT_SZ;
XMEMSET(info.iv, 0x26, PKCS5_SALT_SZ);
XMEMSET(der, 0x33, 24);
ExpectIntEQ(wc_BufferKeyEncrypt(&info, der, 24,
pw, (int)sizeof(pw), WC_HASH_TYPE_SHA),
WC_NO_ERR_TRACE(NOT_COMPILED_IN));
}
#endif

/* ---- decrypt dispatch: iv is hex (Base16-decoded to the PBKDF salt) ---- */
Expand Down Expand Up @@ -342,7 +373,66 @@ int test_wc_BufferKeyEncryptDecryptDecisionCoverage(void)
WC_NO_ERR_TRACE(BUFFER_E));
}
#endif
#if !defined(HAVE_AES_CBC) || !defined(HAVE_AES_DECRYPT)
{
/* 16 hex chars -> 8-byte salt after Base16_Decode */
const byte hexIv[16] = {
'1','1','2','2','3','3','4','4',
'5','5','6','6','7','7','8','8'
};
XMEMSET(&info, 0, sizeof(info));
info.cipherType = WC_CIPHER_AES_CBC;
info.keySz = 16;
info.ivSz = 16;
XMEMCPY(info.iv, hexIv, 16);
XMEMSET(der, 0x33, 16);
ExpectIntEQ(wc_BufferKeyDecrypt(&info, der, 16,
pw, (int)sizeof(pw), WC_HASH_TYPE_SHA),
WC_NO_ERR_TRACE(NOT_COMPILED_IN));
}
#endif
#endif
return EXPECT_RESULT();
} /* END test_wc_BufferKeyEncryptDecryptDecisionCoverage */

/*
* wc_BufferKeyEncrypt / wc_BufferKeyDecrypt: an unknown info->cipherType
* value should return ALGO_ID_E.
*/
int test_wc_BufferKeyEncryptDecryptUnknownCipher(void)
{
EXPECT_DECLS;
#if !defined(NO_ASN) && defined(WOLFSSL_ENCRYPTED_KEYS) && \
!defined(NO_PWDBASED) && !defined(NO_SHA)
const byte pw[] = { 'p','a','s','s','w','o','r','d' };
/* decrypt Base16-decodes info->iv in place, so it must be hex:
* 16 hex chars -> 8-byte salt */
const byte hexIv[16] = {
'1','1','2','2','3','3','4','4',
'5','5','6','6','7','7','8','8'
};
EncryptedInfo info;
byte der[16];

XMEMSET(&info, 0, sizeof(info));
info.cipherType = WC_CIPHER_NONE;
info.keySz = 16;
info.ivSz = 16;
XMEMSET(info.iv, 0x27, 16);
XMEMSET(der, 0x33, sizeof(der));
ExpectIntEQ(wc_BufferKeyEncrypt(&info, der, (word32)sizeof(der),
pw, (int)sizeof(pw), WC_HASH_TYPE_SHA),
WC_NO_ERR_TRACE(ALGO_ID_E));

XMEMSET(&info, 0, sizeof(info));
info.cipherType = WC_CIPHER_NONE;
info.keySz = 16;
info.ivSz = 16;
XMEMCPY(info.iv, hexIv, 16);
XMEMSET(der, 0x33, sizeof(der));
ExpectIntEQ(wc_BufferKeyDecrypt(&info, der, (word32)sizeof(der),
pw, (int)sizeof(pw), WC_HASH_TYPE_SHA),
WC_NO_ERR_TRACE(ALGO_ID_E));
#endif
return EXPECT_RESULT();
} /* END test_wc_BufferKeyEncryptDecryptUnknownCipher */
5 changes: 4 additions & 1 deletion tests/api/test_wc_encrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@ int test_wc_Des3_CbcEncryptDecryptWithKey(void);
int test_wc_Des_CbcEncryptDecryptWithKey(void);
int test_wc_AesCbcEncryptDecryptWithKey(void);
int test_wc_BufferKeyEncryptDecryptDecisionCoverage(void);
int test_wc_BufferKeyEncryptDecryptUnknownCipher(void);

#define TEST_WC_ENCRYPT_DECLS \
TEST_DECL_GROUP("wc_encrypt", test_wc_Des3_CbcEncryptDecryptWithKey), \
TEST_DECL_GROUP("wc_encrypt", test_wc_Des_CbcEncryptDecryptWithKey), \
TEST_DECL_GROUP("wc_encrypt", test_wc_AesCbcEncryptDecryptWithKey), \
TEST_DECL_GROUP("wc_encrypt", \
test_wc_BufferKeyEncryptDecryptDecisionCoverage)
test_wc_BufferKeyEncryptDecryptDecisionCoverage), \
TEST_DECL_GROUP("wc_encrypt", \
test_wc_BufferKeyEncryptDecryptUnknownCipher)

#endif /* WOLFCRYPT_TEST_WC_ENCRYPT_H */
61 changes: 50 additions & 11 deletions wolfcrypt/src/wc_encrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,14 +196,15 @@ int wc_Des3_CbcDecryptWithKey(byte* out, const byte* in, word32 sz,
int wc_BufferKeyDecrypt(EncryptedInfo* info, byte* der, word32 derSz,
const byte* password, int passwordSz, int hashType)
{
int ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
int ret;
WC_DECLARE_VAR(key, byte, WC_MAX_SYM_KEY_SIZE, 0);

(void)derSz;
(void)passwordSz;
(void)hashType;

if (der == NULL || password == NULL || info == NULL || info->keySz == 0) {
if (der == NULL || password == NULL || info == NULL || info->keySz == 0 ||
info->keySz > WC_MAX_SYM_KEY_SIZE) {
return BAD_FUNC_ARG;
}

Expand All @@ -228,6 +229,7 @@ int wc_BufferKeyDecrypt(EncryptedInfo* info, byte* der, word32 derSz,
#ifndef NO_PWDBASED
if ((ret = wc_PBKDF1(key, password, passwordSz, info->iv, PKCS5_SALT_SZ, 1,
(int)info->keySz, hashType)) != 0) {
ForceZero(key, WC_MAX_SYM_KEY_SIZE);
#ifdef WOLFSSL_SMALL_STACK
XFREE(key, NULL, DYNAMIC_TYPE_SYMMETRIC_KEY);
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
Expand All @@ -237,17 +239,35 @@ int wc_BufferKeyDecrypt(EncryptedInfo* info, byte* der, word32 derSz,
}
#endif

switch (info->cipherType)
{
#ifndef NO_DES3
if (info->cipherType == WC_CIPHER_DES)
case WC_CIPHER_DES:
ret = wc_Des_CbcDecryptWithKey(der, der, derSz, key, info->iv);
if (info->cipherType == WC_CIPHER_DES3)
break;
case WC_CIPHER_DES3:
ret = wc_Des3_CbcDecryptWithKey(der, der, derSz, key, info->iv);
break;
#else
case WC_CIPHER_DES:
case WC_CIPHER_DES3:
ret = NOT_COMPILED_IN;
break;
#endif /* NO_DES3 */
#if !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(HAVE_AES_DECRYPT)
if (info->cipherType == WC_CIPHER_AES_CBC)
case WC_CIPHER_AES_CBC:
ret = wc_AesCbcDecryptWithKey(der, der, derSz, key, info->keySz,
info->iv);
break;
#else
case WC_CIPHER_AES_CBC:
ret = NOT_COMPILED_IN;
break;
#endif /* !NO_AES && HAVE_AES_CBC && HAVE_AES_DECRYPT */
default:
ret = ALGO_ID_E;
break;
}

ForceZero(key, WC_MAX_SYM_KEY_SIZE);
#ifdef WOLFSSL_SMALL_STACK
Expand All @@ -262,30 +282,31 @@ int wc_BufferKeyDecrypt(EncryptedInfo* info, byte* der, word32 derSz,
int wc_BufferKeyEncrypt(EncryptedInfo* info, byte* der, word32 derSz,
const byte* password, int passwordSz, int hashType)
{
int ret = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
int ret;
WC_DECLARE_VAR(key, byte, WC_MAX_SYM_KEY_SIZE, 0);

(void)derSz;
(void)passwordSz;
(void)hashType;

if (der == NULL || password == NULL || info == NULL || info->keySz == 0 ||
info->ivSz < PKCS5_SALT_SZ) {
info->keySz > WC_MAX_SYM_KEY_SIZE || info->ivSz < PKCS5_SALT_SZ) {
return BAD_FUNC_ARG;
}

WC_ALLOC_VAR_EX(key, byte, WC_MAX_SYM_KEY_SIZE, NULL,
DYNAMIC_TYPE_SYMMETRIC_KEY, return MEMORY_E);
#ifdef WOLFSSL_CHECK_MEM_ZERO
XMEMSET(key, 0xff, WC_MAX_SYM_KEY_SIZE);
wc_MemZero_Add("wc_BufferKeyDecrypt key", key, WC_MAX_SYM_KEY_SIZE);
wc_MemZero_Add("wc_BufferKeyEncrypt key", key, WC_MAX_SYM_KEY_SIZE);
#endif

(void)XMEMSET(key, 0, WC_MAX_SYM_KEY_SIZE);

#ifndef NO_PWDBASED
if ((ret = wc_PBKDF1(key, password, passwordSz, info->iv, PKCS5_SALT_SZ, 1,
(int)info->keySz, hashType)) != 0) {
ForceZero(key, WC_MAX_SYM_KEY_SIZE);
#ifdef WOLFSSL_SMALL_STACK
XFREE(key, NULL, DYNAMIC_TYPE_SYMMETRIC_KEY);
#elif defined(WOLFSSL_CHECK_MEM_ZERO)
Expand All @@ -295,17 +316,35 @@ int wc_BufferKeyEncrypt(EncryptedInfo* info, byte* der, word32 derSz,
}
#endif

switch (info->cipherType)
{
#ifndef NO_DES3
if (info->cipherType == WC_CIPHER_DES)
case WC_CIPHER_DES:
ret = wc_Des_CbcEncryptWithKey(der, der, derSz, key, info->iv);
if (info->cipherType == WC_CIPHER_DES3)
break;
case WC_CIPHER_DES3:
ret = wc_Des3_CbcEncryptWithKey(der, der, derSz, key, info->iv);
break;
#else
case WC_CIPHER_DES:
case WC_CIPHER_DES3:
ret = NOT_COMPILED_IN;
break;
#endif /* NO_DES3 */
#if !defined(NO_AES) && defined(HAVE_AES_CBC)
if (info->cipherType == WC_CIPHER_AES_CBC)
case WC_CIPHER_AES_CBC:
ret = wc_AesCbcEncryptWithKey(der, der, derSz, key, info->keySz,
info->iv);
break;
#else
case WC_CIPHER_AES_CBC:
ret = NOT_COMPILED_IN;
break;
#endif /* !NO_AES && HAVE_AES_CBC */
default:
ret = ALGO_ID_E;
break;
}

ForceZero(key, WC_MAX_SYM_KEY_SIZE);
#ifdef WOLFSSL_SMALL_STACK
Expand Down
Loading
Loading