I have a function written in C#. Basically the function is used to generate a token on the basis of parameters like text and key.
public string Encrypt(string input, string key) {
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncrptArray = UTF8Encoding.UTF8.GetBytes(input);
Aes kgen = Aes.Create("AES");
kgen.Mode = CipherMode.ECB;
kgen.Key = keyArray;
ICryptoTransform cTransform = kgen.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncrptArray, 0, toEncrptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
I'm trying to search any same alternative for the above function in NodeJS or run this function inside the NodeJS script through any compiler.
I have tried the crypto-js module in NodeJS but got a different token string. Please suggest the alternative function or any idea about running this function inside the NodeJS script.
My Recent code in NodeJS :
First Method :
var CryptoJS = require("crypto-js");
// Encrypt
var ciphertext = CryptoJS.AES.encrypt("<input>", "<key>").toString();
Second Method :
var crypto = require('crypto'),
algorithm = 'aes-256-ctr',
password = '<key>';
function encrypt(text){
var cipher = crypto.createCipher(algorithm,password)
var crypted = cipher.update(text,'utf8','hex')
crypted += cipher.final('hex');
return crypted;
}
Both the method is giving different token if compared to C# function.
The AES algorithm used in the C# code is AES 128-bit in ECB mode.
We can perform the same encryption in Node.js (and decrypt as well if we wish), using the following code:
Node.js Code
const crypto = require("crypto");
function encrypt(plainText, key, outputEncoding = "base64") {
const cipher = crypto.createCipheriv("aes-128-ecb", key, null);
let encrypted = cipher.update(plainText, 'utf8', outputEncoding)
encrypted += cipher.final(outputEncoding);
return encrypted;
}
function decrypt(cipherText, key, outputEncoding = "utf8") {
const cipher = crypto.createDecipheriv("aes-128-ecb", key, null);
let encrypted = cipher.update(cipherText)
encrypted += cipher.final(outputEncoding);
return encrypted;
}
const KEY = Buffer.from("abcdefghijklmnop", "utf8");
console.log("Key length (bits):", KEY.length * 8);
const encrypted = encrypt("hello world", KEY, "base64");
console.log("Encrypted string (base64):", encrypted);
// And if we wish to decrypt as well:
const decrypted = decrypt(Buffer.from(encrypted, "base64"), KEY, "utf8")
console.log("Decrypted string:", decrypted);
C# Code
using System;
using System.Text;
using System.Security.Cryptography;
public class Program
{
public static void Main()
{
Console.WriteLine("Result: " + Encrypt("hello world", "abcdefghijklmnop"));
}
public static string Encrypt(string input, string key) {
byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncrptArray = UTF8Encoding.UTF8.GetBytes(input);
Aes kgen = Aes.Create("AES");
kgen.Mode = CipherMode.ECB;
kgen.Key = keyArray;
ICryptoTransform cTransform = kgen.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncrptArray, 0, toEncrptArray.Length);
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}
}
The results for the encryption (with plaintext and key as above) are:
.Net: f7sSBDV0N6MOpRJLpSJL0w==
Node.js: f7sSBDV0N6MOpRJLpSJL0w==
Obviously we must not use this key in production!
Related
I have been reading several similar questions and based on that for my initial code. Unfortunately, I still can't get it to work.
key="fb52042ada308dd1d4dfd8a3870d5ab5"
iv = "bb8e0b158f57f63dfeea86e24af1abfc"
data = {"MerchantId":"0000000000000001"}
Get SHA256 from "data" (dataSha256)
Get encryption from Encrypt dataSha256 + iv + key
Result of Hexa encryption, similar to:
fd72fcc16b66d04cf0f4dd2265a59eb675103482bae806b405bb85595056f5770b3202b42d42a87b767892591a333eb6b5c9ad3ef34f4d415f8d3bbc3d0f389e2e5b6f7cd915520c7b2c19225680728b
When migrating the code from Java to Node.js, I don't get similar result. The first problem is that the "iv" should be 16 bytes, however in the code it is 32.
JAVA EXTRACT (original)
public class AesEncryption implements SymmetricEncryptionComponent {
Map<String, String> initParams;
String key, iv;
String mode, encoding;
String keyFile;
String ENCODING = "ISO-8859-1";
public AesEncryption() {
Security.addProvider(new BouncyCastleProvider());
}
// PARAMETERS INITIALITATION
public void setInitParams()
{
initParams=params;
key=” 1ea9a91b0ba908b44f598d2822499441”;
iv= "f20946931dd6e8594dc6f469b5e583ab";
mode= "AES/CBC/PKCS7Padding";
encoding= "HEX";
if(encoding.equalsIgnoreCase("BASE64")&&encoding.equalsIgnoreCase("HEX"))
throw new IllegalArgumentException("AES.ENCODING can only be 'HEX' of 'BASE64'")
}
// INFORMATION CIPHERING return encodeBase24
public String encrypt(String data) {
byte[] output = null;
try {
byte[] keyBytes = decode(key);
byte[] input = data.getBytes(ENCODING);
AlgorithmParameterSpec ivSpec = new
IvParameterSpec(Hex.decodeHex(iv.toCharArray()));
SecretKeySpec keySpec = null;
keySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance(mode);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
output = cipher.doFinal(input);
} catch (Exception e) {
throw new EncryptionException("Error", e);
}
return encode(output);
}
// INFORMATION ENCODE
private String encode(byte[] output) {
if (mode.equalsIgnoreCase("BASE64"))
return Base64.encodeBase64String(output);
else
return new String(Hex.encodeHex(output));
}
// INFORMATION DECODE
private byte[] decode(String data) throws DecoderException {
if (data.indexOf("=") > 0 || data.indexOf("+") > 0)
return Base64.decodeBase64(data);
else
return Hex.decodeHex(data.toCharArray());
}
}
NODE EXTRACT (using crypto-js)
const cryptojs = require("crypto-js");
const crypto = require("crypto");
let jsonData = {"MerchantId":"0000000000000001"};
let key = 'fb52042ada308dd1d4dfd8a3870d5ab5';
let iv = 'bb8e0b158f57f63dfeea86e24af1abfc';
const jsonDataSha256 =
crypto.createHash('sha256').update(JSON.stringify(jsonData)).digest('hex');
key = cryptojs.enc.Latin1.parse(key); //Convierte hex string -> word array
iv = cryptojs.enc.Latin1.parse(iv);
jsonDataSha256Bin = cryptojs.enc.Latin1.parse(jsonDataSha256); //Convert hex
string -> word array
console.log(key);
console.log(iv);
console.log(jsonDataSha256);
let encrypted = cryptojs.AES.encrypt(jsonDataSha256Bin, key, {
iv: iv,
mode: cryptojs.mode.CBC,
padding: cryptojs.pad.Pkcs7,
});
encrypted = encrypted.toString();
const salida = crypto.createHash('sha256').update(encrypted).digest('hex');
console.log(`${salida}`);
//Equals to ce994c4d2b1f398ff0bed22c4b48e1f2170dbf26baf2eaacec96ea6b31667cd6
//No match to Java output.
What will I be doing wrong? Any help is appreciated!
I have files encrypted in C# (using DES, PKCS7). I need to decode these files in Node JS.
The code I use to decrypt in C# looks like this:
public string SSFile_Reader( string fileToDecrypt )
{
DESCryptoServiceProvider provider = new DESCryptoServiceProvider
{
Key = Encoding.UTF8.GetBytes( "13^07v90" ),
IV = Encoding.UTF8.GetBytes( "13^07v90" ),
Padding = PaddingMode.PKCS7
};
using( FileStream streamToDecrypt = new FileStream( fileToDecrypt, FileMode.Open, FileAccess.Read, FileShare.ReadWrite ) )
{
ICryptoTransform cryptoTransform = provider.CreateDecryptor();
string outputString = "";
using( CryptoStream stream2 = new CryptoStream( streamToDecrypt, cryptoTransform, CryptoStreamMode.Read ) )
{
try
{
using( StreamReader reader = new StreamReader( stream2 ) )
{
try
{
outputString = reader.ReadToEnd();
}
catch
{
//handle error here
}
stream2.Close();
streamToDecrypt.Close();
return outputString;
}
}
catch( Exception exception )
{
//handle error here
}
}
}
return '';
}
I literally need to convert the above to Node JS. I have tried the Node JS code below, but the output is just some random stuff rather than the original encrypted string:
const { Readable } = require("stream");
const { scrypt, scryptSync, randomFill, createCipheriv, createDecipheriv } = require('crypto');
const fs = require('fs');
const [, , pathToEncryptedFile] = process.argv;
if (!pathToEncryptedFile) {
console.log('No file to decrypt')
exit()
}
const keyAndIv = '31335e3037763930'; //hex equivalence of 13^07v90
const key = Buffer.from(keyAndIv, 'hex');
const iv = Buffer.from(keyAndIv, 'hex');
const decryptedData = '';
const decipher = createDecipheriv('des', key, iv);
const readableStream = Readable.from(fs.createReadStream(pathToEncryptedFile)
.pipe(decipher));
readableStream.on("data", (chunk) => {
decryptedData += chunk.toString()
})
readableStream.on('end', function () {
console.log({decryptedData})
});
readableStream.on('error', function (err) {
console.log({err})
});
I also tried using crypto-js to no avail (https://github.com/brix/crypto-js/issues/396).
This is an example of one of the files I need to decrypt: https://files.fm/u/6pewftkk2
I can also give the C# code that does the encryption if the C# code given above for the decryption does not suffice
One possible variant is to load the ciphertext completely from the file system and decrypt it:
var crypto = require('crypto')
var fs = require('fs')
const algorithm = 'des'; // defaults to 'des-cbc';
const password = 'Password used to generate key';
const key = '13^07v90';
const iv = '13^07v90';
const ciphertext = fs.readFileSync('<path to high_classes.ssdata>');
const decipher = crypto.createDecipheriv(algorithm, key, iv);
const plaintext = decipher.update(ciphertext, '', 'utf8') + decipher.final();
console.log(plaintext);
which outputs the following plaintext (for the linked file):
SSS1
SSS2
SSS3
Alternatively, especially for large data, the plaintext can also be streamed to a file. To do this, replace the last block with:
const decipher = crypto.createDecipheriv(algorithm, key, iv);
const readStream = fs.createReadStream('<path to high_classes.ssdata>');
const writeStream = fs.createWriteStream('<path to file where decrypted data should be saved>');
readStream.pipe(decipher).pipe(writeStream);
which creates a file containing the decrypted data.
Note that DES is outdated and insecure these days. Using the key as an IV is also insecure. Typically, a random IV is generated during encryption and passed to the other side along with the ciphertext (usually concatenated).
I need your help. I have C# example how to sign message digest
signatureFormatter.SetHashAlgorithm("SHA1");
string keyText = Convert.ToBase64String(_certificate.PrivateKey);
byte[] signature = signatureFormatter.CreateSignature(hash);
return signature;
Later it converts it to base64:
Convert.ToBase64String(signature)
I need to achieve same result with node builtin library crypto, what I wrote:
const crypto = require('crypto');
...
const sig = crypto.createSign('RSA-SHA1');
sig.update(hashValue, 'hex');
sig.end();
const signature = sig.sign(privateKeyString, 'base64');
As result I'm getting different signatures for same hash, please help me, how to solve this problem
*** Update ***
Original C# function
private byte[] CreateSignature(byte[] hash)
{
RSAPKCS1SignatureFormatter signatureFormatter = new RSAPKCS1SignatureFormatter(_certificate.PrivateKey);
signatureFormatter.SetHashAlgorithm("SHA1");
byte[] signature = signatureFormatter.CreateSignature(hash);
return signature;
}
Update node.js function
const hashValue= '332a400fdab5b01efcd8407c61987495270ec1b6';
const sig = crypto.createSign('RSA-SHA1');
sig.update(Buffer.from(hashValue, 'utf-8'));
sig.end();
const sign = sig.sign(privateKeyString, 'base64');
In Java to make a signature of some data we are using Mac instance which allows to sign any byte array. How to make a function in JavaScript which produces the same signature for the same byte array?
An example of Java implementation (method sign signs message with HmacSHA256 and than converts signature into url-safe base64 string):
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException {
byte[] secret = new byte[5];
secret[0] = 0x1e;
secret[1] = 0x03;
secret[2] = 0x01;
secret[3] = 0x02;
secret[4] = 0x03;
byte[] message = new byte[5];
message[0] = 0x01;
message[1] = 0x03;
message[2] = 0x02;
message[3] = 0x1e;
message[4] = 0x03;
System.out.println(sign(secret, message));
}
private static String sign(byte[] secret, byte[] message) throws NoSuchAlgorithmException, InvalidKeyException {
Mac sha256Hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(secret, "HmacSHA256");
sha256Hmac.init(secretKey);
byte[] signature = sha256Hmac.doFinal(message);
return Base64.getUrlEncoder().withoutPadding().encodeToString(signature);
}
The example above produces q-l6FioFNkAqMIIxX5rs3AF-VnGIzpApCSSDHmnmjF8 signature string. I am trying to create the equivalent of sign method in JavaScript to get the same signature.
function main(){
var secret = [5];
secret[0] = 0x1e;
secret[1] = 0x03;
secret[2] = 0x01;
secret[3] = 0x02;
secret[4] = 0x03;
var message = [5];
message[0] = 0x01;
message[1] = 0x03;
message[2] = 0x02;
message[3] = 0x1e;
message[4] = 0x03;
console.log(sign(secret, message));
}
function sign(secret, message){
// ?
}
I couldn't find a way to sign bytes with CryptoJS.
The solution appeared to be not complicated. Before using CryptoJS we have to correctly convert bytes array into a String. After returning base64 string we should escape it to url friendly string.
function sign(secret, message){
var secretString = String.fromCharCode.apply(String, secret);
var messageString = String.fromCharCode.apply(String, message);
var hash = CryptoJS.HmacSHA256(messageString, secretString);
return CryptoJS.enc.Base64.stringify(hash).replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
}
Base64 and HmacSHA256 should be included in CryptoJS after install. Try this approach:
function sign(secret, message){
const hash = CryptoJS.HmacSHA256(message.join(''), secret.join(''));
const hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
return hashInBase64}
I'm trying to use the nodeJS crypto module to encrypt some hex strings using the ECB mode of AES 128.
To do so, I'm using the following code:
cryptoAES = function (sInput, sKey, bEncrypt) {
return crypto('AES-128-ECB', sInput, sKey, bEncrypt);
};
crypto = function (sAlgo, sInput, sKey, bEncrypt) {
var result = "";
if (bEncrypt){
var cipher;
var bKey = new Buffer(sKey, 'hex');
var bInput = new Buffer(sInput, 'hex');
cipher = crypto.createCipher(sAlgo, bKey);
cipher.setAutoPadding(false);
result = cipher.update(bInput, null, 'hex');
result += cipher.final('hex');
}
return result;
};
When calling cryptoAES with:
sKey = '12345678900987654321123456789001'
sInput = '060123456789ABCDEF00000000000000'
I should get
result = 'FBECD5D02C5B7CD1055AAF86238D1E2F'
but I'm getting:
result = 'ea1f940da8e269b9e075c936bff6a1f7'
Any idea what I could be doing wrong?
Reading https://github.com/joyent/node/issues/1318#issuecomment-1562766, you do need crypto.createCipheriv():
cipher = crypto.createCipheriv(sAlgo, bKey, '');
That generates the required result.