Min*_*Con 2 .net c# encryption cryptography node.js
我尝试在 C# 中解密的数据在 Nodejs 中使用 AES-256 算法进行加密,代码如下。
const crypto = require('crypto');
const validator = require('validator');
const algorithm = 'aes256';
const inputEncoding = 'utf8';
const outputEncoding = 'hex';
const iv = crypto.randomBytes(16)
function encrypt(key,text) {
key = processKey(key);
let cipher = crypto.createCipheriv(algorithm, key, iv);
let ciphered = cipher.update(text, inputEncoding, outputEncoding);
ciphered += cipher.final(outputEncoding);
return ciphered;
}
Run Code Online (Sandbox Code Playgroud)
现在,我获得了长度为 32 的加密数据(如“1234567304e07a5d2e93fbeefd0e417e”)和长度为 32 的密钥(如“123456673959499f9d37623168b2c977”)。
我尝试使用下面的 C# 代码解密相同的内容,但收到错误“要解密的数据长度无效”。请提供建议。
public static string Decrypt(string combinedString, string keyString)
{
string plainText;
byte[] combinedData = StringToByteArray(combinedString);
Aes aes = Aes.Create();
aes.Key = Encoding.UTF8.GetBytes(keyString);
byte[] iv = new byte[aes.BlockSize / 8];
byte[] cipherText = new byte[combinedData.Length - iv.Length];
Array.Copy(combinedData, iv, iv.Length);
Array.Copy(combinedData, iv.Length, cipherText, 0, cipherText.Length);
aes.IV = iv;
aes.Mode = CipherMode.CBC;
ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream(cipherText))
{
using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
plainText = sr.ReadToEnd();
}
}
return plainText;
}
}
public static byte[] StringToByteArray(string hex) {
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
Run Code Online (Sandbox Code Playgroud)
下面是 Node.js 中的解密代码,运行良好
const crypto = require('../functions/crypto');
const assert = require('assert');
const { v4: uuidv4 } = require('uuid');
describe('crypto module', function() {
it('should work', function(done) {
const toHash = 'Octomate';
const hashKey = uuidv4();
const hash = crypto.encrypt(hashKey, toHash);
const decrypted = crypto.decrypt(hashKey, hash);
assert.strictEqual(toHash, decrypted);
done();
});
});
Run Code Online (Sandbox Code Playgroud)
发布的 NodeJS 在 CBC 模式下使用 AES-256 执行加密。明文采用UTF8编码,密文采用十六进制编码。此外,还会生成随机 IV 并用于加密。由于方法processKey没有贴出来,就不做进一步的考虑,所以使用下面的NodeJS代码衍生出一个C#代码进行解密:
const crypto = require('crypto');
const validator = require('validator');
const algorithm = 'aes256';
const inputEncoding = 'utf8';
const outputEncoding = 'hex';
const iv = crypto.randomBytes(16)
function encrypt(key,text) {
//key = processKey(key); // not posted
let cipher = crypto.createCipheriv(algorithm, key, iv);
let ciphered = cipher.update(text, inputEncoding, outputEncoding);
ciphered += cipher.final(outputEncoding);
return ciphered;
}
const key = '123456673959499f9d37623168b2c977';
const text = 'The quick brown fox jumps over the lazy dog'
const encrypted = encrypt(key, text);
console.log("IV (hex): " + iv.toString('hex'));
console.log("Ciphertext (hex): " + encrypted);
Run Code Online (Sandbox Code Playgroud)
使用发布的密钥,123456673959499f9d37623168b2c977明文The quick brown fox jumps over the lazy dog会产生以下输出:
IV (hex): 850bd88afd08c4ea14e75276277644f0
Ciphertext (hex): 5167ac87ebc79d5240255ff687c6bc8981c8791c353367a2e238a10e0983bf16e230ccf0511096f60c224b99927b3364
Run Code Online (Sandbox Code Playgroud)
请注意,由于随机 IV,每次加密都会生成不同的密文。
C#中的解密可以如下完成:
string ciphertext = "5167ac87ebc79d5240255ff687c6bc8981c8791c353367a2e238a10e0983bf16e230ccf0511096f60c224b99927b3364";
string key = "123456673959499f9d37623168b2c977";
string iv = "850bd88afd08c4ea14e75276277644f0";
string decryptedText = Decrypt(ciphertext, key, iv);
Console.WriteLine("Decrypted text: " + decryptedText);
Run Code Online (Sandbox Code Playgroud)
和
public static string Decrypt(string ciphertextHex, string keyUtf8, string ivHex)
{
byte[] ciphertext = StringToByteArray(ciphertextHex);
byte[] iv = StringToByteArray(ivHex);
string plaintext = "";
using (Aes aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(keyUtf8);
aes.IV = iv;
aes.Mode = CipherMode.CBC; // default
aes.Padding = PaddingMode.PKCS7; // default
ICryptoTransform decipher = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream(ciphertext))
{
using (CryptoStream cs = new CryptoStream(ms, decipher, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs, Encoding.UTF8)) // UTF8: default
{
plaintext = sr.ReadToEnd();
}
}
}
}
return plaintext;
}
Run Code Online (Sandbox Code Playgroud)
和
// from /sf/answers/22498311/
public static byte[] StringToByteArray(string hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
Run Code Online (Sandbox Code Playgroud)
请注意以下事项:
解密和加密必须使用相同的 IV。由于 IV 的大小是已知的(与块大小相同)并且 IV 不是秘密的,因此它通常放在字节级别的密文前面(未加密且没有分隔符),并且结果是 Base64 编码的。该数据被发送到接收器,接收器对接收到的数据进行 Base64 解码,然后分离。
在发布的 NodeJS 代码中不会发生这种情况。然而,在您发布的C# 代码中,这种连接正是预期的,因此执行了 IV 和密文的分离。在我的评论中,我描述了 NodeJS 代码中连接 IV 和密文的更改,以便可以使用 C# 代码解密结果。
由于显然 NodeJS 代码是主要代码并且它不会连接,因此我的答案中发布的 C# 代码也不会连接。然而,在这种情况下,IV 必须作为参数传递,否则,如已经提到的,解密是不可能的。
不幸的是,发布的示例不是很有帮助,因为您只发布了密钥和密文(顺便说一句,它只有 16 个字节长,因为它是十六进制编码的),而不是随机生成的 IV。所以解密是不可能的。该示例也不能用于密文的比较,因为由于随机 IV,每次都会生成不同的密文。
由于 NodeJS 代码使用 AES-256,因此密钥大小必须为 32 字节。因此密钥可能是用 UTF8 编码的。根据这些值,也可以进行十六进制编码,但这只会产生 16 字节的密钥。由于该方法processKey未发布,因此不能排除对密钥进行进一步处理,此处不予考虑。
不幸的是,发布的用于解密的 NodeJS 代码也没有多大帮助,因为没有定义几种方法(例如crypto.encrypt,crypto.decrypt),并且至少我看不到与发布的用于加密的 NodeJS 代码有任何有用的关系。
| 归档时间: |
|
| 查看次数: |
2639 次 |
| 最近记录: |