diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/noscrypt.c | 80 | ||||
-rw-r--r-- | src/noscrypt.h | 84 |
2 files changed, 83 insertions, 81 deletions
diff --git a/src/noscrypt.c b/src/noscrypt.c index 8aeeefe..3719a08 100644 --- a/src/noscrypt.c +++ b/src/noscrypt.c @@ -32,18 +32,13 @@ #include <mbedtls/sha256.h> #include <mbedtls/constant_time.h> -/* Non win platforms may need an inline override */ -#if !defined(_NC_IS_WINDOWS) && !defined(inline) - #define inline __inline__ -#endif /* !IS_WINDOWS */ - /* NULL */ #ifndef NULL #define NULL ((void*)0) #endif /* !NULL */ -#define CHACHA_NONCE_SIZE 12 /* Size of 12 is set by the cipher spec */ -#define CHACHA_KEY_SIZE 32 /* Size of 32 is set by the cipher spec */ +#define CHACHA_NONCE_SIZE 0x0cu /* Size of 12 is set by the cipher spec */ +#define CHACHA_KEY_SIZE 0x20u /* Size of 32 is set by the cipher spec */ /* * Local macro for secure zero buffer fill @@ -99,6 +94,12 @@ #define STATIC_ASSERT(x, m) #endif +/* +* The Nip44 constant salt +* https://github.com/nostr-protocol/nips/blob/master/44.md#encryption +*/ +static const uint8_t Nip44ConstantSalt[8] = { 0x6e, 0x69, 0x70, 0x34, 0x34, 0x2d, 0x76, 0x32 }; + struct shared_secret { uint8_t value[NC_SHARED_SEC_SIZE]; }; @@ -131,7 +132,7 @@ STATIC_ASSERT(sizeof(struct nc_expand_keys) == sizeof(struct message_key), "Expe * Internal helper functions to do common structure conversions */ -static inline int _convertToXonly(const NCContext* ctx, const NCPublicKey* compressedPubKey, secp256k1_xonly_pubkey* xonly) +static _nc_fn_inline int _convertToXonly(const NCContext* ctx, const NCPublicKey* compressedPubKey, secp256k1_xonly_pubkey* xonly) { DEBUG_ASSERT2(ctx != NULL, "Expected valid context") DEBUG_ASSERT2(compressedPubKey != NULL, "Expected a valid public 32byte key structure") @@ -157,14 +158,13 @@ static int _convertToPubKey(const NCContext* ctx, const NCPublicKey* compressedP MEMMOV((compressed + 1), compressedPubKey, sizeof(NCPublicKey)); result = secp256k1_ec_pubkey_parse(ctx->secpCtx, pubKey, compressed, sizeof(compressed)); - - /* zero everything */ + ZERO_FILL(compressed, sizeof(compressed)); return result; } -static inline int _convertFromXonly(const NCContext* ctx, const secp256k1_xonly_pubkey* xonly, NCPublicKey* compressedPubKey) +static _nc_fn_inline int _convertFromXonly(const NCContext* ctx, const secp256k1_xonly_pubkey* xonly, NCPublicKey* compressedPubKey) { DEBUG_ASSERT2(ctx != NULL, "Expected valid context") DEBUG_ASSERT2(xonly != NULL, "Expected valid X-only secp256k1 public key structure.") @@ -239,15 +239,14 @@ static NCResult _computeSharedSecret( &_edhHashFuncInternal, NULL ); - - /* Clean up sensitive data */ + ZERO_FILL(&pubKey, sizeof(pubKey)); /* Result should be 1 on success */ - return result > 0 ? NC_SUCCESS : E_OPERATION_FAILED; + return result == 1 ? NC_SUCCESS : E_OPERATION_FAILED; } -static inline const mbedtls_md_info_t* _getSha256MdInfo(void) +static _nc_fn_inline const mbedtls_md_info_t* _getSha256MdInfo(void) { const mbedtls_md_info_t* info; /* Get sha256 md info for hdkf operations */ @@ -257,7 +256,7 @@ static inline const mbedtls_md_info_t* _getSha256MdInfo(void) } -static inline NCResult _computeConversationKey( +static _nc_fn_inline NCResult _computeConversationKey( const NCContext* ctx, const mbedtls_md_info_t* mdInfo, const struct shared_secret* sharedSecret, @@ -265,7 +264,7 @@ static inline NCResult _computeConversationKey( ) { 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") @@ -281,7 +280,7 @@ static inline NCResult _computeConversationKey( (uint8_t*)ck /* Output produces a conversation key */ ); - /* Return success if the hkdf operation was successful */ + /* 0 is a successful hdkf result */ return opResult == 0 ? NC_SUCCESS : E_OPERATION_FAILED; } @@ -289,7 +288,7 @@ static inline NCResult _computeConversationKey( /* * Explode the hkdf into the chacha key, chacha nonce, and hmac key. */ -static inline const struct nc_expand_keys* _expandKeysFromHkdf(const struct message_key* hkdf) +static _nc_fn_inline const struct nc_expand_keys* _expandKeysFromHkdf(const struct message_key* hkdf) { return (const struct nc_expand_keys*)hkdf; } @@ -309,7 +308,7 @@ static int _chachaEncipher(const struct nc_expand_keys* keys, NCCryptoData* args ); } -static inline NCResult _getMessageKey( +static _nc_fn_inline NCResult _getMessageKey( const mbedtls_md_info_t* mdInfo, const struct conversation_key* converstationKey, const uint8_t* nonce, @@ -337,7 +336,7 @@ static inline NCResult _getMessageKey( return result == 0 ? NC_SUCCESS : E_OPERATION_FAILED; } -static inline NCResult _encryptEx( +static _nc_fn_inline NCResult _encryptEx( const NCContext* ctx, const mbedtls_md_info_t* mdINfo, const struct conversation_key* ck, @@ -354,8 +353,8 @@ static inline NCResult _encryptEx( DEBUG_ASSERT2(args != NULL, "Expected valid encryption args") DEBUG_ASSERT2(mdINfo != NULL, "Expected valid md info struct") DEBUG_ASSERT2(hmacKey != NULL, "Expected valid hmac key buffer") - - /* Failure, bail out */ + + /* Message key will be derrived on every encryption call */ if ((result = _getMessageKey(mdINfo, ck, args->nonce32, NC_ENCRYPTION_NONCE_SIZE, &messageKey)) != NC_SUCCESS) { goto Cleanup; @@ -371,13 +370,12 @@ static inline NCResult _encryptEx( result = (NCResult)_chachaEncipher(expandedKeys, args); Cleanup: - /* Clean up sensitive data */ ZERO_FILL(&messageKey, sizeof(messageKey)); return result; } -static inline NCResult _decryptEx( +static _nc_fn_inline NCResult _decryptEx( const NCContext* ctx, const mbedtls_md_info_t* mdInfo, const struct conversation_key* ck, @@ -391,9 +389,8 @@ static inline NCResult _decryptEx( 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(mdInfo != NULL, "Expected valid md info struct") - - /* Failure to get message keys, bail out */ + DEBUG_ASSERT2(mdInfo != NULL, "Expected valid md info struct") + if ((result = _getMessageKey(mdInfo, ck, args->nonce32, NC_ENCRYPTION_NONCE_SIZE, &messageKey)) != NC_SUCCESS) { goto Cleanup; @@ -406,13 +403,12 @@ static inline NCResult _decryptEx( result = (NCResult) _chachaEncipher(cipherKeys, args); Cleanup: - /* Clean up sensitive data */ ZERO_FILL(&messageKey, sizeof(messageKey)); return result; } -static inline int _computeHmac( +static _nc_fn_inline int _computeHmac( const uint8_t key[NC_HMAC_KEY_SIZE], const NCMacVerifyArgs* args, uint8_t hmacOut[NC_ENCRYPTION_MAC_SIZE] @@ -440,7 +436,6 @@ static NCResult _verifyMacEx( ) { NCResult result; - const mbedtls_md_info_t* sha256Info; const struct nc_expand_keys* keys; struct message_key messageKey; uint8_t hmacOut[NC_ENCRYPTION_MAC_SIZE]; @@ -449,14 +444,11 @@ static NCResult _verifyMacEx( DEBUG_ASSERT2(conversationKey != NULL, "Expected valid conversation key") DEBUG_ASSERT2(args != NULL, "Expected valid mac verification args") - sha256Info = _getSha256MdInfo(); - /* - * We need to get the message key in order to - * get the required hmac key + * Message key is again required for the hmac verification */ result = _getMessageKey( - sha256Info, + _getSha256MdInfo(), (struct conversation_key*)conversationKey, args->nonce32, NC_ENCRYPTION_NONCE_SIZE, @@ -484,7 +476,6 @@ static NCResult _verifyMacEx( result = mbedtls_ct_memcmp(hmacOut, args->mac32, NC_ENCRYPTION_MAC_SIZE) == 0 ? NC_SUCCESS : E_OPERATION_FAILED; Cleanup: - /* Clean up sensitive data */ ZERO_FILL(&messageKey, sizeof(messageKey)); ZERO_FILL(hmacOut, sizeof(hmacOut)); @@ -510,7 +501,10 @@ NC_EXPORT NCResult NC_CC NCInitContext( ctx->secpCtx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - /* Randomize once on init */ + /* + * Randomize once on init, users can call reinit to + * randomize again as needed. + */ return secp256k1_context_randomize(ctx->secpCtx, entropy) ? NC_SUCCESS : E_INVALID_ARG; } @@ -520,8 +514,8 @@ NC_EXPORT NCResult NC_CC NCReInitContext( ) { CHECK_NULL_ARG(ctx, 0) - CHECK_INVALID_ARG(ctx->secpCtx, 0) CHECK_NULL_ARG(entropy, 1) + CHECK_INVALID_ARG(ctx->secpCtx, 0) /* Only randomize again */ return secp256k1_context_randomize(ctx->secpCtx, entropy) ? NC_SUCCESS : E_INVALID_ARG; @@ -612,7 +606,7 @@ NC_EXPORT NCResult NC_CC NCSignDigest( CHECK_NULL_ARG(digest32, 3) CHECK_NULL_ARG(sig64, 4) - /* Generate the keypair */ + /* Fill keypair structure from the callers secret key */ if (secp256k1_keypair_create(ctx->secpCtx, &keyPair, sk->key) != 1) { return E_INVALID_ARG; @@ -628,8 +622,7 @@ NC_EXPORT NCResult NC_CC NCSignDigest( /* Verify the signature is valid */ result = secp256k1_schnorrsig_verify(ctx->secpCtx, sig64, digest32, 32, &xonly); - - /* cleanup any sensitive data */ + ZERO_FILL(&keyPair, sizeof(keyPair)); ZERO_FILL(&xonly, sizeof(xonly)); @@ -689,8 +682,7 @@ NC_EXPORT NCResult NC_CC NCVerifyDigest( /* Verify the signature */ result = secp256k1_schnorrsig_verify(ctx->secpCtx, sig64, digest32, 32, &xonly); - - /* cleanup any sensitive data */ + ZERO_FILL(&xonly, sizeof(xonly)); return result == 1 ? NC_SUCCESS : E_INVALID_ARG; diff --git a/src/noscrypt.h b/src/noscrypt.h index 6a40171..e5dd7aa 100644 --- a/src/noscrypt.h +++ b/src/noscrypt.h @@ -62,32 +62,37 @@ #endif /* !NOSCRYPT_EXPORTING */ #endif /* !NC_EXPORT */ +#if defined(_NC_IS_WINDOWS) || defined(inline) || defined(__clang__) + #define _nc_fn_inline inline +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 allows usage of inline keyword */ + #define _nc_fn_inline inline +#elif defined(__GNUC__) || defined(__GNUG__) + #define _nc_fn_inline __inline__ +#else + #define _nc_fn_inline + #pragma message("Warning: No inline keyword defined for this compiler") +#endif + /* * CONSTANTS */ -#define BIP340_PUBKEY_HEADER_BYTE 0x02 -#define NIP44_MESSAGE_KEY_SIZE 76 -#define NC_ENCRYPTION_NONCE_SIZE 32 -#define NC_SEC_KEY_SIZE 32 -#define NC_PUBKEY_SIZE 32 -#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 BIP340_PUBKEY_HEADER_BYTE 0x02 +#define NIP44_MESSAGE_KEY_SIZE 0x4c /*32 + 12 + 32 */ +#define NC_ENCRYPTION_NONCE_SIZE 0x20 +#define NC_SEC_KEY_SIZE 0x20 +#define NC_PUBKEY_SIZE 0x20 +#define NC_SHARED_SEC_SIZE 0x20 +#define NC_CONV_KEY_SIZE 0x20 +#define NC_HMAC_KEY_SIZE 0x20 +#define NC_ENCRYPTION_MAC_SIZE 0x20 #define NC_MESSAGE_KEY_SIZE NIP44_MESSAGE_KEY_SIZE /* * From spec * https://github.com/nostr-protocol/nips/blob/master/44.md#decryption */ -#define NIP44_MIN_ENC_MESSAGE_SIZE 1 -#define NIP44_MAX_ENC_MESSAGE_SIZE 65535 - -/* -* The Nip44 constant salt -* https://github.com/nostr-protocol/nips/blob/master/44.md#encryption -*/ -static const uint8_t Nip44ConstantSalt[8] = { 0x6e, 0x69, 0x70, 0x34, 0x34, 0x2d, 0x76, 0x32 }; +#define NIP44_MIN_ENC_MESSAGE_SIZE 0x01 +#define NIP44_MAX_ENC_MESSAGE_SIZE 0xffff /* * ERROR CODES @@ -100,15 +105,15 @@ static const uint8_t Nip44ConstantSalt[8] = { 0x6e, 0x69, 0x70, 0x34, 0x34, 0x2d * operations that return a value count. */ -#define NC_ARG_POSITION_OFFSET 8 -#define NC_ERROR_CODE_MASK 0xFF +#define NC_ARG_POSITION_OFFSET 0x08 +#define NC_ERROR_CODE_MASK 0xFF -#define NC_SUCCESS 0 -#define E_NULL_PTR -1 -#define E_INVALID_ARG -2 -#define E_INVALID_CONTEXT -3 -#define E_ARGUMENT_OUT_OF_RANGE -4 -#define E_OPERATION_FAILED -5 +#define NC_SUCCESS 0x00 +#define E_NULL_PTR -1 +#define E_INVALID_ARG -2 +#define E_INVALID_CONTEXT -3 +#define E_ARGUMENT_OUT_OF_RANGE -4 +#define E_OPERATION_FAILED -5 /* A compressed resul/return value, negative values are failure, 0 is success and positive values are @@ -123,7 +128,7 @@ typedef struct secret_key_struct { uint8_t key[NC_SEC_KEY_SIZE]; -}NCSecretKey; +} NCSecretKey; /* An x-only secp256k1 public key @@ -132,7 +137,7 @@ typedef struct xonly_pubkey_struct { uint8_t key[NC_PUBKEY_SIZE]; -}NCPublicKey; +} NCPublicKey; /* An opaque full library context object @@ -141,7 +146,7 @@ typedef struct ctx_struct { void* secpCtx; -}NCContext; +} NCContext; /* * The encryption arguments structure. This structure is used to pass @@ -196,7 +201,7 @@ typedef struct nc_mac_verify { * @param key The 32byte buffer to cast * @return A pointer to the NCSecretKey struct */ -static inline NCSecretKey* NCToSecKey(uint8_t key[NC_SEC_KEY_SIZE]) +static _nc_fn_inline NCSecretKey* NCToSecKey(uint8_t key[NC_SEC_KEY_SIZE]) { return (NCSecretKey*)key; } @@ -206,12 +211,12 @@ static inline NCSecretKey* NCToSecKey(uint8_t key[NC_SEC_KEY_SIZE]) * @param key The 32byte buffer to cast * @return A pointer to the NCPublicKey struct */ -static inline NCPublicKey* NCToPubKey(uint8_t key[NC_PUBKEY_SIZE]) +static _nc_fn_inline NCPublicKey* NCToPubKey(uint8_t key[NC_PUBKEY_SIZE]) { return (NCPublicKey*)key; } -static inline NCResult NCResultWithArgPosition(NCResult err, uint8_t argPosition) +static _nc_fn_inline NCResult NCResultWithArgPosition(NCResult err, uint8_t argPosition) { return -(((NCResult)argPosition << NC_ARG_POSITION_OFFSET) | -err); } @@ -220,17 +225,22 @@ static inline NCResult NCResultWithArgPosition(NCResult err, uint8_t argPosition * Parses an error code and returns the error code and the argument position that caused the error. * @param result The error code to parse -* @param code A pointer to the error code to write to -* @param argPosition A pointer to the argument position to write to +* @param argPositionOut A pointer to the argument position to write to +* @return The error code */ -NC_EXPORT void NC_CC NCParseErrorCode(NCResult result, int* code, uint8_t* argPosition) +static _nc_fn_inline int NCParseErrorCode(NCResult result, uint8_t* argPositionOut) { /* convert result to a positive value*/ - NCResult asPositive = -result; + NCResult asPositive; + int code; + + asPositive = -result; /* Get the error code from the lower 8 bits and the argument position from the upper 8 bits*/ - *code = -(asPositive & NC_ERROR_CODE_MASK); - *argPosition = (asPositive >> NC_ARG_POSITION_OFFSET) & 0xFF; + code = -(asPositive & NC_ERROR_CODE_MASK); + *argPositionOut = (asPositive >> NC_ARG_POSITION_OFFSET) & 0xFF; + + return code; } /*-------------------------------------- |