gpt4 book ai didi

c# - NodeJS 和 C# 中的 AES256 加密/解密

转载 作者:搜寻专家 更新时间:2023-10-31 22:39:22 25 4
gpt4 key购买 nike

我对以下问题的结果有些随意:

并创建了以下类文件...

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace T1.CoreUtils.Utilities
{
public static class CryptoUtility
{
public static string Encrypt(string input, string passphrase = null)
{
byte[] key, iv;
DeriveKeyAndIV(Encoding.ASCII.GetBytes(passphrase), null, 1, out key, out iv);

return Convert.ToBase64String(EncryptStringToBytes(input, key, iv));
}

public static string Decrypt(string inputBase64, string passphrase = null)
{
byte[] key, iv;
DeriveKeyAndIV(Encoding.ASCII.GetBytes(passphrase), null, 1, out key, out iv);

return DecryptStringFromBytes(Convert.FromBase64String(inputBase64), key, iv);
}

private static void DeriveKeyAndIV(byte[] data, byte[] salt, int count, out byte[] key, out byte[] iv)
{
List<byte> hashList = new List<byte>();
byte[] currentHash = new byte[0];

int preHashLength = data.Length + ((salt != null) ? salt.Length : 0);
byte[] preHash = new byte[preHashLength];

System.Buffer.BlockCopy(data, 0, preHash, 0, data.Length);
if (salt != null)
System.Buffer.BlockCopy(salt, 0, preHash, data.Length, salt.Length);

MD5 hash = MD5.Create();
currentHash = hash.ComputeHash(preHash);

for (int i = 1; i < count; i++)
{
currentHash = hash.ComputeHash(currentHash);
}

hashList.AddRange(currentHash);

while (hashList.Count < 48) // for 32-byte key and 16-byte iv
{
preHashLength = currentHash.Length + data.Length + ((salt != null) ? salt.Length : 0);
preHash = new byte[preHashLength];

System.Buffer.BlockCopy(currentHash, 0, preHash, 0, currentHash.Length);
System.Buffer.BlockCopy(data, 0, preHash, currentHash.Length, data.Length);
if (salt != null)
System.Buffer.BlockCopy(salt, 0, preHash, currentHash.Length + data.Length, salt.Length);

currentHash = hash.ComputeHash(preHash);

for (int i = 1; i < count; i++)
{
currentHash = hash.ComputeHash(currentHash);
}

hashList.AddRange(currentHash);
}
hash.Clear();
key = new byte[32];
iv = new byte[16];
hashList.CopyTo(0, key, 0, 32);
hashList.CopyTo(32, iv, 0, 16);
}

static byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;

// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{

//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}


// Return the encrypted bytes from the memory stream.
return encrypted;

}

static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");

// Declare the string used to hold
// the decrypted text.
string plaintext = null;

// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Key = Key;
rijAlg.IV = IV;

// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{

// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}

}

return plaintext;

}
}
}

从这里,我通过 Node 生成了以下内容:

var crypto = require('crypto');
var input = "This is î╥≤ what it is.";
var passkey= "This is my password.";
var cipher = crypto.createCipher('aes-256-cbc', passkey);
var encrypted = cipher.update(input, 'utf8', 'base64') + cipher.final('base64');
encrypted
// '9rTbNbfJkYVE2m5d8g/8b/qAfeCU9rbk09Na/Pw0bak='

input = "I am the walrus, coo coo cachoo!";
passkey = "I am a ≥ò'ÿ boy baby!";
cipher = crypto.createCipher('aes-256-cbc', passkey);
encrypted = cipher.update(input, 'utf8', 'base64') + cipher.final('base64');
// 'j/e+f5JU5yerSvO7FBJzR1tGro0Ie3L8sWYaupRW1JJhraGqBfQ9z+h85VhSzEjD'

var decipher = crypto.createDecipher('aes-256-cbc', passkey);
var plain = decipher.update(encrypted, 'base64', 'utf8') + decipher.final('utf8');
plain
// 'I am the walrus, coo coo cachoo!'

据此,我创建了以下测试用例:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace T1.CoreUtils.Test.Utilities.Tests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void EncryptReturnsExpectedValue1_unicode_in_plaintext()
{
var passkey = "This is my password.";
var plain = "This is î╥≤ what it is.";
var encrypted = "9rTbNbfJkYVE2m5d8g/8b/qAfeCU9rbk09Na/Pw0bak=";

var actual = T1.CoreUtils.Utilities.CryptoUtility.Encrypt(plain, passkey);
Assert.AreEqual(encrypted, actual);
}

[TestMethod]
public void EncryptReturnsExpectedValue2_unicode_in_passkey()
{
var passkey = "I am a ≥ò'ÿ boy baby!";
var plain = "I am the walrus, coo coo cachoo!";
var encrypted = "j/e+f5JU5yerSvO7FBJzR1tGro0Ie3L8sWYaupRW1JJhraGqBfQ9z+h85VhSzEjD";

var actual = T1.CoreUtils.Utilities.CryptoUtility.Encrypt(plain, passkey);
Assert.AreEqual(encrypted, actual);
}

[TestMethod]
public void DecryptReturnsExpectedValue1()
{
var passkey = "This is my password.";
var plain = "This is î╥≤ what it is.";
var encrypted = "9rTbNbfJkYVE2m5d8g/8b/qAfeCU9rbk09Na/Pw0bak=";

var actual = T1.CoreUtils.Utilities.CryptoUtility.Decrypt(encrypted, passkey);
Assert.AreEqual(plain, actual);
}

[TestMethod]
public void DecryptReturnsExpectedValue2()
{
var passkey = "I am a ≥ò'ÿ boy baby!";
var plain = "I am the walrus, coo coo cachoo!";
var encrypted = "j/e+f5JU5yerSvO7FBJzR1tGro0Ie3L8sWYaupRW1JJhraGqBfQ9z+h85VhSzEjD";

var actual = T1.CoreUtils.Utilities.CryptoUtility.Decrypt(encrypted, passkey);
Assert.AreEqual(plain, actual);
}
}
}

通行证:

  • 加密返回预期值1_unicode_in_plaintext
  • 解密ReturnsExpectedValue1

失败:

  • 加密返回预期值2_unicode_in_passkey
  • 解密ReturnsExpectedValue2

我只能猜测问题出在 DeriveKeyAndIV 方法中。如果我自己找到它,我会尝试几种不同的方法并回答。

最佳答案

好的,在检查 node.js 的加密源代码后,我确定编码使用了一个新的 Buffer(passkey, 'binary'),它只使用原始值 x 和 0xFF 作为所使用的字节,所以我在 C# 中创建了一个匹配方法...这是有问题的方法...

private static byte[] RawBytesFromString(string input)
{
var ret = new List<Byte>();

foreach (char x in input)
{
var c = (byte)((ulong)x & 0xFF);
ret.Add(c);
}

return ret.ToArray();
}

以及更新/工作的 CryptoUtil.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace T1.CoreUtils.Utilities
{
public static class CryptoUtility
{
/* Wanting to stay compatible with NodeJS
* http://stackoverflow.com/questions/18502375/aes256-encryption-decryption-in-both-nodejs-and-c-sharp-net/
* http://stackoverflow.com/questions/12261540/decrypting-aes256-encrypted-data-in-net-from-node-js-how-to-obtain-iv-and-key
* http://stackoverflow.com/questions/8008253/c-sharp-version-of-openssl-evp-bytestokey-method
*
* var cipher = crypto.createCipher('aes-256-cbc', 'passphrase');
* var encrypted = cipher.update("test", 'utf8', 'base64') + cipher.final('base64');
*
* var decipher = crypto.createDecipher('aes-256-cbc', 'passphrase');
* var plain = decipher.update(encrypted, 'base64', 'utf8') + decipher.final('utf8');
*/

public static string Encrypt(string input, string passphrase = null)
{
byte[] key, iv;
DeriveKeyAndIV(RawBytesFromString(passphrase), null, 1, out key, out iv);

return Convert.ToBase64String(EncryptStringToBytes(input, key, iv));
}

public static string Decrypt(string inputBase64, string passphrase = null)
{
byte[] key, iv;
DeriveKeyAndIV(RawBytesFromString(passphrase), null, 1, out key, out iv);

return DecryptStringFromBytes(Convert.FromBase64String(inputBase64), key, iv);
}

private static byte[] RawBytesFromString(string input)
{
var ret = new List<Byte>();

foreach (char x in input)
{
var c = (byte)((ulong)x & 0xFF);
ret.Add(c);
}

return ret.ToArray();
}

private static void DeriveKeyAndIV(byte[] data, byte[] salt, int count, out byte[] key, out byte[] iv)
{
List<byte> hashList = new List<byte>();
byte[] currentHash = new byte[0];

int preHashLength = data.Length + ((salt != null) ? salt.Length : 0);
byte[] preHash = new byte[preHashLength];

System.Buffer.BlockCopy(data, 0, preHash, 0, data.Length);
if (salt != null)
System.Buffer.BlockCopy(salt, 0, preHash, data.Length, salt.Length);

MD5 hash = MD5.Create();
currentHash = hash.ComputeHash(preHash);

for (int i = 1; i < count; i++)
{
currentHash = hash.ComputeHash(currentHash);
}

hashList.AddRange(currentHash);

while (hashList.Count < 48) // for 32-byte key and 16-byte iv
{
preHashLength = currentHash.Length + data.Length + ((salt != null) ? salt.Length : 0);
preHash = new byte[preHashLength];

System.Buffer.BlockCopy(currentHash, 0, preHash, 0, currentHash.Length);
System.Buffer.BlockCopy(data, 0, preHash, currentHash.Length, data.Length);
if (salt != null)
System.Buffer.BlockCopy(salt, 0, preHash, currentHash.Length + data.Length, salt.Length);

currentHash = hash.ComputeHash(preHash);

for (int i = 1; i < count; i++)
{
currentHash = hash.ComputeHash(currentHash);
}

hashList.AddRange(currentHash);
}
hash.Clear();
key = new byte[32];
iv = new byte[16];
hashList.CopyTo(0, key, 0, 32);
hashList.CopyTo(32, iv, 0, 16);
}

static byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged cipher = new RijndaelManaged())
{
cipher.Key = Key;
cipher.IV = IV;
//cipher.Mode = CipherMode.CBC;
//cipher.Padding = PaddingMode.PKCS7;

// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = cipher.CreateEncryptor(cipher.Key, cipher.IV);

// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{

//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}


// Return the encrypted bytes from the memory stream.
return encrypted;

}

static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");

// Declare the string used to hold
// the decrypted text.
string plaintext = null;

// Create an RijndaelManaged object
// with the specified key and IV.
using (var cipher = new RijndaelManaged())
{
cipher.Key = Key;
cipher.IV = IV;
//cipher.Mode = CipherMode.CBC;
//cipher.Padding = PaddingMode.PKCS7;

// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = cipher.CreateDecryptor(cipher.Key, cipher.IV);

// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{

// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}

}

return plaintext;

}
}
}

注意:还有一些与此相关的代码......

这些分别不在nugetnpm中,因为它们真的不属于那里……主要是为了想法和引用。我确实需要更好地冲洗 Node 端,以便匹配。

关于c# - NodeJS 和 C# 中的 AES256 加密/解密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18502375/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com