test('build', function(t) { var sessionKey = nacl.box.keyPair() var databaseKey = nacl.box.keyPair() var doc = permit(sessionKey, databaseKey).build() t.equal(doc.nonce.length, nacl.box.nonceLength, 'nonce has correct length') t.equal(doc.ephemeral.length, nacl.box.publicKeyLength, 'ephemeral has correct length') t.deepEqual(doc.sessionKey, sessionKey, 'has session key') t.deepEqual(doc.databaseKey, databaseKey, 'has database key') t.end() })
ecdh: function (pub) { if (!priv) throw new Error('this is a public key!') pub = toUint8Array(pub) const sharedKey = curve25519.before(pub, privArr) return new Buffer(sharedKey) },
box.open = function(doc) { if (turnedOff) return doc if (doc._id.match(/^permit\//)) return doc if (!(sender in doc.receivers)) return doc var permit = doc.receivers[sender] var key = nacl.box.open( nacl.util.decodeBase64(permit.encryptedKey), nacl.util.decodeBase64(permit.nonce), nacl.util.decodeBase64(doc.ephemeral), databaseKey.secretKey ) if (!key) throw('Decryption error') var data = nacl.secretbox.open( nacl.util.decodeBase64(doc.box), nacl.util.decodeBase64(doc.nonce), key ) if (!data) throw('Decryption error') var recs = Object.keys(doc.receivers) .reduce(function(memo, key) { memo[key] = true return memo }, {}) return assign(JSON.parse(nacl.util.encodeUTF8(data)), pick(doc, underscoreProperties), { receivers: recs }) }
test('toJSON', function(t) { var sessionKey = nacl.box.keyPair() var databaseKey = nacl.box.keyPair() var doc = permit(sessionKey) doc.build(databaseKey) var json = doc.toJSON() t.equal(json.nonce, nacl.util.encodeBase64(doc.nonce), 'encodes nonce') t.equal(json.ephemeral, nacl.util.encodeBase64(doc.ephemeral), 'encodes ephemeral') t.equal(json.encryptedKey, nacl.util.encodeBase64(doc.encryptedKey), 'encodes encryptedKey') t.end() })
function extractDecryptInfo(header, secretKey) { let decryptInfo = null const ephemeral = nacl.util.decodeBase64(header.ephemeral) for (let i in header.decryptInfo) { const nonce = nacl.util.decodeBase64(i) debug(`Trying nonce ${hex(nonce)}`) decryptInfo = nacl.util.decodeBase64(header.decryptInfo[i]) decryptInfo = nacl.box.open(decryptInfo, nonce, ephemeral, secretKey) if (decryptInfo) { decryptInfo = JSON.parse(nacl.util.encodeUTF8(decryptInfo)) debug(`Recipient ID is ${decryptInfo.recipientID}`) debug(`Sender ID is ${decryptInfo.senderID}`) decryptInfo.fileInfo = nacl.util.decodeBase64(decryptInfo.fileInfo) decryptInfo.fileInfo = nacl.box.open(decryptInfo.fileInfo, nonce, keyFromId(decryptInfo.senderID), secretKey) decryptInfo.fileInfo = JSON.parse( nacl.util.encodeUTF8(decryptInfo.fileInfo) ) debug(`File key is` + ` ${hex(nacl.util.decodeBase64(decryptInfo.fileInfo.fileKey))}`) debug(`File nonce is` + ` ${hex(nacl.util.decodeBase64(decryptInfo.fileInfo.fileNonce))}`) debug(`File hash is` + ` ${hex(nacl.util.decodeBase64(decryptInfo.fileInfo.fileHash))}`) break } } return decryptInfo }
regen: function () { if (!this.pubkey) throw new Error('wallet must have pubkey prop to regen') var boxKey = nacl.box.keyPair() this.decryptSk = boxKey.secretKey buf = Buffer.concat([ Buffer.from(this.signSk), Buffer.from(this.decryptSk) ]) var pubkeyBuf = Buffer.concat([ Buffer.from(this.pubkey.verifyPk), Buffer.from(boxKey.publicKey) ]) this.pubkey = libPubkey.parse(pubkeyBuf) },
function createWallet () { var boxKey = nacl.box.keyPair() var signKey = nacl.sign.keyPair() var walletBuf = Buffer.concat([ Buffer.from(signKey.secretKey), Buffer.from(boxKey.secretKey) ]) var wallet = parseWallet(walletBuf) var pubkeyBuf = Buffer.concat([ Buffer.from(signKey.publicKey), Buffer.from(boxKey.publicKey) ]) wallet.pubkey = libPubkey.parse(pubkeyBuf) return wallet }
permit.build = function() { var nonce = nacl.randomBytes(nacl.box.nonceLength) var ephemeralKey = nacl.box.keyPair() permit.nonce = nonce permit.ephemeral = ephemeralKey.publicKey permit.encryptedKey = nacl.box( permit.databaseKey.secretKey, nonce, sessionKey.publicKey, ephemeralKey.secretKey ) return permit }
var box = function(doc) { if (turnedOff) return doc if (doc._id.match(/^permit\//)) return doc var key = nacl.randomBytes(nacl.secretbox.keyLength) var nonce = nacl.randomBytes(nacl.secretbox.nonceLength) var ephemeralKey = nacl.box.keyPair() var recs = Object.keys(doc.receivers || {}) .map(function(receiver) { return nacl.util.decodeBase64(receiver) }) .concat(receivers) .reduce(function(memo, publicKey) { var nonce = nacl.randomBytes(nacl.box.nonceLength) memo[nacl.util.encodeBase64(publicKey)] = { nonce: nacl.util.encodeBase64(nonce), encryptedKey: nacl.util.encodeBase64(nacl.box( key, nonce, publicKey, ephemeralKey.secretKey )) } return memo }, {}) var box = nacl.util.encodeBase64(nacl.secretbox( nacl.util.decodeUTF8(JSON.stringify(omit(doc, underscoreProperties))), nonce, key )) return assign({ ephemeral: nacl.util.encodeBase64(ephemeralKey.publicKey), nonce: nacl.util.encodeBase64(nonce), receivers: recs, box: box }, pick(doc, underscoreProperties)) }
function makeHeader(ids, senderInfo, fileInfo) { const ephemeral = nacl.box.keyPair() const header = { version: 1, ephemeral: nacl.util.encodeBase64(ephemeral.publicKey), decryptInfo: {} } debug(`Ephemeral public key is ${hex(ephemeral.publicKey)}`) debug(`Ephemeral secret key is ${hex(ephemeral.secretKey)}`) for (let id of ids) { debug(`Adding recipient ${id}`) const nonce = nacl.randomBytes(24) const publicKey = keyFromId(id) debug(`Using nonce ${hex(nonce)}`) let decryptInfo = { senderID: senderInfo.id, recipientID: id, fileInfo: fileInfo } decryptInfo.fileInfo = nacl.util.encodeBase64(nacl.box( nacl.util.decodeUTF8(JSON.stringify(decryptInfo.fileInfo)), nonce, publicKey, senderInfo.secretKey )) decryptInfo = nacl.util.encodeBase64(nacl.box( nacl.util.decodeUTF8(JSON.stringify(decryptInfo)), nonce, publicKey, ephemeral.secretKey )) header.decryptInfo[nacl.util.encodeBase64(nonce)] = decryptInfo } return JSON.stringify(header) }
permit.parse = function(json) { permit.type = json.type permit.nonce = nacl.util.decodeBase64(json.nonce) permit.ephemeral = nacl.util.decodeBase64(json.ephemeral) permit.encryptedKey = nacl.util.decodeBase64(json.encryptedKey) var secretKey = nacl.box.open( permit.encryptedKey, permit.nonce, permit.ephemeral, sessionKey.secretKey ) permit.databaseKey = nacl.box.keyPair.fromSecretKey(secretKey) permit._conflicts = json._conflicts permit._rev = json._rev return permit }
DiffieHellman.prototype.computeSecret = function (otherpk) { this._keyCheck(otherpk, true); if (!this._isPriv) throw (new Error('DH exchange has not been initialized with ' + 'a private key yet')); var pub; if (this._algo === 'dsa') { return (this._dh.computeSecret( otherpk.part.y.data)); } else if (this._algo === 'ecdsa') { if (CRYPTO_HAVE_ECDH) { return (this._dh.computeSecret( otherpk.part.Q.data)); } else { pub = new ECPublic( this._ecParams, otherpk.part.Q.data); return (this._priv.deriveSharedSecret(pub)); } } else if (this._algo === 'curve25519') { pub = otherpk.part.A.data; while (pub[0] === 0x00 && pub.length > 32) pub = pub.slice(1); var priv = this._priv; assert.strictEqual(pub.length, 32); assert.strictEqual(priv.length, 32); var secret = nacl.box.before(new Uint8Array(pub), new Uint8Array(priv)); return (Buffer.from(secret)); } throw (new Error('Invalid algorithm: ' + this._algo)); };
box.close = function() { turnedOff = true databaseKey = nacl.box.keyPair() }
module.exports = function permit(sessionKey, databaseKey) { var permit = { _id: 'permit/' + nacl.util.encodeBase64(sessionKey.publicKey), type: 'curve25519-xsalsa20-poly1305', sessionKey: sessionKey, databaseKey: databaseKey || nacl.box.keyPair() } permit.toJSON = function() { return { _id: permit._id, _rev: permit._rev, type: permit.type, nonce: nacl.util.encodeBase64(permit.nonce), ephemeral: nacl.util.encodeBase64(permit.ephemeral), encryptedKey: nacl.util.encodeBase64(permit.encryptedKey) } } permit.build = function() { var nonce = nacl.randomBytes(nacl.box.nonceLength) var ephemeralKey = nacl.box.keyPair() permit.nonce = nonce permit.ephemeral = ephemeralKey.publicKey permit.encryptedKey = nacl.box( permit.databaseKey.secretKey, nonce, sessionKey.publicKey, ephemeralKey.secretKey ) return permit } permit.parse = function(json) { permit.type = json.type permit.nonce = nacl.util.decodeBase64(json.nonce) permit.ephemeral = nacl.util.decodeBase64(json.ephemeral) permit.encryptedKey = nacl.util.decodeBase64(json.encryptedKey) var secretKey = nacl.box.open( permit.encryptedKey, permit.nonce, permit.ephemeral, sessionKey.secretKey ) permit.databaseKey = nacl.box.keyPair.fromSecretKey(secretKey) permit._conflicts = json._conflicts permit._rev = json._rev return permit } permit.receiver = function() { return nacl.util.encodeBase64(permit.databaseKey.publicKey) } return permit }
/** * Generate a new key pair. * * @return {Object} - New NaCl key pair. */ newPair () { return nacl.box.keyPair() }
function genSync () { const priv = curve25519.keyPair() return impl.fromJSON({ priv }) }
DiffieHellman.prototype.generateKey = function () { var parts = []; var priv, pub; if (this._algo === 'dsa') { this._dh.generateKeys(); parts.push({name: 'p', data: this._p.data}); parts.push({name: 'q', data: this._key.part.q.data}); parts.push({name: 'g', data: this._g.data}); parts.push({name: 'y', data: this._dh.getPublicKey()}); parts.push({name: 'x', data: this._dh.getPrivateKey()}); this._key = new PrivateKey({ type: 'dsa', parts: parts }); this._isPriv = true; return (this._key); } else if (this._algo === 'ecdsa') { if (CRYPTO_HAVE_ECDH) { this._dh.generateKeys(); parts.push({name: 'curve', data: Buffer.from(this._curve)}); parts.push({name: 'Q', data: this._dh.getPublicKey()}); parts.push({name: 'd', data: this._dh.getPrivateKey()}); this._key = new PrivateKey({ type: 'ecdsa', curve: this._curve, parts: parts }); this._isPriv = true; return (this._key); } else { var n = this._ecParams.getN(); var r = new jsbn(crypto.randomBytes(n.bitLength())); var n1 = n.subtract(jsbn.ONE); priv = r.mod(n1).add(jsbn.ONE); pub = this._ecParams.getG().multiply(priv); priv = Buffer.from(priv.toByteArray()); pub = Buffer.from(this._ecParams.getCurve(). encodePointHex(pub), 'hex'); this._priv = new ECPrivate(this._ecParams, priv); parts.push({name: 'curve', data: Buffer.from(this._curve)}); parts.push({name: 'Q', data: pub}); parts.push({name: 'd', data: priv}); this._key = new PrivateKey({ type: 'ecdsa', curve: this._curve, parts: parts }); this._isPriv = true; return (this._key); } } else if (this._algo === 'curve25519') { var pair = nacl.box.keyPair(); priv = Buffer.from(pair.secretKey); pub = Buffer.from(pair.publicKey); priv = Buffer.concat([priv, pub]); assert.strictEqual(priv.length, 64); assert.strictEqual(pub.length, 32); parts.push({name: 'A', data: pub}); parts.push({name: 'k', data: priv}); this._key = new PrivateKey({ type: 'curve25519', parts: parts }); this._isPriv = true; return (this._key); } throw (new Error('Invalid algorithm: ' + this._algo)); };
var net = require('net-udp') var nacl = require('tweetnacl') var PacketStream = require('../src/packet-stream.js') var MessageStream = require('../src/message-stream.js') nacl.util = require('tweetnacl-util') var NB_BLOCKS = 100 var BLOCK_LENGTH = 1024 var server = net.createServer() var client = new net.Socket() var serverKeyPair = nacl.box.keyPair() var clientKeyPair = nacl.box.keyPair() var source = Buffer(NB_BLOCKS * BLOCK_LENGTH) var sourceServer = Buffer(NB_BLOCKS * BLOCK_LENGTH) for (var i = 0; i < NB_BLOCKS; i++) { var buffer = new Buffer(nacl.randomBytes(BLOCK_LENGTH)) buffer.copy(source, i * BLOCK_LENGTH) } for (i = 0; i < NB_BLOCKS; i++) { buffer = new Buffer(nacl.randomBytes(BLOCK_LENGTH)) buffer.copy(sourceServer, i * BLOCK_LENGTH) } var currentBlock = 0 var currentBlockServer = 0 var messageStream
function generateCurve25519KeyPair() { var keyPair = tweetnacl.box.keyPair(); return keyPair; }