Commit 795e3c57 authored by Girish Ramakrishnan's avatar Girish Ramakrishnan

Add a header for encrypted backup files

this is required to identify old backups and new backups for decryption
parent 3f201464
......@@ -274,22 +274,25 @@ function decryptFilePath(filePath, encryption) {
class EncryptStream extends TransformStream {
constructor(encryption) {
super();
this._ivPushed = false;
this._headerPushed = false;
this._iv = crypto.randomBytes(16);
this._cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(encryption.dataKey, 'hex'), this._iv);
this._hmac = crypto.createHmac('sha256', Buffer.from(encryption.dataHmacKey, 'hex'));
}
pushIvIfNeeded() {
if (!this._ivPushed) {
pushHeaderIfNeeded() {
if (!this._headerPushed) {
const magic = Buffer.from('CBV2');
this.push(magic);
this._hmac.update(magic);
this.push(this._iv);
this._hmac.update(this._iv);
this._ivPushed = true;
this._headerPushed = true;
}
}
_transform(chunk, ignoredEncoding, callback) {
this.pushIvIfNeeded();
this.pushHeaderIfNeeded();
try {
const crypt = this._cipher.update(chunk);
......@@ -302,7 +305,7 @@ class EncryptStream extends TransformStream {
_flush(callback) {
try {
this.pushIvIfNeeded(); // for 0-length files
this.pushHeaderIfNeeded(); // for 0-length files
const crypt = this._cipher.final();
this.push(crypt);
this._hmac.update(crypt);
......@@ -317,25 +320,28 @@ class DecryptStream extends TransformStream {
constructor(encryption) {
super();
this._key = Buffer.from(encryption.dataKey, 'hex');
this._iv = Buffer.alloc(0);
this._header = Buffer.alloc(0);
this._decipher = null;
this._hmac = crypto.createHmac('sha256', Buffer.from(encryption.dataHmacKey, 'hex'));
this._buffer = Buffer.alloc(0);
}
_transform(chunk, ignoredEncoding, callback) {
const needed = 16 - this._iv.length;
const needed = 20 - this._header.length; // 4 for magic, 16 for iv
if (this._iv.length !== 16) { // not gotten IV yet
this._iv = Buffer.concat([this._iv, chunk.slice(0, needed)]);
if (this._iv.length !== 16) return callback();
if (this._header.length !== 20) { // not gotten header yet
this._header = Buffer.concat([this._header, chunk.slice(0, needed)]);
if (this._header.length !== 20) return callback();
this._decipher = crypto.createDecipheriv('aes-256-cbc', this._key, this._iv);
this._hmac.update(this._iv);
if (!this._header.slice(0, 4).equals(new Buffer.from('CBV2'))) return callback(new BoxError(BoxError.CRYPTO_ERROR, 'Invalid magic in header'));
const iv = this._header.slice(4);
this._decipher = crypto.createDecipheriv('aes-256-cbc', this._key, iv);
this._hmac.update(this._header);
}
this._buffer = Buffer.concat([ this._buffer, chunk.slice(needed) ]);
if (this._buffer.length < 32) return callback();
if (this._buffer.length < 32) return callback(); // hmac trailer length is 32
try {
const cipherText = this._buffer.slice(0, -32);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment