Reputation: 105
I have a use case where the text has to be encoded and sent using the AES 256 algorithm. The client-side code is in C# which would be decrypting the code.
Encryption code in JS:
const crypto = require('crypto');
algorithm = 'aes-256-cbc',
secret = '1234567890123456',
keystring = crypto.createHash('sha256').update(String(secret)).digest('base64').substr(0, 16);
iv = crypto.createHash('sha256').update(String(secret)).digest('base64').substr(0, 16);
inputEncoding = 'utf8',
outputEncoding = 'base64';
function encrypt(text) {
let cipher = crypto.createCipheriv('aes-256-cbc', keystring, iv);
let encrypted = cipher.update(text, inputEncoding, outputEncoding)
encrypted += cipher.final(outputEncoding);
return encrypted;
}
Updated code used in the client side:
var keybytes = Encoding.UTF8.GetBytes(passwordKey);
var iv = Encoding.UTF8.GetBytes(passwordKey);
private byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iv)
{
try
{
// 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 a RijndaelManaged object
// with the specified key and IV.
using (var rijAlg = new RijndaelManaged())
{
rijAlg.Mode = CipherMode.CBC;
rijAlg.Padding = PaddingMode.PKCS7;
rijAlg.FeedbackSize = 128;
rijAlg.Key = key;
rijAlg.IV = iv;
// Create a decrytor to perform the stream transform.
var encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for encryption.
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var 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;
}
catch (Exception ex)
{
throw ex;
//LoggerCS.logError("Utility", "EncryptStringToBytes", JsonConvert.SerializeObject(null), ex.ToString(), ex.StackTrace);
}
return null;
}
The keyString and IV value used are same in C# and is encrypted using Utf8. Looking for the equivalent operation in Node JS.
Upvotes: 7
Views: 2890
Reputation: 105
The resolution was pretty simple than expected. The RijndaelManaged code with keylen 128 referred to AES-128 algorithm and using aes-128-cbc in nodeJS.
Also, since the C# code used getBytes for key and iv value. Buffer.from(secret) had to be used for both key and iv value in nodeJS. Final solution looks like:
const crypto = require('crypto');
algorithm = "aes-128-cbc",
secret = '1234567890123456',
keystring = new Buffer(secret),
iv = new Buffer(secret),
inputEncoding = 'utf8',
outputEncoding = 'base64';
function encrypt(text) {
let cipher = crypto.createCipheriv(algorithm,keystring, iv);
let encrypted = cipher.update(text, inputEncoding, outputEncoding)
encrypted += cipher.final(outputEncoding);
return encrypted;
}
function decrypt(encrypted) {
let decipher = crypto.createDecipheriv(algorithm,keystring, iv)
let dec = decipher.update(encrypted, outputEncoding, inputEncoding)
dec += decipher.final(inputEncoding);
return dec;
}
Upvotes: 0
Reputation: 119
The whole issue is likely with the encoding. .Net crypto class by default uses Unicode or utf16-le. While you have specified base64 as output encoding. Change it to utf16le ie
outputEncoding = 'utf16le';
look at Node Js documentation here
Upvotes: 0
Reputation: 1
Try this:
var crypto = require('text');
var mykey = crypto.createCipher('aes-256-cbc', keystring, iv);
var mystr = mykey.update('abc', 'utf8', 'hex')
mystr += mykey.final('hex');
console.log(mystr);
Upvotes: 0
Reputation: 1991
TLDR;
You're using a different IV and algorithm (AES-128 vs AES-256) so you will get different results...
You will need to use the same IV as well as the same key and algorithm if you want to get identical results. This would be an anti-pattern (i.e. don't do this)! Check John's comment about how you're ignoring the algorithm variable in your code, as at a quick glance this and the different IV are responsible for why you're getting different results.
Longer Answer;
1) You actually want it so that the same message (plain text) encrypted with the same key does not always produce the same encrypted result (cipher text). Otherwise any party that is eavesdropping will always know when a duplicate message has been sent again.
2) The initialization vector (IV) is used to provide randomness so that the same plain text does not always result in the same cipher text when a given key is used.
3) This means that to decrypt a message you need to know not only the key but also the IV.
4) The IV should be random and not deterministically derived from the key, otherwise every use of the same key will have the same IV and thus each time the same plain text is encrypted the same cipher text would result. (Leaving you vulnerable to eavesdroppers observing the results of a given message being received and beginning to determine the meaning of the message).
Have a look at the answers to this question AES Encryption - Key versus IV and also this Wikipedia entry http://en.wikipedia.org/wiki/Initialization_vector for more info.
Upvotes: 3