From 7c8f910e5be9a1d86af5bdcb7e51e8092cc06cf6 Mon Sep 17 00:00:00 2001 From: vnugent Date: Wed, 7 Aug 2024 15:11:19 -0400 Subject: feat: added NCEncryptionGetIvSize() function and helpers --- src/noscrypt.c | 71 +++++++++++++++++++++++++++++------------------------- src/noscryptutil.c | 47 +++++++++++++++++++++++++++--------- 2 files changed, 74 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/src/noscrypt.c b/src/noscrypt.c index deadca6..fededaf 100644 --- a/src/noscrypt.c +++ b/src/noscrypt.c @@ -310,7 +310,7 @@ static _nc_fn_inline NCResult _encryptNip44Ex( result = NC_SUCCESS; - ncSpanInitC(&nonceSpan, args->nonceData, NC_ENCRYPTION_NONCE_SIZE); + ncSpanInitC(&nonceSpan, args->nonceData, NC_NIP44_IV_SIZE); /* Message key will be derrived on every encryption call */ if (_getMessageKey(ck, nonceSpan, &messageKey) != CSTATUS_OK) @@ -344,13 +344,14 @@ static _nc_fn_inline NCResult _decryptNip44Ex(const NCContext* ctx, const struct struct message_key messageKey; const struct nc_expand_keys* cipherKeys; - DEBUG_ASSERT2(ctx != NULL, "Expected valid context") - DEBUG_ASSERT2(ck != NULL, "Expected valid conversation key") - DEBUG_ASSERT2(args != NULL, "Expected valid encryption args") + DEBUG_ASSERT2(ctx != NULL, "Expected valid context"); + DEBUG_ASSERT2(ck != NULL, "Expected valid conversation key"); + DEBUG_ASSERT2(args != NULL, "Expected valid encryption args"); + DEBUG_ASSERT(args->version == NC_ENC_VERSION_NIP44); result = NC_SUCCESS; - ncSpanInitC(&nonceSpan, args->nonceData, NC_ENCRYPTION_NONCE_SIZE); + ncSpanInitC(&nonceSpan, args->nonceData, NC_NIP44_IV_SIZE); if (_getMessageKey(ck, nonceSpan, &messageKey) != CSTATUS_OK) { @@ -401,7 +402,7 @@ static NCResult _verifyMacEx( DEBUG_ASSERT2(conversationKey != NULL, "Expected valid conversation key") DEBUG_ASSERT2(args != NULL, "Expected valid mac verification args") - ncSpanInitC(&nonceSpan, args->nonce32, NC_ENCRYPTION_NONCE_SIZE); + ncSpanInitC(&nonceSpan, args->nonce32, NC_NIP44_IV_SIZE); ncSpanInitC(&payloadSpan, args->payload, args->payloadSize); /* @@ -979,7 +980,7 @@ Cleanup: return result; } -NC_EXPORT NCResult NCComputeMac( +NC_EXPORT NCResult NC_CC NCComputeMac( const NCContext* ctx, const uint8_t hmacKey[NC_HMAC_KEY_SIZE], const uint8_t* payload, @@ -1069,13 +1070,14 @@ Cleanup: #define ENSURE_ENC_MODE(args, mode) if(args->version != mode) return E_VERSION_NOT_SUPPORTED; -NC_EXPORT NCResult NCSetEncryptionPropertyEx( +NC_EXPORT NCResult NC_CC NCEncryptionSetPropertyEx( NCEncryptionArgs* args, uint32_t property, uint8_t* value, uint32_t valueLen ) { + uint32_t ivSize; CHECK_NULL_ARG(args, 0) CHECK_NULL_ARG(value, 2) @@ -1091,22 +1093,6 @@ NC_EXPORT NCResult NCSetEncryptionPropertyEx( return NC_SUCCESS; - case NC_ENC_SET_NIP04_IV: - /* - * The safest way to store the nip04 IV is in the nonce - * field. An IV is essentially a nonce. A secure random - * number used to encrypt the first block of a CBC chain. - */ - - CHECK_ARG_RANGE(valueLen, AES_IV_SIZE, UINT32_MAX, 3) - - ENSURE_ENC_MODE(args, NC_ENC_VERSION_NIP04) - - args->nonceData = value; - - return NC_SUCCESS; - - case NC_ENC_SET_NIP04_KEY: /* * The AES key is stored in the hmac key field, since @@ -1122,13 +1108,17 @@ NC_EXPORT NCResult NCSetEncryptionPropertyEx( return NC_SUCCESS; - case NC_ENC_SET_NIP44_NONCE: + case NC_ENC_SET_IV: + + ivSize = NCEncryptionGetIvSize(args->version); - /* Nonce buffer must be at least the size, max doesnt matter */ - CHECK_ARG_RANGE(valueLen, NC_ENCRYPTION_NONCE_SIZE, UINT32_MAX, 3) + /* Gaurd invalid version */ + if (ivSize == 0) + { + return E_VERSION_NOT_SUPPORTED; + } - /* Nonce is only used in nip44 mode */ - ENSURE_ENC_MODE(args, NC_ENC_VERSION_NIP44) + CHECK_ARG_RANGE(valueLen, ivSize, ivSize, 3) args->nonceData = value; @@ -1155,13 +1145,13 @@ NC_EXPORT NCResult NCSetEncryptionPropertyEx( return E_INVALID_ARG; } -NC_EXPORT NCResult NCSetEncryptionProperty( +NC_EXPORT NCResult NC_CC NCEncryptionSetProperty( NCEncryptionArgs* args, uint32_t property, uint32_t value ) { - return NCSetEncryptionPropertyEx( + return NCEncryptionSetPropertyEx( args, property, (uint8_t*)&value, @@ -1169,7 +1159,7 @@ NC_EXPORT NCResult NCSetEncryptionProperty( ); } -NC_EXPORT NCResult NCSetEncryptionData( +NC_EXPORT NCResult NC_CC NCEncryptionSetData( NCEncryptionArgs* args, const uint8_t* input, uint8_t* output, @@ -1186,4 +1176,19 @@ NC_EXPORT NCResult NCSetEncryptionData( args->dataSize = dataSize; return NC_SUCCESS; -} \ No newline at end of file +} + +NC_EXPORT uint32_t NC_CC NCEncryptionGetIvSize(uint32_t version) +{ + switch (version) + { + case NC_ENC_VERSION_NIP04: + return NC_NIP04_IV_SIZE; + + case NC_ENC_VERSION_NIP44: + return NC_NIP44_IV_SIZE; + + default: + return 0; + } +} diff --git a/src/noscryptutil.c b/src/noscryptutil.c index 4cee2c3..0d7a55c 100644 --- a/src/noscryptutil.c +++ b/src/noscryptutil.c @@ -37,6 +37,7 @@ #define MIN_PADDING_SIZE 0x20u #define NIP44_VERSION_SIZE 0x01u #define NIP44_PT_LEN_SIZE sizeof(uint16_t) +#define NIP44_NONCE_SIZE NC_NIP44_IV_SIZE /* * minimum size for a valid nip44 payload @@ -200,7 +201,7 @@ static _nc_fn_inline uint32_t _calcNip44TotalOutSize(uint32_t inputSize) bufferSize = NIP44_VERSION_SIZE; - bufferSize += NC_ENCRYPTION_NONCE_SIZE; + bufferSize += NIP44_NONCE_SIZE; bufferSize += NIP44_PT_LEN_SIZE; @@ -267,7 +268,7 @@ static _nc_fn_inline int _nip44ParseSegments( *nonce = ncSpanSliceC( payload, NIP44_VERSION_SIZE, - NC_ENCRYPTION_NONCE_SIZE + NIP44_NONCE_SIZE ); /* @@ -293,8 +294,8 @@ static _nc_fn_inline int _nip44ParseSegments( */ *cipherText = ncSpanSliceC( payload, - NIP44_VERSION_SIZE + NC_ENCRYPTION_NONCE_SIZE, - payload.size - (NIP44_VERSION_SIZE + NC_ENCRYPTION_NONCE_SIZE + NC_ENCRYPTION_MAC_SIZE) + NIP44_VERSION_SIZE + NIP44_NONCE_SIZE, + payload.size - (NIP44_VERSION_SIZE + NIP44_NONCE_SIZE + NC_ENCRYPTION_MAC_SIZE) ); return 1; @@ -357,12 +358,23 @@ static NCResult _nip44EncryptCompleteCore( ZERO_FILL(hmacKeyOut, sizeof(hmacKeyOut)); + /* Get the nonce/iv size so we know how much nonce data to write */ + result = NCUtilCipherGetIvSize(state); + DEBUG_ASSERT(result > 0); + /* Start by appending the version number */ ncSpanAppend(message, &outPos, Nip44VersionValue, sizeof(Nip44VersionValue)); /* next is nonce data */ - ncSpanAppend(message, &outPos, encArgs.nonceData, NC_ENCRYPTION_NONCE_SIZE); - DEBUG_ASSERT(outPos == 1 + NC_ENCRYPTION_NONCE_SIZE); + ncSpanAppend(message, &outPos, encArgs.nonceData, (uint32_t)result); + + /* + * Assert the output points to the end of the nonce segment + * for nip44 this is exactly 33 bytes. This assert also doubles + * to check the output of NCUtilCipherGetIvSize() to ensure + * it's returning the correct size for nip44 + */ + DEBUG_ASSERT(outPos == 1 + NIP44_NONCE_SIZE); /* * Assign the hmac key from the stack buffer. Since the args structure @@ -372,7 +384,7 @@ static NCResult _nip44EncryptCompleteCore( * addresses. */ - result = NCSetEncryptionPropertyEx( + result = NCEncryptionSetPropertyEx( &encArgs, NC_ENC_SET_NIP44_MAC_KEY, hmacKeyOut, @@ -397,7 +409,7 @@ static NCResult _nip44EncryptCompleteCore( * plainText size field. */ - result = NCSetEncryptionData( + result = NCEncryptionSetData( &encArgs, ncSpanGetOffset(message, outPos), /* in place encryption */ ncSpanGetOffset(message, outPos), @@ -517,7 +529,7 @@ static NCResult _nip44DecryptCompleteCore( if ((state->_flags & NC_UTIL_CIPHER_MAC_NO_VERIFY) == 0) { DEBUG_ASSERT(ncSpanGetSizeC(macValue) == NC_ENCRYPTION_MAC_SIZE); - DEBUG_ASSERT(ncSpanGetSizeC(macData) > NC_ENCRYPTION_NONCE_SIZE + MIN_PADDING_SIZE); + DEBUG_ASSERT(ncSpanGetSizeC(macData) > NIP44_NONCE_SIZE + MIN_PADDING_SIZE); /* Assign the mac data to the mac verify args */ macArgs.mac32 = ncSpanGetOffsetC(macValue, 0); @@ -550,7 +562,7 @@ static NCResult _nip44DecryptCompleteCore( DEBUG_ASSERT2(cipherText.size >= MIN_PADDING_SIZE, "Cipertext segment was parsed incorrectly. Too small"); - result = NCSetEncryptionData( + result = NCEncryptionSetData( &encArgs, ncSpanGetOffsetC(cipherText, 0), ncSpanGetOffset(output, 0), /*decrypt ciphertext and write directly to the output buffer */ @@ -852,7 +864,7 @@ NC_EXPORT NCResult NCUtilCipherSetProperty( CHECK_NULL_ARG(ctx, 0) /* All other arguments are verified */ - return NCSetEncryptionPropertyEx( + return NCEncryptionSetPropertyEx( &ctx->encArgs, property, value, @@ -908,3 +920,16 @@ NC_EXPORT NCResult NC_CC NCUtilCipherUpdate( return E_VERSION_NOT_SUPPORTED; } } + +NC_EXPORT NCResult NC_CC NCUtilCipherGetIvSize(const NCUtilCipherContext* encCtx) +{ + uint32_t ivSize; + + CHECK_NULL_ARG(encCtx, 0); + + ivSize = NCEncryptionGetIvSize(encCtx->encArgs.version); + + return ivSize == 0 + ? E_VERSION_NOT_SUPPORTED + : (NCResult)ivSize; +} -- cgit