diff options
author | vnugent <public@vaughnnugent.com> | 2024-07-05 00:03:48 -0400 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2024-07-05 00:03:48 -0400 |
commit | 23fe6e8c8596333c2183f0f4389817087442c551 (patch) | |
tree | 1b87644b34141f9deedf7c655084a3c0d5b22817 /src | |
parent | dc71f861df8929deee300368b88ef47d45560695 (diff) |
push latest utils and changes
Diffstat (limited to 'src')
-rw-r--r-- | src/hkdf.c | 15 | ||||
-rw-r--r-- | src/hkdf.h | 4 | ||||
-rw-r--r-- | src/nc-util.h | 46 | ||||
-rw-r--r-- | src/noscrypt.c | 15 | ||||
-rw-r--r-- | src/noscryptutil.c | 418 |
5 files changed, 475 insertions, 23 deletions
@@ -21,23 +21,10 @@ #include "hkdf.h" -/* Include string for memmove */ -#include <string.h> - #define HKDF_MIN(a, b) (a < b ? a : b) STATIC_ASSERT(HKDF_IN_BUF_SIZE > SHA256_DIGEST_SIZE, "HDK Buffer must be at least the size of the underlying hashing alg output") -static _nc_fn_inline void ncWriteSpanS(span_t* span, uint32_t offset, const uint8_t* data, uint32_t size) -{ - DEBUG_ASSERT2(span != NULL, "Expected span to be non-null") - DEBUG_ASSERT2(data != NULL, "Expected data to be non-null") - DEBUG_ASSERT2(offset + size <= span->size, "Expected offset + size to be less than span size") - - /* Copy data to span */ - memmove(span->data + offset, data, size); -} - static _nc_fn_inline void debugValidateHandler(const struct nc_hkdf_fn_cb_struct* handler) { DEBUG_ASSERT(handler != NULL) @@ -114,7 +101,7 @@ cstatus_t hkdfExpandProcess( DEBUG_ASSERT(tLen <= sizeof(t)); /* write the T buffer back to okm */ - ncWriteSpanS(okm, okmOffset, t, tLen); + ncSpanWrite(*okm, okmOffset, t, tLen); /* shift base okm pointer by T */ okmOffset += tLen; @@ -42,12 +42,12 @@ /* typedefs for hdkf callback functions */ -typedef cstatus_t (*hmac_hash_func)(void* ctx, const cspan_t* data); +typedef cstatus_t (*hmac_hash_fn)(void* ctx, const cspan_t* data); typedef cstatus_t (*hmac_finish_fn)(void* ctx, sha256_t hmacOut32); struct nc_hkdf_fn_cb_struct { - hmac_hash_func update; + hmac_hash_fn update; hmac_finish_fn finish; }; diff --git a/src/nc-util.h b/src/nc-util.h index dd319c7..0647f4c 100644 --- a/src/nc-util.h +++ b/src/nc-util.h @@ -68,6 +68,28 @@ #define _overflow_check(x) #endif +#ifdef NC_EXTREME_COMPAT + + void _nc_memmove(void* dst, const void* src, uint32_t size) + { + uint32_t i; + + for (i = 0; i < size; i++) + { + ((uint8_t*)dst)[i] = ((uint8_t*)src)[i]; + } + } + + #define MEMMOV _nc_memmove + +#else + + /* Include string for memmove */ + #include <string.h> + #define MEMMOV(dst, src, size) memmove(dst, src, size) + +#endif /* NC_EXTREME_COMPAT */ + typedef struct memory_span_struct { uint8_t* data; @@ -92,4 +114,28 @@ static _nc_fn_inline void ncSpanInit(span_t* span, uint8_t* data, uint32_t size) span->size = size; } +static _nc_fn_inline void ncSpanWrite(span_t span, uint32_t offset, const uint8_t* data, uint32_t size) +{ + DEBUG_ASSERT2(span.data != NULL, "Expected span to be non-null") + DEBUG_ASSERT2(data != NULL, "Expected data to be non-null") + DEBUG_ASSERT2(offset + size <= span.size, "Expected offset + size to be less than span size") + + /* Copy data to span */ + MEMMOV(span.data + offset, data, size); +} + +static _nc_fn_inline void ncSpanAppend(span_t span, uint32_t* offset, const uint8_t* data, uint32_t size) +{ + DEBUG_ASSERT2(span.data != NULL, "Expected span to be non-null") + DEBUG_ASSERT2(offset != NULL, "Expected offset to be non-null") + DEBUG_ASSERT2(data != NULL, "Expected data to be non-null") + DEBUG_ASSERT2(*offset + size <= span.size, "Expected offset + size to be less than span size") + + /* Copy data to span */ + MEMMOV(span.data + *offset, data, size); + + /* Increment offset */ + *offset += size; +} + #endif /* !_NC_UTIL_H */
\ No newline at end of file diff --git a/src/noscrypt.c b/src/noscrypt.c index c523262..910f559 100644 --- a/src/noscrypt.c +++ b/src/noscrypt.c @@ -32,10 +32,6 @@ */ #define ZERO_FILL(x, size) ncCryptoSecureZero(x, size) -/* Include string for memmove */ -#include <string.h> -#define MEMMOV(dst, src, size) memmove(dst, src, size) - /* * Validation macros */ @@ -44,7 +40,6 @@ #define CHECK_INVALID_ARG(x, argPos) if(x == NULL) return NCResultWithArgPosition(E_INVALID_ARG, argPos); #define CHECK_NULL_ARG(x, argPos) if(x == NULL) return NCResultWithArgPosition(E_NULL_PTR, argPos); #define CHECK_ARG_RANGE(x, min, max, argPos) if(x < min || x > max) return NCResultWithArgPosition(E_ARGUMENT_OUT_OF_RANGE, argPos); - #define CHECK_CONTEXT_STATE(ctx, argPos) CHECK_INVALID_ARG(ctx->secpCtx, argPos) #else /* empty macros */ #define CHECK_INVALID_ARG(x) @@ -52,6 +47,8 @@ #define CHECK_ARG_RANGE(x, min, max, argPos) #endif /* !NC_DISABLE_INPUT_VALIDATION */ +#define CHECK_CONTEXT_STATE(ctx, argPos) CHECK_INVALID_ARG(ctx->secpCtx, argPos) + /* * Actual, private defintion of the NCContext structure * to allow for future development and ABI backords @@ -449,7 +446,6 @@ NC_EXPORT NCResult NC_CC NCResultWithArgPosition(NCResult err, uint8_t argPositi return -(((NCResult)argPosition << NC_ARG_POSITION_OFFSET) | -err); } - NC_EXPORT int NC_CC NCParseErrorCode(NCResult result, uint8_t* argPositionOut) { NCResult asPositive; @@ -460,7 +456,12 @@ NC_EXPORT int NC_CC NCParseErrorCode(NCResult result, uint8_t* argPositionOut) /* Get the error code from the lower 8 bits and the argument position from the upper 8 bits*/ code = -(asPositive & NC_ERROR_CODE_MASK); - *argPositionOut = (asPositive >> NC_ARG_POSITION_OFFSET) & 0xFF; + + /* Allow argument position assignment to be null */ + if (argPositionOut) + { + *argPositionOut = (asPositive >> NC_ARG_POSITION_OFFSET) & 0xFF; + } return code; } diff --git a/src/noscryptutil.c b/src/noscryptutil.c new file mode 100644 index 0000000..b7723cb --- /dev/null +++ b/src/noscryptutil.c @@ -0,0 +1,418 @@ +/* +* Copyright (c) 2024 Vaughn Nugent +* +* Package: noscrypt +* File: noscryptutil.h +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public License +* as published by the Free Software Foundation; either version 2.1 +* of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with noscrypt. If not, see http://www.gnu.org/licenses/. +*/ + + +#include <noscryptutil.h> +#include "nc-util.h" +#include "nc-crypto.h" + +/* +* Validation macros +*/ + +#ifdef NC_EXTREME_COMPAT + #error "Utilities library must be disabled when using extreme compat mode" +#endif /* NC_EXTREME_COMPAT */ + +#include <stdlib.h> +#include <math.h> + +#define _nc_mem_free(x) if(x != NULL) { free(x); x = NULL; } +#define _nc_mem_alloc(elements, size) calloc(elements, size); + +#ifndef NC_INPUT_VALIDATION_OFF + #define CHECK_INVALID_ARG(x, argPos) if(x == NULL) return NCResultWithArgPosition(E_INVALID_ARG, argPos); + #define CHECK_NULL_ARG(x, argPos) if(x == NULL) return NCResultWithArgPosition(E_NULL_PTR, argPos); + #define CHECK_ARG_RANGE(x, min, max, argPos) if(x < min || x > max) return NCResultWithArgPosition(E_ARGUMENT_OUT_OF_RANGE, argPos); +#else + /* empty macros */ + #define CHECK_INVALID_ARG(x) + #define CHECK_NULL_ARG(x, argPos) + #define CHECK_ARG_RANGE(x, min, max, argPos) +#endif /* !NC_DISABLE_INPUT_VALIDATION */ + + +/* performs a log2 on integer types */ +#define _math_int_log2(x) (int32_t)log2((double)x) + +#define MIN_PADDING_SIZE 0x20 +#define NIP44_VERSION_SIZE 0x01 +#define NIP44_PT_LEN_SIZE 0x02 + +/* Currently were on nip44 version 2 */ +const static uint8_t Nip44VersionValue = 0x02; + +typedef struct nc_util_enc_buffer_state +{ + uint8_t* ciphertext; + uint32_t ciphertextSize; + +} NCCipherTextOutState; + +struct nc_util_enc_struct { + + /* Dynamically allocated during initialization */ + NCCipherTextOutState* outState; + + const uint8_t* plaintext; + + uint32_t plaintextSize; + + NCEncryptionArgs encArgs; +}; + +static _nc_fn_inline int32_t _calcNip44PtPadding(int32_t plaintextSize) +{ + int32_t chunk, nextPower, factor; + + /* + * Taken from https://github.com/nostr-protocol/nips/blob/master/44.md + * + * I believe the idea is to add consisten padding for some better + * disgusing of the plainText data. + */ + + if (plaintextSize <= MIN_PADDING_SIZE) + { + return MIN_PADDING_SIZE; + } + + nextPower = _math_int_log2(plaintextSize - 1); + + nextPower += 1; + + nextPower = 1 << nextPower; + + if (nextPower <= 256) + { + chunk = 32; + } + else + { + chunk = nextPower / 8; + } + + factor = plaintextSize - 1; + + factor /= chunk; + + factor += 1; + + return chunk * factor; +} + +static _nc_fn_inline int32_t _calcNip44TotalOutSize(int32_t inputSize) +{ + int32_t bufferSize; + + /* + * Buffer size for nip44 is calculated as follows: + * 1 byte for the version + * 32 bytes for the nonce + * 2 bytes for the length of the plainText + * ... padding size + * 32 bytes for the MAC + */ + + bufferSize = NIP44_VERSION_SIZE; + + bufferSize += NC_ENCRYPTION_NONCE_SIZE; + + bufferSize += NIP44_PT_LEN_SIZE; + + bufferSize += _calcNip44PtPadding(inputSize); + + bufferSize += NC_ENCRYPTION_MAC_SIZE; + + return bufferSize; +} + +static NCResult _nip44EncryptCompleteCore( + const NCContext* libContext, + const NCSecretKey* sk, + const NCPublicKey* pk, + NCEncryptionArgs encArgs, + span_t cipherText, + span_t plainText +) +{ + + NCResult result; + uint32_t outPos, paddedCtSize; + uint16_t ptSize; + + outPos = 0; + + DEBUG_ASSERT(encArgs.version == NC_ENC_VERSION_NIP44); + + /* Padded size is required to know how large the CT buffer is for encryption */ + paddedCtSize = (int32_t)_calcNip44PtPadding((int32_t)plainText.size); + + /* Start by appending the version number */ + ncSpanAppend(cipherText, &outPos, &Nip44VersionValue, 0x01); + + /* next is nonce data */ + ncSpanAppend(cipherText, &outPos, encArgs.nonceData, NC_ENCRYPTION_NONCE_SIZE); + DEBUG_ASSERT(outPos == 1 + NC_ENCRYPTION_NONCE_SIZE); + + /* + * So this is the tricky part. The encryption operation appens directly + * on the ciphertext segment + * + * All current implementations allow overlapping input and output buffers + * so we can assign the pt segment on the encryption args + */ + + /* + * Since the message size and padding bytes will get encrypted, + * the buffer should currently point to the start of the encryption segment + * + * The size of the data to encrypt is the padded size plus the size of the + * plainText size field. + */ + + encArgs.inputData = (cipherText.data + outPos); + encArgs.outputData = (cipherText.data + outPos); + encArgs.dataSize = paddedCtSize + sizeof(uint16_t); /* Plaintext + pt size must be encrypted */ + + ptSize = (uint16_t)plainText.size; + + /* Can write the plainText size to buffer now */ + ncSpanAppend(cipherText, &outPos, &ptSize, sizeof(uint16_t)); + + /* concat plainText */ + ncSpanAppend(cipherText, &outPos, plainText.data, plainText.size); + + /* Time to perform encryption operation */ + result = NCEncrypt(libContext, sk, pk, &encArgs); + + if (result == NC_SUCCESS) + { + + } +} + +static NCResult _nip44EncryptCompleteCore( + NCUtilEncryptionContext* encCtx, + const NCContext* libContext, + const NCSecretKey* sk, + const NCPublicKey* pk +) +{ + span_t cipherText, plainText; + + /* Set up spans */ + ncSpanInit( + &cipherText, + encCtx->outState->ciphertext, + encCtx->outState->ciphertextSize + ); + + ncSpanInit( + &plainText, + encCtx->plaintext, + encCtx->plaintextSize + ); + + return _nip44EncryptCompleteCore( + libContext, + sk, + pk, + encCtx->encArgs, + cipherText, + plainText + ); +} + +NC_EXPORT NCResult NC_CC NCUtilGetEncryptionPaddedSize(uint32_t encVersion, int32_t plaintextSize) +{ + int32_t paddingSize; + + CHECK_ARG_RANGE(plaintextSize, 0, INT32_MAX, 1) + + switch (encVersion) + { + default: + return E_VERSION_NOT_SUPPORTED; + + case NC_ENC_VERSION_NIP04: + return plaintextSize; + + case NC_ENC_VERSION_NIP44: + paddingSize = _calcNip44PtPadding(plaintextSize); + + DEBUG_ASSERT(paddingSize > 0) + + return (NCResult)(paddingSize); + } +} + +NC_EXPORT NCResult NC_CC NCUtilGetEncryptionBufferSize(uint32_t encVersion, int32_t plaintextSize) +{ + int32_t totalSize; + + CHECK_ARG_RANGE(plaintextSize, 0, INT32_MAX, 1) + + switch (encVersion) + { + default: + return E_VERSION_NOT_SUPPORTED; + + /* + * NIP-04 simply uses AES to 1:1 encrypt the plainText + * to ciphertext. + */ + case NC_ENC_VERSION_NIP04: + return plaintextSize; + + case NC_ENC_VERSION_NIP44: + totalSize = _calcNip44TotalOutSize(plaintextSize); + + DEBUG_ASSERT(totalSize > 0) + + return (NCResult)(totalSize); + + } +} + + +NC_EXPORT NCUtilEncryptionContext* NC_CC NCUtilAllocEncryptionContext(uint32_t encVersion) +{ + NCUtilEncryptionContext* encCtx; + + /* + * Alloc context on heap + */ + encCtx = (NCUtilEncryptionContext*)_nc_mem_alloc(1, sizeof(NCUtilEncryptionContext)); + + if (encCtx != NULL) + { + encCtx->encArgs.version = encVersion; + } + + return encCtx; +} + +NC_EXPORT void NC_CC NCUtilFreeEncryptionContext(NCUtilEncryptionContext* encCtx) +{ + if (!encCtx) + { + return; + } + + /* Free output buffers */ + _nc_mem_free(encCtx->outState); + + /* context can be released */ + _nc_mem_free(encCtx); +} + +NC_EXPORT NCResult NC_CC NCUtilInitEncryptionContext( + NCUtilEncryptionContext* encCtx, + const uint8_t* plainText, + uint32_t plainTextSize +) +{ + + NCResult outputSize; + NCCipherTextOutState* output; + + CHECK_NULL_ARG(encCtx, 0) + CHECK_NULL_ARG(plainText, 1) + CHECK_ARG_RANGE(plainTextSize, 0, INT32_MAX, 2) + + /* + * The output state must not have alraedy been allocated + */ + if (encCtx->outState) + { + return E_INVALID_ARG; + } + + /* + * Calculate the correct output size to store the encryption + * data for the given cipher version + */ + outputSize = NCUtilGetEncryptionBufferSize(encCtx->encArgs.version, plainTextSize); + + if (outputSize <= 0) + { + return outputSize; + } + + /*Alloc output buffer within the struct */ + output = (NCCipherTextOutState*)_nc_mem_alloc(sizeof(NCCipherTextOutState) + (int)outputSize, 1); + + if (!output) + { + return E_OUT_OF_MEMORY; + } + + /* set cipertext buffer to end of the structure memory */ + output->ciphertext = (uint8_t*)(output + 1); + output->ciphertextSize = outputSize; + + encCtx->outState = output; + encCtx->plaintext = plainText; + encCtx->plaintextSize = plainTextSize; + + return NC_SUCCESS; +} + +NC_EXPORT NCResult NC_CC NCUtilGetEncryptedSize(const NCUtilEncryptionContext* encCtx) +{ + CHECK_NULL_ARG(encCtx, 0); + + return (NCResult)(encCtx->outState->ciphertextSize); +} + +NC_EXPORT NCResult NC_CC NCUtilReadEncryptedData( + const NCUtilEncryptionContext* encCtx, + uint8_t* output, + uint32_t outputSize +) +{ + CHECK_NULL_ARG(encCtx, 0) + CHECK_NULL_ARG(output, 1) + CHECK_ARG_RANGE(outputSize, 0, INT32_MAX, 2) + + if (outputSize < encCtx->outState->ciphertextSize) + { + return E_OPERATION_FAILED; + } + + MEMMOV(output, encCtx->outState->ciphertext, encCtx->outState->ciphertextSize); + + return (NCResult)encCtx->outState->ciphertextSize; +} + +NC_EXPORT NCResult NCUtilSetEncryptionProperty( + NCUtilEncryptionContext* ctx, + uint32_t property, + uint8_t* value, + uint32_t valueLen +) +{ + + CHECK_NULL_ARG(ctx, 0) + + /* All other arguments are verified */ + return NCSetEncryptionPropertyEx(&ctx->encArgs, property, value, valueLen); +} |