I was tinkering with crypto-js and AES.
I have a seemingly straightforward piece of code which takes a plainText and encrypts it using AES with a key and an initial vector.
When I try to decrypt the encrypted text, it gets decrypted to empty string for some reason.
This is the snippet:
const { enc, AES } = require("crypto-js");
const KEY = enc.Utf8.parse("this is a key");
const IV = enc.Utf8.parse("this is initial vector");
const originalText = "someone#example.com";
const hash = AES.encrypt(originalText, KEY, { iv: IV });
const hashText = hash.toString();
console.log(`"${originalText}" was encrypted to "${hashText}"`);
const hashTextCopy = `${hashText}`;
const decrypt = AES.decrypt(hashTextCopy, KEY, { iv: IV });
const decryptText = decrypt.toString(enc.Utf8);
console.log(`"${hashTextCopy}" was decrypted to "${decryptText}"`);
The output I get is:
"someone#example.com" was encrypted to "IgyDXGNVD8IokknoZqjamG0QecGvBM/dyxx4il8gCHA="
"IgyDXGNVD8IokknoZqjamG0QecGvBM/dyxx4il8gCHA=" was decrypted to ""
Can someone explain what is going on? I have seen quite a few examples of it over the Internet and they all seem to working just fine. But here, the text is not getting decrypted.
PS: The version I am using is "crypto-js": "^3.1.9-1",
Maybe try changing your code ever so slightly, this works for me.
As stated in the comments, I believe the problem with your initial example was the key length.
const { enc, AES } = require("crypto-js");
// Keep as a string..
const KEY = "this is a key";
const IV = enc.Utf8.parse("this is initial vector");
const originalText = "someone#example.com";
const hash = AES.encrypt(originalText, KEY, { iv: IV });
const hashText = hash.toString();
console.log(`"${originalText}" was encrypted to "${hashText}"`);
const hashTextCopy = `${hashText}`;
const decrypt = AES.decrypt(hashTextCopy, KEY, { iv: IV });
const decryptText = decrypt.toString(enc.Utf8);
console.log(`"${hashTextCopy}" was decrypted to "${decryptText}"`);
This also works:
const { enc, AES } = require("crypto-js");
// 128-bit key works nicely
const KEY = enc.Hex.parse("000102030405060708090a0b0c0d0e0f");
const IV = enc.Utf8.parse("this is initial vector");
const originalText = "someone#example.com";
const hash = AES.encrypt(originalText, KEY, { iv: IV });
const hashText = hash.toString();
console.log(`"${originalText}" was encrypted to "${hashText}"`);
const hashTextCopy = `${hashText}`;
const decrypt = AES.decrypt(hashTextCopy, KEY, { iv: IV });
const decryptText = decrypt.toString(enc.Utf8);
console.log(`"${hashTextCopy}" was decrypted to "${decryptText}"`);
The key:
const KEY = enc.Utf8.parse("abcdfghi");
Will also work correctly (since it's 128-bits). 256 would work too.
const KEY = enc.Utf8.parse("abcdfghijklmnopq");
If you just use a pass phrase, a 256-bit key will be generated from it.
Related
I have an encryption function like this
const encryptWithInitVector = (string, keyBase64, ivBase64) => {
const key = Buffer.from(keyBase64, 'base64')
const iv = Buffer.from(ivBase64, 'base64')
const cipher = crypto.createCipheriv(getAlgorithm(keyBase64), key, iv)
let encrypted = cipher.update(string, 'utf8', 'base64')
encrypted += cipher.final('base64')
return encrypted
}
that receives a string to be encoded, an AESKey and an initializationVector.
How can I make the reverse path? I want to decode the response of the function encryptWithInitVector
https://nodejs.org/api/crypto.html#crypto_crypto_createdecipheriv_algorithm_key_iv_options
Create decipher using crypto.createDecipheriv
const decryptWithInitVector = (string, keyBase64, ivBase64) => {
const key = Buffer.from(keyBase64, 'base64')
const iv = Buffer.from(ivBase64, 'base64')
const decipher = crypto.createDecipheriv(getAlgorithm(keyBase64), key, iv)
let decrypted = decipher.update(string,'base64','utf-8');
decrypted += decipher.final('utf-8');
return decrypted
}
So the idea is simple but I am not sure if I am doing it correctly.
In my application, I need to use a username/password for some database connections.
The information is stored in my .bashrc file and exports, env vars.
I dont want to store them in clear text so I want to store them encrypted.
At runtime, I read the env variables, decrypt them and use them.
What I currently have is an node.js application that does the encryption,
code snippet:
const crypto = require('crypto');
const emailPassword = CLEAR_TEXT_PASSWORD;
const algorithm = 'aes-192-cbc';
const password = 'p3241';
const key = crypto.scryptSync(password, 'salt', 24);
const iv = Buffer.alloc(16, 0);
const cipher = crypto.createCipheriv(algorithm, key, iv);
let encrypted = cipher.update(emailPassword, 'utf8', 'hex');
encrypted += cipher.final('hex');
console.log(encrypted);
The result of the above becomes my env variable.
Now in my consumer application, to use the env variable, I have a reverse routine from decryption before usage.
It looks like
export const decipher = (input: string) : string => {
const algorithm = 'aes-192-cbc';
const password = 'p3241';
const key = crypto.scryptSync(password, 'salt', 24);
const iv = Buffer.alloc(16, 0);
const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update(input, 'hex', 'utf8');
decrypted += decipher.final('utf8');
console.log(decrypted);
return decrypted;
}
but what I don't is all the parameters for encrypt/decrypt are in clear text in my code on the server.
Is there a better way of doing this or am I overly paranoid?
I have the example from nodejs.org for the file encryption
const fs = require('fs');
const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';
// Use the async `crypto.scrypt()` instead.
const key = crypto.scryptSync(password, 'salt', 24);
// Use `crypto.randomBytes()` to generate a random iv instead of the static iv
// shown here.
const iv = Buffer.alloc(16, 0); // Initialization vector.
const cipher = crypto.createCipheriv(algorithm, key, iv);
const input = fs.createReadStream('test.js');
const output = fs.createWriteStream('test.enc');
input.pipe(cipher).pipe(output);
}
How do i do the oposite and get test.enc to test.js using the same key?
Thanks in advance
You can use a similar process to decrypt the file that you have encrypted using the above code.
We'll write the decrypted file to "test-decoded.js" so we don't end up overwriting our original file.
I'd also point out that you should ideally populate the IV with a random value and store this with the encrypted data, though if you're just testing it doesn't really matter too much!
const fs = require('fs');
const crypto = require("crypto");
const algorithm = 'aes-192-cbc';
const password = 'Password used to generate key';
const key = crypto.scryptSync(password, 'salt', 24);
const iv = Buffer.alloc(16, 0); // Initialization vector.
const decryptInput = fs.createReadStream('test.enc');
const decryptOutput = fs.createWriteStream('test-decoded.js');
const decipher = crypto.createDecipheriv(algorithm, key, iv);
decryptInput.pipe(decipher).pipe(decryptOutput);
This code worked for me to encrypt, but how can I reverse it?
I have hashed the password in the database and I need to decrypt. I have both a key and a hash.
const crypto = require('crypto');
const md5 = text => {
return crypto
.createHash('md5')
.update(text)
.digest();
}
const encrypt = (text, secretKey) => {
secretKey = md5(secretKey);
console.log(secretKey.toString('base64'));
secretKey = Buffer.concat([secretKey, secretKey.slice(0, 8)]); // properly expand 3DES key from 128 bit to 192 bit
const cipher = crypto.createCipheriv('des-ede3', secretKey, '');
const encrypted = cipher.update(text, 'utf8', 'base64');
return encrypted + cipher.final('base64');
};
const encrypted = encrypt('testtext', 'testkey');
console.log(encrypted);
This code should do what you need. We'll create a decrypt function that decrypts using the same algorithm (and key obviously!):
const crypto = require('crypto');
const md5 = text => {
return crypto
.createHash('md5')
.update(text)
.digest();
}
const encrypt = (text, secretKey) => {
secretKey = md5(secretKey);
console.log(secretKey.toString('base64'));
secretKey = Buffer.concat([secretKey, secretKey.slice(0, 8)]); // properly expand 3DES key from 128 bit to 192 bit
const cipher = crypto.createCipheriv('des-ede3', secretKey, '');
const encrypted = cipher.update(text, 'utf8', 'base64');
return encrypted + cipher.final('base64');
};
const decrypt = (encryptedBase64, secretKey) => {
secretKey = md5(secretKey);
secretKey = Buffer.concat([secretKey, secretKey.slice(0, 8)]); // properly expand 3DES key from 128 bit to 192 bit
const decipher = crypto.createDecipheriv('des-ede3', secretKey, '');
let decrypted = decipher.update(encryptedBase64, 'base64');
decrypted += decipher.final();
return decrypted;
};
const encrypted = encrypt('testtext', 'testkey');
console.log("Decrypted text:", decrypt(encrypted, 'testkey'));
I want to encrypt data and write it in my database. This works fine. After I get the data back from my database I want to decrypt this data, but the decryption doesn't work correctly.
I saved the string "test" in the database. The encryption works correctly and the encrypted string is
3ac5d5d6beeb44c5a58ac54e7fc0ad07ea3c819ff6489aae16d490667a309751378ae10800c072551e3a97596f3a2ae0
after i run the decrypt function i get back this:
8ea2e28e0086ef2ad22c2d7805a34111
but it should be "test"
const crypto = require("crypto");
const algorithm = "aes-256-cbc";
const key = new Buffer("11111111111111111111111111111111");
const iv = new Buffer("12345678");
module.exports = {
//my encyrpt function
encrypt(text) {
let ivstring = iv.toString("hex");
let cipher = crypto.createCipheriv(algorithm, key, ivstring);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
// return { iv: iv.toString("hex"), encryptedData: encrypted.toString("hex") };
return encrypted.toString("hex");
},
// my decrypt data
decrypt(text) {
let ivstring = iv.toString("hex");
let encryptedText = Buffer.from(text, "hex");
let decipher = crypto.createDecipheriv(algorithm, key, ivstring);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
};
It seems that you have applied the encryption twice:
encrypt(encrypt('test'))
// returns '3ac5d5d6beeb44c5a58ac54e7fc0ad07ea3c819ff6489aae16d490667a309751378ae10800c072551e3a97596f3a2ae0'
So you can decipher it by calling decrypt twice on the ciphertext:
const cipherText = '3ac5d5d6beeb44c5a58ac54e7fc0ad07ea3c819ff6489aae16d490667a309751378ae10800c072551e3a97596f3a2ae0'
decrypt(decrypt(cipherText))
// returns 'test'