Node.js: create your own encryption/decryption system for plain text files

In Node.js you can create your own basic encryption/decryption system for plain text files.

The original idea is borrowed from Java.

private static void encrypt(String source, String output,int offset) throws IOException { 
    try ( InputStream is = new FileInputStream(source); OutputStream os = new FileOutputStream(output) ) { 
      int x; 
      while ((x = is.read()) >= 0) { 
        byte b = (byte) x; 
        b += offset; os.write(b); 
      }

    }

}

Here the original code reads the source input one byte at time and adds an arbitrary integer value to each byte.

In Node we can achieve a similar result using the Buffer object. This core object features the entries() method that returns an Iterator.

let buf = Buffer.from('Lorem ipsum dolor sit amet.');
for(let bytes of buf.entries()) {
    console.log(bytes); // [index, byte]
}

First we need two helpers for reading and writing files.

'use strict';

const fs = require('fs');

const read = file => {
    return new Promise((resolve, reject) => {
        fs.readFile(file, (err, data) => {
            if(err) {
                reject(err);
            }
            resolve(data);
        });
    });
};

const write = (file, data) => {
    return new Promise((resolve, reject) => {
        fs.writeFile(file, data, err => {
            if(err) {
                reject(err);
            }
            resolve(true);
        });
    });
};

The encryption function is almost identical to the original Java method in its design and underlying logic.

const encrypt = async (file, destination, offset) => {
    try {
        let data = await read(file);
        let buf = Buffer.from(data);
        let bytes = buf.entries();
        let output = [];

        for(let byte of bytes) {
            let b = byte[1] + offset;
            output.push(b);
        }

        let wrote = await write(destination, Buffer.from(output));
        return wrote;
    } catch(err) {
        return err;
    }
};

Here the encryption process takes place by creating a new buffer from an array of bytes where each byte is the result of the addition of an arbitrary integer value to each byte of the original buffer.

The decryption process is exactly the opposite.

const decrypt = async (file, destination, offset) => {
    try {
        let data = await read(file);
        let buf = Buffer.from(data);
        let bytes = buf.entries();
        let output = [];

        for(let byte of bytes) {
            let b = byte[1] - offset;
            output.push(b);
        }

        let wrote = await write(destination, Buffer.from(output));
        return wrote;
    } catch(err) {
        return err;
    }
};

Finally, we can test our code.

const test = async () => {
    try {
        let testFile = await read('./data/data.txt');
        let encrypted =  await encrypt('./data/data.txt', './data/enc.txt', 16);
        let decrypted =  await decrypt('./data/enc.txt', './data/dec.txt', 16);
        let testFileEnc = await read('./data/enc.txt');
        let testFileDec = await read('./data/dec.txt');

        console.log('Original file:');
        console.log(testFile.toString());
        console.log('Encrypted file:');
        console.log(testFileEnc.toString());
        console.log('Decrypted file:');
        console.log(testFileDec.toString());
    }  catch(err) {
        console.log(err);
    }
};

test();

Result.

Articles