我正在尝试使用BouncyCastle库用GCM实现AES 256加密。
到目前为止,我已经通过将Key and Nonce
作为字符串传递给Tag
作为字节数组来实现它的工作。
这是加密方法。
private static byte[] EncryptWithGCM(string plaintext, string KeyString, string NonceString, byte[] tag)
{
byte[] key = Convert.FromBase64String(KeyString);
byte[] nonce = Convert.FromBase64String(NonceString);
var plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
var bcCiphertext = new byte[plaintextBytes.Length + tagLenth];
var cipher = new GcmBlockCipher(new AesEngine());
var parameters = new AeadParameters(new KeyParameter(key), tagLenth * 8, nonce);
cipher.Init(true, parameters);
var offset = cipher.ProcessBytes(plaintextBytes, 0, plaintextBytes.Length, bcCiphertext, 0);
cipher.DoFinal(bcCiphertext, offset);
var ciphertext = new byte[plaintextBytes.Length];
Buffer.BlockCopy(bcCiphertext, 0, ciphertext, 0, plaintextBytes.Length);
Buffer.BlockCopy(bcCiphertext, plaintextBytes.Length, tag, 0, tagLenth);
return ciphertext;
}
这是解密码。
private static string DecryptWithGCM(string EncryptedString, string KeyString, string NonceString, byte[] tag)
{
byte[] key = Convert.FromBase64String(KeyString);
byte[] nonce = Convert.FromBase64String(NonceString);
byte[] ciphertext = Convert.FromBase64String(EncryptedString);
var plaintextBytes = new byte[ciphertext.Length];
var cipher = new GcmBlockCipher(new AesEngine());
var parameters = new AeadParameters(new KeyParameter(key), tag.Length * 8, nonce);
cipher.Init(false, parameters);
var bcCiphertext = ciphertext.Concat(tag).ToArray();
var offset = cipher.ProcessBytes(bcCiphertext, 0, bcCiphertext.Length, plaintextBytes, 0);
cipher.DoFinal(plaintextBytes, offset);
return Encoding.UTF8.GetString(plaintextBytes);
}
如您所见,除了Tag
之外,我将以字符串的形式传递所有内容。因为当我将Tag
作为字符串传递并将其转换为字节数组时,它不起作用。它显示了误差"Mac check in GCM failed"
。
因此,此代码工作如下:
var rnd = new Random();
var tag = new Byte[16]; //16 bytes
rnd.NextBytes(tag);
string TagString = Convert.ToBase64String(tag);
byte[] EncryptedText = EncryptWithGCM(PlainText, KeyString, NonceString, tag);
string EncryptedString = Convert.ToBase64String(EncryptedText);
string DecryptdText = DecryptWithGCM(EncryptedString, KeyString, NonceString, tag);
但是,当我在加密/解密函数中传递TagString并将其转换回字节数组时,它会引发"Mac check in GCM failed"
错误。
// this code does not work.
private static string DecryptWithGCM(string EncryptedString, string KeyString, string NonceString, string TagString)
{
byte[] key = Convert.FromBase64String(KeyString);
byte[] nonce = Convert.FromBase64String(NonceString);
byte[] tag = Convert.FromBase64String(TagString);
...
...
为什么会发生这种情况?
发布于 2022-03-15 15:02:47
标记在加密期间自动创建,并在解密期间用于对数据进行身份验证(在DoFinal()
中这两种情况下)。
由于C#/BC自动将标记与密文连接起来,因此在加密或解密过程中不需要显式传递标记:
private static string EncryptWithGCM(string plaintext, string keyString, string nonceString)
{
var tagLength = 16;
var key = Convert.FromBase64String(keyString);
var nonce = Convert.FromBase64String(nonceString);
var plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
var ciphertextTagBytes = new byte[plaintextBytes.Length + tagLength];
var cipher = new GcmBlockCipher(new AesEngine());
var parameters = new AeadParameters(new KeyParameter(key), tagLength * 8, nonce);
cipher.Init(true, parameters);
var offset = cipher.ProcessBytes(plaintextBytes, 0, plaintextBytes.Length, ciphertextTagBytes, 0);
cipher.DoFinal(ciphertextTagBytes, offset); // create and append tag: ciphertext | tag
return Convert.ToBase64String(ciphertextTagBytes);
}
private static string DecryptWithGCM(string ciphertextTag, string keyString, string nonceString)
{
var tagLength = 16;
var key = Convert.FromBase64String(keyString);
var nonce = Convert.FromBase64String(nonceString);
var ciphertextTagBytes = Convert.FromBase64String(ciphertextTag);
var plaintextBytes = new byte[ciphertextTagBytes.Length - tagLength];
var cipher = new GcmBlockCipher(new AesEngine());
var parameters = new AeadParameters(new KeyParameter(key), tagLength * 8, nonce);
cipher.Init(false, parameters);
var offset = cipher.ProcessBytes(ciphertextTagBytes, 0, ciphertextTagBytes.Length, plaintextBytes, 0);
cipher.DoFinal(plaintextBytes, offset); // authenticate data via tag
return Encoding.UTF8.GetString(plaintextBytes);
}
请注意,对于GCM (here)来说,使用固定的键,静态Note是一个致命的错误。应该随机生成(非秘密) nonce,并将其与密文和标记一起传递到解密端(通常按以下顺序连接: nonce _~--密文_标签)。
https://stackoverflow.com/questions/71481895
复制相似问题