c# - 在 Angular 中加密并在 C# 中解密
问题描述
我有在 Angular 上加密数据的代码,但我不知道如何在服务器端解密
var panno = CryptoJS.AES.encrypt("FEAPS8905Q", "myPassword").toString();
以角度加密,U2FsdGVkX19mi5mXlJ14Lj0XcJBbqMPDzi/UeNXK4Cw=
在使用 Http.post 方法发送加密后,我没有得到确切的数据,而是得到楀뢖᷈鍩ԏ건뫨샞일䜍钚䁞
我也使用了这个参考Decrypting on C#,但我得到了一些数据,比如 壓섢⻫捼笺ﵑ戛ꔉ됒퍿誁累♟콒ꚦ
public string Decrypt(string cipherText)
{
string EncryptionKey = "myPassword";
cipherText = cipherText.Replace(" ", "+");
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] {
0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.Padding = PaddingMode.None;
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(cipherBytes, 0, cipherBytes.Length);
cs.Close();
}
cipherText = Encoding.Unicode.GetString(ms.ToArray());
}
}
return cipherText;
}
解决方案
CryptoJS.AES.encrypt(text, password)
使用派生算法从您的密码中隐式派生加密密钥和 iv,这对于 C# 来说不是原生的。与其依赖隐式推导 - 最好自己明确地这样做,使用众所周知的算法,如 PBKDF2。
需要密钥派生,因为您的密码可以具有任意大小,但给定算法 (AES) 需要特定大小的密钥,例如 256 位。所以我们需要从任意长度的密码变成固定大小的密钥(以不可逆的方式)。
示例 JavaScript 代码:
function encrypt (msg, pass) {
// random salt for derivation
var keySize = 256;
var salt = CryptoJS.lib.WordArray.random(16);
// well known algorithm to generate key
var key = CryptoJS.PBKDF2(pass, salt, {
keySize: keySize/32,
iterations: 100
});
// random IV
var iv = CryptoJS.lib.WordArray.random(128/8);
// specify everything explicitly
var encrypted = CryptoJS.AES.encrypt(msg, key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
});
// combine everything together in base64 string
var result = CryptoJS.enc.Base64.stringify(salt.concat(iv).concat(encrypted.ciphertext));
return result;
}
在 C# 中解密它现在很容易:
public static string Decrypt(string cipherText, string password) {
byte[] cipherBytes = Convert.FromBase64String(cipherText);
using (Aes encryptor = Aes.Create()) {
// extract salt (first 16 bytes)
var salt = cipherBytes.Take(16).ToArray();
// extract iv (next 16 bytes)
var iv = cipherBytes.Skip(16).Take(16).ToArray();
// the rest is encrypted data
var encrypted = cipherBytes.Skip(32).ToArray();
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, salt, 100);
encryptor.Key = pdb.GetBytes(32);
encryptor.Padding = PaddingMode.PKCS7;
encryptor.Mode = CipherMode.CBC;
encryptor.IV = iv;
// you need to decrypt this way, not the way in your question
using (MemoryStream ms = new MemoryStream(encrypted)) {
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Read)) {
using (var reader = new StreamReader(cs, Encoding.UTF8)) {
return reader.ReadToEnd();
}
}
}
}
}
如果您了解后果,您可以使用固定盐(或例如应用程序中每个用户的固定盐),并减少 PBKDF2 中的迭代次数。不过不要使用固定的 IV,也不要使用部分密钥作为 IV。
推荐阅读
- python - Python 函数定型
- powerbi-desktop - 是否有任何服务或 API 可以在 web 上呈现保存的 pbix power BI 文件?不使用 power bi web 或 azure 服务?
- java - Runtime.getRuntime().freeMemory() 显示 50% 的可用内存,但我仍然面临 JAR 应用程序的内存不足错误
- javascript - 如何使用 node.js 中的 ac 头文件解析 UDP 数据包
- javascript - 将 swiperjs 与 Vuejs 一起使用
- sql-server - 从 Oracle 数据库中获取每条记录并将其插入 SQL Server 数据库表中而不会丢失任何数据?
- java - java/javac -version 命令无响应
- laravel - 无法删除或更新父行:即使存在 onDelete Cascade 和 onUpdate 级联,外键约束也会失败?
- powerbi - 如何在 PoweBi 的时间序列中找到变化点
- lua - 在 Lua 编程中使用 for 循环