aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt14
-rw-r--r--CMakePresets.json24
-rw-r--r--include/noscrypt.h2
-rw-r--r--include/noscryptutil.h76
-rw-r--r--src/hkdf.c15
-rw-r--r--src/hkdf.h4
-rw-r--r--src/nc-util.h46
-rw-r--r--src/noscrypt.c15
-rw-r--r--src/noscryptutil.c418
-rw-r--r--tests/test.c53
10 files changed, 630 insertions, 37 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 53fbe29..493b18a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,6 +17,7 @@ project(
set(_NC_PROJ_NAME "noscrypt")
option(NC_BUILD_TESTS "Build tests" OFF)
+option(NC_ENABLE_UTILS "Enables the sidecar utility library" OFF)
option(NC_DISABLE_INPUT_VALIDATION "Disables public function input validation" OFF)
option(NC_FETCH_MBEDTLS "Fetch Mbed-TLS from it's source repository locally" OFF)
option(NC_FETCH_SECP256K1 "Fetch and locally build secp256k1 source code" ON)
@@ -94,6 +95,17 @@ set(NOSCRYPT_HEADERS
"src/nc-crypto.h"
)
+#if utils are enabled, add the source files
+if(NC_ENABLE_UTILS)
+ list(APPEND NOSCRYPT_SRCS "src/noscryptutil.c")
+ list(APPEND NOSCRYPT_HEADERS "include/noscryptutil.h")
+
+ #notify the project that utils are enabled
+ list(APPEND NC_PROJ_DEFINTIONS NC_ENABLE_UTILS)
+
+ message(STATUS "Utilities libraries are enabled")
+endif()
+
#static/shared library
add_library(${_NC_PROJ_NAME} SHARED ${NOSCRYPT_SRCS} ${NOSCRYPT_HEADERS})
add_library(${_NC_PROJ_NAME}_static STATIC ${NOSCRYPT_SRCS} ${NOSCRYPT_HEADERS})
@@ -366,11 +378,13 @@ if(NC_BUILD_TESTS)
#add test executable and link to shared library for more realistic usage
add_executable(nctest tests/test.c)
target_link_libraries(nctest ${_NC_PROJ_NAME})
+
target_include_directories(nctest PRIVATE include)
target_include_directories(nctest PRIVATE src) #allow access to internal headers
#enable c11 for testing
target_compile_features(nctest PRIVATE c_std_11)
+ target_compile_definitions(nctest PRIVATE ${NC_PROJ_DEFINTIONS})
enable_testing()
diff --git a/CMakePresets.json b/CMakePresets.json
index 63ccfec..1b6d907 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -15,7 +15,7 @@
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
- }
+ },
},
{
"name": "x64-debug",
@@ -27,7 +27,8 @@
},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
- "NC_BUILD_TESTS": true
+ "NC_BUILD_TESTS": true,
+ "NC_ENABLE_UTILS": true
}
},
{
@@ -44,13 +45,18 @@
"CRYPTO_LIB": "openssl"
}
},
- {
- "name": "x64-release",
- "displayName": "x64 Release",
- "inherits": "x64-debug",
- "cacheVariables": {
- "CMAKE_BUILD_TYPE": "Release"
- }
+ {
+ "name": "x64-release",
+ "displayName": "x64 Release",
+ "inherits": "windows-base",
+ "architecture": {
+ "value": "x64",
+ "strategy": "external"
+ },
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Release",
+ "NC_ENABLE_UTILS": true
}
+ }
]
}
diff --git a/include/noscrypt.h b/include/noscrypt.h
index bdfaa9f..8b39f17 100644
--- a/include/noscrypt.h
+++ b/include/noscrypt.h
@@ -228,7 +228,7 @@ NC_EXPORT NCResult NC_CC NCResultWithArgPosition(NCResult err, uint8_t argPositi
* 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 argPositionOut A pointer to the argument position to write to
+* @param argPositionOut A pointer to the argument position to write to (optionall, set to NULL of unobserved)
* @return The error code
*/
NC_EXPORT int NC_CC NCParseErrorCode(NCResult result, uint8_t* argPositionOut);
diff --git a/include/noscryptutil.h b/include/noscryptutil.h
new file mode 100644
index 0000000..1a98698
--- /dev/null
+++ b/include/noscryptutil.h
@@ -0,0 +1,76 @@
+/*
+* 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/.
+*/
+
+/*
+* noscrypt is a an open-source, strict C89 library that performs the basic
+* cryptographic operations found in the Nostr protocol. It is designed to be
+* portable and easy to use in any C89 compatible environment. It is also designed
+*/
+
+#pragma once
+
+#ifndef NOSCRYPTUTIL_H
+#define NOSCRYPTUTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include "noscrypt.h"
+
+#define E_OUT_OF_MEMORY -10
+
+typedef struct nc_util_enc_struct NCUtilEncryptionContext;
+
+NC_EXPORT NCResult NC_CC NCUtilGetEncryptionPaddedSize(uint32_t encVersion, int32_t plaintextSize);
+
+NC_EXPORT NCResult NC_CC NCUtilGetEncryptionBufferSize(uint32_t encVersion, int32_t plaintextSize);
+
+NC_EXPORT NCUtilEncryptionContext* NC_CC NCUtilAllocEncryptionContext(uint32_t encVersion);
+
+NC_EXPORT NCResult NC_CC NCUtilInitEncryptionContext(
+ NCUtilEncryptionContext* encCtx,
+ const uint8_t* plainText,
+ uint32_t plainTextSize
+);
+
+NC_EXPORT void NC_CC NCUtilFreeEncryptionContext(NCUtilEncryptionContext* encCtx);
+
+NC_EXPORT NCResult NC_CC NCUtilGetEncryptedSize(const NCUtilEncryptionContext* encCtx);
+
+NC_EXPORT NCResult NC_CC NCUtilReadEncryptedData(
+ const NCUtilEncryptionContext* encCtx,
+ uint8_t* output,
+ uint32_t outputSize
+);
+
+NC_EXPORT NCResult NCUtilSetEncryptionProperty(
+ NCUtilEncryptionContext* ctx,
+ uint32_t property,
+ uint8_t* value,
+ uint32_t valueLen
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NOSCRYPTUTIL_H */ \ No newline at end of file
diff --git a/src/hkdf.c b/src/hkdf.c
index 0d91d14..cff7d60 100644
--- a/src/hkdf.c
+++ b/src/hkdf.c
@@ -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;
diff --git a/src/hkdf.h b/src/hkdf.h
index 460e203..2e3a55e 100644
--- a/src/hkdf.h
+++ b/src/hkdf.h
@@ -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);
+}
diff --git a/tests/test.c b/tests/test.c
index 5feae79..3833e7b 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -101,6 +101,10 @@ static int InitKepair(const NCContext* context, NCSecretKey* secKey, NCPublicKey
static int TestKnownKeys(const NCContext* context);
static int TestCorrectEncryption(const NCContext* context);
+#ifdef NC_ENABLE_UTILS
+static int TestUtilFunctions(void);
+#endif
+
#ifndef NC_INPUT_VALIDATION_OFF
static int TestPublicApiArgumentValidation(void);
#endif
@@ -167,6 +171,13 @@ static int RunTests(void)
return 1;
}
+#ifdef NC_ENABLE_UTILS
+ if (TestUtilFunctions() != 0)
+ {
+ return 1;
+ }
+#endif
+
TEST(NCDestroyContext(ctx), NC_SUCCESS)
PRINTL("\nSUCCESS All tests passed")
@@ -277,6 +288,8 @@ static int TestPublicApiArgumentValidation()
NCEncryptionArgs cryptoData;
+ PRINTL("TEST: Public API argument validation tests")
+
{
/*
* Test arguments for encryption properties
@@ -332,6 +345,7 @@ static int TestPublicApiArgumentValidation()
TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP04_KEY, testBuff32, NC_NIP04_AES_KEY_SIZE - 1), ARG_RANGE_ERROR_POS_3)
}
+ /* Prep the crypto structure for proper usage */
ENSURE(NCSetEncryptionProperty(&cryptoData, NC_ENC_SET_VERSION, NC_ENC_VERSION_NIP44) == NC_SUCCESS);
ENSURE(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP44_NONCE, nonce, sizeof(nonce)) == NC_SUCCESS);
ENSURE(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP44_MAC_KEY, hmacKeyOut, sizeof(hmacKeyOut)) == NC_SUCCESS);
@@ -339,14 +353,13 @@ static int TestPublicApiArgumentValidation()
/* Assign the encryption material */
ENSURE(NCSetEncryptionData(&cryptoData, zero32, sig64, sizeof(zero32)) == NC_SUCCESS);
- PRINTL("TEST: Public API argument validation tests")
FillRandomData(ctxRandom, 32);
FillRandomData(nonce, sizeof(nonce));
/*
* Alloc context structure on the heap before use.
- * THIS WILL LEAK IN THE CURRENT CONFIG ALWAYS FEE UNDER NORMAL CONDITIONS
+ * THIS WILL LEAK IN THE CURRENT CONFIG ALWAYS FREE UNDER NORMAL CONDITIONS
*/
ctx = (NCContext*)malloc(NCGetContextStructSize());
TASSERT(ctx != NULL)
@@ -540,6 +553,8 @@ static int TestCorrectEncryption(const NCContext* context)
NCEncryptionArgs cryptoData;
NCMacVerifyArgs macVerifyArgs;
+ PRINTL("TEST: Correct encryption")
+
ENSURE(NCSetEncryptionProperty(&cryptoData, NC_ENC_SET_VERSION, NC_ENC_VERSION_NIP44) == NC_SUCCESS);
ENSURE(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP44_NONCE, nonce, sizeof(nonce)) == NC_SUCCESS);
ENSURE(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP44_MAC_KEY, hmacKeyOut, NC_HMAC_KEY_SIZE) == NC_SUCCESS);
@@ -552,8 +567,6 @@ static int TestCorrectEncryption(const NCContext* context)
macVerifyArgs.payload = cipherText;
macVerifyArgs.payloadSize = TEST_ENC_DATA_SIZE;
- PRINTL("TEST: Correct encryption")
-
/* init a sending and receiving key */
FillRandomData(&secKey1, sizeof(NCSecretKey));
FillRandomData(&secKey2, sizeof(NCSecretKey));
@@ -590,6 +603,38 @@ static int TestCorrectEncryption(const NCContext* context)
return 0;
}
+#ifdef NC_ENABLE_UTILS
+
+#include <noscryptutil.h>
+
+/*
+* 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 int32_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 int32_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 TestUtilFunctions(void)
+{
+ PRINTL("TEST: Util functions")
+
+ for (int i = 0; i < 24; i++)
+ {
+ int32_t totalSize = _padTestExpected[i] + 67;
+
+ TEST(NCUtilGetEncryptionPaddedSize(NC_ENC_VERSION_NIP44, _padTestActual[i]), _padTestExpected[i]);
+ TEST(NCUtilGetEncryptionBufferSize(NC_ENC_VERSION_NIP44, _padTestActual[i]), totalSize);
+ }
+
+ PRINTL("PASSED: Util functions tests completed")
+ return 0;
+}
+
+#endif
+
static void FillRandomData(void* pbBuffer, size_t length)
{