aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt31
-rw-r--r--Taskfile.yaml53
-rw-r--r--include/noscrypt.h2
-rw-r--r--include/noscryptutil.h4
-rw-r--r--src/hkdf.c30
-rw-r--r--src/hkdf.h6
-rw-r--r--src/nc-crypto.c34
-rw-r--r--src/nc-crypto.h8
-rw-r--r--src/nc-util.h78
-rw-r--r--src/noscrypt.c12
-rw-r--r--src/noscryptutil.c451
-rw-r--r--src/providers/bcrypt.c20
-rw-r--r--src/providers/mbedtls.c42
-rw-r--r--tests/hex.h7
-rw-r--r--tests/test.c19
15 files changed, 469 insertions, 328 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 493b18a..6dad383 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -143,21 +143,6 @@ target_include_directories(${_NC_PROJ_NAME}_static SYSTEM PUBLIC vendor/secp256k
#
#############################################
-#try to load openssl quietly in order to check for its availability
-find_package(OpenSSL QUIET)
-
-#setup default linking to crypto libraries for certain plaftorms.
-#Windows defaults to bcrypt, openssl otherwise if installed
-if(CRYPTO_LIB STREQUAL "")
- if(MSVC)
- set(CRYPTO_LIB "bcrypt")
- elseif(OPENSSL_FOUND)
- set(CRYPTO_LIB "openssl")
- endif()
-
- message(STATUS "No crypto library was specified, defaulting to ${CRYPTO_LIB}")
-endif()
-
#Include mbedtls if enabled
if(NC_FETCH_MBEDTLS)
@@ -186,6 +171,22 @@ if(NC_FETCH_MBEDTLS)
endif()
+#try to load openssl quietly in order to check for its availability
+find_package(OpenSSL QUIET)
+
+#setup default linking to crypto libraries for certain plaftorms.
+#Windows defaults to bcrypt, openssl otherwise if installed
+if(CRYPTO_LIB STREQUAL "")
+ if(MSVC)
+ set(CRYPTO_LIB "bcrypt")
+ elseif(OPENSSL_FOUND)
+ set(CRYPTO_LIB "openssl")
+ endif()
+
+ message(STATUS "No crypto library was specified, defaulting to ${CRYPTO_LIB}")
+endif()
+
+
#if mbedtls linking is enabled target the library
if(CRYPTO_LIB STREQUAL "mbedtls")
diff --git a/Taskfile.yaml b/Taskfile.yaml
index a79921c..93ea182 100644
--- a/Taskfile.yaml
+++ b/Taskfile.yaml
@@ -14,6 +14,7 @@ version: '3'
vars:
CMAKE_BUILD_DIR: 'build/{{ OS }}'
+ TEST_EXE_NAME: 'nctest'
tasks:
@@ -29,14 +30,6 @@ tasks:
- task: build-internal
vars: { CMAKE_TEST_STATUS: 'ON', BUILD_CONFIG: 'Debug' }
- build-internal:
- internal: true
- cmds:
- - cmake -S . -B{{.CMAKE_BUILD_DIR}} -DCMAKE_BUILD_TYPE={{.BUILD_CONFIG}} -DNC_BUILD_TESTS={{ .CMAKE_TEST_STATUS }} {{.CLI_ARGS}}
- - cmake --build {{.CMAKE_BUILD_DIR}} --config {{.BUILD_CONFIG}}
- - cmd: echo "Build complete. Your files can be found in the {{.CMAKE_BUILD_DIR}} directory"
- silent: true
-
#available to users and vnbuild runner
test:
desc: "Builds a local copy of the library in a debug configuration, then runs the test executable"
@@ -44,6 +37,37 @@ tasks:
- task: build-debug
- cmd: cd {{.CMAKE_BUILD_DIR}} && ctest -C Debug --verbose
+ test-mbedtls:
+ desc: "Builds and runs tests for noscrypt using the mbedtls crypto library for the current platform"
+ cmds:
+ - task: build-internal
+ vars:
+ CMAKE_TEST_STATUS: 'ON'
+ BUILD_CONFIG: 'Debug'
+ CLI_ARGS: '-DNC_FETCH_MBEDTLS=ON {{.CLI_ARGS}}' #fetches and enabled medtls
+ - cmd: cd {{.CMAKE_BUILD_DIR}} && ctest -C Debug --verbose
+
+ test-dev:
+ desc: "Re-runs compilation phase and test execution"
+ cmds:
+ - task: compile
+ vars: { BUILD_CONFIG: 'Debug' }
+ - cmd: cd {{.CMAKE_BUILD_DIR}} && ctest -C Debug --verbose --output-on-failure
+
+ compile:
+ internal: true
+ cmds:
+ - cmake --build {{.CMAKE_BUILD_DIR}} --config {{.BUILD_CONFIG}}
+
+ build-internal:
+ internal: true
+ cmds:
+ - cmake -S . -B{{.CMAKE_BUILD_DIR}} -DCMAKE_BUILD_TYPE={{.BUILD_CONFIG}} -DNC_BUILD_TESTS={{ .CMAKE_TEST_STATUS }} {{.CLI_ARGS}}
+ - task: compile
+ vars: { BUILD_CONFIG: '{{.BUILD_CONFIG}}' }
+ - cmd: echo "Build complete. Your files can be found in the {{.CMAKE_BUILD_DIR}} directory"
+ silent: true
+
install:
desc: "Uses cmake to install the library on your system"
cmds:
@@ -115,17 +139,26 @@ tasks:
desc: "Packs up the project source code and creates a tarball in the builds binary directory"
vars:
TARGET_SOURCE: '{{.PROJECT_DIR}}/{{.BINARY_DIR}}/{{.PROJECT_NAME}}-src.tgz'
- SOURCE_FILES: 'CMakeLists.txt src include license tests vendor readme.md Taskfile.yaml'
+ SOURCE_FILES: [ CMakeLists.txt, Taskfile.yaml, src, include, license, tests, vendor, readme.md, CMakePresets.json ]
cmds:
#tar up the source
- - tar -czf "{{.TARGET_SOURCE}}" {{.SOURCE_FILES}}
+ - tar -czf "{{.TARGET_SOURCE}}" {{ .SOURCE_FILES | join " " }}
#################################
#
# DEV TASKS
#
#################################
+
+ dev-gdb-test:
+ platforms: [ linux ]
+ desc: "Starts a new gdb session on the test executable"
+ interactive: true
+ cmds:
+ - task: compile
+ vars: { BUILD_CONFIG: 'Debug' }
+ - cmd: gdb '{{.CMAKE_BUILD_DIR}}/{{.TEST_EXE_NAME}}'
dev-update-deps:
desc: "Updates vendored projects files (headers mostly) from their source repositories to the latest version"
diff --git a/include/noscrypt.h b/include/noscrypt.h
index 8b39f17..b91bc2b 100644
--- a/include/noscrypt.h
+++ b/include/noscrypt.h
@@ -58,7 +58,7 @@ extern "C" {
#ifdef _NC_IS_WINDOWS
#define NC_EXPORT __declspec(dllimport)
#else
- #define NC_EXPORT
+ #define NC_EXPORT extern
#endif /* _NC_IS_WINDOWS */
#endif /* !NOSCRYPT_EXPORTING */
#endif /* !NC_EXPORT */
diff --git a/include/noscryptutil.h b/include/noscryptutil.h
index 13b9231..a5e460f 100644
--- a/include/noscryptutil.h
+++ b/include/noscryptutil.h
@@ -39,11 +39,13 @@ extern "C" {
#define E_CIPHER_INVALID_FORMAT -11
#define E_CIPHER_BAD_NONCE -12
#define E_CIPHER_MAC_INVALID -13
+#define E_CIPHER_NO_OUTPUT -14
#define NC_UTIL_CIPHER_MODE_ENCRYPT 0x00u
#define NC_UTIL_CIPHER_MODE_DECRYPT 0x01u
#define NC_UTIL_CIPHER_ZERO_ON_FREE 0x02u
#define NC_UTIL_CIPHER_MAC_NO_VERIFY 0x04u
+#define NC_UTIL_CIPHER_REUSEABLE 0x08u
/*
* The encryption context structure. This structure is used to store the state
@@ -166,7 +168,7 @@ NC_EXPORT NCResult NC_CC NCUtilCipherGetFlags(const NCUtilCipherContext* ctx);
* so the exact same operation should happen if called again.
*/
NC_EXPORT NCResult NC_CC NCUtilCipherUpdate(
- const NCUtilCipherContext* encCtx,
+ NCUtilCipherContext* encCtx,
const NCContext* libContext,
const NCSecretKey* sk,
const NCPublicKey* pk
diff --git a/src/hkdf.c b/src/hkdf.c
index cff7d60..ab661de 100644
--- a/src/hkdf.c
+++ b/src/hkdf.c
@@ -42,16 +42,15 @@ static _nc_fn_inline void debugValidateHandler(const struct nc_hkdf_fn_cb_struct
cstatus_t hkdfExpandProcess(
const struct nc_hkdf_fn_cb_struct* handler,
void* ctx,
- const cspan_t* info,
- span_t* okm
+ cspan_t info,
+ span_t okm
)
{
cstatus_t result;
-
- uint8_t counter;
+ cspan_t tSpan, counterSpan;
uint32_t tLen, okmOffset;
+ uint8_t counter[1];
uint8_t t[HKDF_IN_BUF_SIZE];
- cspan_t tSpan, counterSpan;
debugValidateHandler(handler);
@@ -59,18 +58,18 @@ cstatus_t hkdfExpandProcess(
tLen = 0; /* T(0) is an empty string(zero length) */
okmOffset = 0;
- counter = 1; /* counter is offset by 1 for init */
+ counter[0] = 1; /* counter is offset by 1 for init */
result = CSTATUS_FAIL; /* Start in fail state */
/* counter as a span */
- ncSpanInitC(&counterSpan, &counter, sizeof(counter));
+ ncSpanInitC(&counterSpan, counter, sizeof(counter));
/* Compute T(N) = HMAC(prk, T(n-1) | info | n) */
- while (okmOffset < okm->size)
+ while (okmOffset < okm.size)
{
ncSpanInitC(&tSpan, t, tLen);
- if (handler->update(ctx, &tSpan) != CSTATUS_OK)
+ if (handler->update(ctx, tSpan) != CSTATUS_OK)
{
goto Exit;
}
@@ -80,7 +79,7 @@ cstatus_t hkdfExpandProcess(
goto Exit;
}
- if (handler->update(ctx, &counterSpan) != CSTATUS_OK)
+ if (handler->update(ctx, counterSpan) != CSTATUS_OK)
{
goto Exit;
}
@@ -96,18 +95,15 @@ cstatus_t hkdfExpandProcess(
}
/* tlen becomes the hash size or remaining okm size */
- tLen = HKDF_MIN(okm->size - okmOffset, SHA256_DIGEST_SIZE);
+ tLen = HKDF_MIN(okm.size - okmOffset, SHA256_DIGEST_SIZE);
DEBUG_ASSERT(tLen <= sizeof(t));
- /* write the T buffer back to okm */
- ncSpanWrite(*okm, okmOffset, t, tLen);
-
- /* shift base okm pointer by T */
- okmOffset += tLen;
+ /* write the T buffer back to okm and advance okmOffset by tLen */
+ ncSpanAppend(okm, &okmOffset, t, tLen);
/* increment counter */
- counter++;
+ (*counter)++;
}
result = CSTATUS_OK; /* HMAC operation completed, so set success */
diff --git a/src/hkdf.h b/src/hkdf.h
index 2e3a55e..50ee6e8 100644
--- a/src/hkdf.h
+++ b/src/hkdf.h
@@ -42,7 +42,7 @@
/* typedefs for hdkf callback functions */
-typedef cstatus_t (*hmac_hash_fn)(void* ctx, const cspan_t* data);
+typedef cstatus_t (*hmac_hash_fn)(void* ctx, cspan_t data);
typedef cstatus_t (*hmac_finish_fn)(void* ctx, sha256_t hmacOut32);
struct nc_hkdf_fn_cb_struct
@@ -54,8 +54,8 @@ struct nc_hkdf_fn_cb_struct
cstatus_t hkdfExpandProcess(
const struct nc_hkdf_fn_cb_struct* handler,
void* ctx,
- const cspan_t* info,
- span_t* okm
+ cspan_t info,
+ span_t okm
);
#endif /* !_NC_HKDF_H */
diff --git a/src/nc-crypto.c b/src/nc-crypto.c
index 99c072d..752c9b0 100644
--- a/src/nc-crypto.c
+++ b/src/nc-crypto.c
@@ -134,7 +134,7 @@ _IMPLSTB cstatus_t _dummyAesFunc(
#define _IMPL_CRYPTO_SHA256_HKDF_EXTRACT _fallbackHkdfExtract
- _IMPLSTB cstatus_t _fallbackHkdfExtract(const cspan_t* salt, const cspan_t* ikm, sha256_t prk)
+ _IMPLSTB cstatus_t _fallbackHkdfExtract(cspan_t salt, cspan_t ikm, sha256_t prk)
{
return _IMPL_CRYPTO_SHA256_HMAC(salt, ikm, prk);
}
@@ -217,11 +217,11 @@ uint32_t ncCryptoFixedTimeComp(const uint8_t* a, const uint8_t* b, uint32_t size
return _IMPL_CRYPTO_FIXED_TIME_COMPARE(a, b, size);
}
-cstatus_t ncCryptoDigestSha256(const cspan_t* data, sha256_t digestOut32)
+cstatus_t ncCryptoDigestSha256(cspan_t data, sha256_t digestOut32)
{
/* Debug arg validate */
- DEBUG_ASSERT2(data != NULL && data->data != NULL, "Expected data to be non-null")
- DEBUG_ASSERT2(digestOut32 != NULL, "Expected digestOut32 to be non-null")
+ DEBUG_ASSERT2(ncSpanIsValidC(data), "Expected data to be non-null")
+ DEBUG_ASSERT2(digestOut32 != NULL, "Expected digestOut32 to be non-null")
#ifndef _IMPL_CRYPTO_SHA256_DIGEST
#error "No SHA256 implementation defined"
@@ -230,12 +230,12 @@ cstatus_t ncCryptoDigestSha256(const cspan_t* data, sha256_t digestOut32)
return _IMPL_CRYPTO_SHA256_DIGEST(data, digestOut32);
}
-cstatus_t ncCryptoHmacSha256(const cspan_t* key, const cspan_t* data, sha256_t hmacOut32)
+cstatus_t ncCryptoHmacSha256(cspan_t key, cspan_t data, sha256_t hmacOut32)
{
/* Debug arg validate */
- DEBUG_ASSERT2(key != NULL && key->data != NULL, "Expected key to be non-null")
- DEBUG_ASSERT2(data != NULL && data->data != NULL, "Expected data to be non-null")
- DEBUG_ASSERT2(hmacOut32 != NULL && data->data != NULL, "Expected hmacOut32 to be non-null")
+ DEBUG_ASSERT2(ncSpanIsValidC(key), "Expected key to be non-null")
+ DEBUG_ASSERT2(ncSpanIsValidC(data), "Expected data to be non-null")
+ DEBUG_ASSERT2(hmacOut32 != NULL, "Expected hmacOut32 to be non-null")
#ifndef _IMPL_CRYPTO_SHA256_HMAC
#error "No SHA256 HMAC implementation defined"
@@ -244,12 +244,12 @@ cstatus_t ncCryptoHmacSha256(const cspan_t* key, const cspan_t* data, sha256_t h
return _IMPL_CRYPTO_SHA256_HMAC(key, data, hmacOut32);
}
-cstatus_t ncCryptoSha256HkdfExpand(const cspan_t* prk, const cspan_t* info, span_t* okm)
+cstatus_t ncCryptoSha256HkdfExpand(cspan_t prk, cspan_t info, span_t okm)
{
/* Debug arg validate */
- DEBUG_ASSERT2(prk != NULL && prk->data != NULL, "Expected prk to be non-null")
- DEBUG_ASSERT2(info != NULL && info->data != NULL, "Expected info to be non-null")
- DEBUG_ASSERT2(okm != NULL && okm->data != NULL, "Expected okm to be non-null")
+ DEBUG_ASSERT2(ncSpanIsValidC(prk), "Expected prk to be non-null")
+ DEBUG_ASSERT2(ncSpanIsValidC(info), "Expected info to be non-null")
+ DEBUG_ASSERT2(ncSpanIsValid(okm), "Expected okm to be non-null")
/*
* RFC 5869: 2.3
@@ -258,7 +258,7 @@ cstatus_t ncCryptoSha256HkdfExpand(const cspan_t* prk, const cspan_t* info, span
* important as the counter is 1 byte, so it cannot overflow
*/
- if(okm->size > (uint32_t)(0xFFu * SHA256_DIGEST_SIZE))
+ if(okm.size > (uint32_t)(0xFFu * SHA256_DIGEST_SIZE))
{
return CSTATUS_FAIL;
}
@@ -270,12 +270,12 @@ cstatus_t ncCryptoSha256HkdfExpand(const cspan_t* prk, const cspan_t* info, span
return _IMPL_CRYPTO_SHA256_HKDF_EXPAND(prk, info, okm);
}
-cstatus_t ncCryptoSha256HkdfExtract(const cspan_t* salt, const cspan_t* ikm, sha256_t prk)
+cstatus_t ncCryptoSha256HkdfExtract(cspan_t salt, cspan_t ikm, sha256_t prk)
{
/* Debug arg validate */
- DEBUG_ASSERT2(salt != NULL, "Expected salt to be non-null")
- DEBUG_ASSERT2(ikm != NULL, "Expected ikm to be non-null")
- DEBUG_ASSERT2(prk != NULL, "Expected prk to be non-null")
+ DEBUG_ASSERT2(ncSpanIsValidC(salt), "Expected salt to be non-null")
+ DEBUG_ASSERT2(ncSpanIsValidC(ikm), "Expected ikm to be non-null")
+ DEBUG_ASSERT2(prk != NULL, "Expected prk to be non-null")
#ifndef _IMPL_CRYPTO_SHA256_HKDF_EXTRACT
#error "No SHA256 HKDF extract implementation defined"
diff --git a/src/nc-crypto.h b/src/nc-crypto.h
index 11da6d3..a1545de 100644
--- a/src/nc-crypto.h
+++ b/src/nc-crypto.h
@@ -42,13 +42,13 @@ uint32_t ncCryptoFixedTimeComp(const uint8_t* a, const uint8_t* b, uint32_t size
void ncCryptoSecureZero(void* ptr, uint32_t size);
-cstatus_t ncCryptoDigestSha256(const cspan_t* data, sha256_t digestOut32);
+cstatus_t ncCryptoDigestSha256(cspan_t data, sha256_t digestOut32);
-cstatus_t ncCryptoHmacSha256(const cspan_t* key, const cspan_t* data, sha256_t hmacOut32);
+cstatus_t ncCryptoHmacSha256(cspan_t key, cspan_t data, sha256_t hmacOut32);
-cstatus_t ncCryptoSha256HkdfExpand(const cspan_t* prk, const cspan_t* info, span_t* okm);
+cstatus_t ncCryptoSha256HkdfExpand(cspan_t prk, cspan_t info, span_t okm);
-cstatus_t ncCryptoSha256HkdfExtract(const cspan_t* salt, const cspan_t* ikm, sha256_t prk);
+cstatus_t ncCryptoSha256HkdfExtract(cspan_t salt, cspan_t ikm, sha256_t prk);
cstatus_t ncCryptoChacha20(
const uint8_t key[CHACHA_KEY_SIZE],
diff --git a/src/nc-util.h b/src/nc-util.h
index d0afe28..2ddfd3f 100644
--- a/src/nc-util.h
+++ b/src/nc-util.h
@@ -102,6 +102,26 @@ typedef struct read_only_memory_span_struct
uint32_t size;
} cspan_t;
+static _nc_fn_inline int ncSpanIsValid(span_t span)
+{
+ return span.data != NULL;
+}
+
+static _nc_fn_inline int ncSpanIsValidC(cspan_t span)
+{
+ return span.data != NULL;
+}
+
+static _nc_fn_inline int ncSpanIsValidRange(span_t span, uint32_t offset, uint32_t size)
+{
+ return ncSpanIsValid(span) && offset + size <= span.size;
+}
+
+static _nc_fn_inline int ncSpanIsValidRangeC(cspan_t span, uint32_t offset, uint32_t size)
+{
+ return ncSpanIsValidC(span) && offset + size <= span.size;
+}
+
static _nc_fn_inline void ncSpanInitC(cspan_t* span, const uint8_t* data, uint32_t size)
{
span->data = data;
@@ -114,9 +134,25 @@ static _nc_fn_inline void ncSpanInit(span_t* span, uint8_t* data, uint32_t size)
span->size = size;
}
+static _nc_fn_inline const uint8_t* ncSpanGetOffsetC(cspan_t span, uint32_t offset)
+{
+ DEBUG_ASSERT2(ncSpanIsValidC(span), "Expected span to be non-null");
+ DEBUG_ASSERT2(offset < span.size, "Expected offset to be less than span size");
+
+ return span.data + offset;
+}
+
+static _nc_fn_inline uint8_t* ncSpanGetOffset(span_t span, uint32_t offset)
+{
+ DEBUG_ASSERT2(ncSpanIsValid(span), "Expected span to be non-null");
+ DEBUG_ASSERT2(offset < span.size, "Expected offset to be less than span size");
+
+ return span.data + offset;
+}
+
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(ncSpanIsValid(span), "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")
@@ -126,7 +162,7 @@ static _nc_fn_inline void ncSpanWrite(span_t span, uint32_t offset, const uint8_
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(ncSpanIsValid(span), "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")
@@ -142,7 +178,7 @@ static _nc_fn_inline span_t ncSpanSlice(span_t span, uint32_t offset, uint32_t s
{
span_t slice;
- DEBUG_ASSERT2(span.data != NULL, "Expected span to be non-null");
+ DEBUG_ASSERT2(ncSpanIsValid(span), "Expected span to be non-null");
DEBUG_ASSERT2(offset + size <= span.size, "Expected offset + size to be less than span size")
/* Initialize slice, offset input data by the specified offset */
@@ -155,7 +191,7 @@ static _nc_fn_inline cspan_t ncSpanSliceC(cspan_t span, uint32_t offset, uint32_
{
cspan_t slice;
- DEBUG_ASSERT2(span.data != NULL, "Expected span to be non-null");
+ DEBUG_ASSERT2(ncSpanIsValidC(span), "Expected span to be non-null");
DEBUG_ASSERT2(offset + size <= span.size, "Expected offset + size to be less than span size")
/* Initialize slice, offset input data by the specified offset */
@@ -164,5 +200,39 @@ static _nc_fn_inline cspan_t ncSpanSliceC(cspan_t span, uint32_t offset, uint32_
return slice;
}
+static _nc_fn_inline void ncSpanCopyC(cspan_t src, span_t dest)
+{
+ DEBUG_ASSERT2(ncSpanIsValidC(src), "Expected span to be non-null");
+ DEBUG_ASSERT2(ncSpanIsValid(dest), "Expected offset + size to be less than span size");
+ DEBUG_ASSERT2(dest.size >= src.size, "Output buffer too small. Overrun detected");
+
+ /* Copy data to span */
+ MEMMOV(dest.data, src.data, src.size);
+}
+
+static _nc_fn_inline void ncSpanCopy(span_t src, span_t dest)
+{
+ cspan_t csrc;
+
+ ncSpanInitC(&csrc, src.data, src.size);
+ ncSpanCopyC(csrc, dest);
+}
+
+static _nc_fn_inline void ncSpanReadC(cspan_t src, uint8_t* dest, uint32_t size)
+{
+ span_t dsts;
+
+ ncSpanInit(&dsts, dest, size);
+ ncSpanCopyC(src, dsts);
+}
+
+static _nc_fn_inline void ncSpanRead(span_t src, uint8_t* dest, uint32_t size)
+{
+ cspan_t srcs;
+
+ ncSpanInitC(&srcs, src.data, src.size);
+ ncSpanReadC(srcs, dest, size);
+}
+
#endif /* !_NC_UTIL_H */ \ No newline at end of file
diff --git a/src/noscrypt.c b/src/noscrypt.c
index f3c28cb..46b3d65 100644
--- a/src/noscrypt.c
+++ b/src/noscrypt.c
@@ -244,7 +244,9 @@ static _nc_fn_inline NCResult _computeConversationKey(
ncSpanInitC(&saltSpan, Nip44ConstantSalt, sizeof(Nip44ConstantSalt));
ncSpanInitC(&ikmSpan, sharedSecret->value, NC_SHARED_SEC_SIZE);
- return ncCryptoSha256HkdfExtract(&saltSpan, &ikmSpan, ck->value) == CSTATUS_OK ? NC_SUCCESS : E_OPERATION_FAILED;
+ return ncCryptoSha256HkdfExtract(saltSpan, ikmSpan, ck->value) == CSTATUS_OK
+ ? NC_SUCCESS
+ : E_OPERATION_FAILED;
}
@@ -286,7 +288,7 @@ static _nc_fn_inline cstatus_t _getMessageKey(
ncSpanInit(&okmSpan, messageKey->value, sizeof(struct message_key)); /* Output produces a message key (write it directly to struct memory) */
/* Nonce is the info */
- return ncCryptoSha256HkdfExpand(&prkSpan, &nonce, &okmSpan);
+ return ncCryptoSha256HkdfExpand(prkSpan, nonce, okmSpan);
}
static _nc_fn_inline NCResult _encryptNip44Ex(
@@ -380,7 +382,7 @@ static _nc_fn_inline cstatus_t _computeHmac(const uint8_t key[NC_HMAC_KEY_SIZE],
ncSpanInitC(&keySpan, key, NC_HMAC_KEY_SIZE);
- return ncCryptoHmacSha256(&keySpan, &payload, hmacOut);
+ return ncCryptoHmacSha256(keySpan, payload, hmacOut);
}
static NCResult _verifyMacEx(
@@ -650,7 +652,7 @@ NC_EXPORT NCResult NC_CC NCSignData(
ncSpanInitC(&dataSpan, data, dataSize);
/* Compute sha256 of the data before signing */
- if(ncCryptoDigestSha256(&dataSpan, digest) != CSTATUS_OK)
+ if(ncCryptoDigestSha256(dataSpan, digest) != CSTATUS_OK)
{
return E_INVALID_ARG;
}
@@ -708,7 +710,7 @@ NC_EXPORT NCResult NC_CC NCVerifyData(
ncSpanInitC(&dataSpan, data, dataSize);
/* Compute sha256 of the data before verifying */
- if (ncCryptoDigestSha256(&dataSpan, digest) != CSTATUS_OK)
+ if (ncCryptoDigestSha256(dataSpan, digest) != CSTATUS_OK)
{
return E_INVALID_ARG;
}
diff --git a/src/noscryptutil.c b/src/noscryptutil.c
index 97526d9..56acb1b 100644
--- a/src/noscryptutil.c
+++ b/src/noscryptutil.c
@@ -34,6 +34,23 @@
#error "Utilities library must be disabled when using extreme compat mode"
#endif /* NC_EXTREME_COMPAT */
+#define MIN_PADDING_SIZE 0x20u
+#define NIP44_VERSION_SIZE 0x01u
+#define NIP44_PT_LEN_SIZE sizeof(uint16_t)
+
+/*
+* minimum size for a valid nip44 payload
+* 1 byte version + 32 byte nonce + 32 byte mac + 2 byte ptSize + 32bytes minimum length
+*/
+#define NIP44_MIN_PAYLOAD_SIZE (NIP44_VERSION_SIZE + 0x20 + 0x02 + 0x20 + 0x02)
+
+/*
+* The minimum ciphertext size is the minimum padded size + the minimum
+* size of the plaintext length field
+*/
+#define NIP44_MIN_CIPHERTEXT_SIZE (MIN_PADDING_SIZE + NIP44_PT_LEN_SIZE)
+
+
#define _nc_mem_free(x) if(x != NULL) { free(x); x = NULL; }
#define _nc_mem_alloc(elements, size) calloc(elements, size);
#define ZERO_FILL ncCryptoSecureZero
@@ -51,7 +68,6 @@
#define CHECK_ARG_IS(is, expected, argPos)
#endif /* !NC_DISABLE_INPUT_VALIDATION */
-
#ifdef _NC_IS_WINDOWS
#include <math.h>
@@ -73,38 +89,24 @@
}
#endif
-#define MIN_PADDING_SIZE 0x20u
-#define NIP44_VERSION_SIZE 0x01u
-#define NIP44_PT_LEN_SIZE sizeof(uint16_t)
-
-/*
-* minimum size for a valid nip44 payload
-* 1 byte version + 32 byte nonce + 32 byte mac + 2 byte ptSize + 32bytes minimum length
-*/
-#define NIP44_MIN_PAYLOAD_SIZE (NIP44_VERSION_SIZE + 0x20 + 0x02 + 0x20 + 0x02)
-
-/*
-* The minimum ciphertext size is the minimum padded size + the minimum
-* size of the plaintext length field
-*/
-#define NIP44_MIN_CIPHERTEXT_SIZE (MIN_PADDING_SIZE + NIP44_PT_LEN_SIZE)
-
-
/* Currently were on nip44 version 2 */
static const uint8_t Nip44VersionValue[1] = { 0x02u };
-struct nc_util_enc_struct {
+struct cipher_buffer_state {
+
+ cspan_t input;
+ span_t output;
- uint32_t _flags;
+ cspan_t actualOutput;
+};
- cspan_t cipherInput;
+struct nc_util_enc_struct {
- /*
- The data this span points to is allocated during initialization
- */
- span_t cipherOutput;
+ uint32_t _flags;
NCEncryptionArgs encArgs;
+
+ struct cipher_buffer_state buffer;
};
static _nc_fn_inline span_t _ncUtilAllocSpan(uint32_t count, size_t size)
@@ -126,6 +128,11 @@ static _nc_fn_inline span_t _ncUtilAllocSpan(uint32_t count, size_t size)
return span;
}
+static _nc_fn_inline void _ncUtilZeroSpan(span_t span)
+{
+ ZERO_FILL(span.data, span.size);
+}
+
static _nc_fn_inline void _ncUtilFreeSpan(span_t span)
{
_nc_mem_free(span.data);
@@ -198,7 +205,7 @@ static _nc_fn_inline uint32_t _calcNip44TotalOutSize(uint32_t inputSize)
return bufferSize;
}
-static _nc_fn_inline cspan_t _nip44GetMacData(cspan_t payload)
+static _nc_fn_inline span_t _nip44GetMacData(span_t payload)
{
DEBUG_ASSERT(payload.size > NIP44_VERSION_SIZE + NC_ENCRYPTION_MAC_SIZE);
@@ -216,7 +223,7 @@ static _nc_fn_inline cspan_t _nip44GetMacData(cspan_t payload)
* macData = ct.size - version.size + mac.size
*/
- return ncSpanSliceC(
+ return ncSpanSlice(
payload,
NIP44_VERSION_SIZE,
payload.size - (NIP44_VERSION_SIZE + NC_ENCRYPTION_MAC_SIZE)
@@ -237,70 +244,105 @@ static _nc_fn_inline span_t _nip44GetMacOutput(span_t payload)
);
}
-static _nc_fn_inline cspan_t _nip44ParseMac(cspan_t payload)
+static _nc_fn_inline int _nip44ParseSegments(
+ cspan_t payload,
+ cspan_t* nonce,
+ cspan_t* mac,
+ cspan_t* macData,
+ cspan_t* cipherText
+)
{
- DEBUG_ASSERT(payload.size >= NIP44_MIN_PAYLOAD_SIZE);
+ if (payload.size < NIP44_MIN_PAYLOAD_SIZE)
+ {
+ return 0;
+ }
+
+ /* slice after the version and before the mac segments */
+ *nonce = ncSpanSliceC(
+ payload,
+ NIP44_VERSION_SIZE,
+ NC_ENCRYPTION_NONCE_SIZE
+ );
/*
* Mac is the final 32 bytes of the ciphertext buffer
*/
- return ncSpanSliceC(
+ *mac = ncSpanSliceC(
payload,
payload.size - NC_ENCRYPTION_MAC_SIZE,
NC_ENCRYPTION_MAC_SIZE
);
-}
-static _nc_fn_inline cspan_t _nip44ParseCipherText(cspan_t payload)
-{
- DEBUG_ASSERT(payload.size >= NIP44_MIN_PAYLOAD_SIZE);
+ /*
+ * The mac data is the nonce+ct segment of the buffer for mac computation.
+ */
+ *macData = ncSpanSliceC(
+ payload,
+ NIP44_VERSION_SIZE,
+ payload.size - (NIP44_VERSION_SIZE + NC_ENCRYPTION_MAC_SIZE)
+ );
- /* ct is all of the data after the nonce and before the mac segment */
- return ncSpanSliceC(
+ /*
+ * Ciphertext is after the nonce segment and before the mac segment
+ */
+ *cipherText = ncSpanSliceC(
payload,
NIP44_VERSION_SIZE + NC_ENCRYPTION_NONCE_SIZE,
payload.size - (NIP44_VERSION_SIZE + NC_ENCRYPTION_NONCE_SIZE + NC_ENCRYPTION_MAC_SIZE)
);
+
+ return 1;
}
-static _nc_fn_inline cspan_t _nip44ParseNonce(cspan_t payload)
+
+static _nc_fn_inline void _cipherPublishOutput(NCUtilCipherContext* buffer, uint32_t offset, uint32_t size)
{
- DEBUG_ASSERT(payload.size >= NIP44_MIN_PAYLOAD_SIZE);
+ span_t slice;
- /* slice after the version and before the mac segments */
- return ncSpanSliceC(
- payload,
- NIP44_VERSION_SIZE,
- NC_ENCRYPTION_NONCE_SIZE
- );
+ DEBUG_ASSERT(ncSpanIsValid(buffer->buffer.output));
+
+ if (size == 0)
+ {
+ ncSpanInitC(&buffer->buffer.actualOutput, NULL, 0);
+ }
+ else
+ {
+ /* use slice for debug guards */
+ slice = ncSpanSlice(buffer->buffer.output, offset, size);
+ ncSpanInitC(&buffer->buffer.actualOutput, slice.data, slice.size);
+ }
}
+/*
+* I want the encryption/decyption functions to be indempodent
+* meaning all mutations that happen can be repeated without
+* side effects. IE no perminent state changes that can't be
+* undone.
+*/
+
static NCResult _nip44EncryptCompleteCore(
const NCContext* libContext,
const NCSecretKey* sk,
const NCPublicKey* pk,
- NCEncryptionArgs encArgs,
- cspan_t plainText,
- span_t payload
+ NCUtilCipherContext* state
)
{
NCResult result;
- cspan_t macData, cPayload;
- span_t macOutput;
- uint32_t outPos, paddedCtSize;
+ cspan_t plainText;
+ span_t macData, macOutput, payload;
+ uint32_t outPos;
uint8_t ptSize[NIP44_PT_LEN_SIZE];
uint8_t hmacKeyOut[NC_ENCRYPTION_MAC_SIZE];
+ NCEncryptionArgs encArgs;
outPos = 0;
+ encArgs = state->encArgs;
+ payload = state->buffer.output;
+ plainText = state->buffer.input;
DEBUG_ASSERT(encArgs.version == NC_ENC_VERSION_NIP44);
- ncSpanInitC(&cPayload, payload.data, payload.size);
-
- /* Padded size is required to know how large the CT buffer is for encryption */
- paddedCtSize = _calcNip44PtPadding(plainText.size);
-
/* Start by appending the version number */
ncSpanAppend(payload, &outPos, Nip44VersionValue, sizeof(Nip44VersionValue));
@@ -343,9 +385,9 @@ static NCResult _nip44EncryptCompleteCore(
result = NCSetEncryptionData(
&encArgs,
- (payload.data + outPos), /* in place encryption */
- (payload.data + outPos),
- paddedCtSize + NIP44_PT_LEN_SIZE /* Plaintext + pt size must be encrypted */
+ ncSpanGetOffset(payload, outPos), /* in place encryption */
+ ncSpanGetOffset(payload, outPos),
+ NIP44_PT_LEN_SIZE + _calcNip44PtPadding(plainText.size) /* Plaintext + pt size must be encrypted */
);
DEBUG_ASSERT(result == NC_SUCCESS);
@@ -363,7 +405,7 @@ static NCResult _nip44EncryptCompleteCore(
* the plaintext data, followed by zero padding.
*/
- ncSpanWrite(payload, outPos, ptSize, NIP44_PT_LEN_SIZE);
+ ncSpanWrite(payload, outPos, ptSize, sizeof(ptSize));
ncSpanWrite(
payload,
@@ -387,15 +429,15 @@ static NCResult _nip44EncryptCompleteCore(
this helper captures that data segment into a span
*/
- macData = _nip44GetMacData(cPayload);
+ macData = _nip44GetMacData(payload);
macOutput = _nip44GetMacOutput(payload);
result = NCComputeMac(
libContext,
hmacKeyOut,
- macData.data,
+ ncSpanGetOffset(macData, 0),
macData.size,
- macOutput.data
+ ncSpanGetOffset(macOutput, 0)
);
if (result != NC_SUCCESS)
@@ -407,6 +449,9 @@ static NCResult _nip44EncryptCompleteCore(
DEBUG_ASSERT2(outPos == payload.size, "Buffer under/overflow detected");
+ /* publish all payload bytes to output */
+ _cipherPublishOutput(state, 0, outPos);
+
/* zero hmac key before returning */
ZERO_FILL(hmacKeyOut, sizeof(hmacKeyOut));
@@ -418,45 +463,55 @@ static NCResult _nip44DecryptCompleteCore(
const NCContext* libContext,
const NCSecretKey* recvKey,
const NCPublicKey* sendKey,
- const NCUtilCipherContext* cipher
+ NCUtilCipherContext* state
)
{
NCResult result;
NCMacVerifyArgs macArgs;
NCEncryptionArgs encArgs;
- cspan_t macData, macValue, cipherText, nonce;
+ cspan_t macData, macValue, nonce, payload, cipherText;
+ span_t output;
+ uint16_t ptSize;
- DEBUG_ASSERT(libContext && recvKey && sendKey && cipher);
- DEBUG_ASSERT(cipher->encArgs.version == NC_ENC_VERSION_NIP44);
+ DEBUG_ASSERT(libContext && recvKey && sendKey && state);
+ DEBUG_ASSERT(state->encArgs.version == NC_ENC_VERSION_NIP44);
+ DEBUG_ASSERT(state->buffer.input.size >= NIP44_MIN_PAYLOAD_SIZE);
/* ensure decryption mode */
- DEBUG_ASSERT(cipher->_flags & NC_UTIL_CIPHER_MODE_DECRYPT);
+ DEBUG_ASSERT(state->_flags & NC_UTIL_CIPHER_MODE_DECRYPT);
/* store local stack copy for safe mutation */
- encArgs = cipher->encArgs;
+ encArgs = state->encArgs;
+ payload = state->buffer.input;
+ output = state->buffer.output;
- nonce = _nip44ParseNonce(cipher->cipherInput);
+ /*
+ * Copy the input buffer to the output buffer because the
+ * decryption happens in-place and needs a writable buffer
+ *
+ * After the operation is complete, we will assign the actual plaintext
+ * data to the actual output buffer
+ */
- /* Verify mac if the user allowed it */
- if ((cipher->_flags & NC_UTIL_CIPHER_MAC_NO_VERIFY) == 0)
- {
- /*
- * The mac data to verify against is the nonce+ciphertext data
- * from within the nip44 message payload
- */
+ DEBUG_ASSERT2(ncSpanIsValid(output), "Output buffer was not allocated");
- macData = _nip44GetMacData(cipher->cipherInput);
- macValue = _nip44ParseMac(cipher->cipherInput);
+ if (!_nip44ParseSegments(payload, &nonce, &macValue, &macData, &cipherText))
+ {
+ return E_CIPHER_INVALID_FORMAT;
+ }
+ /* Verify mac if the user allowed it */
+ if ((state->_flags & NC_UTIL_CIPHER_MAC_NO_VERIFY) == 0)
+ {
DEBUG_ASSERT(macValue.size == NC_ENCRYPTION_MAC_SIZE);
- DEBUG_ASSERT(macData.size > NC_ENCRYPTION_NONCE_SIZE + 0x20);
+ DEBUG_ASSERT(macData.size > NC_ENCRYPTION_NONCE_SIZE + MIN_PADDING_SIZE);
/* Assign the mac data to the mac verify args */
- macArgs.mac32 = macValue.data;
- macArgs.nonce32 = nonce.data;
+ macArgs.mac32 = ncSpanGetOffsetC(macValue, 0);
+ macArgs.nonce32 = ncSpanGetOffsetC(nonce, 0);
/* payload for verifying a mac in nip44 is the nonce+ciphertext */
- macArgs.payload = macData.data;
+ macArgs.payload = ncSpanGetOffsetC(macData, 0);
macArgs.payloadSize = macData.size;
/* Verify the mac */
@@ -474,44 +529,60 @@ static NCResult _nip44DecryptCompleteCore(
}
}
- cipherText = _nip44ParseCipherText(cipher->cipherInput);
-
- DEBUG_ASSERT2(cipherText.size >= MIN_PADDING_SIZE, "Cipertext segment was parsed incorrectly. Too small");
-
- /* manually sign nonce */
- encArgs.nonceData = nonce.data;
-
- /*
- * Remember the decryption operation is symmetric, it reads the input bytes and writes
- * directly to the output.
- *
- * The decryption is performed on the ciphertext segment and we can write the output
- * directly the output buffer.
- *
- * The leading 2 bytes will be the encoded plaintext size, followed by the plaintext data
- * and padding. That's okay. The user will call NCUtilCipherGetOutputSize to get the
- * actual size of the plaintext, which will exlcude the leading 2 bytes and padding.
+ /*
+ * manually assign nonce because it's a constant pointer which
+ * is not allowed when calling setproperty
*/
+ encArgs.nonceData = ncSpanGetOffsetC(nonce, 0);
- DEBUG_ASSERT(cipher->cipherOutput.size >= cipherText.size);
-
+ DEBUG_ASSERT2(cipherText.size >= MIN_PADDING_SIZE, "Cipertext segment was parsed incorrectly. Too small");
+
result = NCSetEncryptionData(
&encArgs,
- cipherText.data,
- cipher->cipherOutput.data,
+ ncSpanGetOffsetC(cipherText, 0),
+ ncSpanGetOffset(output, 0), /*decrypt ciphertext and write directly to the output buffer */
cipherText.size
);
+ DEBUG_ASSERT(result == NC_SUCCESS);
+
+ /*
+ * If decryption was successful, the data should be written
+ * directly to the output buffer
+ */
+ result = NCDecrypt(libContext, recvKey, sendKey, &encArgs);
+
if (result != NC_SUCCESS)
{
return result;
}
/*
- * If decryption was successful, the data should be written
- * directly to the output buffer
+ * Parse CT length and assign the output buffer.
+ *
+ * PT size is stored at the beginning of the ciphertext
+ * segment and is 2 bytes in size, big endian.
*/
- result = NCDecrypt(libContext, recvKey, sendKey, &encArgs);
+
+ ptSize = (uint16_t)(output.data[0] << 8 | output.data[1]);
+
+ /*
+ * If the PT is corrupted or set maliciously, it can overrun
+ * the current buffer. The PT size must be less than the
+ * ciphertext size.
+ */
+ if (!ncSpanIsValidRange(output, NIP44_PT_LEN_SIZE, ptSize))
+ {
+ return E_OPERATION_FAILED;
+ }
+
+ /*
+ * actual output span should now point to the decrypted plaintext
+ * data segment
+ */
+ _cipherPublishOutput(state, NIP44_PT_LEN_SIZE, ptSize);
+
+ DEBUG_ASSERT(state->buffer.actualOutput.size < cipherText.size);
return result;
}
@@ -582,13 +653,13 @@ NC_EXPORT void NC_CC NCUtilCipherFree(NCUtilCipherContext* encCtx)
* If zero on free flag is set, we can zero all output memory
* before returning the buffer back to the heap
*/
- if ((encCtx->_flags & NC_UTIL_CIPHER_ZERO_ON_FREE) > 0 && encCtx->cipherOutput.data)
+ if ((encCtx->_flags & NC_UTIL_CIPHER_ZERO_ON_FREE) > 0 && ncSpanIsValid(encCtx->buffer.output))
{
- ZERO_FILL(encCtx->cipherOutput.data, encCtx->cipherOutput.size);
+ _ncUtilZeroSpan(encCtx->buffer.output);
}
- /* Free output buffers */
- _ncUtilFreeSpan(encCtx->cipherOutput);
+ /* Free output buffers (null buffers are allowed) */
+ _ncUtilFreeSpan(encCtx->buffer.output);
/* context can be released */
_nc_mem_free(encCtx);
@@ -604,14 +675,12 @@ NC_EXPORT NCResult NC_CC NCUtilCipherInit(
CHECK_NULL_ARG(encCtx, 0);
CHECK_NULL_ARG(inputData, 1);
- /* The output state must not have alraedy been allocated */
- CHECK_ARG_IS(encCtx->cipherOutput.data == NULL, 0);
if ((encCtx->_flags & NC_UTIL_CIPHER_MODE_DECRYPT) > 0)
{
/*
* Validate the input data for proper format for
- * the current cipher version
+ * the current state version
*/
switch (encCtx->encArgs.version)
{
@@ -652,7 +721,7 @@ NC_EXPORT NCResult NC_CC NCUtilCipherInit(
{
/*
* Calculate the correct output size to store the encryption
- * data for the given cipher version
+ * data for the given state version
*/
outputSize = NCUtilGetEncryptionBufferSize(encCtx->encArgs.version, inputSize);
}
@@ -662,15 +731,48 @@ NC_EXPORT NCResult NC_CC NCUtilCipherInit(
return outputSize;
}
+ /*
+ * If the buffer was previously allocated, the reuseable flag
+ * must be set to allow the buffer to be re-used for another
+ * operation.
+ */
+
+ if (ncSpanIsValid(encCtx->buffer.output))
+ {
+ CHECK_ARG_IS((encCtx->_flags & NC_UTIL_CIPHER_REUSEABLE) > 0, 0);
+
+ /*
+ * if the existing buffer is large enough to hold the new
+ * data reuse it, otherwise free it and allocate a new buffer
+ */
+
+ if (outputSize <= encCtx->buffer.output.size)
+ {
+ _ncUtilZeroSpan(encCtx->buffer.output);
+
+ goto AssignInputAndExit;
+ }
+ else
+ {
+ _ncUtilFreeSpan(encCtx->buffer.output);
+ }
+ }
+
/* Alloc output buffer within the struct */
- encCtx->cipherOutput = _ncUtilAllocSpan((uint32_t)outputSize, sizeof(uint8_t));
+ encCtx->buffer.output = _ncUtilAllocSpan((uint32_t)outputSize, sizeof(uint8_t));
- if (!encCtx->cipherOutput.data)
+ if (!ncSpanIsValid(encCtx->buffer.output))
{
return E_OUT_OF_MEMORY;
}
- ncSpanInitC(&encCtx->cipherInput, inputData, inputSize);
+AssignInputAndExit:
+
+ /* Confirm output was allocated */
+ DEBUG_ASSERT(ncSpanIsValid(encCtx->buffer.output));
+
+ /* Assign the input data span to point to the assigned input data */
+ ncSpanInitC(&encCtx->buffer.input, inputData, inputSize);
return NC_SUCCESS;
}
@@ -684,48 +786,14 @@ NC_EXPORT NCResult NC_CC NCUtilCipherGetFlags(const NCUtilCipherContext* ctx)
NC_EXPORT NCResult NC_CC NCUtilCipherGetOutputSize(const NCUtilCipherContext* encCtx)
{
- uint16_t nip44PtSize;
-
CHECK_NULL_ARG(encCtx, 0);
- /*
- * if nip44 decryption is desired, the output buffer will be
- * overallocated. It will also contain some padding bytes
- * so we need to parse the plaintext size from the buffer
- * and return that as the output size.
- */
- if (encCtx->encArgs.version == NC_ENC_VERSION_NIP44
- && (encCtx->_flags & NC_UTIL_CIPHER_MODE_DECRYPT) > 0)
+ if (!ncSpanIsValidC(encCtx->buffer.actualOutput))
{
-
- /* ensure the output has been allocated correctly */
- if (encCtx->cipherOutput.size < NIP44_PT_LEN_SIZE)
- {
- return E_INVALID_CONTEXT;
- }
-
- /*
- * If a decryption operation was performed the leading 2 bytes will
- * be the big-endian encoded plaintext size. This function should
- * return the size of the plaintext data, not the entire buffer.
- */
-
- nip44PtSize = (encCtx->cipherOutput.data[0] << 8) | encCtx->cipherOutput.data[1];
-
- /*
- * If improperly decryption/formatted, the pt size may be some really large
- * number when decoded, so make sure it doesn't point to a location outside
- * the buffer, that would be invalid
- */
- if (nip44PtSize > (encCtx->cipherOutput.size - NIP44_PT_LEN_SIZE))
- {
- return E_CIPHER_INVALID_FORMAT;
- }
-
- return (NCResult)nip44PtSize;
+ return E_CIPHER_NO_OUTPUT;
}
- return (NCResult)(encCtx->cipherOutput.size);
+ return (NCResult)(encCtx->buffer.actualOutput.size);
}
NC_EXPORT NCResult NC_CC NCUtilCipherReadOutput(
@@ -734,55 +802,24 @@ NC_EXPORT NCResult NC_CC NCUtilCipherReadOutput(
uint32_t outputSize
)
{
- NCResult result;
-
- CHECK_NULL_ARG(encCtx, 0)
- CHECK_NULL_ARG(output, 1)
-
- /*
- * Again if in nip44 decrypt mode we only want the
- * actual plaintext data
- */
+ CHECK_NULL_ARG(encCtx, 0);
+ CHECK_NULL_ARG(output, 1);
- if (encCtx->encArgs.version == NC_ENC_VERSION_NIP44
- && (encCtx->_flags & NC_UTIL_CIPHER_MODE_DECRYPT) > 0)
+ if (!ncSpanIsValidC(encCtx->buffer.actualOutput))
{
- result = NCUtilCipherGetOutputSize(encCtx);
-
- if (result < 0)
- {
- return result;
- }
-
- DEBUG_ASSERT((result + NIP44_PT_LEN_SIZE) < encCtx->cipherOutput.size);
-
- /* Make sure the output buffer is large enough */
- CHECK_ARG_RANGE(outputSize, result, UINT32_MAX, 2);
-
- /*
- * Plaintext data sits directly after the length bytes
- * and up to the length of the plaintext size
- */
- MEMMOV(
- output,
- encCtx->cipherOutput.data + NIP44_PT_LEN_SIZE,
- (uint32_t)result
- );
-
- return result;
+ return E_CIPHER_NO_OUTPUT;
}
- else
- {
- CHECK_ARG_RANGE(outputSize, encCtx->cipherOutput.size, UINT32_MAX, 2);
- MEMMOV(
- output,
- encCtx->cipherOutput.data,
- encCtx->cipherOutput.size
- );
+ /* Buffer must be as large as the output data */
+ CHECK_ARG_RANGE(outputSize, encCtx->buffer.actualOutput.size, UINT32_MAX, 2);
- return (NCResult)encCtx->cipherOutput.size;
- }
+ ncSpanReadC(
+ encCtx->buffer.actualOutput,
+ output,
+ outputSize
+ );
+
+ return (NCResult)encCtx->buffer.actualOutput.size;
}
NC_EXPORT NCResult NCUtilCipherSetProperty(
@@ -804,7 +841,7 @@ NC_EXPORT NCResult NCUtilCipherSetProperty(
}
NC_EXPORT NCResult NC_CC NCUtilCipherUpdate(
- const NCUtilCipherContext* encCtx,
+ NCUtilCipherContext* encCtx,
const NCContext* libContext,
const NCSecretKey* sk,
const NCPublicKey* pk
@@ -816,15 +853,18 @@ NC_EXPORT NCResult NC_CC NCUtilCipherUpdate(
CHECK_NULL_ARG(pk, 3);
/* Make sure input & output buffers have been assigned/allocated */
- if (encCtx->cipherOutput.data == NULL)
+ if (!ncSpanIsValid(encCtx->buffer.output))
{
return E_INVALID_CONTEXT;
}
- if (encCtx->cipherInput.data == NULL)
+ if (!ncSpanIsValidC(encCtx->buffer.input))
{
return E_INVALID_CONTEXT;
}
+ /* Reset output data pointer incase it has been moved */
+ _cipherPublishOutput(encCtx, 0, 0);
+
switch (encCtx->encArgs.version)
{
case NC_ENC_VERSION_NIP44:
@@ -841,14 +881,7 @@ NC_EXPORT NCResult NC_CC NCUtilCipherUpdate(
return E_CIPHER_BAD_NONCE;
}
- return _nip44EncryptCompleteCore(
- libContext,
- sk,
- pk,
- encCtx->encArgs,
- encCtx->cipherInput,
- encCtx->cipherOutput
- );
+ return _nip44EncryptCompleteCore(libContext, sk, pk, encCtx);
}
default:
diff --git a/src/providers/bcrypt.c b/src/providers/bcrypt.c
index d1b9aa5..67ae695 100644
--- a/src/providers/bcrypt.c
+++ b/src/providers/bcrypt.c
@@ -63,7 +63,7 @@ _IMPLSTB NTSTATUS _bcInitSha256(struct _bcrypt_ctx* ctx, DWORD flags)
return result;
}
-_IMPLSTB NTSTATUS _bcCreateHmac(struct _bcrypt_ctx* ctx, const cspan_t* key)
+_IMPLSTB NTSTATUS _bcCreateHmac(struct _bcrypt_ctx* ctx, cspan_t key)
{
/*
* NOTE:
@@ -79,8 +79,8 @@ _IMPLSTB NTSTATUS _bcCreateHmac(struct _bcrypt_ctx* ctx, const cspan_t* key)
&ctx->hHash,
NULL,
0,
- (uint8_t*)key->data,
- key->size,
+ (uint8_t*)key.data,
+ key.size,
BCRYPT_HASH_REUSABLE_FLAG /* Enable reusable for expand function */
);
}
@@ -92,7 +92,7 @@ _IMPLSTB NTSTATUS _bcCreate(struct _bcrypt_ctx* ctx)
/* Zero out key span for 0 size and NULL data ptr */
SecureZeroMemory(&key, sizeof(cspan_t));
- return _bcCreateHmac(ctx, &key);
+ return _bcCreateHmac(ctx, key);
}
_IMPLSTB NTSTATUS _bcHashDataRaw(const struct _bcrypt_ctx* ctx, const uint8_t* data, uint32_t len)
@@ -100,9 +100,9 @@ _IMPLSTB NTSTATUS _bcHashDataRaw(const struct _bcrypt_ctx* ctx, const uint8_t* d
return BCryptHashData(ctx->hHash, (uint8_t*)data, len, 0);
}
-_IMPLSTB NTSTATUS _bcHashData(const struct _bcrypt_ctx* ctx, const cspan_t* data)
+_IMPLSTB NTSTATUS _bcHashData(const struct _bcrypt_ctx* ctx, cspan_t data)
{
- return _bcHashDataRaw(ctx, data->data, data->size);
+ return _bcHashDataRaw(ctx, data.data, data.size);
}
_IMPLSTB NTSTATUS _bcFinishHash(const struct _bcrypt_ctx* ctx, sha256_t digestOut32)
@@ -146,7 +146,7 @@ _IMPLSTB void _bcDestroyCtx(struct _bcrypt_ctx* ctx)
/* Export function fallack */
#define _IMPL_CRYPTO_SHA256_DIGEST _bcrypt_sha256_digest
- _IMPLSTB cstatus_t _bcrypt_sha256_digest(const cspan_t* data, sha256_t digestOut32)
+ _IMPLSTB cstatus_t _bcrypt_sha256_digest(cspan_t data, sha256_t digestOut32)
{
cstatus_t result;
struct _bcrypt_ctx ctx;
@@ -177,7 +177,7 @@ _IMPLSTB void _bcDestroyCtx(struct _bcrypt_ctx* ctx)
/* Export function */
#define _IMPL_CRYPTO_SHA256_HMAC _bcrypt_hmac_sha256
- _IMPLSTB cstatus_t _bcrypt_hmac_sha256(const cspan_t* key, const cspan_t* data, sha256_t hmacOut32)
+ _IMPLSTB cstatus_t _bcrypt_hmac_sha256(cspan_t key, cspan_t data, sha256_t hmacOut32)
{
cstatus_t result;
struct _bcrypt_ctx ctx;
@@ -213,7 +213,7 @@ _IMPLSTB void _bcDestroyCtx(struct _bcrypt_ctx* ctx)
#define _IMPL_CRYPTO_SHA256_HKDF_EXPAND _bcrypt_fallback_hkdf_expand
- cstatus_t _bcrypt_hkdf_update(void* ctx, const cspan_t* data)
+ cstatus_t _bcrypt_hkdf_update(void* ctx, cspan_t data)
{
DEBUG_ASSERT(ctx != NULL)
@@ -229,7 +229,7 @@ _IMPLSTB void _bcDestroyCtx(struct _bcrypt_ctx* ctx)
return CSTATUS_OK;
}
- _IMPLSTB cstatus_t _bcrypt_fallback_hkdf_expand(const cspan_t* prk, const cspan_t* info, span_t* okm)
+ _IMPLSTB cstatus_t _bcrypt_fallback_hkdf_expand(cspan_t prk, cspan_t info, span_t okm)
{
cstatus_t result;
struct _bcrypt_ctx ctx;
diff --git a/src/providers/mbedtls.c b/src/providers/mbedtls.c
index df5201f..8479380 100644
--- a/src/providers/mbedtls.c
+++ b/src/providers/mbedtls.c
@@ -95,13 +95,13 @@ _IMPLSTB const mbedtls_md_info_t* _mbed_sha256_alg(void)
#define _IMPL_CRYPTO_SHA256_DIGEST _mbed_sha256_digest
- _IMPLSTB cstatus_t _mbed_sha256_digest(const cspan_t* data, sha256_t digestOut32)
+ _IMPLSTB cstatus_t _mbed_sha256_digest(cspan_t data, sha256_t digestOut32)
{
- _overflow_check(data->size)
+ _overflow_check(data.size)
return mbedtls_sha256(
- data->data,
- data->size,
+ data.data,
+ data.size,
digestOut32,
0 /* Set 0 for sha256 mode */
) == 0 ? CSTATUS_OK : CSTATUS_FAIL;
@@ -114,19 +114,19 @@ _IMPLSTB const mbedtls_md_info_t* _mbed_sha256_alg(void)
#define _IMPL_CRYPTO_SHA256_HMAC _mbed_sha256_hmac
- _IMPLSTB cstatus_t _mbed_sha256_hmac(const cspan_t* key, const cspan_t* data, sha256_t hmacOut32)
+ _IMPLSTB cstatus_t _mbed_sha256_hmac(cspan_t key, cspan_t data, sha256_t hmacOut32)
{
- _overflow_check(data->size)
+ _overflow_check(data.size)
/* Keys should never be large enough for this to matter, but sanity check. */
- DEBUG_ASSERT2(key->size < SIZE_MAX, "Expected key size to be less than SIZE_MAX")
+ DEBUG_ASSERT2(key.size < SIZE_MAX, "Expected key size to be less than SIZE_MAX")
return mbedtls_md_hmac(
_mbed_sha256_alg(),
- key->data,
- key->size,
- data->data,
- data->size,
+ key.data,
+ key.size,
+ data.data,
+ data.size,
hmacOut32
) == 0 ? CSTATUS_OK : CSTATUS_FAIL;
}
@@ -137,21 +137,21 @@ _IMPLSTB const mbedtls_md_info_t* _mbed_sha256_alg(void)
#define _IMPL_CRYPTO_SHA256_HKDF_EXPAND _mbed_sha256_hkdf_expand
- _IMPLSTB cstatus_t _mbed_sha256_hkdf_expand(const cspan_t* prk, const cspan_t* info, span_t* okm)
+ _IMPLSTB cstatus_t _mbed_sha256_hkdf_expand(cspan_t prk, cspan_t info, span_t okm)
{
/* These sizes should never be large enough to overflow on <64bit platforms, but sanity check */
- DEBUG_ASSERT(okm->size < SIZE_MAX)
- DEBUG_ASSERT(prk->size < SIZE_MAX)
- DEBUG_ASSERT(info->size < SIZE_MAX)
+ DEBUG_ASSERT(okm.size < SIZE_MAX)
+ DEBUG_ASSERT(prk.size < SIZE_MAX)
+ DEBUG_ASSERT(info.size < SIZE_MAX)
return mbedtls_hkdf_expand(
_mbed_sha256_alg(),
- prk->data,
- prk->size,
- info->data,
- info->size,
- okm->data,
- okm->size
+ prk.data,
+ prk.size,
+ info.data,
+ info.size,
+ okm.data,
+ okm.size
) == 0 ? CSTATUS_OK : CSTATUS_FAIL;
}
diff --git a/tests/hex.h b/tests/hex.h
index e6a2a07..3cfe559 100644
--- a/tests/hex.h
+++ b/tests/hex.h
@@ -68,6 +68,7 @@ static span_t _fromHexString(const char* hexLiteral, uint32_t strLen)
if(!hexLiteral)
{
+ ncSpanInit(&hexBytes, NULL, 0);
return hexBytes;
}
@@ -125,13 +126,13 @@ static void PrintHexRaw(void* bytes, size_t len)
*/
static void PrintHexBytes(span_t hexBytes)
{
- if (!hexBytes.data)
+ if (ncSpanIsValid(hexBytes))
{
- puts("NULL");
+ PrintHexRaw(hexBytes.data, hexBytes.size);
}
else
{
- PrintHexRaw(hexBytes.data, hexBytes.size);
+ puts("NULL");
}
}
diff --git a/tests/test.c b/tests/test.c
index 80b8704..b4cdef1 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -617,7 +617,7 @@ static int TestUtilNip44Encryption(
span_t recvKey,
span_t nonce,
span_t expected,
- const char* plainText
+ span_t plainText
)
{
NCPublicKey recvPubKey;
@@ -634,7 +634,7 @@ static int TestUtilNip44Encryption(
ENSURE(ctx != NULL);
- TEST(NCUtilCipherInit(ctx, (const uint8_t*)plainText, strlen(plainText)), NC_SUCCESS);
+ TEST(NCUtilCipherInit(ctx, plainText.data, plainText.size), NC_SUCCESS);
/* Nonce is required for nip44 encryption */
TEST(NCUtilCipherSetProperty(ctx, NC_ENC_SET_NIP44_NONCE, nonce.data, nonce.size), NC_SUCCESS);
@@ -659,6 +659,8 @@ static int TestUtilNip44Encryption(
/* Free encryption memory */
NCUtilCipherFree(ctx);
+
+ return 0;
}
static int TestUtilNip44Decryption(
@@ -666,7 +668,7 @@ static int TestUtilNip44Decryption(
span_t sendKey,
span_t recvKey,
span_t payload,
- const char* expectedPt
+ span_t expectedPt
)
{
NCPublicKey recvPubKey;
@@ -690,7 +692,7 @@ static int TestUtilNip44Decryption(
NCResult plaintextSize = NCUtilCipherGetOutputSize(ctx);
- TEST(plaintextSize, strlen(expectedPt));
+ TEST(plaintextSize, expectedPt.size);
outData = (uint8_t*)malloc(plaintextSize);
@@ -700,12 +702,14 @@ static int TestUtilNip44Decryption(
TEST(NCUtilCipherReadOutput(ctx, outData, plaintextSize), plaintextSize);
/* Ensure encrypted payload matches */
- TEST(memcmp(outData, expectedPt, plaintextSize), 0);
+ TEST(memcmp(outData, expectedPt.data, plaintextSize), 0);
free(outData);
/* Free encryption memory */
NCUtilCipherFree(ctx);
+
+ return 0;
}
static int TestUtilFunctions(const NCContext* libCtx)
@@ -727,7 +731,7 @@ static int TestUtilFunctions(const NCContext* libCtx)
span_t recvKey = FromHexString("0000000000000000000000000000000000000000000000000000000000000002", sizeof(NCSecretKey));
span_t nonce = FromHexString("0000000000000000000000000000000000000000000000000000000000000001", NC_ENCRYPTION_NONCE_SIZE);
span_t payload = FromHexString("02000000000000000000000000000000000000000000000000000000000000000179ed06e5548ad3ff58ca920e6c0b4329f6040230f7e6e5641f20741780f0adc35a09794259929a02bb06ad8e8cf709ee4ccc567e9d514cdf5781af27a3e905e55b1b", 99);
- const char* plainText = "a";
+ span_t plainText = FromHexString("61", 1);
if (TestUtilNip44Encryption(libCtx, sendKey, recvKey, nonce, payload, plainText) != 0)
{
@@ -740,9 +744,8 @@ static int TestUtilFunctions(const NCContext* libCtx)
/* From the nip44 vectors file */
span_t sendKey = FromHexString("0000000000000000000000000000000000000000000000000000000000000001", sizeof(NCSecretKey));
span_t recvKey = FromHexString("0000000000000000000000000000000000000000000000000000000000000002", sizeof(NCSecretKey));
- span_t nonce = FromHexString("0000000000000000000000000000000000000000000000000000000000000001", NC_ENCRYPTION_NONCE_SIZE);
span_t payload = FromHexString("02000000000000000000000000000000000000000000000000000000000000000179ed06e5548ad3ff58ca920e6c0b4329f6040230f7e6e5641f20741780f0adc35a09794259929a02bb06ad8e8cf709ee4ccc567e9d514cdf5781af27a3e905e55b1b", 99);
- const char* plainText = "a";
+ span_t plainText = FromHexString("61", 1);
if (TestUtilNip44Decryption(libCtx, sendKey, recvKey, payload, plainText) != 0)
{