aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-02-09 22:48:35 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2024-02-09 22:48:35 -0500
commit9f85fff3b9f25da7410569ea94f994b88feb3910 (patch)
tree6d9399d132671a01bcd32eb045fb90a42803cf85
parentaa5113741bb419b02d6ea416bba571fa3d65db46 (diff)
feat: added/update MAC functions to sign or verify nip44 payload
-rw-r--r--src/noscrypt.c182
-rw-r--r--src/noscrypt.h71
-rw-r--r--tests/test.c29
3 files changed, 232 insertions, 50 deletions
diff --git a/src/noscrypt.c b/src/noscrypt.c
index 9ab1c6e..14f959b 100644
--- a/src/noscrypt.c
+++ b/src/noscrypt.c
@@ -27,6 +27,7 @@
#include <mbedtls/platform_util.h>
#include <mbedtls/md.h>
#include <mbedtls/hkdf.h>
+#include <mbedtls/hmac_drbg.h>
#include <mbedtls/chacha20.h>
#include <mbedtls/sha256.h>
@@ -82,7 +83,7 @@
struct nc_expand_keys {
uint8_t chacha_key[CHACHA_KEY_SIZE];
uint8_t chacha_nonce[CHACHA_NONCE_SIZE];
- uint8_t hamc_key[NC_HMAC_KEY_SIZE];
+ uint8_t hmac_key[NC_HMAC_KEY_SIZE];
};
struct shared_secret {
@@ -286,7 +287,7 @@ static inline void _expandKeysFromHkdf(const struct message_key* hkdf, struct nc
hkdfBytes += CHACHA_NONCE_SIZE; //Offset by nonce size
MEMMOV(
- keys->hamc_key,
+ keys->hmac_key,
hkdfBytes,
NC_HMAC_KEY_SIZE
);
@@ -376,7 +377,7 @@ static inline NCResult _encryptEx(
_expandKeysFromHkdf(&messageKey, &cipherKeys);
//Copy the hmac key into the args
- MEMMOV(hmacKey, cipherKeys.hamc_key, NC_HMAC_KEY_SIZE);
+ MEMMOV(hmacKey, cipherKeys.hmac_key, NC_HMAC_KEY_SIZE);
//CHACHA20
result = _chachaEncipher(&cipherKeys, args);
@@ -428,41 +429,6 @@ Cleanup:
}
/*
-* Compute the sha256 digest of the data. This function should always return 0
-* on success.
-*/
-static inline int _computeSha256Digest(const uint8_t* data, size_t length, uint8_t digest[32])
-{
- int result;
- mbedtls_sha256_context sha256;
-
- DEBUG_ASSERT2(data != NULL, "Expected valid data buffer")
- DEBUG_ASSERT2(digest != NULL, "Expected valid digest buffer")
-
- //Init the sha256 context
- mbedtls_sha256_init(&sha256);
-
- //starting context should never fail
- result = mbedtls_sha256_starts(&sha256, 0);
- DEBUG_ASSERT2(result == 0, "Expected sha256 starts to return 0")
-
- //may fail if the data is invalid
- if ((result = mbedtls_sha256_update(&sha256, data, length)) != 0)
- {
- goto Cleanup;
- }
-
- //Finishing context should never fail
- result = mbedtls_sha256_finish(&sha256, digest);
-
-Cleanup:
- //Always free the context
- mbedtls_sha256_free(&sha256);
-
- return result;
-}
-
-/*
* EXTERNAL API FUNCTIONS
*/
NC_EXPORT uint32_t NC_CC NCGetContextStructSize(void)
@@ -626,7 +592,7 @@ NC_EXPORT NCResult NC_CC NCSignData(
CHECK_NULL_ARG(sig64, 5)
//Compute sha256 of the data before signing
- if(_computeSha256Digest(data, dataSize, digest) != 0)
+ if(mbedtls_sha256(data, dataSize, digest, 0) != 0)
{
return E_INVALID_ARG;
}
@@ -683,7 +649,7 @@ NC_EXPORT NCResult NC_CC NCVerifyData(
CHECK_NULL_ARG(sig64, 4)
//Compute sha256 of the data before verifying
- if (_computeSha256Digest(data, dataSize, digest) != 0)
+ if (mbedtls_sha256(data, dataSize, digest, 0) != 0)
{
return E_INVALID_ARG;
}
@@ -922,3 +888,139 @@ Cleanup:
return result;
}
+NC_EXPORT NCResult NCComputeMac(
+ const NCContext* ctx,
+ const uint8_t hmacKey[NC_HMAC_KEY_SIZE],
+ const uint8_t* payload,
+ size_t payloadSize,
+ uint8_t hmacOut[NC_ENCRYPTION_MAC_SIZE]
+)
+{
+ CHECK_NULL_ARG(ctx, 0)
+ CHECK_INVALID_ARG(ctx->secpCtx, 0)
+ CHECK_NULL_ARG(hmacKey, 1)
+ CHECK_NULL_ARG(payload, 2)
+ CHECK_ARG_RANGE(payloadSize, 1, UINT32_MAX, 3)
+ CHECK_NULL_ARG(hmacOut, 4)
+
+ /*
+ * Compute the hmac of the data using the supplied hmac key
+ */
+ return mbedtls_md_hmac(
+ _getSha256MdInfo(),
+ hmacKey,
+ NC_HMAC_KEY_SIZE,
+ payload,
+ payloadSize,
+ hmacOut
+ ) == 0 ? NC_SUCCESS : E_OPERATION_FAILED;
+}
+
+NC_EXPORT NCResult NC_CC NCVerifyMacEx(
+ const NCContext* ctx,
+ const uint8_t conversationKey[NC_CONV_KEY_SIZE],
+ NCMacVerifyArgs* args
+)
+{
+ NCResult result;
+ const mbedtls_md_info_t* sha256Info;
+ struct message_key messageKey;
+ struct nc_expand_keys keys;
+ uint8_t hmacOut[NC_ENCRYPTION_MAC_SIZE];
+
+ CHECK_NULL_ARG(ctx, 0)
+ CHECK_INVALID_ARG(ctx->secpCtx, 0)
+ CHECK_NULL_ARG(conversationKey, 1)
+ CHECK_NULL_ARG(args, 2)
+
+ CHECK_INVALID_ARG(args->mac, 2)
+ CHECK_INVALID_ARG(args->payload, 2)
+ CHECK_INVALID_ARG(args->nonce, 2)
+ CHECK_ARG_RANGE(args->payloadSize, NIP44_MIN_ENC_MESSAGE_SIZE, NIP44_MAX_ENC_MESSAGE_SIZE, 2)
+
+ sha256Info = _getSha256MdInfo();
+
+ /*
+ * We need to get the message key in order to
+ * get the required hmac key
+ */
+ result = _getMessageKey(
+ sha256Info,
+ (struct conversation_key*)conversationKey,
+ args->nonce,
+ NC_ENCRYPTION_NONCE_SIZE,
+ &messageKey
+ );
+
+ if(result != NC_SUCCESS)
+ {
+ goto Cleanup;
+ }
+
+ /* Expand keys to get the hmac-key */
+ _expandKeysFromHkdf(&messageKey, &keys);
+
+ /*
+ * Compute the hmac of the data using the computed hmac key
+ */
+ if(mbedtls_md_hmac(sha256Info, keys.hmac_key, NC_HMAC_KEY_SIZE, args->payload, args->payloadSize, hmacOut) != 0)
+ {
+ result = E_OPERATION_FAILED;
+ goto Cleanup;
+ }
+
+ /* constant time compare the macs */
+
+ result = 0;
+
+ for (int i = 0; i < NC_ENCRYPTION_MAC_SIZE; i++)
+ {
+ result |= args->mac[i] - hmacOut[i];
+ }
+
+Cleanup:
+ /* Clean up sensitive data */
+ ZERO_FILL(&messageKey, sizeof(messageKey));
+ ZERO_FILL(&keys, sizeof(keys));
+ ZERO_FILL(hmacOut, NC_ENCRYPTION_MAC_SIZE);
+
+ return result;
+}
+
+NC_EXPORT NCResult NC_CC NCVerifyMac(
+ const NCContext* ctx,
+ const NCSecretKey* sk,
+ const NCPublicKey* pk,
+ NCMacVerifyArgs* args
+)
+{
+ CHECK_NULL_ARG(ctx, 0)
+ CHECK_INVALID_ARG(ctx->secpCtx, 0)
+ CHECK_NULL_ARG(sk, 1)
+ CHECK_NULL_ARG(pk, 2)
+ CHECK_NULL_ARG(args, 3)
+
+ NCResult result;
+ struct shared_secret sharedSecret;
+ struct conversation_key conversationKey;
+
+ /* Computed the shared point so we can get the converstation key */
+ if ((result = _computeSharedSecret(ctx, sk, pk, &sharedSecret)) != NC_SUCCESS)
+ {
+ goto Cleanup;
+ }
+
+ if ((result = _computeConversationKey(ctx, _getSha256MdInfo(), &sharedSecret, &conversationKey)) != NC_SUCCESS)
+ {
+ goto Cleanup;
+ }
+
+ result = NCVerifyMacEx(ctx, (uint8_t*)&conversationKey, args);
+
+Cleanup:
+ /* Clean up sensitive data */
+ ZERO_FILL(&sharedSecret, sizeof(sharedSecret));
+ ZERO_FILL(&conversationKey, sizeof(conversationKey));
+
+ return result;
+} \ No newline at end of file
diff --git a/src/noscrypt.h b/src/noscrypt.h
index 387d856..983206c 100644
--- a/src/noscrypt.h
+++ b/src/noscrypt.h
@@ -73,6 +73,7 @@
#define NC_SHARED_SEC_SIZE 32
#define NC_CONV_KEY_SIZE 32
#define NC_HMAC_KEY_SIZE 32
+#define NC_ENCRYPTION_MAC_SIZE 32
#define NC_MESSAGE_KEY_SIZE NIP44_MESSAGE_KEY_SIZE
/*
@@ -168,6 +169,27 @@ typedef struct nc_encryption_struct {
} NCCryptoData;
/*
+* A structure for Nip44 message authentication code verification. This structure
+* is used to pass arguments to the NCVerifyMac and NCVerifyMacEx functions.
+*/
+typedef struct nc_mac_verify {
+
+ /* The message authentication code certifying the Nip44 payload */
+ const uint8_t mac[NC_ENCRYPTION_MAC_SIZE];
+
+ /* The nonce used for the original message encryption */
+ const uint8_t nonce[NC_ENCRYPTION_NONCE_SIZE];
+
+ /* The message payload data */
+ const uint8_t* payload;
+
+ /* The size of the payload data */
+ size_t payloadSize;
+
+} NCMacVerifyArgs;
+
+
+/*
API FUNCTIONS
*/
@@ -397,6 +419,22 @@ NC_EXPORT NCResult NC_CC NCDecrypt(
NCCryptoData* args
);
+/*
+* High level api for verifying a Nip44 message authentication code using a secret key
+and a public key. Use the NCVerifyMacEx functions for extended verification functionality.
+* @param ctx A pointer to an existing library context
+* @param sk A pointer to the secret key
+* @param pk A pointer to the 32byte compressed public key (x-only serialized public key)
+* @param args A pointer to the mac verification arguments
+* @return NC_SUCCESS if the operation was successful, otherwise an error code. Use NCParseErrorCode to
+* the error code and positional argument that caused the error
+*/
+NC_EXPORT NCResult NC_CC NCVerifyMac(
+ const NCContext* ctx,
+ const NCSecretKey* sk,
+ const NCPublicKey* pk,
+ NCMacVerifyArgs* args
+);
/*--------------------------------------
* EXTENDED ENCRYPTION API
@@ -481,4 +519,37 @@ NC_EXPORT NCResult NC_CC NCDecryptEx(
NCCryptoData* args
);
+/*
+* Verifies a Nip44 message authentication code using the given conversation key.
+* @param ctx A pointer to the existing library context
+* @param conversationKey A pointer to the 32byte conversation key
+* @param args A pointer to the mac verification arguments
+* @return NC_SUCCESS if the operation was successful, otherwise an error code. Use NCParseErrorCode to
+* the error code and positional argument that caused the error.
+*/
+NC_EXPORT NCResult NC_CC NCVerifyMacEx(
+ const NCContext* ctx,
+ const uint8_t conversationKey[NC_CONV_KEY_SIZE],
+ NCMacVerifyArgs* args
+);
+
+/*
+* Computes a message authentication code for a given payload using the given hmacKey and writes the
+* mac to the hmacOut buffer.
+* @param ctx A pointer to the existing library context
+* @param hmacKey A pointer to the 32byte hmac key
+* @param payload A pointer to the payload data buffer
+* @param payloadSize The size of the payload data buffer
+* @param hmacOut A pointer to the 32byte buffer to write the mac to
+* @return NC_SUCCESS if the operation was successful, otherwise an error code. Use NCParseErrorCode to
+* the error code and positional argument that caused the error.
+*/
+NC_EXPORT NCResult NCComputeMac(
+ const NCContext* ctx,
+ const uint8_t hmacKey[NC_HMAC_KEY_SIZE],
+ const uint8_t* payload,
+ size_t payloadSize,
+ uint8_t hmacOut[NC_ENCRYPTION_MAC_SIZE]
+);
+
#endif // !NOSCRYPT_H
diff --git a/tests/test.c b/tests/test.c
index 6c73466..0c35c21 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -243,7 +243,7 @@ static int TestPublicApiArgumentValidation(void)
NCSecretKey secKey;
NCPublicKey pubKey;
NCCryptoData cryptoData;
- uint8_t hmacOut[NC_HMAC_KEY_SIZE];
+ uint8_t hmacKeyOut[NC_HMAC_KEY_SIZE];
PRINTL("TEST: Public API argument validation tests\n")
@@ -303,25 +303,25 @@ static int TestPublicApiArgumentValidation(void)
cryptoData.outputData = sig64;
FillRandomData(&cryptoData.nonce, 32);
- TEST(NCEncrypt(NULL, &secKey, &pubKey, hmacOut, &cryptoData), ARG_ERROR_POS_0)
- TEST(NCEncrypt(&ctx, NULL, &pubKey, hmacOut, &cryptoData), ARG_ERROR_POS_1)
- TEST(NCEncrypt(&ctx, &secKey, NULL, hmacOut, &cryptoData), ARG_ERROR_POS_2)
+ TEST(NCEncrypt(NULL, &secKey, &pubKey, hmacKeyOut, &cryptoData), ARG_ERROR_POS_0)
+ TEST(NCEncrypt(&ctx, NULL, &pubKey, hmacKeyOut, &cryptoData), ARG_ERROR_POS_1)
+ TEST(NCEncrypt(&ctx, &secKey, NULL, hmacKeyOut, &cryptoData), ARG_ERROR_POS_2)
TEST(NCEncrypt(&ctx, &secKey, &pubKey, NULL, &cryptoData), ARG_ERROR_POS_3)
- TEST(NCEncrypt(&ctx, &secKey, &pubKey, hmacOut, NULL), ARG_ERROR_POS_4)
+ TEST(NCEncrypt(&ctx, &secKey, &pubKey, hmacKeyOut, NULL), ARG_ERROR_POS_4)
//Test invalid data size
cryptoData.dataSize = 0;
- TEST(NCEncrypt(&ctx, &secKey, &pubKey, hmacOut, &cryptoData), ARG_RAMGE_ERROR_POS_4)
+ TEST(NCEncrypt(&ctx, &secKey, &pubKey, hmacKeyOut, &cryptoData), ARG_RAMGE_ERROR_POS_4)
//Test null input data
cryptoData.dataSize = 32;
cryptoData.inputData = NULL;
- TEST(NCEncrypt(&ctx, &secKey, &pubKey, hmacOut, &cryptoData), ARG_INVALID_ERROR_POS_4)
+ TEST(NCEncrypt(&ctx, &secKey, &pubKey, hmacKeyOut, &cryptoData), ARG_INVALID_ERROR_POS_4)
//Test null output data
cryptoData.inputData = zero32;
cryptoData.outputData = NULL;
- TEST(NCEncrypt(&ctx, &secKey, &pubKey, hmacOut, &cryptoData), ARG_INVALID_ERROR_POS_4)
+ TEST(NCEncrypt(&ctx, &secKey, &pubKey, hmacKeyOut, &cryptoData), ARG_INVALID_ERROR_POS_4)
//Decrypt
cryptoData.dataSize = 32;
@@ -345,8 +345,17 @@ static int TestPublicApiArgumentValidation(void)
//Test null output data
cryptoData.inputData = zero32;
cryptoData.outputData = NULL;
- TEST(NCDecrypt(&ctx, &secKey, &pubKey, &cryptoData), ARG_INVALID_ERROR_POS_3)
-
+ TEST(NCDecrypt(&ctx, &secKey, &pubKey, &cryptoData), ARG_INVALID_ERROR_POS_3)
+
+ {
+ uint8_t hmacDataOut[NC_ENCRYPTION_MAC_SIZE];
+ TEST(NCComputeMac(NULL, hmacKeyOut, zero32, 32, hmacDataOut), ARG_ERROR_POS_0)
+ TEST(NCComputeMac(&ctx, NULL, zero32, 32, hmacDataOut), ARG_ERROR_POS_1)
+ TEST(NCComputeMac(&ctx, hmacKeyOut, NULL, 32, hmacDataOut), ARG_ERROR_POS_2)
+ TEST(NCComputeMac(&ctx, hmacKeyOut, zero32, 0, hmacDataOut), ARG_RAMGE_ERROR_POS_3)
+ TEST(NCComputeMac(&ctx, hmacKeyOut, zero32, 32, NULL), ARG_ERROR_POS_4)
+ }
+
PRINTL("\nPASSED: Public API argument validation tests completed\n")
return 0;