Node's Pretty Magical

    @sounisi5011/encrypted-archive
    TypeScript icon, indicating that this package has built-in type declarations

    0.1.0 • Public • Published

    @sounisi5011/encrypted-archive

    Go to the latest release page on npm Supported Node.js version: ^12.17.x || 14.x || 15.x || 16.x || 17.x Tested with Jest Commitizen friendly Minified Bundle Size Details Install Size Details Dependencies Status Build Status Maintainability Status

    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
    • 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.

      See: nonce-disrespect/nonce-disrespect: Nonce-Disrespecting Adversaries: Practical Forgery Attacks on GCM in TLS

    • Backward compatibility

      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-archive
    yarn add @sounisi5011/encrypted-archive
    pnpm add @sounisi5011/encrypted-archive

    Usage

    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

    IteratorConverter(source)

    Returns an AsyncIterableIterator giving a Buffer object.

    • source

      Type:

        Iterable<string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer>
      | AsyncIterable<string | Buffer | TypedArray | DataView | ArrayBuffer | SharedArrayBuffer>

    EncryptOptions

    An object with the following properties:

    All properties are optional.

    algorithm

    Type: CryptoAlgorithmName

    An encryption algorithm name string. Specify one of the following:

    • "aes-256-gcm"
    • "chacha20-poly1305" (default)

    keyDerivation

    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:

    • Argon2

      • 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

    compress

    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

    Structure of the encrypted archive

    see docs/encrypted-archive-structure.md

    Install

    npm i @sounisi5011/encrypted-archive

    DownloadsWeekly Downloads

    8

    Version

    0.1.0

    License

    MIT

    Unpacked Size

    291 kB

    Total Files

    82

    Last publish

    Collaborators

    • sounisi5011