diff options
45 files changed, 3045 insertions, 689 deletions
diff --git a/.onedev-buildspec.yml b/.onedev-buildspec.yml index ef1ac9d..8049766 100644 --- a/.onedev-buildspec.yml +++ b/.onedev-buildspec.yml @@ -11,7 +11,7 @@ jobs: condition: ALL_PREVIOUS_STEPS_WERE_SUCCESSFUL - !PushRepository name: Codeberg push sync - remoteUrl: https://codeberg.com/VnUgE/noscrypt.git + remoteUrl: https://codeberg.org/VnUgE/noscrypt.git userName: VnUgE passwordSecret: codeberg-access-token force: true diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..375d11c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,59 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.3-beta] - 2024-08-6 + +### Added +- Utilities sidecar library for easy note encryption (noscryptutil.h) +- Utilities for padding calculations +- Prints the name of the configured crypto backend during build +- Many internal hardening improvments (span pass-by-value, span validation functions) + +### Fixed +- OpenSSL EVP incorrect cipher initialization vector +- OpenSSL HKDF incorrect key derivation when switching to EVP api + +### Changed +- Updated libsecp256k1 to v0.5.1 +- Updated OpenSSL to v3.3.1 +- Converted `NCToSecKey()` and `NCToPubKey()` to a explicitly named macros +- Converted error code helper functions from header-only functions to standard api +- Added helper functions to alter the `NCEncryptionArgs` api. Altering fields directly is now deprecated. +- Public API visibility for non-Windows platforms now defaults to `extern` +- **Breaking:** Changed the `nonce32` and `hmacKeyOut32` properties of the `NCEncryptionArgs` struct to `nonceData` and `keyData` respectively. ABI is still compatible, but API has changed. Again mutating this structure manually is now deprecated. + +## [0.1.2] - 2024-05-29 + +### Added + +- `NCGetSharedContext()` to get a process-wide shared context. +- C++ extern wrappers noscrypt.h public api +- Integrated test exe to cmake ctest + +### Fixed + +- Potential memory leak for openssl evp contexts during error conditions. +- mbedtls dependency compilation when using fetch for release builds. +- fPIC errors for libsecp256k1. + +### Changed + +- Update libsecp256k1 to v0.5.0. +- **Breaking:** `NCValidateSecretKey()` retruns NC_SUCCESS instead of 1. +- Builds using OpenSSL as a crypto backend no longer require the monocypher dependency. + +### Removed + +- NCContext structure defintion. +- Internal headers from the public include directory. + +[unreleased]: https://github.com/VnUgE/noscrypt/compare/v0.1.3-beta...HEAD +[0.1.3-beta]: https://github.com/VnUgE/noscrypt/compare/v0.1.2...v0.1.3-beta +[0.1.2]: https://github.com/VnUgE/noscrypt/compare/v0.1.1...v0.1.2 +[0.1.1]: https://github.com/VnUgE/noscrypt/compare/v0.1.0...v0.1.1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a1f707..89b2026 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) @@ -50,7 +51,7 @@ if(NC_FETCH_SECP256K1) FetchContent_Declare( libsecp256k1 GIT_REPOSITORY https://github.com/bitcoin-core/secp256k1 - GIT_TAG e3a885d42a7800c1ccebad94ad1e2b82c4df5c65 # release-0.5.0 + GIT_TAG 642c885b6102725e25623738529895a95addc4f4 # release-0.5.1 GIT_PROGRESS TRUE ) @@ -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}) @@ -131,19 +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() -endif() - #Include mbedtls if enabled if(NC_FETCH_MBEDTLS) @@ -172,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") @@ -364,11 +379,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 1c8038d..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,34 +45,18 @@ "CRYPTO_LIB": "openssl" } }, - { - "name": "x64-release", - "displayName": "x64 Release", - "inherits": "x64-debug", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Release" - } - }, - { - "name": "x86-debug", - "displayName": "x86 Debug", - "inherits": "windows-base", - "architecture": { - "value": "x86", - "strategy": "external" - }, - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug", - "NC_BUILD_TESTS": true - } + { + "name": "x64-release", + "displayName": "x64 Release", + "inherits": "windows-base", + "architecture": { + "value": "x64", + "strategy": "external" }, - { - "name": "x86-release", - "displayName": "x86 Release", - "inherits": "x86-debug", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Release" - } + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "NC_ENABLE_UTILS": true } + } ] } diff --git a/GitVersion.yml b/GitVersion.yml new file mode 100644 index 0000000..ebdfba1 --- /dev/null +++ b/GitVersion.yml @@ -0,0 +1,6 @@ +assembly-versioning-scheme: MajorMinorPatch +mode: ContinuousDeployment +branches: {} +ignore: + sha: [] +merge-message-formats: {} diff --git a/Module.Taskfile.yaml b/Module.Taskfile.yaml index 0a80e30..d31449a 100644 --- a/Module.Taskfile.yaml +++ b/Module.Taskfile.yaml @@ -18,6 +18,10 @@ tasks: - git reset --hard - git remote update - git pull origin {{.BRANCH_NAME}} --verify-signatures + + #updates the project versions for all inlcuded .NET projects + - dotnet-gitversion.exe /updateprojectfiles + #called by build pipeline to build module build: @@ -63,7 +63,7 @@ The following table lists the supported platforms and cryptography libraries tha GitHub is simply a mirror for my projects. Extended documentation, pre-compiled binaries and source code bundles are always available on my website, along with PGP signatures and checksums. - **[Documentation](https://www.vaughnnugent.com/resources/software/articles?tags=docs,_noscrypt)** -- **[Signed builds and sourcecode ](https://www.vaughnnugent.com/resources/software/modules/noscrypt)** +- **[Signed builds and source code](https://www.vaughnnugent.com/resources/software/modules/noscrypt)** ### Getting the package There are 3 ways to get the source code to build this project. diff --git a/Taskfile.yaml b/Taskfile.yaml index a79921c..0af15f3 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,35 @@ 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" @@ -134,6 +176,7 @@ tasks: - task: dev-update-monocypher - task: dev-update-mbedtls-headers - task: dev-update-openssl-headers + - task: dev-set-secp256-headers dev-update-monocypher: vars: @@ -162,13 +205,13 @@ tasks: - git clone --branch {{ .MBEDTLS_GIT_BRANCH }} {{ .MBEDTLS_GIT_URL }} '{{ .TMP_DIR }}' - - for: [ 'include/mbedtls', 'include/psa' ] + - for: [ 'include/mbedtls' ] cmd: powershell cp -Recurse -Force '{{ .TMP_DIR }}/{{ .ITEM }}' '{{.MBEDTLS_DIR}}/include' dev-update-openssl-headers: vars: - OPENSSL_GIT_URL: 'git://git.openssl.org/openssl.git' - OPENSSL_GIT_BRANCH: 'master' + OPENSSL_GIT_URL: 'https://github.com/openssl/openssl' + OPENSSL_GIT_BRANCH: 'openssl-3.3.1' OPENSSL_DIR: 'vendor/openssl' TMP_DIR: '.update/openssl' cmds: @@ -183,9 +226,9 @@ tasks: dev-set-secp256-headers: vars: SECP256_GIT_URL: 'https://github.com/bitcoin-core/secp256k1' - SECP256_GIT_BRANCH: 'v0.5.0' + SECP256_GIT_BRANCH: 'v0.5.1' SECP256_DIR: 'vendor/secp256k1' - TMP_DIR: '.update/openssl' + TMP_DIR: '.update/secp256k1' cmds: - cmd: powershell mkdir '{{.TMP_DIR}}' -Force ignore_error: true diff --git a/include/noscrypt.h b/include/noscrypt.h index cdc74fe..faad1f1 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 */ @@ -76,15 +76,16 @@ extern "C" { #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 -#define NC_NIP04_AES_IV_SIZE 0x10 /* AES IV size is 16 bytes (block size) */ +#define NC_MESSAGE_KEY_SIZE NIP44_MESSAGE_KEY_SIZE +#define NC_NIP04_AES_IV_SIZE 0x10 /* AES IV size is 16 bytes (aka cipher block size) */ +#define NC_NIP04_AES_KEY_SIZE 0x20 /* AES 256 key size */ /* * From spec * https://github.com/nostr-protocol/nips/blob/master/44.md#decryption */ #define NIP44_MIN_ENC_MESSAGE_SIZE 0x01 -#define NIP44_MAX_ENC_MESSAGE_SIZE 0xffff +#define NIP44_MAX_ENC_MESSAGE_SIZE UINT16_MAX #define NC_ENC_VERSION_NIP04 0x04 #define NC_ENC_VERSION_NIP44 0x2c @@ -112,6 +113,20 @@ extern "C" { #define E_VERSION_NOT_SUPPORTED -6 +/* +* ENCRYPTION ALTERATION PROPERTEIS +* +* Codes for assigning values to an NCEncryptionArgs +* structure. +*/ + +#define NC_ENC_SET_VERSION 0x01 +#define NC_ENC_SET_NIP44_NONCE 0x02 +#define NC_ENC_SET_NIP44_MAC_KEY 0x03 +#define NC_ENC_SET_NIP04_KEY 0x04 +#define NC_ENC_SET_NIP04_IV 0x05 + + /* A compressed resul/return value, negative values are failure, 0 is success and positive values are defined by the operation. @@ -149,11 +164,11 @@ data buffers and required nonce used for the stream cipher. typedef struct nc_encryption_struct { /* The nonce used for the stream cipher. */ - const uint8_t* nonce32; + const uint8_t* nonceData; /* Writes the hmac key to the buffer during encryption events. Set to NULL on decryption */ - uint8_t* hmacKeyOut32; + uint8_t* keyData; /* The input data buffer to encrypt/decrypt */ const uint8_t* inputData; @@ -197,51 +212,26 @@ typedef struct nc_mac_verify { */ /* -* A helper function to cast a buffer to a NCSecretKey struct -* @param key The buffer to cast -* @return A pointer to the NCSecretKey struct +* Casts a buffer pointer to a NCSecretKey pointer */ -static _nc_fn_inline NCSecretKey* NCToSecKey(uint8_t key[NC_SEC_KEY_SIZE]) -{ - return (NCSecretKey*)key; -} +#define NCByteCastToSecretKey(key) (NCSecretKey*)key /* -* A helper function to cast a buffer to a NCPublicKey struct -* @param key The buffer to cast -* @return A pointer to the NCPublicKey struct +* Casts a buffer pointer to a NCPublicKey pointer */ -static _nc_fn_inline NCPublicKey* NCToPubKey(uint8_t key[NC_PUBKEY_SIZE]) -{ - return (NCPublicKey*)key; -} +#define NCByteCastToPublicKey(key) (NCPublicKey*)key -static _nc_fn_inline NCResult NCResultWithArgPosition(NCResult err, uint8_t argPosition) -{ - return -(((NCResult)argPosition << NC_ARG_POSITION_OFFSET) | -err); -} + +NC_EXPORT NCResult NC_CC 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 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 */ -static _nc_fn_inline int NCParseErrorCode(NCResult result, uint8_t* argPositionOut) -{ - NCResult asPositive; - int code; - - /* convert result to a positive value*/ - 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); - *argPositionOut = (asPositive >> NC_ARG_POSITION_OFFSET) & 0xFF; - - return code; -} +NC_EXPORT int NC_CC NCParseErrorCode(NCResult result, uint8_t* argPositionOut); /*-------------------------------------- * LIB CONTEXT API @@ -578,6 +568,57 @@ NC_EXPORT NCResult NCComputeMac( uint8_t hmacOut[NC_ENCRYPTION_MAC_SIZE] ); + +/* +* A special function that configures custom properties on +* the NCEncryptionArgs structure for a given operation. +* @param args A pointer to the encryption arguments structure +* @param property The ID property to set +* @param value The value to set the property to as a 32-bit integer +* @return NC_SUCCESS if the operation was successful, otherwise an error code. Use NCParseErrorCode to +* the error code and positional argument that caused the error. +*/ +NC_EXPORT NCResult NCSetEncryptionProperty( + NCEncryptionArgs* args, + uint32_t property, + uint32_t value +); + +/* +* A special function that configures custom properties on +* the NCEncryptionArgs structure for a given operation. +* +* @param args A pointer to the encryption arguments structure +* @param property The ID property to set +* @param value The value to set the property to as a byte buffer +* @param valueLen The length of the value buffer +* @return NC_SUCCESS if the operation was successful, otherwise an error code. Use NCParseErrorCode to +* the error code and positional argument that caused the error. +*/ +NC_EXPORT NCResult NCSetEncryptionPropertyEx( + NCEncryptionArgs* args, + uint32_t property, + uint8_t* value, + uint32_t valueLen +); + +/* +* Sets the encryption data buffers for the encryption/decryption +* operation. +* @param args A pointer to the encryption arguments structure +* @param input The input data buffer +* @param output The output data buffer +* @param dataSize The size of the data buffers +* @return NC_SUCCESS if the operation was successful, otherwise an error code. Use NCParseErrorCode to +* the error code and positional argument that caused the error. +*/ +NC_EXPORT NCResult NCSetEncryptionData( + NCEncryptionArgs* args, + const uint8_t* input, + uint8_t* output, + uint32_t dataSize +); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/include/noscryptutil.h b/include/noscryptutil.h new file mode 100644 index 0000000..bd60c79 --- /dev/null +++ b/include/noscryptutil.h @@ -0,0 +1,183 @@ +/* +* 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/. +*/ + +/* +* This header includes some optional high-level nostr crypto utility functions +* for much easer app development. +*/ + +#pragma once + +#ifndef NOSCRYPTUTIL_H +#define NOSCRYPTUTIL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "noscrypt.h" + +#define E_OUT_OF_MEMORY -10 + +#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 E_CIPHER_BAD_INPUT -15 +#define E_CIPHER_BAD_INPUT_SIZE -16 + +#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 +* of the encryption operation. The structure is opaque and should not be accessed +* directly. +*/ +typedef struct nc_util_enc_struct NCUtilCipherContext; + +/* +* Gets the size of the padded buffer required for an encryption operation. +* @param encVersion The encryption specification version to use +* @param plaintextSize The size of the plaintext buffer in bytes +* @return The size of the padded buffer in bytes +*/ +NC_EXPORT NCResult NC_CC NCUtilGetEncryptionPaddedSize(uint32_t encVersion, uint32_t plaintextSize); + +/* +* Gets the size of the payload buffer required for an encryption operation. +* @param encVersion The encryption specification version to use +* @param plaintextSize The size of the plaintext buffer in bytes +* @return The size of the payload buffer in bytes +* @note The payload buffer is the final buffer to be sent to a nostr user. For nip04 this +* is a raw AES message, for nip44 this is a mucher lager buffer. See the nostr specifications +* for more information. +*/ +NC_EXPORT NCResult NC_CC NCUtilGetEncryptionBufferSize(uint32_t encVersion, uint32_t plaintextSize); + +/* +* Allocates a new encryption context and sets the encryption version and flags. The encryption context +* must be freed with NCUtilCipherFree when it is no longer needed. +* @param encVersion The encryption specification version to use +* @param flags The flags to set on the encryption context +* @return A valid pointer to an encryption context or NULL if the operation failed +*/ +NC_EXPORT NCUtilCipherContext* NC_CC NCUtilCipherAlloc(uint32_t encVersion, uint32_t flags); + +/* +* Initializes the cipher context with the input data and size. This function will + internally allocate a the required output buffer for the cipher operation. You may only call + this function once. +* @param encCtx A valid pointer to an allocated encryption context +* @param inputData A pointer to the input data for the Cipher +* @param inputSize The size of the input data +* @return NC_SUCCESS if the operation was successful, otherwise an error code. Use NCParseErrorCode to +the error code and positional argument that caused the error +*/ +NC_EXPORT NCResult NC_CC NCUtilCipherInit( + NCUtilCipherContext* encCtx, + const uint8_t* inputData, + uint32_t inputSize +); + +/* +* Frees the encryption context and clears the memory if the NC_UTIL_CIPHER_ZERO_ON_FREE +* flag is set. +* @param encCtx A valid pointer to an allocated encryption context to free +*/ +NC_EXPORT void NC_CC NCUtilCipherFree(NCUtilCipherContext* encCtx); + +/* +* Gets the output size of the encryption context. This function will return the size of +* the output buffer that will be written to when calling NCUtilCipherReadOutput. +* @param encCtx A valid pointer to an allocated encryption context +* @return The size of the output buffer in bytes +*/ +NC_EXPORT NCResult NC_CC NCUtilCipherGetOutputSize(const NCUtilCipherContext* encCtx); + +/* +* Reads the output buffer from the encryption context. This function will copy the output +* buffer to the output buffer provided. The output buffer must be at least the size of the +* output buffer returned by NCUtilCipherGetOutputSize. +* @param encCtx A valid pointer to an initialized encryption context +* @param output A pointer to the output buffer to copy the output to +* @param outputSize The size of the output buffer in bytes +* @returns The number of bytes written to the output buffer or an error code. Use NCParseErrorCode +* to get the error code and positional argument that caused the error +*/ +NC_EXPORT NCResult NC_CC NCUtilCipherReadOutput( + const NCUtilCipherContext* encCtx, + uint8_t* output, + uint32_t outputSize +); + +/* +* Sets a property on the encryption context. Equivalent to calling NCSetEncryptionPropertyEx +* @param ctx A valid pointer to an encryption context +* @param property The property to set +* @param value A pointer to the value to set +* @param valueLen The length of the value +* @return NC_SUCCESS if the operation was successful, otherwise an error code. Use NCParseErrorCode to +* get the error code and positional argument that caused the error +*/ +NC_EXPORT NCResult NC_CC NCUtilCipherSetProperty( + NCUtilCipherContext* ctx, + uint32_t property, + uint8_t* value, + uint32_t valueLen +); + +/* +* Gets the flags set on the encryption context during initialization. +* @param ctx A valid pointer to an encryption context +* @return The flags set on the encryption context cast to a NCResult, or +* an error code if the context is invalid. Use NCParseErrorCode to get the error code +* and positional argument that caused the error. +*/ +NC_EXPORT NCResult NC_CC NCUtilCipherGetFlags(const NCUtilCipherContext* ctx); + +/* +* Performs the desired Cipher option once. This may either cause an encryption +* or decryption operation to be performed. Regardless of the operation, input data +* is consumed and output data is produced. +* @param encCtx A valid pointer to an initialized encryption context +* @param libContext A valid pointer to an NCContext structure +* @param sk A valid pointer to the sender's private key +* @param pk A valid pointer to the receivers public key +* @return NC_SUCCESS if the operation was successful, otherwise an error code. Use NCParseErrorCode to +* get the error code and positional argument that caused the error. +* @note This function should only be called once. However it is indempotent and deterministic +* so the exact same operation should happen if called again. +*/ +NC_EXPORT NCResult NC_CC NCUtilCipherUpdate( + NCUtilCipherContext* encCtx, + const NCContext* libContext, + const NCSecretKey* sk, + const NCPublicKey* pk +); + +#ifdef __cplusplus +} +#endif + +#endif /* NOSCRYPTUTIL_H */
\ No newline at end of file @@ -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) @@ -55,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); @@ -72,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)); + /* span over counter value that points to the counter buffer */ + 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; } @@ -93,7 +79,7 @@ cstatus_t hkdfExpandProcess( goto Exit; } - if (handler->update(ctx, &counterSpan) != CSTATUS_OK) + if (handler->update(ctx, counterSpan) != CSTATUS_OK) { goto Exit; } @@ -109,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(ncSpanGetSize(okm) - okmOffset, SHA256_DIGEST_SIZE); DEBUG_ASSERT(tLen <= sizeof(t)); - /* write the T buffer back to okm */ - ncWriteSpanS(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 */ @@ -42,20 +42,20 @@ /* 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, 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; }; 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 97b59cb..56bdf75 100644 --- a/src/nc-crypto.c +++ b/src/nc-crypto.c @@ -41,6 +41,7 @@ * _IMPL_CRYPTO_SHA256_DIGEST standard sha256 digest function * _IMPL_CRYPTO_SHA256_HKDF_EXPAND hkdf expand function * _IMPL_CRYPTO_SHA256_HKDF_EXTRACT hkdf extract function +* _IMPL_AES256_CBC_CRYPT performs an AES 256 CBC encryption/decryption * * Macros are used to allow the preprocessor to select the correct implementation * or raise errors if no implementation is defined. @@ -49,6 +50,26 @@ * calling function, and should return CSTATUS_OK on success, CSTATUS_FAIL on failure. */ +#define UNREFPARAM(x) (void)(x) + +_IMPLSTB cstatus_t _dummyAesFunc( + const uint8_t key[32], + const uint8_t iv[16], + const uint8_t* input, + uint8_t* output, + uint32_t dataSize +) +{ + UNREFPARAM(key); + UNREFPARAM(iv); + UNREFPARAM(input); + UNREFPARAM(output); + UNREFPARAM(dataSize); + + return CSTATUS_FAIL; +} + +#define _IMPL_AES256_CBC_CRYPT _dummyAesFunc /* * Prioritize embedded builds with mbedtls @@ -113,7 +134,7 @@ #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); } @@ -196,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" @@ -209,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" @@ -223,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 @@ -237,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; } @@ -249,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" @@ -271,10 +292,10 @@ cstatus_t ncCryptoChacha20( uint32_t dataSize ) { - DEBUG_ASSERT2(key != NULL, "Expected key to be non-null") - DEBUG_ASSERT2(nonce != NULL, "Expected nonce to be non-null") - DEBUG_ASSERT2(input != NULL, "Expected input to be non-null") - DEBUG_ASSERT2(output != NULL, "Expected output to be non-null") + DEBUG_ASSERT2(key != NULL, "Expected key to be non-null"); + DEBUG_ASSERT2(nonce != NULL, "Expected nonce to be non-null"); + DEBUG_ASSERT2(input != NULL, "Expected input to be non-null"); + DEBUG_ASSERT2(output != NULL, "Expected output to be non-null"); #ifndef _IMPL_CHACHA20_CRYPT #error "No chacha20 implementation defined" @@ -282,3 +303,23 @@ cstatus_t ncCryptoChacha20( return _IMPL_CHACHA20_CRYPT(key, nonce, input, output, dataSize); } + +cstatus_t ncAes256CBCEncrypt( + const uint8_t key[32], + const uint8_t iv[16], + const uint8_t* input, + uint8_t* output, + uint32_t dataSize +) +{ + DEBUG_ASSERT2(key != NULL, "Expected key to be non-null") + DEBUG_ASSERT2(iv != NULL, "Expected iv to be non-null") + DEBUG_ASSERT2(input != NULL, "Expected input to be non-null") + DEBUG_ASSERT2(output != NULL, "Expected output to be non-null") + +#ifndef _IMPL_AES256_CBC_CRYPT + #error "No AES256 CBC encrypt implementation defined" +#endif /* !_IMPL_AES256_CBC_CRYPT */ + + return _IMPL_AES256_CBC_CRYPT(key, iv, input, output, dataSize); +}
\ No newline at end of file diff --git a/src/nc-crypto.h b/src/nc-crypto.h index f04ebe0..a1545de 100644 --- a/src/nc-crypto.h +++ b/src/nc-crypto.h @@ -29,6 +29,8 @@ #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 */ #define SHA256_DIGEST_SIZE 0x20u /* Size of 32 is set by the cipher spec */ +#define AES_IV_SIZE 0x10u /* CBC IV size matches the AES block size of 128 */ +#define AES_KEY_SIZE 0x20u /* AES 256 key size */ typedef uint8_t cstatus_t; #define CSTATUS_OK ((cstatus_t)0x01u) @@ -40,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], @@ -56,4 +58,12 @@ cstatus_t ncCryptoChacha20( uint32_t dataSize ); +cstatus_t ncAes256CBCEncrypt( + const uint8_t key[32], + const uint8_t iv[16], + const uint8_t* input, + uint8_t* output, + uint32_t dataSize +); + #endif /* !_NC_CRYPTO_H */ diff --git a/src/nc-util.h b/src/nc-util.h index dd319c7..a248578 100644 --- a/src/nc-util.h +++ b/src/nc-util.h @@ -68,6 +68,32 @@ #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 */ + +#ifndef EMPTY_SPANS + #define EMPTY_SPANS 1 +#endif + typedef struct memory_span_struct { uint8_t* data; @@ -80,6 +106,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; @@ -92,4 +138,132 @@ 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) +{ + +#if EMPTY_SPANS + + /* + * Allow passing null pointers for empty spans, if enabled, + * otherwise debug guards will catch empty spans + */ + if (span.size == 0 && offset == 0) + { + return NULL; + } + +#endif /* !EMPTY_SPANS */ + + 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) +{ + cspan_t cspan; + ncSpanInitC(&cspan, span.data, span.size); + return (uint8_t*)ncSpanGetOffsetC(cspan, offset); +} + +static _nc_fn_inline uint32_t ncSpanGetSizeC(cspan_t span) +{ + return ncSpanIsValidC(span) + ? span.size + : 0; +} + +static _nc_fn_inline uint32_t ncSpanGetSize(span_t span) +{ + return ncSpanIsValid(span) + ? span.size + : 0; +} + +static _nc_fn_inline void ncSpanWrite(span_t span, uint32_t offset, const uint8_t* data, uint32_t size) +{ + 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") + + /* 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(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") + + /* Copy data to span */ + MEMMOV(span.data + *offset, data, size); + + /* Increment offset */ + *offset += size; +} + +static _nc_fn_inline span_t ncSpanSlice(span_t span, uint32_t offset, uint32_t size) +{ + span_t slice; + + 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 */ + ncSpanInit(&slice, span.data + offset, size); + + return slice; +} + +static _nc_fn_inline cspan_t ncSpanSliceC(cspan_t span, uint32_t offset, uint32_t size) +{ + cspan_t slice; + + 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 */ + ncSpanInitC(&slice, span.data + offset, size); + + 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 f1aabd4..deadca6 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 @@ -247,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; } @@ -275,14 +274,13 @@ static cstatus_t _chachaEncipher(const struct nc_expand_keys* keys, NCEncryption static _nc_fn_inline cstatus_t _getMessageKey( const struct conversation_key* converstationKey, - const cspan_t* nonce, + cspan_t nonce, struct message_key* messageKey ) { cspan_t prkSpan; span_t okmSpan; - DEBUG_ASSERT2(nonce != NULL, "Expected valid nonce buffer") DEBUG_ASSERT2(converstationKey != NULL, "Expected valid conversation key") DEBUG_ASSERT2(messageKey != NULL, "Expected valid message key buffer") @@ -290,10 +288,10 @@ 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 _encryptEx( +static _nc_fn_inline NCResult _encryptNip44Ex( const NCContext* ctx, const struct conversation_key* ck, uint8_t* hmacKey, @@ -312,10 +310,10 @@ static _nc_fn_inline NCResult _encryptEx( result = NC_SUCCESS; - ncSpanInitC(&nonceSpan, args->nonce32, NC_ENCRYPTION_NONCE_SIZE); + ncSpanInitC(&nonceSpan, args->nonceData, NC_ENCRYPTION_NONCE_SIZE); /* Message key will be derrived on every encryption call */ - if (_getMessageKey(ck, &nonceSpan, &messageKey) != CSTATUS_OK) + if (_getMessageKey(ck, nonceSpan, &messageKey) != CSTATUS_OK) { result = E_OPERATION_FAILED; goto Cleanup; @@ -339,7 +337,7 @@ Cleanup: return result; } -static _nc_fn_inline NCResult _decryptEx(const NCContext* ctx, const struct conversation_key* ck, NCEncryptionArgs* args) +static _nc_fn_inline NCResult _decryptNip44Ex(const NCContext* ctx, const struct conversation_key* ck, NCEncryptionArgs* args) { NCResult result; cspan_t nonceSpan; @@ -352,9 +350,9 @@ static _nc_fn_inline NCResult _decryptEx(const NCContext* ctx, const struct conv result = NC_SUCCESS; - ncSpanInitC(&nonceSpan, args->nonce32, NC_ENCRYPTION_NONCE_SIZE); + ncSpanInitC(&nonceSpan, args->nonceData, NC_ENCRYPTION_NONCE_SIZE); - if (_getMessageKey(ck, &nonceSpan, &messageKey) != CSTATUS_OK) + if (_getMessageKey(ck, nonceSpan, &messageKey) != CSTATUS_OK) { result = E_OPERATION_FAILED; goto Cleanup; @@ -375,17 +373,16 @@ Cleanup: return result; } -static _nc_fn_inline cstatus_t _computeHmac(const uint8_t key[NC_HMAC_KEY_SIZE], const cspan_t* payload, sha256_t hmacOut) +static _nc_fn_inline cstatus_t _computeHmac(const uint8_t key[NC_HMAC_KEY_SIZE], cspan_t payload, sha256_t hmacOut) { cspan_t keySpan; DEBUG_ASSERT2(key != NULL, "Expected valid hmac key") - DEBUG_ASSERT2(payload != NULL, "Expected valid mac verification args") DEBUG_ASSERT2(hmacOut != NULL, "Expected valid hmac output buffer") ncSpanInitC(&keySpan, key, NC_HMAC_KEY_SIZE); - return ncCryptoHmacSha256(&keySpan, payload, hmacOut); + return ncCryptoHmacSha256(keySpan, payload, hmacOut); } static NCResult _verifyMacEx( @@ -411,7 +408,7 @@ static NCResult _verifyMacEx( * Message key is again required for the hmac verification */ - if (_getMessageKey((struct conversation_key*)conversationKey, &nonceSpan, &messageKey) != CSTATUS_OK) + if (_getMessageKey((struct conversation_key*)conversationKey, nonceSpan, &messageKey) != CSTATUS_OK) { result = E_OPERATION_FAILED; goto Cleanup; @@ -423,7 +420,7 @@ static NCResult _verifyMacEx( /* * Compute the hmac of the data using the computed hmac key */ - if (_computeHmac(keys->hmac_key, &payloadSpan, hmacOut) != CSTATUS_OK) + if (_computeHmac(keys->hmac_key, payloadSpan, hmacOut) != CSTATUS_OK) { result = E_OPERATION_FAILED; goto Cleanup; @@ -442,6 +439,40 @@ Cleanup: /* * EXTERNAL API FUNCTIONS */ + + +NC_EXPORT NCResult NC_CC NCResultWithArgPosition(NCResult err, uint8_t argPosition) +{ + return -(((NCResult)argPosition << NC_ARG_POSITION_OFFSET) | -err); +} + +NC_EXPORT int NC_CC NCParseErrorCode(NCResult result, uint8_t* argPositionOut) +{ + NCResult asPositive; + int code; + + /* convert result to a positive value*/ + 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); + + /* Allow argument position assignment to be null */ + if (argPositionOut) + { + *argPositionOut = (asPositive >> NC_ARG_POSITION_OFFSET) & 0xFF; + } + + return code; +} + +/* ============================= +* +* Context functions +* +* ============================= +*/ + NC_EXPORT uint32_t NC_CC NCGetContextStructSize(void) { return sizeof(NCContext); @@ -499,7 +530,13 @@ NC_EXPORT NCResult NC_CC NCDestroyContext(NCContext* ctx) return NC_SUCCESS; } -/* KEY Functions */ +/* ============================= +* +* ECDSA functions +* +* ============================= +*/ + NC_EXPORT NCResult NC_CC NCGetPublicKey( const NCContext* ctx, const NCSecretKey* sk, @@ -615,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; } @@ -646,7 +683,6 @@ NC_EXPORT NCResult NC_CC NCVerifyDigest( return E_INVALID_ARG; } - /* Verify the signature */ result = secp256k1_schnorrsig_verify(ctx->secpCtx, sig64, digest32, 32, &xonly); ZERO_FILL(&xonly, sizeof(xonly)); @@ -674,16 +710,20 @@ 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; } - /* Verify the freshly computed digest */ return NCVerifyDigest(ctx, pk, digest, sig64); } -/* ECDH Functions */ +/* ============================= +* +* ECDH functions +* +* ============================= +*/ NC_EXPORT NCResult NC_CC NCGetSharedSecret( const NCContext* ctx, @@ -765,11 +805,28 @@ NC_EXPORT NCResult NC_CC NCEncryptEx( /* Validte ciphertext/plaintext */ CHECK_INVALID_ARG(args->inputData, 2) CHECK_INVALID_ARG(args->outputData, 2) - CHECK_INVALID_ARG(args->nonce32, 2) - CHECK_INVALID_ARG(args->hmacKeyOut32, 2) + CHECK_INVALID_ARG(args->nonceData, 2) + CHECK_INVALID_ARG(args->keyData, 2) CHECK_ARG_RANGE(args->dataSize, NIP44_MIN_ENC_MESSAGE_SIZE, NIP44_MAX_ENC_MESSAGE_SIZE, 2) - return _encryptEx(ctx, (struct conversation_key*)conversationKey, args->hmacKeyOut32, args); + switch (args->version) + { + /* TODO: Implement nip04 */ + case NC_ENC_VERSION_NIP04: + return E_VERSION_NOT_SUPPORTED; + + case NC_ENC_VERSION_NIP44: + return _encryptNip44Ex( + ctx, + (struct conversation_key*)conversationKey, + args->keyData, + args + ); + + default: + return E_VERSION_NOT_SUPPORTED; + } + } NC_EXPORT NCResult NC_CC NCEncrypt( @@ -792,34 +849,42 @@ NC_EXPORT NCResult NC_CC NCEncrypt( /* Validate input/output data */ CHECK_INVALID_ARG(args->inputData, 3) CHECK_INVALID_ARG(args->outputData, 3) - CHECK_INVALID_ARG(args->nonce32, 3) - CHECK_INVALID_ARG(args->hmacKeyOut32, 3) - CHECK_ARG_RANGE(args->dataSize, NIP44_MIN_ENC_MESSAGE_SIZE, NIP44_MAX_ENC_MESSAGE_SIZE, 3) + CHECK_INVALID_ARG(args->nonceData, 3) + + result = E_OPERATION_FAILED; switch(args->version) { case NC_ENC_VERSION_NIP44: - break; /* Allow nip44 */ + { + /* Mac key output is only needed for nip44 */ + CHECK_INVALID_ARG(args->keyData, 3) + CHECK_ARG_RANGE(args->dataSize, NIP44_MIN_ENC_MESSAGE_SIZE, NIP44_MAX_ENC_MESSAGE_SIZE, 3) + + /* Compute the shared point */ + if ((result = _computeSharedSecret(ctx, sk, pk, &sharedSecret)) != NC_SUCCESS) + { + goto Cleanup; + } + + /* Compute the conversation key from secret and pubkic keys */ + if ((result = _computeConversationKey(ctx, &sharedSecret, &conversationKey)) != NC_SUCCESS) + { + goto Cleanup; + } + + result = _encryptNip44Ex(ctx, &conversationKey, args->keyData, args); + } + + break; /* At the moment nip04 compatability is not supported */ case NC_ENC_VERSION_NIP04: default: - return E_VERSION_NOT_SUPPORTED; + result = E_VERSION_NOT_SUPPORTED; + break; } - /* Compute the shared point */ - if ((result = _computeSharedSecret(ctx, sk, pk, &sharedSecret)) != NC_SUCCESS) - { - goto Cleanup; - } - - /* Compute the conversation key from secret and pubkic keys */ - if ((result = _computeConversationKey(ctx, &sharedSecret, &conversationKey)) != NC_SUCCESS) - { - goto Cleanup; - } - - result = _encryptEx(ctx, &conversationKey, args->hmacKeyOut32, args); Cleanup: /* Clean up sensitive data */ @@ -830,8 +895,8 @@ Cleanup: } NC_EXPORT NCResult NC_CC NCDecryptEx( - const NCContext* ctx, - const uint8_t conversationKey[NC_CONV_KEY_SIZE], + const NCContext* ctx, + const uint8_t conversationKey[NC_CONV_KEY_SIZE], NCEncryptionArgs* args ) { @@ -843,10 +908,18 @@ NC_EXPORT NCResult NC_CC NCDecryptEx( /* Validte ciphertext/plaintext */ CHECK_INVALID_ARG(args->inputData, 2) CHECK_INVALID_ARG(args->outputData, 2) - CHECK_INVALID_ARG(args->nonce32, 2) + CHECK_INVALID_ARG(args->nonceData, 2) CHECK_ARG_RANGE(args->dataSize, NIP44_MIN_ENC_MESSAGE_SIZE, NIP44_MAX_ENC_MESSAGE_SIZE, 2) - return _decryptEx(ctx, (struct conversation_key*)conversationKey, args); + switch (args->version) + { + case NC_ENC_VERSION_NIP44: + return _decryptNip44Ex(ctx, (struct conversation_key*)conversationKey, args); + + case NC_ENC_VERSION_NIP04: + default: + return E_VERSION_NOT_SUPPORTED; + } } NC_EXPORT NCResult NC_CC NCDecrypt( @@ -869,20 +942,34 @@ NC_EXPORT NCResult NC_CC NCDecrypt( /* Validte ciphertext/plaintext */ CHECK_INVALID_ARG(args->inputData, 3) CHECK_INVALID_ARG(args->outputData, 3) - CHECK_INVALID_ARG(args->nonce32, 3) + CHECK_INVALID_ARG(args->nonceData, 3) CHECK_ARG_RANGE(args->dataSize, NIP44_MIN_ENC_MESSAGE_SIZE, NIP44_MAX_ENC_MESSAGE_SIZE, 3) - if ((result = _computeSharedSecret(ctx, sk, pk, &sharedSecret)) != NC_SUCCESS) - { - goto Cleanup; - } + result = E_OPERATION_FAILED; - if ((result = _computeConversationKey(ctx, &sharedSecret, &conversationKey)) != NC_SUCCESS) + switch (args->version) { - goto Cleanup; + case NC_ENC_VERSION_NIP44: + { + if ((result = _computeSharedSecret(ctx, sk, pk, &sharedSecret)) != NC_SUCCESS) + { + goto Cleanup; + } + + if ((result = _computeConversationKey(ctx, &sharedSecret, &conversationKey)) != NC_SUCCESS) + { + goto Cleanup; + } + + result = _decryptNip44Ex(ctx, &conversationKey, args); } + break; - result = _decryptEx(ctx, &conversationKey, args); + case NC_ENC_VERSION_NIP04: + default: + result = E_VERSION_NOT_SUPPORTED; + break; + } Cleanup: /* Clean up sensitive data */ @@ -914,7 +1001,7 @@ NC_EXPORT NCResult NCComputeMac( /* * Compute the hmac of the data using the supplied hmac key */ - return _computeHmac(hmacKey, &payloadSpan, hmacOut) == CSTATUS_OK ? NC_SUCCESS : E_OPERATION_FAILED; + return _computeHmac(hmacKey, payloadSpan, hmacOut) == CSTATUS_OK ? NC_SUCCESS : E_OPERATION_FAILED; } @@ -978,4 +1065,125 @@ Cleanup: ZERO_FILL(&conversationKey, sizeof(conversationKey)); return result; +} + +#define ENSURE_ENC_MODE(args, mode) if(args->version != mode) return E_VERSION_NOT_SUPPORTED; + +NC_EXPORT NCResult NCSetEncryptionPropertyEx( + NCEncryptionArgs* args, + uint32_t property, + uint8_t* value, + uint32_t valueLen +) +{ + + CHECK_NULL_ARG(args, 0) + CHECK_NULL_ARG(value, 2) + + switch (property) + { + case NC_ENC_SET_VERSION: + + /* Ensure version is proper length */ + CHECK_ARG_RANGE(valueLen, sizeof(uint32_t), sizeof(uint32_t), 2) + + args->version = *((uint32_t*)value); + + return NC_SUCCESS; + + case NC_ENC_SET_NIP04_IV: + /* + * The safest way to store the nip04 IV is in the nonce + * field. An IV is essentially a nonce. A secure random + * number used to encrypt the first block of a CBC chain. + */ + + CHECK_ARG_RANGE(valueLen, AES_IV_SIZE, UINT32_MAX, 3) + + ENSURE_ENC_MODE(args, NC_ENC_VERSION_NIP04) + + args->nonceData = value; + + return NC_SUCCESS; + + + case NC_ENC_SET_NIP04_KEY: + /* + * The AES key is stored in the hmac key field, since + * it won't be used for the operating and should be the same size + * as the hmac key. + */ + + CHECK_ARG_RANGE(valueLen, AES_KEY_SIZE, UINT32_MAX, 3) + + ENSURE_ENC_MODE(args, NC_ENC_VERSION_NIP04) + + args->keyData = value; + + return NC_SUCCESS; + + case NC_ENC_SET_NIP44_NONCE: + + /* Nonce buffer must be at least the size, max doesnt matter */ + CHECK_ARG_RANGE(valueLen, NC_ENCRYPTION_NONCE_SIZE, UINT32_MAX, 3) + + /* Nonce is only used in nip44 mode */ + ENSURE_ENC_MODE(args, NC_ENC_VERSION_NIP44) + + args->nonceData = value; + + return NC_SUCCESS; + + case NC_ENC_SET_NIP44_MAC_KEY: + + /* The maximum size of the buffer doesn't matter as long as its larger than the key size */ + CHECK_ARG_RANGE(valueLen, NC_HMAC_KEY_SIZE, UINT32_MAX, 3) + + /* Mac key is only used in nip44 mode */ + ENSURE_ENC_MODE(args, NC_ENC_VERSION_NIP44) + + /* + * During encryption the key data buffer is used + * to write the hmac hey used for MAC computation + * operations. + */ + args->keyData = value; + + return NC_SUCCESS; + } + + return E_INVALID_ARG; +} + +NC_EXPORT NCResult NCSetEncryptionProperty( + NCEncryptionArgs* args, + uint32_t property, + uint32_t value +) +{ + return NCSetEncryptionPropertyEx( + args, + property, + (uint8_t*)&value, + sizeof(uint32_t) + ); +} + +NC_EXPORT NCResult NCSetEncryptionData( + NCEncryptionArgs* args, + const uint8_t* input, + uint8_t* output, + uint32_t dataSize +) +{ + CHECK_NULL_ARG(args, 0) + CHECK_NULL_ARG(input, 1) + CHECK_NULL_ARG(output, 2) + CHECK_ARG_RANGE(dataSize, NIP44_MIN_ENC_MESSAGE_SIZE, NIP44_MAX_ENC_MESSAGE_SIZE, 3) + + args->inputData = input; + args->outputData = output; + args->dataSize = dataSize; + + return NC_SUCCESS; }
\ No newline at end of file diff --git a/src/noscryptutil.c b/src/noscryptutil.c new file mode 100644 index 0000000..4cee2c3 --- /dev/null +++ b/src/noscryptutil.c @@ -0,0 +1,910 @@ +/* +* 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 <stdlib.h> + +#include "nc-util.h" +#include "nc-crypto.h" + +#include <noscryptutil.h> + +/* +* Validation macros +*/ + +#ifdef NC_EXTREME_COMPAT + #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) + +/* +* Max payload size is the maximum size of the encrypted message +* 1 byte version + 32 byte nonce + 32 byte mac + maximum ciphertext size +*/ +#define NIP44_MAX_PAYLOAD_SIZE (NIP44_VERSION_SIZE + 0x20 + 0x20 + NIP44_MAX_ENC_MESSAGE_SIZE) + +/* +* 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 + +#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); + #define CHECK_ARG_IS(exp, argPos) if(!(exp)) return NCResultWithArgPosition(E_INVALID_ARG, argPos); +#else + /* empty macros */ + #define CHECK_INVALID_ARG(x) + #define CHECK_NULL_ARG(x, argPos) + #define CHECK_ARG_RANGE(x, min, max, argPos) + #define CHECK_ARG_IS(is, expected, argPos) +#endif /* !NC_DISABLE_INPUT_VALIDATION */ + +#ifdef _NC_IS_WINDOWS + + #include <math.h> + + /* performs a log2 on integer types */ + #define _math_int_log2(x) (uint32_t)log2((double)x) + +#else + /* + * GCC/clang does not expose log2 so we can use the __builtin_clz + * to find leading zeros of an integer and subtract that from 31 + * (bit positions) for int32 + */ + static _nc_fn_inline uint32_t _math_int_log2(uint32_t val) + { + DEBUG_ASSERT(val < UINT32_MAX); + + return 31 - __builtin_clz(val); + } +#endif + +/* Currently were on nip44 version 2 */ +static const uint8_t Nip44VersionValue[1] = { 0x02u }; + +struct cipher_buffer_state { + + cspan_t input; + span_t output; + + cspan_t actualOutput; +}; + +struct nc_util_enc_struct { + + uint32_t _flags; + + NCEncryptionArgs encArgs; + + struct cipher_buffer_state buffer; +}; + +static _nc_fn_inline span_t _ncUtilAllocSpan(uint32_t count, size_t size) +{ + span_t span; + +#if SIZE_MAX < UINT32_MAX + + if (count > SIZE_MAX) + { + return span; + } + +#endif + + span.data = _nc_mem_alloc((size_t)count, size); + span.size = (uint32_t)count; + + 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); +} + +static _nc_fn_inline uint32_t _calcNip44PtPadding(uint32_t plaintextSize) +{ + uint32_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; + } + + /* Safe to subtract because pt > 0 */ + nextPower = _math_int_log2(plaintextSize - 1); + + nextPower += 1u; + + nextPower = 1 << nextPower; + + if (nextPower <= 256u) + { + chunk = 32u; + } + else + { + chunk = nextPower / 8u; + } + + factor = plaintextSize - 1; + + factor /= chunk; + + factor += 1; + + return chunk * factor; +} + +static _nc_fn_inline uint32_t _calcNip44TotalOutSize(uint32_t inputSize) +{ + uint32_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 _nc_fn_inline span_t _nip44GetMacData(span_t payload) +{ + DEBUG_ASSERT(payload.size > NIP44_VERSION_SIZE + NC_ENCRYPTION_MAC_SIZE); + + /* + * The nip44 mac is computed over the nonce+encrypted ciphertext + * + * the ciphertext is the entire message buffer, so it includes + * version, nonce, data, padding, and mac space available. + * + * This function will return a span that points to the nonce+data + * segment of the buffer for mac computation. + * + * The nonce sits directly after the version byte, ct is after, + * and the remaining 32 bytes are for the mac. So that means + * macData = ct.size - version.size + mac.size + */ + + return ncSpanSlice( + payload, + NIP44_VERSION_SIZE, + payload.size - (NIP44_VERSION_SIZE + NC_ENCRYPTION_MAC_SIZE) + ); +} + +static _nc_fn_inline span_t _nip44GetMacOutput(span_t payload) +{ + DEBUG_ASSERT(payload.size > NC_ENCRYPTION_MAC_SIZE); + + /* + * Mac is the final 32 bytes of the ciphertext buffer + */ + return ncSpanSlice( + payload, + payload.size - NC_ENCRYPTION_MAC_SIZE, + NC_ENCRYPTION_MAC_SIZE + ); +} + +static _nc_fn_inline int _nip44ParseSegments( + cspan_t payload, + cspan_t* nonce, + cspan_t* mac, + cspan_t* macData, + cspan_t* cipherText +) +{ + 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 + */ + *mac = ncSpanSliceC( + payload, + payload.size - NC_ENCRYPTION_MAC_SIZE, + NC_ENCRYPTION_MAC_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) + ); + + /* + * 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 void _cipherPublishOutput(NCUtilCipherContext* buffer, uint32_t offset, uint32_t size) +{ + span_t slice; + + 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); + + /* init readonly span from mutable */ + ncSpanInitC( + &buffer->buffer.actualOutput, + ncSpanGetOffset(slice, 0), + ncSpanGetSize(slice) + ); + } +} + +/* +* 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, + NCUtilCipherContext* state +) +{ + + NCResult result; + cspan_t plainText; + span_t macData, macOutput, message; + uint32_t outPos; + uint8_t ptSize[NIP44_PT_LEN_SIZE]; + uint8_t hmacKeyOut[NC_ENCRYPTION_MAC_SIZE]; + NCEncryptionArgs encArgs; + + outPos = 0; + encArgs = state->encArgs; + message = state->buffer.output; + plainText = state->buffer.input; + + DEBUG_ASSERT(encArgs.version == NC_ENC_VERSION_NIP44); + + ZERO_FILL(hmacKeyOut, sizeof(hmacKeyOut)); + + /* Start by appending the version number */ + ncSpanAppend(message, &outPos, Nip44VersionValue, sizeof(Nip44VersionValue)); + + /* next is nonce data */ + ncSpanAppend(message, &outPos, encArgs.nonceData, NC_ENCRYPTION_NONCE_SIZE); + DEBUG_ASSERT(outPos == 1 + NC_ENCRYPTION_NONCE_SIZE); + + /* + * Assign the hmac key from the stack buffer. Since the args structure + * is copied, it won't leak the address to the stack buffer. + * + * Should always return success for nip44 because all properties are valid + * addresses. + */ + + result = NCSetEncryptionPropertyEx( + &encArgs, + NC_ENC_SET_NIP44_MAC_KEY, + hmacKeyOut, + sizeof(hmacKeyOut) + ); + + DEBUG_ASSERT(result == NC_SUCCESS); + + /* + * 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. + */ + + result = NCSetEncryptionData( + &encArgs, + ncSpanGetOffset(message, outPos), /* in place encryption */ + ncSpanGetOffset(message, outPos), + NIP44_PT_LEN_SIZE + _calcNip44PtPadding(plainText.size) /* Plaintext + pt size must be encrypted */ + ); + + DEBUG_ASSERT(result == NC_SUCCESS); + + /* big endian plaintext size */ + ptSize[0] = (uint8_t)(ncSpanGetSizeC(plainText) >> 8); + ptSize[1] = (uint8_t)(ncSpanGetSizeC(plainText) & 0xFF); + + /* + * Written position must point to the end of the padded ciphertext + * area which the plaintext is written to. + * + * The plaintext data will be encrypted in place. The encrypted + * data is the entired padded region containing the leading byte count + * the plaintext data, followed by zero padding. + */ + + ncSpanWrite(message, outPos, ptSize, sizeof(ptSize)); + + ncSpanWrite( + message, + outPos + NIP44_PT_LEN_SIZE, /* write pt directly after length */ + ncSpanGetOffsetC(plainText, 0), + ncSpanGetSizeC(plainText) + ); + + /* Move position pointer directly after final padding bytes */ + outPos += encArgs.dataSize; + + result = NCEncrypt(libContext, sk, pk, &encArgs); + + if (result != NC_SUCCESS) + { + return result; + } + + /* + MAC is computed over the nonce+encrypted data + this helper captures that data segment into a span + */ + + macData = _nip44GetMacData(message); + macOutput = _nip44GetMacOutput(message); + + result = NCComputeMac( + libContext, + hmacKeyOut, + ncSpanGetOffset(macData, 0), + ncSpanGetSize(macData), + ncSpanGetOffset(macOutput, 0) + ); + + if (result != NC_SUCCESS) + { + return result; + } + + outPos += NC_ENCRYPTION_MAC_SIZE; + + DEBUG_ASSERT2(outPos == message.size, "Buffer under/overflow detected"); + + /* publish all message bytes to output */ + _cipherPublishOutput(state, 0, outPos); + + /* zero hmac key before returning */ + ZERO_FILL(hmacKeyOut, sizeof(hmacKeyOut)); + + return NC_SUCCESS; +} + +static NCResult _nip44DecryptCompleteCore( + const NCContext* libContext, + const NCSecretKey* recvKey, + const NCPublicKey* sendKey, + NCUtilCipherContext* state +) +{ + NCResult result; + NCMacVerifyArgs macArgs; + NCEncryptionArgs encArgs; + cspan_t macData, macValue, nonce, payload, cipherText; + span_t output; + uint16_t ptSize; + + DEBUG_ASSERT(libContext && recvKey && sendKey && state); + DEBUG_ASSERT(state->encArgs.version == NC_ENC_VERSION_NIP44); + DEBUG_ASSERT(ncSpanGetSizeC(state->buffer.input) >= NIP44_MIN_PAYLOAD_SIZE); + + /* ensure decryption mode */ + DEBUG_ASSERT(state->_flags & NC_UTIL_CIPHER_MODE_DECRYPT); + + /* store local stack copy for safe mutation */ + encArgs = state->encArgs; + payload = state->buffer.input; + output = state->buffer.output; + + /* + * 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 + */ + + DEBUG_ASSERT2(ncSpanIsValid(output), "Output buffer was not allocated"); + + 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(ncSpanGetSizeC(macValue) == NC_ENCRYPTION_MAC_SIZE); + DEBUG_ASSERT(ncSpanGetSizeC(macData) > NC_ENCRYPTION_NONCE_SIZE + MIN_PADDING_SIZE); + + /* Assign the mac data to the mac verify args */ + macArgs.mac32 = ncSpanGetOffsetC(macValue, 0); + macArgs.nonce32 = ncSpanGetOffsetC(nonce, 0); + + /* message for verifying a mac in nip44 is the nonce+ciphertext */ + macArgs.payload = ncSpanGetOffsetC(macData, 0); + macArgs.payloadSize = ncSpanGetSizeC(macData); + + /* Verify the mac */ + result = NCVerifyMac(libContext, recvKey, sendKey, &macArgs); + + /* When the mac is invlaid */ + if (result == E_OPERATION_FAILED) + { + return E_CIPHER_MAC_INVALID; + } + /* argument errors */ + else if (result != NC_SUCCESS) + { + return result; + } + } + + /* + * manually assign nonce because it's a constant pointer which + * is not allowed when calling setproperty + */ + encArgs.nonceData = ncSpanGetOffsetC(nonce, 0); + + DEBUG_ASSERT2(cipherText.size >= MIN_PADDING_SIZE, "Cipertext segment was parsed incorrectly. Too small"); + + result = NCSetEncryptionData( + &encArgs, + ncSpanGetOffsetC(cipherText, 0), + ncSpanGetOffset(output, 0), /*decrypt ciphertext and write directly to the output buffer */ + ncSpanGetSizeC(cipherText) + ); + + 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; + } + + /* + * 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. + */ + + 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(ncSpanGetSizeC(state->buffer.actualOutput) < cipherText.size); + + return NC_SUCCESS; +} + +NC_EXPORT NCResult NC_CC NCUtilGetEncryptionPaddedSize(uint32_t encVersion, uint32_t plaintextSize) +{ + switch (encVersion) + { + default: + return E_VERSION_NOT_SUPPORTED; + + case NC_ENC_VERSION_NIP04: + return plaintextSize; + + case NC_ENC_VERSION_NIP44: + + /* + * Ensure the plaintext size if a nip44 message does not exceed the maximum size + */ + CHECK_ARG_IS(plaintextSize - 1 <= NIP44_MAX_ENC_MESSAGE_SIZE, 1); + + return (NCResult)(_calcNip44PtPadding(plaintextSize)); + } +} + +NC_EXPORT NCResult NC_CC NCUtilGetEncryptionBufferSize(uint32_t encVersion, uint32_t plaintextSize) +{ + + 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: + return (NCResult)(_calcNip44TotalOutSize(plaintextSize)); + } +} + + +NC_EXPORT NCUtilCipherContext* NC_CC NCUtilCipherAlloc(uint32_t encVersion, uint32_t flags) +{ + NCUtilCipherContext* encCtx; + + /* + * Alloc context on heap + */ + encCtx = (NCUtilCipherContext*)_nc_mem_alloc(1, sizeof(NCUtilCipherContext)); + + if (encCtx != NULL) + { + encCtx->encArgs.version = encVersion; + encCtx->_flags = flags; + } + + return encCtx; +} + +NC_EXPORT void NC_CC NCUtilCipherFree(NCUtilCipherContext* encCtx) +{ + if (!encCtx) + { + return; + } + + /* + * 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 && ncSpanIsValid(encCtx->buffer.output)) + { + _ncUtilZeroSpan(encCtx->buffer.output); + } + + /* Free output buffers (null buffers are allowed) */ + _ncUtilFreeSpan(encCtx->buffer.output); + + /* context can be released */ + _nc_mem_free(encCtx); +} + +NC_EXPORT NCResult NC_CC NCUtilCipherInit( + NCUtilCipherContext* encCtx, + const uint8_t* inputData, + uint32_t inputSize +) +{ + NCResult outputSize; + + CHECK_NULL_ARG(encCtx, 0); + CHECK_NULL_ARG(inputData, 1); + + if ((encCtx->_flags & NC_UTIL_CIPHER_MODE_DECRYPT) > 0) + { + /* + * Validate the input data for proper format for + * the current state version + */ + switch (encCtx->encArgs.version) + { + case NC_ENC_VERSION_NIP44: + { + if (inputSize < NIP44_MIN_PAYLOAD_SIZE) + { + return E_CIPHER_BAD_INPUT_SIZE; + } + + if (inputSize > NIP44_MAX_PAYLOAD_SIZE) + { + return E_CIPHER_BAD_INPUT_SIZE; + } + + /* Ensure the first byte is a valid version */ + if (inputData[0] != Nip44VersionValue[0]) + { + return E_VERSION_NOT_SUPPORTED; + } + + break; + } + default: + return E_VERSION_NOT_SUPPORTED; + } + + /* + * Alloc a the output buffer to be the same size as the input + * data for decryption because the output will always be equal + * or smaller than the input data. This is an over-alloc but + * that should be fine + */ + + outputSize = inputSize; + } + else + { + /* + * Calculate the correct output size to store the encryption + * data for the given state version + */ + outputSize = NCUtilGetEncryptionBufferSize(encCtx->encArgs.version, inputSize); + + if (outputSize < 0) + { + return E_CIPHER_BAD_INPUT_SIZE; + } + } + + DEBUG_ASSERT(outputSize > 0); + + /* + * 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->buffer.output = _ncUtilAllocSpan((uint32_t)outputSize, sizeof(uint8_t)); + + if (!ncSpanIsValid(encCtx->buffer.output)) + { + return E_OUT_OF_MEMORY; + } + +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; +} + +NC_EXPORT NCResult NC_CC NCUtilCipherGetFlags(const NCUtilCipherContext* ctx) +{ + CHECK_NULL_ARG(ctx, 0); + + return (NCResult)(ctx->_flags); +} + +NC_EXPORT NCResult NC_CC NCUtilCipherGetOutputSize(const NCUtilCipherContext* encCtx) +{ + CHECK_NULL_ARG(encCtx, 0); + + if (!ncSpanIsValidC(encCtx->buffer.actualOutput)) + { + return E_CIPHER_NO_OUTPUT; + } + + return (NCResult)(encCtx->buffer.actualOutput.size); +} + +NC_EXPORT NCResult NC_CC NCUtilCipherReadOutput( + const NCUtilCipherContext* encCtx, + uint8_t* output, + uint32_t outputSize +) +{ + CHECK_NULL_ARG(encCtx, 0); + CHECK_NULL_ARG(output, 1); + + if (!ncSpanIsValidC(encCtx->buffer.actualOutput)) + { + return E_CIPHER_NO_OUTPUT; + } + + /* Buffer must be as large as the output data */ + CHECK_ARG_RANGE(outputSize, encCtx->buffer.actualOutput.size, UINT32_MAX, 2); + + ncSpanReadC( + encCtx->buffer.actualOutput, + output, + outputSize + ); + + return (NCResult)encCtx->buffer.actualOutput.size; +} + +NC_EXPORT NCResult NCUtilCipherSetProperty( + NCUtilCipherContext* 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 + ); +} + +NC_EXPORT NCResult NC_CC NCUtilCipherUpdate( + NCUtilCipherContext* encCtx, + const NCContext* libContext, + const NCSecretKey* sk, + const NCPublicKey* pk +) +{ + CHECK_NULL_ARG(encCtx, 0); + CHECK_NULL_ARG(libContext, 1); + CHECK_NULL_ARG(sk, 2); + CHECK_NULL_ARG(pk, 3); + + /* Make sure input & output buffers have been assigned/allocated */ + if (!ncSpanIsValid(encCtx->buffer.output)) + { + return E_INVALID_CONTEXT; + } + 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: + + if ((encCtx->_flags & NC_UTIL_CIPHER_MODE_DECRYPT) > 0) + { + return _nip44DecryptCompleteCore(libContext, sk, pk, encCtx); + } + else + { + /* Ensure the user manually specified a nonce buffer for encryption mode */ + if (!encCtx->encArgs.nonceData) + { + return E_CIPHER_BAD_NONCE; + } + + return _nip44EncryptCompleteCore(libContext, sk, pk, encCtx); + } + + default: + return E_VERSION_NOT_SUPPORTED; + } +} diff --git a/src/providers/bcrypt.c b/src/providers/bcrypt.c index d1b9aa5..b9c370b 100644 --- a/src/providers/bcrypt.c +++ b/src/providers/bcrypt.c @@ -2,7 +2,7 @@ * Copyright (c) 2024 Vaughn Nugent * * Package: noscrypt -* File: impl/bcrypt.c +* File: providers/bcrypt.c * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -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*)ncSpanGetOffsetC(key, 0), + ncSpanGetSizeC(key), 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,13 @@ _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, + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data) + ); } _IMPLSTB NTSTATUS _bcFinishHash(const struct _bcrypt_ctx* ctx, sha256_t digestOut32) @@ -118,8 +122,8 @@ _IMPLSTB void _bcDestroyCtx(struct _bcrypt_ctx* ctx) /* Close the algorithm provider */ if (ctx->hAlg) BCryptCloseAlgorithmProvider(ctx->hAlg, 0); - ctx->hAlg = NULL; ctx->hHash = NULL; + ctx->hAlg = NULL; } #ifndef _IMPL_SECURE_ZERO_MEMSET @@ -146,7 +150,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 +181,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 +217,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) + static cstatus_t _bcrypt_hkdf_update(void* ctx, cspan_t data) { DEBUG_ASSERT(ctx != NULL) @@ -221,15 +225,16 @@ _IMPLSTB void _bcDestroyCtx(struct _bcrypt_ctx* ctx) return CSTATUS_OK; } - cstatus_t _bcrypt_hkdf_finish(void* ctx, sha256_t hmacOut32) + static cstatus_t _bcrypt_hkdf_finish(void* ctx, sha256_t hmacOut32) { - DEBUG_ASSERT(ctx != NULL) + DEBUG_ASSERT(ctx != NULL); + DEBUG_ASSERT(hmacOut32 != NULL); BC_FAIL(_bcFinishHash((struct _bcrypt_ctx*)ctx, hmacOut32)) 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..ead3279 100644 --- a/src/providers/mbedtls.c +++ b/src/providers/mbedtls.c @@ -2,7 +2,7 @@ * Copyright (c) 2024 Vaughn Nugent * * Package: noscrypt -* File: mbedtls.c +* File: providers/mbedtls.c * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -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/src/providers/monocypher.c b/src/providers/monocypher.c index 8ffe048..c35f63e 100644 --- a/src/providers/monocypher.c +++ b/src/providers/monocypher.c @@ -2,7 +2,7 @@ * Copyright (c) 2024 Vaughn Nugent * * Package: noscrypt -* File: impl/monocypher.c +* File: providers/monocypher.c * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License diff --git a/src/providers/openssl.c b/src/providers/openssl.c index 1f31796..c2933fb 100644 --- a/src/providers/openssl.c +++ b/src/providers/openssl.c @@ -2,7 +2,7 @@ * Copyright (c) 2024 Vaughn Nugent * * Package: noscrypt -* File: impl/openssl.c +* File: providers/openssl.c * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -26,6 +26,10 @@ #define _OSSL_FAIL(x) if(!(x)) return CSTATUS_FAIL; +#define ossl_md_sha256() EVP_MD_fetch(NULL, "SHA2-256", NULL) +#define ossl_evp_fetch_chacha20() EVP_CIPHER_fetch(NULL, "ChaCha20", NULL) +#define ossl_mac_fetch_hmac() EVP_MAC_fetch(NULL, "hmac", NULL) + #ifndef _IMPL_SECURE_ZERO_MEMSET #define _IMPL_SECURE_ZERO_MEMSET _ossl_secure_zero_memset @@ -63,11 +67,20 @@ #define _IMPL_CRYPTO_SHA256_DIGEST _ossl_sha256_digest - _IMPLSTB cstatus_t _ossl_sha256_digest(const cspan_t* data, sha256_t digestOut32) + _IMPLSTB cstatus_t _ossl_sha256_digest(cspan_t data, sha256_t digestOut32) { - _overflow_check(data->size) + _overflow_check(data.size); + + DEBUG_ASSERT(digestOut32 != NULL); + DEBUG_ASSERT(ncSpanIsValidC(data)); - _OSSL_FAIL(SHA256(data->data, data->size, digestOut32)) + _OSSL_FAIL( + SHA256( + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data), + digestOut32 + ) + ); return CSTATUS_OK; } @@ -81,29 +94,29 @@ /* Export function */ #define _IMPL_CRYPTO_SHA256_HMAC _ossl_hmac_sha256 - _IMPLSTB cstatus_t _ossl_hmac_sha256(const cspan_t* key, const cspan_t* data, sha256_t hmacOut32) + _IMPLSTB cstatus_t _ossl_hmac_sha256(cspan_t key, cspan_t data, sha256_t hmacOut32) { unsigned int hmacLen; - _overflow_check(key->size) - _overflow_check(data->size) + _overflow_check(key.size) + _overflow_check(data.size) hmacLen = sizeof(sha256_t); _OSSL_FAIL( HMAC( - EVP_sha256(), - key->data, - key->size, - data->data, - data->size, + ossl_md_sha256(), + ncSpanGetOffsetC(key, 0), + ncSpanGetSizeC(key), + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data), hmacOut32, &hmacLen ) - ) + ); /* digest length should match the actual digest size */ - DEBUG_ASSERT(hmacLen == sizeof(sha256_t)) + DEBUG_ASSERT(hmacLen == sizeof(sha256_t)); return CSTATUS_OK; } @@ -112,73 +125,144 @@ #ifndef _IMPL_CRYPTO_SHA256_HKDF_EXPAND - #include <openssl/hmac.h> + #include <openssl/evp.h> #define _IMPL_CRYPTO_SHA256_HKDF_EXPAND _ossl_sha256_hkdf_expand - cstatus_t _ossl_hkdf_update(void* ctx, const cspan_t* data) + struct ossl_hmac_state { + EVP_MAC_CTX* libCtx; + OSSL_PARAM params[2]; + cspan_t prk; + }; + + static cstatus_t _ossl_hmac_init(const struct ossl_hmac_state* osslCtx) { - DEBUG_ASSERT(ctx != NULL) + DEBUG_ASSERT(ncSpanIsValidC(osslCtx->prk)); + DEBUG_ASSERT(osslCtx->params != NULL); - _overflow_check(data->size) + _OSSL_FAIL( + EVP_MAC_init( + osslCtx->libCtx, + ncSpanGetOffsetC(osslCtx->prk, 0), + ncSpanGetSizeC(osslCtx->prk), + osslCtx->params + ) + ); - _OSSL_FAIL(EVP_DigestUpdate((EVP_MD_CTX*)ctx, data->data, data->size)) - return CSTATUS_OK; } - cstatus_t _ossl_hkdf_finish(void* ctx, sha256_t hmacOut32) + static cstatus_t _ossl_hkdf_update(void* ctx, cspan_t data) { - unsigned int hmacSize; + const struct ossl_hmac_state* osslCtx; - DEBUG_ASSERT(ctx != NULL) + DEBUG_ASSERT(ctx != NULL); + _overflow_check(data.size); - hmacSize = sizeof(sha256_t); + osslCtx = (const struct ossl_hmac_state*)ctx; - _OSSL_FAIL(EVP_DigestFinal_ex((EVP_MD_CTX*)ctx, hmacOut32, &hmacSize)) + DEBUG_ASSERT(osslCtx->libCtx != NULL); - /* When configured for sha256, should always be the same size in/out */ - DEBUG_ASSERT(hmacSize == sizeof(sha256_t)) + _OSSL_FAIL( + EVP_MAC_update( + osslCtx->libCtx, + ncSpanGetOffsetC(data, 0), + ncSpanGetSizeC(data) + ) + ); return CSTATUS_OK; } - _IMPLSTB cstatus_t _ossl_sha256_hkdf_expand(const cspan_t* prk, const cspan_t* info, span_t* okm) + static cstatus_t _ossl_hkdf_finish(void* ctx, sha256_t hmacOut32) { - EVP_MD_CTX* ctx; + const struct ossl_hmac_state* osslCtx; + size_t hmacSize; + + DEBUG_ASSERT(ctx != NULL); + DEBUG_ASSERT(hmacOut32 != NULL); + + osslCtx = (const struct ossl_hmac_state*)ctx; + hmacSize = 0; + + DEBUG_ASSERT(osslCtx->libCtx != NULL); + + _OSSL_FAIL( + EVP_MAC_final( + osslCtx->libCtx, + hmacOut32, + &hmacSize, + sizeof(sha256_t) + ) + ); + + /* When configured for sha256, should always be the same size in/out */ + DEBUG_ASSERT(hmacSize == sizeof(sha256_t)); + + /* + * Context must be re-initalized after finalize + * See lifecycle https://docs.openssl.org/3.0/man7/life_cycle-mac/#copyright + */ + + return _ossl_hmac_init(osslCtx); + } + + + _IMPLSTB cstatus_t _ossl_sha256_hkdf_expand(cspan_t prk, cspan_t info, span_t okm) + { + EVP_MAC* mac; cstatus_t result; - struct nc_hkdf_fn_cb_struct handler; + struct ossl_hmac_state hkdfState; + struct nc_hkdf_fn_cb_struct handler; result = CSTATUS_FAIL; + + handler.update = _ossl_hkdf_update; + handler.finish = _ossl_hkdf_finish; + _overflow_check(prk.size); + _overflow_check(info.size); + _overflow_check(okm.size); + + hkdfState.params[0] = OSSL_PARAM_construct_utf8_string("digest", "sha256", 0); + hkdfState.params[1] = OSSL_PARAM_construct_end(); + + hkdfState.prk = prk; + /* - * NOTE! Hmac reusable flag must be set to allow for multiple - * calls to the finish function without losing the context. + * Silly openssl stuff. Enable hmac with sha256 using the system default + * security provider. The one-shot flag must also be disabled (0) because + * we need to call update multiple times. */ - if ((ctx = EVP_MD_CTX_create()) == NULL) + mac = ossl_mac_fetch_hmac(); + + if (mac == NULL) { - return CSTATUS_FAIL; + goto Cleanup; } - if (!EVP_DigestInit_ex2(ctx, EVP_sha256(), NULL)) + hkdfState.libCtx = EVP_MAC_CTX_new(mac); + + if (hkdfState.libCtx == NULL) { goto Cleanup; } - if (!EVP_DigestUpdate(ctx, prk->data, prk->size)) + if (_ossl_hmac_init(&hkdfState) != CSTATUS_OK) { goto Cleanup; } - - handler.update = _ossl_hkdf_update; - handler.finish = _ossl_hkdf_finish; - result = hkdfExpandProcess(&handler, ctx, info, okm); + DEBUG_ASSERT(EVP_MAC_CTX_get_mac_size(hkdfState.libCtx) == sizeof(sha256_t)); - Cleanup: + /* Pass the library */ + result = hkdfExpandProcess(&handler, &hkdfState, info, okm); - EVP_MD_CTX_destroy(ctx); + Cleanup: + + if (hkdfState.libCtx) EVP_MAC_CTX_free(hkdfState.libCtx); + if (mac) EVP_MAC_free(mac); return result; } @@ -191,39 +275,130 @@ #define _IMPL_CHACHA20_CRYPT _ossl_chacha20_crypt - _IMPLSTB cstatus_t _ossl_chacha20_crypt( - const uint8_t* key, - const uint8_t* nonce, - const uint8_t* input, - uint8_t* output, - uint32_t dataLen + _IMPLSTB cstatus_t _ossl_cipher_core( + const EVP_CIPHER* cipher, + cspan_t key, + cspan_t iv, + cspan_t input, + span_t output ) { cstatus_t result; EVP_CIPHER_CTX* ctx; + int tempLen, osslResult; + + DEBUG_ASSERT2(ncSpanGetSize(output) <= ncSpanGetSizeC(input), "Output buffer must be equal or larger than the input buffer"); + DEBUG_ASSERT(cipher != NULL); + + DEBUG_ASSERT((uint32_t)EVP_CIPHER_get_key_length(cipher) == ncSpanGetSizeC(key)); + DEBUG_ASSERT((uint32_t)EVP_CIPHER_iv_length(cipher) == ncSpanGetSizeC(iv)); result = CSTATUS_FAIL; - if ((ctx = EVP_CIPHER_CTX_new()) == NULL) + ctx = EVP_CIPHER_CTX_new(); + + if (ctx == NULL) { - return CSTATUS_FAIL; + goto Cleanup; } - if (!EVP_EncryptInit_ex(ctx, EVP_chacha20(), NULL, key, nonce)) + osslResult = EVP_EncryptInit_ex2( + ctx, + cipher, + ncSpanGetOffsetC(key, 0), + ncSpanGetOffsetC(iv, 0), + NULL + ); + + if (!osslResult) { goto Cleanup; } - if (!EVP_EncryptUpdate(ctx, output, (int*)&dataLen, input, dataLen)) + osslResult = EVP_EncryptUpdate( + ctx, + ncSpanGetOffset(output, 0), + &tempLen, + ncSpanGetOffsetC(input, 0), + ncSpanGetSizeC(input) + ); + + if (!osslResult) { goto Cleanup; } + /* + * We can't get a pointer outside the range of the + * output buffer + */ + if (((uint32_t)tempLen) < ncSpanGetSize(output)) + { + if (!EVP_EncryptFinal_ex(ctx, ncSpanGetOffset(output, tempLen), &tempLen)) + { + goto Cleanup; + } + } + result = CSTATUS_OK; Cleanup: - EVP_CIPHER_CTX_free(ctx); + if (ctx) EVP_CIPHER_CTX_free(ctx); + + return result; + } + + _IMPLSTB cstatus_t _ossl_chacha20_crypt( + const uint8_t* key, + const uint8_t* nonce, + const uint8_t* input, + uint8_t* output, + uint32_t dataLen + ) + { + cstatus_t result; + EVP_CIPHER* cipher; + uint8_t chaChaIv[CHACHA_NONCE_SIZE + 4]; + cspan_t keySpan, nonceSpan, inputSpan; + span_t outputSpan; + + result = CSTATUS_FAIL; + + /* + * RFC 7539 ChaCha20 requires a 16 byte initialization vector. A + * counter value is preprended to the nonce to make up the 16 byte + * size. + * + * The counter is always set to 0 for the nonce. + */ + + ncCryptoSecureZero(chaChaIv, sizeof(chaChaIv)); + MEMMOV(chaChaIv + 4, nonce, CHACHA_NONCE_SIZE); + + ncSpanInitC(&keySpan, key, CHACHA_KEY_SIZE); + ncSpanInitC(&nonceSpan, chaChaIv, sizeof(chaChaIv)); + ncSpanInitC(&inputSpan, input, dataLen); + ncSpanInit(&outputSpan, output, dataLen); + + cipher = ossl_evp_fetch_chacha20(); + + if (cipher == NULL) + { + goto Cleanup; + } + + result = _ossl_cipher_core( + cipher, + keySpan, + nonceSpan, + inputSpan, + outputSpan + ); + + Cleanup: + + if (cipher) EVP_CIPHER_free(cipher); return result; } diff --git a/tests/hex.h b/tests/hex.h index 5e90ce9..3cfe559 100644 --- a/tests/hex.h +++ b/tests/hex.h @@ -28,18 +28,12 @@ #include <nc-util.h> -typedef struct hexBytes -{ - uint8_t* data; - size_t length; -} HexBytes; - -/* Deferred list of HexBytes to be freed on exit */ -static HexBytes* _hdeferList[10]; +/* Deferred list of span_t to be freed on exit */ +static span_t _hdeferList[20]; static size_t _hdeferListIndex = 0; /* - Allocates a HexBytes and decodes the hexadecimal string into it's binary + Allocates a span_t and decodes the hexadecimal string into it's binary representation. The string must be a valid hexadecimal string and the length and may not be NULL. The length may be known at compile time and can be used to assert the length of the string literal. @@ -48,34 +42,34 @@ static size_t _hdeferListIndex = 0; */ #define FromHexString(str, len) _fromHexString(str, sizeof(str) - 1); STATIC_ASSERT(sizeof(str)/2 == len && len > 0, "Invalid length hex string literal"); -static HexBytes* __allocHexBytes(size_t length) +static span_t __allocHexBytes(size_t length) { - HexBytes* hexBytes; + span_t hexBytes; length /= 2; - hexBytes = (HexBytes*)malloc(length + sizeof(HexBytes)); - if(!hexBytes) + hexBytes.data = malloc(length); + + if(!hexBytes.data) { - return NULL; + return hexBytes; } - hexBytes->length = length; - /* data starts after the structure size */ - hexBytes-> data = ((uint8_t*)hexBytes) + sizeof(HexBytes); + hexBytes.size = length; /* add new value to deferred cleanup list */ _hdeferList[_hdeferListIndex++] = hexBytes; return hexBytes; } -static HexBytes* _fromHexString(const char* hexLiteral, size_t strLen) +static span_t _fromHexString(const char* hexLiteral, uint32_t strLen) { - HexBytes* hexBytes; + span_t hexBytes; size_t i; if(!hexLiteral) { - return NULL; + ncSpanInit(&hexBytes, NULL, 0); + return hexBytes; } /* alloc the raw bytes */ @@ -90,14 +84,14 @@ static HexBytes* _fromHexString(const char* hexLiteral, size_t strLen) byteString[0] = hexLiteral[i]; byteString[1] = hexLiteral[i + 1]; - hexBytes->data[i / 2] = (uint8_t)strtol(byteString, NULL, 16); + hexBytes.data[i / 2] = (uint8_t)strtol(byteString, NULL, 16); } return hexBytes; } /* - Frees all the HexBytes that were allocated by the + Frees all the span_t that were allocated by the FromHexString function. To be called at the end of the program. */ @@ -105,8 +99,8 @@ static void FreeHexBytes(void) { while(_hdeferListIndex > 0) { - free(_hdeferList[--_hdeferListIndex]); - _hdeferList[_hdeferListIndex] = NULL; + free(_hdeferList[--_hdeferListIndex].data); + memset(&_hdeferList[_hdeferListIndex], 0, sizeof(span_t)); } } @@ -127,18 +121,18 @@ static void PrintHexRaw(void* bytes, size_t len) } /* -* Prints the value of the HexBytes as a hexadecimal string -* @param hexBytes A pointer to the HexBytes structure to print the value of +* Prints the value of the span_t as a hexadecimal string +* @param hexBytes A pointer to the span_t structure to print the value of */ -static void PrintHexBytes(HexBytes* hexBytes) +static void PrintHexBytes(span_t hexBytes) { - if (!hexBytes) + if (ncSpanIsValid(hexBytes)) { - puts("NULL"); + PrintHexRaw(hexBytes.data, hexBytes.size); } else { - PrintHexRaw(hexBytes->data, hexBytes->length); + puts("NULL"); } } diff --git a/tests/test.c b/tests/test.c index 084ac13..b4cdef1 100644 --- a/tests/test.c +++ b/tests/test.c @@ -44,7 +44,7 @@ /*Prints a string literal to the console*/ #define PRINTL(x) puts(x); puts("\n"); -#define ENSURE(x) if(!(x)) { puts("Assumption failed!\n"); return 1; } +#define ENSURE(x) if(!(x)) { printf("Test assumption failed on line %d\n", __LINE__); return 1; } #define TEST(x, expected) printf("\tTesting %s\n", #x); if(((long)x) != ((long)expected)) \ { printf("FAILED: Expected %ld but got %ld @ callsite %s. Line: %d \n", ((long)expected), ((long)x), #x, __LINE__); return 1; } @@ -68,28 +68,31 @@ /*Pre-computed constants for argument errors */ #define ARG_ERROR_POS_0 E_NULL_PTR -#define ARG_ERROR_POS_1 NCResultWithArgPosition(E_NULL_PTR, 0x01) -#define ARG_ERROR_POS_2 NCResultWithArgPosition(E_NULL_PTR, 0x02) -#define ARG_ERROR_POS_3 NCResultWithArgPosition(E_NULL_PTR, 0x03) -#define ARG_ERROR_POS_4 NCResultWithArgPosition(E_NULL_PTR, 0x04) -#define ARG_ERROR_POS_5 NCResultWithArgPosition(E_NULL_PTR, 0x05) -#define ARG_ERROR_POS_6 NCResultWithArgPosition(E_NULL_PTR, 0x06) +#define ARG_ERROR(pos) NCResultWithArgPosition(E_NULL_PTR, pos) +#define ARG_ERROR_POS_1 ARG_ERROR(0x01) +#define ARG_ERROR_POS_2 ARG_ERROR(0x02) +#define ARG_ERROR_POS_3 ARG_ERROR(0x03) +#define ARG_ERROR_POS_4 ARG_ERROR(0x04) +#define ARG_ERROR_POS_5 ARG_ERROR(0x05) +#define ARG_ERROR_POS_6 ARG_ERROR(0x06) #define ARG_RANGE_ERROR_POS_0 E_ARGUMENT_OUT_OF_RANGE -#define ARG_RANGE_ERROR_POS_1 NCResultWithArgPosition(E_ARGUMENT_OUT_OF_RANGE, 0x01) -#define ARG_RANGE_ERROR_POS_2 NCResultWithArgPosition(E_ARGUMENT_OUT_OF_RANGE, 0x02) -#define ARG_RANGE_ERROR_POS_3 NCResultWithArgPosition(E_ARGUMENT_OUT_OF_RANGE, 0x03) -#define ARG_RANGE_ERROR_POS_4 NCResultWithArgPosition(E_ARGUMENT_OUT_OF_RANGE, 0x04) -#define ARG_RANGE_ERROR_POS_5 NCResultWithArgPosition(E_ARGUMENT_OUT_OF_RANGE, 0x05) -#define ARG_RANGE_ERROR_POS_6 NCResultWithArgPosition(E_ARGUMENT_OUT_OF_RANGE, 0x06) +#define ARG_RANGE_ERROR(pos) NCResultWithArgPosition(E_ARGUMENT_OUT_OF_RANGE, pos) +#define ARG_RANGE_ERROR_POS_1 ARG_RANGE_ERROR(0x01) +#define ARG_RANGE_ERROR_POS_2 ARG_RANGE_ERROR(0x02) +#define ARG_RANGE_ERROR_POS_3 ARG_RANGE_ERROR(0x03) +#define ARG_RANGE_ERROR_POS_4 ARG_RANGE_ERROR(0x04) +#define ARG_RANGE_ERROR_POS_5 ARG_RANGE_ERROR(0x05) +#define ARG_RANGE_ERROR_POS_6 ARG_RANGE_ERROR(0x06) #define ARG_INVALID_ERROR_POS_0 E_INVALID_ARG -#define ARG_INVALID_ERROR_POS_1 NCResultWithArgPosition(E_INVALID_ARG, 0x01) -#define ARG_INVALID_ERROR_POS_2 NCResultWithArgPosition(E_INVALID_ARG, 0x02) -#define ARG_INVALID_ERROR_POS_3 NCResultWithArgPosition(E_INVALID_ARG, 0x03) -#define ARG_INVALID_ERROR_POS_4 NCResultWithArgPosition(E_INVALID_ARG, 0x04) -#define ARG_INVALID_ERROR_POS_5 NCResultWithArgPosition(E_INVALID_ARG, 0x05) -#define ARG_INVALID_ERROR_POS_6 NCResultWithArgPosition(E_INVALID_ARG, 0x06) +#define ARG_INVALID_ERROR(pos) NCResultWithArgPosition(E_INVALID_ARG, pos) +#define ARG_INVALID_ERROR_POS_1 ARG_INVALID_ERROR(0x01) +#define ARG_INVALID_ERROR_POS_2 ARG_INVALID_ERROR(0x02) +#define ARG_INVALID_ERROR_POS_3 ARG_INVALID_ERROR(0x03) +#define ARG_INVALID_ERROR_POS_4 ARG_INVALID_ERROR(0x04) +#define ARG_INVALID_ERROR_POS_5 ARG_INVALID_ERROR(0x05) +#define ARG_INVALID_ERROR_POS_6 ARG_INVALID_ERROR(0x06) static int RunTests(void); static void FillRandomData(void* pbBuffer, size_t length); @@ -98,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(const NCContext * libCtx); +#endif + #ifndef NC_INPUT_VALIDATION_OFF static int TestPublicApiArgumentValidation(void); #endif @@ -164,6 +171,13 @@ static int RunTests(void) return 1; } +#ifdef NC_ENABLE_UTILS + if (TestUtilFunctions(ctx) != 0) + { + return 1; + } +#endif + TEST(NCDestroyContext(ctx), NC_SUCCESS) PRINTL("\nSUCCESS All tests passed") @@ -199,7 +213,7 @@ static int TestEcdsa(const NCContext* context, NCSecretKey* secKey, NCPublicKey* uint8_t sigEntropy[32]; uint8_t invalidSig[64]; - HexBytes* digestHex; + span_t digestHex; PRINTL("TEST: Ecdsa") @@ -213,8 +227,8 @@ static int TestEcdsa(const NCContext* context, NCSecretKey* secKey, NCPublicKey* /* Test signing just the message digest */ { uint8_t sig[64]; - TEST(NCSignDigest(context, secKey, sigEntropy, digestHex->data, sig), NC_SUCCESS); - TEST(NCVerifyDigest(context, pubKey, digestHex->data, sig), NC_SUCCESS); + TEST(NCSignDigest(context, secKey, sigEntropy, digestHex.data, sig), NC_SUCCESS); + TEST(NCVerifyDigest(context, pubKey, digestHex.data, sig), NC_SUCCESS); } /* Sign and verify the raw message */ @@ -231,7 +245,7 @@ static int TestEcdsa(const NCContext* context, NCSecretKey* secKey, NCPublicKey* /* Ensure operations succeed but dont print them as test cases */ ENSURE(NCSignData(context, secKey, sigEntropy, (uint8_t*)message, strlen32(message), sig1) == NC_SUCCESS); - ENSURE(NCSignDigest(context, secKey, sigEntropy, digestHex->data, sig2) == NC_SUCCESS); + ENSURE(NCSignDigest(context, secKey, sigEntropy, digestHex.data, sig2) == NC_SUCCESS); /* Perform test */ TEST(memcmp(sig1, sig2, 64), 0); @@ -242,18 +256,18 @@ static int TestEcdsa(const NCContext* context, NCSecretKey* secKey, NCPublicKey* uint8_t sig[64]; ENSURE(NCSignData(context, secKey, sigEntropy, (uint8_t*)message, strlen32(message), sig) == NC_SUCCESS); - TEST(NCVerifyDigest(context, pubKey, digestHex->data, sig), NC_SUCCESS); + TEST(NCVerifyDigest(context, pubKey, digestHex.data, sig), NC_SUCCESS); /* Now invert test, zero signature to ensure its overwritten */ ZERO_FILL(sig, sizeof(sig)); - ENSURE(NCSignDigest(context, secKey, sigEntropy, digestHex->data, sig) == NC_SUCCESS); + ENSURE(NCSignDigest(context, secKey, sigEntropy, digestHex.data, sig) == NC_SUCCESS); TEST(NCVerifyData(context, pubKey, (uint8_t*)message, strlen32(message), sig), NC_SUCCESS); } /* test verification of invalid signature */ { - TEST(NCVerifyDigest(context, pubKey, digestHex->data, invalidSig), E_INVALID_ARG); + TEST(NCVerifyDigest(context, pubKey, digestHex.data, invalidSig), E_INVALID_ARG); } PRINTL("\nPASSED: Ecdsa tests completed") @@ -273,21 +287,79 @@ static int TestPublicApiArgumentValidation() uint8_t nonce[NC_ENCRYPTION_NONCE_SIZE]; NCEncryptionArgs cryptoData; - cryptoData.dataSize = sizeof(zero32); - cryptoData.inputData = zero32; - cryptoData.outputData = sig64; /*just an arbitrary writeable buffer*/ - cryptoData.nonce32 = nonce; - cryptoData.hmacKeyOut32 = hmacKeyOut; - cryptoData.version = NC_ENC_VERSION_NIP44; PRINTL("TEST: Public API argument validation tests") + { + /* + * Test arguments for encryption properties + */ + + uint8_t testBuff32[32]; + + TEST(NCSetEncryptionProperty(NULL, NC_ENC_SET_VERSION, NC_ENC_VERSION_NIP44), ARG_ERROR_POS_0) + TEST(NCSetEncryptionProperty(&cryptoData, 0, 1), E_INVALID_ARG) + + TEST(NCSetEncryptionData(NULL, zero32, sig64, sizeof(zero32)), ARG_ERROR_POS_0) + TEST(NCSetEncryptionData(&cryptoData, NULL, sig64, sizeof(zero32)), ARG_ERROR_POS_1) + TEST(NCSetEncryptionData(&cryptoData, zero32, NULL, sizeof(zero32)), ARG_ERROR_POS_2) + TEST(NCSetEncryptionData(&cryptoData, zero32, sig64, 0), ARG_RANGE_ERROR_POS_3) + + /* Setting any version specific value should fail */ + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP44_NONCE, nonce, sizeof(nonce)), E_VERSION_NOT_SUPPORTED) + + /* Set to nip44 to continue nip44 tests */ + TEST(NCSetEncryptionProperty(&cryptoData, NC_ENC_SET_VERSION, NC_ENC_VERSION_NIP44), NC_SUCCESS) + + TEST(NCSetEncryptionPropertyEx(&cryptoData, 0, nonce, sizeof(nonce)), E_INVALID_ARG) + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP44_NONCE, NULL, sizeof(nonce)), ARG_ERROR_POS_2) + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP44_NONCE, nonce, 0), ARG_RANGE_ERROR_POS_3) + /* Nonce size should fail if smaller than the required nonce size */ + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP44_NONCE, nonce, NC_ENCRYPTION_NONCE_SIZE - 1), ARG_RANGE_ERROR_POS_3) + + TEST(NCSetEncryptionPropertyEx(&cryptoData, 0, hmacKeyOut, sizeof(hmacKeyOut)), E_INVALID_ARG) + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP44_MAC_KEY, NULL, sizeof(hmacKeyOut)), ARG_ERROR_POS_2) + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP44_MAC_KEY, hmacKeyOut, 0), ARG_RANGE_ERROR_POS_3) + /* Key size should fail if smaller than the required nip44 key size */ + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP44_MAC_KEY, hmacKeyOut, NC_HMAC_KEY_SIZE - 1), ARG_RANGE_ERROR_POS_3) + + /* Test for nip04 */ + + /* Any nip04 specific properties should fail since nip44 has already been set */ + + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP04_IV, testBuff32, sizeof(testBuff32)), E_VERSION_NOT_SUPPORTED) + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP04_KEY, testBuff32, sizeof(testBuff32)), E_VERSION_NOT_SUPPORTED) + + /* Set to nip04 to continue nip04 tests */ + ENSURE(NCSetEncryptionProperty(&cryptoData, NC_ENC_SET_VERSION, NC_ENC_VERSION_NIP04) == NC_SUCCESS) + + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP04_IV, NULL, sizeof(testBuff32)), ARG_ERROR_POS_2) + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP04_IV, testBuff32, 0), ARG_RANGE_ERROR_POS_3) + /* IV size should fail if smaller than IV */ + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP04_IV, testBuff32, NC_NIP04_AES_IV_SIZE - 1), ARG_RANGE_ERROR_POS_3) + + + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP04_KEY, NULL, sizeof(testBuff32)), ARG_ERROR_POS_2) + TEST(NCSetEncryptionPropertyEx(&cryptoData, NC_ENC_SET_NIP04_KEY, testBuff32, 0), ARG_RANGE_ERROR_POS_3) + /* Key size should fail if smaller than the required nip04 key size */ + 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); + + /* Assign the encryption material */ + ENSURE(NCSetEncryptionData(&cryptoData, zero32, sig64, sizeof(zero32)) == NC_SUCCESS); + + 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) @@ -308,27 +380,27 @@ static int TestPublicApiArgumentValidation() TEST(NCDestroyContext(NULL), ARG_ERROR_POS_0) /*reinit*/ - TEST(NCReInitContext(NULL, ctxRandom), ARG_ERROR_POS_0) - TEST(NCReInitContext(ctx, NULL), ARG_ERROR_POS_1) + TEST(NCReInitContext(NULL, ctxRandom), ARG_ERROR_POS_0) + TEST(NCReInitContext(ctx, NULL), ARG_ERROR_POS_1) /*Test null secret key*/ - TEST(NCGetPublicKey(ctx, NULL, &pubKey), ARG_ERROR_POS_1) - TEST(NCGetPublicKey(ctx, &secKey, NULL), ARG_ERROR_POS_2) + TEST(NCGetPublicKey(ctx, NULL, &pubKey), ARG_ERROR_POS_1) + TEST(NCGetPublicKey(ctx, &secKey, NULL), ARG_ERROR_POS_2) /*Test null secret key*/ TEST(NCValidateSecretKey(NULL, &secKey), ARG_ERROR_POS_0) - TEST(NCValidateSecretKey(ctx, NULL), ARG_ERROR_POS_1) + TEST(NCValidateSecretKey(ctx, NULL), ARG_ERROR_POS_1) /* Should fail with a zero key */ - TEST(NCValidateSecretKey(ctx, NCToSecKey(zero32)), E_OPERATION_FAILED) + TEST(NCValidateSecretKey(ctx, NCByteCastToSecretKey(zero32)), E_OPERATION_FAILED) /*Verify sig64 args test*/ - TEST(NCVerifyDigest(NULL, &pubKey, zero32, sig64), ARG_ERROR_POS_0) + TEST(NCVerifyDigest(NULL, &pubKey, zero32, sig64), ARG_ERROR_POS_0) TEST(NCVerifyDigest(ctx, NULL, zero32, sig64), ARG_ERROR_POS_1) TEST(NCVerifyDigest(ctx, &pubKey, NULL, sig64), ARG_ERROR_POS_2) TEST(NCVerifyDigest(ctx, &pubKey, zero32, NULL), ARG_ERROR_POS_3) /*Test verify data args*/ - TEST(NCVerifyData(NULL, &pubKey, zero32, 32, sig64), ARG_ERROR_POS_0) + TEST(NCVerifyData(NULL, &pubKey, zero32, 32, sig64), ARG_ERROR_POS_0) TEST(NCVerifyData(ctx, NULL, zero32, 32, sig64), ARG_ERROR_POS_1) TEST(NCVerifyData(ctx, &pubKey, NULL, 32, sig64), ARG_ERROR_POS_2) TEST(NCVerifyData(ctx, &pubKey, zero32, 0, sig64), ARG_RANGE_ERROR_POS_3) @@ -336,24 +408,24 @@ static int TestPublicApiArgumentValidation() /*Test null sign data args*/ TEST(NCSignData(NULL, &secKey, zero32, zero32, 32, sig64), ARG_ERROR_POS_0) - TEST(NCSignData(ctx, NULL, zero32, zero32, 32, sig64), ARG_ERROR_POS_1) - TEST(NCSignData(ctx, &secKey, NULL, zero32, 32, sig64), ARG_ERROR_POS_2) - TEST(NCSignData(ctx, &secKey, zero32, NULL, 32, sig64), ARG_ERROR_POS_3) - TEST(NCSignData(ctx, &secKey, zero32, zero32, 0, sig64), ARG_RANGE_ERROR_POS_4) - TEST(NCSignData(ctx, &secKey, zero32, zero32, 32, NULL), ARG_ERROR_POS_5) + TEST(NCSignData(ctx, NULL, zero32, zero32, 32, sig64), ARG_ERROR_POS_1) + TEST(NCSignData(ctx, &secKey, NULL, zero32, 32, sig64), ARG_ERROR_POS_2) + TEST(NCSignData(ctx, &secKey, zero32, NULL, 32, sig64), ARG_ERROR_POS_3) + TEST(NCSignData(ctx, &secKey, zero32, zero32, 0, sig64), ARG_RANGE_ERROR_POS_4) + TEST(NCSignData(ctx, &secKey, zero32, zero32, 32, NULL), ARG_ERROR_POS_5) /*Test null sign digest args*/ TEST(NCSignDigest(NULL, &secKey, zero32, zero32, sig64), ARG_ERROR_POS_0) - TEST(NCSignDigest(ctx, NULL, zero32, zero32, sig64), ARG_ERROR_POS_1) - TEST(NCSignDigest(ctx, &secKey, NULL, zero32, sig64), ARG_ERROR_POS_2) - TEST(NCSignDigest(ctx, &secKey, zero32, NULL, sig64), ARG_ERROR_POS_3) - TEST(NCSignDigest(ctx, &secKey, zero32, zero32, NULL), ARG_ERROR_POS_4) + TEST(NCSignDigest(ctx, NULL, zero32, zero32, sig64), ARG_ERROR_POS_1) + TEST(NCSignDigest(ctx, &secKey, NULL, zero32, sig64), ARG_ERROR_POS_2) + TEST(NCSignDigest(ctx, &secKey, zero32, NULL, sig64), ARG_ERROR_POS_3) + TEST(NCSignDigest(ctx, &secKey, zero32, zero32, NULL), ARG_ERROR_POS_4) /*Test null encrypt args*/ TEST(NCEncrypt(NULL, &secKey, &pubKey, &cryptoData), ARG_ERROR_POS_0) - TEST(NCEncrypt(ctx, NULL, &pubKey, &cryptoData), ARG_ERROR_POS_1) - TEST(NCEncrypt(ctx, &secKey, NULL, &cryptoData), ARG_ERROR_POS_2) - TEST(NCEncrypt(ctx, &secKey, &pubKey, NULL), ARG_ERROR_POS_3) + TEST(NCEncrypt(ctx, NULL, &pubKey, &cryptoData), ARG_ERROR_POS_1) + TEST(NCEncrypt(ctx, &secKey, NULL, &cryptoData), ARG_ERROR_POS_2) + TEST(NCEncrypt(ctx, &secKey, &pubKey, NULL), ARG_ERROR_POS_3) /*Test invalid data size*/ cryptoData.dataSize = 0; @@ -432,7 +504,7 @@ static int TestPublicApiArgumentValidation() static int TestKnownKeys(const NCContext* context) { NCPublicKey pubKey; - HexBytes* secKey1, * pubKey1, * secKey2, * pubKey2; + span_t secKey1, pubKey1, secKey2, pubKey2; PRINTL("TEST: Known keys") @@ -443,18 +515,18 @@ static int TestKnownKeys(const NCContext* context) pubKey2 = FromHexString("421181660af5d39eb95e48a0a66c41ae393ba94ffeca94703ef81afbed724e5a", sizeof(NCPublicKey)); /*Test known keys*/ - TEST(NCValidateSecretKey(context, NCToSecKey(secKey1->data)), NC_SUCCESS); + TEST(NCValidateSecretKey(context, NCByteCastToSecretKey(secKey1.data)), NC_SUCCESS); /* Recover a public key from secret key 1 */ - TEST(NCGetPublicKey(context, NCToSecKey(secKey1->data), &pubKey), NC_SUCCESS); + TEST(NCGetPublicKey(context, NCByteCastToSecretKey(secKey1.data), &pubKey), NC_SUCCESS); /* Ensure the public key matches the known public key value */ - TEST(memcmp(pubKey1->data, &pubKey, sizeof(pubKey)), 0); + TEST(memcmp(pubKey1.data, &pubKey, sizeof(pubKey)), 0); /* Repeat with second key */ - TEST(NCValidateSecretKey(context, (NCSecretKey*)secKey2->data), NC_SUCCESS); - TEST(NCGetPublicKey(context, (NCSecretKey*)secKey2->data, &pubKey), NC_SUCCESS); - TEST(memcmp(pubKey2->data, &pubKey, sizeof(pubKey)), 0); + TEST(NCValidateSecretKey(context, NCByteCastToSecretKey(secKey2.data)), NC_SUCCESS); + TEST(NCGetPublicKey(context, NCByteCastToSecretKey(secKey2.data), &pubKey), NC_SUCCESS); + TEST(memcmp(pubKey2.data, &pubKey, sizeof(pubKey)), 0); PRINTL("\nPASSED: Known keys tests completed") return 0; @@ -481,21 +553,20 @@ static int TestCorrectEncryption(const NCContext* context) NCEncryptionArgs cryptoData; NCMacVerifyArgs macVerifyArgs; - /* setup the crypto data structure */ - cryptoData.dataSize = TEST_ENC_DATA_SIZE; - cryptoData.inputData = plainText; - cryptoData.outputData = cipherText; - cryptoData.nonce32 = nonce; - cryptoData.hmacKeyOut32 = hmacKeyOut; - cryptoData.version = NC_ENC_VERSION_NIP44; + 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); + + /* Assign the encryption material */ + ENSURE(NCSetEncryptionData(&cryptoData, plainText, cipherText, TEST_ENC_DATA_SIZE) == NC_SUCCESS); macVerifyArgs.nonce32 = nonce; /* nonce is shared */ macVerifyArgs.mac32 = mac; 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)); @@ -532,6 +603,162 @@ static int TestCorrectEncryption(const NCContext* context) return 0; } +#ifdef NC_ENABLE_UTILS + +#include <noscryptutil.h> + +/* Padding tests taken from the nip44 repo vectors.json file */ +static const uint32_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 }; +static const uint32_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 TestUtilNip44Encryption( + const NCContext* libCtx, + span_t sendKey, + span_t recvKey, + span_t nonce, + span_t expected, + span_t plainText +) +{ + NCPublicKey recvPubKey; + uint8_t* outData; + + ENSURE(NCValidateSecretKey(libCtx, NCByteCastToSecretKey(sendKey.data)) == NC_SUCCESS); + ENSURE(NCGetPublicKey(libCtx, NCByteCastToSecretKey(recvKey.data), &recvPubKey) == NC_SUCCESS); + + /* Alloc cipher in nip44 encryption mode */ + NCUtilCipherContext* ctx = NCUtilCipherAlloc( + NC_ENC_VERSION_NIP44, + NC_UTIL_CIPHER_MODE_ENCRYPT | NC_UTIL_CIPHER_ZERO_ON_FREE + ); + + ENSURE(ctx != NULL); + + 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); + + /* Cipher update should return the */ + TEST(NCUtilCipherUpdate(ctx, libCtx, NCByteCastToSecretKey(sendKey.data), &recvPubKey), NC_SUCCESS); + + NCResult cipherOutputSize = NCUtilCipherGetOutputSize(ctx); + + TEST(cipherOutputSize, expected.size); + + outData = (uint8_t*)malloc(cipherOutputSize); + TASSERT(outData != NULL); + + /* Read the encrypted payload to test */ + TEST(NCUtilCipherReadOutput(ctx, outData, cipherOutputSize), cipherOutputSize); + + /* Ensure encrypted payload matches */ + TEST(memcmp(outData, expected.data, cipherOutputSize), 0); + + free(outData); + + /* Free encryption memory */ + NCUtilCipherFree(ctx); + + return 0; +} + +static int TestUtilNip44Decryption( + const NCContext* libCtx, + span_t sendKey, + span_t recvKey, + span_t payload, + span_t expectedPt +) +{ + NCPublicKey recvPubKey; + uint8_t* outData; + + ENSURE(NCValidateSecretKey(libCtx, NCByteCastToSecretKey(sendKey.data)) == NC_SUCCESS); + ENSURE(NCGetPublicKey(libCtx, NCByteCastToSecretKey(recvKey.data), &recvPubKey) == NC_SUCCESS); + + /* Alloc cipher in nip44 decryption mode */ + NCUtilCipherContext* ctx = NCUtilCipherAlloc( + NC_ENC_VERSION_NIP44, + NC_UTIL_CIPHER_MODE_DECRYPT | NC_UTIL_CIPHER_ZERO_ON_FREE + ); + + ENSURE(ctx != NULL); + + /* submit encrypted payload for ciphertext */ + TEST(NCUtilCipherInit(ctx, payload.data, payload.size), NC_SUCCESS); + + TEST(NCUtilCipherUpdate(ctx, libCtx, NCByteCastToSecretKey(sendKey.data), &recvPubKey), NC_SUCCESS); + + NCResult plaintextSize = NCUtilCipherGetOutputSize(ctx); + + TEST(plaintextSize, expectedPt.size); + + outData = (uint8_t*)malloc(plaintextSize); + + TASSERT(outData != NULL); + + /* Read the encrypted payload to test */ + TEST(NCUtilCipherReadOutput(ctx, outData, plaintextSize), plaintextSize); + + /* Ensure encrypted payload matches */ + TEST(memcmp(outData, expectedPt.data, plaintextSize), 0); + + free(outData); + + /* Free encryption memory */ + NCUtilCipherFree(ctx); + + return 0; +} + +static int TestUtilFunctions(const NCContext* libCtx) +{ + 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("TEST: NIP-44 util encryption") + + /* 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); + span_t plainText = FromHexString("61", 1); + + if (TestUtilNip44Encryption(libCtx, sendKey, recvKey, nonce, payload, plainText) != 0) + { + return 1; + } + } + { + PRINTL("TEST: NIP-44 util decryption"); + + /* From the nip44 vectors file */ + span_t sendKey = FromHexString("0000000000000000000000000000000000000000000000000000000000000001", sizeof(NCSecretKey)); + span_t recvKey = FromHexString("0000000000000000000000000000000000000000000000000000000000000002", sizeof(NCSecretKey)); + span_t payload = FromHexString("02000000000000000000000000000000000000000000000000000000000000000179ed06e5548ad3ff58ca920e6c0b4329f6040230f7e6e5641f20741780f0adc35a09794259929a02bb06ad8e8cf709ee4ccc567e9d514cdf5781af27a3e905e55b1b", 99); + span_t plainText = FromHexString("61", 1); + + if (TestUtilNip44Decryption(libCtx, sendKey, recvKey, payload, plainText) != 0) + { + return 1; + } + } + + PRINTL("\nPASSED: Util functions tests completed") + return 0; +} + +#endif + static void FillRandomData(void* pbBuffer, size_t length) { diff --git a/vendor/mbedtls/include/mbedtls/build_info.h b/vendor/mbedtls/include/mbedtls/build_info.h index eab167f..cf38f90 100644 --- a/vendor/mbedtls/include/mbedtls/build_info.h +++ b/vendor/mbedtls/include/mbedtls/build_info.h @@ -101,6 +101,13 @@ #define inline __inline #endif +#if defined(MBEDTLS_CONFIG_FILES_READ) +#error "Something went wrong: MBEDTLS_CONFIG_FILES_READ defined before reading the config files!" +#endif +#if defined(MBEDTLS_CONFIG_IS_FINALIZED) +#error "Something went wrong: MBEDTLS_CONFIG_IS_FINALIZED defined before reading the config files!" +#endif + /* X.509, TLS and non-PSA crypto configuration */ #if !defined(MBEDTLS_CONFIG_FILE) #include "mbedtls/mbedtls_config.h" @@ -135,6 +142,12 @@ #endif #endif /* defined(MBEDTLS_PSA_CRYPTO_CONFIG) */ +/* Indicate that all configuration files have been read. + * It is now time to adjust the configuration (follow through on dependencies, + * make PSA and legacy crypto consistent, etc.). + */ +#define MBEDTLS_CONFIG_FILES_READ + /* Auto-enable MBEDTLS_CTR_DRBG_USE_128_BIT_KEY if * MBEDTLS_AES_ONLY_128_BIT_KEY_LENGTH and MBEDTLS_CTR_DRBG_C defined * to ensure a 128-bit key size in CTR_DRBG. @@ -169,8 +182,13 @@ #include "mbedtls/config_adjust_ssl.h" -/* Make sure all configuration symbols are set before including check_config.h, - * even the ones that are calculated programmatically. */ +/* Indicate that all configuration symbols are set, + * even the ones that are calculated programmatically. + * It is now safe to query the configuration (to check it, to size buffers, + * etc.). + */ +#define MBEDTLS_CONFIG_IS_FINALIZED + #include "mbedtls/check_config.h" #endif /* MBEDTLS_BUILD_INFO_H */ diff --git a/vendor/mbedtls/include/mbedtls/check_config.h b/vendor/mbedtls/include/mbedtls/check_config.h index b3c038d..2673229 100644 --- a/vendor/mbedtls/include/mbedtls/check_config.h +++ b/vendor/mbedtls/include/mbedtls/check_config.h @@ -2,6 +2,13 @@ * \file check_config.h * * \brief Consistency checks for configuration options + * + * This is an internal header. Do not include it directly. + * + * This header is included automatically by all public Mbed TLS headers + * (via mbedtls/build_info.h). Do not include it directly in a configuration + * file such as mbedtls/mbedtls_config.h or #MBEDTLS_USER_CONFIG_FILE! + * It would run at the wrong time due to missing derived symbols. */ /* * Copyright The Mbed TLS Contributors @@ -12,6 +19,13 @@ #define MBEDTLS_CHECK_CONFIG_H /* *INDENT-OFF* */ + +#if !defined(MBEDTLS_CONFIG_IS_FINALIZED) +#warning "Do not include mbedtls/check_config.h manually! " \ + "This may cause spurious errors. " \ + "It is included automatically at the right point since Mbed TLS 3.0." +#endif /* !MBEDTLS_CONFIG_IS_FINALIZED */ + /* * We assume CHAR_BIT is 8 in many places. In practice, this is true on our * target platforms, so not an issue, but let's just be extra sure. @@ -175,9 +189,7 @@ defined(MBEDTLS_ECDH_GEN_PUBLIC_ALT) || \ defined(MBEDTLS_ECDSA_SIGN_ALT) || \ defined(MBEDTLS_ECDSA_VERIFY_ALT) || \ - defined(MBEDTLS_ECDSA_GENKEY_ALT) || \ - defined(MBEDTLS_ECP_INTERNAL_ALT) || \ - defined(MBEDTLS_ECP_ALT) ) + defined(MBEDTLS_ECDSA_GENKEY_ALT) ) #error "MBEDTLS_ECP_RESTARTABLE defined, but it cannot coexist with an alternative ECP implementation" #endif @@ -255,42 +267,6 @@ #error "MBEDTLS_CHACHAPOLY_C defined, but not all prerequisites" #endif -#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) -#error "MBEDTLS_ECP_RANDOMIZE_JAC_ALT defined, but not all prerequisites" -#endif - -#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) -#error "MBEDTLS_ECP_ADD_MIXED_ALT defined, but not all prerequisites" -#endif - -#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) -#error "MBEDTLS_ECP_DOUBLE_JAC_ALT defined, but not all prerequisites" -#endif - -#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) -#error "MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT defined, but not all prerequisites" -#endif - -#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) -#error "MBEDTLS_ECP_NORMALIZE_JAC_ALT defined, but not all prerequisites" -#endif - -#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) -#error "MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT defined, but not all prerequisites" -#endif - -#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) -#error "MBEDTLS_ECP_RANDOMIZE_MXZ_ALT defined, but not all prerequisites" -#endif - -#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) && !defined(MBEDTLS_ECP_INTERNAL_ALT) -#error "MBEDTLS_ECP_NORMALIZE_MXZ_ALT defined, but not all prerequisites" -#endif - -#if defined(MBEDTLS_ECP_NO_FALLBACK) && !defined(MBEDTLS_ECP_INTERNAL_ALT) -#error "MBEDTLS_ECP_NO_FALLBACK defined, but no alternative implementation enabled" -#endif - #if defined(MBEDTLS_HKDF_C) && !defined(MBEDTLS_MD_C) #error "MBEDTLS_HKDF_C defined, but not all prerequisites" #endif @@ -754,8 +730,8 @@ #if !defined(MBEDTLS_SHA512_C) #error "MBEDTLS_SHA512_USE_A64_CRYPTO_* defined without MBEDTLS_SHA512_C" #endif -#if defined(MBEDTLS_SHA512_ALT) || defined(MBEDTLS_SHA512_PROCESS_ALT) -#error "MBEDTLS_SHA512_*ALT can't be used with MBEDTLS_SHA512_USE_A64_CRYPTO_*" +#if defined(MBEDTLS_SHA512_PROCESS_ALT) +#error "MBEDTLS_SHA512_PROCESS_ALT can't be used with MBEDTLS_SHA512_USE_A64_CRYPTO_*" #endif #endif /* MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT || MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY */ @@ -774,8 +750,8 @@ #if !defined(MBEDTLS_SHA256_C) #error "MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_* defined without MBEDTLS_SHA256_C" #endif -#if defined(MBEDTLS_SHA256_ALT) || defined(MBEDTLS_SHA256_PROCESS_ALT) -#error "MBEDTLS_SHA256_*ALT can't be used with MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_*" +#if defined(MBEDTLS_SHA256_PROCESS_ALT) +#error "MBEDTLS_SHA256_PROCESS_ALT can't be used with MBEDTLS_SHA256_USE_ARMV8_A_CRYPTO_*" #endif #endif diff --git a/vendor/mbedtls/include/mbedtls/config_adjust_legacy_crypto.h b/vendor/mbedtls/include/mbedtls/config_adjust_legacy_crypto.h index e477c07..7a375d8 100644 --- a/vendor/mbedtls/include/mbedtls/config_adjust_legacy_crypto.h +++ b/vendor/mbedtls/include/mbedtls/config_adjust_legacy_crypto.h @@ -2,7 +2,9 @@ * \file mbedtls/config_adjust_legacy_crypto.h * \brief Adjust legacy configuration configuration * - * Automatically enable certain dependencies. Generally, MBEDLTS_xxx + * This is an internal header. Do not include it directly. + * + * Automatically enable certain dependencies. Generally, MBEDTLS_xxx * configurations need to be explicitly enabled by the user: enabling * MBEDTLS_xxx_A but not MBEDTLS_xxx_B when A requires B results in a * compilation error. However, we do automatically enable certain options @@ -22,6 +24,14 @@ #ifndef MBEDTLS_CONFIG_ADJUST_LEGACY_CRYPTO_H #define MBEDTLS_CONFIG_ADJUST_LEGACY_CRYPTO_H +#if !defined(MBEDTLS_CONFIG_FILES_READ) +#error "Do not include mbedtls/config_adjust_*.h manually! This can lead to problems, " \ + "up to and including runtime errors such as buffer overflows. " \ + "If you're trying to fix a complaint from check_config.h, just remove " \ + "it from your configuration file: since Mbed TLS 3.0, it is included " \ + "automatically at the right point." +#endif /* */ + /* Ideally, we'd set those as defaults in mbedtls_config.h, but * putting an #ifdef _WIN32 in mbedtls_config.h would confuse config.py. * @@ -48,7 +58,8 @@ defined(MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING) || \ defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING) || \ defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7) || \ - defined(MBEDTLS_PSA_BUILTIN_ALG_CCM_STAR_NO_TAG)) + defined(MBEDTLS_PSA_BUILTIN_ALG_CCM_STAR_NO_TAG) || \ + defined(MBEDTLS_PSA_BUILTIN_ALG_CMAC)) #define MBEDTLS_CIPHER_C #endif @@ -422,7 +433,7 @@ #define MBEDTLS_PSA_UTIL_HAVE_ECDSA #endif -/* Some internal helpers to determine which keys are availble. */ +/* Some internal helpers to determine which keys are available. */ #if (!defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_AES_C)) || \ (defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_KEY_TYPE_AES)) #define MBEDTLS_SSL_HAVE_AES @@ -436,7 +447,7 @@ #define MBEDTLS_SSL_HAVE_CAMELLIA #endif -/* Some internal helpers to determine which operation modes are availble. */ +/* Some internal helpers to determine which operation modes are available. */ #if (!defined(MBEDTLS_USE_PSA_CRYPTO) && defined(MBEDTLS_CIPHER_MODE_CBC)) || \ (defined(MBEDTLS_USE_PSA_CRYPTO) && defined(PSA_WANT_ALG_CBC_NO_PADDING)) #define MBEDTLS_SSL_HAVE_CBC diff --git a/vendor/mbedtls/include/mbedtls/config_adjust_psa_from_legacy.h b/vendor/mbedtls/include/mbedtls/config_adjust_psa_from_legacy.h index 3456615..14ca146 100644 --- a/vendor/mbedtls/include/mbedtls/config_adjust_psa_from_legacy.h +++ b/vendor/mbedtls/include/mbedtls/config_adjust_psa_from_legacy.h @@ -2,6 +2,8 @@ * \file mbedtls/config_adjust_psa_from_legacy.h * \brief Adjust PSA configuration: construct PSA configuration from legacy * + * This is an internal header. Do not include it directly. + * * When MBEDTLS_PSA_CRYPTO_CONFIG is disabled, we automatically enable * cryptographic mechanisms through the PSA interface when the corresponding * legacy mechanism is enabled. In many cases, this just enables the PSA @@ -18,6 +20,14 @@ #ifndef MBEDTLS_CONFIG_ADJUST_PSA_FROM_LEGACY_H #define MBEDTLS_CONFIG_ADJUST_PSA_FROM_LEGACY_H +#if !defined(MBEDTLS_CONFIG_FILES_READ) +#error "Do not include mbedtls/config_adjust_*.h manually! This can lead to problems, " \ + "up to and including runtime errors such as buffer overflows. " \ + "If you're trying to fix a complaint from check_config.h, just remove " \ + "it from your configuration file: since Mbed TLS 3.0, it is included " \ + "automatically at the right point." +#endif /* */ + /* * Ensure PSA_WANT_* defines are setup properly if MBEDTLS_PSA_CRYPTO_CONFIG * is not defined diff --git a/vendor/mbedtls/include/mbedtls/config_adjust_ssl.h b/vendor/mbedtls/include/mbedtls/config_adjust_ssl.h index 39c7b3b..1f82d9c 100644 --- a/vendor/mbedtls/include/mbedtls/config_adjust_ssl.h +++ b/vendor/mbedtls/include/mbedtls/config_adjust_ssl.h @@ -2,7 +2,9 @@ * \file mbedtls/config_adjust_ssl.h * \brief Adjust TLS configuration * - * Automatically enable certain dependencies. Generally, MBEDLTS_xxx + * This is an internal header. Do not include it directly. + * + * Automatically enable certain dependencies. Generally, MBEDTLS_xxx * configurations need to be explicitly enabled by the user: enabling * MBEDTLS_xxx_A but not MBEDTLS_xxx_B when A requires B results in a * compilation error. However, we do automatically enable certain options @@ -22,6 +24,14 @@ #ifndef MBEDTLS_CONFIG_ADJUST_SSL_H #define MBEDTLS_CONFIG_ADJUST_SSL_H +#if !defined(MBEDTLS_CONFIG_FILES_READ) +#error "Do not include mbedtls/config_adjust_*.h manually! This can lead to problems, " \ + "up to and including runtime errors such as buffer overflows. " \ + "If you're trying to fix a complaint from check_config.h, just remove " \ + "it from your configuration file: since Mbed TLS 3.0, it is included " \ + "automatically at the right point." +#endif /* */ + /* The following blocks make it easier to disable all of TLS, * or of TLS 1.2 or 1.3 or DTLS, without having to manually disable all * key exchanges, options and extensions related to them. */ diff --git a/vendor/mbedtls/include/mbedtls/config_adjust_x509.h b/vendor/mbedtls/include/mbedtls/config_adjust_x509.h index 346c8ae..cfb2d88 100644 --- a/vendor/mbedtls/include/mbedtls/config_adjust_x509.h +++ b/vendor/mbedtls/include/mbedtls/config_adjust_x509.h @@ -2,7 +2,9 @@ * \file mbedtls/config_adjust_x509.h * \brief Adjust X.509 configuration * - * Automatically enable certain dependencies. Generally, MBEDLTS_xxx + * This is an internal header. Do not include it directly. + * + * Automatically enable certain dependencies. Generally, MBEDTLS_xxx * configurations need to be explicitly enabled by the user: enabling * MBEDTLS_xxx_A but not MBEDTLS_xxx_B when A requires B results in a * compilation error. However, we do automatically enable certain options @@ -22,4 +24,12 @@ #ifndef MBEDTLS_CONFIG_ADJUST_X509_H #define MBEDTLS_CONFIG_ADJUST_X509_H +#if !defined(MBEDTLS_CONFIG_FILES_READ) +#error "Do not include mbedtls/config_adjust_*.h manually! This can lead to problems, " \ + "up to and including runtime errors such as buffer overflows. " \ + "If you're trying to fix a complaint from check_config.h, just remove " \ + "it from your configuration file: since Mbed TLS 3.0, it is included " \ + "automatically at the right point." +#endif /* */ + #endif /* MBEDTLS_CONFIG_ADJUST_X509_H */ diff --git a/vendor/mbedtls/include/mbedtls/mbedtls_config.h b/vendor/mbedtls/include/mbedtls/mbedtls_config.h index 3592141..0f1b54e 100644 --- a/vendor/mbedtls/include/mbedtls/mbedtls_config.h +++ b/vendor/mbedtls/include/mbedtls/mbedtls_config.h @@ -40,12 +40,10 @@ * library/aria.c * library/bn_mul.h * library/constant_time.c - * library/padlock.h * * Required by: * MBEDTLS_AESCE_C * MBEDTLS_AESNI_C (on some platforms) - * MBEDTLS_PADLOCK_C * * Comment to disable the use of assembly code. */ @@ -353,62 +351,6 @@ //#define MBEDTLS_TIMING_ALT /** - * \def MBEDTLS_AES_ALT - * - * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let Mbed TLS use your - * alternate core implementation of a symmetric crypto, an arithmetic or hash - * module (e.g. platform specific assembly optimized implementations). Keep - * in mind that the function prototypes should remain the same. - * - * This replaces the whole module. If you only want to replace one of the - * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. - * - * Example: In case you uncomment MBEDTLS_AES_ALT, Mbed TLS will no longer - * provide the "struct mbedtls_aes_context" definition and omit the base - * function declarations and implementations. "aes_alt.h" will be included from - * "aes.h" to include the new function definitions. - * - * Uncomment a macro to enable alternate implementation of the corresponding - * module. - * - * \warning MD5, DES and SHA-1 are considered weak and their - * use constitutes a security risk. If possible, we recommend - * avoiding dependencies on them, and considering stronger message - * digests and ciphers instead. - * - */ -//#define MBEDTLS_AES_ALT -//#define MBEDTLS_ARIA_ALT -//#define MBEDTLS_CAMELLIA_ALT -//#define MBEDTLS_CCM_ALT -//#define MBEDTLS_CHACHA20_ALT -//#define MBEDTLS_CHACHAPOLY_ALT -//#define MBEDTLS_CMAC_ALT -//#define MBEDTLS_DES_ALT -//#define MBEDTLS_DHM_ALT -//#define MBEDTLS_ECJPAKE_ALT -//#define MBEDTLS_GCM_ALT -//#define MBEDTLS_NIST_KW_ALT -//#define MBEDTLS_MD5_ALT -//#define MBEDTLS_POLY1305_ALT -//#define MBEDTLS_RIPEMD160_ALT -//#define MBEDTLS_RSA_ALT -//#define MBEDTLS_SHA1_ALT -//#define MBEDTLS_SHA256_ALT -//#define MBEDTLS_SHA512_ALT - -/* - * When replacing the elliptic curve module, please consider, that it is - * implemented with two .c files: - * - ecp.c - * - ecp_curves.c - * You can replace them very much like all the other MBEDTLS__MODULE_NAME__ALT - * macros as described above. The only difference is that you have to make sure - * that you provide functionality for both .c files. - */ -//#define MBEDTLS_ECP_ALT - -/** * \def MBEDTLS_SHA256_PROCESS_ALT * * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let Mbed TLS use you @@ -464,71 +406,6 @@ //#define MBEDTLS_ECDSA_GENKEY_ALT /** - * \def MBEDTLS_ECP_INTERNAL_ALT - * - * Expose a part of the internal interface of the Elliptic Curve Point module. - * - * MBEDTLS_ECP__FUNCTION_NAME__ALT: Uncomment a macro to let Mbed TLS use your - * alternative core implementation of elliptic curve arithmetic. Keep in mind - * that function prototypes should remain the same. - * - * This partially replaces one function. The header file from Mbed TLS is still - * used, in contrast to the MBEDTLS_ECP_ALT flag. The original implementation - * is still present and it is used for group structures not supported by the - * alternative. - * - * The original implementation can in addition be removed by setting the - * MBEDTLS_ECP_NO_FALLBACK option, in which case any function for which the - * corresponding MBEDTLS_ECP__FUNCTION_NAME__ALT macro is defined will not be - * able to fallback to curves not supported by the alternative implementation. - * - * Any of these options become available by defining MBEDTLS_ECP_INTERNAL_ALT - * and implementing the following functions: - * unsigned char mbedtls_internal_ecp_grp_capable( - * const mbedtls_ecp_group *grp ) - * int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ) - * void mbedtls_internal_ecp_free( const mbedtls_ecp_group *grp ) - * The mbedtls_internal_ecp_grp_capable function should return 1 if the - * replacement functions implement arithmetic for the given group and 0 - * otherwise. - * The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_free are - * called before and after each point operation and provide an opportunity to - * implement optimized set up and tear down instructions. - * - * Example: In case you set MBEDTLS_ECP_INTERNAL_ALT and - * MBEDTLS_ECP_DOUBLE_JAC_ALT, Mbed TLS will still provide the ecp_double_jac() - * function, but will use your mbedtls_internal_ecp_double_jac() if the group - * for the operation is supported by your implementation (i.e. your - * mbedtls_internal_ecp_grp_capable() function returns 1 for this group). If the - * group is not supported by your implementation, then the original Mbed TLS - * implementation of ecp_double_jac() is used instead, unless this fallback - * behaviour is disabled by setting MBEDTLS_ECP_NO_FALLBACK (in which case - * ecp_double_jac() will return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE). - * - * The function prototypes and the definition of mbedtls_ecp_group and - * mbedtls_ecp_point will not change based on MBEDTLS_ECP_INTERNAL_ALT, so your - * implementation of mbedtls_internal_ecp__function_name__ must be compatible - * with their definitions. - * - * Uncomment a macro to enable alternate implementation of the corresponding - * function. - */ -/* Required for all the functions in this section */ -//#define MBEDTLS_ECP_INTERNAL_ALT -/* Turn off software fallback for curves not supported in hardware */ -//#define MBEDTLS_ECP_NO_FALLBACK -/* Support for Weierstrass curves with Jacobi representation */ -//#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT -//#define MBEDTLS_ECP_ADD_MIXED_ALT -//#define MBEDTLS_ECP_DOUBLE_JAC_ALT -//#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT -//#define MBEDTLS_ECP_NORMALIZE_JAC_ALT -/* Support for curves with Montgomery arithmetic */ -//#define MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT -//#define MBEDTLS_ECP_RANDOMIZE_MXZ_ALT -//#define MBEDTLS_ECP_NORMALIZE_MXZ_ALT - -/** * \def MBEDTLS_ENTROPY_HARDWARE_ALT * * Uncomment this macro to let Mbed TLS use your own implementation of a @@ -830,7 +707,7 @@ * * \note This option only works with the default software implementation of * elliptic curve functionality. It is incompatible with - * MBEDTLS_ECP_ALT, MBEDTLS_ECDH_XXX_ALT, MBEDTLS_ECDSA_XXX_ALT. + * MBEDTLS_ECDH_XXX_ALT, MBEDTLS_ECDSA_XXX_ALT. * * Requires: MBEDTLS_ECP_C * @@ -1118,7 +995,7 @@ * MBEDTLS_ECP_DP_SECP256R1_ENABLED * * \warning If SHA-256 is provided only by a PSA driver, you must call - * psa_crypto_init() before the first hanshake (even if + * psa_crypto_init() before the first handshake (even if * MBEDTLS_USE_PSA_CRYPTO is disabled). * * This enables the following ciphersuites (if other requisites are @@ -2606,11 +2483,6 @@ * Enable the CMAC (Cipher-based Message Authentication Code) mode for block * ciphers. * - * \note When #MBEDTLS_CMAC_ALT is active, meaning that the underlying - * implementation of the CMAC algorithm is provided by an alternate - * implementation, that alternate implementation may opt to not support - * AES-192 or 3DES as underlying block ciphers for the CMAC operation. - * * Module: library/cmac.c * * Requires: MBEDTLS_CIPHER_C, MBEDTLS_AES_C or MBEDTLS_DES_C @@ -2625,7 +2497,7 @@ * The CTR_DRBG generator uses AES-256 by default. * To use AES-128 instead, enable \c MBEDTLS_CTR_DRBG_USE_128_BIT_KEY above. * - * AES support can either be achived through builtin (MBEDTLS_AES_C) or PSA. + * AES support can either be achieved through builtin (MBEDTLS_AES_C) or PSA. * Builtin is the default option when MBEDTLS_AES_C is defined otherwise PSA * is used. * @@ -3011,20 +2883,6 @@ #define MBEDTLS_OID_C /** - * \def MBEDTLS_PADLOCK_C - * - * Enable VIA Padlock support on x86. - * - * Module: library/padlock.c - * Caller: library/aes.c - * - * Requires: MBEDTLS_HAVE_ASM - * - * This modules adds support for the VIA PadLock on x86. - */ -#define MBEDTLS_PADLOCK_C - -/** * \def MBEDTLS_PEM_PARSE_C * * Enable PEM decoding / parsing. diff --git a/vendor/mbedtls/include/mbedtls/ssl.h b/vendor/mbedtls/include/mbedtls/ssl.h index ca130a3..5b22517 100644 --- a/vendor/mbedtls/include/mbedtls/ssl.h +++ b/vendor/mbedtls/include/mbedtls/ssl.h @@ -643,8 +643,8 @@ */ #if defined(MBEDTLS_SSL_PROTO_TLS1_3) && \ defined(MBEDTLS_SSL_SESSION_TICKETS) && \ - defined(MBEDTLS_SSL_HAVE_AES) && defined(MBEDTLS_SSL_HAVE_GCM) && \ - defined(MBEDTLS_MD_CAN_SHA384) + defined(PSA_WANT_KEY_TYPE_AES) && defined(PSA_WANT_ALG_GCM) && \ + defined(PSA_WANT_ALG_SHA_384) #define MBEDTLS_PSK_MAX_LEN 48 /* 384 bits */ #else #define MBEDTLS_PSK_MAX_LEN 32 /* 256 bits */ @@ -1153,10 +1153,10 @@ typedef void mbedtls_ssl_async_cancel_t(mbedtls_ssl_context *ssl); #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) && \ !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE) #define MBEDTLS_SSL_PEER_CERT_DIGEST_MAX_LEN 48 -#if defined(MBEDTLS_MD_CAN_SHA256) +#if defined(PSA_WANT_ALG_SHA_256) #define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA256 #define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN 32 -#elif defined(MBEDTLS_MD_CAN_SHA384) +#elif defined(PSA_WANT_ALG_SHA_384) #define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE MBEDTLS_MD_SHA384 #define MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN 48 #elif defined(MBEDTLS_MD_CAN_SHA1) @@ -2364,7 +2364,7 @@ int mbedtls_ssl_set_cid(mbedtls_ssl_context *ssl, */ int mbedtls_ssl_get_own_cid(mbedtls_ssl_context *ssl, int *enabled, - unsigned char own_cid[MBEDTLS_SSL_CID_OUT_LEN_MAX], + unsigned char own_cid[MBEDTLS_SSL_CID_IN_LEN_MAX], size_t *own_cid_len); /** diff --git a/vendor/openssl/include/openssl/cmp.h.in b/vendor/openssl/include/openssl/cmp.h.in index c46b9ab..ad9eb34 100644 --- a/vendor/openssl/include/openssl/cmp.h.in +++ b/vendor/openssl/include/openssl/cmp.h.in @@ -228,12 +228,6 @@ DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_ITAV) {- generate_stack_macros("OSSL_CMP_ITAV"); -} - -typedef struct ossl_cmp_crlstatus_st OSSL_CMP_CRLSTATUS; -{- - generate_stack_macros("OSSL_CMP_CRLSTATUS"); --} - typedef struct ossl_cmp_revrepcontent_st OSSL_CMP_REVREPCONTENT; typedef struct ossl_cmp_pkisi_st OSSL_CMP_PKISI; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKISI) @@ -263,7 +257,7 @@ void OSSL_CMP_ITAV_set0(OSSL_CMP_ITAV *itav, ASN1_OBJECT *type, ASN1_TYPE *value); ASN1_OBJECT *OSSL_CMP_ITAV_get0_type(const OSSL_CMP_ITAV *itav); ASN1_TYPE *OSSL_CMP_ITAV_get0_value(const OSSL_CMP_ITAV *itav); -int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **sk_p, +int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **itav_sk_p, OSSL_CMP_ITAV *itav); void OSSL_CMP_ITAV_free(OSSL_CMP_ITAV *itav); @@ -284,22 +278,6 @@ int OSSL_CMP_ITAV_get0_rootCaKeyUpdate(const OSSL_CMP_ITAV *itav, X509 **newWithOld, X509 **oldWithNew); -OSSL_CMP_CRLSTATUS *OSSL_CMP_CRLSTATUS_create(const X509_CRL *crl, - const X509 *cert, int only_DN); -OSSL_CMP_CRLSTATUS *OSSL_CMP_CRLSTATUS_new1(const DIST_POINT_NAME *dpn, - const GENERAL_NAMES *issuer, - const ASN1_TIME *thisUpdate); -int OSSL_CMP_CRLSTATUS_get0(const OSSL_CMP_CRLSTATUS *crlstatus, - DIST_POINT_NAME **dpn, GENERAL_NAMES **issuer, - ASN1_TIME **thisUpdate); -void OSSL_CMP_CRLSTATUS_free(OSSL_CMP_CRLSTATUS *crlstatus); -OSSL_CMP_ITAV -*OSSL_CMP_ITAV_new0_crlStatusList(STACK_OF(OSSL_CMP_CRLSTATUS) *crlStatusList); -int OSSL_CMP_ITAV_get0_crlStatusList(const OSSL_CMP_ITAV *itav, - STACK_OF(OSSL_CMP_CRLSTATUS) **out); -OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_crls(const X509_CRL *crls); -int OSSL_CMP_ITAV_get0_crls(const OSSL_CMP_ITAV *it, STACK_OF(X509_CRL) **out); - void OSSL_CMP_MSG_free(OSSL_CMP_MSG *msg); /* from cmp_ctx.c */ @@ -543,9 +521,6 @@ int OSSL_CMP_get1_caCerts(OSSL_CMP_CTX *ctx, STACK_OF(X509) **out); int OSSL_CMP_get1_rootCaKeyUpdate(OSSL_CMP_CTX *ctx, const X509 *oldWithOld, X509 **newWithNew, X509 **newWithOld, X509 **oldWithNew); -int OSSL_CMP_get1_crlUpdate(OSSL_CMP_CTX *ctx, const X509 *crlcert, - const X509_CRL *last_crl, - X509_CRL **crl); # ifdef __cplusplus } diff --git a/vendor/openssl/include/openssl/cmperr.h b/vendor/openssl/include/openssl/cmperr.h index 700ffbe..0d876e5 100644 --- a/vendor/openssl/include/openssl/cmperr.h +++ b/vendor/openssl/include/openssl/cmperr.h @@ -60,9 +60,7 @@ # define CMP_R_FAILED_EXTRACTING_PUBKEY 141 # define CMP_R_FAILURE_OBTAINING_RANDOM 110 # define CMP_R_FAIL_INFO_OUT_OF_RANGE 129 -# define CMP_R_GENERATE_CRLSTATUS 198 # define CMP_R_GETTING_GENP 192 -# define CMP_R_GET_ITAV 199 # define CMP_R_INVALID_ARGS 100 # define CMP_R_INVALID_GENP 193 # define CMP_R_INVALID_OPTION 174 @@ -102,7 +100,6 @@ # define CMP_R_TRANSFER_ERROR 159 # define CMP_R_UNCLEAN_CTX 191 # define CMP_R_UNEXPECTED_CERTPROFILE 196 -# define CMP_R_UNEXPECTED_CRLSTATUSLIST 201 # define CMP_R_UNEXPECTED_PKIBODY 133 # define CMP_R_UNEXPECTED_PKISTATUS 185 # define CMP_R_UNEXPECTED_POLLREQ 105 @@ -110,7 +107,6 @@ # define CMP_R_UNEXPECTED_SENDER 106 # define CMP_R_UNKNOWN_ALGORITHM_ID 134 # define CMP_R_UNKNOWN_CERT_TYPE 135 -# define CMP_R_UNKNOWN_CRL_ISSUER 200 # define CMP_R_UNKNOWN_PKISTATUS 186 # define CMP_R_UNSUPPORTED_ALGORITHM 136 # define CMP_R_UNSUPPORTED_KEY_TYPE 137 diff --git a/vendor/openssl/include/openssl/comp.h.in b/vendor/openssl/include/openssl/comp.h.in new file mode 100644 index 0000000..bd1efdc --- /dev/null +++ b/vendor/openssl/include/openssl/comp.h.in @@ -0,0 +1,76 @@ +/* + * Copyright 2015-2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +{- +use OpenSSL::stackhash qw(generate_stack_macros); +-} + +#ifndef OPENSSL_COMP_H +# define OPENSSL_COMP_H +# pragma once + +# include <openssl/macros.h> +# ifndef OPENSSL_NO_DEPRECATED_3_0 +# define HEADER_COMP_H +# endif + +# include <openssl/opensslconf.h> + +# include <openssl/crypto.h> +# include <openssl/comperr.h> +# ifdef __cplusplus +extern "C" { +# endif + + + +# ifndef OPENSSL_NO_COMP + +COMP_CTX *COMP_CTX_new(COMP_METHOD *meth); +const COMP_METHOD *COMP_CTX_get_method(const COMP_CTX *ctx); +int COMP_CTX_get_type(const COMP_CTX* comp); +int COMP_get_type(const COMP_METHOD *meth); +const char *COMP_get_name(const COMP_METHOD *meth); +void COMP_CTX_free(COMP_CTX *ctx); + +int COMP_compress_block(COMP_CTX *ctx, unsigned char *out, int olen, + unsigned char *in, int ilen); +int COMP_expand_block(COMP_CTX *ctx, unsigned char *out, int olen, + unsigned char *in, int ilen); + +COMP_METHOD *COMP_zlib(void); +COMP_METHOD *COMP_zlib_oneshot(void); +COMP_METHOD *COMP_brotli(void); +COMP_METHOD *COMP_brotli_oneshot(void); +COMP_METHOD *COMP_zstd(void); +COMP_METHOD *COMP_zstd_oneshot(void); + +# ifndef OPENSSL_NO_DEPRECATED_1_1_0 +# define COMP_zlib_cleanup() while(0) continue +# endif + +# ifdef OPENSSL_BIO_H +const BIO_METHOD *BIO_f_zlib(void); +const BIO_METHOD *BIO_f_brotli(void); +const BIO_METHOD *BIO_f_zstd(void); +# endif + +# endif + +typedef struct ssl_comp_st SSL_COMP; + +{- + generate_stack_macros("SSL_COMP"); +-} + + +# ifdef __cplusplus +} +# endif +#endif diff --git a/vendor/openssl/include/openssl/crypto.h.in b/vendor/openssl/include/openssl/crypto.h.in index 034f150..b2d691b 100644 --- a/vendor/openssl/include/openssl/crypto.h.in +++ b/vendor/openssl/include/openssl/crypto.h.in @@ -90,7 +90,6 @@ int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret, CRYPTO_RWLOCK *lock); int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock); int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock); -int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock); /* No longer needed, so this is a no-op */ #define OPENSSL_malloc_init() while(0) continue @@ -99,9 +98,6 @@ int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock); CRYPTO_malloc(num, OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_zalloc(num) \ CRYPTO_zalloc(num, OPENSSL_FILE, OPENSSL_LINE) -# define OPENSSL_aligned_alloc(num, alignment, freeptr) \ - CRYPTO_aligned_alloc(num, alignment, freeptr, \ - OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_realloc(addr, num) \ CRYPTO_realloc(addr, num, OPENSSL_FILE, OPENSSL_LINE) # define OPENSSL_clear_realloc(addr, old_num, num) \ @@ -325,9 +321,6 @@ void CRYPTO_get_mem_functions(CRYPTO_malloc_fn *malloc_fn, OSSL_CRYPTO_ALLOC void *CRYPTO_malloc(size_t num, const char *file, int line); OSSL_CRYPTO_ALLOC void *CRYPTO_zalloc(size_t num, const char *file, int line); -OSSL_CRYPTO_ALLOC void *CRYPTO_aligned_alloc(size_t num, size_t align, - void **freeptr, const char *file, - int line); OSSL_CRYPTO_ALLOC void *CRYPTO_memdup(const void *str, size_t siz, const char *file, int line); OSSL_CRYPTO_ALLOC char *CRYPTO_strdup(const char *str, const char *file, int line); OSSL_CRYPTO_ALLOC char *CRYPTO_strndup(const char *str, size_t s, const char *file, int line); @@ -536,8 +529,6 @@ int OSSL_LIB_CTX_load_config(OSSL_LIB_CTX *ctx, const char *config_file); void OSSL_LIB_CTX_free(OSSL_LIB_CTX *); OSSL_LIB_CTX *OSSL_LIB_CTX_get0_global_default(void); OSSL_LIB_CTX *OSSL_LIB_CTX_set0_default(OSSL_LIB_CTX *libctx); -int OSSL_LIB_CTX_get_conf_diagnostics(OSSL_LIB_CTX *ctx); -void OSSL_LIB_CTX_set_conf_diagnostics(OSSL_LIB_CTX *ctx, int value); void OSSL_sleep(uint64_t millis); diff --git a/vendor/openssl/include/openssl/e_os2.h b/vendor/openssl/include/openssl/e_os2.h index a4aea0b..f1e1795 100644 --- a/vendor/openssl/include/openssl/e_os2.h +++ b/vendor/openssl/include/openssl/e_os2.h @@ -1,5 +1,5 @@ /* - * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -200,7 +200,6 @@ extern "C" { # endif # ifndef ossl_ssize_t -# include <sys/types.h> # define ossl_ssize_t ssize_t # if defined(SSIZE_MAX) # define OSSL_SSIZE_MAX SSIZE_MAX @@ -229,6 +228,7 @@ typedef INT32 int32_t; typedef UINT32 uint32_t; typedef INT64 int64_t; typedef UINT64 uint64_t; +typedef UINTN uintptr_t; # elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ defined(__osf__) || defined(__sgi) || defined(__hpux) || \ defined(OPENSSL_SYS_VMS) || defined (__OpenBSD__) diff --git a/vendor/openssl/include/openssl/indicator.h b/vendor/openssl/include/openssl/indicator.h new file mode 100644 index 0000000..3ea0122 --- /dev/null +++ b/vendor/openssl/include/openssl/indicator.h @@ -0,0 +1,31 @@ +/* + * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef OPENSSL_INDICATOR_H +# define OPENSSL_INDICATOR_H +# pragma once + +# ifdef __cplusplus +extern "C" { +# endif + +#include <openssl/params.h> + +typedef int (OSSL_INDICATOR_CALLBACK)(const char *type, const char *desc, + const OSSL_PARAM params[]); + +void OSSL_INDICATOR_set_callback(OSSL_LIB_CTX *libctx, + OSSL_INDICATOR_CALLBACK *cb); +void OSSL_INDICATOR_get_callback(OSSL_LIB_CTX *libctx, + OSSL_INDICATOR_CALLBACK **cb); + +# ifdef __cplusplus +} +# endif +#endif /* OPENSSL_INDICATOR_H */ diff --git a/vendor/openssl/include/openssl/pem.h b/vendor/openssl/include/openssl/pem.h index 6ea1a49..0446c77 100644 --- a/vendor/openssl/include/openssl/pem.h +++ b/vendor/openssl/include/openssl/pem.h @@ -58,7 +58,6 @@ extern "C" { # define PEM_STRING_PARAMETERS "PARAMETERS" # define PEM_STRING_CMS "CMS" # define PEM_STRING_SM2PARAMETERS "SM2 PARAMETERS" -# define PEM_STRING_ACERT "ATTRIBUTE CERTIFICATE" # define PEM_TYPE_ENCRYPTED 10 # define PEM_TYPE_MIC_ONLY 20 diff --git a/vendor/openssl/include/openssl/sslerr.h b/vendor/openssl/include/openssl/sslerr.h index 8222b25..ec35df6 100644 --- a/vendor/openssl/include/openssl/sslerr.h +++ b/vendor/openssl/include/openssl/sslerr.h @@ -117,7 +117,6 @@ # define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 354 # define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 150 # define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 151 -# define SSL_R_ERROR_IN_SYSTEM_DEFAULT_CONFIG 419 # define SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN 204 # define SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE 194 # define SSL_R_EXCESSIVE_MESSAGE_SIZE 152 diff --git a/vendor/openssl/include/openssl/tls1.h b/vendor/openssl/include/openssl/tls1.h index 8ff39e3..7e3d1a7 100644 --- a/vendor/openssl/include/openssl/tls1.h +++ b/vendor/openssl/include/openssl/tls1.h @@ -622,10 +622,6 @@ int SSL_CTX_set_tlsext_ticket_key_evp_cb # define TLS1_3_CK_AES_128_CCM_SHA256 0x03001304 # define TLS1_3_CK_AES_128_CCM_8_SHA256 0x03001305 -/* Integrity-only ciphersuites from RFC 9150 */ -# define TLS1_3_CK_SHA256_SHA256 0x0300C0B4 -# define TLS1_3_CK_SHA384_SHA384 0x0300C0B5 - /* Aria ciphersuites from RFC6209 */ # define TLS1_CK_RSA_WITH_ARIA_128_GCM_SHA256 0x0300C050 # define TLS1_CK_RSA_WITH_ARIA_256_GCM_SHA384 0x0300C051 @@ -703,8 +699,6 @@ int SSL_CTX_set_tlsext_ticket_key_evp_cb # define TLS1_3_RFC_AES_128_GCM_SHA256 "TLS_AES_128_GCM_SHA256" # define TLS1_3_RFC_AES_256_GCM_SHA384 "TLS_AES_256_GCM_SHA384" # define TLS1_3_RFC_CHACHA20_POLY1305_SHA256 "TLS_CHACHA20_POLY1305_SHA256" -# define TLS1_3_RFC_SHA256_SHA256 "TLS_SHA256_SHA256" -# define TLS1_3_RFC_SHA384_SHA384 "TLS_SHA384_SHA384" # define TLS1_3_RFC_AES_128_CCM_SHA256 "TLS_AES_128_CCM_SHA256" # define TLS1_3_RFC_AES_128_CCM_8_SHA256 "TLS_AES_128_CCM_8_SHA256" # define TLS1_RFC_ECDHE_ECDSA_WITH_NULL_SHA "TLS_ECDHE_ECDSA_WITH_NULL_SHA" diff --git a/vendor/openssl/include/openssl/x509.h.in b/vendor/openssl/include/openssl/x509.h.in index 7d7ffa2..7210391 100644 --- a/vendor/openssl/include/openssl/x509.h.in +++ b/vendor/openssl/include/openssl/x509.h.in @@ -67,24 +67,16 @@ extern "C" { # define X509_FILETYPE_ASN1 2 # define X509_FILETYPE_DEFAULT 3 -/*- - * <https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3>: - * The KeyUsage BITSTRING is treated as a little-endian integer, hence bit `0` - * is 0x80, while bit `7` is 0x01 (the LSB of the integer value), bit `8` is - * then the MSB of the second octet, or 0x8000. - */ -# define X509v3_KU_DIGITAL_SIGNATURE 0x0080 /* (0) */ -# define X509v3_KU_NON_REPUDIATION 0x0040 /* (1) */ -# define X509v3_KU_KEY_ENCIPHERMENT 0x0020 /* (2) */ -# define X509v3_KU_DATA_ENCIPHERMENT 0x0010 /* (3) */ -# define X509v3_KU_KEY_AGREEMENT 0x0008 /* (4) */ -# define X509v3_KU_KEY_CERT_SIGN 0x0004 /* (5) */ -# define X509v3_KU_CRL_SIGN 0x0002 /* (6) */ -# define X509v3_KU_ENCIPHER_ONLY 0x0001 /* (7) */ -# define X509v3_KU_DECIPHER_ONLY 0x8000 /* (8) */ -# ifndef OPENSSL_NO_DEPRECATED_3_4 -# define X509v3_KU_UNDEF 0xffff /* vestigial, not used */ -# endif +# define X509v3_KU_DIGITAL_SIGNATURE 0x0080 +# define X509v3_KU_NON_REPUDIATION 0x0040 +# define X509v3_KU_KEY_ENCIPHERMENT 0x0020 +# define X509v3_KU_DATA_ENCIPHERMENT 0x0010 +# define X509v3_KU_KEY_AGREEMENT 0x0008 +# define X509v3_KU_KEY_CERT_SIGN 0x0004 +# define X509v3_KU_CRL_SIGN 0x0002 +# define X509v3_KU_ENCIPHER_ONLY 0x0001 +# define X509v3_KU_DECIPHER_ONLY 0x8000 +# define X509v3_KU_UNDEF 0xffff struct X509_algor_st { ASN1_OBJECT *algorithm; diff --git a/vendor/openssl/include/openssl/x509_acert.h.in b/vendor/openssl/include/openssl/x509_acert.h.in index 42376a6..70facf8 100644 --- a/vendor/openssl/include/openssl/x509_acert.h.in +++ b/vendor/openssl/include/openssl/x509_acert.h.in @@ -153,4 +153,40 @@ int OSSL_IETF_ATTR_SYNTAX_add1_value(OSSL_IETF_ATTR_SYNTAX *a, int type, void *data); int OSSL_IETF_ATTR_SYNTAX_print(BIO *bp, OSSL_IETF_ATTR_SYNTAX *a, int indent); +struct TARGET_CERT_st { + OSSL_ISSUER_SERIAL *targetCertificate; + GENERAL_NAME *targetName; + OSSL_OBJECT_DIGEST_INFO *certDigestInfo; +}; + +typedef struct TARGET_CERT_st OSSL_TARGET_CERT; + +# define OSSL_TGT_TARGET_NAME 0 +# define OSSL_TGT_TARGET_GROUP 1 +# define OSSL_TGT_TARGET_CERT 2 + +typedef struct TARGET_st { + int type; + union { + GENERAL_NAME *targetName; + GENERAL_NAME *targetGroup; + OSSL_TARGET_CERT *targetCert; + } choice; +} OSSL_TARGET; + +typedef STACK_OF(OSSL_TARGET) OSSL_TARGETS; +typedef STACK_OF(OSSL_TARGETS) OSSL_TARGETING_INFORMATION; + +{- + generate_stack_macros("OSSL_TARGET"); +-} + +{- + generate_stack_macros("OSSL_TARGETS"); +-} + +DECLARE_ASN1_FUNCTIONS(OSSL_TARGET) +DECLARE_ASN1_FUNCTIONS(OSSL_TARGETS) +DECLARE_ASN1_FUNCTIONS(OSSL_TARGETING_INFORMATION) + #endif diff --git a/vendor/openssl/include/openssl/x509v3.h.in b/vendor/openssl/include/openssl/x509v3.h.in index a967064..5696803 100644 --- a/vendor/openssl/include/openssl/x509v3.h.in +++ b/vendor/openssl/include/openssl/x509v3.h.in @@ -178,8 +178,6 @@ typedef struct ACCESS_DESCRIPTION_st { GENERAL_NAME *location; } ACCESS_DESCRIPTION; -int GENERAL_NAME_set1_X509_NAME(GENERAL_NAME **tgt, const X509_NAME *src); - {- generate_stack_macros("ACCESS_DESCRIPTION") .generate_stack_macros("GENERAL_NAME"); @@ -203,7 +201,6 @@ typedef struct DIST_POINT_NAME_st { /* If relativename then this contains the full distribution point name */ X509_NAME *dpname; } DIST_POINT_NAME; -DECLARE_ASN1_DUP_FUNCTION(DIST_POINT_NAME) /* All existing reasons */ # define CRLDP_ALL_REASONS 0x807f @@ -425,16 +422,15 @@ struct ISSUING_DIST_POINT_st { # define EXFLAG_SAN_CRITICAL 0x80000 # define EXFLAG_NO_FINGERPRINT 0x100000 -/* https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 */ -# define KU_DIGITAL_SIGNATURE X509v3_KU_DIGITAL_SIGNATURE -# define KU_NON_REPUDIATION X509v3_KU_NON_REPUDIATION -# define KU_KEY_ENCIPHERMENT X509v3_KU_KEY_ENCIPHERMENT -# define KU_DATA_ENCIPHERMENT X509v3_KU_DATA_ENCIPHERMENT -# define KU_KEY_AGREEMENT X509v3_KU_KEY_AGREEMENT -# define KU_KEY_CERT_SIGN X509v3_KU_KEY_CERT_SIGN -# define KU_CRL_SIGN X509v3_KU_CRL_SIGN -# define KU_ENCIPHER_ONLY X509v3_KU_ENCIPHER_ONLY -# define KU_DECIPHER_ONLY X509v3_KU_DECIPHER_ONLY +# define KU_DIGITAL_SIGNATURE 0x0080 +# define KU_NON_REPUDIATION 0x0040 +# define KU_KEY_ENCIPHERMENT 0x0020 +# define KU_DATA_ENCIPHERMENT 0x0010 +# define KU_KEY_AGREEMENT 0x0008 +# define KU_KEY_CERT_SIGN 0x0004 +# define KU_CRL_SIGN 0x0002 +# define KU_ENCIPHER_ONLY 0x0001 +# define KU_DECIPHER_ONLY 0x8000 # define NS_SSL_CLIENT 0x80 # define NS_SSL_SERVER 0x40 diff --git a/vendor/secp256k1/include/secp256k1/secp256k1_ellswift.h b/vendor/secp256k1/include/secp256k1/secp256k1_ellswift.h new file mode 100644 index 0000000..ae37287 --- /dev/null +++ b/vendor/secp256k1/include/secp256k1/secp256k1_ellswift.h @@ -0,0 +1,200 @@ +#ifndef SECP256K1_ELLSWIFT_H +#define SECP256K1_ELLSWIFT_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* This module provides an implementation of ElligatorSwift as well as a + * version of x-only ECDH using it (including compatibility with BIP324). + * + * ElligatorSwift is described in https://eprint.iacr.org/2022/759 by + * Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding + * uniformly chosen public keys as 64-byte arrays which are indistinguishable + * from uniformly random arrays. + * + * Let f be the function from pairs of field elements to point X coordinates, + * defined as follows (all operations modulo p = 2^256 - 2^32 - 977) + * f(u,t): + * - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852, + * a square root of -3. + * - If u=0, set u=1 instead. + * - If t=0, set t=1 instead. + * - If u^3 + t^2 + 7 = 0, multiply t by 2. + * - Let X = (u^3 + 7 - t^2) / (2 * t) + * - Let Y = (X + t) / (C * u) + * - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an + * X coordinate on the curve (at least one of them is, for any u and t). + * + * Then an ElligatorSwift encoding of x consists of the 32-byte big-endian + * encodings of field elements u and t concatenated, where f(u,t) = x. + * The encoding algorithm is described in the paper, and effectively picks a + * uniformly random pair (u,t) among those which encode x. + * + * If the Y coordinate is relevant, it is given the same parity as t. + * + * Changes w.r.t. the the paper: + * - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point + * at infinity in the paper. Here they are remapped to finite points. + * - The paper uses an additional encoding bit for the parity of y. Here the + * parity of t is used (negating t does not affect the decoded x coordinate, + * so this is possible). + * + * For mathematical background about the scheme, see the doc/ellswift.md file. + */ + +/** A pointer to a function used by secp256k1_ellswift_xdh to hash the shared X + * coordinate along with the encoded public keys to a uniform shared secret. + * + * Returns: 1 if a shared secret was successfully computed. + * 0 will cause secp256k1_ellswift_xdh to fail and return 0. + * Other return values are not allowed, and the behaviour of + * secp256k1_ellswift_xdh is undefined for other return values. + * Out: output: pointer to an array to be filled by the function + * In: x32: pointer to the 32-byte serialized X coordinate + * of the resulting shared point (will not be NULL) + * ell_a64: pointer to the 64-byte encoded public key of party A + * (will not be NULL) + * ell_b64: pointer to the 64-byte encoded public key of party B + * (will not be NULL) + * data: arbitrary data pointer that is passed through + */ +typedef int (*secp256k1_ellswift_xdh_hash_function)( + unsigned char *output, + const unsigned char *x32, + const unsigned char *ell_a64, + const unsigned char *ell_b64, + void *data +); + +/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses + * SHA256(prefix64 || ell_a64 || ell_b64 || x32), where prefix64 is the 64-byte + * array pointed to by data. */ +SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix; + +/** An implementation of an secp256k1_ellswift_xdh_hash_function compatible with + * BIP324. It returns H_tag(ell_a64 || ell_b64 || x32), where H_tag is the + * BIP340 tagged hash function with tag "bip324_ellswift_xonly_ecdh". Equivalent + * to secp256k1_ellswift_xdh_hash_function_prefix with prefix64 set to + * SHA256("bip324_ellswift_xonly_ecdh")||SHA256("bip324_ellswift_xonly_ecdh"). + * The data argument is ignored. */ +SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324; + +/** Construct a 64-byte ElligatorSwift encoding of a given pubkey. + * + * Returns: 1 always. + * Args: ctx: pointer to a context object + * Out: ell64: pointer to a 64-byte array to be filled + * In: pubkey: pointer to a secp256k1_pubkey containing an + * initialized public key + * rnd32: pointer to 32 bytes of randomness + * + * It is recommended that rnd32 consists of 32 uniformly random bytes, not + * known to any adversary trying to detect whether public keys are being + * encoded, though 16 bytes of randomness (padded to an array of 32 bytes, + * e.g., with zeros) suffice to make the result indistinguishable from + * uniform. The randomness in rnd32 must not be a deterministic function of + * the pubkey (it can be derived from the private key, though). + * + * It is not guaranteed that the computed encoding is stable across versions + * of the library, even if all arguments to this function (including rnd32) + * are the same. + * + * This function runs in variable time. + */ +SECP256K1_API int secp256k1_ellswift_encode( + const secp256k1_context *ctx, + unsigned char *ell64, + const secp256k1_pubkey *pubkey, + const unsigned char *rnd32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Decode a 64-bytes ElligatorSwift encoded public key. + * + * Returns: always 1 + * Args: ctx: pointer to a context object + * Out: pubkey: pointer to a secp256k1_pubkey that will be filled + * In: ell64: pointer to a 64-byte array to decode + * + * This function runs in variable time. + */ +SECP256K1_API int secp256k1_ellswift_decode( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, + const unsigned char *ell64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Compute an ElligatorSwift public key for a secret key. + * + * Returns: 1: secret was valid, public key was stored. + * 0: secret was invalid, try again. + * Args: ctx: pointer to a context object + * Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift + * public key + * In: seckey32: pointer to a 32-byte secret key + * auxrnd32: (optional) pointer to 32 bytes of randomness + * + * Constant time in seckey and auxrnd32, but not in the resulting public key. + * + * It is recommended that auxrnd32 contains 32 uniformly random bytes, though + * it is optional (and does result in encodings that are indistinguishable from + * uniform even without any auxrnd32). It differs from the (mandatory) rnd32 + * argument to secp256k1_ellswift_encode in this regard. + * + * This function can be used instead of calling secp256k1_ec_pubkey_create + * followed by secp256k1_ellswift_encode. It is safer, as it uses the secret + * key as entropy for the encoding (supplemented with auxrnd32, if provided). + * + * Like secp256k1_ellswift_encode, this function does not guarantee that the + * computed encoding is stable across versions of the library, even if all + * arguments (including auxrnd32) are the same. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create( + const secp256k1_context *ctx, + unsigned char *ell64, + const unsigned char *seckey32, + const unsigned char *auxrnd32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Given a private key, and ElligatorSwift public keys sent in both directions, + * compute a shared secret using x-only Elliptic Curve Diffie-Hellman (ECDH). + * + * Returns: 1: shared secret was successfully computed + * 0: secret was invalid or hashfp returned 0 + * Args: ctx: pointer to a context object. + * Out: output: pointer to an array to be filled by hashfp. + * In: ell_a64: pointer to the 64-byte encoded public key of party A + * (will not be NULL) + * ell_b64: pointer to the 64-byte encoded public key of party B + * (will not be NULL) + * seckey32: pointer to our 32-byte secret key + * party: boolean indicating which party we are: zero if we are + * party A, non-zero if we are party B. seckey32 must be + * the private key corresponding to that party's ell_?64. + * This correspondence is not checked. + * hashfp: pointer to a hash function. + * data: arbitrary data pointer passed through to hashfp. + * + * Constant time in seckey32. + * + * This function is more efficient than decoding the public keys, and performing + * ECDH on them. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh( + const secp256k1_context *ctx, + unsigned char *output, + const unsigned char *ell_a64, + const unsigned char *ell_b64, + const unsigned char *seckey32, + int party, + secp256k1_ellswift_xdh_hash_function hashfp, + void *data +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_ELLSWIFT_H */ diff --git a/vendor/secp256k1/include/secp256k1/secp256k1_recovery.h b/vendor/secp256k1/include/secp256k1/secp256k1_recovery.h new file mode 100644 index 0000000..341b8ba --- /dev/null +++ b/vendor/secp256k1/include/secp256k1/secp256k1_recovery.h @@ -0,0 +1,113 @@ +#ifndef SECP256K1_RECOVERY_H +#define SECP256K1_RECOVERY_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Opaque data structured that holds a parsed ECDSA signature, + * supporting pubkey recovery. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 65 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, use + * the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_parse_* functions. + * + * Furthermore, it is guaranteed that identical signatures (including their + * recoverability) will have identical representation, so they can be + * memcmp'ed. + */ +typedef struct { + unsigned char data[65]; +} secp256k1_ecdsa_recoverable_signature; + +/** Parse a compact ECDSA signature (64 bytes + recovery id). + * + * Returns: 1 when the signature could be parsed, 0 otherwise + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input64: pointer to a 64-byte compact signature + * recid: the recovery id (0, 1, 2 or 3) + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( + const secp256k1_context *ctx, + secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *input64, + int recid +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Convert a recoverable signature into a normal signature. + * + * Returns: 1 + * Args: ctx: pointer to a context object. + * Out: sig: pointer to a normal signature. + * In: sigin: pointer to a recoverable signature. + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( + const secp256k1_context *ctx, + secp256k1_ecdsa_signature *sig, + const secp256k1_ecdsa_recoverable_signature *sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in compact format (64 bytes + recovery id). + * + * Returns: 1 + * Args: ctx: pointer to a context object. + * Out: output64: pointer to a 64-byte array of the compact signature. + * recid: pointer to an integer to hold the recovery id. + * In: sig: pointer to an initialized signature object. + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( + const secp256k1_context *ctx, + unsigned char *output64, + int *recid, + const secp256k1_ecdsa_recoverable_signature *sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Create a recoverable ECDSA signature. + * + * Returns: 1: signature created + * 0: the nonce generation function failed, or the secret key was invalid. + * Args: ctx: pointer to a context object (not secp256k1_context_static). + * Out: sig: pointer to an array where the signature will be placed. + * In: msghash32: the 32-byte message hash being signed. + * seckey: pointer to a 32-byte secret key. + * noncefp: pointer to a nonce generation function. If NULL, + * secp256k1_nonce_function_default is used. + * ndata: pointer to arbitrary data used by the nonce generation function + * (can be NULL for secp256k1_nonce_function_default). + */ +SECP256K1_API int secp256k1_ecdsa_sign_recoverable( + const secp256k1_context *ctx, + secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msghash32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Recover an ECDSA public key from a signature. + * + * Returns: 1: public key successfully recovered (which guarantees a correct signature). + * 0: otherwise. + * Args: ctx: pointer to a context object. + * Out: pubkey: pointer to the recovered public key. + * In: sig: pointer to initialized signature that supports pubkey recovery. + * msghash32: the 32-byte message hash assumed to be signed. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( + const secp256k1_context *ctx, + secp256k1_pubkey *pubkey, + const secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msghash32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_RECOVERY_H */ |