< Summary

Information
Class: LOCKnet.Core.Crypto.AesGcmEncryptionService
Assembly: LOCKnet.Core
File(s): /home/runner/work/LOCKnet/LOCKnet/src/LOCKnet.Core/Crypto/AesGcmEncryptionService.cs
Line coverage
97%
Covered lines: 35
Uncovered lines: 1
Coverable lines: 36
Total lines: 76
Line coverage: 97.2%
Branch coverage
83%
Covered branches: 5
Total branches: 6
Branch coverage: 83.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Encrypt(...)100%11100%
Encrypt(...)100%22100%
Decrypt(...)100%11100%
Decrypt(...)75%4494.11%

File(s)

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

#LineLine coverage
 1using System.Security.Cryptography;
 2
 3namespace LOCKnet.Core.Crypto;
 4
 5/// <summary>
 6/// AES-256-GCM-Implementierung von <see cref="IEncryptionService"/>.
 7///
 8/// Paket-Format: <c>[Nonce (12 Bytes)][Tag (16 Bytes)][Ciphertext (n Bytes)]</c>
 9/// </summary>
 10public sealed class AesGcmEncryptionService : IEncryptionService
 11{
 12  private const int KeyBytes = 32;      // AES-256
 13  private const int NonceBytes = 12;    // GCM-Standard-Nonce
 14  private const int TagBytes = 16;      // GCM-Authentifizierungs-Tag
 15  private const int HeaderBytes = NonceBytes + TagBytes; // 28 Bytes Overhead
 16
 17  /// <inheritdoc/>
 18  public byte[] Encrypt(byte[] plaintext, byte[] key)
 8119    => Encrypt(plaintext, key, []);
 20
 21  /// <inheritdoc/>
 22  public byte[] Encrypt(byte[] plaintext, byte[] key, byte[] associatedData)
 15223  {
 15224    ArgumentNullException.ThrowIfNull(plaintext);
 15125    ArgumentNullException.ThrowIfNull(key);
 15126    ArgumentNullException.ThrowIfNull(associatedData);
 15127    if (key.Length != KeyBytes)
 128      throw new ArgumentException($"Key muss genau {KeyBytes} Bytes lang sein.", nameof(key));
 29
 15030    var nonce = RandomNumberGenerator.GetBytes(NonceBytes);
 15031    var tag = new byte[TagBytes];
 15032    var ciphertext = new byte[plaintext.Length];
 33
 15034    using var aes = new AesGcm(key, TagBytes);
 15035    aes.Encrypt(nonce, plaintext, ciphertext, tag, associatedData);
 36
 37    // Paket zusammensetzen: Nonce | Tag | Ciphertext
 15038    var packet = new byte[HeaderBytes + ciphertext.Length];
 15039    nonce.CopyTo(packet, 0);
 15040    tag.CopyTo(packet, NonceBytes);
 15041    ciphertext.CopyTo(packet, HeaderBytes);
 42
 15043    return packet;
 15044  }
 45
 46  /// <inheritdoc/>
 47  public byte[] Decrypt(byte[] cipherPacket, byte[] key)
 5448    => Decrypt(cipherPacket, key, []);
 49
 50  /// <inheritdoc/>
 51  public byte[] Decrypt(byte[] cipherPacket, byte[] key, byte[] associatedData)
 10352  {
 10353    ArgumentNullException.ThrowIfNull(cipherPacket);
 10254    ArgumentNullException.ThrowIfNull(key);
 10255    ArgumentNullException.ThrowIfNull(associatedData);
 56
 10257    if (key.Length != KeyBytes)
 058      throw new ArgumentException($"Key muss genau {KeyBytes} Bytes lang sein.", nameof(key));
 59
 10260    if (cipherPacket.Length < HeaderBytes)
 161      throw new ArgumentException(
 162        $"Paket zu kurz — mindestens {HeaderBytes} Bytes erwartet.", nameof(cipherPacket));
 63
 64    // Paket zerlegen
 10165    var nonce = cipherPacket[..NonceBytes];
 10166    var tag = cipherPacket[NonceBytes..HeaderBytes];
 10167    var ciphertext = cipherPacket[HeaderBytes..];
 68
 10169    var plaintext = new byte[ciphertext.Length];
 70
 10171    using var aes = new AesGcm(key, TagBytes);
 10172    aes.Decrypt(nonce, ciphertext, tag, plaintext, associatedData);
 73
 8874    return plaintext;
 8875  }
 76}