From 44044eb0fb28b774773e3284fd147c91d59d64e3 Mon Sep 17 00:00:00 2001 From: vnugent Date: Fri, 18 Oct 2024 22:10:17 -0400 Subject: refactor: Wire up unit testing and refactor c# api --- .../src/Encryption/NCCipherUtil.cs | 171 ++++++++++++++ .../src/Encryption/NCUtilCipher.cs | 128 ----------- .../src/Encryption/NoscryptCipher.cs | 227 ------------------ .../src/Encryption/NoscryptMessageCipher.cs | 256 +++++++++++++++++++++ 4 files changed, 427 insertions(+), 355 deletions(-) create mode 100644 wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCCipherUtil.cs delete mode 100644 wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCUtilCipher.cs delete mode 100644 wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipher.cs create mode 100644 wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptMessageCipher.cs (limited to 'wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption') diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCCipherUtil.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCCipherUtil.cs new file mode 100644 index 0000000..5dc2a94 --- /dev/null +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCCipherUtil.cs @@ -0,0 +1,171 @@ +// 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 . + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +using VNLib.Utils.Cryptography.Noscrypt.@internal; + +using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary; + +using NCResult = System.Int64; + +namespace VNLib.Utils.Cryptography.Noscrypt.Encryption +{ + public unsafe static class NCCipherUtil + { + /* + * This class wraps the low-level cipher functions provided by + * the Noscrypt utility side-car library. + */ + + internal 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; + } + + internal static uint GetFlags(NCContext ctx, nint cipher) + { + NCResult result = GetTable(ctx).NCUtilCipherGetFlags(cipher); + + NCUtil.CheckResult(result, raiseOnFailure: true); + + return (uint)result; + } + + internal static void Free(NCContext ctx, nint cipher) => GetTable(ctx).NCUtilCipherFree(cipher); + + internal static int GetIvSize(NCContext ctx, nint cipher) + { + NCResult result = GetTable(ctx).NCUtilCipherGetIvSize(cipher); + + NCUtil.CheckResult(result, raiseOnFailure: true); + + return checked((int)result); + } + + internal static 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(result, raiseOnFailure: true); + } + } + + internal static uint GetOutputSize(NCContext ctx, nint cipher) + { + NCResult result = GetTable(ctx).NCUtilCipherGetOutputSize(cipher); + + NCUtil.CheckResult(result, raiseOnFailure: true); + + return (uint)result; + } + + internal static 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(result, raiseOnFailure: true); + + return (uint)result; + } + } + + internal static void InitCipher(NCContext ctx, nint cipher, byte* inputPtr, uint inputSize) + { + NCResult result = GetTable(ctx).NCUtilCipherInit(cipher, inputPtr, inputSize); + + NCUtil.CheckResult(result, raiseOnFailure: true); + } + + internal static 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(result, raiseOnFailure: true); + } + } + + +#if DEBUG + /* + * Conversation key is not meant to be a public api. Callers + * should use Encrypt/Decrypt methods to handle encryption. + * + * This method exists for vector testing purposes only. + */ + public static void GetConverstationKey( + NCContext ctx, + ref readonly NCSecretKey localKey, + ref readonly NCPublicKey remoteKey, + Span conversationKeyOut32 + ) + { + ArgumentNullException.ThrowIfNull(ctx); + ArgumentOutOfRangeException.ThrowIfNotEqual( + conversationKeyOut32.Length, + NC_CONVERSATION_KEY_SIZE, + nameof(conversationKeyOut32) + ); + + fixed (NCSecretKey* sk = &localKey) + fixed (NCPublicKey* pk = &remoteKey) + fixed(byte* convKey32Ptr = &MemoryMarshal.GetReference(conversationKeyOut32)) + { + NCResult result = GetTable(ctx).NCGetConversationKey( + ctx: ctx.DangerousGetHandle(), + sk, + pk, + convKey32Ptr + ); + + NCUtil.CheckResult(result, raiseOnFailure: true); + } + } +#endif + + private static ref readonly FunctionTable GetTable(NCContext ctx) + => ref ctx.Library.Functions; + } + +} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCUtilCipher.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCUtilCipher.cs deleted file mode 100644 index 72bb75a..0000000 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NCUtilCipher.cs +++ /dev/null @@ -1,128 +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 . - -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(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(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(result, raiseOnFailure: true); - } - } - - public static uint GetOutputSize(NCContext ctx, nint cipher) - { - NCResult result = GetTable(ctx).NCUtilCipherGetOutputSize(cipher); - - NCUtil.CheckResult(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(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(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(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 deleted file mode 100644 index b30ea44..0000000 --- a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptCipher.cs +++ /dev/null @@ -1,227 +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 . - -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 -{ - /// - /// The noscrypt util cipher wapper - /// - /// - /// Cipher creation flags - /// The cipher specification version - public sealed class NoscryptCipher(NCContext ctx, NoscryptCipherVersion version, NoscryptCipherFlags flags) : VnDisposeable - { - private IMemoryHandle? _ivBuffer; - private readonly nint _cipher = NCUtilCipher.Alloc(ctx, (uint)version, (uint)flags); - - /// - /// The cipher standard version used by this instance - /// - public NoscryptCipherVersion Version => version; - - /// - /// Gets the flags set for the cipher instance - /// - public uint GetFlags() => NCUtilCipher.GetFlags(ctx, _cipher); - - /// - /// Gets the cipher's initilaization vector size (or nonce) - /// - /// The size of the IV in bytes - public int GetIvSize() => NCUtilCipher.GetIvSize(ctx, _cipher); - - /// - /// Gets the internal heap buffer that holds the cipher's initalization - /// vector. - /// - /// The mutable span of the cipher's IV buffer - public Span IvBuffer - { - get => LazyInitializer.EnsureInitialized(ref _ivBuffer, AllocIvBuffer).Span; - } - - /// - /// Sets the cipher's initialization vector to a random value using - /// the specified random source - /// - /// The random source - public void SetRandomIv(IRandomSource rng) - { - ArgumentNullException.ThrowIfNull(rng); - rng.GetRandomBytes(IvBuffer); - } - - /// - /// Performs the cipher operation on the input data using the specified - /// local and remote keys. - /// - /// The secret key of the local user - /// The public key of the remote user - /// A pointer to the first byte in the buffer sequence - /// The size of the input buffer in bytes - /// - /// - /// If the flag is - /// set, this function may be considered independent and called repeatedly. - /// - 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); - } - } - - /// - /// Performs the cipher operation on the input data using the specified - /// local and remote keys. - /// - /// The secret key of the local user - /// The public key of the remote user - /// The buffer sequence to read the input data from - /// - public void Update( - ref readonly NCSecretKey localKey, - ref readonly NCPublicKey remoteKey, - ReadOnlySpan input - ) - { - Update( - in localKey, - in remoteKey, - inputData: ref MemoryMarshal.GetReference(input), //If empty, null ref will throw - inputSize: (uint)input.Length - ); - } - - /// - /// Gets the size of the output buffer required to read the cipher output - /// - /// The size of the output in bytes - public int GetOutputSize() => checked((int)NCUtilCipher.GetOutputSize(ctx, _cipher)); - - /// - /// Reads the output data from the cipher into the specified buffer - /// - /// A reference to the first byte in the buffer sequence - /// The size of the buffer sequence - /// The number of bytes written to the buffer - /// - public int ReadOutput(ref byte outputData, int size) - { - ArgumentOutOfRangeException.ThrowIfLessThan(size, GetOutputSize()); - - return checked((int)NCUtilCipher.ReadOutput(ctx, _cipher, ref outputData, (uint)size)); - } - - /// - /// Reads the output data from the cipher into the specified buffer - /// - /// The buffer sequence to write output data to - /// The number of bytes written to the buffer - /// - public int ReadOutput(Span buffer) - { - return ReadOutput( - ref MemoryMarshal.GetReference(buffer), - buffer.Length - ); - } - - private IMemoryHandle AllocIvBuffer() - { - //Use the context heap to allocate the internal iv buffer - MemoryHandle buffer = MemoryUtil.SafeAlloc(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; - } - - /// - protected override void Free() - { - NCUtilCipher.Free(ctx, _cipher); - _ivBuffer?.Dispose(); - } - } - -} diff --git a/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptMessageCipher.cs b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptMessageCipher.cs new file mode 100644 index 0000000..e44addf --- /dev/null +++ b/wrappers/dotnet/VNLib.Utils.Cryptography.Noscrypt/src/Encryption/NoscryptMessageCipher.cs @@ -0,0 +1,256 @@ +// 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 . + +using System; +using System.Threading; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using Microsoft.Win32.SafeHandles; + +using VNLib.Utils.Memory; +using VNLib.Utils.Cryptography.Noscrypt.Random; +using static VNLib.Utils.Cryptography.Noscrypt.NoscryptLibrary; + +namespace VNLib.Utils.Cryptography.Noscrypt.Encryption +{ + /// + /// The noscrypt util cipher wapper + /// + /// A reference to the library context object + /// A pointer to an existing cipher context that this instance owns + /// The cipher specification version + public class NoscryptMessageCipher : SafeHandleMinusOneIsInvalid + { + private readonly NCContext _context; + private readonly NoscryptCipherVersion _version; + private IMemoryHandle? _ivBuffer; + + private NoscryptMessageCipher(NCContext ctx, nint cipher, NoscryptCipherVersion version) + : base(ownsHandle: true) + { + SetHandle(cipher); + _context = ctx; + _version = version; + } + + /// + /// Allocates and initializes a new cipher instance using the specified + /// + /// A reference to the noscrypt library context + /// The encryption standard to use + /// The raw cipher flags to the pass to the cipher initialization function + /// A new instance + public static NoscryptMessageCipher Create(NCContext context, NoscryptCipherVersion version, NoscryptCipherFlags flags) + { + return new( + context, + NCCipherUtil.Alloc(context, (uint)version, (uint)flags), + version + ); + } + + /// + /// The cipher standard version used by this instance + /// + public NoscryptCipherVersion Version => _version; + + /// + /// Gets the flags set for the cipher instance + /// + public uint GetFlags() => NCCipherUtil.GetFlags(_context, handle); + + /// + /// Gets the cipher's initilaization vector size (or nonce) + /// + /// The size of the IV in bytes + public int GetIvSize() => NCCipherUtil.GetIvSize(_context, handle); + + /// + /// Gets the internal heap buffer that holds the cipher's initalization + /// vector. + /// + /// The mutable span of the cipher's IV buffer + public Span IvBuffer + { + get => LazyInitializer.EnsureInitialized(ref _ivBuffer, AllocIvBuffer).Span; + } + + /// + /// Sets the cipher's initialization vector to a random value using + /// the specified random source + /// + /// The random source + public void SetRandomIv(IRandomSource rng) + { + ArgumentNullException.ThrowIfNull(rng); + rng.GetRandomBytes(IvBuffer); + } + + /// + /// Performs the cipher operation on the input data using the specified + /// local and remote keys. + /// + /// The secret key of the local user + /// The public key of the remote user + /// A pointer to the first byte in the buffer sequence + /// The size of the input buffer in bytes + /// + /// + /// If the flag is + /// set, this function may be considered independent and called repeatedly. + /// + 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) + { + NCCipherUtil.InitCipher(_context, handle, inputPtr, inputSize); + + NCCipherUtil.Update(_context, handle, in localKey, in remoteKey); + } + } + + /// + /// Performs the cipher operation on the input data using the specified + /// local and remote keys. + /// + /// The secret key of the local user + /// The public key of the remote user + /// The buffer sequence to read the input data from + /// + public void Update( + ref readonly NCSecretKey localKey, + ref readonly NCPublicKey remoteKey, + ReadOnlySpan input + ) + { + Update( + in localKey, + in remoteKey, + inputData: ref MemoryMarshal.GetReference(input), //If empty, null ref will throw + inputSize: (uint)input.Length + ); + } + + /// + /// Gets the size of the output buffer required to read the cipher output + /// + /// The size of the output in bytes + public int GetOutputSize() => checked((int)NCCipherUtil.GetOutputSize(_context, handle)); + + /// + /// Reads the output data from the cipher into the specified buffer + /// + /// A reference to the first byte in the buffer sequence + /// The size of the buffer sequence + /// The number of bytes written to the buffer + /// + public int ReadOutput(ref byte outputData, int size) + { + ArgumentOutOfRangeException.ThrowIfLessThan(size, GetOutputSize()); + + return checked((int)NCCipherUtil.ReadOutput(_context, handle, ref outputData, (uint)size)); + } + + /// + /// Reads the output data from the cipher into the specified buffer + /// + /// The buffer sequence to write output data to + /// The number of bytes written to the buffer + /// + public int ReadOutput(Span buffer) + { + return ReadOutput( + ref MemoryMarshal.GetReference(buffer), + buffer.Length + ); + } + + private IMemoryHandle AllocIvBuffer() + { + //Use the context heap to allocate the internal iv buffer + MemoryHandle buffer = MemoryUtil.SafeAlloc(_context.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. + */ + NCCipherUtil.SetProperty( + _context, + DangerousGetHandle(), + NC_ENC_SET_IV, + ref buffer.GetReference(), + (uint)buffer.Length + ); + } + catch + { + buffer.Dispose(); + throw; + } + + return buffer; + } + + /// + protected override bool ReleaseHandle() + { + NCCipherUtil.Free(_context, handle); + _ivBuffer?.Dispose(); + + return true; + } + } + +} -- cgit