LUKS for nodejs
Implementation of the Linux Unified Key Setup for nodejs. The goal is to provide a way to encrypt/decrypt data in a secure and established way by following the LUKS Spec. An unlockable master key using multiple pass keys serves to encrypt and decrypt the data.
While the default values adhere to the spec defaults, many variables are customizable in order to gain complete control over the data encryption.
The resulting header may not be compatible with cryptsetup(8).
Use cases
- Encrypt sensitive data using multiple passkeys (or only one of course)
- Store encrypted user files on a webserver which can only be read using the user password or an additional passphrase (e.g.: ProtonMail)
- Simply as powerful password hasher
- ...
Install
$ npm install
Test
$ npm test
Function Reference
constructor([options : Object])
LUKS Header Creation
createLUKSHeaderWithMasterKey(masterKey : Buffer [,options : Object]) : Buffer
createLUKSHeader(passKey : Buffer|string [,options : Object]) : Buffer
LUKS Header Information
getLUKSHeaderInfo(luksHeader : Buffer) : LUKSInfo
getLUKSKeyslotIndex(luksHeader : Buffer, passKey : Buffer|string [,options : Object]) : number
getLUKSMasterKey(luksHeader : Buffer, passKey : Buffer|string [,options : Object]) : Buffer
LUKS Passkey Modification
addLUKSKeyWithMasterKey(luksHeader : Buffer, masterKey : Buffer, passKey : Buffer|string [,options : Object]) : number
addLUKSKey(luksHeader : Buffer, existingPassKey : Buffer|string, newPassKey : Buffer|string [,options : Object]) : number
removeLUKSKey(luksHeader : Buffer, index : number [,options : Object]) : void
LUKS Data Encryption/Decryption
encryptLUKSWithMasterKey(luksHeader : Buffer, masterKey : Buffer [,options : Object]) : stream.Duplex
encryptLUKS(luksHeader : Buffer, passKey : Buffer|string [,options : Object]) : stream.Duplex
decryptLUKSWithMasterKey(luksHeader : Buffer, masterKey : Buffer [,options : Object]) : stream.Duplex
decryptLUKS(luksHeader : Buffer, passKey : Buffer|string [,options : Object]) : stream.Duplex
Options
Default options
luks_numkeys: 8 /* amount of key slots ; default: 8 */ luks_mkd_iter: 1000 /* amount of iterations for the master key digest ; default: 1000 */ /* cryptsetup infers the value using a benchmark */ luks_stripes: 4000 /* amount of stripes for the anti-forensic split ; default: 4000 */ luks_align_keyslots: 4096 /* alignment for keyslot in bytes ; default: 4096 */ luks_sector_size: 512 /* LUKS version 1 always use sector of fixed size 512 bytes ; default: 512 */ luks_ciphername: 'aes' /* Name of the cipher : aes, twofish, serpent, cast5, cast6 ; default: 'aes' */ /* (IMPORTANT! Only 'aes' is supported in this version) */ luks_ciphermode: 'xts-plain64' /* Name of the cipher mode : ecb, cbc-plain, cbc-essiv:hash, xts-plain64 ; default: 'xts-plain64' ; default: 'xts-plain64' */ /* (IMPORTANT! Only 'xts-plain64' is supported in this version) */ luks_hashspec: 'sha256' /* Name of the hash spec : sha1, sha256, sha512, ripemd160 ; default: 'sha256' */ luks_key_bytes: 32 /* length of the master key in bytes (32 => 256bits, 64 => 512bits) ; default: 32 */ /* depends on the cipher used (e.g.: 32 for aes-128-xts and 64 for aes-256-xts, the key is cut in half for xts) */ luks_pwd_iter: 2000 /* number of iterations for the password in an individual keyslot ; default: 2000 */ /* cryptsetup infers the value using a benchmark */
Example for web oriented applications
luks_numkeys: 2 /* 2 keyslots should be sufficient, at least one is used to store the PBKDF2'ed user password */ luks_mkd_iter: 5000 /* PBKDF2 iterations for the master key digest, this really depends on the performance of the server */ /* too low and brute force attacks might be possible, too high and the system will spend a considerable amount of time to recover the master key */ luks_stripes: 1 /* striping does not seem as useful in this context, the key material area is effectively the size of the master key */ luks_align_keyslots: 64 /* set alignment to the same size as the master key */ luks_sector_size: 64 /* sector size also the same size as the master key */ luks_ciphername: 'aes' /* aes is hardware accelerated on most systems */ luks_ciphermode: 'xts-plain64' /* the default of cryptsetup */ luks_hashspec: 'sha512' /* nice hashing :) */ luks_key_bytes: 64 /* 512bits for aes-xts corresponds to aes-256-xts, the key is split in 2 */ luks_pwd_iter: 10000 /* PBKDF2 iterations for the passkey, same as for luks_mkd_iter it really depends on the performance of the machine */ /* the user supplied passkey is not stored as is in a keyblock, it is run through PBKDF2 to get an entropy rich version of the passkey in order to encrypt the master key */
Info Object
/** * @typedef LUKSInfo * @type * @property * @property * @property * @property * @property * @property * @property * @property * @property * @property * @property * @property * @property * @property * @property * @property * @property * @property * @property */
LUKS Header Layout
+-----------------------------+----------+------+
|Field Name |Type |Bytes |
+-----------------------------+----------+------+
|LUKS_MAGIC | chars | 6|
|LUKS_VERSION | UInt16BE | 2|
|LUKS_CIPHERNAME | charsnt | 32|
|LUKS_CIPHERMODE | charsnt | 32|
|LUKS_HASHSPEC | charsnt | 32|
|LUKS_PAYLOAD_OFFSET | UInt32BE | 4|
|LUKS_KEY_BYTES | UInt32BE | 4|
|LUKS_MK_DIGEST | chars | 20|
|LUKS_MK_DIGEST_SALT | chars | 32|
|LUKS_MK_DIGEST_ITER | UInt32BE | 4|
|LUKS_UUID | charsnt | 40|
+-----------------------------+----------+------+
|KEYBLOCK_ACTIVE | UInt32BE | 4|
|KEYBLOCK_PWD_ITER | UInt32BE | 4|
|KEYBLOCK_PWD_SALT | chars | 32|
|KEYBLOCK_KEY_MATERIAL_OFFSET | UInt32BE | 4|
|KEYBLOCK_STRIPES | UInt32BE | 4|
+-----------------------------+----------+------+
| KEYBLOCKS ... | | |
+-----------------------------+----------+------+
| KEY MATERIALS ... | | |
+-----------------------------+----------+------+
chars : byte array
charsnt : null terminated byte array
UInt16BE : 16 bits big endian unsigned int
UInt32BE : 32 bits big endian unsigned int
KEYBLOCKS : the remaining keyblocks if more than one
KEY MATERIALS : KEYBLOCK_KEY_MATERIAL_OFFSET marks the beginning of a key material in sector counts aligned to the sectorsize and keyslot alignment
Function Reference (cont.)
constructor([options : Object])
/** * LUKS Constructor * @constructor * @public * @param */
Example:
const LUKS = ;var luks = ;
createLUKSHeaderWithMasterKey(masterKey : Buffer [,options : Object]) : Buffer
/** * Generates a new LUKS header using a masterKey * @public * @param * @param * @returns */
Example:
const Crypto = ;const LUKS = ;var luks = ; // use default optionsvar masterKey = Crypto; // using the default aes-128-xts ciphervar luksHeader = luks;
createLUKSHeader(passKey : Buffer|string [,options : Object]) : Buffer
/** * Creates a luks header initialized with a passKey * @public * @param * @param * @returns */
Example:
const LUKS = ;var luks = ; // use default optionsvar passKey = 'verysecretpassword';var luksHeader = luks;
getLUKSHeaderInfo(luksHeader : Buffer) : LUKSInfo
/** * Parses a LUKS header for its information, also acts as header validation * @public * @throws Will throw if the luksHeader is not a buffer : 'Not a buffer' * @throws Will throw if the header is invalid : 'Not a luks header' * @param * @returns */
Example:
const LUKS = ;var luks = ; // use default optionsvar passKey = 'verysecretpassword';var luksHeader = luks;var info = luks;
getLUKSKeyslotIndex(luksHeader : Buffer, passKey : Buffer|string [,options : Object]) : number
/** * Fetches the keyslot index that matches the passKey * If multiple keyslots use the same passKey, then the first one to match will be returned * @public * @param * @param * @param * @returns */
Example:
const LUKS = ;var luks = ; // use default optionsvar passKey = 'verysecretpassword';var luksHeader = luks;var index = luks;
getLUKSMasterKey(luksHeader : Buffer, passKey : Buffer|string [,options : Object]) : Buffer
/** * Recover the masterkey using a passkey * @public * @param * @param * @param * @returns */
Example:
const LUKS = ;var luks = ; // use default optionsvar passKey = 'verysecretpassword';var luksHeader = luks;var masterKey = luks;
addLUKSKeyWithMasterKey(luksHeader : Buffer, masterKey : Buffer, passKey : Buffer|string [,options : Object]) : number
/** * Adds a new LUKS key to the header * @param * @param * @param * @param * @returns */
Example:
const LUKS = ;var luks = ; // use default optionsvar passKey = 'verysecretpassword';var luksHeader = luks;var masterKey = luks;var anotherPassKey = 'anothersecretpassword';var index = luks;
addLUKSKey(luksHeader : Buffer, existingPassKey : Buffer|string, newPassKey : Buffer|string [,options : Object]) : number
/** * Adds a new passKey to a luks header using an existing passKey * @public * @throws Will throw if the masterKey could not be unlocked : 'Could not unlock masterkey' * @param * @param * @param * @param * @returns */
Example:
const LUKS = ;var luks = ; // use default optionsvar passKey = 'verysecretpassword';var luksHeader = luks;var anotherPassKey = 'anothersecretpassword';var index = luks;
removeLUKSKey(luksHeader : Buffer, index : number [,options : Object]) : void
/** * Removes the passKey at index setting the keyblock to disabled * @public * @throws Will throw if the index is out of bounds : 'Index is out of bounds' * @param * @param * @param */
Example:
const LUKS = ;var luks = ; // use default optionsvar passKey = 'verysecretpassword';var luksHeader = luks;var anotherPassKey = 'anothersecretpassword';var index = luks;luks;
encryptLUKSWithMasterKey(luksHeader : Buffer, masterKey : Buffer [,options : Object]) : stream.Duplex
/** * Creates a duplex stream in which you write unencrypted data and read encrypted data * @public * @throws Will throw if the masterKey is not a buffer : 'MasterKey is not a buffer' * @param * @param * @param * @returns */
Example:
const FS = ;const LUKS = ;var luks = ; // use default optionsvar passKey = 'verysecretpassword';var luksHeader = luks;var masterKey = luks;FS;
encryptLUKS(luksHeader : Buffer, passKey : Buffer|string [,options : Object]) : stream.Duplex
/** * Creates a duplex stream in which you write unencrypted data and read encrypted data * @public * @throws Will throw if the masterKey could not be unlocked using the passKey : 'Could not unlock masterkey' * @param * @param * @param * @returns */
Example:
const FS = ;const LUKS = ;var luks = ; // use default optionsvar passKey = 'verysecretpassword';var luksHeader = luks;FS;
decryptLUKSWithMasterKey(luksHeader : Buffer, masterKey : Buffer [,options : Object]) : stream.Duplex
/** * Creates a duplex stream in which you write encrypted data and read unencrypted data * @public * @throws Will throw if the masterKey is not a buffer : 'MasterKey is not a buffer' * @param * @param * @param * @returns */
Example:
const FS = ;const LUKS = ;var luks = ; // use default optionsvar passKey = 'verysecretpassword';var luksHeader = luks;var masterKey = luks;FS;
decryptLUKS(luksHeader : Buffer, passKey : Buffer|string [,options : Object]) : stream.Duplex
/** * Creates a duplex stream in which you write encrypted data and read unencrypted data * @public * @throws Will throw if the masterKey could not be unlocked using the passKey : 'Could not unlock masterkey' * @param * @param * @param * @returns */
Example:
const FS = ;const LUKS = ;var luks = ; // use default optionsvar passKey = 'verysecretpassword';var luksHeader = luks;FS;