1 | var fs = require('fs')
|
2 | , libEphemeral = require('./ephemeral')
|
3 | , constants = require('./constants')
|
4 | , libHeader = require('./header')
|
5 | , through = require('through')
|
6 | , assert = require('assert')
|
7 |
|
8 | function decrypt (inStream, wallet, encryptedSize) {
|
9 | var self = this
|
10 | var outStream = through()
|
11 | var decryptor, hashStream, ephSlice, eph
|
12 | var chunks = []
|
13 | function parseEphemeral (chunk) {
|
14 | chunks.push(chunk)
|
15 | var buf = Buffer.concat(chunks)
|
16 | if (buf.length >= constants.EPH_LENGTH) {
|
17 | ephSlice = buf.slice(0, constants.EPH_LENGTH)
|
18 | chunks = [buf.slice(constants.EPH_LENGTH)]
|
19 | withEphSlice(ephSlice)
|
20 | }
|
21 | }
|
22 | inStream.on('data', parseEphemeral)
|
23 | inStream.once('end', function () {
|
24 | if (!ephSlice) {
|
25 | return outStream.emit('error', new Error('not a salty file'))
|
26 | }
|
27 | })
|
28 | function withEphSlice (buf) {
|
29 | var header
|
30 | var headerStr = ''
|
31 | var ended = false
|
32 | inStream.removeListener('data', parseEphemeral)
|
33 | try {
|
34 | var eph = libEphemeral.parse(buf, wallet)
|
35 | var decryptor = eph.createDecryptor(encryptedSize)
|
36 | var hashStream = eph.createHmac()
|
37 | }
|
38 | catch (e) {
|
39 | return outStream.emit('error', e)
|
40 | }
|
41 | var tail
|
42 | hashStream.once('data', withHash)
|
43 | outStream.pipe(hashStream)
|
44 | function withHash (hash) {
|
45 | try {
|
46 | assert(tail)
|
47 | header = libHeader.parse(headerStr).validate(hash).toObject()
|
48 | var me = wallet.pubkey.toBuffer().toString('base64')
|
49 | if (header['to-salty-id'] === 'self') {
|
50 | if (header['from-salty-id'] !== me) {
|
51 | return outStream.emit('error', new Error('to-salty-id is self, not addressed to you'))
|
52 | }
|
53 | }
|
54 | else if (header['to-salty-id'] && header['to-salty-id'] !== me) {
|
55 | return outStream.emit('error', new Error('to-salty-id is not addressed to you'))
|
56 | }
|
57 | outStream.emit('header', header)
|
58 | }
|
59 | catch (e) {
|
60 | return outStream.emit('error', e)
|
61 | }
|
62 | }
|
63 | var bytesDecrypted = 0
|
64 | var parserStream = through(function write (chunk) {
|
65 | if (bytesDecrypted + chunk.length < eph.totalSize) {
|
66 | this.queue(chunk)
|
67 | bytesDecrypted += chunk.length
|
68 | }
|
69 | else if (headerStr) {
|
70 | headerStr += chunk.toString()
|
71 | }
|
72 | else {
|
73 | tail = chunk.slice(0, eph.totalSize - bytesDecrypted)
|
74 | if (tail.length) this.queue(tail)
|
75 | bytesDecrypted += tail.length
|
76 | headerStr = chunk.slice(tail.length).toString()
|
77 | }
|
78 | })
|
79 | decryptor.pipe(parserStream).pipe(outStream)
|
80 | var head = Buffer.concat(chunks)
|
81 | decryptor.write(head)
|
82 | inStream.pipe(decryptor)
|
83 | }
|
84 | return outStream
|
85 | }
|
86 | module.exports = decrypt |
\ | No newline at end of file |