Open cannikin opened 1 year ago
I found this example:
'use strict';
const assert = require('node:assert');
const crypto = require('node:crypto');
const CryptoJS = require('crypto-js');
const secret = 'secret';
const plainText = 'message';
class CryptoHelper {
decryptAES(encryptedText, secret) {
// From https://gist.github.com/schakko/2628689?permalink_comment_id=3321113#gistcomment-3321113
// From https://gist.github.com/chengen/450129cb95c7159cb05001cc6bdbf6a1
const cypher = Buffer.from(encryptedText, 'base64');
const salt = cypher.slice(8, 16);
const password = Buffer.concat([Buffer.from(secret, 'binary'), salt]);
const md5Hashes = [];
let digest = password;
for (let i = 0; i < 3; i++) {
md5Hashes[i] = crypto.createHash('md5').update(digest).digest();
digest = Buffer.concat([md5Hashes[i], password]);
}
const key = Buffer.concat([md5Hashes[0], md5Hashes[1]]);
const iv = md5Hashes[2];
const contents = cypher.slice(16);
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
return decipher.update(contents) + decipher.final();
}
}
const cryptoHelper = new CryptoHelper;
const encrypted = CryptoJS.AES.encrypt(plainText, secret, { mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });
const encryptedText = encrypted.toString();
console.log('encrypted', encryptedText);
const decryptedText = cryptoHelper.decryptAES(encryptedText, secret);
console.log('decrypted', decryptedText);
assert.equal(plainText, decryptedText);
@a-tortevois Thank you for the example!
I'm going to test it later this afternoon, but from a quick glance I'm a little worried about the padding: CryptoJS.pad.Pkcs7
There's no mention of PKCS7 in any of the node:crypto
docs, only PKCS1. CryptoJS says that it uses PKCS7 by default if you don't tell it to use something different, and I didn't specify the padding in my existing code, so I assume it's using PKCS7 as well.
I'm wondering if that difference will make my encrypted strings non-decryptable by node:crypto
...
It work fine with your string, secret :
console.log('decrypted:', cryptoHelper.decryptAES('U2FsdGVkX18ZLpNMrgcEPbbEfE2c6h3E9kc0GRLE4pU=', 'V7gRKWw4uz6QVH7cGHqcUEPHpr8CfqD4LTckiTpmdeeDzS423Zc7zaBngvpwBv6Y'));
decrypted: Hello, world
This worked perfectly, thank you so much @a-tortevois!!
To add to this we are also using CryptoJs and we would like to replace existing cryptoJs implementation with web crypto APIs. For text and objects, it is working fine but with files, we are first converting into wordArray using
cryptoJs.lib.WordArray.create(fileObject)
what is something equivalent we can use to achieve the same result so that hash generated by web crypto API is same
Hi there,
thanks for this!
Is there an equivalent encryptAES(plainText, secret)
that will be backwards compatible (which could be decrypted with decryptAES()
)?
Cheers,
paul
what about encryption?.......... chatgpt can't do it.......
Of course, encryption is simply the reverse operation Something like this:
encryptAES(plainText, secret) {
const salt = crypto.randomBytes(8);
const password = Buffer.concat([Buffer.from(secret, 'binary'), salt]);
const hash = [];
let digest = password;
for (let i = 0; i < 3; i++) {
hash[i] = crypto.createHash('md5').update(digest).digest();
digest = Buffer.concat([hash[i], password]);
}
const keyDerivation = Buffer.concat(hash);
const key = keyDerivation.subarray(0, 32);
const iv = keyDerivation.subarray(32);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
return Buffer.concat([
Buffer.from('Salted__', 'utf8'),
salt,
cipher.update(plainText),
cipher.final()
]).toString('base64');
}
@a-tortevois Thanks... but it doesn't work.. I guess my cryptojs ecnryption is different or sth.... could you please look at it and give a small hint? thank you
function checkAndConvertToHex(str) {
if (/^\d+$/.test(str)) {
// eslint-disable-next-line no-undef
let hex = BigInt(str).toString(16).padStart(64, '0');
return '0x' + hex;
}
else {
return str;
}
}
function is_odd(num) {
return num % 2 !== 0;
}
export const encryptPrivateKey2 = (privateKey: string, password: string) => {
const padded = checkAndConvertToHex(privateKey);
let privateKeyBytes;
if (is_odd(padded.length)) {
privateKeyBytes = CryptoJS.enc.Utf8.parse(padded);
} else {
privateKeyBytes = CryptoJS.enc.Hex.parse(padded);
}
const key = CryptoJS.PBKDF2(password, CryptoJS.SHA256(password), { keySize: 256 / 32 });
const ciphertext = CryptoJS.AES.encrypt(privateKeyBytes, key, { mode: CryptoJS.mode.ECB });
return (is_odd(padded.length) ? 'UTF8' : '') + ciphertext.toString();
};
Be careful, you use CryptoJS.mode.ECB, mine is with aes-256-cbc algorithm
Be careful, you use CryptoJS.mode.ECB, mine is with aes-256-cbc algorithm
could you say what's more secured? if it's even correct to compare them?
@a-tortevois Thank you! both encrypt and decrypt work fine as expected 🚀
Hi folks! I have decided to create this NPM module with a similar API: https://github.com/RaisinTen/aes-crypto-js to make it easier to migrate away from this deprecated library. Thanks to the conversation above, the library uses Node.js' builtin crypto module internally and is far easier to maintain. Feel free to give it a try, post issues and submit PRs, thanks!
We are using CryptoJS in our code but now that 4.2.0 comes with a big deprecation notice we plan on moving off. We'd like to eliminate the CryptoJS lib completely, and just use
node:crypto
going forward, but I can't figure out the proper incantation ofnode:crypto
commands to decrypt something that was encrypted with CryptoJS:We'd like to be able to decrypt using
node:crypto
and then re-encrypt using a more secure version, with aniv
and all that good stuff. I've tried several different iterations of this code, with 6 different algorithms, but none of them are able to decrypt:The
node:crypto
docs state:Which sounds similar to what CryptoJS is doing, but maybe not similar enough. :(
I've tried truncating the
secret
to only 32 characters (tried both first 32 and last 32) but it didn't help.Any ideas of what else I could try? For testing, here's the
encText
andsecret
that should decrypt toHello, world
: