Issuetype: bug
Version: v6.14.0
Platform: Linux 4.4.0-116-generic ~14.04.1-Ubuntu SMP x86_64 GNU/Linux
Subsystem: crypto
Hi, I am using crypto module for encryption and decryption.
const { pbkdf2, createCipheriv } = require('crypto');
const encryptData = (plainText, password) => new Promise((resolve, reject) => {
const salt = randomBytes(32);
const iv = randomBytes(16);
pbkdf2(password, salt, 100000, 32, 'sha512', (error, derivedKey) => {
if (error) {
console.log(error);
reject(error);
}
else {
let encrypted = '';
const cipher = createCipheriv('aes-256-ctr', derivedKey, iv);
encrypted += cipher.update(plainText, 'utf8', 'hex');
encrypted += cipher.final('hex');
const data = {
cipherText: encrypted,
salt: salt.toString('hex'),
iv: iv.toString('hex')
};
resolve(data);
}
});
});
const decryptData = (cipherText, password, salt, iv) => new Promise((resolve, reject) => {
const _salt = Buffer.from(salt, 'hex');
const _iv = Buffer.from(iv, 'hex');
pbkdf2(password, _salt, 100000, 32, 'sha512', (error, derivedKey) => {
if (error) {
reject(error);
}
else {
let decrypted = '';
const decipher = createCipheriv('aes-256-ctr', derivedKey, _iv);
decrypted += decipher.update(cipherText, 'hex', 'utf8');
decrypted += decipher.final('utf8');
resolve(decrypted);
}
});
});
Data that is encrypted: "Hello World"
I think my decryption code is broken in 4th step.
invalid encoded string.I don't know whether my code is correct or not. Can someone help me with this issue?
Could you please post code showing how you invoke these functions? Does this reproduce in recent LTS releases?
Is it possible array passwords are being converted to a (constant) string (e.g. '[object Array]'), which might explain why any array value will work?
@tniessen I am building a react project using webpack. I am using the functions as follows:
import { encryptData, decryptData } from './crypto-methods';
// both the functions are in different components.
// I have just nested functions to show how I am invoking them
// I am actually saving the data returned by encrypData function in localStorage,
// Later in a different component, I am getting the values from localStorage and decrypting it
encryptData(this.state.message, this.state.password).then(data => {
console.log(`Encrypted Data: ${JSON.stringify(data)}`); // this goes to localStorage
decryptData(data.cipherText, this.state.password, data.salt, data.iv).then(data => console.log(data));
});
I made a mistake while updating the textbox value,
handleTextbox_onChange(event){
this.setState({
[event.target.name]: [event.target.value]
})
}
As you can see, instead of passing event.target.value, I was passing [event.target.value]. So when I entered different passwords, I could decrypt the cipherText.
@gmk292 Which CJS crypto module are using in your project? The officially maintained crypto module does not work as part of a client-side JS application.
@tniessen I am using the nodejs crypto module. You are right.
I just tested the same in node console. When array is used I am getting the following error.
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): TypeError: Pass phrase must be a buffer
Sorry for raising an issue, without checking this first.:bow:
To summarize: The problem occurs when passing an array as the "passphrase" parameter to crypto.pbkdf2 in node 6.14.0. Is that correct?
The function should throw an error:
> process.version
'v6.14.0'
> crypto.pbkdf2([ 'LOCKIT' ], crypto.randomBytes(32), 100000, 32, 'sha512', (err, key) => console.log(key));
TypeError: Pass phrase must be a buffer
at TypeError (native)
at pbkdf2 (crypto.js:622:20)
at Object.exports.pbkdf2 (crypto.js:604:10)
at repl:1:8
at sigintHandlersWrap (vm.js:22:35)
at sigintHandlersWrap (vm.js:73:12)
at ContextifyScript.Script.runInThisContext (vm.js:21:12)
at REPLServer.defaultEval (repl.js:340:29)
at bound (domain.js:280:14)
at REPLServer.runBound [as eval] (domain.js:293:12)
I am using the nodejs crypto module.
So you are using the nodejs crypto modulo on the client-side from within a browser or is the code being executed by a Node.js server application?
@tniessen I am using webpack-dev-server for the react application. It is pure client-side app. There are no services in the backend that do the encryption/decryption for the app
@gmk292 I didn't notice that you already edited https://github.com/nodejs/node/issues/19699#issuecomment-377533195, sorry. As suspected, this is not a problem with Node.js but with the module used within webpack. Please open an issue there.
@tniessen Thanks for your help :smile:
No problem, always glad to be of assistance 馃槂
Juding from the comments above, this looks like it may be a noticeable security footgun in whatever npm package that is responsible for this.
Encrypt functions absolutely mustn't coerce invalid values in passwords to constant strings.
@ChALkeR Should be fixed in https://github.com/crypto-browserify/pbkdf2/pull/77.
@tniessen Thanks for finding that module and fixing it!
Most helpful comment
Juding from the comments above, this looks like it may be a noticeable security footgun in whatever npm package that is responsible for this.
Encrypt functions absolutely mustn't coerce invalid values in passwords to constant strings.