117 lines
3.0 KiB
JavaScript
Raw Normal View History

2016-05-22 01:03:53 +02:00
'use strict'
const crypto = require('libp2p-crypto')
const debug = require('debug')
2016-05-22 01:33:50 +02:00
const fs = require('fs')
const path = require('path')
2016-05-22 13:19:17 +02:00
const protobuf = require('protocol-buffers')
2016-05-22 01:33:50 +02:00
const log = debug('libp2p:secio:2-exchange')
log.error = debug('libp2p:secio:2-exchange:error')
2016-05-22 01:03:53 +02:00
2016-05-22 01:33:50 +02:00
const pbm = protobuf(fs.readFileSync(path.join(__dirname, '../secio.proto')))
2016-05-22 01:31:00 +02:00
const support = require('../support')
2016-05-22 18:36:31 +02:00
// step 2. Exchange
// -- exchange (signed) ephemeral keys. verify signatures.
module.exports = function exchange (session, cb) {
log('start')
let genSharedKey
let exchangeOut
2016-05-22 01:03:53 +02:00
2016-05-22 18:36:31 +02:00
try {
const eResult = crypto.generateEphemeralKeyPair(session.local.curveT)
session.local.ephemeralPubKey = eResult.key
genSharedKey = eResult.genSharedKey
exchangeOut = makeExchange(session)
log('exout', exchangeOut.toString('hex'))
2016-05-22 18:36:31 +02:00
} catch (err) {
log.error(err)
2016-05-22 18:36:31 +02:00
return cb(err)
}
session.insecureLp.write(exchangeOut)
session.insecureLp.once('data', (chunk) => {
const exchangeIn = pbm.Exchange.decode(chunk)
log('exIn', exchangeIn)
2016-05-22 18:36:31 +02:00
try {
verify(session, exchangeIn)
keys(session, exchangeIn, genSharedKey)
macAndCipher(session)
} catch (err) {
log.error(err)
2016-05-22 18:36:31 +02:00
return cb(err)
}
log('2. exchange - finish')
cb()
})
}
2016-05-22 01:03:53 +02:00
2016-05-22 18:36:31 +02:00
function makeExchange (session) {
log('make exchange')
2016-05-22 01:03:53 +02:00
// Gather corpus to sign.
const selectionOut = Buffer.concat([
2016-05-22 18:36:31 +02:00
session.proposal.out,
session.proposal.in,
2016-05-22 01:03:53 +02:00
session.local.ephemeralPubKey
])
const epubkey = session.local.ephemeralPubKey
const signature = session.localKey.sign(selectionOut)
log('exOut', epubkey, signature)
return pbm.Exchange.encode({epubkey, signature})
2016-05-22 18:36:31 +02:00
}
2016-05-22 01:03:53 +02:00
2016-05-22 18:36:31 +02:00
function verify (session, exchangeIn) {
2016-05-22 01:03:53 +02:00
log('2.1. verify')
session.remote.ephemeralPubKey = exchangeIn.epubkey
const selectionIn = Buffer.concat([
2016-05-22 18:36:31 +02:00
session.proposal.in,
session.proposal.out,
2016-05-22 01:03:53 +02:00
session.remote.ephemeralPubKey
])
const sigOk = session.remote.permanentPubKey.verify(selectionIn, exchangeIn.signature)
if (!sigOk) {
throw new Error('Bad signature')
}
log('2.1. verify - signature verified')
2016-05-22 18:36:31 +02:00
}
2016-05-22 01:03:53 +02:00
2016-05-22 18:36:31 +02:00
function keys (session, exchangeIn, genSharedKey) {
2016-05-22 01:03:53 +02:00
log('2.2. keys')
session.sharedSecret = genSharedKey(exchangeIn.epubkey)
const keys = crypto.keyStretcher(session.local.cipherT, session.local.hashT, session.sharedSecret)
// use random nonces to decide order.
2016-05-22 18:36:31 +02:00
if (session.proposal.order > 0) {
2016-05-22 01:03:53 +02:00
session.local.keys = keys.k1
session.remote.keys = keys.k2
2016-05-22 18:36:31 +02:00
} else if (session.proposal.order < 0) {
2016-05-22 01:03:53 +02:00
// swap
session.local.keys = keys.k2
session.remote.keys = keys.k1
} else {
// we should've bailed before this. but if not, bail here.
throw new Error('you are trying to talk to yourself')
}
log('2.2. keys - shared: %s\n\tlocal: %s\n\tremote: %s', session.sharedSecret, session.local.keys, session.remote.keys)
2016-05-22 18:36:31 +02:00
}
2016-05-22 01:03:53 +02:00
2016-05-22 18:36:31 +02:00
function macAndCipher (session) {
2016-05-22 01:03:53 +02:00
log('2.3. mac + cipher')
2016-05-22 01:31:00 +02:00
support.makeMacAndCipher(session.local)
support.makeMacAndCipher(session.remote)
2016-05-22 01:03:53 +02:00
}