alilland
alilland

Reputation: 2572

Nodejs Crypto encrypted string not decrypting correctly after storing in MySQL

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

Answers (1)

Terry Lennox
Terry Lennox

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

Related Questions