In Node.js possiamo cifrare e decifrare file di testo implementando un nostro sistema.

L'idea proviene da questo codice in 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); 
      }

    }

}

Qui il file viene letto per singolo byte e a ciascun bytee viene sommato un intero arbitrario.

In Node possiamo usare l'oggetto Buffer. Il metodo entries() di questo oggetto core restituisce un oggetto Iterator.

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

Iniziamo creando due helper per leggere e scrivere i file.

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

La funzione di cifratura è identica nella sua logica al metodo Java.

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

Dal buffer originale ricaviamo un array di byte in cui a ciascun byte originale è stato sommato un valore intero arbitrario.

La funzione di decifratura è l'esatto opposto.

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

Infine testiamo il nostro codice.

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