aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--include/signer/noscrypt_signer.hpp16
-rw-r--r--src/cryptography/noscrypt_cipher.cpp109
-rw-r--r--src/cryptography/noscrypt_cipher.hpp (renamed from include/cryptography/noscrypt_cipher.hpp)68
-rw-r--r--src/cryptography/nostr_secure_rng.cpp46
-rw-r--r--src/cryptography/nostr_secure_rng.hpp51
-rw-r--r--src/internal/noscrypt_logger.hpp43
-rw-r--r--src/signer/noscrypt_signer.cpp273
8 files changed, 325 insertions, 285 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b875512..889f19d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,7 +59,7 @@ include_directories(${uuid_v4_SOURCE_DIR})
FetchContent_Declare(
libnoscrypt
GIT_REPOSITORY git@github.com:VnUgE/noscrypt.git
- GIT_TAG fb3608b9455b3e0956e401e6254da13cebd71558
+ GIT_TAG v0.1.5
)
FetchContent_MakeAvailable(libnoscrypt)
@@ -86,7 +86,6 @@ set(HEADERS
${INCLUDE_DIR}/nostr.hpp
${CLIENT_INCLUDE_DIR}/web_socket_client.hpp
${CLIENT_INCLUDE_DIR}/websocketpp_client.hpp
- ${CRYPTOGRAPHY_INCLUDE_DIR}/noscrypt_cipher.hpp
${DATA_INCLUDE_DIR}/data.hpp
${SERVICE_INCLUDE_DIR}/nostr_service_base.hpp
${SIGNER_INCLUDE_DIR}/signer.hpp
@@ -102,6 +101,7 @@ set(SIGNER_SOURCE_DIR ./src/signer)
set(SOURCES
${CLIENT_SOURCE_DIR}/websocketpp_client.cpp
${CRYPTOGRAPHY_SOURCE_DIR}/noscrypt_cipher.cpp
+ ${CRYPTOGRAPHY_SOURCE_DIR}/nostr_secure_rng.cpp
${DATA_SOURCE_DIR}/event.cpp
${DATA_SOURCE_DIR}/filters.cpp
${SERVICE_SOURCE_DIR}/nostr_service_base.cpp
diff --git a/include/signer/noscrypt_signer.hpp b/include/signer/noscrypt_signer.hpp
index 85188fa..0a7d0fd 100644
--- a/include/signer/noscrypt_signer.hpp
+++ b/include/signer/noscrypt_signer.hpp
@@ -146,12 +146,6 @@ private:
#pragma region Cryptography
/**
- * @brief Reseeds OpenSSL's pseudo-random number generator, using `/dev/random` as the seed, if
- * possible.
- */
- void _reseedRandomNumberGenerator(uint32_t bufferSize = 32);
-
- /**
* @brief Encrypts a string according to the standard specified in NIP-04.
* @param input The string to be encrypted.
* @return The resulting encrypted string, or an empty string if the input could not be
@@ -182,16 +176,6 @@ private:
std::string _decryptNip44(const std::string input);
#pragma endregion
-
- #pragma region Logging
-
- inline void _logNoscryptInitResult(NCResult initResult) const;
-
- inline void _logNoscryptSecretValidationResult(NCResult secretValidationResult) const;
-
- inline void _logNoscryptPubkeyGenerationResult(NCResult pubkeyGenerationResult) const;
-
- #pragma endregion
};
} // namespace signer
} // namespace nostr
diff --git a/src/cryptography/noscrypt_cipher.cpp b/src/cryptography/noscrypt_cipher.cpp
index ae9aaf0..2d5d671 100644
--- a/src/cryptography/noscrypt_cipher.cpp
+++ b/src/cryptography/noscrypt_cipher.cpp
@@ -2,49 +2,16 @@
#include <plog/Log.h>
#include <openssl/evp.h>
-#include <openssl/rand.h>
-#include "cryptography/noscrypt_cipher.hpp"
+#include "nostr_secure_rng.hpp"
+#include "noscrypt_cipher.hpp"
+#include "../internal/noscrypt_logger.hpp"
-using namespace nostr::cryptography;
using namespace std;
+using namespace nostr::cryptography;
-static void _printNoscryptError(NCResult result, const std::string funcName, int lineNum)
-{
- uint8_t argPosition;
-
- switch (NCParseErrorCode(result, &argPosition))
- {
- case E_NULL_PTR:
- PLOG_ERROR << "noscrypt - error: A null pointer was passed in " << funcName << "(" << argPosition << ") at line " << lineNum;
- break;
-
- case E_INVALID_ARG:
- PLOG_ERROR << "noscrypt - error: An invalid argument was passed in " << funcName << "(" << argPosition << ") at line " << lineNum;
- break;
-
- case E_INVALID_CONTEXT:
- PLOG_ERROR << "noscrypt - error: An invalid context was passed in " << funcName << "(" << argPosition << ") on line " << lineNum;
- break;
-
- case E_ARGUMENT_OUT_OF_RANGE:
- PLOG_ERROR << "noscrypt - error: An argument was out of range in " << funcName << "(" << argPosition << ") at line " << lineNum;
- break;
-
- case E_OPERATION_FAILED:
- PLOG_ERROR << "noscrypt - error: An operation failed in " << funcName << "(" << argPosition << ") at line " << lineNum;
- break;
-
- default:
- PLOG_ERROR << "noscrypt - error: An unknown error " << result << " occurred in " << funcName << "(" << argPosition << ") at line " << lineNum;
- break;
- }
-
-}
-
-#define LOG_NC_ERROR(result) _printNoscryptError(result, __func__, __LINE__)
-NoscryptCipher::NoscryptCipher(uint32_t version, uint32_t mode) :
+NoscryptCipher::NoscryptCipher(NoscryptCipherVersion version, NoscryptCipherMode mode) :
_cipher(version, mode)
{
/*
@@ -54,7 +21,7 @@ NoscryptCipher::NoscryptCipher(uint32_t version, uint32_t mode) :
* operation.
*/
- if ((mode & NC_UTIL_CIPHER_MODE) == NC_UTIL_CIPHER_MODE_ENCRYPT)
+ if (mode == NoscryptCipherMode::CIPHER_MODE_ENCRYPT)
{
//Resize the vector to the size of the current cipher
this->_ivBuffer.resize(this->_cipher.ivSize());
@@ -82,10 +49,10 @@ std::string NoscryptCipher::update(
//Safely convert the string to a vector of bytes (allocates and copies, so maybe speed up later)
const vector<uint8_t> inputBuffer(input.begin(), input.end());
-result = this->_cipher.setInput(inputBuffer);
+ result = this->_cipher.setInput(inputBuffer);
if (result != NC_SUCCESS)
{
- LOG_NC_ERROR(result);
+ NC_LOG_ERROR(result);
return string();
}
@@ -97,25 +64,17 @@ result = this->_cipher.setInput(inputBuffer);
* Keep in mind, this will automatically work for nip44 and nip04, either the
* AES iv or the ChaCha nonce.
*/
- if ((this->_cipher.flags() & NC_UTIL_CIPHER_MODE) == NC_UTIL_CIPHER_MODE_ENCRYPT)
+ if (this->_cipher.mode() == NoscryptCipherMode::CIPHER_MODE_ENCRYPT)
{
- int code = RAND_bytes(
- this->_ivBuffer.data(),
- this->_ivBuffer.size() //Size set in constructor
- );
-
- if (code <= 0)
- {
- PLOG_ERROR << "Failed to generate a nonce or IV for encryption.";
- return string();
- }
+ //A secure random initialization vector is needed for encryption operations
+ NostrSecureRng::fill(this->_ivBuffer);
}
//Performs the operation (either encryption or decryption)
result = this->_cipher.update(libContext, localKey, remoteKey);
if (result != NC_SUCCESS)
{
- LOG_NC_ERROR(result);
+ NC_LOG_ERROR(result);
return string();
}
@@ -127,7 +86,7 @@ result = this->_cipher.setInput(inputBuffer);
NCResult outputSize = this->_cipher.outputSize();
if (outputSize <= 0)
{
- LOG_NC_ERROR(outputSize);
+ NC_LOG_ERROR(outputSize);
return string();
}
@@ -137,7 +96,7 @@ result = this->_cipher.setInput(inputBuffer);
result = this->_cipher.readOutput(output);
if (result != outputSize)
{
- LOG_NC_ERROR(result);
+ NC_LOG_ERROR(result);
return string();
}
@@ -148,36 +107,40 @@ string NoscryptCipher::naiveEncodeBase64(const std::string& str)
{
// Compute base64 size and allocate a string buffer of that size.
const size_t encodedSize = NoscryptCipher::base64EncodedSize(str.size());
- unsigned char* encodedData = new unsigned char[encodedSize];
+
+ auto encodedData = make_unique<uint8_t>(encodedSize);
// Encode the input string to base64.
- EVP_EncodeBlock(encodedData, (const unsigned char*)str.data(), str.size());
+ EVP_EncodeBlock(
+ encodedData.get(),
+ reinterpret_cast<const uint8_t*>(str.c_str()),
+ str.size()
+ );
// Construct the encoded string from the buffer.
- string encodedStr((char*)encodedData);
-
- // Zero out the buffer and delete the pointer.
- memset(encodedData, 0, encodedSize);
- delete [] encodedData;
-
- return encodedStr;
+ return string(
+ reinterpret_cast<char*>(encodedData.get()),
+ encodedSize
+ );
}
string NoscryptCipher::naiveDecodeBase64(const string& str)
{
// Compute the size of the decoded string and allocate a buffer of that size.
const size_t decodedSize = NoscryptCipher::base64DecodedSize(str.size());
- unsigned char* decodedData = new unsigned char[decodedSize];
+
+ auto decodedData = make_unique<uint8_t>(decodedSize);
// Decode the input string from base64.
- EVP_DecodeBlock(decodedData, (const unsigned char*)str.data(), str.size());
+ EVP_DecodeBlock(
+ decodedData.get(),
+ reinterpret_cast<const uint8_t*>(str.c_str()),
+ str.size()
+ );
// Construct the decoded string from the buffer.
- string decodedStr((char*)decodedData);
-
- // Zero out the buffer and delete the pointer.
- memset(decodedData, 0, decodedSize);
- delete [] decodedData;
-
- return decodedStr;
+ return string(
+ reinterpret_cast<char*>(decodedData.get()),
+ decodedSize
+ );
};
diff --git a/include/cryptography/noscrypt_cipher.hpp b/src/cryptography/noscrypt_cipher.hpp
index 3337240..04bdbf2 100644
--- a/include/cryptography/noscrypt_cipher.hpp
+++ b/src/cryptography/noscrypt_cipher.hpp
@@ -4,11 +4,25 @@
#include <noscrypt.h>
#include <noscryptutil.h>
+#include "../internal/noscrypt_logger.hpp"
namespace nostr
{
namespace cryptography
{
+
+enum NoscryptCipherMode : uint32_t
+{
+ CIPHER_MODE_ENCRYPT = NC_UTIL_CIPHER_MODE_ENCRYPT,
+ CIPHER_MODE_DECRYPT = NC_UTIL_CIPHER_MODE_DECRYPT,
+};
+
+enum NoscryptCipherVersion : uint32_t
+{
+ NIP04 = NC_ENC_VERSION_NIP04,
+ NIP44 = NC_ENC_VERSION_NIP44,
+};
+
class NoscryptCipherContext
{
private:
@@ -16,30 +30,30 @@ private:
public:
- NoscryptCipherContext(uint32_t version, uint32_t mode)
+ NoscryptCipherContext(NoscryptCipherVersion version, NoscryptCipherMode mode)
{
- /*
- * Create a new cipher context with the specified
- * version and mode that will live for the duration of the
- * instance.
- *
- * The user is expected to use the noscryptutil mode for
- * setting encryption/decryption modes.
- *
- * The cipher will zero out the memory when it is freed.
- *
- * For decryption, by default the mac is verified before
- * decryption occurs.
- *
- * NOTE: The ciper is set to reusable mode, so encrypt/decrypt
- * can be called multiple times although it's not recommended,
- * its just the more predictable way for users to handle it.
- */
-
- _cipher = NCUtilCipherAlloc(
- version,
- mode | NC_UTIL_CIPHER_ZERO_ON_FREE | NC_UTIL_CIPHER_REUSEABLE
- );
+ /*
+ * Create a new cipher context with the specified
+ * version and mode that will live for the duration of the
+ * instance.
+ *
+ * The user is expected to use the noscryptutil mode for
+ * setting encryption/decryption modes.
+ *
+ * The cipher will zero out the memory when it is freed.
+ *
+ * For decryption, by default the mac is verified before
+ * decryption occurs.
+ *
+ * NOTE: The ciper is set to reusable mode, so encrypt/decrypt
+ * can be called multiple times although it's not recommended,
+ * its just the more predictable way for users to handle it.
+ */
+
+ _cipher = NCUtilCipherAlloc(
+ (uint32_t)version,
+ ((uint32_t)mode) | NC_UTIL_CIPHER_ZERO_ON_FREE | NC_UTIL_CIPHER_REUSEABLE
+ );
//TODO, may fail to allocate memory.
}
@@ -95,6 +109,12 @@ public:
return (uint32_t)result;
}
+ NoscryptCipherMode mode() const
+ {
+ //Mode bit is lsb so just mask off the rest of the flags and convert back to enum
+ return (NoscryptCipherMode)(flags() & NC_UTIL_CIPHER_MODE);
+ }
+
NCResult readOutput(std::vector<uint8_t>& output) const
{
return NCUtilCipherReadOutput(_cipher, output.data(), (uint32_t)output.size());
@@ -125,7 +145,7 @@ private:
std::vector<uint8_t> _ivBuffer;
public:
- NoscryptCipher(uint32_t version, uint32_t mode);
+ NoscryptCipher(NoscryptCipherVersion version, NoscryptCipherMode mode);
/*
* @brief Performs the cipher operation on the input data. Depending on the mode
diff --git a/src/cryptography/nostr_secure_rng.cpp b/src/cryptography/nostr_secure_rng.cpp
new file mode 100644
index 0000000..9d92514
--- /dev/null
+++ b/src/cryptography/nostr_secure_rng.cpp
@@ -0,0 +1,46 @@
+#include <plog/Init.h>
+#include <plog/Log.h>
+
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/crypto.h>
+
+#include "nostr_secure_rng.hpp"
+
+using namespace std;
+using namespace nostr::cryptography;
+
+void NostrSecureRng::fill(void* buffer, size_t length)
+{
+ if (RAND_bytes((uint8_t*)buffer, length) != 1)
+ {
+ //TODO throw runtime exception
+ PLOG_ERROR << "Failed to generate random bytes";
+ }
+}
+
+inline void NostrSecureRng::fill(vector<uint8_t>& buffer)
+{
+ fill(buffer.data(), buffer.size());
+}
+
+void NostrSecureRng::reseed(uint32_t bufferSize)
+{
+ int rc = RAND_load_file("/dev/random", bufferSize);
+
+ if (rc != bufferSize)
+ {
+ PLOG_WARNING << "Failed to reseed the RNG with /dev/random, falling back to /dev/urandom.";
+ RAND_poll();
+ }
+}
+
+void NostrSecureRng::zero(void* buffer, size_t length)
+{
+ OPENSSL_cleanse(buffer, length);
+}
+
+inline void NostrSecureRng::zero(vector<uint8_t>& buffer)
+{
+ zero(buffer.data(), buffer.size());
+} \ No newline at end of file
diff --git a/src/cryptography/nostr_secure_rng.hpp b/src/cryptography/nostr_secure_rng.hpp
new file mode 100644
index 0000000..7fa340e
--- /dev/null
+++ b/src/cryptography/nostr_secure_rng.hpp
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <memory>
+
+namespace nostr
+{
+namespace cryptography
+{
+
+class NostrSecureRng
+{
+private:
+
+public:
+
+ /**
+ * @brief Fills the given buffer with secure random bytes.
+ * @param buffer The buffer to fill with random bytes.
+ * @param length The number of bytes to fill.
+ */
+ static void fill(void* buffer, size_t length);
+
+ /*
+ * @brief Fills the given vector with secure random bytes.
+ * @param buffer The vector to fill with random bytes.
+ */
+ static inline void fill(std::vector<uint8_t>& buffer);
+
+ /*
+ * @brief Reseeds the RNG with random bytes from /dev/random.
+ * @param bufferSize The number of bytes to read from /dev/random.
+ * @remark Falls back to /dev/urandom if /dev/random is not available.
+ */
+ static void reseed(uint32_t bufferSize = 32);
+
+ /*
+ * @brief Securley zeroes out the given buffer.
+ * @param buffer A pointer to the buffer to zero out.
+ * @param length The number of bytes to zero out.
+ */
+ static void zero(void* buffer, size_t length);
+
+ /*
+ * @brief Securley zeroes out the given vector.
+ * @param buffer The vector to zero out.
+ */
+ static inline void zero(std::vector<uint8_t>& buffer);
+};
+
+} // namespace cryptography
+} // namespace nostr
diff --git a/src/internal/noscrypt_logger.hpp b/src/internal/noscrypt_logger.hpp
new file mode 100644
index 0000000..b767b81
--- /dev/null
+++ b/src/internal/noscrypt_logger.hpp
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <plog/Log.h>
+#include <noscrypt.h>
+
+/*
+* @brief Logs an error message with the function name and line number where the
+* error occurred. This is useful for debugging and logging errors in the Noscrypt
+* library.
+*/
+#define NC_LOG_ERROR(result) _printNoscryptError(result, __func__, __LINE__)
+
+static inline void _printNoscryptError(NCResult result, const std::string funcName, int lineNum)
+{
+ uint8_t argPosition;
+
+ switch (NCParseErrorCode(result, &argPosition))
+ {
+ case E_NULL_PTR:
+ PLOG_ERROR << "noscrypt - error: A null pointer was passed in " << funcName << "(" << argPosition << ") at line " << lineNum;
+ break;
+
+ case E_INVALID_ARG:
+ PLOG_ERROR << "noscrypt - error: An invalid argument was passed in " << funcName << "(" << argPosition << ") at line " << lineNum;
+ break;
+
+ case E_INVALID_CONTEXT:
+ PLOG_ERROR << "noscrypt - error: An invalid context was passed in " << funcName << "(" << argPosition << ") on line " << lineNum;
+ break;
+
+ case E_ARGUMENT_OUT_OF_RANGE:
+ PLOG_ERROR << "noscrypt - error: An argument was out of range in " << funcName << "(" << argPosition << ") at line " << lineNum;
+ break;
+
+ case E_OPERATION_FAILED:
+ PLOG_ERROR << "noscrypt - error: An operation failed in " << funcName << "(" << argPosition << ") at line " << lineNum;
+ break;
+
+ default:
+ PLOG_ERROR << "noscrypt - error: An unknown error " << result << " occurred in " << funcName << "(" << argPosition << ") at line " << lineNum;
+ break;
+ }
+}
diff --git a/src/signer/noscrypt_signer.cpp b/src/signer/noscrypt_signer.cpp
index 2b87703..d12bd44 100644
--- a/src/signer/noscrypt_signer.cpp
+++ b/src/signer/noscrypt_signer.cpp
@@ -2,23 +2,87 @@
#include <chrono>
#include <cstring>
#include <memory>
-#include <random>
#include <sstream>
#include <tuple>
#include <nlohmann/json.hpp>
-#include <openssl/err.h>
-#include <openssl/rand.h>
#include <uuid_v4.h>
#include "signer/noscrypt_signer.hpp"
-#include "noscrypt_cipher.hpp"
+#include "../cryptography/nostr_secure_rng.hpp"
+#include "../cryptography/noscrypt_cipher.hpp"
+#include "../internal/noscrypt_logger.hpp"
+using namespace std;
using namespace nostr::data;
using namespace nostr::service;
using namespace nostr::signer;
using namespace nostr::cryptography;
-using namespace std;
+
+#pragma region Local Statics
+
+static shared_ptr<NCContext> ncAllocContext()
+{
+ /*
+ * Use the utilties library to allocate a new Noscrypt context.
+ * Shared pointer will call free when smart pointer is destroyed
+ */
+
+ return shared_ptr<NCContext>(
+ NCUtilContextAlloc(),
+ &NCUtilContextFree
+ );
+}
+
+static shared_ptr<NCContext> initNoscryptContext()
+{
+ //Use helper to allocate a dynamic sized shared pointer
+ auto ctx = ncAllocContext();
+
+ auto randomEntropy = make_unique<uint8_t>(NC_CONTEXT_ENTROPY_SIZE);
+ NostrSecureRng::fill(randomEntropy.get(), NC_CONTEXT_ENTROPY_SIZE);
+
+ NCResult initResult = NCInitContext(ctx.get(), randomEntropy.get());
+
+ NC_LOG_ERROR(initResult);
+
+ return ctx;
+};
+
+/**
+ * @brief Generates a private/public key pair for local use.
+ * @returns The generated keypair of the form `[privateKey, publicKey]`, or a pair of empty
+ * strings if the function failed.
+ * @remarks This keypair is intended for temporary use, and should not be saved or used outside
+ * of this class.
+ */
+static void createLocalKeypair(
+ const shared_ptr<const NCContext> ctx,
+ shared_ptr<NCSecretKey> secret,
+ shared_ptr<NCPublicKey> pubkey
+)
+{
+ // Loop attempts to generate a secret key until a valid key is produced.
+ // Limit the number of attempts to prevent resource exhaustion in the event of a failure.
+ NCResult secretValidationResult;
+ int loopCount = 0;
+ do
+ {
+ NostrSecureRng::fill(secret.get(), sizeof(NCSecretKey));
+
+ secretValidationResult = NCValidateSecretKey(ctx.get(), secret.get());
+
+ } while (secretValidationResult != NC_SUCCESS && ++loopCount < 64);
+
+ NC_LOG_ERROR(secretValidationResult);
+
+ // Use noscrypt to derive the public key from its private counterpart.
+ NCResult pubkeyGenerationResult = NCGetPublicKey(ctx.get(), secret.get(), pubkey.get());
+
+ NC_LOG_ERROR(pubkeyGenerationResult);
+};
+
+#pragma endregion
#pragma region Constructors and Destructors
@@ -28,9 +92,13 @@ NoscryptSigner::NoscryptSigner(
{
plog::init(plog::debug, appender.get());
- this->_reseedRandomNumberGenerator();
- this->_initNoscryptContext();
- this->_createLocalKeypair();
+ this->_noscryptContext = initNoscryptContext();
+
+ createLocalKeypair(
+ this->_noscryptContext,
+ this->_localPrivateKey,
+ this->_localPublicKey
+ );
this->_nostrService = nostrService;
};
@@ -258,67 +326,6 @@ inline void NoscryptSigner::_setRemotePublicKey(const string value)
#pragma region Setup
-void NoscryptSigner::_initNoscryptContext()
-{
- shared_ptr<NCContext> context;
- auto contextStructSize = NCGetContextStructSize();
- auto randomEntropy = make_unique<uint8_t>(contextStructSize);
-
- random_device rd;
- mt19937 gen(rd());
- uniform_int_distribution<> dist(0, contextStructSize);
- generate_n(randomEntropy.get(), contextStructSize, [&]() { return dist(gen); });
-
- NCResult initResult = NCInitContext(context.get(), randomEntropy.get());
- this->_logNoscryptInitResult(initResult);
-
- this->_noscryptContext = move(context);
-};
-
-/**
- * @brief Generates a private/public key pair for local use.
- * @returns The generated keypair of the form `[privateKey, publicKey]`, or a pair of empty
- * strings if the function failed.
- * @remarks This keypair is intended for temporary use, and should not be saved or used outside
- * of this class.
- */
-void NoscryptSigner::_createLocalKeypair()
-{
- string privateKey;
- string publicKey;
-
- // To generate a private key, all we need is a random 32-bit buffer.
- auto secret = make_unique<NCSecretKey>();
-
- // Loop attempts to generate a secret key until a valid key is produced.
- // Limit the number of attempts to prevent resource exhaustion in the event of a failure.
- NCResult secretValidationResult;
- int loopCount = 0;
- do
- {
- int rc = RAND_bytes(secret->key, sizeof(NCSecretKey));
- if (rc != 1)
- {
- unsigned long err = ERR_get_error();
- PLOG_ERROR << "OpenSSL error " << err << " occurred while generating a secret key.";
- }
-
- secretValidationResult = NCValidateSecretKey(this->_noscryptContext.get(), secret.get());
- } while (secretValidationResult != NC_SUCCESS && ++loopCount < 64);
-
- this->_logNoscryptSecretValidationResult(secretValidationResult);
- this->_localPrivateKey = move(secret);
-
- // Use noscrypt to derive the public key from its private counterpart.
- auto pubkey = make_unique<NCPublicKey>();
- NCResult pubkeyGenerationResult = NCGetPublicKey(
- this->_noscryptContext.get(),
- secret.get(),
- pubkey.get());
- this->_logNoscryptPubkeyGenerationResult(pubkeyGenerationResult);
- this->_localPublicKey = move(pubkey);
-};
-
int NoscryptSigner::_parseRemotePublicKey(string connectionToken)
{
int queryStart = connectionToken.find('?');
@@ -403,35 +410,39 @@ shared_ptr<Event> NoscryptSigner::_wrapSignerMessage(nlohmann::json jrpc)
wrapperEvent->tags.push_back({ "p", this->_getRemotePublicKey() });
wrapperEvent->content = encryptedContent;
- // Generate a random seed for the signer.
- auto random32 = make_shared<uint8_t>(32);
- int code = RAND_bytes(random32.get(), 32);
- if (code <= 0)
- {
- PLOG_ERROR << "Failed to generate a random 32-byte seed buffer for the signer.";
- return nullptr;
- }
+ uint8_t schnorrSig[64];
+ uint8_t random32[32];
+
+ //Secure random signing entropy is required
+ NostrSecureRng::fill(random32, sizeof(random32));
// Sign the wrapper message with the local secret key.
string serializedEvent = wrapperEvent->serialize();
- uint32_t dataSize = serializedEvent.length();
- auto signature = make_unique<uint8_t>(64);
+
NCResult signatureResult = NCSignData(
this->_noscryptContext.get(),
this->_localPrivateKey.get(),
- random32.get(),
- reinterpret_cast<uint8_t*>(serializedEvent.data()),
- dataSize,
- signature.get());
+ random32,
+ reinterpret_cast<const uint8_t*>(serializedEvent.c_str()),
+ serializedEvent.length(),
+ schnorrSig
+ );
+
+ //Random buffer could leak sensitive signing information
+ NostrSecureRng::zero(random32, sizeof(random32));
// TODO: Handle result codes.
if (signatureResult != NC_SUCCESS)
{
+ NC_LOG_ERROR(signatureResult);
return nullptr;
}
// Add the signature to the event.
- wrapperEvent->sig = string((char*)signature.get(), 64);
+ wrapperEvent->sig = string(
+ reinterpret_cast<char*>(schnorrSig),
+ sizeof(schnorrSig)
+ );
return wrapperEvent;
};
@@ -512,16 +523,6 @@ promise<bool> NoscryptSigner::_pingSigner()
#pragma region Cryptography
-void NoscryptSigner::_reseedRandomNumberGenerator(uint32_t bufferSize)
-{
- int rc = RAND_load_file("/dev/random", bufferSize);
- if (rc != bufferSize)
- {
- PLOG_WARNING << "Failed to reseed the RNG with /dev/random, falling back to /dev/urandom.";
- RAND_poll();
- }
-};
-
string NoscryptSigner::_encryptNip04(std::string input)
{
throw runtime_error("NIP-04 encryption is not yet implemented.");
@@ -534,7 +535,10 @@ string NoscryptSigner::_decryptNip04(string input)
string NoscryptSigner::_encryptNip44(string input)
{
- NoscryptCipher cipher = NoscryptCipher(NC_ENC_VERSION_NIP44, NC_UTIL_CIPHER_MODE_ENCRYPT);
+ NoscryptCipher cipher = NoscryptCipher(
+ NoscryptCipherVersion::NIP44,
+ NoscryptCipherMode::CIPHER_MODE_ENCRYPT
+ );
auto output = cipher.update(
this->_noscryptContext,
@@ -552,7 +556,10 @@ string NoscryptSigner::_decryptNip44(string input)
{
//TODO handle input validation as per nip44 spec
- NoscryptCipher cipher = NoscryptCipher(NC_ENC_VERSION_NIP44, NC_UTIL_CIPHER_MODE_DECRYPT);
+ NoscryptCipher cipher = NoscryptCipher(
+ NoscryptCipherVersion::NIP44,
+ NoscryptCipherMode::CIPHER_MODE_DECRYPT
+ );
return cipher.update(
this->_noscryptContext,
@@ -564,77 +571,3 @@ string NoscryptSigner::_decryptNip44(string input)
#pragma endregion
-#pragma region Logging
-
-inline void NoscryptSigner::_logNoscryptInitResult(NCResult initResult) const
-{
- switch (NCParseErrorCode(initResult, NULL)) {
- case NC_SUCCESS:
- PLOG_INFO << "noscrypt - success";
- break;
-
- case E_NULL_PTR:
- PLOG_ERROR << "noscrypt - error: A null pointer was passed to the initializer.";
- break;
-
- case E_INVALID_ARG:
- PLOG_ERROR << "noscrypt - error: An invalid argument was passed to the initializer.";
- break;
-
- case E_INVALID_CONTEXT:
- PLOG_ERROR << "noscrypt - error: The NCContext struct is in an invalid state.";
- break;
-
- case E_ARGUMENT_OUT_OF_RANGE:
- PLOG_ERROR << "noscrypt - error: An initializer argument was outside the range of acceptable values.";
- break;
-
- case E_OPERATION_FAILED:
- PLOG_ERROR << "noscrypt - error";
- break;
- }
-};
-
-inline void NoscryptSigner::_logNoscryptSecretValidationResult(NCResult secretValidationResult) const
-{
- if (NCParseErrorCode(secretValidationResult, NULL) == NC_SUCCESS)
- {
- PLOG_INFO << "noscrypt_signer - success: Generated a valid secret key.";
- }
- else
- {
- PLOG_ERROR << "noscrypt_signer - error: Failed to generate a valid secret key.";
- }
-};
-
-inline void NoscryptSigner::_logNoscryptPubkeyGenerationResult(NCResult pubkeyGenerationResult) const
-{
-
- switch (NCParseErrorCode(pubkeyGenerationResult, NULL)) {
- case NC_SUCCESS:
- PLOG_INFO << "noscrypt - success: Generated a valid public key.";
- break;
-
- case E_NULL_PTR:
- PLOG_ERROR << "noscrypt - error: A null pointer was passed to the public key generation function.";
- break;
-
- case E_INVALID_ARG:
- PLOG_ERROR << "noscrypt - error: An invalid argument was passed to the public key generation function.";
- break;
-
- case E_INVALID_CONTEXT:
- PLOG_ERROR << "noscrypt - error: The NCContext struct is in an invalid state.";
- break;
-
- case E_ARGUMENT_OUT_OF_RANGE:
- PLOG_ERROR << "noscrypt - error: An argument was outside the range of acceptable values.";
- break;
-
- case E_OPERATION_FAILED:
- PLOG_ERROR << "noscrypt - error: Failed to generate the public key from the secret key.";
- break;
- }
-};
-
-#pragma endregion