使用 AesGcm class
Using the AesGcm class
我刚刚注意到 .NET Standard 2.1/.NET Core 3.0 终于添加了一个 class for AES-GCM encryption.
然而,它的 API 似乎与通常的 .NET 加密 classes 略有不同:它的 Encrypt
函数要求为密文和标签,而不是自己提供它们。不幸的是,文档中没有示例显示 class.
的正确用法
我知道如何从理论上计算 AES 加密的预期密文大小,但我想知道这是否真的是 "guess" 密文缓冲区大小的预期方法。通常加密库会提供处理这些计算的函数。
有人有关于如何正确使用AesGcm
加密字节数组的示例吗?
我现在想通了。
我忘记了,在GCM中,密文has the same length as the plain text;与 CBC 等其他加密模式相反,不需要填充。随机数和标记长度分别由 AesGcm
的 NonceByteSizes
和 TagByteSizes
属性确定。
使用它,可以通过以下方式进行加密:
public string Encrypt(string plain)
{
// Get bytes of plaintext string
byte[] plainBytes = Encoding.UTF8.GetBytes(plain);
// Get parameter sizes
int nonceSize = AesGcm.NonceByteSizes.MaxSize;
int tagSize = AesGcm.TagByteSizes.MaxSize;
int cipherSize = plainBytes.Length;
// We write everything into one big array for easier encoding
int encryptedDataLength = 4 + nonceSize + 4 + tagSize + cipherSize;
Span<byte> encryptedData = encryptedDataLength < 1024
? stackalloc byte[encryptedDataLength]
: new byte[encryptedDataLength].AsSpan();
// Copy parameters
BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(0, 4), nonceSize);
BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(4 + nonceSize, 4), tagSize);
var nonce = encryptedData.Slice(4, nonceSize);
var tag = encryptedData.Slice(4 + nonceSize + 4, tagSize);
var cipherBytes = encryptedData.Slice(4 + nonceSize + 4 + tagSize, cipherSize);
// Generate secure nonce
RandomNumberGenerator.Fill(nonce);
// Encrypt
using var aes = new AesGcm(_key);
aes.Encrypt(nonce, plainBytes.AsSpan(), cipherBytes, tag);
// Encode for transmission
return Convert.ToBase64String(encryptedData);
}
对应的解密如下:
public string Decrypt(string cipher)
{
// Decode
Span<byte> encryptedData = Convert.FromBase64String(cipher).AsSpan();
// Extract parameter sizes
int nonceSize = BinaryPrimitives.ReadInt32LittleEndian(encryptedData.Slice(0, 4));
int tagSize = BinaryPrimitives.ReadInt32LittleEndian(encryptedData.Slice(4 + nonceSize, 4));
int cipherSize = encryptedData.Length - 4 - nonceSize - 4 - tagSize;
// Extract parameters
var nonce = encryptedData.Slice(4, nonceSize);
var tag = encryptedData.Slice(4 + nonceSize + 4, tagSize);
var cipherBytes = encryptedData.Slice(4 + nonceSize + 4 + tagSize, cipherSize);
// Decrypt
Span<byte> plainBytes = cipherSize < 1024
? stackalloc byte[cipherSize]
: new byte[cipherSize];
using var aes = new AesGcm(_key);
aes.Decrypt(nonce, cipherBytes, tag, plainBytes);
// Convert plain bytes back into string
return Encoding.UTF8.GetString(plainBytes);
}
有关完整实施和示例,请参阅 dotnetfiddle。
请注意,我写这个是为了网络传输,所以所有内容都被编码成一个大的base-64字符串;或者,您可以通过 out
参数分别 return nonce
、tag
和 cipherBytes
。
网络设置也是我发送 nonce 和标记大小的原因:class 可能由具有不同运行时环境的不同应用程序使用,这些应用程序可能具有不同的支持参数大小。
我刚刚注意到 .NET Standard 2.1/.NET Core 3.0 终于添加了一个 class for AES-GCM encryption.
然而,它的 API 似乎与通常的 .NET 加密 classes 略有不同:它的 Encrypt
函数要求为密文和标签,而不是自己提供它们。不幸的是,文档中没有示例显示 class.
我知道如何从理论上计算 AES 加密的预期密文大小,但我想知道这是否真的是 "guess" 密文缓冲区大小的预期方法。通常加密库会提供处理这些计算的函数。
有人有关于如何正确使用AesGcm
加密字节数组的示例吗?
我现在想通了。
我忘记了,在GCM中,密文has the same length as the plain text;与 CBC 等其他加密模式相反,不需要填充。随机数和标记长度分别由 AesGcm
的 NonceByteSizes
和 TagByteSizes
属性确定。
使用它,可以通过以下方式进行加密:
public string Encrypt(string plain)
{
// Get bytes of plaintext string
byte[] plainBytes = Encoding.UTF8.GetBytes(plain);
// Get parameter sizes
int nonceSize = AesGcm.NonceByteSizes.MaxSize;
int tagSize = AesGcm.TagByteSizes.MaxSize;
int cipherSize = plainBytes.Length;
// We write everything into one big array for easier encoding
int encryptedDataLength = 4 + nonceSize + 4 + tagSize + cipherSize;
Span<byte> encryptedData = encryptedDataLength < 1024
? stackalloc byte[encryptedDataLength]
: new byte[encryptedDataLength].AsSpan();
// Copy parameters
BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(0, 4), nonceSize);
BinaryPrimitives.WriteInt32LittleEndian(encryptedData.Slice(4 + nonceSize, 4), tagSize);
var nonce = encryptedData.Slice(4, nonceSize);
var tag = encryptedData.Slice(4 + nonceSize + 4, tagSize);
var cipherBytes = encryptedData.Slice(4 + nonceSize + 4 + tagSize, cipherSize);
// Generate secure nonce
RandomNumberGenerator.Fill(nonce);
// Encrypt
using var aes = new AesGcm(_key);
aes.Encrypt(nonce, plainBytes.AsSpan(), cipherBytes, tag);
// Encode for transmission
return Convert.ToBase64String(encryptedData);
}
对应的解密如下:
public string Decrypt(string cipher)
{
// Decode
Span<byte> encryptedData = Convert.FromBase64String(cipher).AsSpan();
// Extract parameter sizes
int nonceSize = BinaryPrimitives.ReadInt32LittleEndian(encryptedData.Slice(0, 4));
int tagSize = BinaryPrimitives.ReadInt32LittleEndian(encryptedData.Slice(4 + nonceSize, 4));
int cipherSize = encryptedData.Length - 4 - nonceSize - 4 - tagSize;
// Extract parameters
var nonce = encryptedData.Slice(4, nonceSize);
var tag = encryptedData.Slice(4 + nonceSize + 4, tagSize);
var cipherBytes = encryptedData.Slice(4 + nonceSize + 4 + tagSize, cipherSize);
// Decrypt
Span<byte> plainBytes = cipherSize < 1024
? stackalloc byte[cipherSize]
: new byte[cipherSize];
using var aes = new AesGcm(_key);
aes.Decrypt(nonce, cipherBytes, tag, plainBytes);
// Convert plain bytes back into string
return Encoding.UTF8.GetString(plainBytes);
}
有关完整实施和示例,请参阅 dotnetfiddle。
请注意,我写这个是为了网络传输,所以所有内容都被编码成一个大的base-64字符串;或者,您可以通过 out
参数分别 return nonce
、tag
和 cipherBytes
。
网络设置也是我发送 nonce 和标记大小的原因:class 可能由具有不同运行时环境的不同应用程序使用,这些应用程序可能具有不同的支持参数大小。