< Summary - Combined Code Coverage

Line coverage
66%
Covered lines: 75
Uncovered lines: 38
Coverable lines: 113
Total lines: 308
Line coverage: 66.3%
Branch coverage
55%
Covered branches: 11
Total branches: 20
Branch coverage: 55%
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;
 13using Interfaces;
 14
 15internal sealed partial class NativeCryptoProvider : ICryptoProvider
 16{
 332017    private readonly IncrementalHash _sha256 = IncrementalHash.CreateHash(HashAlgorithmName.SHA256);
 18
 19    public void Sha256Init(IntPtr state)
 20    {
 21        // There's no need to initialize it here, since if it was used before, it was already reseted
 4359622    }
 23
 24    public void Sha256Update(IntPtr state, ReadOnlySpan<byte> data)
 25    {
 4190026        _sha256.AppendData(data.ToArray());
 4190027    }
 28
 29    public void Sha256Final(IntPtr state, Span<byte> result)
 30    {
 4069831        _ = _sha256.GetHashAndReset(result);
 4069832    }
 33
 34    public int AeadChaCha20Poly1305IetfEncrypt(ReadOnlySpan<byte> key, ReadOnlySpan<byte> publicNonce,
 35                                               ReadOnlySpan<byte> secureNonce, ReadOnlySpan<byte> authenticationData,
 36                                               ReadOnlySpan<byte> message, Span<byte> cipher, out long cipherLength)
 37    {
 38        try
 39        {
 407640            using var chaCha20Poly1305 = new ChaCha20Poly1305(key);
 41
 407642            chaCha20Poly1305.Encrypt(publicNonce, message, cipher[..message.Length],
 407643                                     cipher[message.Length..(message.Length + CryptoConstants.Chacha20Poly1305TagLen)],
 407644                                     authenticationData);
 45
 407646            cipherLength = message.Length + CryptoConstants.Chacha20Poly1305TagLen;
 47
 407648            return 0;
 49        }
 050        catch (Exception e)
 51        {
 052            throw new CryptographicException("Encryption failed.", e);
 53        }
 407654    }
 55
 56    public int AeadChaCha20Poly1305IetfDecrypt(ReadOnlySpan<byte> key, ReadOnlySpan<byte> publicNonce,
 57                                               ReadOnlySpan<byte> secureNonce, ReadOnlySpan<byte> authenticationData,
 58                                               ReadOnlySpan<byte> cipher, Span<byte> clearTextMessage,
 59                                               out long messageLength)
 60    {
 61        try
 62        {
 407263            using var chaCha20Poly1305 = new ChaCha20Poly1305(key);
 64
 407265            var messageLengthWithoutTag = cipher.Length - CryptoConstants.Chacha20Poly1305TagLen;
 66
 407267            chaCha20Poly1305.Decrypt(publicNonce, cipher[..messageLengthWithoutTag], cipher[messageLengthWithoutTag..],
 407268                                     clearTextMessage[..messageLengthWithoutTag], authenticationData);
 69
 406270            messageLength = messageLengthWithoutTag;
 71
 406272            return 0;
 73        }
 1074        catch (Exception e)
 75        {
 1076            throw new CryptographicException("Decryption failed.", e);
 77        }
 406278    }
 79
 80    public IntPtr MemoryAlloc(ulong size)
 81    {
 333682        return Marshal.AllocHGlobal((IntPtr)size);
 83    }
 84
 85    public int MemoryLock(IntPtr addr, ulong len)
 86    {
 43887        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 88        {
 089            return VirtualLock(addr, len) ? 0 : Marshal.GetLastWin32Error();
 90        }
 91
 92        // TODO: Log somewhere that Memory lock is not available on this platform.
 93        // but return success so the process can continue
 43894        return 0;
 95    }
 96
 97    public void MemoryUnlock(IntPtr addr, ulong len)
 98    {
 43699        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 100        {
 0101            _ = VirtualUnlock(addr, len);
 102        }
 103        // else
 104        // {
 105        // TODO: Log somewhere that Memory unlock is not available on this platform.
 106        // but don't fail so the process can continue
 107        // }
 436108    }
 109
 110    public int AeadXChaCha20Poly1305IetfEncrypt(ReadOnlySpan<byte> key, ReadOnlySpan<byte> nonce,
 111                                                ReadOnlySpan<byte> additionalData, ReadOnlySpan<byte> plainText,
 112                                                Span<byte> cipherText, out long cipherTextLength)
 113    {
 114        try
 115        {
 2116            if (key.Length != XChaCha20Constants.KeySize)
 0117                throw new ArgumentException("Key must be 32 bytes", nameof(key));
 118
 2119            if (nonce.Length != XChaCha20Constants.NonceSize)
 0120                throw new ArgumentException("Nonce must be 24 bytes", nameof(nonce));
 121
 2122            if (cipherText.Length != plainText.Length + CryptoConstants.Xchacha20Poly1305TagLen)
 0123                throw new ArgumentException(
 0124                    $"Ciphertext must be {plainText.Length + CryptoConstants.Xchacha20Poly1305TagLen} bytes long.",
 0125                    nameof(cipherText));
 126
 127            // subkey (hchacha20(key, nonce[0:15]))
 2128            Span<byte> subkey = stackalloc byte[XChaCha20Constants.SubkeySize];
 2129            HChaCha20.CreateSubkey(key, nonce, subkey);
 130
 131            // nonce (chacha20_nonce = "\x00\x00\x00\x00" + nonce[16:23])
 2132            Span<byte> chaChaNonce = stackalloc byte[12];
 2133            "\0\0\0\0"u8.ToArray().CopyTo(chaChaNonce[..4]);
 2134            nonce[16..].CopyTo(chaChaNonce[4..]);
 135
 136            // chacha20_encrypt(subkey, chacha20_nonce, plaintext, blk_ctr)
 2137            var keyMaterial = new KeyParameter(subkey.ToArray());
 2138            var parameters = new ParametersWithIV(keyMaterial, chaChaNonce.ToArray());
 139
 2140            var chaCha20Poly1305 = new Org.BouncyCastle.Crypto.Modes.ChaCha20Poly1305();
 2141            chaCha20Poly1305.Init(true, parameters);
 142
 143            // if additional data present
 2144            if (additionalData != Span<byte>.Empty)
 145            {
 2146                chaCha20Poly1305.ProcessAadBytes(additionalData.ToArray(), 0, additionalData.Length);
 147            }
 148
 2149            var cipherTextBytes = new byte[cipherText.Length];
 2150            var len1 = chaCha20Poly1305.ProcessBytes(plainText.ToArray(), 0, plainText.Length, cipherTextBytes, 0);
 2151            var len2 = chaCha20Poly1305.DoFinal(cipherTextBytes, len1);
 2152            cipherTextLength = len1 + len2;
 153
 2154            cipherTextBytes.CopyTo(cipherText);
 155
 2156            return 0;
 157        }
 0158        catch (Exception e)
 159        {
 0160            throw new CryptographicException("Encryption failed.", e);
 161        }
 2162    }
 163
 164    public int AeadXChaCha20Poly1305IetfDecrypt(ReadOnlySpan<byte> key, ReadOnlySpan<byte> nonce,
 165                                                ReadOnlySpan<byte> additionalData, ReadOnlySpan<byte> cipherText,
 166                                                Span<byte> plainText, out long plainTextLength)
 167    {
 168        try
 169        {
 2170            if (key.Length != XChaCha20Constants.KeySize)
 0171                throw new ArgumentException("Key must be 32 bytes", nameof(key));
 172
 2173            if (nonce.Length != XChaCha20Constants.NonceSize)
 0174                throw new ArgumentException("Nonce must be 24 bytes", nameof(nonce));
 175
 176            // subkey (hchacha20(key, nonce[0:15]))
 2177            Span<byte> subkey = stackalloc byte[XChaCha20Constants.SubkeySize];
 2178            HChaCha20.CreateSubkey(key, nonce, subkey);
 179
 180            // nonce (chacha20_nonce = "\x00\x00\x00\x00" + nonce[16:23])
 2181            Span<byte> chaChaNonce = stackalloc byte[12];
 2182            "\0\0\0\0"u8.ToArray().CopyTo(chaChaNonce[..4]);
 2183            nonce[16..].CopyTo(chaChaNonce[4..]);
 184
 185            // chacha20_encrypt(subkey, chacha20_nonce, plaintext, blk_ctr)
 2186            var keyMaterial = new KeyParameter(subkey.ToArray());
 2187            var parameters = new ParametersWithIV(keyMaterial, chaChaNonce.ToArray());
 188
 2189            var chaCha20Poly1305 = new Org.BouncyCastle.Crypto.Modes.ChaCha20Poly1305();
 2190            chaCha20Poly1305.Init(false, parameters);
 191
 192            // if additional data present
 2193            if (additionalData != Span<byte>.Empty)
 2194                chaCha20Poly1305.ProcessAadBytes(additionalData.ToArray(), 0, additionalData.Length);
 195
 2196            var plainTextBytes = new byte[plainText.Length];
 2197            var len1 = chaCha20Poly1305.ProcessBytes(cipherText.ToArray(), 0, cipherText.Length, plainTextBytes, 0);
 2198            var len2 = chaCha20Poly1305.DoFinal(plainTextBytes, (int)len1);
 2199            plainTextLength = len1 + len2;
 200
 2201            plainTextBytes.CopyTo(plainText);
 202
 2203            return 0;
 204        }
 0205        catch (Exception e)
 206        {
 0207            throw new CryptographicException("Decryption failed.", e);
 208        }
 2209    }
 210
 211    public int DeriveKeyFromPasswordUsingArgon2I(Span<byte> key, string password, ReadOnlySpan<byte> salt,
 212                                                 ulong opsLimit, ulong memLimit)
 213    {
 0214        using var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password));
 0215        argon2.Salt = salt.ToArray();
 0216        argon2.Iterations = (int)opsLimit;
 0217        argon2.MemorySize = (int)(memLimit / 1024); // memLimit is in bytes, MemorySize is in KB
 0218        argon2.DegreeOfParallelism = 1;
 219
 0220        var derived = argon2.GetBytes(key.Length);
 0221        derived.CopyTo(key);
 0222        return 0;
 0223    }
 224
 225    public void RandomBytes(Span<byte> buffer)
 226    {
 0227        RandomNumberGenerator.Fill(buffer);
 0228    }
 229
 230    public void MemoryFree(IntPtr ptr)
 231    {
 3332232        Marshal.FreeHGlobal(ptr);
 3332233    }
 234
 235    public void MemoryZero(IntPtr ptr, ulong len)
 236    {
 237        unsafe
 238        {
 7860239            var span = new Span<byte>((void*)ptr, (int)len);
 7860240            CryptographicOperations.ZeroMemory(span);
 241        }
 7860242    }
 243
 244    // P/Invoke for Windows VirtualLock and VirtualUnlock
 245    [LibraryImport("kernel32.dll", SetLastError = true)]
 246    [return: MarshalAs(UnmanagedType.Bool)]
 247    private static partial bool VirtualLock(IntPtr lpAddress, ulong dwSize);
 248
 249    [LibraryImport("kernel32.dll", SetLastError = true)]
 250    [return: MarshalAs(UnmanagedType.Bool)]
 251    private static partial bool VirtualUnlock(IntPtr lpAddress, ulong dwSize);
 252
 253    public void Dispose()
 254    {
 3212255        _sha256.Dispose();
 3212256    }
 257}
 258#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)