@sounisi5011/encrypted-archive v0.1.0
@sounisi5011/encrypted-archive
Convert data into a single encrypted archive data that contains all metadata needed for decryption.
Features
- Only password and target data are required - Other data required for encryption (nonce, key derivation function, etc.) will be generated automatically. 
- Support for secure algorithms - This package supports only the following algorithms that are currently (2021) recommended. - Encryption algorithm- AES-GCM (256-bit)
- ChaCha20-Poly1305
 
- Key derivation function- Argon2
 
 
- Encryption algorithm
- A counter is used to generate the IV (Initialization Vector) - When encrypting with the same key, the IV MUST NEVER be reused. However, there is a risk of generating the same IV when using random numbers. In this package, IVs are counter-generated to avoid unintentional reuse of IVs. 
- Backward compatibility - unsigned varint: https://github.com/multiformats/unsigned-varint - Protocol Buffers: https://developers.google.com/protocol-buffers/ - The data format uses unsigned varint and Protocol Buffers. High backward compatibility is maintained even when new features are added in the future. 
Example of use
- Generating a backup file
- Private data files accessible through public URLs
Not recommended for use
- Encryption of transmission data - If you encrypt a large amount of small data, there is a risk that the counter used to generate the IV will overflow. 
- Multi-processing and multi-threading - Currently, the counter used to generate IVs does not support different processes or threads. If used in multiple processes or threads, there is a danger of duplicate IVs. 
Attention
I am not a security expert. I have researched a lot of information in order to create this package. I believe that this package will be secure. However, there is a possibility that I am wrong.
Installation
npm install @sounisi5011/encrypted-archiveyarn add @sounisi5011/encrypted-archivepnpm add @sounisi5011/encrypted-archiveUsage
Small data
If you have a short string or a small file of data to encrypt, you can use a simple function.
const { encrypt, decrypt } = require('@sounisi5011/encrypted-archive');
const cleartext = 'Hello World!';
const password = '1234';
encrypt(cleartext, password, {
    // These options are optional, but it is recommended that you specify the appropriate options for your application.
    algorithm: 'chacha20-poly1305',
    keyDerivation: {
        algorithm: 'argon2d',
        iterations: 3,
        memory: 12,
        parallelism: 1,
    },
    // If the data to be encrypted is text, you can also compress the data.
    // Binary data (e.g. images, videos, etc.) can also be compressed,
    // but the effect of compression is often small and is not recommended.
    compress: 'gzip',
})
    .then(encryptedData => {
        // ...
    })
    .catch(error => {
        // ...
    });
// ----- //
const encryptedData = Buffer.from( ... );
decrypt(encryptedData, password)
    .then(decryptedData => {
        // ...
    })
    .catch(error => {
        // ...
    });Huge data
For huge files or data (e.g., hundreds of megabytes or tens of gigabytes), you can use Node.js Stream or Async Iteration.
Stream
const fs = require('fs');
const stream = require('stream');
const { encryptStream, decryptStream } = require('@sounisi5011/encrypted-archive');
const password = '1234';
const inputStream = fs.createReadStream('very-large.mp4');
const outputStream = fs.createWriteStream('very-large.mp4.enc');
stream.pipeline(
    inputStream,
    encryptStream(password, {
        // These options are optional, but it is recommended that you specify the appropriate options for your application.
        algorithm: 'aes-256-gcm',
        keyDerivation: {
            algorithm: 'argon2d',
            iterations: 3,
            memory: 12,
            parallelism: 1,
        },
        // If the data to be encrypted is text, you can also compress the data.
        // Binary data (e.g. images, videos, etc.) can also be compressed,
        // but the effect of compression is often small and is not recommended.
        //compress: 'gzip',
    }),
    outputStream,
    error => {
        if (error) {
            // ...
        } else {
            // ...
        }
    },
);
// ----- //
stream.pipeline(
    fs.createReadStream('very-large.mp4.enc'),
    decryptStream(password),
    fs.createWriteStream('very-large.mp4'),
    error => {
        if (error) {
            // ...
        } else {
            // ...
        }
    },
);Async Iteration
const fs = require('fs');
const stream = require('stream');
const { encryptIterator, decryptIterator } = require('@sounisi5011/encrypted-archive');
const password = '1234';
const inputIterator = (async function*() {
    for await (const chunk of fs.createReadStream('very-large.mp4')) {
        yield chunk;
    }
})();
const encryptor = encryptIterator(password, {
    // These options are optional, but it is recommended that you specify the appropriate options for your application.
    algorithm: 'aes-256-gcm',
    keyDerivation: {
        algorithm: 'argon2d',
        iterations: 3,
        memory: 12,
        parallelism: 1,
    },
    // If the data to be encrypted is text, you can also compress the data.
    // Binary data (e.g. images, videos, etc.) can also be compressed,
    // but the effect of compression is often small and is not recommended.
    //compress: 'gzip',
});
(async () => {
    try {
        for await (const encryptedDataChunk of encryptor(inputIterator)) {
            // ...
        }
    } catch (error) {
        // ...
    }
})();
// ----- //
const inputEncryptedIterator = (async function*() {
    for await (const chunk of fs.createReadStream('very-large.mp4.enc')) {
        yield chunk;
    }
})();
const decryptor = decryptIterator(password);
(async () => {
    try {
        for await (const decryptedDataChunk of decryptor(inputEncryptedIterator)) {
            // ...
        }
    } catch (error) {
        // ...
    }
})();API
encrypt(cleartext, password, options?)
Returns a Promise giving a Buffer object.
- cleartext- Type: - string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer
- password- Type: - string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer
- options- see - EncryptOptions
decrypt(encryptedData, password)
Returns a Promise giving a Buffer object.
- encryptedData- Type: - string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer
- password- Type: - string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer
encryptStream(password, options?)
Returns a Transform stream.
- password- Type: - string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer
- options- see - EncryptOptions
decryptStream(password)
Returns a Transform stream.
- password- Type: - string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer
encryptIterator(password, options?)
Returns an IteratorConverter function.
- password- Type: - string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer
- options- see - EncryptOptions
decryptIterator(password)
Returns an IteratorConverter function.
- password- Type: - string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer
Returns an AsyncIterableIterator giving a Buffer object.
- source- Type: - Iterable<string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer> | AsyncIterable<string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer>
An object with the following properties:
All properties are optional.
Type: CryptoAlgorithmName
An encryption algorithm name string. Specify one of the following:
- "aes-256-gcm"
- "chacha20-poly1305"(default)
Type: KeyDerivationOptions
An object with the key derivation function name and options.
The key derivation function name is specified as a string in the algorithm property.
The other properties are options for the key derivation function.
Currently, the following key derivation functions are supported:
- algorithm- "argon2d"(default)
- "argon2id"
 
- iterations- Type: - number- the number of iterations. default: - 3
- memory- Type: - number- used memory, in KiB. default: - 12
- parallelism- Type: `number` desired parallelism. default: `1`- For more information on the values that should be specified for these parameters, please refer to the following article: Choose Argon2 Parameters for Secure Password Hashing and Login - ory.sh 
 
Type: CompressOptions | CompressOptions['algorithm']
A compression algorithm name string, or an options object for the compression algorithm.
When specifying an object, the compression algorithm name is specified as a string in the algorithm property.
The other properties are options for the compression algorithm.
Currently, the following compression algorithm are supported:
- Gzip - algorithm*- "gzip"- Other properties are passed to zlib options. However, the following properties are not allowed: 
- flush
- finishFlush
- dictionary
- info
- maxOutputLength
 
- Brotli - algorithm*- "brotli"- Other properties are passed to brotli options. However, the following properties are not allowed: 
- flush
- finishFlush
- maxOutputLength