我有一个ASP.NET核心应用程序,它提供了SPA应用程序要使用的一些数据路由(没有涉及的UI框架,只有JavaScript和HTML5)。响应JSON中的某些值使用AES加密;客户端需要解密值以便向用户显示主题。在客户端,我使用CryptoJS,但我无法解密。如下,这就是我试过的......
首先,这是用于使用AES加密数据的功能(服务器端代码)。它使用SHA256对键和引脚进行哈希处理,并使用键和IV的计算值:
async Task<byte[]> Encrypt(string key, string pin, byte[] data)
{
using (var sha = SHA256.Create())
{
byte[] keyData = sha.ComputeHash(Encoding.UTF8.GetBytes($"{key}"));
byte[] rgbIv = sha.ComputeHash(Encoding.UTF8.GetBytes($"{pin}"));
using (Aes aes = Aes.Create())
{
byte[] rgbKey = keyData.Slice(0, aes.Key.Length); // 32
byte[] iv = rgbIv.Slice(0, aes.IV.Length); // 16
using (ICryptoTransform transform = aes.CreateEncryptor(rgbKey, iv))
using (var stream = new MemoryStream())
using (var cryptStream = new CryptoStream(stream, transform, CryptoStreamMode.Write))
{
await cryptStream.WriteAsync(data, 0, data.Length);
await cryptStream.FlushAsync();
return stream.ToArray();
}
}
}
}
加密数据在模型中存储为Base64编码的字符串,例如:
class Model
{
public string EncryptedValue { get; set; }
}
...
byte[] data = Encoding.Utf8.GetBytes("...");
byte[] encrypted = await Encrypt("api-key", "123456", data);
var model = new Model { EncryptedValue = Convert.ToBase64String(encrypted) };
我使用Bower安装了crypto-js 3.1.12:
bower install crypto-js
我从CryptoJS构建文件夹中选择了所需的JavaScript文件;这是我用来捆绑所有文件的捆绑配置(使用bundleconfig.json
;通过反复试验找到了文件的工作顺序):
{
"outputFileName": "Content/js/encryption.js",
"minify": { "enabled": false },
"inputFiles": [
"bower_components/crypto-js/build/components/core.js",
"bower_components/crypto-js/build/rollups/sha256.js",
"bower_components/crypto-js/build/rollups/aes.js",
"bower_components/crypto-js/build/components/cipher-core.js",
"bower_components/crypto-js/build/components/enc-base64.js"
]
}
由于我在TypeScript中实现了所有客户端功能,因此我还使用以下用于crypto-js的TypeScript定义来获取Visual Studio中的Intellisense:
typings install dt~cryptojs --global
这是我的客户端代码:
import WordArray = CryptoJS.lib.WordArray;
...
decodeData(data: string): JQueryPromise<string> {
let deferred: JQueryDeferred<string> = $.Deferred<string>();
this.obtainPublicKey().done((publicKey: string) => {
this.promptUserPinCode().done((pin: string) => {
let cipherBuffer: WordArray = CryptoJS.enc.Base64.parse(data);
let publicKeyHash: WordArray = CryptoJS.SHA256(CryptoJS.enc.Utf8.parse(publicKey));
let key: WordArray = CryptoJS.lib.WordArray.create(publicKeyHash.words.slice(0, 8), 32);
let pinHash: WordArray = CryptoJS.SHA256(CryptoJS.enc.Utf8.parse(pin));
let iv: WordArray = CryptoJS.lib.WordArray.create(pinHash.words.slice(0, 4), 16);
let cfg: CryptoJS.lib.IBlockCipherCfg = {
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
iv: iv
};
let params: CryptoJS.lib.CipherParamsData = {
ciphertext: cipherBuffer,
key: key,
iv: iv,
algorithm: CryptoJS.algo.AES,
blockSize: 128,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
salt: CryptoJS.lib.WordArray.create([], 0)
};
let decrypted: WordArray = CryptoJS.AES.decrypt(params, key, cfg);
const s = CryptoJS.enc.Utf8.stringify(decrypted);
console.log(s);
deferred.resolve(s);
});
});
return deferred.promise();
}
从C#中的params
对象中挑选cfg
和AES
的配置;我只是想确保CryptoJS使用与服务器完全相同的配置......
解密的数据总是空的,所以我认为解密失败了,但它并没有给我任何错误。我还检查过,如果客户端和服务器上的密钥和IV是相同的,那就是这种情况。我猜CryptoJS使用给定的密钥作为密码,然后从中获取新的密钥信息......如果是这种情况,我可以阻止它......我需要提供密钥和IV信息吗?
我怎样才能使这个工作?