Skip to content

Instantly share code, notes, and snippets.

@arlolra
Created June 28, 2013 17:09
Show Gist options
  • Save arlolra/5886310 to your computer and use it in GitHub Desktop.
Save arlolra/5886310 to your computer and use it in GitHub Desktop.
diff --git a/.jshintrc b/.jshintrc
index 62a53cf..8fcd5f7 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -12,10 +12,13 @@
, "white" : false
, "multistr" : true
, "globals" : {
- "it" : true
- , "beforeEach" : true
- , "before" : true
- , "describe" : true
- , "define" : true
+ "it" : true
+ , "beforeEach" : true
+ , "before" : true
+ , "describe" : true
+ , "define" : true
+ , "postMessage" : true
+ , "onmessage" : true
+ , "importScripts" : true
}
}
\ No newline at end of file
diff --git a/lib/otr.js b/lib/otr.js
index 02f28a4..0df67a7 100644
--- a/lib/otr.js
+++ b/lib/otr.js
@@ -3,12 +3,15 @@
var root = this
- var CryptoJS, BigInt, EventEmitter, CONST, HLP, Parse, AKE, SM, DSA
+ var CryptoJS, BigInt, EventEmitter, Worker, SMWPath
+ , CONST, HLP, Parse, AKE, SM, DSA
if (typeof module !== 'undefined' && module.exports) {
module.exports = OTR
CryptoJS = require('../vendor/crypto.js')
BigInt = require('../vendor/bigint.js')
EventEmitter = require('../vendor/eventemitter.js').EventEmitter
+ Worker = require('webworker-threads').Worker
+ SMWPath = require('path').join(__dirname, '/sm-webworker.js')
CONST = require('./const.js')
HLP = require('./helpers.js')
Parse = require('./parse.js')
@@ -26,6 +29,8 @@
CryptoJS = root.CryptoJS
BigInt = root.BigInt
EventEmitter = root.EventEmitter
+ Worker = root.Worker
+ SMWPath = 'sm-webworker.js'
CONST = OTR.CONST
HLP = OTR.HLP
Parse = OTR.Parse
@@ -72,6 +77,11 @@
// debug
this.debug = !!options.debug
+ // smp in webworker options
+ this.sm_webworker = !!options.sm_webworker
+ this.seed_ww = (typeof options.seed_ww === 'function') ?
+ options.seed_ww : BigInt.getSeed
+
// init vals
this.init()
@@ -142,7 +152,44 @@
this.ssid = null
}
+ // smp over webworker
+ OTR.prototype._wwSM = function (otr) {
+ this.otr = otr
+ this.worker = new Worker(SMWPath)
+ this.worker.onmessage = function (e) {
+ console.log("Worker said : " + e.data)
+ }
+ this.worker.postMessage({
+ type: 'seed'
+ , seed: otr.seed_ww()
+ })
+ this.worker.postMessage({
+ type: 'init'
+ , ssid: otr.ssid
+ , our_fp: otr.priv.fingerprint()
+ , their_fp: otr.their_priv_pk.fingerprint()
+ , msgstate: otr.msgstate
+ })
+ }
+
+ // shim sm methods
+ ;['handleSM', 'rcvSecret'].forEach(function (m) {
+ OTR.prototype._wwSM.prototype[m] = function () {
+ this.worker.postMessage({
+ type: 'method'
+ , method: m
+ , args: Array.prototype.slice.call(arguments, 0)
+ , msgstate: this.otr.msgstate
+ })
+ }
+ })
+
OTR.prototype._smInit = function () {
+ if (this.sm_webworker) {
+ if (this.sm) this.sm.close() // destroy prev webworker
+ this.sm = new this._wwSM(this)
+ return
+ }
this.sm = new SM(this)
}
diff --git a/lib/sm-webworker.js b/lib/sm-webworker.js
new file mode 100644
index 0000000..95c1196
--- /dev/null
+++ b/lib/sm-webworker.js
@@ -0,0 +1,75 @@
+;(function (root) {
+ "use strict";
+
+ // ughhh
+ var seed = null
+
+ root.OTR = {}
+ root.crypto = {
+ randomBytes: function () { return seed }
+ }
+
+ function err() {
+ postMessage(arguments)
+ }
+
+ function send() {
+ postMessage(arguments)
+ }
+
+ function trigger() {
+ postMessage(arguments)
+ }
+
+ var sm
+ onmessage = function (msg) {
+ var d = msg.data
+ switch(d.type) {
+ case 'seed':
+ seed = d.seed
+ try {
+ importScripts('vendor/salsa20.js')
+ importScripts('vendor/bigint.js')
+ importScripts('vendor/crypto.js')
+ importScripts('lib/const.js')
+ importScripts('lib/helpers.js')
+ importScripts('lib/sm.js')
+ } catch (e) {
+ console.log(e.stack)
+ }
+ console.log('done seeding')
+ break
+ case 'init':
+ try {
+ console.log('typeof')
+ console.log(typeof root.SM)
+ sm = new root.OTR.SM({
+ debug: true
+ , trust: false
+ , sm_webworker: true
+ , ssid: d.ssid
+ , priv: { fingerprint: function () { return d.our_fp } }
+ , their_priv_pk: { fingerprint: function () { return d.their_fp } }
+ , msgstate: d.msgstate
+ , error: err
+ , trigger: trigger
+ , _sendMsg: send
+ })
+ } catch (e) {
+ console.log(e.stack)
+ }
+ break
+ case 'method':
+ console.log(d)
+ console.log(sm)
+ sm.otr.msgstate = d.msgstate
+ console.log('here')
+ try {
+ sm[d.method].apply(sm, d.args)
+ } catch (e) { console.log(e.stack) }
+ console.log('done')
+ break
+ }
+ }
+
+}(this))
\ No newline at end of file
diff --git a/lib/sm.js b/lib/sm.js
index d3fa1da..7a61826 100644
--- a/lib/sm.js
+++ b/lib/sm.js
@@ -3,21 +3,19 @@
var root = this
- var CryptoJS, BigInt, CONST, HLP, DSA
+ var CryptoJS, BigInt, CONST, HLP
if (typeof module !== 'undefined' && module.exports) {
module.exports = SM
CryptoJS = require('../vendor/crypto.js')
BigInt = require('../vendor/bigint.js')
CONST = require('./const.js')
HLP = require('./helpers.js')
- DSA = require('./dsa.js')
} else {
root.OTR.SM = SM
CryptoJS = root.CryptoJS
BigInt = root.BigInt
CONST = root.OTR.CONST
HLP = root.OTR.HLP
- DSA = root.DSA
}
// diffie-hellman modulus and generator
@@ -32,6 +30,8 @@
function SM(otr) {
if (!(this instanceof SM)) return new SM(otr)
+ console.log('haha')
+
this.otr = otr
this.version = '1'
this.our_fp = otr.priv.fingerprint()
@@ -342,6 +342,8 @@
rcvSecret: function (secret, question) {
HLP.debug.call(this.otr, 'receive secret')
+ console.log('here')
+
this.otr.trigger('status', [CONST.STATUS_SMP_SECRET])
if (this.otr.msgstate !== CONST.MSGSTATE_ENCRYPTED)
diff --git a/package.json b/package.json
index e6d8fdc..679bfda 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,9 @@
"socialist millionaire",
"dsa"
],
+ "optionalDependencies": {
+ "webworker-threads": "0.4.x"
+ },
"devDependencies": {
"mocha": "1.10.x",
"simple-xmpp": "0.1.x",
diff --git a/test/spec/unit/sm.js b/test/spec/unit/sm.js
index 4586d74..dd2e183 100644
--- a/test/spec/unit/sm.js
+++ b/test/spec/unit/sm.js
@@ -81,7 +81,6 @@ describe('SM', function () {
})
-
it('2 should verify the SM secret failed', function (done) {
this.timeout(15000)
var both = false
@@ -169,4 +168,52 @@ describe('SM', function () {
})
})
+ it.only('4 should verify the SM secret in a webworker', function (done) {
+ this.timeout(15000)
+ var both = false
+
+ // use webworkers
+ userA.sm_webworker = true
+ userB.sm_webworker = true
+
+ userA.on('ui', function (msg) { assert.equal(false, !!msg, msg) })
+ userA.on('error', function (err) { assert.equal(false, !!err, err) })
+
+ userA.on('status', function (state) {
+ if (state === CONST.STATUS_AKE_SUCCESS) {
+ assert.equal(userB.msgstate, CONST.MSGSTATE_ENCRYPTED, 'Encrypted')
+ assert.equal(userA.msgstate, CONST.MSGSTATE_ENCRYPTED, 'Encrypted')
+ assert.ok(!userA.trust, 'Trust B? false')
+ assert.ok(!userB.trust, 'Trust A? false')
+ userA.smpSecret('applesAndOranges')
+ }
+ })
+
+ userA.on('smp', function (type) {
+ if (type === 'trust') {
+ assert.ok(userA.trust, 'Trust B? false')
+ if (both) done()
+ else both = true
+ }
+ })
+
+ userB.sendQueryMsg() // must have AKEd for SM
+
+ userB.on('smp', function (type) {
+ switch (type) {
+ case 'question':
+ userB.smpSecret('applesAndOranges')
+ break
+ case 'trust':
+ assert.ok(userB.trust, 'Trust A? false')
+ if (both) done()
+ else both = true
+ break
+ default:
+ throw new Error('should not be here')
+ }
+ })
+
+ })
+
})
\ No newline at end of file
diff --git a/vendor/bigint.js b/vendor/bigint.js
index ad2a7ab..fe476d6 100644
--- a/vendor/bigint.js
+++ b/vendor/bigint.js
@@ -1567,10 +1567,21 @@
, bpe : bpe
, primes : primes
, findPrimes : findPrimes
+ , getSeed : getSeed
}
- function seedRand(state) {
- return function () {
+ function seedRand(buf) {
+
+ var state = new Salsa20([
+ buf[ 0], buf[ 1], buf[ 2], buf[ 3], buf[ 4], buf[ 5], buf[ 6], buf[ 7],
+ buf[ 8], buf[ 9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15],
+ buf[16], buf[17], buf[18], buf[19], buf[20], buf[21], buf[22], buf[23],
+ buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31]
+ ],[
+ buf[32], buf[33], buf[34], buf[35], buf[36], buf[37], buf[38], buf[39]
+ ])
+
+ Math.random = function () {
var x, o = ''
while (o.length < 16) {
x = state.getBytes(1)
@@ -1578,10 +1589,10 @@
}
return parseFloat('0.' + o)
}
- }
- ;(function seed() {
+ }
+ function getSeed() {
var buf
if ( (typeof crypto !== 'undefined') &&
(typeof crypto.randomBytes === 'function')
@@ -1597,20 +1608,15 @@
} else {
throw new Error('Keys should not be generated without CSPRNG.')
}
+ return Array.prototype.slice.call(buf, 0)
+ }
- var state = new Salsa20([
- buf[ 0], buf[ 1], buf[ 2], buf[ 3], buf[ 4], buf[ 5], buf[ 6], buf[ 7],
- buf[ 8], buf[ 9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15],
- buf[16], buf[17], buf[18], buf[19], buf[20], buf[21], buf[22], buf[23],
- buf[24], buf[25], buf[26], buf[27], buf[28], buf[29], buf[30], buf[31]
- ],[
- buf[32], buf[33], buf[34], buf[35], buf[36], buf[37], buf[38], buf[39]
- ])
+ ;(function seed() {
- Math.random = seedRand(state)
+ seedRand(getSeed())
// reseed every 5 mins
- setTimeout(seed, 5 * 60 * 1000)
+ if (typeof setTimeout === 'function') setTimeout(seed, 5 * 60 * 1000)
}())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment