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 | , bs58 = require('bs58')
|
8 |
|
9 | function decrypt (inStream, wallet, encryptedSize, noTranslate) {
|
10 | var self = this
|
11 | var outStream = through()
|
12 | var decryptor, hashStream, ephSlice, eph
|
13 | var chunks = []
|
14 | function parseEphemeral (chunk) {
|
15 | chunks.push(chunk)
|
16 | var buf = Buffer.concat(chunks)
|
17 | if (buf.length >= constants.EPH_LENGTH) {
|
18 | ephSlice = buf.slice(0, constants.EPH_LENGTH)
|
19 | chunks = [buf.slice(constants.EPH_LENGTH)]
|
20 | withEphSlice(ephSlice)
|
21 | }
|
22 | }
|
23 | inStream.on('data', parseEphemeral)
|
24 | inStream.once('end', function () {
|
25 | if (!ephSlice) {
|
26 | return outStream.emit('error', new Error('not a salty file'))
|
27 | }
|
28 | })
|
29 | function withEphSlice (buf) {
|
30 | var header
|
31 | var headerStr = ''
|
32 | var ended = false
|
33 | inStream.removeListener('data', parseEphemeral)
|
34 | try {
|
35 | var eph = libEphemeral.parse(buf, wallet)
|
36 | var decryptor = eph.createDecryptor(encryptedSize)
|
37 | var hashStream = eph.createHmac('sha256')
|
38 | }
|
39 | catch (e) {
|
40 | return outStream.emit('error', e)
|
41 | }
|
42 | var tail
|
43 | hashStream.once('data', withHash)
|
44 | outStream.pipe(hashStream)
|
45 | function withHash (hash) {
|
46 | try {
|
47 | assert(tail)
|
48 | header = libHeader.parse(headerStr, noTranslate).validate(hash).toObject()
|
49 | if (header['to-salty-id'] === 'self') {
|
50 | if (header['from-salty-id'] !== wallet.pubkey.pubkey) {
|
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'] !== wallet.pubkey.pubkey) {
|
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 |