npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

cipher-chain

v4.0.2

Published

Encrypting and decrypting your data in chains made easy!

Downloads

7

Readme

cipher-chain

HitCount Package quality Build Status Coverage Status Licensing Repo size Downloads per week Node version Help us and star this project

Symmetric encryption and decryption in cipher chains protected by a unique secret strings per chain, Can compress data (zlib), Can encrypt/decrypt files and whole directories. Uses zxcvbn for secret requirements with minimum of 24 characters per secret. encrypt-then-mac authentication.

Installation

npm install cipher-chain --save

How it works

- Encrypting

When creating a cipher-chain instance you are presented with some options, First you need to define a secret this is a array and it needs to have the same length as your chain variable. Secrets need to be unique from each other, error will be thrown if not. If enableSecurityRequirements is enabled (default true) then secret(s) need to be min 24 chars and comply to at least a score of 3 from the zxcvbn package.

So secondly you will need to define a chain, this will be the path the encryption/decryption process goes through to get the encrypted and plaintext respectively. chain is a array with strings representing all cipher algorithms names. The cipher algorithm list can be viewed by calling cipherchain.ciphers

When you create a cipher-chain instance the script goes through the chain list and for every algorithm it creates a KDF generated hashed key derived from the secret array corresponding index of the current chain index which is used as the key for that specific encipherment algorithm in the chain.

Then when you call the cipherchain.encrypt, cipherchain.encryptFile(file) or cipherchain.encryptDirectory(directory) function it checks what the chain is and will convert your plaintext to ciphertext via traversal of the chain list.

So if you have a chain value of ['aes-256-gcm', 'aes-192-gcm', 'camellia-256-cbc']

then the encryption process will be:

plaintext -> aes-256-gcm -> aes-192-gcm -> camellia-256-cbc -> ciphertext

and decryption process will be:

ciphertext -> camellia-256-cbc -> aes-192-gcm -> aes-256-gcm -> plaintext

After encryption chain end a hmac is computed of the end resulting ciphertext and before decryption chain start the hmac is compared (timings safe) against the end resulting ciphertext of that decryption process. If it not verifies a error is thrown

For each algorithm encryption chain pass a random initialization vector is generated

- Decrypting

All encrypted strings have the same format and recgonisable by the starting prefix of @CC4- indicating its a cipher-chain encrypted string and its major version 3, so if there are breaking changes because of a major version update in the module, the encrypted ciphertext wont be compatible to decrypt. They can look like this:

@CC4-56832c1b9e806bc1164523ba86925707a3ba6eb59716ae3c148426a036967f9469bb73a7cdd038969b6172098465ea33e97de072ba112112cf46f00ecf31dd40:80c0b153a3f83b34b481c3e5843c2c9c:038bb16ebbd0bdcecec2d82b:53b04561ea178266f146b52f7dd1e07386f5c95bf1efad75f06bbbbc702ea0b8:0ed43ae8

or if compressData option is set to true:

eJwVj8dtBEAMAysysAqrcC8DV4li/yV4/SRIgsPf75d/FGskqtMw9jJyWxMfVgftdYNwttmUubAjWrygCVAcVZan8hnlnDcpQwwGq+9KX2BEvngkKSCX0aKllmFMKu4ltSr94MUocIQZclvfID8v7nryeOYHICKu1lzr8RBCnOalj+aDnHMYyF/eGtfx/8k+dQKLpPF0A9PKg8cAffabdXqV+CDVFdf+Az+9SUQ=

If you look closely you can see : being delimiters which will have the following result when split:

first the @CC4- is removed internally when decrypting the string

;[
	'56832c1b9e806bc1164523ba86925707a3ba6eb59716ae3c148426a036967f9469bb73a7cdd038969b6172098465ea33e97de072ba112112cf46f00ecf31dd40',
	'80c0b153a3f83b34b481c3e5843c2c9c',
	'038bb16ebbd0bdcecec2d82b',
	'53b04561ea178266f146b52f7dd1e07386f5c95bf1efad75f06bbbbc702ea0b8',
	'0ed43ae8'
]

The mapping for this format is as followed:

@CC[majorVersionNumberCipherChain]-[hmac]:[authTag]:[kdfSalt]:[initializationVector]:[encryptedData]

So we can conclude we have the following data when decrypting the string:

const data = {
	hmac: '56832c1b9e806bc1164523ba86925707a3ba6eb59716ae3c148426a036967f9469bb73a7cdd038969b6172098465ea33e97de072ba112112cf46f00ecf31dd40',
	authTag: '80c0b153a3f83b34b481c3e5843c2c9c',
	kdfSalt: '038bb16ebbd0bdcecec2d82b',
	initializationVector: '53b04561ea178266f146b52f7dd1e07386f5c95bf1efad75f06bbbbc702ea0b8',
	encryptedData: '0ed43ae8'
}

Cipher-chain knows internally which algorithm cipher to use for this to decrypt your strings. The only piece of the puzzle here to decrypt the encryptedData variable is if we know the secret kdf hash for that specific chain

Initialization

const CipherChain = require('cipher-chain')

const aAsyncFunction = async () => {
	const options = {} // default options
	const cipherchain = await new CipherChain(options)
}

Options

| Argument | Explanation | Default | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- | | secret | The secret(s) to use for specific chains, needs to be a array and as long as your chain option | undefined | | chain | Array with strings that hold the cipher algorithms you want to use as a path to traverse from plain to cipher and vice versa | undefined | | autoPadding | Boolean to switch auto padding for the cipher. | true | | timingSafeCheck | Boolean for function equal check for hmac based on a constant-time algorithm without leaking timing information that would allow an attacker to guess one of the values. | true | | compressData | Boolean to compress end result after encryption to save data space, works for all encrypt functions | true | | concurrentFiles | How many concurrent files will be encrypted and decrypted at any given time. | 20 | | enableSecurityRequirements | Enables the zxcvbn package and min 24 char secret(s) requirements for extra security. | true | | hmacAlgorithm | String for what algorith the hmac verify should use. | sha512 | | kdf | See Below | See Below |

 // const argon2 = require('argon2')
{
    use: 'argon2', // or blake2, scrypt, pbkdf2,
    saltLength: 12, // salt length for the kdf, bigger value means bigger ciphertext data, especially with multiple chain encrypts
    options: {
      argon2: { // some argon2 setings you could do
        type: argon2.argon2i,
        memoryCost: 1024 * 8,
        timeCost: 6
      },
      pbkdf2: { // some pbkdf2 setings you could do, since 'use' in options is set to 'argon2' this is obsolete
        rounds: 10000,
        hash: 'sha512'
      }
    }
}

Methods

cipherchain.ciphers

Gets a list of all available ciphers to work with

cipherchain.kdfs

Gets a list of all available KDFs to work with

cipherchain.encrypt(plaintext:[string])

Encrypts a plaintext to a ciphertext

let encrypted = await cipherchain.encrypt('secret data')

cipherchain.decrypt(ciphertext:[string])

Decrypts a ciphertext to a plaintext

let decrypted = await cipherchain.decrypt(encrypted)

cipherchain.encryptFile(filename:[path])

Encrypts a file, also hashes filename

const newFilename = await cipherchain.encryptFile(path.join('../', 'encryptme.txt'))

cipherchain.decryptFile(filename:[path])

Decrypts a file

await cipherchain.decryptFile(path.join('../', 'encryptme.txt'))

cipherchain.encryptDirectory(directory:[path])

Encrypts a directory, also hashes filenames

await cipherchain.encryptDirectory(path.join('../', 'encryptme'))

cipherchain.decryptDirectory(directory:[path])

Decrypts a directory

await cipherchain.decryptDirectory(path.join('../', 'encryptme'))

Example

const CipherChain = require('cipher-chain')

const start = async () => {
	const cipherchain = await new CipherChain({
		secret: ['BxDPiKEAEaHZPiKERqLZDVaz', 'WRWqLZDPiKEqLZDsEFMCmgqLZDHH', 'IeiKEBxDRwvFmYERqLZjOi'],
		chain: ['aes-256-gcm', 'blowfish', 'camellia-256-cbc'],
		kdf: {
			use: 'argon2', // or blake2, scrypt, pbkdf2,
			saltLength: 12, // salt length for the kdf, bigger value means bigger ciphertext data, especially with multiple chain encrypts
			options: {
				argon2: { // some argon2 setings you could do
					type: argon2.argon2i,
					memoryCost: 1024 * 8,
					timeCost: 6
				},
				pbkdf2: { // some pbkdf2 setings you could do, since 'use' in options is set to 'argon2' this is obsolete
					rounds: 10000,
					hash: 'sha512'
				}
			}
		}
	})

	const ciphers = cipherchain.ciphers // List of cipher algorithms to use in your chain
	const kdfs = cipherchain.kdfs // List of KDFs (key derivation function) to use

	// Encrypt/decrypt a string
	const ciphertext = await cipherchain.encrypt('encrypt this')
	const plaintext = await cipherchain.decrypt(ciphertext)

	// Encrypt/decrypt a file
	const newFilename = await cipherchain.encryptFile('./file.txt')
	await cipherchain.decryptFile(newFilename)

	// Encrypt/decrypt a directory
	await cipherchain.encryptDirectory('./directory')
	await cipherchain.decryptDirectory('./directory')
}

start()

License

Copyright (c) 2020 by GiveMeAllYourCats. Some rights reserved. cipher-chain is licensed under the MIT License as stated in the LICENSE file.