Skip to content
This repository was archived by the owner on Aug 23, 2019. It is now read-only.

Commit c47dea1

Browse files
committed
refactor: remove handshaking to resolve issues with go dialing js
1 parent 22cf606 commit c47dea1

File tree

7 files changed

+117
-110
lines changed

7 files changed

+117
-110
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ Connection protection management for libp2p leveraging PSK encryption via XSalsa
1717

1818
## Usage
1919

20+
```js
21+
const Protector = require('libp2p-pnet')
22+
const protector = new Protector(swarmKeyBuffer)
23+
const privateConnection = protector.protect(myPublicConnection, (err) => { })
24+
```
25+
2026
### Private Shared Keys
2127

2228
Private Shared Keys are expected to be in the following format:
@@ -49,6 +55,15 @@ that project, assuming the node_modules are installed.
4955
node -e "require('libp2p-pnet').generate(process.stdout)" > swarm.key
5056
```
5157

58+
#### Programmatically
59+
60+
```js
61+
const writeKey = require('libp2p-pnet').generate
62+
const swarmKey = Buffer.alloc(95)
63+
writeKey(swarmKey)
64+
fs.writeFileSync('swarm.key', swarmKey)
65+
```
66+
5267
## Contribute
5368

5469
There are some ways you can make this module better:

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
"dependencies": {
2828
"debug": "^3.1.0",
2929
"interface-connection": "^0.3.2",
30+
"pull-cat": "^1.1.11",
3031
"pull-handshake": "^1.1.4",
32+
"pull-reader": "^1.2.9",
3133
"pull-stream": "^3.6.7",
3234
"xsalsa20": "^1.0.2"
3335
},

src/crypto.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const debug = require('debug')
55
const Errors = require('./errors')
66
const xsalsa20 = require('xsalsa20')
77
const KEY_LENGTH = require('./key-generator').KEY_LENGTH
8+
const NONCE_LENGTH = require('./key-generator').NONCE_LENGTH
89

910
const log = debug('libp2p:pnet')
1011
log.trace = debug('libp2p:pnet:trace')
@@ -30,15 +31,24 @@ module.exports.createBoxStream = (nonce, psk) => {
3031
/**
3132
* Creates a pull stream to decrypt messages in a private network
3233
*
33-
* @param {Buffer} nonce The nonce to use in decryption
34+
* @param {Object} remote Holds the nonce of the peer
3435
* @param {Buffer} psk The private shared key to use in decryption
3536
* @returns {PullStream} a through stream
3637
*/
37-
module.exports.createUnboxStream = (nonce, psk) => {
38-
const xor = xsalsa20(nonce, psk)
38+
module.exports.createUnboxStream = (remote, psk) => {
39+
let xor
3940
return pull(
4041
ensureBuffer(),
4142
pull.map((chunk) => {
43+
if (!xor) {
44+
if (!remote.nonce || remote.nonce.byteLength !== NONCE_LENGTH) {
45+
log.trace('No nonce was read, throwing an error')
46+
throw new Error(Errors.INVALID_PEER)
47+
}
48+
xor = xsalsa20(remote.nonce, psk)
49+
log.trace('Decryption enabled')
50+
}
51+
4252
return xor.update(chunk, chunk)
4353
})
4454
)

src/handshake.js

Lines changed: 0 additions & 86 deletions
This file was deleted.

src/index.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const Connection = require('interface-connection').Connection
55
const assert = require('assert')
66

77
const Errors = require('./errors')
8-
const handshake = require('./handshake')
98
const State = require('./state')
109
const decodeV1PSK = require('./crypto').decodeV1PSK
1110
const debug = require('debug')
@@ -19,12 +18,10 @@ log.err = debug('libp2p:pnet:err')
1918
class Protector {
2019
/**
2120
* @param {Buffer} keyBuffer The private shared key buffer
22-
* @param {any} options Options for the protector
2321
* @constructor
2422
*/
25-
constructor (keyBuffer, options) {
23+
constructor (keyBuffer) {
2624
const decodedPSK = decodeV1PSK(keyBuffer)
27-
this.options = options || {}
2825
this.psk = decodedPSK.psk
2926
this.tag = decodedPSK.tag
3027
}
@@ -42,21 +39,21 @@ class Protector {
4239
assert(connection, Errors.NO_HANDSHAKE_CONNECTION)
4340

4441
const protectedConnection = new Connection(undefined, connection)
45-
const state = new State(this.psk, { timeout: this.options.timeout }, callback)
42+
const state = new State(this.psk)
4643

4744
log('protecting the connection')
4845

49-
// Run the connection through an encryption handshake
46+
// Run the connection through an encryptor
5047
pull(
5148
connection,
52-
handshake(state, (err) => {
49+
state.encrypt((err, encryptedOuterStream) => {
5350
if (err) {
5451
log.err('There was an error attempting to protect the connection', err)
5552
return callback(err)
5653
}
5754

5855
connection.getPeerInfo(() => {
59-
protectedConnection.setInnerConn(new Connection(state.secure, connection))
56+
protectedConnection.setInnerConn(new Connection(encryptedOuterStream, connection))
6057
log('the connection has been successfully wrapped by the protector')
6158
callback()
6259
})

src/state.js

Lines changed: 81 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,105 @@
11
'use strict'
22

3-
const handshake = require('pull-handshake')
4-
const deferred = require('pull-defer')
53
const crypto = require('crypto')
4+
const debug = require('debug')
5+
const pair = require('pull-pair')
6+
const Reader = require('pull-reader')
7+
const cat = require('pull-cat')
8+
const pull = require('pull-stream')
9+
10+
const cryptoStreams = require('./crypto')
611
const NONCE_LENGTH = require('./key-generator').NONCE_LENGTH
712

13+
const log = debug('libp2p:pnet')
14+
log.err = debug('libp2p:pnet:err')
15+
816
/**
917
* Keeps track of the state of a given connection, such as the local psk
1018
* and local and remote nonces for encryption/decryption
1119
*/
1220
class State {
1321
/**
1422
* @param {Buffer} psk The key buffer used for encryption
15-
* @param {any} options Options for the state, including timeout of the handshake
16-
* @param {function(Error)} callback Called on completion of the handshake
1723
* @constructor
1824
*/
19-
constructor (psk, options, callback) {
25+
constructor (psk) {
2026
this.local = {
2127
nonce: Buffer.from(
2228
crypto.randomBytes(NONCE_LENGTH)
2329
),
2430
psk: psk
2531
}
26-
options = options || {}
27-
2832
this.remote = { nonce: null }
29-
this.timeout = options.timeout || 60e3
30-
this.secure = deferred.duplex()
31-
this.stream = handshake({ timeout: this.timeout }, callback)
32-
this.shake = this.stream.handshake
33-
delete this.stream.handshake
33+
34+
this.rawReader = Reader(60e3)
35+
this.encryptedReader = Reader(60e3)
36+
37+
this.rawPairStream = pair()
38+
this.encryptedPairStream = pair()
39+
40+
// The raw, pair stream
41+
this.innerRawStream = null
42+
this.outerRawStream = {
43+
sink: this.rawReader,
44+
source: cat([
45+
pull.values([
46+
this.local.nonce
47+
]),
48+
this.rawPairStream.source
49+
])
50+
}
51+
52+
// The encrypted, pair stream
53+
this.innerEncryptedStream = {
54+
sink: this.encryptedReader,
55+
source: this.encryptedPairStream.source
56+
}
57+
this.outerEncryptedStream = null
58+
}
59+
60+
/**
61+
* Creates encryption streams for the given state
62+
*
63+
* @param {function(Error, Connection)} callback
64+
* @returns {void}
65+
*/
66+
encrypt (callback) {
67+
// The outer stream needs to be returned before we setup the
68+
// rest of the streams, so we're delaying the execution
69+
setTimeout(() => {
70+
// Read the nonce first, this queues up the read when data
71+
// is available, so we will have the nonce before any
72+
// decryption occurs
73+
this.rawReader.read(NONCE_LENGTH, (err, data) => {
74+
if (err) {
75+
log.err('There was an error attempting to read the nonce', err)
76+
}
77+
this.remote.nonce = data
78+
})
79+
80+
this.innerRawStream = {
81+
sink: this.rawPairStream.sink,
82+
source: this.rawReader.read()
83+
}
84+
85+
// Create the pull exchange between the two inner streams
86+
pull(
87+
this.innerRawStream,
88+
cryptoStreams.createUnboxStream(this.remote, this.local.psk),
89+
this.innerEncryptedStream,
90+
cryptoStreams.createBoxStream(this.local.nonce, this.local.psk),
91+
this.innerRawStream
92+
)
93+
94+
this.outerEncryptedStream = {
95+
sink: this.encryptedPairStream.sink,
96+
source: this.encryptedReader.read()
97+
}
98+
99+
callback(null, this.outerEncryptedStream)
100+
}, 0)
101+
102+
return this.outerRawStream
34103
}
35104
}
36105

test/pnet.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ describe('private network', () => {
2828
parallel([
2929
(cb) => PeerId.createFromJSON(require('./fixtures/peer-a'), cb),
3030
(cb) => PeerId.createFromJSON(require('./fixtures/peer-b'), cb)
31-
], (err, peers) => {
31+
], (err) => {
3232
expect(err).to.not.exist()
3333
done()
3434
})

0 commit comments

Comments
 (0)