Package Exports
- cipher-chain
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (cipher-chain) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
cipher-chain
Symmetric encryption and decryption of string(s) or file(s) protected via a secret
string or secretFile
Installation
npm install cipher-chain --save
How it works
- Encrypting
When creating a cipher-chain
instance you are presented with some options, you can use a secret
or use a secretFile
, a secretFile
is a computer generated 'key' if you will that is a unique signature representing your secret
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 string representing all cipher algorithms. 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
that matches the key
length requirements for that particular cipher
Then when you call the cipherchain.encrypt
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 @CC2-
indicating its a cipher-chain version 2 string. They can look like this:
@CC2-72887cf9ecf196d8b13bb05a6141a34c73af7ca719abf994d170ca2cc6629e169d743ef6c93c486079f60 d8cbdf1b7787eee937fe9c4cf62522d0d4d8c304195:0:1:0:ab561e52d1e9c68d3d63c62952c0314f3c73ff01 99657849ef20708af21a291e:3522e975157c2dc1:cbb83e90afeb9a3de67638502148c40b
If you look closely you can see :
being delimiters which will have the following result when split:
first the @CC2-
is removed internally when decrypting the string
;[
'72887cf9ecf196d8b13bb05a6141a34c73af7ca719abf994d170ca2cc6629e169d743ef6c93c486079f60d8cbdf1b7787eee937fe9c4cf62522d0d4d8c304195',
'0',
'1',
'0',
'ab561e52d1e9c68d3d63c62952c0314f3c73ff0199657849ef20708af21a291e',
'3522e975157c2dc1',
'cbb83e90afeb9a3de67638502148c40b'
]
The mapping for this format is as followed:
@CC2-[hmac]:[cipherAlgorithmId]:[autoPadding]:[authTag]:[kdfSalt]:[initializationVector]:[encryptedData]
So we can conclude we have the following data when decrypting the string:
const data = {
hmac: '72887cf9ecf196d8b13bb05a6141a34c73af7ca719abf994d170ca2cc6629e169d743ef6c93c486079f60d8cbdf1b7787eee937fe9c4cf62522d0d4d8c304195',
cipherAlgorithmId: '0',
autoPadding: '1',
authTag: '0',
kdfSalt: 'ab561e52d1e9c68d3d63c62952c0314f3c73ff0199657849ef20708af21a291e',
initializationVector: '3522e975157c2dc1',
encryptedData: 'cbb83e90afeb9a3de67638502148c40b'
}
Cipher-chain knows this internally when trying to decrypt your strings. The only piece of the puzzle here to decrypt the encryptedData
variable is if we know the secret
Usage
const CipherChain = require('cipher-chain')
const start = async () => {
const cipherchain = await new CipherChain({
secret: 'very secret!',
kdf: 'argon2',
chain: ['aes-256-gcm', 'blowfish', 'camellia-256-cbc'],
options: {
argon2: {
timeCost: 6,
memoryCost: 1024 * 4,
parallelism: 1
}
}
})
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
await cipherchain.encryptFile('./file.txt')
await cipherchain.decryptFile('./file.txt')
// Encrypt/decrypt a directory
await cipherchain.encryptFile('./directory')
await cipherchain.decryptFile('./directory')
}
start()
Api
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
example:
let encrypted = await cipherchain.encrypt('secret data')
cipherchain.decrypt(ciphertext:[string])
Decrypts a ciphertext to a plaintext
example:
let decrypted = await cipherchain.decrypt(encrypted)
cipherchain.encryptFile(filename:[path])
Encrypts a file
example:
await cipherchain.encryptFile(path.join('../', 'encryptme.txt'))
cipherchain.decryptFile(filename:[path])
Decrypts a file
example:
await cipherchain.decryptFile(path.join('../', 'encryptme.txt'))
cipherchain.encryptDirectory(directory:[path])
Encrypts a directory
example:
await cipherchain.encryptDirectory(path.join('../', 'encryptme'))
cipherchain.decryptDirectory(directory:[path])
Decrypts a directory
example:
await cipherchain.decryptDirectory(path.join('../', 'encryptme'))
License
Copyright (c) 2020 by GiveMeAllYourCats. Some rights reserved.
cipher-chain is licensed under the MIT License as stated in the LICENSE file.