aboutsummaryrefslogtreecommitdiff
path: root/back-end
diff options
context:
space:
mode:
authorLibravatar vnugent <public@vaughnnugent.com>2024-02-18 13:47:24 -0500
committerLibravatar vnugent <public@vaughnnugent.com>2024-02-18 13:47:24 -0500
commit8bf42df576f494f89b6058ad2dd8a9d5cdbff0a1 (patch)
tree2723a9befa767f0abce9865b112d5833db88b136 /back-end
parentd9f4778896407ebe6e1b8bb439d2c175b4a22f45 (diff)
refactor: deprecate secp256k1 native, transition to noscrypt library
Diffstat (limited to 'back-end')
-rw-r--r--back-end/plugins/nvault/src/INostrCryptoProvider.cs10
-rw-r--r--back-end/plugins/nvault/src/ManagedCryptoprovider.cs16
-rw-r--r--back-end/plugins/nvault/src/Model/NostrContext.cs2
-rw-r--r--back-end/plugins/nvault/src/Model/NostrEventEntry.cs5
-rw-r--r--back-end/plugins/nvault/src/Model/NostrKeyMeta.cs9
-rw-r--r--back-end/plugins/nvault/src/Model/NostrRelay.cs10
-rw-r--r--back-end/plugins/nvault/src/NVault.csproj9
-rw-r--r--back-end/plugins/nvault/src/NativeSecp256k1Library.cs217
-rw-r--r--back-end/plugins/nvault/src/NoscryptProvider.cs148
-rw-r--r--back-end/plugins/nvault/src/NostrOpProvider.cs91
-rw-r--r--back-end/plugins/nvault/src/Properties/launchSettings.json8
11 files changed, 223 insertions, 302 deletions
diff --git a/back-end/plugins/nvault/src/INostrCryptoProvider.cs b/back-end/plugins/nvault/src/INostrCryptoProvider.cs
index c65d3e9..797e034 100644
--- a/back-end/plugins/nvault/src/INostrCryptoProvider.cs
+++ b/back-end/plugins/nvault/src/INostrCryptoProvider.cs
@@ -28,14 +28,14 @@ namespace NVault.Plugins.Vault
int GetSignatureBufferSize();
/// <summary>
- /// Signs a message digest with the specified private key and writes
+ /// Signs a message with the specified private key and writes
/// the signature to the specified buffer.
/// </summary>
- /// <param name="key"></param>
- /// <param name="digest"></param>
- /// <param name="signatureBuffer"></param>
+ /// <param name="key">The secret key used to sign the message</param>
+ /// <param name="data">The message data to sign</param>
+ /// <param name="signatureBuffer">The signature output buffer</param>
/// <returns>The number of bytes written to the signature buffer, 0 or less if the operation failed</returns>
- ERRNO SignMessage(ReadOnlySpan<byte> key, ReadOnlySpan<byte> digest, Span<byte> signatureBuffer);
+ ERRNO SignData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> data, Span<byte> signatureBuffer);
/// <summary>
/// Determines the exact size of the buffer required to hold a key pair during
diff --git a/back-end/plugins/nvault/src/ManagedCryptoprovider.cs b/back-end/plugins/nvault/src/ManagedCryptoprovider.cs
index fb15b8f..fe585cc 100644
--- a/back-end/plugins/nvault/src/ManagedCryptoprovider.cs
+++ b/back-end/plugins/nvault/src/ManagedCryptoprovider.cs
@@ -18,11 +18,12 @@ using System.Text.Json;
using System.Collections.Generic;
using VNLib.Utils;
+using VNLib.Utils.Memory;
using VNLib.Utils.Logging;
using VNLib.Plugins;
using VNLib.Plugins.Extensions.Loading;
-using NVault.Crypto.Secp256k1;
+using NVault.Crypto.Noscrypt;
namespace NVault.Plugins.Vault
{
@@ -59,24 +60,27 @@ namespace NVault.Plugins.Vault
string nativePath = config.GetRequiredProperty("lib_crypto", p => p.GetString()!);
//Load native library path
- _provider = NativeSecp256k1Library.LoadLibrary(nativePath, random);
- plugin.Log.Verbose("Loaded native Secp256k1 library from {path}", nativePath);
+ _provider = NoscryptProvider.LoadLibrary(nativePath, random, MemoryUtil.Shared);
+ plugin.Log.Verbose("Loaded native Noscrypt library from {path}", nativePath);
}
///<inheritdoc/>
public int GetSignatureBufferSize() => _provider.GetSignatureBufferSize();
///<inheritdoc/>
- public ERRNO SignMessage(ReadOnlySpan<byte> key, ReadOnlySpan<byte> digest, Span<byte> signatureBuffer) => _provider.SignMessage(key, digest, signatureBuffer);
+ public ERRNO SignData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> digest, Span<byte> signatureBuffer)
+ => _provider.SignData(key, digest, signatureBuffer);
///<inheritdoc/>
public KeyBufferSizes GetKeyBufferSize() => _provider.GetKeyBufferSize();
///<inheritdoc/>
- public bool TryGenerateKeyPair(Span<byte> publicKey, Span<byte> privateKey) => _provider.TryGenerateKeyPair(publicKey, privateKey);
+ public bool TryGenerateKeyPair(Span<byte> publicKey, Span<byte> privateKey)
+ => _provider.TryGenerateKeyPair(publicKey, privateKey);
///<inheritdoc/>
- public bool RecoverPublicKey(ReadOnlySpan<byte> privateKey, Span<byte> pubKey) => _provider.RecoverPublicKey(privateKey, pubKey);
+ public bool RecoverPublicKey(ReadOnlySpan<byte> privateKey, Span<byte> pubKey)
+ => _provider.RecoverPublicKey(privateKey, pubKey);
///<inheritdoc/>
public ERRNO DecryptMessage(ReadOnlySpan<byte> secretKey, ReadOnlySpan<byte> targetKey, ReadOnlySpan<byte> aseIv, ReadOnlySpan<byte> cyphterText, Span<byte> outputBuffer)
diff --git a/back-end/plugins/nvault/src/Model/NostrContext.cs b/back-end/plugins/nvault/src/Model/NostrContext.cs
index 7dc29d0..bfda43e 100644
--- a/back-end/plugins/nvault/src/Model/NostrContext.cs
+++ b/back-end/plugins/nvault/src/Model/NostrContext.cs
@@ -21,7 +21,7 @@ using VNLib.Plugins.Extensions.Loading.Sql;
namespace NVault.Plugins.Vault.Model
{
- internal class NostrContext : TransactionalDbContext, IDbTableDefinition
+ internal class NostrContext : DBContextBase, IDbTableDefinition
{
public DbSet<NostrRelay> NostrRelays { get; set; }
diff --git a/back-end/plugins/nvault/src/Model/NostrEventEntry.cs b/back-end/plugins/nvault/src/Model/NostrEventEntry.cs
index 9fa5aa2..b34fd9d 100644
--- a/back-end/plugins/nvault/src/Model/NostrEventEntry.cs
+++ b/back-end/plugins/nvault/src/Model/NostrEventEntry.cs
@@ -16,6 +16,7 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
+using System.ComponentModel.DataAnnotations;
using VNLib.Plugins.Extensions.Data;
using VNLib.Plugins.Extensions.Data.Abstractions;
@@ -25,6 +26,8 @@ namespace NVault.Plugins.Vault.Model
{
internal sealed class NostrEventEntry : DbModelBase, IUserEntity
{
+ [Key]
+ [MaxLength(64)]
public override string Id { get; set; }
public override DateTime Created { get; set; }
@@ -33,8 +36,10 @@ namespace NVault.Plugins.Vault.Model
//Never share userids with the client
[JsonIgnore]
+ [MaxLength(64)]
public string? UserId { get; set; }
+ [MaxLength(8000)]
public string? EventData { get; set; }
public static NostrEventEntry FromEvent(string userId, NostrEvent @event) => new()
diff --git a/back-end/plugins/nvault/src/Model/NostrKeyMeta.cs b/back-end/plugins/nvault/src/Model/NostrKeyMeta.cs
index 3f0b985..3568b8a 100644
--- a/back-end/plugins/nvault/src/Model/NostrKeyMeta.cs
+++ b/back-end/plugins/nvault/src/Model/NostrKeyMeta.cs
@@ -28,9 +28,11 @@ namespace NVault.Plugins.Vault.Model
internal class NostrKeyMeta : DbModelBase, IUserEntity
{
[Key]
- [MaxLength(50)]
+ [MaxLength(64)]
public override string Id { get; set; }
+
public override DateTime Created { get; set; }
+
public override DateTime LastModified { get; set; }
[JsonPropertyName("PublicKey")]
@@ -41,7 +43,7 @@ namespace NVault.Plugins.Vault.Model
[MaxLength(50)]
public string? UserId { get; set; }
- [MaxLength(100)]
+ [MaxLength(64)]
public string? UserName { get; set; }
public void CleanupFromUser()
@@ -60,8 +62,7 @@ namespace NVault.Plugins.Vault.Model
public void Merge(NostrKeyMeta other)
{
- if (other == null)
- throw new ArgumentNullException(nameof(other));
+ ArgumentNullException.ThrowIfNull(other);
//We only update username and key value
UserName = other.UserName;
diff --git a/back-end/plugins/nvault/src/Model/NostrRelay.cs b/back-end/plugins/nvault/src/Model/NostrRelay.cs
index ab8cea7..f45897f 100644
--- a/back-end/plugins/nvault/src/Model/NostrRelay.cs
+++ b/back-end/plugins/nvault/src/Model/NostrRelay.cs
@@ -31,22 +31,24 @@ namespace NVault.Plugins.Vault.Model
internal class NostrRelay : DbModelBase, IUserEntity
{
[Key]
- [MaxLength(50)]
+ [MaxLength(64)]
[JsonPropertyName("id")]
public override string Id { get; set; }
+
public override DateTime Created { get; set; }
+
public override DateTime LastModified { get; set; }
[JsonPropertyName("url")]
[MaxLength(200)]
- public string Url { get; set; }
+ public string? Url { get; set; }
[JsonPropertyName("flags")]
public NostrRelayFlags Flags { get; set; }
[JsonIgnore]
- [MaxLength(50)]
- public string UserId { get; set; }
+ [MaxLength(64)]
+ public string? UserId { get; set; }
public void CleanupFromUser()
{
diff --git a/back-end/plugins/nvault/src/NVault.csproj b/back-end/plugins/nvault/src/NVault.csproj
index e876eec..343fd46 100644
--- a/back-end/plugins/nvault/src/NVault.csproj
+++ b/back-end/plugins/nvault/src/NVault.csproj
@@ -21,14 +21,13 @@
<ItemGroup>
<PackageReference Include="FluentValidation" Version="11.9.0" />
- <PackageReference Include="VNLib.Plugins.Extensions.Data" Version="0.1.0-ci0047" />
- <PackageReference Include="VNLib.Plugins.Extensions.Validation" Version="0.1.0-ci0047" />
- <PackageReference Include="VNLib.Plugins.Extensions.Loading.Sql" Version="0.1.0-ci0047" />
+ <PackageReference Include="VNLib.Plugins.Extensions.Data" Version="0.1.0-ci0049" />
+ <PackageReference Include="VNLib.Plugins.Extensions.Validation" Version="0.1.0-ci0049" />
+ <PackageReference Include="VNLib.Plugins.Extensions.Loading.Sql" Version="0.1.0-ci0049" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\lib\NVault.Crypto.Noscrypt\src\NVault.Crypto.Noscrypt.csproj" />
- <ProjectReference Include="..\..\..\..\lib\NVault.Crypto.Secp256k1\src\NVault.Crypto.Secp256k1.csproj" />
<ProjectReference Include="..\..\..\..\lib\NVault.VaultExtensions\src\NVault.VaultExtensions.csproj" />
</ItemGroup>
@@ -44,5 +43,5 @@
</None>
</ItemGroup>
-
+
</Project>
diff --git a/back-end/plugins/nvault/src/NativeSecp256k1Library.cs b/back-end/plugins/nvault/src/NativeSecp256k1Library.cs
deleted file mode 100644
index abbafaf..0000000
--- a/back-end/plugins/nvault/src/NativeSecp256k1Library.cs
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright (C) 2024 Vaughn Nugent
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// This program 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 Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-using System;
-using System.Security.Cryptography;
-using System.Runtime.InteropServices;
-
-using NVault.Crypto.Secp256k1;
-
-using VNLib.Utils;
-using VNLib.Utils.Memory;
-
-namespace NVault.Plugins.Vault
-{
- internal sealed class NativeSecp256k1Library : VnDisposeable, INostrCryptoProvider
- {
- private readonly LibSecp256k1 _lib;
-
- private NativeSecp256k1Library(LibSecp256k1 lib)
- {
- _lib = lib;
- }
-
- /// <summary>
- /// Loads the native library from the specified path
- /// </summary>
- /// <param name="libFilePath">The library path</param>
- /// <param name="random">The optional random source</param>
- /// <returns>The loaded <see cref="NativeSecp256k1Library"/></returns>
- public static NativeSecp256k1Library LoadLibrary(string libFilePath, IRandomSource? random)
- {
- LibSecp256k1 lib = LibSecp256k1.LoadLibrary(libFilePath, DllImportSearchPath.SafeDirectories, random);
- return new(lib);
- }
-
- ///<inheritdoc/>
- public ERRNO DecryptMessage(ReadOnlySpan<byte> secretKey, ReadOnlySpan<byte> targetKey, ReadOnlySpan<byte> aesIv, ReadOnlySpan<byte> ciphterText, Span<byte> outputBuffer)
- {
- Check();
- //Start with new context
- using Secp256k1Context context = _lib.CreateContext();
-
- //Randomize context
- if (!context.Randomize())
- {
- return false;
- }
-
- //Get shared key
- byte[] sharedKeyBuffer = new byte[32];
-
- try
- {
- //Get the Secp256k1 shared key
- context.ComputeSharedKey(sharedKeyBuffer, targetKey, secretKey, HashFuncCallback, IntPtr.Zero);
-
- //Init the AES cipher
- using Aes aes = Aes.Create();
- aes.Key = sharedKeyBuffer;
- aes.Mode = CipherMode.CBC;
-
- return aes.DecryptCbc(ciphterText, aesIv, outputBuffer, PaddingMode.Zeros);
- }
- finally
- {
- //Zero out buffers
- MemoryUtil.InitializeBlock(sharedKeyBuffer);
- }
- }
-
- ///<inheritdoc/>
- public ERRNO EncryptMessage(ReadOnlySpan<byte> secretKey, ReadOnlySpan<byte> targetKey, ReadOnlySpan<byte> aesIv, ReadOnlySpan<byte> plainText, Span<byte> cipherText)
- {
- Check();
- //Start with new context
- using Secp256k1Context context = _lib.CreateContext();
-
- //Randomize context
- if (!context.Randomize())
- {
- return false;
- }
-
- //Get shared key
- byte[] sharedKeyBuffer = new byte[32];
-
- try
- {
- //Get the Secp256k1 shared key
- if(!context.ComputeSharedKey(sharedKeyBuffer, targetKey, secretKey, HashFuncCallback, IntPtr.Zero))
- {
- return ERRNO.E_FAIL;
- }
-
- //Init the AES cipher
- using Aes aes = Aes.Create();
- aes.Key = sharedKeyBuffer;
- aes.Mode = CipherMode.CBC;
-
- return aes.EncryptCbc(plainText, aesIv, cipherText, PaddingMode.Zeros);
- }
- finally
- {
- //Zero out buffers
- MemoryUtil.InitializeBlock(sharedKeyBuffer);
- }
- }
-
- static int HashFuncCallback(in Secp256HashFuncState state)
- {
- //Get function args
- Span<byte> sharedKey = state.GetOutput();
- ReadOnlySpan<byte> xCoord = state.GetXCoordArg();
-
- //Nostr literally just uses the shared x coord as the shared key
- xCoord.CopyTo(sharedKey);
-
- return xCoord.Length;
- }
-
- //Key sizes are constant
- ///<inheritdoc/>
- public KeyBufferSizes GetKeyBufferSize() => new(LibSecp256k1.SecretKeySize, LibSecp256k1.XOnlyPublicKeySize);
-
- //Signature sizes are constant
- ///<inheritdoc/>
- public int GetSignatureBufferSize() => LibSecp256k1.SignatureSize;
-
- ///<inheritdoc/>
- public bool RecoverPublicKey(ReadOnlySpan<byte> privateKey, Span<byte> pubKey)
- {
- Check();
-
- //Init new context
- using Secp256k1Context context = _lib.CreateContext();
-
- //Randomize context
- if (!context.Randomize())
- {
- return false;
- }
-
- //Recover public key from the privatkey
- return context.GeneratePubKeyFromSecret(privateKey, pubKey) == LibSecp256k1.XOnlyPublicKeySize;
- }
-
- ///<inheritdoc/>
- public ERRNO SignMessage(ReadOnlySpan<byte> key, ReadOnlySpan<byte> digest, Span<byte> signatureBuffer)
- {
- Check();
-
- //Init new context
- using Secp256k1Context context = _lib.CreateContext();
-
- //Randomize context
- if (!context.Randomize())
- {
- return false;
- }
-
- //Sign the message
- return context.SchnorSignDigest(key, digest, signatureBuffer);
- }
-
- ///<inheritdoc/>
- public void GetRandomBytes(Span<byte> bytes) => _lib.GetRandomBytes(bytes);
-
- ///<inheritdoc/>
- public bool TryGenerateKeyPair(Span<byte> publicKey, Span<byte> privateKey)
- {
- //Trim buffers to the exact size required to avoid exceptions in the native lib
- privateKey = privateKey[..LibSecp256k1.SecretKeySize];
- publicKey = publicKey[..LibSecp256k1.XOnlyPublicKeySize];
-
- 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 context.GeneratePubKeyFromSecret(privateKey, publicKey) == LibSecp256k1.XOnlyPublicKeySize;
- }
-
- ///<inheritdoc/>
- protected override void Free()
- {
- _lib.Dispose();
- }
-
-
- }
-} \ No newline at end of file
diff --git a/back-end/plugins/nvault/src/NoscryptProvider.cs b/back-end/plugins/nvault/src/NoscryptProvider.cs
new file mode 100644
index 0000000..51774b0
--- /dev/null
+++ b/back-end/plugins/nvault/src/NoscryptProvider.cs
@@ -0,0 +1,148 @@
+// Copyright (C) 2024 Vaughn Nugent
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+using System;
+
+using NVault.Crypto.Noscrypt;
+
+using VNLib.Utils;
+using VNLib.Utils.Memory;
+using VNLib.Hashing;
+
+
+namespace NVault.Plugins.Vault
+{
+ internal sealed class NoscryptProvider(IRandomSource random, NostrCrypto noscrypt) : VnDisposeable, INostrCryptoProvider
+ {
+ const int MaxInvalidSecKeyAttempts = 10;
+
+ ///<inheritdoc/>
+ public ERRNO DecryptMessage(ReadOnlySpan<byte> secretKey, ReadOnlySpan<byte> targetKey, ReadOnlySpan<byte> aseIv, ReadOnlySpan<byte> cyphterText, Span<byte> outputBuffer)
+ {
+ return false;
+ }
+
+ ///<inheritdoc/>
+ public ERRNO EncryptMessage(ReadOnlySpan<byte> secretKey, ReadOnlySpan<byte> targetKey, ReadOnlySpan<byte> aesIv, ReadOnlySpan<byte> plainText, Span<byte> cipherText)
+ {
+ return false;
+ }
+
+ ///<inheritdoc/>
+ public KeyBufferSizes GetKeyBufferSize()
+ {
+ return new()
+ {
+ PrivateKeySize = LibNoscrypt.NC_SEC_KEY_SIZE,
+ PublicKeySize = LibNoscrypt.NC_SEC_PUBKEY_SIZE
+ };
+ }
+
+ ///<inheritdoc/>
+ public void GetRandomBytes(Span<byte> bytes) => random.GetRandomBytes(bytes);
+
+ ///<inheritdoc/>
+ public int GetSignatureBufferSize() => LibNoscrypt.NC_SIGNATURE_SIZE;
+
+ ///<inheritdoc/>
+ public bool RecoverPublicKey(ReadOnlySpan<byte> privateKey, Span<byte> pubKey)
+ {
+ ArgumentOutOfRangeException.ThrowIfLessThan(privateKey.Length, LibNoscrypt.NC_SEC_KEY_SIZE, nameof(privateKey));
+ ArgumentOutOfRangeException.ThrowIfLessThan(pubKey.Length, LibNoscrypt.NC_SEC_PUBKEY_SIZE, nameof(pubKey));
+
+ noscrypt.GetPublicKey(
+ in NCUtil.AsSecretKey(privateKey),
+ ref NCUtil.AsPublicKey(pubKey)
+ );
+
+ return true;
+ }
+
+ ///<inheritdoc/>
+ public ERRNO SignData(ReadOnlySpan<byte> key, ReadOnlySpan<byte> data, Span<byte> signatureBuffer)
+ {
+ //Get a buffer of message entropy for libnoscrypt
+ Span<byte> entropy = stackalloc byte[32];
+ random.GetRandomBytes(entropy);
+
+ ref readonly NCSecretKey secretKey = ref NCUtil.AsSecretKey(key);
+ noscrypt.SignData(in secretKey, entropy, data, signatureBuffer);
+
+ return LibNoscrypt.NC_SIGNATURE_SIZE;
+ }
+
+ ///<inheritdoc/>
+ public bool TryGenerateKeyPair(Span<byte> publicKey, Span<byte> privateKey)
+ {
+ ArgumentOutOfRangeException.ThrowIfLessThan(privateKey.Length, LibNoscrypt.NC_SEC_KEY_SIZE, nameof(privateKey));
+ ArgumentOutOfRangeException.ThrowIfLessThan(publicKey.Length, LibNoscrypt.NC_SEC_PUBKEY_SIZE, nameof(publicKey));
+
+ ref readonly NCSecretKey asSecretKey = ref NCUtil.AsSecretKey(privateKey);
+ ref NCPublicKey asPubKey = ref NCUtil.AsPublicKey(publicKey);
+
+ int loopCount = 0;
+
+ random.GetRandomBytes(privateKey);
+
+ //Validate the secret key data
+ while (noscrypt.ValidateSecretKey(in asSecretKey) == false)
+ {
+ if(loopCount++ > MaxInvalidSecKeyAttempts)
+ {
+ return false;
+ }
+
+ //Try to get random key again
+ random.GetRandomBytes(privateKey);
+ }
+
+ //Generate the public key after secret key is validated
+ noscrypt.GetPublicKey(in asSecretKey, ref asPubKey);
+ return true;
+ }
+
+ ///<inheritdoc/>
+ protected override void Free() => noscrypt.Dispose();
+
+
+ public static NoscryptProvider LoadLibrary(string libPath, IRandomSource? random, IUnmangedHeap heap)
+ {
+ //Fallback to platform random crypto
+ random ??= new PlatformRandom();
+
+ LibNoscrypt lib = LibNoscrypt.Load(libPath);
+
+ try
+ {
+ Span<byte> entropy = stackalloc byte[LibNoscrypt.CTX_ENTROPY_SIZE];
+ random.GetRandomBytes(entropy);
+
+ NostrCrypto nostr = lib.InitializeCrypto(heap, entropy);
+ return new NoscryptProvider(random, nostr);
+ }
+ catch
+ {
+ lib.Dispose();
+ throw;
+ }
+ }
+
+ sealed class PlatformRandom() : IRandomSource
+ {
+ ///<inheritdoc/>
+ public void GetRandomBytes(Span<byte> buffer) => RandomHash.GetRandomBytes(buffer);
+ }
+ }
+} \ No newline at end of file
diff --git a/back-end/plugins/nvault/src/NostrOpProvider.cs b/back-end/plugins/nvault/src/NostrOpProvider.cs
index 48ffe93..cc7342a 100644
--- a/back-end/plugins/nvault/src/NostrOpProvider.cs
+++ b/back-end/plugins/nvault/src/NostrOpProvider.cs
@@ -36,28 +36,16 @@ using NVault.Plugins.Vault.Model;
namespace NVault.Plugins.Vault
{
- internal sealed class NostrOpProvider : INostrOperations
+ internal sealed class NostrOpProvider(PluginBase plugin) : INostrOperations
{
public const int AES_IV_SIZE = 16;
public static int IvMaxBase64EncodedSize { get; } = Base64.GetMaxEncodedToUtf8Length(AES_IV_SIZE);
- private static JavaScriptEncoder _encoder { get; } = GetJsEncoder();
+ private static readonly JavaScriptEncoder _encoder = GetJsEncoder();
- readonly IKvVaultStore _vault;
- readonly INostrKeyEncoder _keyEncoder;
- readonly INostrCryptoProvider _cryptoProvider;
-
- public NostrOpProvider(PluginBase plugin)
- {
- //Use base64 key encoder
- _keyEncoder = new Base64KeyEncoder();
-
- //Setup crypto provider
- _cryptoProvider = plugin.CreateService<ManagedCryptoprovider>();
-
- //Get the vault
- _vault = plugin.CreateService<ManagedVaultClient>();
- }
+ private readonly IKvVaultStore _vault = plugin.CreateService<ManagedVaultClient>();
+ private readonly INostrKeyEncoder _keyEncoder = new Base64KeyEncoder();
+ private readonly INostrCryptoProvider _cryptoProvider = plugin.CreateService<ManagedCryptoprovider>();
///<inheritdoc/>
public Task<bool> CreateCredentialAsync(VaultUserScope scope, NostrKeyMeta newKey, CancellationToken cancellation)
@@ -167,56 +155,30 @@ namespace NVault.Plugins.Vault
private bool SignMessage(ReadOnlySpan<char> vaultKey, NostrEvent ev)
{
- //Decode the key
- int keyBufSize = _keyEncoder.GetKeyBufferSize(vaultKey);
-
- //Get the signature buffer size
- int sigBufSize = _cryptoProvider.GetSignatureBufferSize();
-
- //Alloc key buffer
- using IMemoryHandle<byte> buffHandle = MemoryUtil.SafeAllocNearestPage(keyBufSize + sigBufSize, true);
-
- //Wrap the buffer
- EvBuffer buffer = new(buffHandle, keyBufSize, sigBufSize, (int)HashAlg.SHA256);
+ Span<byte> keyBuffer = stackalloc byte[_keyEncoder.GetKeyBufferSize(vaultKey)];
try
{
//Decode the key
- ERRNO keySize = _keyEncoder.DecodeKey(vaultKey, buffer.KeyBuffer);
+ ERRNO keySize = _keyEncoder.DecodeKey(vaultKey, keyBuffer);
if (!keySize)
{
return false;
}
- //Get the event id/event digest from the event
- GetNostrEventId(ev, buffer.HashBuffer);
-
- //Store the event id
- ev.Id = Convert.ToHexString(buffer.HashBuffer).ToLower();
-
- //Sign the event
- ERRNO sigSize = _cryptoProvider.SignMessage(buffer.KeyBuffer[..(int)keySize], buffer.HashBuffer, buffer.SigBuffer);
-
- if (!sigSize)
- {
- return false;
- }
-
- //Store the signature as loewrcase hex
- ev.Signature = Convert.ToHexString(buffer.SigBuffer[..(int)sigSize]).ToLower();
- return true;
+ //Compute the message signature
+ return ComputeMessageSignature(ev, keyBuffer[0.. (int)keySize]);
}
finally
{
- //Zero the key buffer and key
- MemoryUtil.InitializeBlock(buffHandle.Span);
+ //Zero the key before returning
+ MemoryUtil.InitializeBlock(keyBuffer);
}
}
- private void GetNostrEventId(NostrEvent evnt, Span<byte> idHash)
+ private bool ComputeMessageSignature(NostrEvent evnt, ReadOnlySpan<byte> secKey)
{
-
JsonWriterOptions options = new()
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
@@ -224,6 +186,9 @@ namespace NVault.Plugins.Vault
MaxDepth = 4
};
+ Span<byte> idHash = stackalloc byte[(int)HashAlg.SHA256];
+ Span<byte> sigBuffer = stackalloc byte[_cryptoProvider.GetSignatureBufferSize()];
+
using VnMemoryStream ms = new();
using (Utf8JsonWriter writer = new(ms, options))
{
@@ -259,8 +224,23 @@ namespace NVault.Plugins.Vault
//Compute the hash
if (!ManagedHash.ComputeHash(ms.AsSpan(), idHash, HashAlg.SHA256))
{
- throw new CryptographicException("Failed to compute event data hash");
+ return false;
+ }
+
+ //Set message id
+ evnt.Id = Convert.ToHexString(idHash).ToLower();
+
+ if(_cryptoProvider.SignData(secKey, ms.AsSpan(), sigBuffer) != sigBuffer.Length)
+ {
+ return false;
}
+
+ //Set the signature as lowercase hex
+ evnt.Signature = Convert.ToHexString(sigBuffer).ToLower();
+
+ MemoryUtil.InitializeBlock(sigBuffer);
+
+ return true;
}
private static JavaScriptEncoder GetJsEncoder()
@@ -442,14 +422,5 @@ namespace NVault.Plugins.Vault
MemoryUtil.InitializeBlock(ivBuffer);
}
}
-
- readonly record struct EvBuffer(IMemoryHandle<byte> Handle, int KeySize, int SigSize, int HashSize)
- {
- public readonly Span<byte> KeyBuffer => Handle.Span[..KeySize];
-
- public readonly Span<byte> SigBuffer => Handle.AsSpan(KeySize, SigSize);
-
- public readonly Span<byte> HashBuffer => Handle.AsSpan(KeySize + SigSize, HashSize);
- }
}
}
diff --git a/back-end/plugins/nvault/src/Properties/launchSettings.json b/back-end/plugins/nvault/src/Properties/launchSettings.json
new file mode 100644
index 0000000..0f138be
--- /dev/null
+++ b/back-end/plugins/nvault/src/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "NVault": {
+ "commandName": "Project",
+ "nativeDebugging": true
+ }
+ }
+} \ No newline at end of file