diff options
Diffstat (limited to 'wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src')
24 files changed, 527 insertions, 1324 deletions
diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCUtilCipher.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCUtilCipher.cs new file mode 100644 index 0000000..72bb75a --- /dev/null +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCUtilCipher.cs @@ -0,0 +1,128 @@ +// 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.Diagnostics; +using VNLib.Utils.Cryptography.Noscrypt.@internal; + +using NCResult = System.Int64; + +namespace VNLib.Utils.Cryptography.Noscrypt.Encryption +{ + internal static class NCUtilCipher + { + /* + * This class wraps the low-level cipher functions provided by + * the Noscrypt utility side-car library. + */ + + public static nint Alloc(NCContext ctx, uint version, uint flags) + { + nint cipher = GetTable(ctx).NCUtilCipherAlloc(version, flags); + + if (cipher == nint.Zero) + { + throw new OutOfMemoryException("Failed to allocate cipher context"); + } + + //Ensure flags are identical to those set during allocation + Debug.Assert(GetFlags(ctx, cipher) == flags); + + return cipher; + } + + public static uint GetFlags(NCContext ctx, nint cipher) + { + NCResult result = GetTable(ctx).NCUtilCipherGetFlags(cipher); + + NCUtil.CheckResult<FunctionTable.NCUtilCipherGetFlagsDelegate>(result, raiseOnFailure: true); + + return (uint)result; + } + + public static void Free(NCContext ctx, nint cipher) => GetTable(ctx).NCUtilCipherFree(cipher); + + public static int GetIvSize(NCContext ctx, nint cipher) + { + NCResult result = GetTable(ctx).NCUtilCipherGetIvSize(cipher); + + NCUtil.CheckResult<FunctionTable.NCUtilCipherGetIvSizeDelegate>(result, raiseOnFailure: true); + + return checked((int)result); + } + + public static unsafe void SetProperty(NCContext ctx, nint cipher, uint property, ref readonly byte value, uint valueLen) + { + fixed (byte* valPtr = &value) + { + NCResult result = GetTable(ctx).NCUtilCipherSetProperty(cipher, property, valPtr, valueLen); + + NCUtil.CheckResult<FunctionTable.NCUtilCipherSetPropertyDelegate>(result, raiseOnFailure: true); + } + } + + public static uint GetOutputSize(NCContext ctx, nint cipher) + { + NCResult result = GetTable(ctx).NCUtilCipherGetOutputSize(cipher); + + NCUtil.CheckResult<FunctionTable.NCUtilCipherGetOutputSizeDelegate>(result, raiseOnFailure: true); + + return (uint)result; + } + + public static unsafe uint ReadOutput(NCContext ctx, nint cipher, ref byte outputData, uint outLen) + { + fixed (byte* outPtr = &outputData) + { + NCResult result = GetTable(ctx).NCUtilCipherReadOutput(cipher, outPtr, outLen); + + NCUtil.CheckResult<FunctionTable.NCUtilCipherReadOutputDelegate>(result, raiseOnFailure: true); + + return (uint)result; + } + } + + public static unsafe void InitCipher(NCContext ctx, nint cipher, byte* inputPtr, uint inputSize) + { + NCResult result = GetTable(ctx).NCUtilCipherInit(cipher, inputPtr, inputSize); + + NCUtil.CheckResult<FunctionTable.NCUtilCipherInitDelegate>(result, raiseOnFailure: true); + } + + public static unsafe void Update( + NCContext ctx, + nint cipher, + ref readonly NCSecretKey localKey, + ref readonly NCPublicKey remoteKey + ) + { + fixed (NCSecretKey* sk = &localKey) + fixed (NCPublicKey* pk = &remoteKey) + { + NCResult result = GetTable(ctx).NCUtilCipherUpdate( + cipher: cipher, + libContext: ctx.DangerousGetHandle(), + secKey: sk, + pubKey: pk + ); + + NCUtil.CheckResult<FunctionTable.NCUtilCipherInitDelegate>(result, raiseOnFailure: true); + } + } + + private static ref readonly FunctionTable GetTable(NCContext ctx) => ref ctx.Library.Functions; + } + +} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipher.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipher.cs new file mode 100644 index 0000000..b30ea44 --- /dev/null +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipher.cs @@ -0,0 +1,227 @@ +// 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.Threading; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using VNLib.Utils.Memory; +using VNLib.Utils.Cryptography.Noscrypt.Random; +using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary; + +namespace VNLib.Utils.Cryptography.Noscrypt.Encryption +{ + /// <summary> + /// The noscrypt util cipher wapper + /// </summary> + /// <param name="ctx"></param> + /// <param name="flags">Cipher creation flags</param> + /// <param name="version">The cipher specification version</param> + public sealed class NoscryptCipher(NCContext ctx, NoscryptCipherVersion version, NoscryptCipherFlags flags) : VnDisposeable + { + private IMemoryHandle<byte>? _ivBuffer; + private readonly nint _cipher = NCUtilCipher.Alloc(ctx, (uint)version, (uint)flags); + + /// <summary> + /// The cipher standard version used by this instance + /// </summary> + public NoscryptCipherVersion Version => version; + + /// <summary> + /// Gets the flags set for the cipher instance + /// </summary> + public uint GetFlags() => NCUtilCipher.GetFlags(ctx, _cipher); + + /// <summary> + /// Gets the cipher's initilaization vector size (or nonce) + /// </summary> + /// <returns>The size of the IV in bytes</returns> + public int GetIvSize() => NCUtilCipher.GetIvSize(ctx, _cipher); + + /// <summary> + /// Gets the internal heap buffer that holds the cipher's initalization + /// vector. + /// </summary> + /// <returns>The mutable span of the cipher's IV buffer</returns> + public Span<byte> IvBuffer + { + get => LazyInitializer.EnsureInitialized(ref _ivBuffer, AllocIvBuffer).Span; + } + + /// <summary> + /// Sets the cipher's initialization vector to a random value using + /// the specified random source + /// </summary> + /// <param name="rng">The random source</param> + public void SetRandomIv(IRandomSource rng) + { + ArgumentNullException.ThrowIfNull(rng); + rng.GetRandomBytes(IvBuffer); + } + + /// <summary> + /// Performs the cipher operation on the input data using the specified + /// local and remote keys. + /// </summary> + /// <param name="localKey">The secret key of the local user</param> + /// <param name="remoteKey">The public key of the remote user</param> + /// <param name="inputData">A pointer to the first byte in the buffer sequence</param> + /// <param name="inputSize">The size of the input buffer in bytes</param> + /// <exception cref="ArgumentNullException"></exception> + /// <remarks> + /// If the <see cref="NoscryptCipherFlags.Reusable"/> flag is + /// set, this function may be considered independent and called repeatedly. + /// </remarks> + public unsafe void Update( + ref readonly NCSecretKey localKey, + ref readonly NCPublicKey remoteKey, + ref readonly byte inputData, + uint inputSize + ) + { + if (Unsafe.IsNullRef(in localKey)) + { + throw new ArgumentNullException(nameof(localKey)); + } + + if (Unsafe.IsNullRef(in remoteKey)) + { + throw new ArgumentNullException(nameof(remoteKey)); + } + + if (Unsafe.IsNullRef(in inputData)) + { + throw new ArgumentNullException(nameof(inputData)); + } + + /* + * Initializing the cipher requires the context holding a pointer + * to the input data, so it has to be pinned in a fixed statment + * for the duration of the update operation. + * + * So init and update must be done as an atomic operation. + * + * If ciphers have the Reusable flag set this function may be called + * repeatedly. The results of this operation can be considered + * independent. + */ + + fixed (byte* inputPtr = &inputData) + { + NCUtilCipher.InitCipher(ctx, _cipher, inputPtr, inputSize); + + NCUtilCipher.Update(ctx, _cipher, in localKey, in remoteKey); + } + } + + /// <summary> + /// Performs the cipher operation on the input data using the specified + /// local and remote keys. + /// </summary> + /// <param name="localKey">The secret key of the local user</param> + /// <param name="remoteKey">The public key of the remote user</param> + /// <param name="input">The buffer sequence to read the input data from</param> + /// <exception cref="ArgumentNullException"></exception> + public void Update( + ref readonly NCSecretKey localKey, + ref readonly NCPublicKey remoteKey, + ReadOnlySpan<byte> input + ) + { + Update( + in localKey, + in remoteKey, + inputData: ref MemoryMarshal.GetReference(input), //If empty, null ref will throw + inputSize: (uint)input.Length + ); + } + + /// <summary> + /// Gets the size of the output buffer required to read the cipher output + /// </summary> + /// <returns>The size of the output in bytes</returns> + public int GetOutputSize() => checked((int)NCUtilCipher.GetOutputSize(ctx, _cipher)); + + /// <summary> + /// Reads the output data from the cipher into the specified buffer + /// </summary> + /// <param name="outputData">A reference to the first byte in the buffer sequence</param> + /// <param name="size">The size of the buffer sequence</param> + /// <returns>The number of bytes written to the buffer</returns> + /// <exception cref="ArgumentOutOfRangeException"></exception> + public int ReadOutput(ref byte outputData, int size) + { + ArgumentOutOfRangeException.ThrowIfLessThan(size, GetOutputSize()); + + return checked((int)NCUtilCipher.ReadOutput(ctx, _cipher, ref outputData, (uint)size)); + } + + /// <summary> + /// Reads the output data from the cipher into the specified buffer + /// </summary> + /// <param name="buffer">The buffer sequence to write output data to</param> + /// <returns>The number of bytes written to the buffer</returns> + /// <exception cref="ArgumentOutOfRangeException"></exception> + public int ReadOutput(Span<byte> buffer) + { + return ReadOutput( + ref MemoryMarshal.GetReference(buffer), + buffer.Length + ); + } + + private IMemoryHandle<byte> AllocIvBuffer() + { + //Use the context heap to allocate the internal iv buffer + MemoryHandle<byte> buffer = MemoryUtil.SafeAlloc<byte>(ctx.Heap, GetIvSize(), zero: true); + + try + { + /* + * Assign the buffer reference to the cipher context + * + * NOTE: This pointer will be held as long as the cipher + * context is allocated. So the buffer must be held until + * the cipher is freed. Because of this an umnanaged heap + * buffer is required so we don't need to pin managed memory + * nor worry about the GC moving the buffer. + */ + NCUtilCipher.SetProperty( + ctx, + _cipher, + NC_ENC_SET_IV, + ref buffer.GetReference(), + (uint)buffer.Length + ); + } + catch + { + buffer.Dispose(); + throw; + } + + return buffer; + } + + ///<inheritdoc/> + protected override void Free() + { + NCUtilCipher.Free(ctx, _cipher); + _ivBuffer?.Dispose(); + } + } + +} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipherFlags.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipherFlags.cs new file mode 100644 index 0000000..275c90c --- /dev/null +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipherFlags.cs @@ -0,0 +1,60 @@ +// 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; + +namespace VNLib.Utils.Cryptography.Noscrypt.Encryption +{ + /// <summary> + /// Cipher specific flags that control the behavior of a cipher + /// instance + /// </summary> + [Flags] + public enum NoscryptCipherFlags : uint + { + /// <summary> + /// Puts the cipher into encryption mode + /// </summary> + ModeEncryption = 0x00u, + + /// <summary> + /// Puts the cipher into decryption mode + /// </summary> + ModeDecryption = 0x01u, + + /// <summary> + /// Forces all internal memory to be freed when + /// the cipher is freed + /// </summary> + ZeroOnFree = 0x02u, + + /// <summary> + /// Disables mac verification during decryption operations, + /// by default nip44 macs are verified before the decryption + /// operation. + /// </summary> + MacNoVerify = 0x04u, + + /// <summary> + /// Allows allocated cipher instances to be reused multiple + /// times. Otherwise the cipher may only be used once after + /// allocation. + /// </summary> + Reusable = 0x08u, + + EncryptDefault = ModeEncryption | Reusable | ZeroOnFree, + DecryptDefault = ModeDecryption | Reusable | ZeroOnFree + } +} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCNip44EncryptionVersion.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipherVersion.cs index 0d5907a..763a5f4 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCNip44EncryptionVersion.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipherVersion.cs @@ -15,25 +15,22 @@ using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary; -namespace VNLib.Utils.Cryptography.Noscrypt +namespace VNLib.Utils.Cryptography.Noscrypt.Encryption { /// <summary> - /// The NIP44 encryption version used by the Nostr protocol + /// The Noscrypt utility cipher encryption + /// standard version /// </summary> - public sealed class NCNip44EncryptionVersion : INostrEncryptionVersion + public enum NoscryptCipherVersion : uint { /// <summary> - /// A static nip44 encryption version instance + /// Tells the cipher to use the NIP04 encryption standard /// </summary> - public static readonly NCNip44EncryptionVersion Instance = new(); + Nip04 = NC_ENC_VERSION_NIP04, - ///<inheritdoc/> - uint INostrEncryptionVersion.Version => NC_ENC_VERSION_NIP44; - - int INostrEncryptionVersion.GetMessageBufferSize(int dataSize) => Nip44Util.CalcFinalBufferSize(dataSize); - - ///<inheritdoc/> - int INostrEncryptionVersion.GetPayloadBufferSize(int dataSize) => Nip44Util.CalcBufferSize(dataSize); + /// <summary> + /// Tells the cipher to use the NIP44 encryption standard + /// </summary> + Nip44 = NC_ENC_VERSION_NIP44 } - } diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/INostrCrypto.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/INostrCrypto.cs index 49c0cc0..9b4d36c 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/INostrCrypto.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/INostrCrypto.cs @@ -15,6 +15,8 @@ using System; +using VNLib.Utils.Cryptography.Noscrypt.Encryption; + namespace VNLib.Utils.Cryptography.Noscrypt { public interface INostrCrypto @@ -39,6 +41,14 @@ namespace VNLib.Utils.Cryptography.Noscrypt bool ValidateSecretKey(ref readonly NCSecretKey secretKey); /// <summary> + /// Allocates a new cipher instance with the supplied options. + /// </summary> + /// <param name="version">The cipher specification version</param> + /// <param name="flags">The cipher initialziation flags</param> + /// <returns>The cipher instance</returns> + NoscryptCipher AllocCipher(NoscryptCipherVersion version, NoscryptCipherFlags flags); + + /// <summary> /// Signs the supplied data with the secret key and random32 nonce, then writes /// the message signature to the supplied sig64 buffer. /// </summary> @@ -74,91 +84,5 @@ namespace VNLib.Utils.Cryptography.Noscrypt uint dataSize, ref readonly byte sig64 ); - - /// <summary> - /// Computes a nip44 message authentication code (MAC) using the supplied key and payload. - /// </summary> - /// <param name="hmacKey32">The key returned during a - /// <see cref="Encrypt(ref readonly NCSecretKey, ref readonly NCPublicKey, ref readonly byte, ref readonly byte, ref byte, uint, ref byte)"/> - /// </param> - /// <param name="payload">A pointer to a buffer </param> - /// <param name="payloadSize">The size of the buffer to compute the mac of, in bytes</param> - /// <param name="hmacOut32">A pointer to the 32byte buffer to write the mac to</param> - /// <exception cref="ArgumentException"></exception> - /// <exception cref="ArgumentNullException"></exception> - void ComputeMac( - ref readonly byte hmacKey32, - ref readonly byte payload, - uint payloadSize, - ref byte hmacOut32 - ); - - /// <summary> - /// Verifies a nip44 message authentication code (MAC) against the supplied key and payload. - /// </summary> - /// <param name="secretKey">A pointer to the receiver's secret key</param> - /// <param name="publicKey">A pointer to senders the public key</param> - /// <param name="nonce32">A pointer to the 32byte nonce buffer</param> - /// <param name="mac32">A pointer to the 32byte message buffer</param> - /// <param name="payload">A pointer to the message buffer</param> - /// <param name="payloadSize">The size in bytes of the payload buffer</param> - /// <returns>True if the message authentication code (MAC) matches, false otherwise </returns> - /// <exception cref="ArgumentException"></exception> - /// <exception cref="ArgumentNullException"></exception> - bool VerifyMac( - ref readonly NCSecretKey secretKey, - ref readonly NCPublicKey publicKey, - ref readonly byte nonce32, - ref readonly byte mac32, - ref readonly byte payload, - uint payloadSize - ); - - /// <summary> - /// Encrypts a message using the supplied secret key, public key, and nonce. When this function - /// returns, the cipherText buffer will contain the encrypted message, and the hmacKeyOut32 buffer - /// will contain the key used to compute the message authentication code (MAC). - /// <para> - /// NOTE: The cipherText buffer must be at least as large as the plaintext buffer. The - /// size parameter must be the size of the number of bytes to encrypt. - /// </para> - /// </summary> - /// <param name="secretKey">A pointer to the receiver's secret key</param> - /// <param name="publicKey">A pointer to senders the public key</param> - /// <param name="nonce32">A pointer to the 32byte nonce used for message encryption</param> - /// <param name="plainText">A pointer to the plaintext buffer to encrypt</param> - /// <param name="cipherText">A pointer to the cyphertext buffer to write encrypted data to (must be as large or larger than the plaintext buffer)</param> - /// <param name="size">The size of the data to encrypt</param> - /// <param name="hmacKeyOut32"></param> - /// <exception cref="ArgumentException"></exception> - /// <exception cref="ArgumentNullException"></exception> - void EncryptNip44( - ref readonly NCSecretKey secretKey, - ref readonly NCPublicKey publicKey, - ref readonly byte nonce32, - ref readonly byte plainText, - ref byte cipherText, - uint size, - ref byte hmacKeyOut32 - ); - - /// <summary> - /// Decrypts a message using the supplied secret key, public key, and the original message - /// nonce. - /// </summary> - /// <param name="secretKey">A pointer to the receiver's secret key</param> - /// <param name="publicKey">A pointer to senders the public key</param> - /// <param name="nonce32">A pointer to the 32byte nonce used for message encryption</param> - /// <param name="plainText">A pointer to the plaintext buffer to write plaintext data to (must be as large or larger than the ciphertext buffer)</param> - /// <param name="cipherText">A pointer to the cyphertext buffer to read encrypted data from</param> - /// <param name="size">The size of the buffer to decrypt</param> - void DecryptNip44( - ref readonly NCSecretKey secretKey, - ref readonly NCPublicKey publicKey, - ref readonly byte nonce32, - ref readonly byte cipherText, - ref byte plainText, - uint size - ); } } diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/INostrEncryptionVersion.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/INostrEncryptionVersion.cs deleted file mode 100644 index 3a26466..0000000 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/INostrEncryptionVersion.cs +++ /dev/null @@ -1,43 +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/>. - -namespace VNLib.Utils.Cryptography.Noscrypt -{ - /// <summary> - /// Represents a message encryption version used by the Nostr protocol - /// </summary> - public interface INostrEncryptionVersion - { - /// <summary> - /// The noscrypt compatible encryption version - /// </summary> - internal uint Version { get; } - - /// <summary> - /// Calculates the required payload buffer size for the specified data size - /// </summary> - /// <param name="dataSize">The size of the input data</param> - /// <returns>The estimated size of the buffer required to complete the opeation</returns> - internal int GetPayloadBufferSize(int dataSize); - - /// <summary> - /// Calculates the required message buffer size for the specified data size - /// </summary> - /// <param name="dataSize">Plain text data size</param> - /// <returns>The estimated size of the buffer required to complete the opeation</returns> - internal int GetMessageBufferSize(int dataSize); - } - -} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCContext.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCContext.cs index 8f8c6b4..61128eb 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCContext.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCContext.cs @@ -33,7 +33,7 @@ namespace VNLib.Utils.Cryptography.Noscrypt /// </summary> public sealed class NCContext : SafeHandleZeroOrMinusOneIsInvalid { - private readonly IUnmangedHeap Heap; + internal readonly IUnmangedHeap Heap; /// <summary> /// The library this context was created from diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCNip04EncryptionVersion.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCNip04EncryptionVersion.cs deleted file mode 100644 index beb21c2..0000000 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCNip04EncryptionVersion.cs +++ /dev/null @@ -1,40 +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 static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary; - -namespace VNLib.Utils.Cryptography.Noscrypt -{ - /// <summary> - /// The NIP04 encryption version used by the Nostr protocol - /// </summary> - public sealed class NCNip04EncryptionVersion : INostrEncryptionVersion - { - /// <summary> - /// A static nip04 encryption version instance - /// </summary> - public static readonly NCNip04EncryptionVersion Instance = new(); - - ///<inheritdoc/> - uint INostrEncryptionVersion.Version => NC_ENC_VERSION_NIP04; - - ///<inheritdoc/> - int INostrEncryptionVersion.GetMessageBufferSize(int dataSize) => Nip04Util.CalcBufferSize(dataSize); - - ///<inheritdoc/> - int INostrEncryptionVersion.GetPayloadBufferSize(int dataSize) => Nip04Util.CalcBufferSize(dataSize); - } - -} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCUtil.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCUtil.cs index 49c66c1..307bbc1 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCUtil.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NCUtil.cs @@ -127,35 +127,34 @@ namespace VNLib.Utils.Cryptography.Noscrypt // Error code are only 8 bits, if an argument error occured, the // argument number will be in the next upper 8 bits - byte errorCode = (byte)(asPositive & 0xFF); + NCErrorCodes errorCode = (NCErrorCodes)(asPositive & 0xFF); byte argNumber = (byte)((asPositive >> 8) & 0xFF); switch (errorCode) { - case E_NULL_PTR: + case NCErrorCodes.E_NULL_PTR: RaiseNullArgExceptionForArgumentNumber<T>(argNumber); break; - case E_INVALID_ARG: + case NCErrorCodes.E_INVALID_ARG: RaiseArgExceptionForArgumentNumber<T>(argNumber); break; - case E_ARGUMENT_OUT_OF_RANGE: + case NCErrorCodes.E_ARGUMENT_OUT_OF_RANGE: RaiseOORExceptionForArgumentNumber<T>(argNumber); break; - case E_INVALID_CTX: + case NCErrorCodes.E_INVALID_CTX: throw new InvalidOperationException("The library context object is null or invalid"); - case E_OPERATION_FAILED: + case NCErrorCodes.E_OPERATION_FAILED: RaiseOperationFailedException(raiseOnFailure); break; - case E_VERSION_NOT_SUPPORTED: + case NCErrorCodes.E_VERSION_NOT_SUPPORTED: throw new NotSupportedException("The requested version is not supported"); default: if(raiseOnFailure) { - throw new InvalidOperationException($"The operation failed for an unknown reason, code: {errorCode:x}"); + throw new InvalidOperationException($"The operation failed with error, code: {errorCode} for arugment {argNumber:x}"); } break; - } } diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Nip04Util.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Nip04Util.cs deleted file mode 100644 index c1906f0..0000000 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Nip04Util.cs +++ /dev/null @@ -1,50 +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.Buffers.Text; - -using VNLib.Utils.Extensions; - -namespace VNLib.Utils.Cryptography.Noscrypt -{ - public static class Nip04Util - { - public static bool IsValidPayload(ReadOnlySpan<char> payload) - { - /* Iv is base64 encoded so it should be 33% larger than 16 byte iv */ - ReadOnlySpan<char> iv = payload.SliceAfterParam("?iv="); - return iv.Length > 20 && iv.Length <= 26; - } - - public static ReadOnlySpan<char> GetIV(ReadOnlySpan<char> payload) => payload.SliceAfterParam("?iv="); - - public static ReadOnlySpan<char> GetCipherText(ReadOnlySpan<char> payload) => payload.SliceBeforeParam("?iv="); - - public static int CalcBufferSize(int dataSize) - { - throw new NotImplementedException(); - } - - static readonly int MaxEncodedIvLength = Base64.GetMaxEncodedToUtf8Length(16); - - public static int CalcMessageBufferSize(int dataSize) - { - int bufSize = CalcBufferSize(dataSize); - return bufSize + "?iv=".Length + MaxEncodedIvLength; - } - } - -} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Nip44MessageSegments.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Nip44MessageSegments.cs deleted file mode 100644 index ddc2d68..0000000 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Nip44MessageSegments.cs +++ /dev/null @@ -1,36 +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; - -namespace VNLib.Utils.Cryptography.Noscrypt -{ - public readonly ref struct Nip44MessageSegments(ReadOnlySpan<byte> payload) - { - readonly ReadOnlySpan<byte> _payload = payload; - - public ReadOnlySpan<byte> Payload => _payload; - - public ReadOnlySpan<byte> Nonce => Nip44Util.GetNonceFromPayload(_payload); - - public ReadOnlySpan<byte> Ciphertext => Nip44Util.GetCiphertextFromPayload(_payload); - - public ReadOnlySpan<byte> Mac => Nip44Util.GetMacFromPayload(_payload); - - public ReadOnlySpan<byte> NonceAndCiphertext => Nip44Util.GetNonceAndCiphertext(_payload); - - public byte Version => Nip44Util.GetMessageVersion(_payload); - } -} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Nip44Util.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Nip44Util.cs deleted file mode 100644 index 2aebee1..0000000 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Nip44Util.cs +++ /dev/null @@ -1,190 +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.Buffers.Binary; -using System.Runtime.InteropServices; - -using VNLib.Utils.Memory; - -using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary; - -namespace VNLib.Utils.Cryptography.Noscrypt -{ - - /// <summary> - /// Provides a set of utility methods for working with the Noscrypt library - /// </summary> - public static class Nip44Util - { - /// <summary> - /// Calculates the required NIP44 encryption buffer size for - /// the specified input data size - /// </summary> - /// <param name="dataSize">The size (in bytes) of the encoded data to encrypt</param> - /// <returns>The exact size of the padded buffer output</returns> - public static int CalcBufferSize(int dataSize) - { - /* - * Taken from https://github.com/nostr-protocol/nips/blob/master/44.md - * - * Not gonna lie, kinda dumb branches. I guess they want to save space - * with really tiny messages... Dunno, but whatever RTFM - */ - - //Min message size is 32 bytes - int minSize = Math.Max(dataSize, 32); - - //find the next power of 2 that will fit the min size - int nexPower = 1 << ((int)Math.Log2(minSize - 1)) + 1; - - int chunk = nexPower <= 256 ? 32 : nexPower / 8; - - return (chunk * ((int)Math.Floor((double)((minSize - 1) / chunk)) + 1)) + sizeof(ushort); - } - - /// <summary> - /// Calculates the final buffer size required to hold the encrypted data - /// </summary> - /// <param name="dataSize">The size (in bytes) of plaintext data to encrypt</param> - /// <returns>The number of bytes required to store the final nip44 message</returns> - public static int CalcFinalBufferSize(int dataSize) - { - /* version + nonce + payload + mac */ - return CalcBufferSize(dataSize) + NC_ENCRYPTION_NONCE_SIZE + NC_ENCRYPTION_MAC_SIZE + 1; - } - - /// <summary> - /// Formats the plaintext data into a buffer that can be properly encrypted. - /// The output buffer must be zeroed, or can be zeroed using the - /// <paramref name="zeroOutput"/> parameter. Use <see cref="CalcBufferSize(uint)"/> - /// to determine the required output buffer size. - /// </summary> - /// <param name="plaintextData">A buffer containing plaintext data to copy to the output</param> - /// <param name="output">The output data buffer to format</param> - /// <param name="zeroOutput">A value that indicates if the buffer should be zeroed before use</param> - public static void FormatBuffer(ReadOnlySpan<byte> plaintextData, Span<byte> output, bool zeroOutput) - { - //First zero out the buffer - if (zeroOutput) - { - MemoryUtil.InitializeBlock(output); - } - - //Make sure the output buffer is large enough so we dont overrun it - ArgumentOutOfRangeException.ThrowIfLessThan(output.Length, plaintextData.Length + sizeof(ushort), nameof(output)); - - //Write the data size to the first 2 bytes - ushort dataSize = (ushort)plaintextData.Length; - BinaryPrimitives.WriteUInt16BigEndian(output, dataSize); - - //Copy the plaintext data to the output buffer after the data size - MemoryUtil.Memmove( - src: in MemoryMarshal.GetReference(plaintextData), - srcOffset: 0, - dst: ref MemoryMarshal.GetReference(output), - dstOffset: sizeof(ushort), - elementCount: (uint)plaintextData.Length - ); - - //We assume the remaining buffer is zeroed out - } - - public static void WriteNip44Message( - ReadOnlySpan<byte> payloadBuffer, - byte version, - ReadOnlySpan<byte> mac, - Span<byte> outBuffer - ) - { - int requiredBufferSize = CalcFinalBufferSize(payloadBuffer.Length); - - //Make sure the output buffer is large enough so we dont overrun it - ArgumentOutOfRangeException.ThrowIfLessThan(outBuffer.Length, requiredBufferSize, nameof(outBuffer)); - ArgumentOutOfRangeException.ThrowIfLessThan(mac.Length, NC_ENCRYPTION_MAC_SIZE, nameof(mac)); - - //Write the version number to the first byte - outBuffer[0] = version; - - //Copy the payload buffer to the output buffer after the version number - MemoryUtil.Memmove( - src: in MemoryMarshal.GetReference(payloadBuffer), - srcOffset: 0, - dst: ref MemoryMarshal.GetReference(outBuffer), - dstOffset: 1, - elementCount: (uint)payloadBuffer.Length - ); - - //Copy the mac to the end of the output buffer - MemoryUtil.Memmove( - src: in MemoryMarshal.GetReference(mac), - srcOffset: 0, - dst: ref MemoryMarshal.GetReference(outBuffer), - dstOffset: (uint)(requiredBufferSize - NC_ENCRYPTION_MAC_SIZE), - elementCount: NC_ENCRYPTION_MAC_SIZE - ); - } - - public static ReadOnlySpan<byte> GetNonceFromPayload(ReadOnlySpan<byte> message) - { - //The nonce is 32 bytes following the 1st byte version number of the message - return message.Slice(1, NC_ENCRYPTION_NONCE_SIZE); - } - - public static ReadOnlySpan<byte> GetCiphertextFromPayload(ReadOnlySpan<byte> message) - { - //Message is between the nonce and the trailing mac - int payloadSize = message.Length - (1 + NC_ENCRYPTION_NONCE_SIZE + NC_ENCRYPTION_MAC_SIZE); - return message.Slice(1 + NC_ENCRYPTION_NONCE_SIZE, payloadSize); - } - - public static ReadOnlySpan<byte> GetMacFromPayload(ReadOnlySpan<byte> message) - { - //The mac is the last 32 bytes of the message - return message[^NC_ENCRYPTION_MAC_SIZE..]; - } - - public static ReadOnlySpan<byte> GetNonceAndCiphertext(ReadOnlySpan<byte> message) - { - //The nonce is 32 bytes following the 1st byte version number of the message - return message.Slice(1, NC_ENCRYPTION_NONCE_SIZE + GetCiphertextFromPayload(message).Length); - } - - public static byte GetMessageVersion(ReadOnlySpan<byte> message) - { - //The first byte is the message version - return message[0]; - } - - public static ReadOnlySpan<byte> GetPlaintextMessage(ReadOnlySpan<byte> plaintextPayload) - { - ushort ptLength = BinaryPrimitives.ReadUInt16BigEndian(plaintextPayload); - return plaintextPayload.Slice(sizeof(ushort), ptLength); - } - - public static bool IsValidPlaintextMessage(ReadOnlySpan<byte> plaintextPayload) - { - ushort ptLength = BinaryPrimitives.ReadUInt16BigEndian(plaintextPayload); - return ptLength == plaintextPayload.Length - sizeof(ushort); - } - - public static Range GetPlaintextRange(ReadOnlySpan<byte> plaintextPayload) - { - ushort ptLength = BinaryPrimitives.ReadUInt16BigEndian(plaintextPayload); - return new Range(sizeof(ushort), ptLength); - } - } - -} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptExtensions.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptExtensions.cs index ccae190..e96ff96 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptExtensions.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptExtensions.cs @@ -24,168 +24,6 @@ namespace VNLib.Utils.Cryptography.Noscrypt public static class NoscryptExtensions { - public static void EncryptNip44( - this INostrCrypto lib, - ref readonly NCSecretKey secretKey, - ref readonly NCPublicKey publicKey, - ReadOnlySpan<byte> nonce32, - ReadOnlySpan<byte> plainText, - Span<byte> hmackKeyOut32, - Span<byte> cipherText - ) - { - ArgumentNullException.ThrowIfNull(lib); - - //Chacha requires the output buffer to be at-least the size of the input buffer - ArgumentOutOfRangeException.ThrowIfGreaterThan(plainText.Length, cipherText.Length, nameof(plainText)); - - //Nonce must be exactly 32 bytes - ArgumentOutOfRangeException.ThrowIfNotEqual(nonce32.Length, NC_ENCRYPTION_NONCE_SIZE, nameof(nonce32)); - - ArgumentOutOfRangeException.ThrowIfNotEqual(hmackKeyOut32.Length, NC_HMAC_KEY_SIZE, nameof(hmackKeyOut32)); - - //Encrypt data, use the plaintext buffer size as the data size - lib.EncryptNip44( - secretKey: in secretKey, - publicKey: in publicKey, - nonce32: in MemoryMarshal.GetReference(nonce32), - plainText: in MemoryMarshal.GetReference(plainText), - cipherText: ref MemoryMarshal.GetReference(cipherText), - size: (uint)plainText.Length, - hmacKeyOut32: ref MemoryMarshal.GetReference(hmackKeyOut32) - ); - } - - public static unsafe void EncryptNip44( - this INostrCrypto lib, - ref NCSecretKey secretKey, - ref NCPublicKey publicKey, - void* nonce32, - void* hmacKeyOut32, - void* plainText, - void* cipherText, - uint size - ) - { - ArgumentNullException.ThrowIfNull(plainText); - ArgumentNullException.ThrowIfNull(cipherText); - ArgumentNullException.ThrowIfNull(nonce32); - - //Spans are easer to forward references from pointers without screwing up arguments - lib.EncryptNip44( - secretKey: in secretKey, - publicKey: in publicKey, - nonce32: in Unsafe.AsRef<byte>(nonce32), - plainText: in Unsafe.AsRef<byte>(plainText), - cipherText: ref Unsafe.AsRef<byte>(cipherText), - size: size, - hmacKeyOut32: ref Unsafe.AsRef<byte>(hmacKeyOut32) - ); - } - - - public static void DecryptNip44( - this INostrCrypto lib, - ref readonly NCSecretKey secretKey, - ref readonly NCPublicKey publicKey, - ReadOnlySpan<byte> nonce32, - ReadOnlySpan<byte> cipherText, - Span<byte> plainText - ) - { - ArgumentNullException.ThrowIfNull(lib); - - //Chacha requires the output buffer to be at-least the size of the input buffer - ArgumentOutOfRangeException.ThrowIfGreaterThan(cipherText.Length, plainText.Length, nameof(cipherText)); - - //Nonce must be exactly 32 bytes - ArgumentOutOfRangeException.ThrowIfNotEqual(nonce32.Length, 32, nameof(nonce32)); - - //Decrypt data, use the ciphertext buffer size as the data size - lib.DecryptNip44( - secretKey: in secretKey, - publicKey: in publicKey, - nonce32: in MemoryMarshal.GetReference(nonce32), - cipherText: in MemoryMarshal.GetReference(cipherText), - plainText: ref MemoryMarshal.GetReference(plainText), - size: (uint)cipherText.Length - ); - } - - public static unsafe void DecryptNip44( - this INostrCrypto lib, - ref readonly NCSecretKey secretKey, - ref readonly NCPublicKey publicKey, - void* nonce32, - void* cipherText, - void* plainText, - uint size - ) - { - ArgumentNullException.ThrowIfNull(nonce32); - ArgumentNullException.ThrowIfNull(cipherText); - ArgumentNullException.ThrowIfNull(plainText); - - //Spans are easer to forward references from pointers without screwing up arguments - DecryptNip44( - lib: lib, - secretKey: in secretKey, - publicKey: in publicKey, - nonce32: new Span<byte>(nonce32, NC_ENCRYPTION_NONCE_SIZE), - cipherText: new Span<byte>(cipherText, (int)size), - plainText: new Span<byte>(plainText, (int)size) - ); - } - - public static bool VerifyMac( - this INostrCrypto lib, - ref readonly NCSecretKey secretKey, - ref readonly NCPublicKey publicKey, - ReadOnlySpan<byte> nonce32, - ReadOnlySpan<byte> mac32, - ReadOnlySpan<byte> payload - ) - { - ArgumentNullException.ThrowIfNull(lib); - ArgumentOutOfRangeException.ThrowIfZero(payload.Length, nameof(payload)); - ArgumentOutOfRangeException.ThrowIfNotEqual(nonce32.Length, NC_ENCRYPTION_NONCE_SIZE, nameof(nonce32)); - ArgumentOutOfRangeException.ThrowIfNotEqual(mac32.Length, NC_ENCRYPTION_MAC_SIZE, nameof(mac32)); - - //Verify the HMAC - return lib.VerifyMac( - secretKey: in secretKey, - publicKey: in publicKey, - nonce32: in MemoryMarshal.GetReference(nonce32), - mac32: in MemoryMarshal.GetReference(mac32), - payload: in MemoryMarshal.GetReference(payload), - payloadSize: (uint)payload.Length - ); - } - - public static unsafe bool VerifyMac( - this INostrCrypto lib, - ref readonly NCSecretKey secretKey, - ref readonly NCPublicKey publicKey, - void* nonce32, - void* mac32, - void* payload, - uint payloadSize - ) - { - ArgumentNullException.ThrowIfNull(nonce32); - ArgumentNullException.ThrowIfNull(mac32); - ArgumentNullException.ThrowIfNull(payload); - - return lib.VerifyMac( - secretKey: in secretKey, - publicKey: in publicKey, - nonce32: in Unsafe.AsRef<byte>(nonce32), - mac32: in Unsafe.AsRef<byte>(mac32), - payload: in Unsafe.AsRef<byte>(payload), - payloadSize: payloadSize - ); - } - public static void SignData( this INostrCrypto lib, ref readonly NCSecretKey secKey, diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptLibrary.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptLibrary.cs index 108a713..35c6a49 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptLibrary.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptLibrary.cs @@ -16,10 +16,12 @@ using System; using System.Diagnostics; using System.Runtime.InteropServices; + using VNLib.Utils.Memory; using VNLib.Utils.Native; using VNLib.Utils.Extensions; +using VNLib.Utils.Cryptography.Noscrypt.Random; using VNLib.Utils.Cryptography.Noscrypt.@internal; using NCResult = System.Int64; @@ -39,7 +41,6 @@ namespace VNLib.Utils.Cryptography.Noscrypt //Constant values match the noscrypt.h header public const int NC_SEC_KEY_SIZE = 0x20; public const int NC_SEC_PUBKEY_SIZE = 0x20; - public const int NC_ENCRYPTION_NONCE_SIZE = 0x20; public const int NC_PUBKEY_SIZE = 0x20; public const int NC_SIGNATURE_SIZE = 0x40; public const int NC_CONV_KEY_SIZE = 0x20; @@ -54,19 +55,37 @@ namespace VNLib.Utils.Cryptography.Noscrypt public const uint NC_ENC_VERSION_NIP44 = 0x00000002c; public const uint NC_ENC_SET_VERSION = 0x01u; - public const uint NC_ENC_SET_NIP44_NONCE = 0x02u; + public const uint NC_ENC_SET_IV = 0x02u; public const uint NC_ENC_SET_NIP44_MAC_KEY = 0x03u; public const uint NC_ENC_SET_NIP04_KEY = 0x04u; - public const uint NC_ENC_SET_NIP04_IV = 0x05u; - //Noscrypt error codes public const NCResult NC_SUCCESS = 0x00; - public const byte E_NULL_PTR = 0x01; - public const byte E_INVALID_ARG = 0x02; - public const byte E_INVALID_CTX = 0x03; - public const byte E_ARGUMENT_OUT_OF_RANGE = 0x04; - public const byte E_OPERATION_FAILED = 0x05; - public const byte E_VERSION_NOT_SUPPORTED = 0x06; + + public enum NCErrorCodes : long + { + NC_SUCCESS = 0, + + //Generic argument related errors + E_NULL_PTR = 1, + E_INVALID_ARG = 2, + E_INVALID_CTX = 3, + E_ARGUMENT_OUT_OF_RANGE = 4, + E_OPERATION_FAILED = 5, + E_VERSION_NOT_SUPPORTED = 6, + + //Cipher errors + E_CIPHER_INVALID_FORMAT = 11, + E_CIPHER_BAD_NONCE = 12, + E_CIPHER_MAC_INVALID = 13, + E_CIPHER_NO_OUTPUT = 14, + E_CIPHER_BAD_INPUT = 15, + E_CIPHER_BAD_INPUT_SIZE = 16 + } + + //Cipher flags + public const uint NC_UTIL_CIPHER_MODE = 0x01u; + + private readonly FunctionTable _functions = FunctionTable.BuildFunctionTable(Library); diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptSigner.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptSigner.cs index 586fa46..c81790b 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptSigner.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NoscryptSigner.cs @@ -14,7 +14,7 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. using System; - +using VNLib.Utils.Cryptography.Noscrypt.Random; using VNLib.Utils.Extensions; using VNLib.Utils.Memory; diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NostrCrypto.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NostrCrypto.cs index 36e2381..1e833d2 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NostrCrypto.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NostrCrypto.cs @@ -18,13 +18,13 @@ using System.Runtime.CompilerServices; using System.Diagnostics.CodeAnalysis; using VNLib.Utils.Cryptography.Noscrypt.@internal; +using VNLib.Utils.Cryptography.Noscrypt.Encryption; using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary; using NCResult = System.Int64; namespace VNLib.Utils.Cryptography.Noscrypt { - /// <summary> /// A default implementation of the <see cref="INostrCrypto"/> interface /// </summary> @@ -39,78 +39,7 @@ namespace VNLib.Utils.Cryptography.Noscrypt private ref readonly FunctionTable Functions => ref context.Library.Functions; ///<inheritdoc/> - public void DecryptNip44( - ref readonly NCSecretKey secretKey, - ref readonly NCPublicKey publicKey, - ref readonly byte nonce32, - ref readonly byte cipherText, - ref byte plainText, - uint size - ) - { - Check(); - - ThrowIfNullRef(in nonce32, nameof(nonce32)); - - fixed (NCSecretKey* pSecKey = &secretKey) - fixed (NCPublicKey* pPubKey = &publicKey) - fixed (byte* pCipherText = &cipherText, pTextPtr = &plainText, pNonce = &nonce32) - { - NCEncryptionArgs data = new(); - - //Version set first otherwise errors will occur - SetEncProperty(&data, NC_ENC_SET_VERSION, NC_ENC_VERSION_NIP44); - //Only the nonce must be set, the hmac key is not needed for decryption - SetEncPropertyEx(&data, NC_ENC_SET_NIP44_NONCE, pNonce, NC_ENCRYPTION_NONCE_SIZE); - SetEncData(&data, pTextPtr, pCipherText, size); - - NCResult result = Functions.NCDecrypt.Invoke(context.DangerousGetHandle(), pSecKey, pPubKey, &data); - NCUtil.CheckResult<FunctionTable.NCDecryptDelegate>(result, true); - } - } - - ///<inheritdoc/> - public void EncryptNip44( - ref readonly NCSecretKey secretKey, - ref readonly NCPublicKey publicKey, - ref readonly byte nonce32, - ref readonly byte plainText, - ref byte cipherText, - uint size, - ref byte hmackKeyOut32 - ) - { - Check(); - - ThrowIfNullRef(in nonce32, nameof(nonce32)); - - fixed (NCSecretKey* pSecKey = &secretKey) - fixed (NCPublicKey* pPubKey = &publicKey) - fixed (byte* pCipherText = &cipherText, - pTextPtr = &plainText, - pHmacKeyOut = &hmackKeyOut32, - pNonce = &nonce32 - ) - { - NCEncryptionArgs data = new(); - - /* - * Use the extended api to set properties correctly and validate them. - * - * The version MUST be set before continuing to set properties - * - * Since pointers are used, they must be only be set/accessed inside - * this fixed statement. - */ - SetEncProperty(&data, NC_ENC_SET_VERSION, NC_ENC_VERSION_NIP44); - SetEncPropertyEx(&data, NC_ENC_SET_NIP44_MAC_KEY, pHmacKeyOut, NC_HMAC_KEY_SIZE); - SetEncPropertyEx(&data, NC_ENC_SET_NIP44_NONCE, pNonce, NC_ENCRYPTION_NONCE_SIZE); - SetEncData(&data, pTextPtr, pCipherText, size); - - NCResult result = Functions.NCEncrypt.Invoke(context.DangerousGetHandle(), pSecKey, pPubKey, &data); - NCUtil.CheckResult<FunctionTable.NCEncryptDelegate>(result, true); - } - } + public NoscryptCipher AllocCipher(NoscryptCipherVersion version, NoscryptCipherFlags flags) => new (context, version, flags); ///<inheritdoc/> public void GetPublicKey(ref readonly NCSecretKey secretKey, ref NCPublicKey publicKey) @@ -192,63 +121,6 @@ namespace VNLib.Utils.Cryptography.Noscrypt } } - ///<inheritdoc/> - public bool VerifyMac( - ref readonly NCSecretKey secretKey, - ref readonly NCPublicKey publicKey, - ref readonly byte nonce32, - ref readonly byte mac32, - ref readonly byte payload, - uint payloadSize - ) - { - Check(); - - //Check pointers we need to use - ThrowIfNullRef(in nonce32, nameof(nonce32)); - ThrowIfNullRef(in mac32, nameof(mac32)); - ThrowIfNullRef(in payload, nameof(payload)); - - fixed (NCSecretKey* pSecKey = &secretKey) - fixed (NCPublicKey* pPubKey = &publicKey) - fixed (byte* pPayload = &payload, pMac = &mac32, pNonce = &nonce32) - { - - NCMacVerifyArgs args = new() - { - payloadSize = payloadSize, - payload = pPayload, - mac32 = pMac, - nonce32 = pNonce - }; - - //Exec and bypass failure - NCResult result = Functions.NCVerifyMac.Invoke(context.DangerousGetHandle(), pSecKey, pPubKey, &args); - NCUtil.CheckResult<FunctionTable.NCVerifyMacDelegate>(result, false); - - //Result should be success if the hmac is valid - return result == NC_SUCCESS; - } - } - - ///<inheritdoc/> - public void ComputeMac( - ref readonly byte hmacKey32, - ref readonly byte payload, - uint payloadSize, - ref byte hmacOut32 - ) - { - Check(); - - //Library will check for null pointers, since they are all arguments - fixed (byte* pKey = &hmacKey32, pPayload = &payload, pOut = &hmacOut32) - { - NCResult result = Functions.NCComputeMac.Invoke(context.DangerousGetHandle(), pKey, pPayload, payloadSize, pOut); - NCUtil.CheckResult<FunctionTable.NCComputeMacDelegate>(result, true); - } - } - #if DEBUG /// <summary> @@ -275,33 +147,6 @@ namespace VNLib.Utils.Cryptography.Noscrypt } #endif - - - private void SetEncPropertyEx(NCEncryptionArgs* args, uint prop, byte* value, uint valueLen) - { - NCResult result = Functions.NCSetEncryptionPropertyEx(args, prop, value, valueLen); - NCUtil.CheckResult<FunctionTable.NCSetEncryptionPropertyExDelegate>(result, true); - } - - private void SetEncProperty(NCEncryptionArgs* args, uint prop, uint value) - { - NCResult result = Functions.NCSetEncryptionProperty(args, prop, value); - NCUtil.CheckResult<FunctionTable.NCSetEncryptionPropertyExDelegate>(result, true); - } - - private void SetEncData(NCEncryptionArgs* args, byte* input, byte* output, uint dataLen) - { - /* - * WARNING: - * For now this a short-cut for setting the input and output data pointers - * technically this still works and avoids the PInvoke call, but this may - * change in the future. - */ - args->dataSize = dataLen; - args->inputData = input; - args->outputData = output; - } - ///<inheritdoc/> protected override void Free() { diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NostrMessageCipher.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NostrMessageCipher.cs deleted file mode 100644 index 918d196..0000000 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NostrMessageCipher.cs +++ /dev/null @@ -1,423 +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.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Security.Authentication; - -using VNLib.Utils.Memory; - -using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary; - -namespace VNLib.Utils.Cryptography.Noscrypt -{ - - public sealed class NostrMessageCipher(INostrCrypto lib, INostrEncryptionVersion version) : VnDisposeable - { - const int Nip44MaxMessageSize = 65603; - - private readonly INostrCrypto library = lib; - - private NCSecretKey _fromKey; - private NCPublicKey _toKey; - private Buffer32 _nonce32; - private Buffer32 _mac32; - - /// <summary> - /// The message encryption version used by this instance - /// </summary> - public uint Version { get; } = version.Version; - - /// <summary> - /// The message nonce created during encryption event - /// </summary> - public unsafe Span<byte> Nonce => MemoryMarshal.CreateSpan(ref GetNonceRef(), sizeof(Buffer32)); - - /// <summary> - /// The message MAC set during encryption, and required for decryption - /// </summary> - public unsafe Span<byte> Mac => MemoryMarshal.CreateSpan(ref GetMacRef(), sizeof(Buffer32)); - - /// <summary> - /// Gets the size of the buffer required to encrypt the specified data size - /// </summary> - /// <param name="dataSize">The size of the message raw plaintext message to send</param> - /// <returns>The minimum number of bytes required for message encryption output</returns> - /// <exception cref="NotSupportedException"></exception> - public int GetPayloadBufferSize(int dataSize) - => version.GetPayloadBufferSize(dataSize); - - /// <summary> - /// Gets the size of the buffer required to hold the full encrypted message data - /// for the encryption version used - /// </summary> - /// <param name="dataSize">The plaintext data size</param> - /// <returns>The estimated size of the output buffer</returns> - public int GetMessageBufferSize(int dataSize) - => version.GetMessageBufferSize(dataSize); - - /// <summary> - /// Sets the encryption secret key for the message - /// </summary> - /// <param name="secKey">The secret key buffer</param> - /// <returns>The current instance for chaining</returns> - /// <exception cref="ArgumentException"></exception> - public NostrMessageCipher SetSecretKey(ReadOnlySpan<byte> secKey) - => SetSecretKey(in NCUtil.AsSecretKey(secKey)); - - /// <summary> - /// Sets the encryption secret key for the message - /// </summary> - /// <param name="secKey">The secret key structure to copy</param> - /// <returns>The current instance for chaining</returns> - /// <exception cref="ArgumentException"></exception> - public NostrMessageCipher SetSecretKey(ref readonly NCSecretKey secKey) - { - MemoryUtil.CloneStruct(in secKey, ref _fromKey); - return this; - } - - /// <summary> - /// Assigns the public key used to encrypt the message as the - /// receiver of the message - /// </summary> - /// <param name="pubKey">The user's public key receiving the message</param> - /// <returns>The current instance for chaining</returns> - /// <exception cref="ArgumentException"></exception> - public NostrMessageCipher SetPublicKey(ReadOnlySpan<byte> pubKey) - => SetPublicKey(in NCUtil.AsPublicKey(pubKey)); - - /// <summary> - /// Assigns the public key used to encrypt the message as the - /// receiver of the message - /// </summary> - /// <param name="pubKey">The user's public key receiving the message</param> - /// <returns>The current instance for chaining</returns> - /// <exception cref="ArgumentException"></exception> - public NostrMessageCipher SetPublicKey(ref readonly NCPublicKey pubKey) - { - MemoryUtil.CloneStruct(in pubKey, ref _toKey); - return this; - } - - /// <summary> - /// Assigns the nonce to the message. Must be <see cref="NC_ENCRYPTION_NONCE_SIZE"/> - /// in length - /// </summary> - /// <param name="nonce">The nonce value to copy</param> - /// <returns>The current instance for chaining</returns> - /// <exception cref="ArgumentException"></exception> - public NostrMessageCipher SetNonce(ReadOnlySpan<byte> nonce) - { - MemoryUtil.CopyStruct(nonce, ref _nonce32); - return this; - } - - /// <summary> - /// Assigns a random nonce using the specified random source - /// </summary> - /// <param name="rng">The random source to genrate a random nonce from</param> - /// <returns>The current instance for chaining</returns> - public NostrMessageCipher SetRandomNonce(IRandomSource rng) - { - rng.GetRandomBytes(Nonce); - return this; - } - - /// <summary> - /// Configures a 32 byte mac for the message for nip44 decryption - /// </summary> - /// <param name="mac">The message mac</param> - /// <returns>The current instance for chaining</returns> - public NostrMessageCipher SetMac(ReadOnlySpan<byte> mac) - { - MemoryUtil.CopyStruct(mac, ref _mac32); - return this; - } - - /// <summary> - /// Decrypts a full nostr encrypted message and writes the plaintext - /// data to the output buffer - /// </summary> - /// <param name="message">The nostr message buffer to decrypt</param> - /// <param name="plaintext">The output plaintext buffer</param> - /// <returns>The number of bytes written the the plaintext buffer</returns> - /// <exception cref="FormatException"></exception> - /// <exception cref="NotSupportedException"></exception> - public int DecryptMessage(ReadOnlySpan<byte> message, Span<byte> plaintext) - { - return Version switch - { - NC_ENC_VERSION_NIP44 => DecryptNip44Message(message, plaintext), - _ => throw new NotSupportedException("NIP04 encryption is not supported"), - }; - } - - /// <summary> - /// Encrypts the plaintext message and writes the encrypted message to the - /// specified buffer. The output matches the format of the full nostr message - /// for the specified encryption version - /// </summary> - /// <param name="plaintext">The plaintext data to be encrypted</param> - /// <param name="message">The buffer to write the encrypted message data to</param> - /// <returns>The number of bytes written to the message buffer</returns> - /// <exception cref="NotSupportedException"></exception> - public int EncryptMessage(ReadOnlySpan<byte> plaintext, Span<byte> message) - { - return Version switch - { - NC_ENC_VERSION_NIP44 => EncryptNip44Message(plaintext, message), - _ => throw new NotSupportedException("NIP04 encryption is not supported"), - }; - } - - private int EncryptNip44Message(ReadOnlySpan<byte> plaintext, Span<byte> message) - { - int minRequiredOutSize = Nip44Util.CalcFinalBufferSize(plaintext.Length); - - ArgumentOutOfRangeException.ThrowIfZero(plaintext.Length, nameof(plaintext)); - ArgumentOutOfRangeException.ThrowIfLessThan(message.Length, minRequiredOutSize, nameof(message)); - - ForwardOnlyWriter<byte> messageWriter = new(message); - - // From spec -> concat(version, nonce, ciphertext, mac) - messageWriter.Append(0x02); // Version - messageWriter.Append<byte>(Nonce); // nonce - - //Encrypt plaintext and write directly the message buffer - int written = EncryptPayload(plaintext, messageWriter.Remaining); - - messageWriter.Advance(written); - - //Append the message mac, it was writen after the encryption operation - messageWriter.Append<byte>(Mac); - - return messageWriter.Written; - } - - /// <summary> - /// Encrypts the plaintext message and writes the encrypted message to the - /// specified buffer, along with a 32 byte mac of the message - /// </summary> - /// <param name="plaintext">The plaintext data to encrypt</param> - /// <param name="message">The message output buffer to write encrypted data to</param> - /// <param name="macOut32">A buffer to write the computed message mac to</param> - /// <returns>The number of bytes writtn to the message output buffer</returns> - /// <remarks> - /// The message buffer must be at-least the size of the output buffer, and it is not - /// initialized before the encryption operation. - /// </remarks> - /// <exception cref="ArgumentOutOfRangeException"></exception> - public int EncryptPayload(ReadOnlySpan<byte> plaintext, Span<byte> message) - { - return Version switch - { - NC_ENC_VERSION_NIP44 => EncryptNip44(plaintext, message), - _ => throw new NotSupportedException("NIP04 encryption is not supported"), - }; - } - - private int EncryptNip44(ReadOnlySpan<byte> plaintext, Span<byte> message) - { - int payloadSize = GetPayloadBufferSize(plaintext.Length); - - ArgumentOutOfRangeException.ThrowIfZero(plaintext.Length, nameof(plaintext)); - ArgumentOutOfRangeException.ThrowIfZero(message.Length, nameof(message)); - ArgumentOutOfRangeException.ThrowIfLessThan(message.Length, payloadSize, nameof(message)); - - /* - * Alloc temp buffer to copy formatted payload to data to for the encryption - * operation. Encryption will write directly to the message buffer - */ - - using UnsafeMemoryHandle<byte> ptPayloadBuf = MemoryUtil.UnsafeAllocNearestPage<byte>(payloadSize, true); - using UnsafeMemoryHandle<byte> hmacKeyBuf = MemoryUtil.UnsafeAlloc<byte>(NC_HMAC_KEY_SIZE, true); - - Debug.Assert(hmacKeyBuf.Length == NC_HMAC_KEY_SIZE); - - Nip44Util.FormatBuffer(plaintext, ptPayloadBuf.Span, false); - - library.EncryptNip44( - secretKey: in _fromKey, - publicKey: in _toKey, - nonce32: in GetNonceRef(), - plainText: in ptPayloadBuf.GetReference(), - cipherText: ref MemoryMarshal.GetReference(message), - size: (uint)payloadSize, //IMPORTANT: Format buffer will pad the buffer to the exact size - hmacKeyOut32: ref hmacKeyBuf.GetReference() //Must set the hmac key buffer - ); - - - //Compute message mac, key should be set by the encryption operation - library.ComputeMac( - hmacKey32: in hmacKeyBuf.GetReference(), - payload: in MemoryMarshal.GetReference(message), - payloadSize: (uint)payloadSize, //Again set exact playload size - hmacOut32: ref GetMacRef() - ); - - //Clear buffers - MemoryUtil.InitializeBlock(ref hmacKeyBuf.GetReference(), hmacKeyBuf.IntLength); - MemoryUtil.InitializeBlock(ref ptPayloadBuf.GetReference(), ptPayloadBuf.IntLength); - - return payloadSize; - } - - private int DecryptNip44Message(ReadOnlySpan<byte> message, Span<byte> plaintext) - { - //Full Nip44 messages must be at-least 99 bytes in length - ArgumentOutOfRangeException.ThrowIfLessThan(message.Length, 99, nameof(message)); - ArgumentOutOfRangeException.ThrowIfGreaterThan(message.Length, Nip44MaxMessageSize, nameof(message)); - - //Message decoder used to get the nip44 message segments - Nip44MessageSegments msg = new(message); - - if (msg.Version != 0x02) - { - return 0; - } - - SetNonce(msg.Nonce); - SetMac(msg.Mac); - - //Temporary buffer to write decrypted plaintext data to - using UnsafeMemoryHandle<byte> plaintextBuffer = MemoryUtil.UnsafeAllocNearestPage<byte>(msg.Ciphertext.Length, true); - - int written = DecryptPayload(msg.Ciphertext, plaintextBuffer.Span); - - Span<byte> ptOut = plaintextBuffer.AsSpan(0, written); - - //Must check message bounds before returning a range - if (!Nip44Util.IsValidPlaintextMessage(ptOut)) - { - throw new FormatException("Plaintext data was not properly encrypted because it was not properly formatted or decryption failed"); - } - - Range msgRange = Nip44Util.GetPlaintextRange(ptOut); - Debug.Assert(msgRange.Start.Value > 0); - Debug.Assert(msgRange.End.Value > 0); - - int ptLength = msgRange.End.Value - msgRange.Start.Value; - - Debug.Assert(ptLength > 0); - - //Write the wrapped plaintext (unpadded) to the output plaintext buffer - MemoryUtil.Memmove( - src: in plaintextBuffer.GetReference(), - srcOffset: (uint)msgRange.Start.Value, - dst: ref MemoryMarshal.GetReference(plaintext), - dstOffset: 0, - elementCount: (uint)ptLength - ); - - return ptLength; - } - - /// <summary> - /// Decrypts a nostr encrypted message in it's full binary from. - /// </summary> - /// <param name="payload"></param> - /// <param name="plaintext"></param> - /// <returns>The number of bytes written to the output buffer, or an error code if an error occured during the encryption</returns> - /// <exception cref="NotSupportedException"></exception> - public int DecryptPayload(ReadOnlySpan<byte> payload, Span<byte> plaintext) - { - return Version switch - { - NC_ENC_VERSION_NIP44 => DecryptNip44Payload(payload, plaintext), - _ => throw new NotSupportedException("NIP04 encryption is not supported"), - }; - } - - private int DecryptNip44Payload(ReadOnlySpan<byte> message, Span<byte> plaintext) - { - ArgumentOutOfRangeException.ThrowIfZero(message.Length, nameof(message)); - ArgumentOutOfRangeException.ThrowIfZero(plaintext.Length, nameof(plaintext)); - - //Validate the incoming message for a nip44 message - ArgumentOutOfRangeException.ThrowIfLessThan(message.Length, 32, nameof(message)); - ArgumentOutOfRangeException.ThrowIfGreaterThan(message.Length, Nip44MaxMessageSize, nameof(message)); - - //Plaintext buffer must be large enough to hold the decrypted message - ArgumentOutOfRangeException.ThrowIfLessThan(plaintext.Length, message.Length, nameof(plaintext)); - - bool macValid = library.VerifyMac( - in _fromKey, - in _toKey, - nonce32: in GetNonceRef(), - mac32: in GetMacRef(), - payload: ref MemoryMarshal.GetReference(message), - (uint)message.Length - ); - - if (!macValid) - { - throw new AuthenticationException("Message MAC is invalid"); - } - - library.DecryptNip44( - in _fromKey, - in _toKey, - nonce32: in GetNonceRef(), - cipherText: in MemoryMarshal.GetReference(message), - plainText: ref MemoryMarshal.GetReference(plaintext), - (uint)message.Length - ); - - //Return the number of bytes written to the output buffer - return message.Length; - } - - private unsafe ref byte GetNonceRef() - { - Debug.Assert(NC_ENCRYPTION_NONCE_SIZE == sizeof(Buffer32)); - return ref Unsafe.As<Buffer32, byte>(ref _nonce32); - } - - private unsafe ref byte GetMacRef() - { - Debug.Assert(NC_ENCRYPTION_MAC_SIZE == sizeof(Buffer32)); - return ref Unsafe.As<Buffer32, byte>(ref _mac32); - } - - protected override void Free() - { - //Zero all internal memory - MemoryUtil.ZeroStruct(ref _fromKey); - MemoryUtil.ZeroStruct(ref _toKey); - MemoryUtil.ZeroStruct(ref _nonce32); - MemoryUtil.ZeroStruct(ref _mac32); - } - - /// <summary> - /// Initializes a new <see cref="NostrMessageCipher"/> with the nip44 encryption - /// method. - /// </summary> - /// <param name="lib">The nostr crypto implementation instance to use</param> - /// <returns>The intialzied message instance</returns> - public static NostrMessageCipher CreateNip44Cipher(INostrCrypto lib) - => new(lib, NCNip44EncryptionVersion.Instance); - - - [StructLayout(LayoutKind.Sequential, Size = 32)] - unsafe struct Buffer32 - { - fixed byte value[32]; - } - } - -} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/IRandomSource.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Random/IRandomSource.cs index 5c5f2ac..84430a0 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/IRandomSource.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Random/IRandomSource.cs @@ -15,7 +15,7 @@ using System; -namespace VNLib.Utils.Cryptography.Noscrypt +namespace VNLib.Utils.Cryptography.Noscrypt.Random { /// <summary> /// Represents a generator for random data, that fills abinary buffer with random bytes diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NcFallbackRandom.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Random/NcFallbackRandom.cs index 0949ad8..5e0675e 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/NcFallbackRandom.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Random/NcFallbackRandom.cs @@ -17,18 +17,18 @@ using System; using VNLib.Hashing; -namespace VNLib.Utils.Cryptography.Noscrypt +namespace VNLib.Utils.Cryptography.Noscrypt.Random { /// <summary> /// A fallback crypographic random source used for default /// rng if you wish /// </summary> - public sealed class NcFallbackRandom : IRandomSource + public sealed class NCFallbackRandom : IRandomSource { /// <summary> /// Gets the shared instance of the fallback random source /// </summary> - public static NcFallbackRandom Shared { get; } = new NcFallbackRandom(); + public static NCFallbackRandom Shared { get; } = new NCFallbackRandom(); /// <inheritdoc/> public void GetRandomBytes(Span<byte> buffer) => RandomHash.GetRandomBytes(buffer); diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/UnmanagedRandomSource.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Random/UnmanagedRandomSource.cs index 91ff64b..73ff374 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/UnmanagedRandomSource.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Random/UnmanagedRandomSource.cs @@ -16,11 +16,10 @@ using System; using System.Runtime.InteropServices; -using VNLib.Utils; using VNLib.Utils.Native; using VNLib.Utils.Extensions; -namespace VNLib.Utils.Cryptography.Noscrypt +namespace VNLib.Utils.Cryptography.Noscrypt.Random { /// <summary> diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/VNLib.Utils.Cryptography.Noscrypt.csproj b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/VNLib.Utils.Cryptography.Noscrypt.csproj index 7e7f5de..4d1868c 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/VNLib.Utils.Cryptography.Noscrypt.csproj +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/VNLib.Utils.Cryptography.Noscrypt.csproj @@ -21,8 +21,8 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="VNLib.Hashing.Portable" Version="0.1.0-ci0122" /> - <PackageReference Include="VNLib.Utils" Version="0.1.0-ci0122" /> + <PackageReference Include="VNLib.Hashing.Portable" Version="0.1.0-ci0124" /> + <PackageReference Include="VNLib.Utils" Version="0.1.0-ci0124" /> </ItemGroup> </Project> diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/FunctionTable.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/FunctionTable.cs index 17b66b2..0cda5e2 100644 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/FunctionTable.cs +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/FunctionTable.cs @@ -34,13 +34,16 @@ namespace VNLib.Utils.Cryptography.Noscrypt.@internal public readonly NCValidateSecretKeyDelegate NCValidateSecretKey; public readonly NCSignDataDelegate NCSignData; public readonly NCVerifyDataDelegate NCVerifyData; - public readonly NCEncryptDelegate NCEncrypt; - public readonly NCDecryptDelegate NCDecrypt; - public readonly NCVerifyMacDelegate NCVerifyMac; - public readonly NCComputeMacDelegate NCComputeMac; - public readonly NCSetEncryptionDataDelegate NCSetEncryptionData; - public readonly NCSetEncryptionPropertyDelegate NCSetEncryptionProperty; - public readonly NCSetEncryptionPropertyExDelegate NCSetEncryptionPropertyEx; + public readonly NCUtilCipherAllocDelegate NCUtilCipherAlloc; + public readonly NCUtilCipherFreeDelegate NCUtilCipherFree; + public readonly NCUtilCipherInitDelegate NCUtilCipherInit; + public readonly NCUtilCipherGetFlagsDelegate NCUtilCipherGetFlags; + public readonly NCUtilCipherGetOutputSizeDelegate NCUtilCipherGetOutputSize; + public readonly NCUtilCipherReadOutputDelegate NCUtilCipherReadOutput; + public readonly NCUtilCipherSetPropertyDelegate NCUtilCipherSetProperty; + public readonly NCUtilCipherUpdateDelegate NCUtilCipherUpdate; + public readonly NCUtilCipherGetIvSizeDelegate NCUtilCipherGetIvSize; + #if DEBUG public readonly NCGetConversationKeyDelegate NCGetConversationKey; @@ -59,13 +62,17 @@ namespace VNLib.Utils.Cryptography.Noscrypt.@internal NCVerifyData = library.DangerousGetFunction<NCVerifyDataDelegate>(); NCSignData = library.DangerousGetFunction<NCSignDataDelegate>(); NCVerifyData = library.DangerousGetFunction<NCVerifyDataDelegate>(); - NCEncrypt = library.DangerousGetFunction<NCEncryptDelegate>(); - NCDecrypt = library.DangerousGetFunction<NCDecryptDelegate>(); - NCVerifyMac = library.DangerousGetFunction<NCVerifyMacDelegate>(); - NCComputeMac = library.DangerousGetFunction<NCComputeMacDelegate>(); - NCSetEncryptionData = library.DangerousGetFunction<NCSetEncryptionDataDelegate>(); - NCSetEncryptionProperty = library.DangerousGetFunction<NCSetEncryptionPropertyDelegate>(); - NCSetEncryptionPropertyEx = library.DangerousGetFunction<NCSetEncryptionPropertyExDelegate>(); + + //Cipher util library functions + NCUtilCipherAlloc = library.DangerousGetFunction<NCUtilCipherAllocDelegate>(); + NCUtilCipherFree = library.DangerousGetFunction<NCUtilCipherFreeDelegate>(); + NCUtilCipherInit = library.DangerousGetFunction<NCUtilCipherInitDelegate>(); + NCUtilCipherGetFlags = library.DangerousGetFunction<NCUtilCipherGetFlagsDelegate>(); + NCUtilCipherGetOutputSize = library.DangerousGetFunction<NCUtilCipherGetOutputSizeDelegate>(); + NCUtilCipherReadOutput = library.DangerousGetFunction<NCUtilCipherReadOutputDelegate>(); + NCUtilCipherSetProperty = library.DangerousGetFunction<NCUtilCipherSetPropertyDelegate>(); + NCUtilCipherUpdate = library.DangerousGetFunction<NCUtilCipherUpdateDelegate>(); + NCUtilCipherGetIvSize = library.DangerousGetFunction<NCUtilCipherGetIvSizeDelegate>(); #if DEBUG NCGetConversationKey = library.DangerousGetFunction<NCGetConversationKeyDelegate>(); @@ -114,28 +121,35 @@ namespace VNLib.Utils.Cryptography.Noscrypt.@internal [SafeMethodName("NCVerifyData")] internal delegate NCResult NCVerifyDataDelegate(IntPtr ctx, NCPublicKey* sk, byte* data, uint dataSize, byte* sig64); - [SafeMethodName("NCEncrypt")] - internal delegate NCResult NCEncryptDelegate(IntPtr ctx, NCSecretKey* sk, NCPublicKey* pk, NCEncryptionArgs* data); + [SafeMethodName("NCGetConversationKey")] + internal delegate NCResult NCGetConversationKeyDelegate(IntPtr ctx, NCSecretKey* sk, NCPublicKey* pk, byte* keyOut32); - [SafeMethodName("NCDecrypt")] - internal delegate NCResult NCDecryptDelegate(IntPtr ctx, NCSecretKey* sk, NCPublicKey* pk, NCEncryptionArgs* data); - [SafeMethodName("NCVerifyMac")] - internal delegate NCResult NCVerifyMacDelegate(IntPtr ctx, NCSecretKey* sk, NCPublicKey* pk, NCMacVerifyArgs* args); + [SafeMethodName("NCUtilCipherAlloc")] + internal delegate IntPtr NCUtilCipherAllocDelegate(uint version, uint flags); - [SafeMethodName("NCComputeMac")] - internal delegate NCResult NCComputeMacDelegate(IntPtr ctx, byte* hmacKey32, byte* payload, uint payloadSize, byte* hmacOut32); + [SafeMethodName("NCUtilCipherFree")] + internal delegate void NCUtilCipherFreeDelegate(IntPtr cipher); - [SafeMethodName("NCGetConversationKey")] - internal delegate NCResult NCGetConversationKeyDelegate(nint ctx, NCSecretKey* sk, NCPublicKey* pk, byte* keyOut32); + [SafeMethodName("NCUtilCipherInit")] + internal delegate NCResult NCUtilCipherInitDelegate(IntPtr cipher, byte* inputData, uint inputLen); + + [SafeMethodName("NCUtilCipherGetFlags")] + internal delegate NCResult NCUtilCipherGetFlagsDelegate(IntPtr cipher); + + [SafeMethodName("NCUtilCipherGetOutputSize")] + internal delegate NCResult NCUtilCipherGetOutputSizeDelegate(IntPtr cipher); + + [SafeMethodName("NCUtilCipherReadOutput")] + internal delegate NCResult NCUtilCipherReadOutputDelegate(IntPtr cipher, byte* outputData, uint outputLen); - [SafeMethodName("NCSetEncryptionProperty")] - internal delegate NCResult NCSetEncryptionPropertyDelegate(NCEncryptionArgs* args, uint property, uint value); + [SafeMethodName("NCUtilCipherSetProperty")] + internal delegate NCResult NCUtilCipherSetPropertyDelegate(IntPtr cipher, uint property, byte* value, uint valueLen); - [SafeMethodName("NCSetEncryptionPropertyEx")] - internal delegate NCResult NCSetEncryptionPropertyExDelegate(NCEncryptionArgs* args, uint property, byte* value, uint valueLen); + [SafeMethodName("NCUtilCipherUpdate")] + internal delegate NCResult NCUtilCipherUpdateDelegate(IntPtr cipher, IntPtr libContext, NCSecretKey* secKey, NCPublicKey* pubKey); - [SafeMethodName("NCSetEncryptionData")] - internal delegate NCResult NCSetEncryptionDataDelegate(NCEncryptionArgs* args, byte* input, byte* output, uint dataSize); + [SafeMethodName("NCUtilCipherGetIvSize")] + internal delegate NCResult NCUtilCipherGetIvSizeDelegate(IntPtr cipher); } } diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/NCEncryptionArgs.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/NCEncryptionArgs.cs deleted file mode 100644 index 91f0ff5..0000000 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/NCEncryptionArgs.cs +++ /dev/null @@ -1,31 +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.Runtime.InteropServices; - -namespace VNLib.Utils.Cryptography.Noscrypt.@internal -{ - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct NCEncryptionArgs - { - public byte* nonceData; - public byte* keyData; - public byte* inputData; - public byte* outputData; - public uint dataSize; - public uint version; - } -} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/NCMacVerifyArgs.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/NCMacVerifyArgs.cs deleted file mode 100644 index 8a9ba1f..0000000 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/internal/NCMacVerifyArgs.cs +++ /dev/null @@ -1,34 +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; - -namespace VNLib.Utils.Cryptography.Noscrypt.@internal -{ - internal unsafe struct NCMacVerifyArgs - { - /* The message authentication code certifying the Nip44 payload */ - public byte* mac32; - - /* The nonce used for the original message encryption */ - public byte* nonce32; - - /* The message payload data */ - public byte* payload; - - /* The size of the payload data */ - public uint payloadSize; - } -} |