/
Aes256Hmac512Encrypter.cs
60 lines (47 loc) · 2 KB
/
Aes256Hmac512Encrypter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
using System;
using System.Security.Cryptography;
using IOKode.OpinionatedFramework.Ensuring;
using IOKode.OpinionatedFramework.Security;
namespace IOKode.OpinionatedFramework.ContractImplementations.Aes256GcmModeEncrypter;
public class Aes256GcmModeEncrypter : IEncrypter
{
private readonly byte[] _key;
public Aes256GcmModeEncrypter(byte[] key)
{
Ensure.Boolean.IsTrue(key.Length == 32)
.ElseThrowsIllegalArgument("The key must be exactly 256 bits in length", nameof(key));
_key = key;
}
public ReadOnlySpan<byte> Encrypt(ReadOnlySpan<byte> plainData)
{
byte[] nonce = _generateNonce();
byte[] tag = _generateTag();
var cipheredData = new byte[plainData.Length];
var result = new byte[nonce.Length + cipheredData.Length + tag.Length];
using var aes = new AesGcm(_key);
aes.Encrypt(nonce, plainData, cipheredData, tag);
nonce.CopyTo(result.AsSpan(0, nonce.Length));
cipheredData.CopyTo(result.AsSpan(nonce.Length, cipheredData.Length));
tag.CopyTo(result.AsSpan(nonce.Length + cipheredData.Length, tag.Length));
return result;
}
public ReadOnlySpan<byte> Decrypt(ReadOnlySpan<byte> payload)
{
var nonce = payload[..AesGcm.NonceByteSizes.MaxSize];
var tag = payload.Slice(payload.Length - AesGcm.TagByteSizes.MaxSize, AesGcm.TagByteSizes.MaxSize);
var cipheredData = payload.Slice(AesGcm.NonceByteSizes.MaxSize,
payload.Length - (AesGcm.NonceByteSizes.MaxSize + AesGcm.TagByteSizes.MaxSize));
byte[] decryptedData = new byte[cipheredData.Length];
using var aes = new AesGcm(_key);
aes.Decrypt(nonce, cipheredData, tag, decryptedData, null);
return decryptedData;
}
private byte[] _generateNonce()
{
return RandomNumberGenerator.GetBytes(AesGcm.NonceByteSizes.MaxSize);
}
private byte[] _generateTag()
{
return RandomNumberGenerator.GetBytes(AesGcm.TagByteSizes.MaxSize);
}
}