Reputation: 2572
I have a simple nodejs application that is storing tokens from an external service, its unsafe to store them as plain strings in the event of database compromise so I need to encrypt them.
copying and pasting the following github gist into my application simple-nodejs-iv-encrypt-decrypt.js
I am able to successfully encrypt and decrypt my strings, however once saving the encrypted string to MySQL
it no longer decrypts into a matching string
my MySQL column is formatted encryptedToken VARCHAR(255)
// before storing to database
{
encryptedToken: 'OKWLlYEsCtddWQOL8ezQBI+whtU30gVs67nGiRLxxca10Y4AELjMZN3afVzuys17leE9U9Ski+fByaEXFTXnefDUdyR4PUwJBi6poY1RHOY=',
decryptedToken: 'Z4XkR0vkrbAO6LzmaYGYa0dnaaxvlkIme27L-GlPB7l6M4gkikz1S_vTfJyCUJMx'
}
// after storing to database
{
encryptedToken: 'OKWLlYEsCtddWQOL8ezQBI+whtU30gVs67nGiRLxxca10Y4AELjMZN3afVzuys17leE9U9Ski+fByaEXFTXnefDUdyR4PUwJBi6poY1RHOY=',
decryptedToken: ':D�\b�O3Qlס��,,\u0017aYGYa0dnaaxvlkIme27L-GlPB7l6M4gkikz1S_vTfJyCUJMx'
}
the algorithm used is aes256
and the encoding is base64
Upvotes: 0
Views: 602
Reputation: 30685
I believe this is happening because you're using a different IV (Initialization Vector) each time.
The encryptionHelper function getKeyAndIV creates a random IV each time you call it, so decryption will not be deterministic.
If you ensure you're using the same IV each time, the decrypted token should be the same as well.
I've tested this out like so:
SQL
create table tokens (encryptedToken varchar(255))
Javascript / Node.js
const encryptionHelper = require("./simple-nodejs-iv-encrypt-decrypt.js")
// This could be anything
const token = "abcdefghijklmonp";
// We're using fixed values here. In reality you could use a different IV for each row, it's ok to store this in the database.
const key = Buffer.from("MTIzNDU2Nzg5MGFiY2RlZmdoaWprbG1ub3BxcnN0dXY=", "base64");
const iv = Buffer.from("26vFZGhH66xFszo59pEaWA==", "base64");
const encryptedToken = encryptionHelper.encryptText(encryptionHelper.CIPHERS.AES_256, key, iv, token, "base64");
// con should be initialized with a connection to the relevant db.
con.query("insert into tokens (encryptedToken) values (?)", [encryptedToken ], (error, results) => {
if (error) {
console.error("Insert query failed: ", error);
} else {
console.log("Token insert successful!");
}
});
con.query("select * from tokens", (error, results) => {
if (error) {
console.error("Select query failed: ", error);
return;
}
console.log("Tokens (encrypted):", results.map(r => r.encryptedToken));
console.log("Tokens (decrypted):", results.map(r => encryptionHelper.decryptText(encryptionHelper.CIPHERS.AES_256, key, iv, r.encryptedToken, "base64").toString("base64")));
});
// Let's just ensure con is closed
setTimeout(() => {
con.end()
}, 100);
Upvotes: 1