Protect nedb database with user/password. - node.js

I'am evaluating the use of nedb for one proyect. But it seems that natively it's don't support user/password protection. There is any way to protect an nedb database with user and password?

Here's an example.
const crypto = require('crypto')
const Datastore = require('nedb')
const ALGORITHM = 'aes-256-cbc'
const BLOCK_SIZE = 16
const KEY_SIZE = 32
// Generate a random key.
// If you want to use a password, use scrypt to generate the key instead.
const key = crypto.randomBytes(KEY_SIZE)
const db = new Datastore({
filename: 'encrypted.db',
afterSerialization (plaintext) {
// Encryption
// Generate random IV.
const iv = crypto.randomBytes(BLOCK_SIZE)
// Create cipher from key and IV.
const cipher = crypto.createCipheriv(ALGORITHM, key, iv)
// Encrypt record and prepend with IV.
const ciphertext = Buffer.concat([iv, cipher.update(plaintext), cipher.final()])
// Encode encrypted record as Base64.
return ciphertext.toString('base64')
},
beforeDeserialization (ciphertext) {
// Decryption
// Decode encrypted record from Base64.
const ciphertextBytes = Buffer.from(ciphertext, 'base64')
// Get IV from initial bytes.
const iv = ciphertextBytes.slice(0, BLOCK_SIZE)
// Get encrypted data from remaining bytes.
const data = ciphertextBytes.slice(BLOCK_SIZE)
// Create decipher from key and IV.
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv)
// Decrypt record.
const plaintextBytes = Buffer.concat([decipher.update(data), decipher.final()])
// Encode record as UTF-8.
return plaintextBytes.toString()
},
})
Note that this only protects the database with an encryption key, not a username/password combination.
For more detailed information, see https://gist.github.com/jordanbtucker/e9dde26b372048cf2cbe85a6aa9618de

You can use nedb hooksafterSerialization, beforeDeserialization to encrypt & decrypt data
example :
var db = new Datastore({
filename : path.join(__dirname, 'data/anything.db'),
autoload: true,
afterSerialization: function (doc) {
// encription usig AES or any algo
},
beforeDeserialization : function(doc) {
// encription usig AES and or algo with same key
return doc;
}
});

Related

How to store encrypted password in an environment variable in node.js?

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?

How do i decrypt after wards in npm

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);

Cant decrypt data after encryption with crypto

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'

CrytoJS AES: Encrypted string gets decrypted to empty string

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.

Encrypt and Decrypt files using Node.js Crypto Stream

I am making a Desktop application using Electron and react.js in which I have to encrypt and decrypt files (.txt, .pdf, .jpg, .png) using Crypto library.
I am using streams to do that.
So I just get the file from FileAPI and pass the file path to create readStream.
export function encrypt (passphrase) {
const crypto = require('crypto');
const fs = require('fs');
const cipher = crypto.createCipher('aes192', passphrase);
const input = fs.createReadStream(file_path);
const output = fs.createWriteStream('test.enc');
input.pipe(cipher).pipe(output);}
export function decrypt (passphrase) {
const crypto = require('crypto');
const fs = require('fs');
const cipher = crypto.createDecipher('aes192', passphrase);
const input = fs.createReadStream(file_path);
const output = fs.createWriteStream('test.pdf');}
input.pipe(cipher).pipe(output);
This code works fine for only for .txt files.
Any help to make this work for other file formats?
so here is a function that works.. just call on the function using 'data' in which ever format you need.. it seems best using strings or buffers.
function Encrypt_AES(data, pubkey) {
const algorithm = 'aes-192-cbc';
// Use the async `crypto.scrypt()` instead.
const key = crypto.scryptSync(pubkey, '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);
let encrypted = cipher.update(data, 'utf8', 'hex');
encrypted += cipher.final('hex');
return encrypted;
}
function Decrypt_AES(data, pubkey) {
const algorithm = 'aes-192-cbc';
// Use the async `crypto.scrypt()` instead.
const key = crypto.scryptSync(pubkey, 'salt', 24);
// The IV is usually passed along with the ciphertext.
const iv = Buffer.alloc(16, 0); // Initialization vector.
const decipher = crypto.createDecipheriv(algorithm, key, iv);
// Encrypted using same algorithm, key and iv.
let decrypted = decipher.update(data, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}

Resources