首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用标记作为基本64字符串时,C# BouncyCastle Mac在GCM中检查失败

使用标记作为基本64字符串时,C# BouncyCastle Mac在GCM中检查失败
EN

Stack Overflow用户
提问于 2022-03-15 12:02:10
回答 1查看 694关注 0票数 1

我正在尝试使用BouncyCastle库用GCM实现AES 256加密。

到目前为止,我已经通过将Key and Nonce作为字符串传递给Tag作为字节数组来实现它的工作。

这是加密方法。

代码语言:javascript
运行
复制
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;
}

这是解密码。

代码语言:javascript
运行
复制
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"

因此,此代码工作如下:

代码语言:javascript
运行
复制
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"错误。

代码语言:javascript
运行
复制
// 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);
    ...
    ...

为什么会发生这种情况?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-15 15:02:47

标记在加密期间自动创建,并在解密期间用于对数据进行身份验证(在DoFinal()中这两种情况下)。

由于C#/BC自动将标记与密文连接起来,因此在加密或解密过程中不需要显式传递标记:

代码语言:javascript
运行
复制
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 _~--密文_标签)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71481895

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档