问题描述
我已经采取了一些调戏以下问题的结果:
- 的
- 的
- 的
和创建以下类文件...
使用系统;
使用System.Collections.Generic;
:使用System.IO;
使用System.Linq的;
使用System.Security.Cryptography;
使用System.Text;使用System.Threading.Tasks
;
命名空间T1.CoreUtils.Utilities
{
公共静态类CryptoUtility
{
公共静态字符串加密(字符串输入,字符串密码= NULL)
{
的byte []键,IV;
DeriveKeyAndIV(Encoding.ASCII.GetBytes(密码),NULL,1,出重点,走出四);
返回Convert.ToBase64String(EncryptStringToBytes(输入,键,IV));
}
公共静态字符串解密(字符串inputBase64,字符串密码= NULL)
{
的byte []键,IV;
DeriveKeyAndIV(Encoding.ASCII.GetBytes(密码),NULL,1,出重点,走出四);
返回DecryptStringFromBytes(Convert.FromBase64String(inputBase64),键,IV);
}
私有静态无效DeriveKeyAndIV(字节[]数据字节[]盐,诠释计数,出的byte []键,出来的byte [] IV)
{
名单,LT;字节> hashList =新的List<位>();
字节[] = currentHash新的字节[0];
INT preHashLength = data.Length +(!?(盐= NULL)salt.Length:0);
字节[] = preHash新的字节[preHashLength]
System.Buffer.BlockCopy(数据,0,preHash,0,data.Length);
如果(盐!= NULL)
System.Buffer.BlockCopy(盐,0,preHash,data.Length,salt.Length);
MD5哈希值= MD5.Create();
currentHash = hash.ComputeHash(preHash);
的for(int i = 1; I<计数;我++)
{
currentHash = hash.ComputeHash(currentHash);
}
hashList.AddRange(currentHash);
,而(hashList.Count< 48)// 32字节的密钥和16字节的IV
{
preHashLength = currentHash.Length + data.Length +(( !?盐= NULL)salt.Length:0);
preHash =新的字节[preHashLength]
System.Buffer.BlockCopy(currentHash,0,preHash,0,currentHash.Length);
System.Buffer.BlockCopy(数据,0,preHash,currentHash.Length,data.Length);
如果(盐!= NULL)
System.Buffer.BlockCopy(盐,0,preHash,currentHash.Length + data.Length,salt.Length);
currentHash = hash.ComputeHash(preHash);
的for(int i = 1; I<计数;我++)
{
currentHash = hash.ComputeHash(currentHash);
}
hashList.AddRange(currentHash);
}
hash.Clear();
键=新的字节[32];
IV =新的字节[16];
hashList.CopyTo(0,键,0,32);
hashList.CopyTo(32,四,0,16);
}
静态的byte [] EncryptStringToBytes(明文字符串,字节[]键,字节[] IV)
{
//检查参数。
如果(明文== NULL || plainText.Length< = 0)
抛出新的ArgumentNullException(明文);
如果(主要== NULL || Key.Length< = 0)
抛出新的ArgumentNullException(钥匙);
如果(IV == NULL || IV.Length< = 0)
抛出新的ArgumentNullException(钥匙);
字节[]加密;
//创建一个对象RijndaelManaged的
//使用指定的密钥和IV。
使用(RijndaelManaged的rijAlg =新RijndaelManaged的())
{
rijAlg.Key =键;
rijAlg.IV = IV;
//创建一个decrytor执行流转换。
ICryptoTransform的加密= rijAlg.CreateEncryptor(rijAlg.Key,rijAlg.IV);
//创建用于加密的数据流。
使用(MemoryStream的msEncrypt =新的MemoryStream())
{
使用(CryptoStream的csEncrypt =新的CryptoStream(msEncrypt,加密,CryptoStreamMode.Write))
{
使用(StreamWriter的swEncrypt =新的StreamWriter(csEncrypt))
{
//写的所有数据流。
swEncrypt.Write(明文);
}
加密= msEncrypt.ToArray();
}
}
}
//从内存流返回加密的字节。
返回加密;
}
静态字符串DecryptStringFromBytes(字节[]的密文,字节[]键,字节[] IV)
{
//检查参数。
如果(密文== NULL || cipherText.Length< = 0)
抛出新的ArgumentNullException(密文);
如果(主要== NULL || Key.Length< = 0)
抛出新的ArgumentNullException(钥匙);
如果(IV == NULL || IV.Length< = 0)
抛出新的ArgumentNullException(钥匙);
//声明用来保存
//解密的文本字符串。
字符串明文= NULL;
//创建一个对象RijndaelManaged的
//使用指定的密钥和IV。
使用(RijndaelManaged的rijAlg =新RijndaelManaged的())
{
rijAlg.Key =键;
rijAlg.IV = IV;
//创建一个decrytor执行流转换。
ICryptoTransform的解密= rijAlg.CreateDecryptor(rijAlg.Key,rijAlg.IV);
//创建用于解密的流。
使用(MemoryStream的msDecrypt =新的MemoryStream(密文))
{使用
(CryptoStream的csDecrypt =新的CryptoStream(msDecrypt,解密,CryptoStreamMode.Read))
{
使用(StreamReader的srDecrypt =新的StreamReader(csDecrypt))
{
//读取从解密流
//解密的字节,并将其放置在一个字符串。
明文= srDecrypt.ReadToEnd();
}
}
}
}
返回明文;
}
}
}
从这里,我产生的通过节点如下:
VAR密码=要求('密码');
VAR输入=这是î╥≤它是什么。
VAR密钥=这是我的密码。
VAR密码= crypto.createCipher(AES-256-CBC,密钥);
变种加密= cipher.update(输入,'UTF8','的base64')+ cipher.final('的base64');
加密
//'9rTbNbfJkYVE2m5d8g / 8B / qAfeCU9rbk09Na / Pw0bak ='
输入=我是海象,首席运营官COO cachoo!;
密钥=我是一个≥ò'ÿ男婴!;
密码= crypto.createCipher(AES-256-CBC,密钥);
加密= cipher.update(输入,'UTF8','的base64')+ cipher.final('的base64');
//'J / E + f5JU5yerSvO7FBJzR1tGro0Ie3L8sWYaupRW1JJhraGqBfQ9z + h85VhSzEjD'
VAR译码= crypto.createDecipher(AES-256-CBC,密钥);
无功纯= decipher.update(加密的base64','UTF8')+ decipher.final('UTF8');
普通
//我是海象,首席运营官COO cachoo!
在此,我创建了下面的测试情况:
使用系统;
使用Microsoft.VisualStudio.TestTools.UnitTesting;
命名空间T1.CoreUtils.Test.Utilities.Tests
{
[TestClass中]
公共类UnitTest1
{
[TestMethod的]
酒店的公共空间EncryptReturnsExpectedValue1_unicode_in_plaintext()
{
VAR密钥=这是我的密码。
VAR纯=这是î╥≤它是什么。
VAR加密=9rTbNbfJkYVE2m5d8g / 8B / qAfeCU9rbk09Na / Pw0bak =;
VAR实际= T1.CoreUtils.Utilities.CryptoUtility.Encrypt(普通纸,密钥);
Assert.AreEqual(加密,实际);
}
[TestMethod的]
公共无效EncryptReturnsExpectedValue2_unicode_in_passkey()
{
VAR密钥=我是一个≥ò'ÿ男婴!;
VAR纯=我是海象,首席运营官COO cachoo!;
VAR加密=j / E + f5JU5yerSvO7FBJzR1tGro0Ie3L8sWYaupRW1JJhraGqBfQ9z + h85VhSzEjD
VAR实际= T1.CoreUtils.Utilities.CryptoUtility.Encrypt(普通纸,密钥);
Assert.AreEqual(加密,实际);
}
[TestMethod的]
公共无效DecryptReturnsExpectedValue1()
{
VAR密钥=这是我的密码。
VAR纯=这是î╥≤它是什么。
VAR加密=9rTbNbfJkYVE2m5d8g / 8B / qAfeCU9rbk09Na / Pw0bak =;
VAR实际= T1.CoreUtils.Utilities.CryptoUtility.Decrypt(加密密钥);
Assert.AreEqual(普通纸,实际的);
}
[TestMethod的]
公共无效DecryptReturnsExpectedValue2()
{
VAR密钥=我是一个≥ò'ÿ男婴!;
VAR纯=我是海象,首席运营官COO cachoo!;
VAR加密=j / E + f5JU5yerSvO7FBJzR1tGro0Ie3L8sWYaupRW1JJhraGqBfQ9z + h85VhSzEjD
VAR实际= T1.CoreUtils.Utilities.CryptoUtility.Decrypt(加密密钥);
Assert.AreEqual(普通纸,实际的);
}
}
}
通行证:
- EncryptReturnsExpectedValue1_unicode_in_plaintext
- DecryptReturnsExpectedValue1
失败:
- EncryptReturnsExpectedValue2_unicode_in_passkey
- DecryptReturnsExpectedValue2
我只能猜测,这个问题是在 DeriveKeyAndIV
方法。会尝试一些不同的方法和回答,如果我觉得我自己。
好吧,在检查的node.js源对于加密,我下定决心,该编码是用一个新的缓冲区(万能钥匙,二进制),这是只有在使用原始值x和0xFF的所使用的字节数,所以我创建了C#中的匹配方法......这里的方法有问题...
私有静态的byte [] RawBytesFromString(字符串输入)
{
变种RET =新的List<&字节GT;();
的foreach(在输入字符X)
{
变种C =(字节)((ULONG)x&安培; 0xFF的);
ret.Add(三);
}
返回ret.ToArray();
}
和更新/工作CryptoUtil.cs
使用系统;
使用System.Collections.Generic;
:使用System.IO;
使用System.Linq的;
使用System.Security.Cryptography;
使用System.Text;使用System.Threading.Tasks
;
命名空间T1.CoreUtils.Utilities
{
公共静态类CryptoUtility
{
/ *想留的NodeJS与
*兼容HTTP ://stackoverflow.com/questions/18502375/aes256-encryption-decryption-in-both-nodejs-and-c-sharp-net/
* http://stackoverflow.com/questions/12261540/decrypting- AES256加密的数据,在净从节点JS-如何对获得-IV和钥匙
* http://stackoverflow.com/questions/8008253/c-sharp-version-的-OpenSSL的-EVP-bytestokey法
*
* VAR密码= crypto.createCipher(AES-256-CBC','密码');
* VAR加密= cipher.update(测试,UTF8','的base64')+ cipher.final('的base64');
*
* VAR译码= crypto.createDecipher(AES-256-CBC','密码');
* VAR纯= decipher.update(加密的base64','UTF8')+ decipher.final('UTF8');
* /
公共静态字符串加密(字符串输入,字符串密码= NULL)
{
的byte []键,IV;
DeriveKeyAndIV(RawBytesFromString(密码),NULL,1,出重点,走出四);
返回Convert.ToBase64String(EncryptStringToBytes(输入,键,IV));
}
公共静态字符串解密(字符串inputBase64,字符串密码= NULL)
{
的byte []键,IV;
DeriveKeyAndIV(RawBytesFromString(密码),NULL,1,出重点,走出四);
返回DecryptStringFromBytes(Convert.FromBase64String(inputBase64),键,IV);
}
私人静态的byte [] RawBytesFromString(字符串输入)
{
变种RET =新的List<&字节GT;();
的foreach(在输入字符X)
{
变种C =(字节)((ULONG)x&安培; 0xFF的);
ret.Add(三);
}
返回ret.ToArray();
}
私有静态无效DeriveKeyAndIV(字节[]数据字节[]盐,诠释计数,出的byte []键,出来的byte [] IV)
{
名单,LT;字节> hashList =新的List<位>();
字节[] = currentHash新的字节[0];
INT preHashLength = data.Length +(!?(盐= NULL)salt.Length:0);
字节[] = preHash新的字节[preHashLength]
System.Buffer.BlockCopy(数据,0,preHash,0,data.Length);
如果(盐!= NULL)
System.Buffer.BlockCopy(盐,0,preHash,data.Length,salt.Length);
MD5哈希值= MD5.Create();
currentHash = hash.ComputeHash(preHash);
的for(int i = 1; I<计数;我++)
{
currentHash = hash.ComputeHash(currentHash);
}
hashList.AddRange(currentHash);
,而(hashList.Count< 48)// 32字节的密钥和16字节的IV
{
preHashLength = currentHash.Length + data.Length +(( !?盐= NULL)salt.Length:0);
preHash =新的字节[preHashLength]
System.Buffer.BlockCopy(currentHash,0,preHash,0,currentHash.Length);
System.Buffer.BlockCopy(数据,0,preHash,currentHash.Length,data.Length);
如果(盐!= NULL)
System.Buffer.BlockCopy(盐,0,preHash,currentHash.Length + data.Length,salt.Length);
currentHash = hash.ComputeHash(preHash);
的for(int i = 1; I<计数;我++)
{
currentHash = hash.ComputeHash(currentHash);
}
hashList.AddRange(currentHash);
}
hash.Clear();
键=新的字节[32];
IV =新的字节[16];
hashList.CopyTo(0,键,0,32);
hashList.CopyTo(32,四,0,16);
}
静态的byte [] EncryptStringToBytes(明文字符串,字节[]键,字节[] IV)
{
//检查参数。
如果(明文== NULL || plainText.Length< = 0)
抛出新的ArgumentNullException(明文);
如果(主要== NULL || Key.Length< = 0)
抛出新的ArgumentNullException(钥匙);
如果(IV == NULL || IV.Length< = 0)
抛出新的ArgumentNullException(钥匙);
字节[]加密;
//创建一个对象RijndaelManaged的
//使用指定的密钥和IV。使用(RijndaelManaged的密码=新RijndaelManaged的())
{
cipher.Key =键
;
cipher.IV = IV;
//cipher.Mode = CipherMode.CBC;
//cipher.Padding = PaddingMode.PKCS7;
//创建一个decrytor执行流转换。
ICryptoTransform的加密= cipher.CreateEncryptor(cipher.Key,cipher.IV);
//创建用于加密的数据流。
使用(MemoryStream的msEncrypt =新的MemoryStream())
{
使用(CryptoStream的csEncrypt =新的CryptoStream(msEncrypt,加密,CryptoStreamMode.Write))
{
使用(StreamWriter的swEncrypt =新的StreamWriter(csEncrypt))
{
//写的所有数据流。
swEncrypt.Write(明文);
}
加密= msEncrypt.ToArray();
}
}
}
//从内存流返回加密的字节。
返回加密;
}
静态字符串DecryptStringFromBytes(字节[]的密文,字节[]键,字节[] IV)
{
//检查参数。
如果(密文== NULL || cipherText.Length< = 0)
抛出新的ArgumentNullException(密文);
如果(主要== NULL || Key.Length< = 0)
抛出新的ArgumentNullException(钥匙);
如果(IV == NULL || IV.Length< = 0)
抛出新的ArgumentNullException(钥匙);
//声明用来保存
//解密的文本字符串。
字符串明文= NULL;
//创建一个对象RijndaelManaged的
//使用指定的密钥和IV。
使用(VAR密码=新RijndaelManaged的())
{
cipher.Key =键;
cipher.IV = IV;
//cipher.Mode = CipherMode.CBC;
//cipher.Padding = PaddingMode.PKCS7;
//创建一个decrytor执行流转换。
ICryptoTransform的解密= cipher.CreateDecryptor(cipher.Key,cipher.IV);
//创建用于解密的流。
使用(MemoryStream的msDecrypt =新的MemoryStream(密文))
{使用
(CryptoStream的csDecrypt =新的CryptoStream(msDecrypt,解密,CryptoStreamMode.Read))
{
使用(StreamReader的srDecrypt =新的StreamReader(csDecrypt))
{
//读取从解密流
//解密的字节,并将其放置在一个字符串。
明文= srDecrypt.ReadToEnd();
}
}
}
}
返回明文;
}
}
}
请注意:一些与此相关的...
- 更代码的
- 的
这不是在的NuGet
或 NPM
分别为他们真的不属于那里......这是主要的想法和参考。我确实需要一个好一点冲出节点一侧,它匹配了。
I've taken some liberties with the results of the following questions:
- AES encrypt in .NET and decrypt with Node.js crypto?
- Decrypting AES256 encrypted data in .NET from node.js - how to obtain IV and Key from passphrase
- C# version of OpenSSL EVP_BytesToKey method?
And created the following class file...
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;
}
}
}
From here, I generated the following via 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!'
From this, I create the following test case:
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);
}
}
}
Passes:
- EncryptReturnsExpectedValue1_unicode_in_plaintext
- DecryptReturnsExpectedValue1
Fails:
- EncryptReturnsExpectedValue2_unicode_in_passkey
- DecryptReturnsExpectedValue2
I can only guess that the issue is in the DeriveKeyAndIV
method. Will try a few different approaches and answer if I find it on my own.
Okay, upon inspecting the node.js source for crypto, I determined, that the encoding was using a new Buffer(passkey, 'binary'), which was only using the original value xand 0xFF for the bytes used, so I created a matching method in C#... here's the method in question...
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();
}
And the updated/working 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;
}
}
}
NOTE: Some more code related to this...
- https://github.com/tracker1/T1.CoreUtils/blob/master/T1.CoreUtils/Utilities/CryptoUtility.cs
- https://github.com/tracker1/t1-coreutils-node/blob/master/lib/hashutils.js
These are not in nuget
or npm
respectively as they really don't belong there... it's mainly for ideas and reference. I do need to flush out the node side a bit better so it matches up.
这篇关于在这两个和的NodeJS C#AES256加密/解密(.NET)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!