From ffe42b6858f112a00405be4f0605ab1163063749 Mon Sep 17 00:00:00 2001 From: vnugent Date: Sat, 13 Jul 2024 22:13:13 -0400 Subject: test: Add decryption test cases and fixes --- include/noscryptutil.h | 8 ++--- src/noscryptutil.c | 50 +++++++++++++++++++---------- tests/test.c | 86 ++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 108 insertions(+), 36 deletions(-) diff --git a/include/noscryptutil.h b/include/noscryptutil.h index 20384c4..13b9231 100644 --- a/include/noscryptutil.h +++ b/include/noscryptutil.h @@ -40,10 +40,10 @@ extern "C" { #define E_CIPHER_BAD_NONCE -12 #define E_CIPHER_MAC_INVALID -13 -#define NC_UTIL_CIPHER_MODE_ENCRYPT 0x00ui32 -#define NC_UTIL_CIPHER_MODE_DECRYPT 0x01ui32 -#define NC_UTIL_CIPHER_ZERO_ON_FREE 0x02ui32 -#define NC_UTIL_CIPHER_MAC_NO_VERIFY 0x04ui32 +#define NC_UTIL_CIPHER_MODE_ENCRYPT 0x00u +#define NC_UTIL_CIPHER_MODE_DECRYPT 0x01u +#define NC_UTIL_CIPHER_ZERO_ON_FREE 0x02u +#define NC_UTIL_CIPHER_MAC_NO_VERIFY 0x04u /* * The encryption context structure. This structure is used to store the state diff --git a/src/noscryptutil.c b/src/noscryptutil.c index 09b7c92..97526d9 100644 --- a/src/noscryptutil.c +++ b/src/noscryptutil.c @@ -20,7 +20,6 @@ #include -#include #include "nc-util.h" #include "nc-crypto.h" @@ -53,8 +52,26 @@ #endif /* !NC_DISABLE_INPUT_VALIDATION */ -/* performs a log2 on integer types */ -#define _math_int_log2(x) (int32_t)log2((double)x) +#ifdef _NC_IS_WINDOWS + + #include + + /* performs a log2 on integer types */ + #define _math_int_log2(x) (uint32_t)log2((double)x) + +#else + /* + * GCC/clang does not expose log2 so we can use the __builtin_clz + * to find leading zeros of an integer and subtract that from 31 + * (bit positions) for int32 + */ + static _nc_fn_inline uint32_t _math_int_log2(uint32_t val) + { + DEBUG_ASSERT(val < UINT32_MAX); + + return 31 - __builtin_clz(val); + } +#endif #define MIN_PADDING_SIZE 0x20u #define NIP44_VERSION_SIZE 0x01u @@ -66,10 +83,15 @@ */ #define NIP44_MIN_PAYLOAD_SIZE (NIP44_VERSION_SIZE + 0x20 + 0x02 + 0x20 + 0x02) +/* +* The minimum ciphertext size is the minimum padded size + the minimum +* size of the plaintext length field +*/ +#define NIP44_MIN_CIPHERTEXT_SIZE (MIN_PADDING_SIZE + NIP44_PT_LEN_SIZE) /* Currently were on nip44 version 2 */ -const static uint8_t Nip44VersionValue[1] = { 0x02u }; +static const uint8_t Nip44VersionValue[1] = { 0x02u }; struct nc_util_enc_struct { @@ -217,7 +239,7 @@ static _nc_fn_inline span_t _nip44GetMacOutput(span_t payload) static _nc_fn_inline cspan_t _nip44ParseMac(cspan_t payload) { - DEBUG_ASSERT(payload.size > NC_ENCRYPTION_MAC_SIZE); + DEBUG_ASSERT(payload.size >= NIP44_MIN_PAYLOAD_SIZE); /* * Mac is the final 32 bytes of the ciphertext buffer @@ -231,30 +253,26 @@ static _nc_fn_inline cspan_t _nip44ParseMac(cspan_t payload) static _nc_fn_inline cspan_t _nip44ParseCipherText(cspan_t payload) { - DEBUG_ASSERT(payload.size < NIP44_MIN_PAYLOAD_SIZE); + DEBUG_ASSERT(payload.size >= NIP44_MIN_PAYLOAD_SIZE); - /* slice after the nonce and before the mac segments */ + /* ct is all of the data after the nonce and before the mac segment */ return ncSpanSliceC( payload, NIP44_VERSION_SIZE + NC_ENCRYPTION_NONCE_SIZE, - payload.size - NC_ENCRYPTION_MAC_SIZE + payload.size - (NIP44_VERSION_SIZE + NC_ENCRYPTION_NONCE_SIZE + NC_ENCRYPTION_MAC_SIZE) ); } static _nc_fn_inline cspan_t _nip44ParseNonce(cspan_t payload) { - cspan_t nonceData; - - DEBUG_ASSERT(payload.size > NIP44_MIN_PAYLOAD_SIZE); + DEBUG_ASSERT(payload.size >= NIP44_MIN_PAYLOAD_SIZE); /* slice after the version and before the mac segments */ - nonceData = ncSpanSliceC( + return ncSpanSliceC( payload, NIP44_VERSION_SIZE, NC_ENCRYPTION_NONCE_SIZE ); - - return nonceData; } static NCResult _nip44EncryptCompleteCore( @@ -325,7 +343,7 @@ static NCResult _nip44EncryptCompleteCore( result = NCSetEncryptionData( &encArgs, - (payload.data + outPos), + (payload.data + outPos), /* in place encryption */ (payload.data + outPos), paddedCtSize + NIP44_PT_LEN_SIZE /* Plaintext + pt size must be encrypted */ ); @@ -458,7 +476,7 @@ static NCResult _nip44DecryptCompleteCore( cipherText = _nip44ParseCipherText(cipher->cipherInput); - DEBUG_ASSERT2(cipherText.size > 0x20, "Cipertext segment was parsed incorrectly. Too small"); + DEBUG_ASSERT2(cipherText.size >= MIN_PADDING_SIZE, "Cipertext segment was parsed incorrectly. Too small"); /* manually sign nonce */ encArgs.nonceData = nonce.data; diff --git a/tests/test.c b/tests/test.c index c917f52..80b8704 100644 --- a/tests/test.c +++ b/tests/test.c @@ -607,15 +607,9 @@ static int TestCorrectEncryption(const NCContext* context) #include -/* -* This function is not currently public, but we can access it for testing -* purposes because it is used to calculate the output buffer size for encryption -*/ -extern NCResult NCUtilGetEncryptionPaddedSize(uint32_t encVersion, int32_t plaintextSize); - /* Padding tests taken from the nip44 repo vectors.json file */ -const uint32_t _padTestActual[24] = { 16, 32, 33, 37, 45, 49, 64, 65, 100, 111, 200, 250, 320, 383, 384, 400, 500, 512, 515, 700, 800, 900, 1020, 65536 }; -const uint32_t _padTestExpected[24] = { 32, 32, 64, 64, 64, 64, 64, 96, 128, 128, 224, 256, 320, 384, 384, 448, 512, 512, 640, 768, 896, 1024, 1024, 65536 }; +static const uint32_t _padTestActual[24] = { 16, 32, 33, 37, 45, 49, 64, 65, 100, 111, 200, 250, 320, 383, 384, 400, 500, 512, 515, 700, 800, 900, 1020, 65536 }; +static const uint32_t _padTestExpected[24] = { 32, 32, 64, 64, 64, 64, 64, 96, 128, 128, 224, 256, 320, 384, 384, 448, 512, 512, 640, 768, 896, 1024, 1024, 65536 }; static int TestUtilNip44Encryption( const NCContext* libCtx, @@ -627,7 +621,7 @@ static int TestUtilNip44Encryption( ) { NCPublicKey recvPubKey; - span_t outData; + uint8_t* outData; ENSURE(NCValidateSecretKey(libCtx, NCByteCastToSecretKey(sendKey.data)) == NC_SUCCESS); ENSURE(NCGetPublicKey(libCtx, NCByteCastToSecretKey(recvKey.data), &recvPubKey) == NC_SUCCESS); @@ -645,25 +639,70 @@ static int TestUtilNip44Encryption( /* Nonce is required for nip44 encryption */ TEST(NCUtilCipherSetProperty(ctx, NC_ENC_SET_NIP44_NONCE, nonce.data, nonce.size), NC_SUCCESS); - /* Ciper update should return the */ + /* Cipher update should return the */ TEST(NCUtilCipherUpdate(ctx, libCtx, NCByteCastToSecretKey(sendKey.data), &recvPubKey), NC_SUCCESS); NCResult cipherOutputSize = NCUtilCipherGetOutputSize(ctx); TEST(cipherOutputSize, expected.size); - outData.data = (uint8_t*)malloc(cipherOutputSize); - outData.size = (uint32_t)cipherOutputSize; + outData = (uint8_t*)malloc(cipherOutputSize); + TASSERT(outData != NULL); + + /* Read the encrypted payload to test */ + TEST(NCUtilCipherReadOutput(ctx, outData, cipherOutputSize), cipherOutputSize); + + /* Ensure encrypted payload matches */ + TEST(memcmp(outData, expected.data, cipherOutputSize), 0); + + free(outData); + + /* Free encryption memory */ + NCUtilCipherFree(ctx); +} + +static int TestUtilNip44Decryption( + const NCContext* libCtx, + span_t sendKey, + span_t recvKey, + span_t payload, + const char* expectedPt +) +{ + NCPublicKey recvPubKey; + uint8_t* outData; - TASSERT(outData.data != NULL); + ENSURE(NCValidateSecretKey(libCtx, NCByteCastToSecretKey(sendKey.data)) == NC_SUCCESS); + ENSURE(NCGetPublicKey(libCtx, NCByteCastToSecretKey(recvKey.data), &recvPubKey) == NC_SUCCESS); + + /* Alloc cipher in nip44 decryption mode */ + NCUtilCipherContext* ctx = NCUtilCipherAlloc( + NC_ENC_VERSION_NIP44, + NC_UTIL_CIPHER_MODE_DECRYPT | NC_UTIL_CIPHER_ZERO_ON_FREE + ); + + ENSURE(ctx != NULL); + + /* submit encrypted payload for ciphertext */ + TEST(NCUtilCipherInit(ctx, payload.data, payload.size), NC_SUCCESS); + + TEST(NCUtilCipherUpdate(ctx, libCtx, NCByteCastToSecretKey(sendKey.data), &recvPubKey), NC_SUCCESS); + + NCResult plaintextSize = NCUtilCipherGetOutputSize(ctx); + + TEST(plaintextSize, strlen(expectedPt)); + + outData = (uint8_t*)malloc(plaintextSize); + + TASSERT(outData != NULL); /* Read the encrypted payload to test */ - TEST(NCUtilCipherReadOutput(ctx, outData.data, cipherOutputSize), cipherOutputSize); + TEST(NCUtilCipherReadOutput(ctx, outData, plaintextSize), plaintextSize); /* Ensure encrypted payload matches */ - TEST(memcmp(outData.data, expected.data, cipherOutputSize), 0); + TEST(memcmp(outData, expectedPt, plaintextSize), 0); - free(outData.data); + free(outData); /* Free encryption memory */ NCUtilCipherFree(ctx); @@ -695,6 +734,21 @@ static int TestUtilFunctions(const NCContext* libCtx) return 1; } } + { + PRINTL("TEST: NIP-44 util decryption"); + + /* From the nip44 vectors file */ + span_t sendKey = FromHexString("0000000000000000000000000000000000000000000000000000000000000001", sizeof(NCSecretKey)); + span_t recvKey = FromHexString("0000000000000000000000000000000000000000000000000000000000000002", sizeof(NCSecretKey)); + span_t nonce = FromHexString("0000000000000000000000000000000000000000000000000000000000000001", NC_ENCRYPTION_NONCE_SIZE); + span_t payload = FromHexString("02000000000000000000000000000000000000000000000000000000000000000179ed06e5548ad3ff58ca920e6c0b4329f6040230f7e6e5641f20741780f0adc35a09794259929a02bb06ad8e8cf709ee4ccc567e9d514cdf5781af27a3e905e55b1b", 99); + const char* plainText = "a"; + + if (TestUtilNip44Decryption(libCtx, sendKey, recvKey, payload, plainText) != 0) + { + return 1; + } + } PRINTL("\nPASSED: Util functions tests completed") return 0; -- cgit