【问题标题】:C# AES decryption returns junk dataC# AES 解密返回垃圾数据
【发布时间】:2020-10-09 03:56:48
【问题描述】:

我正在使用 aes.js 加密纯文本并在 c# 中解密

JS中的加密代码

var aesKey = "87E67EF6-ECFB-4295-ACA3-B3F06BE489B1-87E67EF6-ECFB-4295-ACA3-B3F06BE489B1";
var encrypted = CryptoJS.AES.encrypt(JSON.stringify(emailParams), aesKey, {
                keySize: 256,
                padding: CryptoJS.pad.Pkcs7
});
var encAesKey = aesKey;
var encData = new Object();
encData.pId = 1234;
encData.encAesKey = encAesKey;
encData.encAesData = encrypted.toString();

我正在尝试解密 C# 中的加密字符串

byte[] data = Convert.FromBase64String(cipherText);
MemoryStream ms = new MemoryStream();
Rijndael alg = Rijndael.Create();
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(key, new byte[] { 0x43, 0x72, 0x6e, 0x6d, 0x54, 0x4d, 0x65, 0x94, 0x16, 0x32, 0x44, 0x84, 0x7e, 0x18, 0x64, 0x76, 0x6e, 0x63, 0x64, 0x7a, 0x5f, 0x84, 0x7f, 0x9a });
alg.KeySize = 256;
alg.Key = pdb.GetBytes(32);
alg.IV = pdb.GetBytes(16);
alg.Padding = PaddingMode.PKCS7;
CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(data, 0, data.Length);
//cs.Close();
string st = System.Text.Encoding.ASCII.GetString(ms.ToArray());
return st;

如果我取消注释 cs.Close(); 行,则会在此行抛出“填充无效且无法删除”。 如果我评论cs.Close(); 行,它正在解密为垃圾数据。

这是什么原因?我错过了什么吗? 你能帮我解决这个问题吗

【问题讨论】:

  • 这两个代码根本不适合,因为使用了不同的 KDF。 Rfc2898DeriveBytes 对应的 CryptoJS 是 PBKDF2。 KDF 与随机生成的盐结合使用,盐与密文一起发送给接收者。 IV 要么通过 KDF 生成(与密钥一起),要么单独生成(在后一种情况下也是随机生成的,并与盐/密文一起发送)。
  • 解决方案是什么?我需要解密加密的字符串。使用 CryptoJS.AES.encrypt 加密
  • 当前 CryptoJS 代码使用 OpenSSL KDF EVP_BytesToKey。如果不能更改 CryptoJS 代码,则需要一个 C# 对应项,例如here(未测试)。如果可以更改 CryptoJS 代码,那么 PBKDF2 将是一个更好的替代方案(更好,因为EVP_BytesToKey 不是标准并且被认为相对不安全)。或者,可以直接使用密钥而不是密码。所以这取决于要求。
  • 顺便说一下encrypt.encrypt(aesKey) 没有定义。请贴出相应的代码。
  • encrypt.encrypt(aesKey) 在这部分不需要。更新了问题

标签: c# aes


【解决方案1】:

由于您没有回答 @Topaco 关于您的要求的问题,我更改了示例代码以显示使用 AES CBC 256 和 PBKDF2 密钥派生的跨平台加密。

请注意,我懒得将我的代码用于您的特定数据,所以我让您自己来获取您喜欢的输入数据。

安全警告:两个代码都没有任何异常处理,并且由于 Javascript 在浏览器中运行,PBKDF2 迭代次数 (1000) 很低。 以及 salt & iv 处理和拆分数据需要一些改进。

Javascript 代码(用于加密)提供(连接的)salt、iv 和加密数据的输出,这些数据在 C# 端(用于解密)被拆分以提供 PBKDF2 和 AES 解密函数。

这是两个程序的输出 - 您可以在此处运行两个程序的实时示例 ( JS:https://repl.it/@javacrypto/SoJsAesCbcPbkdf2EncryptOnly#index.js,C#:https://repl.it/@javacrypto/SoCAesCbcPbkdf2DecryptOnly)。

Javascript:

SO AES CBC 256 PBKDF2 encryption only (JS)
transitmessage: 8c22a29d14f5e1e1582a795bfec8e4f8b91af5e6390c1b0b598b7d0d63cd2e6f1LSz9IT93Fe6OwWYZ7Dpj1LrSIwsV46ccs3oV3A2FoBCH6+8Jp+fSLprYqh1adIJ

C#:

SO AES CBC 256 PBKDF2 decryption only (C#)
plaintext: The quick brown fox jumps over the lazy dog

Javascript 代码:

var CryptoJS = require("crypto-js");

console.log('SO AES CBC 256 PBKDF2 encryption only (JS)');

var keySize = 256;
var saltSize = 128;
var ivSize = 128;
var iterations = 1000;

var message = "The quick brown fox jumps over the lazy dog";

var aesKey = "87E67EF6-ECFB-4295-ACA3-B3F06BE489B1-87E67EF6-ECFB-4295-ACA3-B3F06BE489B1";

// pbkdf2
var salt = CryptoJS.lib.WordArray.random(saltSize/8);
var key = CryptoJS.PBKDF2(aesKey, salt, {
    keySize: keySize/32,
    iterations: iterations
  });

// encrypt
var iv = CryptoJS.lib.WordArray.random(ivSize/8);
var encrypted = CryptoJS.AES.encrypt(message, key, { 
    iv: iv, 
    padding: CryptoJS.pad.Pkcs7,
    mode: CryptoJS.mode.CBC
  });
var transitmessage = salt.toString()+ iv.toString() + encrypted.toString();
console.log('transitmessage:', transitmessage);

C#代码:

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class Program {

    public static void Main() {
        Console.WriteLine("SO AES CBC 256 PBKDF2 decryption only (C#)");

    const int ITERATIONS = 1000; // number of pbkdf2 iterations
    String aesData = "87E67EF6-ECFB-4295-ACA3-B3F06BE489B1-87E67EF6-ECFB-4295-ACA3-B3F06BE489B1";
    // data coming from javascript CryptoJS encryption
    string data = "8c22a29d14f5e1e1582a795bfec8e4f8b91af5e6390c1b0b598b7d0d63cd2e6f1LSz9IT93Fe6OwWYZ7Dpj1LrSIwsV46ccs3oV3A2FoBCH6+8Jp+fSLprYqh1adIJ";

    // splitting the datastring
    string saltHex = data.Substring(0, 32);
    string ivHex = data.Substring(32, 32);
    string cipherBase64 = data.Substring(64, (data.Length - 64));
    //Console.WriteLine("saltHex: " + saltHex);
    //Console.WriteLine("ivHex: " + ivHex);
    //Console.WriteLine("cipherBase64: " + cipherBase64);

    // pbkdf2
    Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(aesData, 
    StringToByteArray(saltHex), ITERATIONS);
    byte[] key = pbkdf2.GetBytes(32);

    // decryption
    string decryptedtext;
    using(Aes aesAlg = Aes.Create()) {
            aesAlg.Key = key;
            byte[] IV = StringToByteArray(ivHex);
            byte[] cipherText = Convert.FromBase64String(cipherBase64);
            aesAlg.IV = IV;
            aesAlg.Mode = CipherMode.CBC;
            ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
            using(var msDecrypt = new MemoryStream(cipherText)) {
                using(var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) {
                    using(var srDecrypt = new StreamReader(csDecrypt)) {
                        decryptedtext = srDecrypt.ReadToEnd();
                    }
                }
            }
        }
    Console.WriteLine("plaintext: " + decryptedtext);
    }

  static byte[] StringToByteArray(String hex) {
    int NumberChars = hex.Length;
    byte[] bytes = new byte[NumberChars / 2];
    for (int i = 0; i < NumberChars; i += 2)
    bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
    return bytes;
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多