vpn.email.client
Version:
Vpn.Email client IMAP core
137 lines (104 loc) • 3.62 kB
text/typescript
/*!
* 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.
*/
import * as crypto from 'crypto'
export interface packetBuffer {
command: number;
uuid: string;
buffer: Buffer;
serial: number
}
export interface pairConnect {
serverListen: string;
clientListen: string;
}
export const encrypt = ( text: Buffer, masterkey: string, 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
*/
export const decrypt = ( data: Buffer, 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 )
}
}
export const packetBuffer = ( bit0: number, _serial: number, id: string, buffer: 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 ])
}
export const openPacket = ( buffer: 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 )
}
}