I need to replicate this from Java to JavaScript (NodeJs) - javascript

I try to get the same functionality of java class to replicate in NodeJs, but I can't do it. I don't understand all the JavaCode, specialy when the instance sing() (what's return). for that can't replicate into NodeJs
Java Code
public String generateSignature(String key, String stringToSign) throws Exception {
Signature signatureInstance = Signature.getInstance("SHA256WithRSA");
ServiceKeyRep keyRep = new ServiceKeyRep(KeyRep.Type.PRIVATE, "RSA", "PKCS#8", Base64.getDecoder().decode(key));
PrivateKey resolvedPrivateKey = (PrivateKey) keyRep.readResolve();
signatureInstance.initSign(resolvedPrivateKey);
byte[] bytesToSign = stringToSign.getBytes("UTF-8");
signatureInstance.update(bytesToSign);
String signatureString = Base64.getEncoder().encodeToString(signatureBytes);
return signatureString;
}
And I try this on Node JS
const privateKey = fs.readFileSync('myKey.pem', 'utf-8');
const stringToSign = new Int8Array([ myData ]);
const data = Buffer.from(stringToSign);
const sign = crypto.sign("RSA-SHA256", data , privateKey);
const signature = sign.toString('base64');
//Printing the signature
console.log(`Signature:\n\n ${signature}`);
but when I print, the out is not the same

Using crypto library we can do something similar in JS. Adapt as appropriate, this is just a reference.
const fs = require('fs');
const crypto = require('crypto');
function generateSignature(key, stringToSign) {
const privateKey = fs.readFileSync(key, 'utf-8');
const sign = crypto.createSign('RSA-SHA256');
sign.update(stringToSign);
const signature = sign.sign(privateKey, 'base64');
return signature;
}
const key = 'myKey.pem';
const stringToSign = 'myData';
const signature = generateSignature(key, stringToSign);
console.log(`Signature:\n\n${signature}`);

Related

compute hmac from message bytes and key bytes in javascript

I'm trying to reproduce the following code in javascript
var hashInput = "a::string::to::hash";
var privateKey = "C0B615950F9D577A4EAF64C9B4F2E50F3DA2C6BB6F790FA346E9732788B29A08AC5444F1B82984DB190A75D3861CC4802D598EBF0025FD1C327928F43EB1C80E";
byte[] inputBytes = Encoding.UTF8.GetBytes(hashInput);
byte[] keyBytes = Encoding.UTF8.GetBytes(privateKey);
HMACSHA256 hmac = new HMACSHA256(keyBytes);
hmac.Initialize();
var clientHash = hmac.ComputeHash(inputBytes);
var base64 = Convert.ToBase64String(clientHash);
But i ignore how can i import Enocde and HMACSHA256. I found the code in the following answer:
stackoverflow answer
This is what i've tried so far
const HashMAC = (key, message) => {
let keyBytes = Buffer.from(key, 'base64');
let messageBytes = Buffer.from(message, 'utf8');
// i don't know which library should i use, in crypto js thay're talking about
message and key noy bytes i tried but nothing.
const base64 = Buffer.from(hmac, 'base64');
return base64;
};

How to use Node JS to decrypt a file that was encrypted using C#

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).

Sign hex digest message with js crypto library

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');

How to convert this signature method from crypto (node) to crypto-js (browser)?

I have a signature method that is meant to be used in Node.js but I'd like to implement it client-side with crypto-js. It should work in latest Chrome versions.
I have tried to follow some answers like this one: Decode a Base64 String using CryptoJS
But I either get errors such as "Error: Malformed UTF-8 data", or a different result than the expected hmacDigest.
I am not sure how I could find an alternative to the "binary" digest although I found this question:
How to get digest representation of CryptoJS.HmacSHA256 in JS
The method is supposed to answer the following:
"Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data)) and base64 decoded secret API key"
This is the Nodejs version (with crypto):
const crypto = require('crypto')
function sign(path, params, secret) {
const message = querystring.stringify(params)
const secretBase64 = Buffer.from(secret, 'base64')
const hash = crypto.createHash('sha256')
const hmac = crypto.createHmac('sha512', secretBase64)
const hashDigest = hash.update(params.nonce + message).digest('binary')
const hmacDigest = hmac.update(path + hashDigest, 'binary').digest('base64')
return hmacDigest
}
note: querystring is just an helper module that can also run in browsers: https://nodejs.org/api/querystring.html
This is my attempt (wip) at implementing with crypto-js:
import cryptojs from 'crypto-js')
function sign (path, params, secret) {
const message = querystring.stringify(params)
const secretParsed = cryptojs.enc.Base64.parse(secret)
const secretDecoded = cryptojs.enc.Utf8.stringify(secretParsed) // -> this throws an error as "Error: Malformed UTF-8 data"
const hash = cryptojs.SHA256(params.nonce + message).toString(cryptojs.enc.hex)
const hmac = cryptojs.HmacSHA512(path + hash, secretDecoded).toString(cryptojs.enc.hex)
return hmac
}
Try this ! I think this is what you looking for !
const crypto = require("crypto")
const sign = (path, params, secret) => {
const message = querystring.stringify(params)
const secret = Buffer.from(secret, 'base64')
let sign = params.nonce + message
let hash = crypto.createHmac('sha256', secret)
.update(sign)
.digest("base64").toString()
let encoded = encodeURIComponent(hash)
return encoded
}

Node.js encrypts large file using AES

I try to use following code to encrypt a file of 1 GB. But Node.js abort with "FATAL ERROR: JS Allocation failed - process out of memory". How can I deal with it?
var fs = require('fs');
var crypto = require('crypto');
var key = "14189dc35ae35e75ff31d7502e245cd9bc7803838fbfd5c773cdcd79b8a28bbd";
var cipher = crypto.createCipher('aes-256-cbc', key);
var file_cipher = "";
var f = fs.ReadStream("test.txt");
f.on('data', function(d) {
file_cipher = file_cipher + cipher.update(d, 'utf8', 'hex');
});
f.on('end', function() {
file_cipher = file_cipher + cipher.final('hex');
});
You could write the encrypted file back to disk instead of buffering the entire thing in memory:
var fs = require('fs');
var crypto = require('crypto');
var key = '14189dc35ae35e75ff31d7502e245cd9bc7803838fbfd5c773cdcd79b8a28bbd';
var cipher = crypto.createCipher('aes-256-cbc', key);
var input = fs.createReadStream('test.txt');
var output = fs.createWriteStream('test.txt.enc');
input.pipe(cipher).pipe(output);
output.on('finish', function() {
console.log('Encrypted file written to disk!');
});
crypto.createCipher() without initialization vector is deprecated since NodeJS v10.0.0 use crypto.createCipheriv() instead.
You can also pipe streams using stream.pipeline() instead of pipe method and then promisify it (so the code will easily fit into promise-like and async/await flow).
const {createReadStream, createWriteStream} = require('fs');
const {pipeline} = require('stream');
const {randomBytes, createCipheriv} = require('crypto');
const {promisify} = require('util');
const key = randomBytes(32); // ... replace with your key
const iv = randomBytes(16); // ... replace with your initialization vector
promisify(pipeline)(
createReadStream('./text.txt'),
createCipheriv('aes-256-cbc', key, iv),
createWriteStream('./text.txt.enc')
)
.then(() => {/* ... */})
.catch(err => {/* ... */});
With NodeJS 15+ you could simplify it (skip promisify part)
const {createReadStream, createWriteStream} = require('fs');
const {pipeline} = require('stream/promises');
const {randomBytes, createCipheriv} = require('crypto');
const key = randomBytes(32); // ... replace with your key
const iv = randomBytes(16); // ... replace with your initialization vector
pipeline(
createReadStream('./text.txt'),
createCipheriv('aes-256-cbc', key, iv),
createWriteStream('./text.txt.enc')
)
.then(() => {/* ... */})
.catch(err => {/* ... */});
I would simply use the Fileger to do it. It's a promise-based package and a clean alternative to the NodeJS filesystem.
const fileger = require("fileger")
const file = new fileger.File("./your-file-path.txt");
file.encrypt("your-password") // this will encrypt the file
.then(() => {
file.decrypt("your-password") // this will decrypt the file
})

Categories

Resources