diff --git a/wolfcrypt/src/rsa.c b/wolfcrypt/src/rsa.c index df9681866..aea0ad7c0 100644 --- a/wolfcrypt/src/rsa.c +++ b/wolfcrypt/src/rsa.c @@ -871,6 +871,23 @@ static int wc_RsaPad_ex(const byte* input, word32 inputLen, byte* pkcsBlock, break; #endif + #ifdef WC_RSA_NO_PADDING + case WC_RSA_NO_PAD: + WOLFSSL_MSG("wolfSSL Using NO padding"); + + /* In the case of no padding being used check that input is exactly + * the RSA key length */ + if (bits <= 0 || inputLen != ((word32)bits/8)) { + WOLFSSL_MSG("Bad input size"); + ret = RSA_PAD_E; + } + else { + XMEMCPY(pkcsBlock, input, inputLen); + ret = 0; + } + break; + #endif + default: WOLFSSL_MSG("Unknown RSA Pad Type"); ret = RSA_PAD_E; @@ -1099,7 +1116,10 @@ static int RsaUnPad(const byte *pkcsBlock, unsigned int pkcsBlockLen, return outputLen; } -/* helper function to direct unpadding */ +/* helper function to direct unpadding + * + * bits is the key modulus size in bits + */ static int wc_RsaUnPad_ex(byte* pkcsBlock, word32 pkcsBlockLen, byte** out, byte padValue, int padType, enum wc_HashType hType, int mgf, byte* optLabel, word32 labelLen, int saltLen, @@ -1129,6 +1149,25 @@ static int wc_RsaUnPad_ex(byte* pkcsBlock, word32 pkcsBlockLen, byte** out, break; #endif + #ifdef WC_RSA_NO_PADDING + case WC_RSA_NO_PAD: + WOLFSSL_MSG("wolfSSL Using NO un-padding"); + + /* In the case of no padding being used check that input is exactly + * the RSA key length */ + if (bits <= 0 || pkcsBlockLen != ((word32)bits/8)) { + WOLFSSL_MSG("Bad input size"); + ret = RSA_PAD_E; + } + else { + if (out != NULL) { + *out = pkcsBlock; + } + ret = pkcsBlockLen; + } + break; + #endif /* WC_RSA_NO_PADDING */ + default: WOLFSSL_MSG("Unknown RSA UnPad Type"); ret = RSA_PAD_E; @@ -1470,6 +1509,62 @@ static int wc_RsaFunctionAsync(const byte* in, word32 inLen, byte* out, } #endif /* WOLFSSL_ASYNC_CRYPT && WC_ASYNC_ENABLE_RSA */ +#ifdef WC_RSA_NO_PADDING +/* Function that does the RSA operation directly with no padding. + * + * in buffer to do operation on + * inLen length of input buffer + * out buffer to hold results + * outSz gets set to size of result buffer. Should be passed in as length + * of out buffer. If the pointer "out" is null then outSz gets set to + * the expected buffer size needed and LENGTH_ONLY_E gets returned. + * key RSA key to use for encrypt/decrypt + * type if using private or public key {RSA_PUBLIC_ENCRYPT, + * RSA_PUBLIC_DECRYPT, RSA_PRIVATE_ENCRYPT, RSA_PRIVATE_DECRYPT} + * rng wolfSSL RNG to use if needed + * + * returns 0 on success + */ +int wc_RsaDirect(byte* in, word32 inLen, byte* out, word32* outSz, + RsaKey* key, int type, WC_RNG* rng) +{ + int ret; + + if (in == NULL || outSz == NULL || key == NULL) { + return BAD_FUNC_ARG; + } + + /* sanity check on type of RSA operation */ + switch (type) { + case RSA_PUBLIC_ENCRYPT: + case RSA_PUBLIC_DECRYPT: + case RSA_PRIVATE_ENCRYPT: + case RSA_PRIVATE_DECRYPT: + break; + default: + WOLFSSL_MSG("Bad RSA type"); + return BAD_FUNC_ARG; + } + + if ((ret = wc_RsaEncryptSize(key)) < 0) { + return BAD_FUNC_ARG; + } + + if (inLen != (word32)ret) { + WOLFSSL_MSG("Bad input length. Should be RSA key size"); + return BAD_FUNC_ARG; + } + + if (out == NULL) { + *outSz = inLen; + return LENGTH_ONLY_E; + } + + return wc_RsaFunction(in, inLen, out, outSz, type, key, rng); +} +#endif /* WC_RSA_NO_PADDING */ + + int wc_RsaFunction(const byte* in, word32 inLen, byte* out, word32* outLen, int type, RsaKey* key, WC_RNG* rng) { @@ -1517,8 +1612,8 @@ int wc_RsaFunction(const byte* in, word32 inLen, byte* out, rsa_type : type of RSA: RSA_PUBLIC_ENCRYPT, RSA_PUBLIC_DECRYPT, RSA_PRIVATE_ENCRYPT or RSA_PRIVATE_DECRYPT pad_value: RSA_BLOCK_TYPE_1 or RSA_BLOCK_TYPE_2 - pad_type : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD or - WC_RSA_PSS_PAD + pad_type : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD, + WC_RSA_NO_PAD or WC_RSA_PSS_PAD hash : type of hash algorithm to use found in wolfssl/wolfcrypt/hash.h mgf : type of mask generation function to use label : optional label @@ -1548,6 +1643,11 @@ static int RsaPublicEncryptEx(const byte* in, word32 inLen, byte* out, } if (inLen > (word32)(sz - RSA_MIN_PAD_SZ)) { +#ifdef WC_RSA_NO_PADDING + /* In the case that no padding is used the input length can and should + * be the same size as the RSA key. */ + if (pad_type != WC_RSA_NO_PAD) +#endif return RSA_BUFFER_E; } @@ -1630,8 +1730,8 @@ static int RsaPublicEncryptEx(const byte* in, word32 inLen, byte* out, rsa_type : type of RSA: RSA_PUBLIC_ENCRYPT, RSA_PUBLIC_DECRYPT, RSA_PRIVATE_ENCRYPT or RSA_PRIVATE_DECRYPT pad_value: RSA_BLOCK_TYPE_1 or RSA_BLOCK_TYPE_2 - pad_type : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD - WC_RSA_PSS_PAD + pad_type : type of padding: WC_RSA_PKCSV15_PAD, WC_RSA_OAEP_PAD, + WC_RSA_NO_PAD, WC_RSA_PSS_PAD hash : type of hash algorithm to use found in wolfssl/wolfcrypt/hash.h mgf : type of mask generation function to use label : optional label @@ -1777,7 +1877,7 @@ int wc_RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen, } -#ifndef WC_NO_RSA_OAEP +#if !defined(WC_NO_RSA_OAEP) || defined(WC_RSA_NO_PADDING) int wc_RsaPublicEncrypt_ex(const byte* in, word32 inLen, byte* out, word32 outLen, RsaKey* key, WC_RNG* rng, int type, enum wc_HashType hash, int mgf, byte* label, @@ -1829,7 +1929,7 @@ int wc_RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, rng); } -#ifndef WC_NO_RSA_OAEP +#if !defined(WC_NO_RSA_OAEP) || defined(WC_RSA_NO_PADDING) int wc_RsaPrivateDecrypt_ex(const byte* in, word32 inLen, byte* out, word32 outLen, RsaKey* key, int type, enum wc_HashType hash, int mgf, byte* label, @@ -1843,7 +1943,7 @@ int wc_RsaPrivateDecrypt_ex(const byte* in, word32 inLen, byte* out, RSA_PRIVATE_DECRYPT, RSA_BLOCK_TYPE_2, type, hash, mgf, label, labelSz, 0, rng); } -#endif /* WC_NO_RSA_OAEP */ +#endif /* WC_NO_RSA_OAEP || WC_RSA_NO_PADDING */ int wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 91e6eac73..9da753ef0 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -250,6 +250,7 @@ int gmac_test(void); int aesccm_test(void); int aeskeywrap_test(void); int camellia_test(void); +int rsa_no_pad_test(void); int rsa_test(void); int dh_test(void); int dsa_test(void); @@ -731,6 +732,12 @@ int wolfcrypt_test(void* args) #endif #ifndef NO_RSA + #ifdef WC_RSA_NO_PADDING + if ( (ret = rsa_no_pad_test()) != 0) + return err_sys("RSA NOPAD test failed!\n", ret); + else + printf( "RSA NOPAD test passed!\n"); + #endif if ( (ret = rsa_test()) != 0) return err_sys("RSA test failed!\n", ret); else @@ -8494,6 +8501,173 @@ exit_rsa_pss: } #endif +#ifdef WC_RSA_NO_PADDING +int rsa_no_pad_test(void) +{ + WC_RNG rng; + RsaKey key; + byte* tmp = NULL; + size_t bytes; + int ret; + word32 inLen = 0; + word32 idx = 0; + word32 outSz = RSA_TEST_BYTES; + word32 plainSz = RSA_TEST_BYTES; +#if !defined(USE_CERT_BUFFERS_1024) && !defined(USE_CERT_BUFFERS_2048) \ + && !defined(NO_FILESYSTEM) + FILE *file; +#endif + DECLARE_VAR(out, byte, RSA_TEST_BYTES, HEAP_HINT); + DECLARE_VAR(plain, byte, RSA_TEST_BYTES, HEAP_HINT); + + /* initialize stack structures */ + XMEMSET(&rng, 0, sizeof(rng)); + XMEMSET(&key, 0, sizeof(key)); +#ifdef USE_CERT_BUFFERS_1024 + bytes = (size_t)sizeof_client_key_der_1024; + if (bytes < (size_t)sizeof_client_cert_der_1024) + bytes = (size_t)sizeof_client_cert_der_1024; +#elif defined(USE_CERT_BUFFERS_2048) + bytes = (size_t)sizeof_client_key_der_2048; + if (bytes < (size_t)sizeof_client_cert_der_2048) + bytes = (size_t)sizeof_client_cert_der_2048; +#else + bytes = FOURK_BUF; +#endif + + tmp = (byte*)XMALLOC(bytes, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (tmp == NULL + #ifdef WOLFSSL_ASYNC_CRYPT + || out == NULL || plain == NULL + #endif + ) { + return -500; + } + +#ifdef USE_CERT_BUFFERS_1024 + XMEMCPY(tmp, client_key_der_1024, (size_t)sizeof_client_key_der_1024); +#elif defined(USE_CERT_BUFFERS_2048) + XMEMCPY(tmp, client_key_der_2048, (size_t)sizeof_client_key_der_2048); +#elif !defined(NO_FILESYSTEM) + file = fopen(clientKey, "rb"); + if (!file) { + err_sys("can't open ./certs/client-key.der, " + "Please run from wolfSSL home dir", -40); + ERROR_OUT(-501, exit_rsa_nopadding); + } + + bytes = fread(tmp, 1, FOURK_BUF, file); + fclose(file); +#else + /* No key to use. */ + ERROR_OUT(-502, exit_rsa_nopadding); +#endif /* USE_CERT_BUFFERS */ + + ret = wc_InitRsaKey_ex(&key, HEAP_HINT, devId); + if (ret != 0) { + ERROR_OUT(-503, exit_rsa_nopadding); + } + ret = wc_RsaPrivateKeyDecode(tmp, &idx, &key, (word32)bytes); + if (ret != 0) { + ERROR_OUT(-504, exit_rsa_nopadding); + } + + /* after loading in key use tmp as the test buffer */ + +#ifndef HAVE_FIPS + ret = wc_InitRng_ex(&rng, HEAP_HINT, devId); +#else + ret = wc_InitRng(&rng); +#endif + if (ret != 0) { + ERROR_OUT(-505, exit_rsa_nopadding); + } + + inLen = wc_RsaEncryptSize(&key); + XMEMSET(tmp, 7, inLen); + ret = wc_RsaDirect(tmp, inLen, out, &outSz, &key, RSA_PRIVATE_ENCRYPT, &rng); + if (ret != 0) { + ERROR_OUT(-506, exit_rsa_nopadding); + } + + /* encrypted result should not be the same as input */ + if (XMEMCMP(out, tmp, inLen) == 0) { + ERROR_OUT(-507, exit_rsa_nopadding); + } + + /* decrypt with public key and compare result */ + ret = wc_RsaDirect(out, outSz, plain, &plainSz, &key, RSA_PUBLIC_DECRYPT, + &rng); + if (ret != 0) { + ERROR_OUT(-508, exit_rsa_nopadding); + } + + if (XMEMCMP(plain, tmp, inLen) != 0) { + ERROR_OUT(-509, exit_rsa_nopadding); + } + +#ifdef WC_RSA_BLINDING + ret = wc_RsaSetRNG(&key, &rng); + if (ret < 0) { + ERROR_OUT(-510, exit_rsa_nopadding); + } +#endif + + /* test encrypt and decrypt using WC_RSA_NO_PAD */ + ret = wc_RsaPublicEncrypt_ex(tmp, inLen, out, (int)outSz, &key, &rng, + WC_RSA_NO_PAD, WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0); + if (ret < 0) { + ERROR_OUT(-511, exit_rsa_nopadding); + } + + printf("outSz = %d plainSz = %d\n", outSz, plainSz); + ret = wc_RsaPrivateDecrypt_ex(out, outSz, plain, (int)plainSz, &key, + WC_RSA_NO_PAD, WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0); + if (ret < 0) { + ERROR_OUT(-512, exit_rsa_nopadding); + } + + if (XMEMCMP(plain, tmp, inLen) != 0) { + ERROR_OUT(-513, exit_rsa_nopadding); + } + + /* test some bad arguments */ + ret = wc_RsaDirect(out, outSz, plain, &plainSz, &key, -1, + &rng); + if (ret != BAD_FUNC_ARG) { + ERROR_OUT(-514, exit_rsa_nopadding); + } + + ret = wc_RsaDirect(out, outSz, plain, &plainSz, NULL, RSA_PUBLIC_DECRYPT, + &rng); + if (ret != BAD_FUNC_ARG) { + ERROR_OUT(-515, exit_rsa_nopadding); + } + + ret = wc_RsaDirect(out, outSz, NULL, &plainSz, &key, RSA_PUBLIC_DECRYPT, + &rng); + if (ret != LENGTH_ONLY_E || plainSz != inLen) { + ERROR_OUT(-516, exit_rsa_nopadding); + } + + ret = wc_RsaDirect(out, outSz - 10, plain, &plainSz, &key, + RSA_PUBLIC_DECRYPT, &rng); + if (ret != BAD_FUNC_ARG) { + ERROR_OUT(-517, exit_rsa_nopadding); + } + + /* if making it to this point of code without hitting an ERROR_OUT then + * all tests have passed */ + ret = 0; + +exit_rsa_nopadding: + wc_FreeRsaKey(&key); + wc_FreeRng(&rng); + + return ret; +} +#endif /* WC_RSA_NO_PADDING */ + int rsa_test(void) { int ret; diff --git a/wolfssl/wolfcrypt/rsa.h b/wolfssl/wolfcrypt/rsa.h index 47d6dc5ae..3214bfea4 100644 --- a/wolfssl/wolfcrypt/rsa.h +++ b/wolfssl/wolfcrypt/rsa.h @@ -217,6 +217,7 @@ WOLFSSL_API int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng); #define WC_RSA_PKCSV15_PAD 0 #define WC_RSA_OAEP_PAD 1 #define WC_RSA_PSS_PAD 2 +#define WC_RSA_NO_PAD 3 WOLFSSL_API int wc_RsaPublicEncrypt_ex(const byte* in, word32 inLen, byte* out, word32 outLen, RsaKey* key, WC_RNG* rng, int type, @@ -227,6 +228,8 @@ WOLFSSL_API int wc_RsaPrivateDecrypt_ex(const byte* in, word32 inLen, WOLFSSL_API int wc_RsaPrivateDecryptInline_ex(byte* in, word32 inLen, byte** out, RsaKey* key, int type, enum wc_HashType hash, int mgf, byte* label, word32 lableSz); +WOLFSSL_API int wc_RsaDirect(byte* in, word32 inLen, byte* out, word32* outSz, + RsaKey* key, int type, WC_RNG* rng); #endif /* HAVE_FIPS*/ WOLFSSL_API int wc_RsaFlattenPublicKey(RsaKey*, byte*, word32*, byte*, word32*);