vpn.email.client
Version:
Vpn.Email client IMAP core
99 lines (98 loc) • 3.59 kB
JavaScript
/*!
* Copyright 2017 Vpn.Email network security technology Canada Inc. All Rights Reserved.
*
* Vpn.Email network technolog Canada Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
;
const crypto = require("crypto");
exports.encrypt = (text, masterkey, CallBack) => {
// random initialization vector
const iv = crypto.randomBytes(12);
// random salt
const salt = crypto.randomBytes(64);
// derive key: 32 byte key length - in assumption the masterkey is a cryptographic and NOT a password there is no need for
// a large number of iterations. It may can replaced by HKDF
try {
crypto.pbkdf2(masterkey, salt, 2145, 32, 'sha512', (err, derivedKey) => {
if (err)
return CallBack(err);
// AES 256 GCM Mode
const cipher = crypto.createCipheriv('aes-256-gcm', derivedKey, iv);
// encrypt the given text
const encrypted = Buffer.concat([cipher.update(text), cipher.final()]);
// generate output
const ret = Buffer.concat([salt, iv, cipher.getAuthTag(), encrypted]);
return CallBack(null, ret);
});
}
catch (ex) {
console.log('encrypt catch error!');
return CallBack(ex);
}
};
/**
* Decrypts text by given key
* @param String base64 encoded input data
* @param Buffer masterkey
* @returns String decrypted (original) text
*/
exports.decrypt = (data, masterkey, CallBack) => {
if (!data || !data.length)
return CallBack(new Error('null'));
try {
// base64 decoding
// convert data to buffers
const salt = data.slice(0, 64);
const iv = data.slice(64, 76);
const tag = data.slice(76, 92);
const text = data.slice(92);
// derive key using; 32 byte key length
crypto.pbkdf2(masterkey, salt, 2145, 32, 'sha512', (err, derivedKey) => {
if (err)
return CallBack(err);
// AES 256 GCM Mode
try {
const decipher = crypto.createDecipheriv('aes-256-gcm', derivedKey, iv);
decipher.setAuthTag(tag);
const decrypted = decipher.update(text) + decipher.final('utf8');
return CallBack(null, decrypted);
}
catch (ex) {
}
});
}
catch (e) {
return CallBack(e);
}
};
exports.packetBuffer = (bit0, _serial, id, buffer) => {
const _buffer = new Buffer(6);
_buffer.fill(0);
_buffer.writeUInt8(bit0, 0);
_buffer.writeUInt32BE(_serial, 1);
const uuid = new Buffer(id, 'utf8');
_buffer.writeUInt8(id.length, 5);
if (buffer && buffer.length)
return Buffer.concat([_buffer, uuid, buffer]);
return Buffer.concat([_buffer, uuid]);
};
exports.openPacket = (buffer) => {
const idLength = buffer.readUInt8(5);
return {
command: buffer.readUInt8(0),
serial: buffer.readUInt32BE(1),
uuid: buffer.toString('utf8', 6, 6 + idLength),
buffer: buffer.slice(6 + idLength)
};
};