< Summary - Combined Code Coverage

Line coverage
30%
Covered lines: 34
Uncovered lines: 77
Coverable lines: 111
Total lines: 305
Line coverage: 30.6%
Branch coverage
11%
Covered branches: 2
Total branches: 18
Branch coverage: 11.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/nlightning/nlightning/src/NLightning.Infrastructure/Crypto/Providers/Native/NativeCryptoProvider.cs

#LineLine coverage
 1#if CRYPTO_NATIVE
 2using System.Runtime.InteropServices;
 3using System.Security.Cryptography;
 4using System.Text;
 5using Konscious.Security.Cryptography;
 6using Org.BouncyCastle.Crypto.Parameters;
 7
 8namespace NLightning.Infrastructure.Crypto.Providers.Native;
 9
 10using Ciphers;
 11using Constants;
 12using Domain.Crypto.Constants;
 13
 14using Interfaces;
 15
 16internal sealed partial class NativeCryptoProvider: ICryptoProvider
 17{
 355818    private readonly IncrementalHash _sha256 = IncrementalHash.CreateHash(HashAlgorithmName.SHA256);
 19
 20    public void Sha256Init(IntPtr state)
 21    {
 22        // There's no need to initialize it here, since if it was used before, it was already reseted
 4400023    }
 24
 25    public void Sha256Update(IntPtr state, ReadOnlySpan<byte> data)
 26    {
 4204627        _sha256.AppendData(data.ToArray());
 4204628    }
 29
 30    public void Sha256Final(IntPtr state, Span<byte> result)
 31    {
 4083632        _ = _sha256.GetHashAndReset(result);
 4083633    }
 34
 35    public int AeadChaCha20Poly1305IetfEncrypt(ReadOnlySpan<byte> key, ReadOnlySpan<byte> publicNonce,
 36                                                ReadOnlySpan<byte> secureNonce, ReadOnlySpan<byte> authenticationData,
 37                                                ReadOnlySpan<byte> message, Span<byte> cipher, out long cipherLength)
 38    {
 39        try
 40        {
 407241            using var chaCha20Poly1305 = new ChaCha20Poly1305(key);
 42
 407243            chaCha20Poly1305.Encrypt(publicNonce, message, cipher[..message.Length],
 407244                                     cipher[message.Length..(message.Length + CryptoConstants.CHACHA20_POLY1305_TAG_LEN)
 407245                                     authenticationData);
 46
 407247            cipherLength = message.Length + CryptoConstants.CHACHA20_POLY1305_TAG_LEN;
 48
 407249            return 0;
 50        }
 051        catch (Exception e)
 52        {
 053            throw new CryptographicException("Encryption failed.", e);
 54        }
 407255    }
 56
 57    public int AeadChaCha20Poly1305IetfDecrypt(ReadOnlySpan<byte> key, ReadOnlySpan<byte> publicNonce,
 58                                                ReadOnlySpan<byte> secureNonce, ReadOnlySpan<byte> authenticationData,
 59                                                ReadOnlySpan<byte> cipher, Span<byte> clearTextMessage,
 60                                                out long messageLength)
 61    {
 62        try
 63        {
 406864            using var chaCha20Poly1305 = new ChaCha20Poly1305(key);
 65
 406866            var messageLengthWithoutTag = cipher.Length - CryptoConstants.CHACHA20_POLY1305_TAG_LEN;
 67
 406868            chaCha20Poly1305.Decrypt(publicNonce, cipher[..messageLengthWithoutTag], cipher[messageLengthWithoutTag..],
 406869                                     clearTextMessage[..messageLengthWithoutTag], authenticationData);
 70
 406071            messageLength = messageLengthWithoutTag;
 72
 406073            return 0;
 74        }
 875        catch (Exception e)
 76        {
 877            throw new CryptographicException("Decryption failed.", e);
 78        }
 406079    }
 80
 81    public IntPtr MemoryAlloc(ulong size)
 82    {
 359083        return Marshal.AllocHGlobal((IntPtr)size);
 84    }
 85
 86    public int MemoryLock(IntPtr addr, ulong len)
 87    {
 42688        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 89        {
 090            return VirtualLock(addr, len) ? 0 : Marshal.GetLastWin32Error();
 91        }
 92
 93        // TODO: Log somewhere that Memory lock is not available on this platform.
 94        // but return success so the process can continue
 42695        return 0;
 96    }
 97
 98    public void MemoryUnlock(IntPtr addr, ulong len)
 99    {
 378100        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 101        {
 0102            _ = VirtualUnlock(addr, len);
 103        }
 104        // else
 105        // {
 106            // TODO: Log somewhere that Memory unlock is not available on this platform.
 107            // but don't fail so the process can continue
 108        // }
 378109    }
 110
 111    public int AeadXChaCha20Poly1305IetfEncrypt(ReadOnlySpan<byte> key, ReadOnlySpan<byte> nonce,
 112                                                ReadOnlySpan<byte> additionalData, ReadOnlySpan<byte> plainText,
 113                                                Span<byte> cipherText, out long cipherTextLength)
 114    {
 115        try
 116        {
 0117            if (key.Length != XChaCha20Constants.KEY_SIZE)
 0118                throw new ArgumentException("Key must be 32 bytes", nameof(key));
 0119            if (nonce.Length != XChaCha20Constants.NONCE_SIZE)
 0120                throw new ArgumentException("Nonce must be 24 bytes", nameof(nonce));
 121
 122            // subkey (hchacha20(key, nonce[0:15]))
 0123            Span<byte> subkey = stackalloc byte[XChaCha20Constants.SUBKEY_SIZE];
 0124            HChaCha20.CreateSubkey(key, nonce, subkey);
 125
 126            // nonce (chacha20_nonce = "\x00\x00\x00\x00" + nonce[16:23])
 0127            Span<byte> chaChaNonce = stackalloc byte[12];
 0128            "\0\0\0\0"u8.ToArray().CopyTo(chaChaNonce[..4]);
 0129            nonce[16..].CopyTo(chaChaNonce[4..]);
 130
 131            // chacha20_encrypt(subkey, chacha20_nonce, plaintext, blk_ctr)
 0132            var keyMaterial = new KeyParameter(subkey.ToArray());
 0133            var parameters = new ParametersWithIV(keyMaterial, chaChaNonce.ToArray());
 134
 0135            var chaCha20Poly1305 = new Org.BouncyCastle.Crypto.Modes.ChaCha20Poly1305();
 0136            chaCha20Poly1305.Init(true, parameters);
 137
 138            // if additional data present
 0139            if (additionalData != Span<byte>.Empty)
 140            {
 0141                chaCha20Poly1305.ProcessAadBytes(additionalData.ToArray(), 0, additionalData.Length);
 142            }
 143
 0144            var cipherTextBytes = new byte[cipherText.Length];
 0145            cipherTextLength = chaCha20Poly1305.ProcessBytes(plainText.ToArray(), 0, plainText.Length,
 0146                                                             cipherTextBytes, 0);
 0147            chaCha20Poly1305.DoFinal(cipherTextBytes, (int)cipherTextLength);
 148
 0149            cipherTextBytes.CopyTo(cipherText);
 0150            cipherTextLength = cipherTextBytes.Length;
 151
 0152            return 0;
 153        }
 0154        catch (Exception e)
 155        {
 0156            throw new CryptographicException("Encryption failed.", e);
 157        }
 0158    }
 159
 160    public int AeadXChaCha20Poly1305IetfDecrypt(ReadOnlySpan<byte> key, ReadOnlySpan<byte> nonce,
 161                                                ReadOnlySpan<byte> additionalData, ReadOnlySpan<byte> cipherText,
 162                                                Span<byte> plainText, out long plainTextLength)
 163    {
 164        try
 165        {
 0166            if (key.Length != XChaCha20Constants.KEY_SIZE)
 0167                throw new ArgumentException("Key must be 32 bytes", nameof(key));
 0168            if (nonce.Length != XChaCha20Constants.NONCE_SIZE)
 0169                throw new ArgumentException("Nonce must be 24 bytes", nameof(nonce));
 170
 171            // subkey (hchacha20(key, nonce[0:15]))
 0172            Span<byte> subkey = stackalloc byte[XChaCha20Constants.SUBKEY_SIZE];
 0173            HChaCha20.CreateSubkey(key, nonce, subkey);
 174
 175            // nonce (chacha20_nonce = "\x00\x00\x00\x00" + nonce[16:23])
 0176            Span<byte> chaChaNonce = stackalloc byte[12];
 0177            "\0\0\0\0"u8.ToArray().CopyTo(chaChaNonce[..4]);
 0178            nonce[16..].CopyTo(chaChaNonce[4..]);
 179
 180            // chacha20_encrypt(subkey, chacha20_nonce, plaintext, blk_ctr)
 0181            var keyMaterial = new KeyParameter(subkey.ToArray());
 0182            var parameters = new ParametersWithIV(keyMaterial, chaChaNonce.ToArray());
 183
 0184            var chaCha20Poly1305 = new Org.BouncyCastle.Crypto.Modes.ChaCha20Poly1305();
 0185            chaCha20Poly1305.Init(false, parameters);
 186
 187            // if additional data present
 0188            if (additionalData != Span<byte>.Empty)
 189            {
 0190                chaCha20Poly1305.ProcessAadBytes(additionalData.ToArray(), 0, additionalData.Length);
 191            }
 192
 0193            var plainTextBytes = new byte[plainText.Length];
 0194            plainTextLength = chaCha20Poly1305.ProcessBytes(cipherText.ToArray(), 0, cipherText.Length,
 0195                plainTextBytes, 0);
 0196            chaCha20Poly1305.DoFinal(plainTextBytes, (int)plainTextLength);
 197
 0198            plainTextBytes.CopyTo(plainText);
 0199            plainTextLength = plainTextBytes.Length;
 200
 0201            return 0;
 202        }
 0203        catch (Exception e)
 204        {
 0205            throw new CryptographicException("Decryption failed.", e);
 206        }
 0207    }
 208
 209    public int DeriveKeyFromPasswordUsingArgon2I(Span<byte> key, string password, ReadOnlySpan<byte> salt, ulong opsLimi
 210    {
 0211        using var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password));
 0212        argon2.Salt = salt.ToArray();
 0213        argon2.Iterations = (int)opsLimit;
 0214        argon2.MemorySize = (int)(memLimit / 1024); // memLimit is in bytes, MemorySize is in KB
 0215        argon2.DegreeOfParallelism = Environment.ProcessorCount;
 216
 0217        var derived = argon2.GetBytes(key.Length);
 0218        derived.CopyTo(key);
 0219        return 0;
 0220    }
 221
 222    public void RandomBytes(Span<byte> buffer)
 223    {
 0224        new Random().NextBytes(buffer);
 0225    }
 226
 227    public void MemoryFree(IntPtr ptr)
 228    {
 3518229        Marshal.FreeHGlobal(ptr);
 3518230    }
 231
 232    public void MemoryZero(IntPtr ptr, ulong len)
 233    {
 234        unsafe
 235        {
 8046236            var span = new Span<byte>((void*)ptr, (int)len);
 8046237            CryptographicOperations.ZeroMemory(span);
 238        }
 8046239    }
 240
 241    // P/Invoke for Windows VirtualLock and VirtualUnlock
 242    [LibraryImport("kernel32.dll", SetLastError = true)]
 243    [return: MarshalAs(UnmanagedType.Bool)]
 244    private static partial bool VirtualLock(IntPtr lpAddress, ulong dwSize);
 245
 246    [LibraryImport("kernel32.dll", SetLastError = true)]
 247    [return: MarshalAs(UnmanagedType.Bool)]
 248    private static partial bool VirtualUnlock(IntPtr lpAddress, ulong dwSize);
 249
 250    public void Dispose()
 251    {
 3460252        _sha256.Dispose();
 3460253    }
 254}
 255#endif

/home/runner/work/nlightning/nlightning/src/NLightning.Infrastructure/obj/Release.Native/net9.0/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs

File '/home/runner/work/nlightning/nlightning/src/NLightning.Infrastructure/obj/Release.Native/net9.0/Microsoft.Interop.LibraryImportGenerator/Microsoft.Interop.LibraryImportGenerator/LibraryImports.g.cs' does not exist (any more).

Methods/Properties

.ctor()
Sha256Init(System.IntPtr)
Sha256Update(System.IntPtr,System.ReadOnlySpan`1<System.Byte>)
Sha256Final(System.IntPtr,System.Span`1<System.Byte>)
AeadChaCha20Poly1305IetfEncrypt(System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Byte>,System.Int64&)
AeadChaCha20Poly1305IetfDecrypt(System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Byte>,System.Int64&)
MemoryAlloc(System.UInt64)
MemoryLock(System.IntPtr,System.UInt64)
MemoryUnlock(System.IntPtr,System.UInt64)
AeadXChaCha20Poly1305IetfEncrypt(System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Byte>,System.Int64&)
AeadXChaCha20Poly1305IetfDecrypt(System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.ReadOnlySpan`1<System.Byte>,System.Span`1<System.Byte>,System.Int64&)
DeriveKeyFromPasswordUsingArgon2I(System.Span`1<System.Byte>,System.String,System.ReadOnlySpan`1<System.Byte>,System.UInt64,System.UInt64)
RandomBytes(System.Span`1<System.Byte>)
MemoryFree(System.IntPtr)
MemoryZero(System.IntPtr,System.UInt64)
Dispose()
VirtualLock(System.IntPtr,System.UInt64)
VirtualUnlock(System.IntPtr,System.UInt64)