From ac1e58837f1ba687939f78b5c03cadd346c10ddd Mon Sep 17 00:00:00 2001 From: vnugent Date: Tue, 30 Jan 2024 12:25:05 -0500 Subject: couple more tests, renable range checks, set flags for all projects --- CMakeLists.txt | 14 ++------------ src/noscrypt.c | 32 +++++++++++++++++++++---------- src/noscrypt.h | 1 + tests/test.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 78 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3872f13..847f9fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,14 +44,10 @@ if(MSVC) $<$:/FC> #show full path in diagnostics $<$:/showIncludes> #show a list of all included header files during build - ) - - #only target our project - target_compile_options( - ${CMAKE_PROJECT_NAME} - PRIVATE + $<$:/wd4820> #disable warnings for struct padding and spectre mitigation wuen WX is enabled + $<$:/wd5045> #disable warnings for spectre mitigation insertion #for debug configs $<$:/options:strict> @@ -78,12 +74,6 @@ elseif(CMAKE_COMPILER_IS_GNUCC) $<$:-Og> $<$:-Wall> $<$:-Werror> - ) - - #only target our project if building other 3rd party libs in current build - target_compile_options( - ${CMAKE_PROJECT_NAME} - PRIVATE $<$:-Wall> $<$:-pedantic> ) diff --git a/src/noscrypt.c b/src/noscrypt.c index 6ef273f..55a098e 100644 --- a/src/noscrypt.c +++ b/src/noscrypt.c @@ -178,7 +178,8 @@ static NCResult _computeSharedSecret( //Clean up sensitive data ZERO_FILL(&pubKey, sizeof(secp256k1_pubkey)); - return (NCResult)result; + //Result should be 1 on success + return result > 0 ? NC_SUCCESS : E_OPERATION_FAILED; } static inline const mbedtls_md_info_t* _getSha256MdInfo(void) @@ -198,14 +199,15 @@ static inline NCResult _computeConversationKey( struct conversation_key* ck ) { + int opResult; //Validate internal args DEBUG_ASSERT2(ctx != NULL, "Expected valid context") DEBUG_ASSERT2(sharedSecret != NULL, "Expected a valid shared-point") DEBUG_ASSERT2(mdInfo != NULL, "Expected valid md context") DEBUG_ASSERT2(ck != NULL, "Expected a valid conversation key") - //Derive the encryption key (returns 0 on success so it can be cast to an NCResult) - return (NCResult)mbedtls_hkdf_extract( + //Derive the encryption key + opResult = mbedtls_hkdf_extract( mdInfo, Nip44ConstantSalt, sizeof(Nip44ConstantSalt), @@ -213,6 +215,9 @@ static inline NCResult _computeConversationKey( NC_SHARED_SEC_SIZE, (uint8_t*)ck //Output produces a conversation key ); + + //Return success if the hkdf operation was successful + return opResult == 0 ? NC_SUCCESS : E_OPERATION_FAILED; } @@ -224,6 +229,7 @@ static inline void _expandKeysFromHkdf(const struct message_key* hkdf, struct nc uint8_t* hkdfBytes; DEBUG_ASSERT2(hkdf != NULL, "Expected valid hkdf") + DEBUG_ASSERT2(keys != NULL, "Expected valid key expand structure") hkdfBytes = (uint8_t*)hkdf; @@ -233,16 +239,20 @@ static inline void _expandKeysFromHkdf(const struct message_key* hkdf, struct nc hkdfBytes, CHACHA_KEY_SIZE ); + + hkdfBytes += CHACHA_KEY_SIZE; //Offset by key size MEMMOV( keys->chacha_nonce, - (hkdfBytes + CHACHA_KEY_SIZE), + hkdfBytes, CHACHA_NONCE_SIZE ); + hkdfBytes += CHACHA_NONCE_SIZE; //Offset by nonce size + MEMMOV( keys->hamc_key, - (hkdfBytes + CHACHA_KEY_SIZE + CHACHA_NONCE_SIZE), + hkdfBytes, HMAC_KEY_SIZE ); } @@ -254,7 +264,6 @@ static int _chachaEncipher(const struct nc_expand_keys* keys, NCCryptoData* args DEBUG_ASSERT2(keys != NULL, "Expected valid keys") DEBUG_ASSERT2(args != NULL, "Expected valid encryption args") - DEBUG_ASSERT2(sizeof(keys->chacha_nonce) == 12, "Chacha nonce must be 12 exactly bytes in length") //Init the chacha context mbedtls_chacha20_init(&chachaCtx); @@ -284,21 +293,24 @@ static inline NCResult _getMessageKey( struct message_key* messageKey ) { + int result; DEBUG_ASSERT2(mdInfo != NULL, "Expected valid md context") DEBUG_ASSERT2(nonce != NULL, "Expected valid nonce buffer") DEBUG_ASSERT2(converstationKey != NULL, "Expected valid conversation key") DEBUG_ASSERT2(messageKey != NULL, "Expected valid message key buffer") //Another HKDF to derive the message key with nonce - return (NCResult)mbedtls_hkdf_expand( + result = mbedtls_hkdf_expand( mdInfo, (uint8_t*)converstationKey, //Conversation key is the input key NC_CONV_KEY_SIZE, nonce, nonceSize, - (uint8_t*)messageKey, //Output produces a message key + (uint8_t*)messageKey, //Output produces a message key (write it directly to struct memory) NC_MESSAGE_KEY_SIZE ); + + return result == 0 ? NC_SUCCESS : E_OPERATION_FAILED; } static inline NCResult _encryptEx( @@ -564,7 +576,7 @@ NC_EXPORT NCResult NC_CC NCSignData( uint8_t digest[32]; CHECK_NULL_ARG(data, 2) - //CHECK_ARG_RANGE(dataSize, 1, UINT32_MAX, 3) + CHECK_ARG_RANGE(dataSize, 1, UINT32_MAX, 3) //Compute sha256 of the data before signing if(_computeSha256Digest(data, dataSize, digest) != 0) @@ -620,7 +632,7 @@ NC_EXPORT NCResult NC_CC NCVerifyData( uint8_t digest[32]; CHECK_NULL_ARG(data, 2) - //CHECK_ARG_RANGE(dataSize, 1, UINT32_MAX, 3) + CHECK_ARG_RANGE(dataSize, 1, UINT32_MAX, 3) //Compute sha256 of the data before verifying if (_computeSha256Digest(data, dataSize, digest) != 0) diff --git a/src/noscrypt.h b/src/noscrypt.h index 8a43743..2a2d051 100644 --- a/src/noscrypt.h +++ b/src/noscrypt.h @@ -121,6 +121,7 @@ static const uint8_t Nip44ConstantSalt[8] = { 0x6e, 0x69, 0x70, 0x34, 0x34, 0x2d #define E_INVALID_ARG -2 #define E_INVALID_CONTEXT -3 #define E_ARGUMENT_OUT_OF_RANGE -4 +#define E_OPERATION_FAILED -5 /* * Validation macros diff --git a/tests/test.c b/tests/test.c index 499ef50..b44f820 100644 --- a/tests/test.c +++ b/tests/test.c @@ -22,30 +22,41 @@ #include #include #include +#include #include "../src/noscrypt.h" #include "../include/mbedtls/sha256.h" +#include "../include/mbedtls/platform_util.h" #if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) #define IS_WINDOWS #endif #ifdef IS_WINDOWS - - #include + #include #include +#endif + +#ifdef IS_WINDOWS //Prints a string literal to the console #define PRINTL(x) printf(x); printf("\r\n"); #define TEST(x) printf("Testing %s\n", #x); if(!(x)) { printf("Test failed!\n"); return 1; } else { printf("Test passed\n\n"); } #define TASSERT(x) if(!(x)) { printf("ERROR! Internal test assumption failed: %s.\n Aborting tests...\n", #x); ExitProcess(1); } + #define ENSURE(x) if(!(x)) { printf("Assumption failed!\n"); return 1; } #else - #include //Prints a string literal to the console #define PRINTL(x) printf(x); printf("\n"); #define TEST(x) printf("Testing %s\n", #x); if(!(x)) { printf("Test failed!\n"); return 1; } else { printf("Test passed\n\n"); } #define TASSERT(x) if(!(x)) { printf("Internal assumption failed: %s\n", #x); exit(1); } + #define ENSURE(x) if(!(x)) { printf("Assumption failed!\n"); return 1; } +#endif + +#ifdef IS_WINDOWS + #define ZERO_FILL(x, size) SecureZeroMemory(x, size) +#else + #define ZERO_FILL(x, size) memset(x, 0, size) #endif static void FillRandomData(uint8_t* pbBuffer, size_t length); @@ -88,12 +99,15 @@ static void _sha256(const uint8_t* data, size_t length, uint8_t digest[32]) } static const char* message = "Test message to sign"; +static const uint8_t zero32[32] = { 0 }; +static const uint8_t zero64[64] = { 0 }; static int TestEcdsa(NCContext* context) { - uint8_t digestToSign[32]; + uint8_t secretKey[NC_SEC_KEY_SIZE]; uint8_t publicKey[NC_PUBKEY_SIZE]; + uint8_t digestToSign[32]; uint8_t sigEntropy[32]; uint8_t invalidSig[64]; NCSecretKey* secKey; @@ -112,18 +126,22 @@ static int TestEcdsa(NCContext* context) FillRandomData(invalidSig, sizeof(invalidSig)); FillRandomData(sigEntropy, sizeof(sigEntropy)); + //compute sha256 of the test string + _sha256((uint8_t*)message, strlen(message), digestToSign); + //Verify that the secret key is valid for the curve TEST(NCValidateSecretKey(context, secKey) == NC_SUCCESS); //Generate a public key from the secret key TEST(NCGetPublicKey(context, secKey, pubKey) == NC_SUCCESS); + //Ensure not empty + TEST(memcmp(zero32, secretKey, 32) != 0); + TEST(memcmp(zero32, publicKey, 32) != 0); + //Sign and verify digest { uint8_t sig[64]; - - //compute sha256 of the test string - _sha256((uint8_t*)message, strlen(message), digestToSign); TEST(NCSignDigest(context, secKey, sigEntropy, digestToSign, sig) == NC_SUCCESS); TEST(NCVerifyDigest(context, pubKey, digestToSign, sig) == NC_SUCCESS); @@ -136,8 +154,36 @@ static int TestEcdsa(NCContext* context) TEST(NCVerifyData(context, pubKey, (uint8_t*)message, strlen(message), sig) == NC_SUCCESS); } + //ensure the signature is the same for signing data and digest + { + uint8_t sig1[64]; + uint8_t sig2[64]; + + //Ensure operations succeed but dont print them as test cases + ENSURE(NCSignData(context, secKey, sigEntropy, (uint8_t*)message, strlen(message), sig1) == NC_SUCCESS); + ENSURE(NCSignDigest(context, secKey, sigEntropy, digestToSign, sig2) == NC_SUCCESS); + + //Perform test + TEST(memcmp(sig1, sig2, 64) == 0); + } + + //Try signing data then veriyfing the digest + { + uint8_t sig[64]; + + ENSURE(NCSignData(context, secKey, sigEntropy, (uint8_t*)message, strlen(message), sig) == NC_SUCCESS); + TEST(NCVerifyDigest(context, pubKey, digestToSign, sig) == NC_SUCCESS); + + //Now invert test, zero signature to ensure its overwritten + ZERO_FILL(sig, sizeof(sig)); + + ENSURE(NCSignDigest(context, secKey, sigEntropy, digestToSign, sig) == NC_SUCCESS); + TEST(NCVerifyData(context, pubKey, (uint8_t*)message, strlen(message), sig) == NC_SUCCESS); + } + //test verification of invalid signature { + TEST(NCVerifyDigest(context, pubKey, digestToSign, invalidSig) == E_INVALID_ARG); } -- cgit