Skip to content

Commit

Permalink
implement compression and start decryption functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
HR committed May 15, 2016
1 parent 032608f commit e995751
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 14 deletions.
19 changes: 18 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,23 @@ function CrypterWindow (callback) {
webContents.send('cryptErr', err)
})
})

// When user selects a file to decrypt in Crypter window
ipc.on('decryptFile', function (event, filePath) {
logger.verbose('IPCMAIN: cryptFile emitted. Starting encryption...')
let destPath = filePath.replace('.crypto', '.decrypto')
crypto.decrypt(filePath, destPath, global.MasterPassKey.get())
.then((creds) => {
logger.info('decrypted')
return
// webContents.send('decryptedFile', file)
})
.catch((err) => {
logger.error(err)
webContents.send('cryptErr', err)
})
})

win.on('closed', function () {
logger.info('win.closed event emitted for PromptWindow')
win = null
Expand Down Expand Up @@ -276,7 +293,7 @@ function SetupWindow (callback) {
function MasterPassPromptWindow (callback) {
let gotMP = false // init gotMP flag with false
let error = null
const CLOSE_TIMEOUT = 5000
const CLOSE_TIMEOUT = 2000
// creates a new BrowserWindow
let win = new BrowserWindow({
width: 300,
Expand Down
94 changes: 90 additions & 4 deletions src/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
const fs = require('fs-extra')
const path = require('path')
const scrypto = require('crypto')
const logger = require('../script/logger')
const Readable = require('stream').Readable
const zlib = require('zlib')

// Crypto default constants
let defaults = {
Expand Down Expand Up @@ -50,13 +53,15 @@ exports.crypt = function (origpath, masterpass) {
}

exports.encrypt = function (origpath, destpath, mpkey) {
// decrypts any arbitrary data passed with the pass
// Encrypts any arbitrary data passed with the pass
return new Promise(function (resolve, reject) {
// derive the encryption key
exports.deriveKey(mpkey, null, defaults.iterations)
.then((dcreds) => {
// readstream to read the (unencrypted) file
const origin = fs.createReadStream(origpath)
// create compressor
const zip = zlib.createGzip()
// writestream to write (encrypted) file
const dest = fs.createWriteStream(destpath)
// generate a cryptographically secure random iv
Expand All @@ -66,7 +71,14 @@ exports.encrypt = function (origpath, destpath, mpkey) {

// Read file, apply tranformation (encryption) to stream and
// then write stream to filesystem
origin.pipe(cipher).pipe(dest)
origin.pipe(zip).pipe(cipher).pipe(dest, { end: false })

cipher.on('end', () => {
// Append iv used to encrypt the file to end of file
// write in format Crypter#iv#authTag#salt
dest.write(`\nCrypter#${iv.toString('hex')}#${cipher.getAuthTag().toString('hex')}#${dcreds.salt.toString('hex')}`)
dest.end()
})

// readstream error handler
origin.on('error', (err) => {
Expand All @@ -89,8 +101,7 @@ exports.encrypt = function (origpath, destpath, mpkey) {
salt: dcreds.salt,
key: dcreds.key,
iv,
tag
})
tag})
})
})
.catch((err) => {
Expand All @@ -100,6 +111,81 @@ exports.encrypt = function (origpath, destpath, mpkey) {
})
}

exports.decrypt = function (origpath, destpath, mpkey, iv, authTag) {
// Decrypts any arbitrary data passed with the pass
return new Promise(function (resolve, reject) {
if (!iv || !authTag) {
// extract from last line of file
fs.readFile(origpath, 'utf-8', function (err, data) {
if (err) reject(err)

let lines = data.trim().split('\n')
let lastLine = lines.slice(-1)[0]
let fields = lastLine.split('#')
logger.info(`lines: ${lines}, lastLine: ${lastLine}, fields: ${fields}`)

if (fields[0] === 'Crypter') {
const iv = new Buffer(fields[1], 'hex')
const authTag = new Buffer(fields[2], 'hex')
const salt = new Buffer(fields[3], 'hex')
const mainData = lines.slice(0, -1).join()
logger.info(`mainData: ${mainData}`)

// derive the original encryption key for the file
exports.deriveKey(mpkey, salt, defaults.iterations)
.then((dcreds) => {
try {
logger.info(`Derived encryption key ${dcreds.key.toString('hex')}`)
const decipher = scrypto.createDecipheriv(defaults.algorithm, dcreds.key, iv)
logger.info(`authTag: ${authTag.toString('hex')}`)
// decipher.setAuthTag(authTag)
const dest = fs.createWriteStream(destpath)
const unzip = zlib.createGunzip()
// let dec = decipher.update(mainData, 'utf8', 'utf8')
// dec += decipher.final('utf8')
// let origin = new Readable()
// // read as stream
// origin.push(dec)
// origin.push(null)
//
// origin.pipe(dest)
let origin = new Readable()
// read as stream
origin.push(mainData)
origin.push(null)

origin.pipe(unzip).pipe(decipher).pipe(dest)

decipher.on('error', (err) => {
reject(err)
})

origin.on('error', (err) => {
reject(err)
})

dest.on('error', (err) => {
reject(err)
})

dest.on('finish', () => {
logger.verbose(`Finished encrypted/written to ${destpath}`)
resolve({iv, authTag})
})
} catch (err) {
reject(err)
}
})
} else {
reject(new Error('IV and authTag not supplied'))
}
})
} else {
// TODO: Implement normal flow
}
})
}

exports.deriveKey = function (pass, psalt, iterations = defaults.mpk_iterations) {
return new Promise(function (resolve, reject) {
// reject with error if pass not provided
Expand Down
37 changes: 28 additions & 9 deletions static/crypter.html
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,12 @@ <h3>Encrypted {{name}}</h3>
var path = require('path')
var errLabel = $('#errLabel')
var fileInput = $('#fileInput')
var fileInputText = fileInput.find('#fileInputText').text()
var fileInfo = $('#finfo')
var fileInputText = fileInput.find('#fileInputText')
var ifileInputText = fileInputText.text()
// compile the crypted template
var crypted_template = Handlebars.compile($('#crypted-template').html())
const cryptoExt = '.crypto'

$(window).load(function() {
// attach click event
Expand All @@ -106,9 +109,17 @@ <h3>Encrypted {{name}}</h3>
ipcRenderer.on('cryptedFile', function(event, file) {
logger.verbose(`IPCRENDER cryptedFile emitted`)
var fileHTML = crypted_template(file)
$('#finfo').html(fileHTML)
$('#fileInputText').text(fileInputText)
fileInfo.html(fileHTML)
fileInputText.text(ifileInputText)
navigate('crypted')
fileInput.on('click', handler)
})
ipcRenderer.on('decryptedFile', function(event, file) {
logger.verbose(`IPCRENDER decryptedFile emitted`)
// var fileHTML = crypted_template(file)
// fileInfo.html(fileHTML)
// fileInputText.text(ifileInputText)
// navigate('crypted')
// fileInput.on('click', handler)
})
ipcRenderer.on('cryptErr', function(event, err) {
Expand All @@ -128,12 +139,20 @@ <h3>Encrypted {{name}}</h3>
// callback for selected file
// returns undefined if file not selected by user
if (filePath && filePath.length === 1) {
var file = filePath[0]
// fileInput.off('click',handler)
// Set
$('#fileInputText').text(`Encrypting ${path.basename(file)}...`)
// send file to crypter controller function
ipcRenderer.send('cryptFile', file)
let file = filePath[0]
let fileExt = path.extname(file)
fileInput.off('click',handler)

if (fileExt.toLowerCase() === cryptoExt) {
// Decrypt file
fileInputText.text(`Decrypting ${path.basename(file)}...`)
ipcRenderer.send('decryptFile', file)
} else {
// Encrypt file
fileInputText.text(`Encrypting ${path.basename(file)}...`)
// send file to crypter controller function
ipcRenderer.send('cryptFile', file)
}
logger.info(require('util').inspect(filePath, {depth: null}))
}
})
Expand Down

0 comments on commit e995751

Please sign in to comment.