UNPKG

node-aescrypt

Version:

A node implementation of the AES Crypt <https://www.aescrypt.com/> file encryption format.

149 lines 12.1 kB
import { createCipheriv, randomBytes } from 'crypto'; import { Transform } from 'stream'; import { AESCRYPT_FILE_FORMAT_VERSION, getHMAC, getKey, NAME, toStream, VERSION, withStream, } from './util'; /** * Encrypt a Buffer using the AES Crypt file format. * * Create a stream transformer that takes any [Readable stream](https://nodejs.org/api/stream.html) * and passes on a Readable stream of the encrypted Buffer in the * [AES Crypt file format](https://www.aescrypt.com/aes_file_format.html). */ export class Encrypt extends Transform { constructor(password, options) { super(options); this.password = password; this.cipher = null; this.hmac = null; this.contentLength = 0; // Delay initialization. } // Create a small helper static method if you just want to encrypt a whole // Buffer all at once. // Note: There is a bit of duplication with the Decrypt version of this method. static buffer(password, buffer) { return new Promise((resolve, reject) => { toStream(buffer) .pipe(new Encrypt(password)) .pipe(withStream(contents => { resolve(contents); })) .on('error', reject); }); } _transform(chunk, _, callback) { // Okay, we have data. Let's initialize. this._init(); // This is unnecessary, but makes tslint keep quiet. if (this.cipher == null) { return; } if (this.hmac == null) { return; } // Track the file contents size. this.contentLength += chunk.length; // Encrypt this chunk and push it. const encChunk = this.cipher.update(chunk); this.push(encChunk); // And add the encrypted cipher block to the signature. this.hmac.update(encChunk); callback(); } _flush(callback) { // Make sure we have initialized (even if it is an empty file). this._init(); // This is unnecessary, but makes tslint keep quiet. if (this.cipher == null) { return; } if (this.hmac == null) { return; } // Store the size of the last block and determin the padding. const lenMod16 = this.contentLength % 16; const padding = 16 - lenMod16; // Encrypt and sign the padding. const encChunk = this.cipher.update(Buffer.alloc(padding, padding)); this.push(encChunk); this.hmac.update(encChunk); // Push down the final encryption, size of the last content block and the signature. this.push(this.cipher.final()); // This one should be unnecessary, as we are disabling the padding, but just in case. this.push(Buffer.from([lenMod16])); this.push(this.hmac.digest()); callback(); } _init() { if (this.cipher == null) { this._pushFileHeader(); this._pushExtensions(); const credentials = this._getCredentials(this.password); this._pushCredentials(credentials); this.cipher = this._getCipher(credentials.encKey, credentials.encIV); this.hmac = getHMAC(credentials.encKey); delete this.password; // Don't need this anymore. return true; } return false; } _pushFileHeader() { const buff = Buffer.alloc(3 + 1 + 1); buff.write('AES', 0); buff.writeUInt8(AESCRYPT_FILE_FORMAT_VERSION, 3); this.push(buff); } _pushExtensions() { const extensions = { CREATED_BY: NAME + ' ' + VERSION, }; // Calculate the final length of the extensions. const capacity = Object.keys(extensions).reduce((acc, k) => acc + 2 + k.length + 1 + extensions[k].length, 0) + // Extensions (2 + 128) + // extension container 2; // end extensions // Allocate a single buffer for all the extensions. const buff = Buffer.alloc(capacity); let len = 0; Object.keys(extensions).forEach(k => { len = buff.writeUInt16BE(k.length + 1 + extensions[k].length, len); len += buff.write(k, len); len += 1; // Delimiter len += buff.write(extensions[k], len); }); len = buff.writeUInt16BE(128, len); // We don't need to actually "create" the extension container, as it is just // 0x00s, and that is the default fill from Buffer.alloc(). this.push(buff); } _getCredentials(password) { const credIV = randomBytes(16); return { credIV, credKey: getKey(credIV, password), encIV: randomBytes(16), encKey: randomBytes(32), }; } _pushCredentials(credentials) { const { credIV, credKey, encIV, encKey } = credentials; // Encrypt our credentials. const credCipher = this._getCipher(credKey, credIV); const credBlock = Buffer.concat([ credCipher.update(encIV), credCipher.update(encKey), credCipher.final(), ]); // Sign them. const credHMAC = getHMAC(credKey) .update(credBlock) .digest(); // Than push them downstream. this.push(credIV); this.push(credBlock); this.push(credHMAC); } _getCipher(key, iv) { const encCipher = createCipheriv('aes-256-cbc', key, iv); encCipher.setAutoPadding(false); return encCipher; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5jcnlwdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvZW5jcnlwdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQVUsY0FBYyxFQUFRLFdBQVcsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUNuRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQ25DLE9BQU8sRUFDTCw0QkFBNEIsRUFDNUIsT0FBTyxFQUNQLE1BQU0sRUFDTixJQUFJLEVBQ0osUUFBUSxFQUVSLE9BQU8sRUFDUCxVQUFVLEdBQ1gsTUFBTSxRQUFRLENBQUM7QUFTaEI7Ozs7OztHQU1HO0FBQ0gsTUFBTSxPQUFPLE9BQVEsU0FBUSxTQUFTO0lBc0JwQyxZQUFZLFFBQWdCLEVBQUUsT0FBYTtRQUN6QyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUN6QixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztRQUNuQixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsYUFBYSxHQUFHLENBQUMsQ0FBQztRQUN2Qix3QkFBd0I7SUFDMUIsQ0FBQztJQTVCRCwwRUFBMEU7SUFDMUUsc0JBQXNCO0lBQ3RCLCtFQUErRTtJQUN4RSxNQUFNLENBQUMsTUFBTSxDQUFDLFFBQWdCLEVBQUUsTUFBYztRQUNuRCxPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1lBQ3JDLFFBQVEsQ0FBQyxNQUFNLENBQUM7aUJBQ2IsSUFBSSxDQUFDLElBQUksT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO2lCQUMzQixJQUFJLENBQ0gsVUFBVSxDQUFDLFFBQVEsQ0FBQyxFQUFFO2dCQUNwQixPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDcEIsQ0FBQyxDQUFDLENBQ0g7aUJBQ0EsRUFBRSxDQUFD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