【问题标题】:AES GCM Encryption/Decryption C# and AngularAES GCM 加密/解密 C# 和 Angular
【发布时间】:2023-01-31 18:22:02
【问题描述】:

我正在尝试实施 AES GCM 模式加密。在我的应用程序中,加密发生在 C# 代码中的角度和解密中。 iam 在角度中使用 nodejs 加密库进行加密

Angular 中的加密代码

data = "{hello world}";
var randomIV = CryptoJS.lib.WordArray.random(12).toString();
const ALGO = 'aes-256-gcm';
var forge = require('node-forge');
// encrypt some bytes using GCM mode
var cipher = forge.cipher.createCipher('AES-GCM', _dEncP);
cipher.start({
      iv: randomIV, // should be a 12-byte binary-encoded string or byte buffer
      additionalData: 'nvn', // optional
      tagLength: 128 // optional, defaults to 128 bits
});
cipher.update(forge.util.createBuffer('object' == typeof data ? JSON.stringify(data) : data.toString()));
cipher.finish();
var encryptedData = cipher.output;
const encodedB64 = forge.util.encode64(encryptedData.data);
const tag = cipher.mode.tag;
const tagB64 = forge.util.encode64(tag.data);
// outputs encrypted hex

const trasmitmsg = randomIV + "|" + tagB64 + "|" + encodedB64;

在 C# 中,我正在尝试使用 system.crypto 库

C#中的解密代码

string[] data = cipherText.Split("|");
           
String ivString = data[0];
String additionalString = data[1];
String cipherString = data[2];

byte[] keyBytes = Encoding.UTF8.GetBytes(key);
byte[] ivBytes = Convert.FromBase64String(ivString);

byte[] encdata = Convert.FromBase64String(cipherString);
byte[] tag = Convert.FromBase64String(additionalString);

var aesAlg = new AesGcm(keyBytes);
var plaintextBytes = new byte[encdata.Length];
aesAlg.Decrypt(ivBytes, encdata, tag, plaintextBytes);
var result = Encoding.UTF8.GetString(plaintextBytes)

当我运行这段代码时,出现以下错误 System.Security.Cryptography.CryptographicException:“计算的身份验证标签与输入的身份验证标签不匹配。”

你能帮我看看我在这里做错了什么吗,你有角度(加密)和 c#(解密代码)的示例工作示例吗

【问题讨论】:

    标签: angular aes c#-3.0 aes-gcm


    【解决方案1】:

    IV/nonce 在两个代码中的编码/解码不一致,这导致在加密/解密期间不同的 IV/nonce。此外,在解密期间不考虑附加数据。

    CryptoJS.lib.WordArray.random(12) 生成一个包含在 WordArray 中的 12 字节序列,并用 .toString() 进行十六进制编码,从而产生 24 字节的 IV/nonce。这在加密期间使用。尽管 GCM 可以使用任意长的 IV/nonce,但推荐长度为 12 字节,出于效率和兼容性原因也应保留该长度。为此,必须使用 Latin1 编码器将 WordArray 转换为字节字符串,然后传递给 start() 函数。
    对于拼接,WordArray 不应该使用 Hex 编码器进行转换,而是使用 Base64 编码器进行转换,因为这与标签和密文的编码一致(另外,在 C# 代码中,IV/Nonce 是使用 Base64 解码的)。
    如您所见,在与 node-forge 交互时,由于 WordArray 类型,使用 CryptoJS 效率低下。因此,IV/nonce 的生成应该直接使用 node-forge 完成,这消除了对 CryptoJS 库的依赖(因为 CryptoJS 专门用于在发布的代码中生成 IV/nonce):

    var randomIV = forge.random.getBytesSync(12);
    

    这直接将 IV/nonce 作为字节字符串返回,可以将其直接传递给 start() 函数。对于连接,IV/nonce 必须使用 Base64 编码:

    var randomIVB64 = forge.util.encode64(randomIV);
    

    关于额外的关联数据 (aad),它们是可选的,即它们不必在加密期间使用。但如果在加密期间使用它们,那么它们也必须在解密期间使用。 如果有额外的关联数据,则必须将其连接起来,因为解密方需要它进行解密:

    var aad = 'nvn'
    cipher.start({
          iv: randomIV, 
          additionalData: aad, 
          tagLength: 128 
    });
    ...
    var aadB64 = forge.util.encode64(aad) 
    const trasmitmsg = aadB64 + "|" + randomIVB64 + "|" + tagB64 + "|" + encodedB64;
    

    在 C# 代码中,各个部分将相应地分开:

    ...
    string addString = data[0];
    string ivString = data[1];
    string additionalString = data[2];
    string cipherString = data[3];
    byte[] add = Convert.FromBase64String(addString);
    ...
    

    并且在解密时要考虑额外的相关数据:

    aesAlg.Decrypt(ivBytes, encdata, tag, plaintextBytes, add);
    

    通过这些更改,可以使用 C# 代码解密使用 JavaScript 代码生成的密文。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-14
      • 1970-01-01
      • 1970-01-01
      • 2021-09-30
      • 2021-09-03
      • 2017-10-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多