使用AesGcm类 [英] Using the AesGcm class

查看:85
本文介绍了使用AesGcm类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是注意到.NET Standard 2.1/.NET Core 3.0最终添加了

I just noticed that .NET Standard 2.1/.NET Core 3.0 finally added a class for AES-GCM encryption.

但是,它的API似乎与通常的.NET加密类略有不同:

However, its API seems to be slightly different from the usual .NET crypto classes: Its Encrypt function asks for pre-allocated byte arrays for the cipher text and the tag, instead of providing them itself. Unfortunately there is no example in the docs showing proper usage of that class.

从理论上讲,我知道如何计算AES加密的预期密文大小,但是我想知道这是否真的是一种猜测"那里密文缓冲区大小的方法.通常,加密库提供负责这些计算的功能.

I know how to calculate the expected cipher text size for an AES encryption in theory, but I wonder whether it is really the intended approach to kind of "guess" a buffer size for the cipher text there. Usually crypto libraries provide functions that take care of those calculations.

有人举过一个例子,说明如何使用 AesGcm 正确加密字节数组吗?

Does someone have an example on how to properly encrypt a byte array using AesGcm?

推荐答案

我现在已经知道了.

我忘记了在GCM中,密文具有与纯文本相同的长度;与其他加密模式(例如CBC)相反,不需要填充.随机数和标记的长度分别由 AesGcm NonceByteSizes TagByteSizes 属性确定.

I forgot that in GCM, the cipher text has the same length as the plain text; contrary to other encryption modes like CBC, no padding is required. The nonce and tag lengths are determined by the NonceByteSizes and TagByteSizes properties of AesGcm, respectively.

使用此方法,可以通过以下方式进行加密:

Using this, encryption can be done in the following way:

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 .

See dotnetfiddle for the full implementation and an example.

请注意,我是为网络传输编写的,因此所有内容都编码为一个大的base-64字符串;或者,您可以通过 out 参数分别返回 nonce tag cipherBytes .

Note that I wrote this for network transmission, so everything is encoded into one, big base-64 string; alternatively, you can return nonce, tag and cipherBytes separately via out parameters.

网络设置也是我发送随机数和标记大小的原因:该类可能被具有不同运行时环境(可能具有不同支持的参数大小)的不同应用程序使用.

The network setting is also the reason why I send the nonce and tag sizes: The class might be used by different applications with different runtime environments, which might have different supported parameter sizes.

这篇关于使用AesGcm类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆