< Summary

Information
Class: LOCKnet.Core.Crypto.SecureStringService
Assembly: LOCKnet.Core
File(s): /home/runner/work/LOCKnet/LOCKnet/src/LOCKnet.Core/Crypto/SecureStringService.cs
Line coverage
90%
Covered lines: 39
Uncovered lines: 4
Coverable lines: 43
Total lines: 86
Line coverage: 90.6%
Branch coverage
100%
Covered branches: 10
Total branches: 10
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ToByteArray(...)100%44100%
ZeroMemory(...)100%44100%
FromByteArray(...)100%2281.81%

File(s)

/home/runner/work/LOCKnet/LOCKnet/src/LOCKnet.Core/Crypto/SecureStringService.cs

#LineLine coverage
 1using System.Runtime.InteropServices;
 2using System.Security;
 3using System.Security.Cryptography;
 4using System.Text;
 5
 6namespace LOCKnet.Core.Crypto;
 7
 8/// <summary>
 9/// Implementierung von <see cref="ISecureStringService"/>.
 10/// Alle Konvertierungen pinnen den Speicher so kurz wie möglich.
 11/// </summary>
 12public sealed class SecureStringService : ISecureStringService
 13{
 14  /// <inheritdoc/>
 15  public byte[] ToByteArray(SecureString secureString)
 14116  {
 14117    ArgumentNullException.ThrowIfNull(secureString);
 14018    if (secureString.Length == 0)
 119      return [];
 20
 21    // SecureString intern als UTF-16 — wir holen den Pointer
 22    // und konvertieren direkt, ohne einen verwalteten String zu erzeugen.
 13923    var ptr = IntPtr.Zero;
 24    try
 13925    {
 13926      ptr = Marshal.SecureStringToGlobalAllocUnicode(secureString);
 27
 28      // Länge in UTF-16-Zeichen ist secureString.Length
 13929      var utf16 = new char[secureString.Length];
 13930      Marshal.Copy(ptr, utf16, 0, utf16.Length);
 31
 32      // UTF-16 → UTF-8 (was die Krypto-Layer erwartet)
 13933      var bytes = Encoding.UTF8.GetBytes(utf16);
 34
 35      // char-Array sofort überschreiben
 13936      Array.Clear(utf16, 0, utf16.Length);
 37
 13938      return bytes;
 39    }
 40    finally
 13941    {
 13942      if (ptr != IntPtr.Zero)
 13943        Marshal.ZeroFreeGlobalAllocUnicode(ptr);
 13944    }
 14045  }
 46
 47  /// <inheritdoc/>
 48  public void ZeroMemory(byte[] data)
 20549  {
 20550    if (data is { Length: > 0 })
 20351      CryptographicOperations.ZeroMemory(data);
 20552  }
 53
 54  /// <inheritdoc/>
 55  public SecureString FromByteArray(byte[] data)
 756  {
 757    ArgumentNullException.ThrowIfNull(data);
 58
 659    var secure = new SecureString();
 60    try
 661    {
 662      var chars = Encoding.UTF8.GetChars(data);
 63      try
 664      {
 14865        foreach (var c in chars)
 6566          secure.AppendChar(c);
 667      }
 68      finally
 669      {
 670        Array.Clear(chars, 0, chars.Length);
 671      }
 72
 673      secure.MakeReadOnly();
 674      return secure;
 75    }
 076    catch
 077    {
 078      secure.Dispose();
 079      throw;
 80    }
 81    finally
 682    {
 683      ZeroMemory(data);
 684    }
 685  }
 86}