From 96d4e6c61900a8c0a61e5b34e0fcabe6b9645421 Mon Sep 17 00:00:00 2001 From: vnugent Date: Wed, 18 Oct 2023 14:24:51 -0400 Subject: add missing secret key verification --- .../src/ContextExtensions.cs | 29 ++++++++++++++++++++-- .../NVault.Crypto.Secp256k1/src/LibSecp256k1.cs | 8 ++++++ .../src/Secp256k1Context.cs | 3 ++- .../src/UnmanagedRandomSource.cs | 2 +- .../plugins/nvault/src/NativeSecp256k1Library.cs | 21 +++++++++++++--- 5 files changed, 56 insertions(+), 7 deletions(-) diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs index b0e8695..a89fce8 100644 --- a/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs +++ b/back-end/libs/NVault.Crypto.Secp256k1/src/ContextExtensions.cs @@ -15,6 +15,7 @@ using System; using System.Security.Cryptography; +using System.Runtime.InteropServices; using VNLib.Hashing; using VNLib.Utils; @@ -89,7 +90,8 @@ namespace NVault.Crypto.Secp256k1 try { - fixed (byte* sigPtr = signature, digestPtr = digest) + fixed (byte* sigPtr = &MemoryMarshal.GetReference(signature), + digestPtr = &MemoryMarshal.GetReference(digest)) { //Sign the message hash and write the output to the signature buffer if (context.Lib._signHash(context.Context, sigPtr, digestPtr, &keyPair, random) != 1) @@ -153,7 +155,7 @@ namespace NVault.Crypto.Secp256k1 return ERRNO.E_FAIL; } - fixed (byte* pubBuffer = pubKeyBuffer) + fixed (byte* pubBuffer = &MemoryMarshal.GetReference(pubKeyBuffer)) { //Serialize the public key to the buffer as an X-only public key without leading status byte if (context.Lib._serializeXonly(context.Context, pubBuffer, &xOnlyPubKey) != 1) @@ -171,5 +173,28 @@ namespace NVault.Crypto.Secp256k1 //PubKey length is constant return XOnlyPublicKeySize; } + + /// + /// Verifies that a given secret key is valid using the current context + /// + /// + /// The secret key to verify + /// A boolean value that indicates if the secret key is valid or not + /// + public static bool VerifySecretKey(this in Secp256k1Context context, ReadOnlySpan secretKey) + { + if (secretKey.Length != SecretKeySize) + { + throw new CryptographicException($"Your secret key must be exactly {SecretKeySize} bytes long"); + } + + context.Lib.SafeLibHandle.ThrowIfClosed(); + + //Get sec key ref and verify + fixed(byte* ptr = &MemoryMarshal.GetReference(secretKey)) + { + return context.Lib._secKeyVerify.Invoke(context.Context, ptr) == 1; + } + } } } \ No newline at end of file diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs index 2eea450..80d6eb8 100644 --- a/back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs +++ b/back-end/libs/NVault.Crypto.Secp256k1/src/LibSecp256k1.cs @@ -72,6 +72,9 @@ namespace NVault.Crypto.Secp256k1 [SafeMethodName("secp256k1_schnorrsig_sign32")] internal delegate int SignHash(IntPtr ctx, byte* sig64, byte* msg32, KeyPair* keypair, byte* aux_rand32); + [SafeMethodName("secp256k1_ec_seckey_verify")] + internal delegate int SecKeyVerify(IntPtr ctx, in byte* seckey); + /// /// Loads the Secp256k1 library from the specified path and creates a wrapper class (loads methods from the library) /// @@ -118,6 +121,7 @@ namespace NVault.Crypto.Secp256k1 internal readonly KeypairXOnlyPub _createXonly; internal readonly XOnlyPubkeySerialize _serializeXonly; internal readonly SignHash _signHash; + internal readonly SecKeyVerify _secKeyVerify; private readonly IRandomSource _randomSource; /// @@ -143,6 +147,7 @@ namespace NVault.Crypto.Secp256k1 _createXonly = handle.DangerousGetMethod(); _serializeXonly = handle.DangerousGetMethod(); _signHash = handle.DangerousGetMethod(); + _secKeyVerify = handle.DangerousGetMethod(); //Store random source _randomSource = randomSource; @@ -161,6 +166,9 @@ namespace NVault.Crypto.Secp256k1 /// /// Generates a new secret key and writes it to the specified buffer. The buffer size must be exactly bytes long + /// + /// NOTE: You should verify this validity of the key against the library with a new + /// /// /// The secret key buffer /// diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1Context.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1Context.cs index 8aac0b8..67f1d9f 100644 --- a/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1Context.cs +++ b/back-end/libs/NVault.Crypto.Secp256k1/src/Secp256k1Context.cs @@ -14,6 +14,7 @@ // along with this program. If not, see . using System; +using System.Runtime.InteropServices; using VNLib.Utils.Extensions; using VNLib.Utils.Memory; @@ -57,7 +58,7 @@ namespace NVault.Crypto.Secp256k1 { Lib.SafeLibHandle.ThrowIfClosed(); - fixed (byte* sk = secretKey) + fixed (byte* sk = &MemoryMarshal.GetReference(secretKey)) { //Create the keypair from the secret key return Lib._createKeyPair(Context, keyPair, sk) == 1; diff --git a/back-end/libs/NVault.Crypto.Secp256k1/src/UnmanagedRandomSource.cs b/back-end/libs/NVault.Crypto.Secp256k1/src/UnmanagedRandomSource.cs index d4d9a06..d6ff5aa 100644 --- a/back-end/libs/NVault.Crypto.Secp256k1/src/UnmanagedRandomSource.cs +++ b/back-end/libs/NVault.Crypto.Secp256k1/src/UnmanagedRandomSource.cs @@ -83,7 +83,7 @@ namespace NVault.Crypto.Secp256k1 _library.ThrowIfClosed(); //Fix buffer and call unmanaged method - fixed(byte* ptr = buffer) + fixed(byte* ptr = &MemoryMarshal.GetReference(buffer)) { _getRandomBytes(ptr, buffer.Length); } diff --git a/back-end/plugins/nvault/src/NativeSecp256k1Library.cs b/back-end/plugins/nvault/src/NativeSecp256k1Library.cs index 67143fc..6c670dd 100644 --- a/back-end/plugins/nvault/src/NativeSecp256k1Library.cs +++ b/back-end/plugins/nvault/src/NativeSecp256k1Library.cs @@ -93,11 +93,26 @@ namespace NVault.Plugins.Vault privateKey = privateKey[..LibSecp256k1.SecretKeySize]; publicKey = publicKey[..LibSecp256k1.XOnlyPublicKeySize]; - //Create the secret key - _lib.CreateSecretKey(privateKey); + Check(); + + //Init new context + using Secp256k1Context context = _lib.CreateContext(); + + //Randomize context + if (!context.Randomize()) + { + return false; + } + + do + { + //Create the secret key and verify + _lib.CreateSecretKey(privateKey); + } + while(context.VerifySecretKey(privateKey) == false); //Create the public key - return RecoverPublicKey(privateKey, publicKey); + return context.GeneratePubKeyFromSecret(privateKey, publicKey) == LibSecp256k1.XOnlyPublicKeySize; } /// -- cgit