// 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; using VNLib.Utils.Extensions; using VNLib.Utils.Memory; using VNLib.Utils.Native; using NCResult = System.Int64; namespace NVault.Crypto.Noscrypt { /// /// Initializes the native library and provides access to the native functions /// /// An existing noscrypt library handle /// A value that indicates if the instance owns the library handle public unsafe sealed class LibNoscrypt(SafeLibraryHandle Library, bool OwnsHandle) : VnDisposeable { //Values that match the noscrypt.h header public const int NC_SEC_KEY_SIZE = 32; public const int NC_SEC_PUBKEY_SIZE = 32; public const int NC_ENCRYPTION_NONCE_SIZE = 32; public const int NC_PUBKEY_SIZE = 32; public const int NC_SIGNATURE_SIZE = 64; public const int NC_CONV_KEY_SIZE = 32; public const int NC_MESSAGE_KEY_SIZE = 32; public const int NC_HMAC_KEY_SIZE = 32; public const int NC_ENCRYPTION_MAC_SIZE = 32; public const int NC_CONVERSATION_KEY_SIZE = 32; public const int CTX_ENTROPY_SIZE = 32; public const NCResult NC_SUCCESS = 0; 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; private readonly FunctionTable _functions = FunctionTable.BuildFunctionTable(Library); /// /// Gets a reference to the loaded function table for /// the native library /// internal ref readonly FunctionTable Functions { get { Check(); Library.ThrowIfClosed(); return ref _functions; } } /// /// Gets a value that determines if the library has been released /// internal bool IsClosed => Library.IsClosed || Library.IsInvalid; /// /// Initialize a new NCContext for use. This may be done once at app startup /// and is thread-safe for the rest of the application lifetime. /// /// /// Initialization entropy buffer /// The size of the buffer (must be 32 bytes) /// The inialized context /// /// /// public NCContext Initialize(IUnmangedHeap heap, ref readonly byte entropy32, int size) { ArgumentNullException.ThrowIfNull(heap); //Entropy must be exactly 32 bytes ArgumentOutOfRangeException.ThrowIfNotEqual(size, CTX_ENTROPY_SIZE); //Get struct size nuint ctxSize = Functions.NCGetContextStructSize.Invoke(); //Allocate the context with the struct alignment on a heap IntPtr ctx = heap.Alloc(1, ctxSize, true); try { NCResult result; fixed (byte* p = &entropy32) { result = Functions.NCInitContext.Invoke(ctx, p); } NCUtil.CheckResult(result, true); Trace.WriteLine($"Initialzied noscrypt context 0x{ctx:x}"); return new NCContext(ctx, heap, this); } catch { heap.Free(ref ctx); throw; } } /// /// Initialize a new NCContext for use. This may be done once at app startup /// and is thread-safe for the rest of the application lifetime. /// /// /// The 32byte random seed/nonce for the noscrypt context /// The inialized context /// /// /// public NCContext Initialize(IUnmangedHeap heap, ReadOnlySpan enropy32) { return Initialize( heap, ref MemoryMarshal.GetReference(enropy32), enropy32.Length ); } /// protected override void Free() { if (OwnsHandle) { Library.Dispose(); Trace.WriteLine($"Disposed noscrypt library 0x{Library.DangerousGetHandle():x}"); } } /// /// Loads the native library from the specified path and initializes the /// function table for use. /// /// The native library path or name to load /// The search path options /// The loaded library instance public static LibNoscrypt Load(string path, DllImportSearchPath search) { //Load the native library SafeLibraryHandle handle = SafeLibraryHandle.LoadLibrary(path, search); Trace.WriteLine($"Loaded noscrypt library 0x{handle.DangerousGetHandle():x} from {path}"); //Create the wrapper return new LibNoscrypt(handle, true); } /// /// Loads the native library from the specified path and initializes the /// function table for use. /// /// The native library path or name to load /// The loaded library instance public static LibNoscrypt Load(string path) => Load(path, DllImportSearchPath.SafeDirectories); } }