
Company News
Socket Has Acquired Secure Annex
Socket has acquired Secure Annex to expand extension security across browsers, IDEs, and AI tools.
cipher-chain
Advanced tools

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.
npm install cipher-chain --save
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
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
const CipherChain = require('cipher-chain')
const aAsyncFunction = async () => {
const options = {} // default options
const cipherchain = await new CipherChain(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'
}
}
}
Gets a list of all available ciphers to work with
Gets a list of all available KDFs to work with
Encrypts a plaintext to a ciphertext
let encrypted = await cipherchain.encrypt('secret data')
Decrypts a ciphertext to a plaintext
let decrypted = await cipherchain.decrypt(encrypted)
Encrypts a file, also hashes filename
const newFilename = await cipherchain.encryptFile(path.join('../', 'encryptme.txt'))
Decrypts a file
await cipherchain.decryptFile(path.join('../', 'encryptme.txt'))
Encrypts a directory, also hashes filenames
await cipherchain.encryptDirectory(path.join('../', 'encryptme'))
Decrypts a directory
await cipherchain.decryptDirectory(path.join('../', 'encryptme'))
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()
Copyright (c) 2020 by GiveMeAllYourCats. Some rights reserved.
cipher-chain is licensed under the MIT License as stated in the LICENSE file.
FAQs
Encrypting and decrypting your data in chains made easy!
We found that cipher-chain demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Socket has acquired Secure Annex to expand extension security across browsers, IDEs, and AI tools.

Research
/Security News
Socket is tracking cloned Open VSX extensions tied to GlassWorm, with several updated from benign-looking sleepers into malware delivery vehicles.

Product
Reachability analysis for PHP is now available in experimental, helping teams identify which vulnerabilities are actually exploitable.