使用 Node.js 加密文本文件中的各个行

Encrypt individual rows within a text file using Node.js

我试图加密文本文件中的每一行,而不是文本文件本身。这是我用于加密单行文本的代码。

crypto.pbkdf2(password, salt, iteration, keylen, digest, (error, derivedKey) => {
    const iv = Buffer.from('myiv', 'hex');

    const cipher = crypto.createCipheriv(algorithm, derivedKey, iv);

    let encryptThis = `Encrypt me`;
    let encrypted = '';

    cipher.on('readable', () => {
        let chunk;
        while (null !== (chunk = cipher.read())) {
            encrypted += chunk.toString('base64');
        }
    });

    cipher.on('end', () => {
        console.log(`Example string:   ${encryptThis}`);
    });

    cipher.write(encryptThis);
    cipher.end();
});

我知道我也可以使用 cipher.update(text)cipher.final() 进行加密,我也尝试过这种方法,但没有成功。问题是如何逐行读取文件并加密每一行。这两种方法我都试过了,但总是只有一行被加密或出错。我希望能够通过流转换来做到这一点,比如。

readStream
    .pipe(encryptLine)
    .pipe(writeStream)
    .on('finish', err => {
        if (err) console.log(err);
    });

想出了一个解决方案。我将所有加密逻辑移动到一个函数中,包括创建和结束,我对文件中的每一行都这样做。我的问题是尝试重用密码。

const encrypt = (line, thisTransform) => {
    crypto.pbkdf2(password, salt, iteration, keylen, digest, (error, derivedKey) => {
        const cipher = crypto.createCipheriv(algorithm, derivedKey, iv);

        let encrypted = '';
        cipher.on('readable', () => {
            while (null !== (chunk = cipher.read())) {
                encrypted += chunk.toString('base64');
            }
        });

        cipher.on('end', () => {
            thisTransform.push(`${encrypted}\n`);
        });
        cipher.write(line);
        cipher.end();
    });
};

let encryptLine = new stream.Transform();
encryptLine._transform = function(chunk, encoding, callback) {
    let rows = chunk
        .toString()
        .split('\n')
        .map(line => line.replace(/[\n\r]/g, ''))
        .forEach(line => {
            encrypt(line, this);
        });
};

readStream
    .pipe(encryptLine)
    .pipe(writeStream)
    .on('finish', err => {
        if (err) console.log(err);
    });

我会首先实现一个转换流(或利用现有的库)来逐行读取文件。

function toLines() {
    let line = '';
    return new Transform({
        decodeStrings: false,
        readableObjectMode: true,
        transform(chunk, encoding, callback) {
            const lines = chunk.split(/\r?\n/g);

            line += lines.shift();
            while (lines.length) {
                this.push(line);
                line = lines.shift();
            }

            callback();
        },
        flush(callback) {
            if (line) {
                this.push(line);
            }
            callback();
        }
    });
}

然后我会实现一个转换流来加密每一行。

function encryptLines(algorithm, derivedKey, iv) {
    return new Transform({
        readableObjectMode: false,
        writableObjectMode: true,
        transform(line, encoding, callback) {
            const cipher = crypto.createCipheriv(algorithm, derivedKey, iv);
            this.push(cipher.update(line, encoding, 'base64'));
            this.push(cipher.final('base64'));
            this.push('\n');
            callback();
        }
    });
}

然后您可以简单地pipe将所有内容输出到输出流(根据需要)。

fs.createReadStream('input.txt', {encoding: 'utf8'})
    .pipe(toLines())
    .pipe(encryptLines(algorithm, derivedKey, iv))
    .pipe(fs.createWriteStream('output.txt'))
    .on('finish', () => console.log('done'));