Mercurial > sat_docs
comparison scripts/minifier/otr/otr.js @ 12:1596660ddf72
Add minifier script for otr.js and its dependencies
author | souliane <souliane@mailoo.org> |
---|---|
date | Wed, 03 Sep 2014 19:38:05 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
11:4920c8da790b | 12:1596660ddf72 |
---|---|
1 /*! | |
2 | |
3 otr.js v0.2.12 - 2014-04-15 | |
4 (c) 2014 - Arlo Breault <arlolra@gmail.com> | |
5 Freely distributed under the MPL v2.0 license. | |
6 | |
7 This file is concatenated for the browser. | |
8 Please see: https://github.com/arlolra/otr | |
9 | |
10 */ | |
11 | |
12 ;(function (root, factory) { | |
13 | |
14 if (typeof define === 'function' && define.amd) { | |
15 define([ | |
16 "bigint" | |
17 , "crypto" | |
18 , "eventemitter" | |
19 ], function (BigInt, CryptoJS, EventEmitter) { | |
20 var root = { | |
21 BigInt: BigInt | |
22 , CryptoJS: CryptoJS | |
23 , EventEmitter: EventEmitter | |
24 , OTR: {} | |
25 , DSA: {} | |
26 } | |
27 return factory.call(root) | |
28 }) | |
29 } else { | |
30 root.OTR = {} | |
31 root.DSA = {} | |
32 factory.call(root) | |
33 } | |
34 | |
35 }(this, function () { | |
36 | |
37 ;(function () { | |
38 "use strict"; | |
39 | |
40 var root = this | |
41 | |
42 var CONST = { | |
43 | |
44 // diffie-heilman | |
45 N : 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF' | |
46 , G : '2' | |
47 | |
48 // otr message states | |
49 , MSGSTATE_PLAINTEXT : 0 | |
50 , MSGSTATE_ENCRYPTED : 1 | |
51 , MSGSTATE_FINISHED : 2 | |
52 | |
53 // otr auth states | |
54 , AUTHSTATE_NONE : 0 | |
55 , AUTHSTATE_AWAITING_DHKEY : 1 | |
56 , AUTHSTATE_AWAITING_REVEALSIG : 2 | |
57 , AUTHSTATE_AWAITING_SIG : 3 | |
58 | |
59 // whitespace tags | |
60 , WHITESPACE_TAG : '\x20\x09\x20\x20\x09\x09\x09\x09\x20\x09\x20\x09\x20\x09\x20\x20' | |
61 , WHITESPACE_TAG_V2 : '\x20\x20\x09\x09\x20\x20\x09\x20' | |
62 , WHITESPACE_TAG_V3 : '\x20\x20\x09\x09\x20\x20\x09\x09' | |
63 | |
64 // otr tags | |
65 , OTR_TAG : '?OTR' | |
66 , OTR_VERSION_1 : '\x00\x01' | |
67 , OTR_VERSION_2 : '\x00\x02' | |
68 , OTR_VERSION_3 : '\x00\x03' | |
69 | |
70 // smp machine states | |
71 , SMPSTATE_EXPECT0 : 0 | |
72 , SMPSTATE_EXPECT1 : 1 | |
73 , SMPSTATE_EXPECT2 : 2 | |
74 , SMPSTATE_EXPECT3 : 3 | |
75 , SMPSTATE_EXPECT4 : 4 | |
76 | |
77 // unstandard status codes | |
78 , STATUS_SEND_QUERY : 0 | |
79 , STATUS_AKE_INIT : 1 | |
80 , STATUS_AKE_SUCCESS : 2 | |
81 , STATUS_END_OTR : 3 | |
82 | |
83 } | |
84 | |
85 if (typeof module !== 'undefined' && module.exports) { | |
86 module.exports = CONST | |
87 } else { | |
88 root.OTR.CONST = CONST | |
89 } | |
90 | |
91 }).call(this) | |
92 ;(function () { | |
93 "use strict"; | |
94 | |
95 var root = this | |
96 | |
97 var HLP = {}, CryptoJS, BigInt | |
98 if (typeof module !== 'undefined' && module.exports) { | |
99 module.exports = HLP = {} | |
100 CryptoJS = require('../vendor/crypto.js') | |
101 BigInt = require('../vendor/bigint.js') | |
102 } else { | |
103 if (root.OTR) root.OTR.HLP = HLP | |
104 if (root.DSA) root.DSA.HLP = HLP | |
105 CryptoJS = root.CryptoJS | |
106 BigInt = root.BigInt | |
107 } | |
108 | |
109 // data types (byte lengths) | |
110 var DTS = { | |
111 BYTE : 1 | |
112 , SHORT : 2 | |
113 , INT : 4 | |
114 , CTR : 8 | |
115 , MAC : 20 | |
116 , SIG : 40 | |
117 } | |
118 | |
119 // otr message wrapper begin and end | |
120 var WRAPPER_BEGIN = "?OTR" | |
121 , WRAPPER_END = "." | |
122 | |
123 var TWO = BigInt.str2bigInt('2', 10) | |
124 | |
125 HLP.debug = function (msg) { | |
126 // used as HLP.debug.call(ctx, msg) | |
127 if ( this.debug && | |
128 typeof this.debug !== 'function' && | |
129 typeof console !== 'undefined' | |
130 ) console.log(msg) | |
131 } | |
132 | |
133 HLP.extend = function (child, parent) { | |
134 for (var key in parent) { | |
135 if (Object.hasOwnProperty.call(parent, key)) | |
136 child[key] = parent[key] | |
137 } | |
138 function Ctor() { this.constructor = child } | |
139 Ctor.prototype = parent.prototype | |
140 child.prototype = new Ctor() | |
141 child.__super__ = parent.prototype | |
142 } | |
143 | |
144 // constant-time string comparison | |
145 HLP.compare = function (str1, str2) { | |
146 if (str1.length !== str2.length) | |
147 return false | |
148 var i = 0, result = 0 | |
149 for (; i < str1.length; i++) | |
150 result |= str1[i].charCodeAt(0) ^ str2[i].charCodeAt(0) | |
151 return result === 0 | |
152 } | |
153 | |
154 HLP.randomExponent = function () { | |
155 return BigInt.randBigInt(1536) | |
156 } | |
157 | |
158 HLP.smpHash = function (version, fmpi, smpi) { | |
159 var sha256 = CryptoJS.algo.SHA256.create() | |
160 sha256.update(CryptoJS.enc.Latin1.parse(HLP.packBytes(version, DTS.BYTE))) | |
161 sha256.update(CryptoJS.enc.Latin1.parse(HLP.packMPI(fmpi))) | |
162 if (smpi) sha256.update(CryptoJS.enc.Latin1.parse(HLP.packMPI(smpi))) | |
163 var hash = sha256.finalize() | |
164 return HLP.bits2bigInt(hash.toString(CryptoJS.enc.Latin1)) | |
165 } | |
166 | |
167 HLP.makeMac = function (aesctr, m) { | |
168 var pass = CryptoJS.enc.Latin1.parse(m) | |
169 var mac = CryptoJS.HmacSHA256(CryptoJS.enc.Latin1.parse(aesctr), pass) | |
170 return HLP.mask(mac.toString(CryptoJS.enc.Latin1), 0, 160) | |
171 } | |
172 | |
173 HLP.make1Mac = function (aesctr, m) { | |
174 var pass = CryptoJS.enc.Latin1.parse(m) | |
175 var mac = CryptoJS.HmacSHA1(CryptoJS.enc.Latin1.parse(aesctr), pass) | |
176 return mac.toString(CryptoJS.enc.Latin1) | |
177 } | |
178 | |
179 HLP.encryptAes = function (msg, c, iv) { | |
180 var opts = { | |
181 mode: CryptoJS.mode.CTR | |
182 , iv: CryptoJS.enc.Latin1.parse(iv) | |
183 , padding: CryptoJS.pad.NoPadding | |
184 } | |
185 var aesctr = CryptoJS.AES.encrypt( | |
186 msg | |
187 , CryptoJS.enc.Latin1.parse(c) | |
188 , opts | |
189 ) | |
190 var aesctr_decoded = CryptoJS.enc.Base64.parse(aesctr.toString()) | |
191 return CryptoJS.enc.Latin1.stringify(aesctr_decoded) | |
192 } | |
193 | |
194 HLP.decryptAes = function (msg, c, iv) { | |
195 msg = CryptoJS.enc.Latin1.parse(msg) | |
196 var opts = { | |
197 mode: CryptoJS.mode.CTR | |
198 , iv: CryptoJS.enc.Latin1.parse(iv) | |
199 , padding: CryptoJS.pad.NoPadding | |
200 } | |
201 return CryptoJS.AES.decrypt( | |
202 CryptoJS.enc.Base64.stringify(msg) | |
203 , CryptoJS.enc.Latin1.parse(c) | |
204 , opts | |
205 ) | |
206 } | |
207 | |
208 HLP.multPowMod = function (a, b, c, d, e) { | |
209 return BigInt.multMod(BigInt.powMod(a, b, e), BigInt.powMod(c, d, e), e) | |
210 } | |
211 | |
212 HLP.ZKP = function (v, c, d, e) { | |
213 return BigInt.equals(c, HLP.smpHash(v, d, e)) | |
214 } | |
215 | |
216 // greater than, or equal | |
217 HLP.GTOE = function (a, b) { | |
218 return (BigInt.equals(a, b) || BigInt.greater(a, b)) | |
219 } | |
220 | |
221 HLP.between = function (x, a, b) { | |
222 return (BigInt.greater(x, a) && BigInt.greater(b, x)) | |
223 } | |
224 | |
225 HLP.checkGroup = function (g, N_MINUS_2) { | |
226 return HLP.GTOE(g, TWO) && HLP.GTOE(N_MINUS_2, g) | |
227 } | |
228 | |
229 HLP.h1 = function (b, secbytes) { | |
230 var sha1 = CryptoJS.algo.SHA1.create() | |
231 sha1.update(CryptoJS.enc.Latin1.parse(b)) | |
232 sha1.update(CryptoJS.enc.Latin1.parse(secbytes)) | |
233 return (sha1.finalize()).toString(CryptoJS.enc.Latin1) | |
234 } | |
235 | |
236 HLP.h2 = function (b, secbytes) { | |
237 var sha256 = CryptoJS.algo.SHA256.create() | |
238 sha256.update(CryptoJS.enc.Latin1.parse(b)) | |
239 sha256.update(CryptoJS.enc.Latin1.parse(secbytes)) | |
240 return (sha256.finalize()).toString(CryptoJS.enc.Latin1) | |
241 } | |
242 | |
243 HLP.mask = function (bytes, start, n) { | |
244 return bytes.substr(start / 8, n / 8) | |
245 } | |
246 | |
247 var _toString = String.fromCharCode; | |
248 HLP.packBytes = function (val, bytes) { | |
249 val = val.toString(16) | |
250 var nex, res = '' // big-endian, unsigned long | |
251 for (; bytes > 0; bytes--) { | |
252 nex = val.length ? val.substr(-2, 2) : '0' | |
253 val = val.substr(0, val.length - 2) | |
254 res = _toString(parseInt(nex, 16)) + res | |
255 } | |
256 return res | |
257 } | |
258 | |
259 HLP.packINT = function (d) { | |
260 return HLP.packBytes(d, DTS.INT) | |
261 } | |
262 | |
263 HLP.packCtr = function (d) { | |
264 return HLP.padCtr(HLP.packBytes(d, DTS.CTR)) | |
265 } | |
266 | |
267 HLP.padCtr = function (ctr) { | |
268 return ctr + '\x00\x00\x00\x00\x00\x00\x00\x00' | |
269 } | |
270 | |
271 HLP.unpackCtr = function (d) { | |
272 d = HLP.toByteArray(d.substring(0, 8)) | |
273 return HLP.unpack(d) | |
274 } | |
275 | |
276 HLP.unpack = function (arr) { | |
277 var val = 0, i = 0, len = arr.length | |
278 for (; i < len; i++) { | |
279 val = (val * 256) + arr[i] | |
280 } | |
281 return val | |
282 } | |
283 | |
284 HLP.packData = function (d) { | |
285 return HLP.packINT(d.length) + d | |
286 } | |
287 | |
288 HLP.bits2bigInt = function (bits) { | |
289 bits = HLP.toByteArray(bits) | |
290 return BigInt.ba2bigInt(bits) | |
291 } | |
292 | |
293 HLP.packMPI = function (mpi) { | |
294 return HLP.packData(BigInt.bigInt2bits(BigInt.trim(mpi, 0))) | |
295 } | |
296 | |
297 HLP.packSHORT = function (short) { | |
298 return HLP.packBytes(short, DTS.SHORT) | |
299 } | |
300 | |
301 HLP.unpackSHORT = function (short) { | |
302 short = HLP.toByteArray(short) | |
303 return HLP.unpack(short) | |
304 } | |
305 | |
306 HLP.packTLV = function (type, value) { | |
307 return HLP.packSHORT(type) + HLP.packSHORT(value.length) + value | |
308 } | |
309 | |
310 HLP.readLen = function (msg) { | |
311 msg = HLP.toByteArray(msg.substring(0, 4)) | |
312 return HLP.unpack(msg) | |
313 } | |
314 | |
315 HLP.readData = function (data) { | |
316 var n = HLP.unpack(data.splice(0, 4)) | |
317 return [n, data] | |
318 } | |
319 | |
320 HLP.readMPI = function (data) { | |
321 data = HLP.toByteArray(data) | |
322 data = HLP.readData(data) | |
323 return BigInt.ba2bigInt(data[1]) | |
324 } | |
325 | |
326 HLP.packMPIs = function (arr) { | |
327 return arr.reduce(function (prv, cur) { | |
328 return prv + HLP.packMPI(cur) | |
329 }, '') | |
330 } | |
331 | |
332 HLP.unpackMPIs = function (num, mpis) { | |
333 var i = 0, arr = [] | |
334 for (; i < num; i++) arr.push('MPI') | |
335 return (HLP.splitype(arr, mpis)).map(function (m) { | |
336 return HLP.readMPI(m) | |
337 }) | |
338 } | |
339 | |
340 HLP.wrapMsg = function (msg, fs, v3, our_it, their_it) { | |
341 msg = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Latin1.parse(msg)) | |
342 msg = WRAPPER_BEGIN + ":" + msg + WRAPPER_END | |
343 | |
344 var its | |
345 if (v3) { | |
346 its = '|' | |
347 its += (HLP.readLen(our_it)).toString(16) | |
348 its += '|' | |
349 its += (HLP.readLen(their_it)).toString(16) | |
350 } | |
351 | |
352 if (!fs) return [null, msg] | |
353 | |
354 var n = Math.ceil(msg.length / fs) | |
355 if (n > 65535) return ['Too many fragments'] | |
356 if (n == 1) return [null, msg] | |
357 | |
358 var k, bi, ei, frag, mf, mfs = [] | |
359 for (k = 1; k <= n; k++) { | |
360 bi = (k - 1) * fs | |
361 ei = k * fs | |
362 frag = msg.slice(bi, ei) | |
363 mf = WRAPPER_BEGIN | |
364 if (v3) mf += its | |
365 mf += ',' + k + ',' | |
366 mf += n + ',' | |
367 mf += frag + ',' | |
368 mfs.push(mf) | |
369 } | |
370 | |
371 return [null, mfs] | |
372 } | |
373 | |
374 HLP.splitype = function splitype(arr, msg) { | |
375 var data = [] | |
376 arr.forEach(function (a) { | |
377 var str | |
378 switch (a) { | |
379 case 'PUBKEY': | |
380 str = splitype(['SHORT', 'MPI', 'MPI', 'MPI', 'MPI'], msg).join('') | |
381 break | |
382 case 'DATA': // falls through | |
383 case 'MPI': | |
384 str = msg.substring(0, HLP.readLen(msg) + 4) | |
385 break | |
386 default: | |
387 str = msg.substring(0, DTS[a]) | |
388 } | |
389 data.push(str) | |
390 msg = msg.substring(str.length) | |
391 }) | |
392 return data | |
393 } | |
394 | |
395 // https://github.com/msgpack/msgpack-javascript/blob/master/msgpack.js | |
396 | |
397 var _bin2num = (function () { | |
398 var i = 0, _bin2num = {} | |
399 for (; i < 0x100; ++i) { | |
400 _bin2num[String.fromCharCode(i)] = i // "\00" -> 0x00 | |
401 } | |
402 for (i = 0x80; i < 0x100; ++i) { // [Webkit][Gecko] | |
403 _bin2num[String.fromCharCode(0xf700 + i)] = i // "\f780" -> 0x80 | |
404 } | |
405 return _bin2num | |
406 }()) | |
407 | |
408 HLP.toByteArray = function (data) { | |
409 var rv = [] | |
410 , ary = data.split("") | |
411 , i = -1 | |
412 , iz = ary.length | |
413 , remain = iz % 8 | |
414 | |
415 while (remain--) { | |
416 ++i | |
417 rv[i] = _bin2num[ary[i]] | |
418 } | |
419 remain = iz >> 3 | |
420 while (remain--) { | |
421 rv.push(_bin2num[ary[++i]], _bin2num[ary[++i]], | |
422 _bin2num[ary[++i]], _bin2num[ary[++i]], | |
423 _bin2num[ary[++i]], _bin2num[ary[++i]], | |
424 _bin2num[ary[++i]], _bin2num[ary[++i]]) | |
425 } | |
426 return rv | |
427 } | |
428 | |
429 }).call(this) | |
430 ;(function () { | |
431 "use strict"; | |
432 | |
433 var root = this | |
434 | |
435 var CryptoJS, BigInt, Worker, WWPath, HLP | |
436 if (typeof module !== 'undefined' && module.exports) { | |
437 module.exports = DSA | |
438 CryptoJS = require('../vendor/crypto.js') | |
439 BigInt = require('../vendor/bigint.js') | |
440 WWPath = require('path').join(__dirname, '/dsa-webworker.js') | |
441 HLP = require('./helpers.js') | |
442 } else { | |
443 // copy over and expose internals | |
444 Object.keys(root.DSA).forEach(function (k) { | |
445 DSA[k] = root.DSA[k] | |
446 }) | |
447 root.DSA = DSA | |
448 CryptoJS = root.CryptoJS | |
449 BigInt = root.BigInt | |
450 Worker = root.Worker | |
451 WWPath = 'dsa-webworker.js' | |
452 HLP = DSA.HLP | |
453 } | |
454 | |
455 var ZERO = BigInt.str2bigInt('0', 10) | |
456 , ONE = BigInt.str2bigInt('1', 10) | |
457 , TWO = BigInt.str2bigInt('2', 10) | |
458 , KEY_TYPE = '\x00\x00' | |
459 | |
460 var DEBUG = false | |
461 function timer() { | |
462 var start = (new Date()).getTime() | |
463 return function (s) { | |
464 if (!DEBUG || typeof console === 'undefined') return | |
465 var t = (new Date()).getTime() | |
466 console.log(s + ': ' + (t - start)) | |
467 start = t | |
468 } | |
469 } | |
470 | |
471 function makeRandom(min, max) { | |
472 var c = BigInt.randBigInt(BigInt.bitSize(max)) | |
473 if (!HLP.between(c, min, max)) return makeRandom(min, max) | |
474 return c | |
475 } | |
476 | |
477 // altered BigInt.randProbPrime() | |
478 // n rounds of Miller Rabin (after trial division with small primes) | |
479 var rpprb = [] | |
480 function isProbPrime(k, n) { | |
481 var i, B = 30000, l = BigInt.bitSize(k) | |
482 var primes = BigInt.primes | |
483 | |
484 if (primes.length === 0) | |
485 primes = BigInt.findPrimes(B) | |
486 | |
487 if (rpprb.length != k.length) | |
488 rpprb = BigInt.dup(k) | |
489 | |
490 // check ans for divisibility by small primes up to B | |
491 for (i = 0; (i < primes.length) && (primes[i] <= B); i++) | |
492 if (BigInt.modInt(k, primes[i]) === 0 && !BigInt.equalsInt(k, primes[i])) | |
493 return 0 | |
494 | |
495 // do n rounds of Miller Rabin, with random bases less than k | |
496 for (i = 0; i < n; i++) { | |
497 BigInt.randBigInt_(rpprb, l, 0) | |
498 while(!BigInt.greater(k, rpprb)) // pick a random rpprb that's < k | |
499 BigInt.randBigInt_(rpprb, l, 0) | |
500 if (!BigInt.millerRabin(k, rpprb)) | |
501 return 0 | |
502 } | |
503 | |
504 return 1 | |
505 } | |
506 | |
507 var bit_lengths = { | |
508 '1024': { N: 160, repeat: 40 } // 40x should give 2^-80 confidence | |
509 , '2048': { N: 224, repeat: 56 } | |
510 } | |
511 | |
512 var primes = {} | |
513 | |
514 // follows go lang http://golang.org/src/pkg/crypto/dsa/dsa.go | |
515 // fips version was removed in 0c99af0df3e7 | |
516 function generatePrimes(bit_length) { | |
517 | |
518 var t = timer() // for debugging | |
519 | |
520 // number of MR tests to perform | |
521 var repeat = bit_lengths[bit_length].repeat | |
522 | |
523 var N = bit_lengths[bit_length].N | |
524 | |
525 var LM1 = BigInt.twoToThe(bit_length - 1) | |
526 var bl4 = 4 * bit_length | |
527 var brk = false | |
528 | |
529 var q, p, rem, counter | |
530 for (;;) { | |
531 | |
532 q = BigInt.randBigInt(N, 1) | |
533 q[0] |= 1 | |
534 | |
535 if (!isProbPrime(q, repeat)) continue | |
536 t('q') | |
537 | |
538 for (counter = 0; counter < bl4; counter++) { | |
539 p = BigInt.randBigInt(bit_length, 1) | |
540 p[0] |= 1 | |
541 | |
542 rem = BigInt.mod(p, q) | |
543 rem = BigInt.sub(rem, ONE) | |
544 p = BigInt.sub(p, rem) | |
545 | |
546 if (BigInt.greater(LM1, p)) continue | |
547 if (!isProbPrime(p, repeat)) continue | |
548 | |
549 t('p') | |
550 primes[bit_length] = { p: p, q: q } | |
551 brk = true | |
552 break | |
553 } | |
554 | |
555 if (brk) break | |
556 } | |
557 | |
558 var h = BigInt.dup(TWO) | |
559 var pm1 = BigInt.sub(p, ONE) | |
560 var e = BigInt.multMod(pm1, BigInt.inverseMod(q, p), p) | |
561 | |
562 var g | |
563 for (;;) { | |
564 g = BigInt.powMod(h, e, p) | |
565 if (BigInt.equals(g, ONE)) { | |
566 h = BigInt.add(h, ONE) | |
567 continue | |
568 } | |
569 primes[bit_length].g = g | |
570 t('g') | |
571 return | |
572 } | |
573 | |
574 throw new Error('Unreachable!') | |
575 } | |
576 | |
577 function DSA(obj, opts) { | |
578 if (!(this instanceof DSA)) return new DSA(obj, opts) | |
579 | |
580 // options | |
581 opts = opts || {} | |
582 | |
583 // inherit | |
584 if (obj) { | |
585 var self = this | |
586 ;['p', 'q', 'g', 'y', 'x'].forEach(function (prop) { | |
587 self[prop] = obj[prop] | |
588 }) | |
589 this.type = obj.type || KEY_TYPE | |
590 return | |
591 } | |
592 | |
593 // default to 1024 | |
594 var bit_length = parseInt(opts.bit_length ? opts.bit_length : 1024, 10) | |
595 | |
596 if (!bit_lengths[bit_length]) | |
597 throw new Error('Unsupported bit length.') | |
598 | |
599 // set primes | |
600 if (!primes[bit_length]) | |
601 generatePrimes(bit_length) | |
602 | |
603 this.p = primes[bit_length].p | |
604 this.q = primes[bit_length].q | |
605 this.g = primes[bit_length].g | |
606 | |
607 // key type | |
608 this.type = KEY_TYPE | |
609 | |
610 // private key | |
611 this.x = makeRandom(ZERO, this.q) | |
612 | |
613 // public keys (p, q, g, y) | |
614 this.y = BigInt.powMod(this.g, this.x, this.p) | |
615 | |
616 // nocache? | |
617 if (opts.nocache) primes[bit_length] = null | |
618 } | |
619 | |
620 DSA.prototype = { | |
621 | |
622 constructor: DSA, | |
623 | |
624 packPublic: function () { | |
625 var str = this.type | |
626 str += HLP.packMPI(this.p) | |
627 str += HLP.packMPI(this.q) | |
628 str += HLP.packMPI(this.g) | |
629 str += HLP.packMPI(this.y) | |
630 return str | |
631 }, | |
632 | |
633 packPrivate: function () { | |
634 var str = this.packPublic() + HLP.packMPI(this.x) | |
635 str = CryptoJS.enc.Latin1.parse(str) | |
636 return str.toString(CryptoJS.enc.Base64) | |
637 }, | |
638 | |
639 // http://www.imperialviolet.org/2013/06/15/suddendeathentropy.html | |
640 generateNonce: function (m) { | |
641 var priv = BigInt.bigInt2bits(BigInt.trim(this.x, 0)) | |
642 var rand = BigInt.bigInt2bits(BigInt.randBigInt(256)) | |
643 | |
644 var sha256 = CryptoJS.algo.SHA256.create() | |
645 sha256.update(CryptoJS.enc.Latin1.parse(priv)) | |
646 sha256.update(m) | |
647 sha256.update(CryptoJS.enc.Latin1.parse(rand)) | |
648 | |
649 var hash = sha256.finalize() | |
650 hash = HLP.bits2bigInt(hash.toString(CryptoJS.enc.Latin1)) | |
651 BigInt.rightShift_(hash, 256 - BigInt.bitSize(this.q)) | |
652 | |
653 return HLP.between(hash, ZERO, this.q) ? hash : this.generateNonce(m) | |
654 }, | |
655 | |
656 sign: function (m) { | |
657 m = CryptoJS.enc.Latin1.parse(m) | |
658 var b = BigInt.str2bigInt(m.toString(CryptoJS.enc.Hex), 16) | |
659 var k, r = ZERO, s = ZERO | |
660 while (BigInt.isZero(s) || BigInt.isZero(r)) { | |
661 k = this.generateNonce(m) | |
662 r = BigInt.mod(BigInt.powMod(this.g, k, this.p), this.q) | |
663 if (BigInt.isZero(r)) continue | |
664 s = BigInt.inverseMod(k, this.q) | |
665 s = BigInt.mult(s, BigInt.add(b, BigInt.mult(this.x, r))) | |
666 s = BigInt.mod(s, this.q) | |
667 } | |
668 return [r, s] | |
669 }, | |
670 | |
671 fingerprint: function () { | |
672 var pk = this.packPublic() | |
673 if (this.type === KEY_TYPE) pk = pk.substring(2) | |
674 pk = CryptoJS.enc.Latin1.parse(pk) | |
675 return CryptoJS.SHA1(pk).toString(CryptoJS.enc.Hex) | |
676 } | |
677 | |
678 } | |
679 | |
680 DSA.parsePublic = function (str, priv) { | |
681 var fields = ['SHORT', 'MPI', 'MPI', 'MPI', 'MPI'] | |
682 if (priv) fields.push('MPI') | |
683 str = HLP.splitype(fields, str) | |
684 var obj = { | |
685 type: str[0] | |
686 , p: HLP.readMPI(str[1]) | |
687 , q: HLP.readMPI(str[2]) | |
688 , g: HLP.readMPI(str[3]) | |
689 , y: HLP.readMPI(str[4]) | |
690 } | |
691 if (priv) obj.x = HLP.readMPI(str[5]) | |
692 return new DSA(obj) | |
693 } | |
694 | |
695 function tokenizeStr(str) { | |
696 var start, end | |
697 | |
698 start = str.indexOf("(") | |
699 end = str.lastIndexOf(")") | |
700 | |
701 if (start < 0 || end < 0) | |
702 throw new Error("Malformed S-Expression") | |
703 | |
704 str = str.substring(start + 1, end) | |
705 | |
706 var splt = str.search(/\s/) | |
707 var obj = { | |
708 type: str.substring(0, splt) | |
709 , val: [] | |
710 } | |
711 | |
712 str = str.substring(splt + 1, end) | |
713 start = str.indexOf("(") | |
714 | |
715 if (start < 0) obj.val.push(str) | |
716 else { | |
717 | |
718 var i, len, ss, es | |
719 while (start > -1) { | |
720 i = start + 1 | |
721 len = str.length | |
722 for (ss = 1, es = 0; i < len && es < ss; i++) { | |
723 if (str[i] === "(") ss++ | |
724 if (str[i] === ")") es++ | |
725 } | |
726 obj.val.push(tokenizeStr(str.substring(start, ++i))) | |
727 str = str.substring(++i) | |
728 start = str.indexOf("(") | |
729 } | |
730 | |
731 } | |
732 return obj | |
733 } | |
734 | |
735 function parseLibotr(obj) { | |
736 if (!obj.type) throw new Error("Parse error.") | |
737 | |
738 var o, val | |
739 if (obj.type === "privkeys") { | |
740 o = [] | |
741 obj.val.forEach(function (i) { | |
742 o.push(parseLibotr(i)) | |
743 }) | |
744 return o | |
745 } | |
746 | |
747 o = {} | |
748 obj.val.forEach(function (i) { | |
749 | |
750 val = i.val[0] | |
751 if (typeof val === "string") { | |
752 | |
753 if (val.indexOf("#") === 0) { | |
754 val = val.substring(1, val.lastIndexOf("#")) | |
755 val = BigInt.str2bigInt(val, 16) | |
756 } | |
757 | |
758 } else { | |
759 val = parseLibotr(i) | |
760 } | |
761 | |
762 o[i.type] = val | |
763 }) | |
764 | |
765 return o | |
766 } | |
767 | |
768 DSA.parsePrivate = function (str, libotr) { | |
769 if (!libotr) { | |
770 str = CryptoJS.enc.Base64.parse(str) | |
771 str = str.toString(CryptoJS.enc.Latin1) | |
772 return DSA.parsePublic(str, true) | |
773 } | |
774 // only returning the first key found | |
775 return parseLibotr(tokenizeStr(str))[0]["private-key"].dsa | |
776 } | |
777 | |
778 DSA.verify = function (key, m, r, s) { | |
779 if (!HLP.between(r, ZERO, key.q) || !HLP.between(s, ZERO, key.q)) | |
780 return false | |
781 | |
782 var hm = CryptoJS.enc.Latin1.parse(m) // CryptoJS.SHA1(m) | |
783 hm = BigInt.str2bigInt(hm.toString(CryptoJS.enc.Hex), 16) | |
784 | |
785 var w = BigInt.inverseMod(s, key.q) | |
786 var u1 = BigInt.multMod(hm, w, key.q) | |
787 var u2 = BigInt.multMod(r, w, key.q) | |
788 | |
789 u1 = BigInt.powMod(key.g, u1, key.p) | |
790 u2 = BigInt.powMod(key.y, u2, key.p) | |
791 | |
792 var v = BigInt.mod(BigInt.multMod(u1, u2, key.p), key.q) | |
793 | |
794 return BigInt.equals(v, r) | |
795 } | |
796 | |
797 DSA.createInWebWorker = function (options, cb) { | |
798 var opts = { | |
799 path: WWPath | |
800 , seed: BigInt.getSeed | |
801 } | |
802 if (options && typeof options === 'object') | |
803 Object.keys(options).forEach(function (k) { | |
804 opts[k] = options[k] | |
805 }) | |
806 | |
807 // load optional dep. in node | |
808 if (typeof module !== 'undefined' && module.exports) | |
809 Worker = require('webworker-threads').Worker | |
810 | |
811 var worker = new Worker(opts.path) | |
812 worker.onmessage = function (e) { | |
813 var data = e.data | |
814 switch (data.type) { | |
815 case "debug": | |
816 if (!DEBUG || typeof console === 'undefined') return | |
817 console.log(data.val) | |
818 break; | |
819 case "data": | |
820 worker.terminate() | |
821 cb(DSA.parsePrivate(data.val)) | |
822 break; | |
823 default: | |
824 throw new Error("Unrecognized type.") | |
825 } | |
826 } | |
827 worker.postMessage({ | |
828 seed: opts.seed() | |
829 , imports: opts.imports | |
830 , debug: DEBUG | |
831 }) | |
832 } | |
833 | |
834 }).call(this) | |
835 ;(function () { | |
836 "use strict"; | |
837 | |
838 var root = this | |
839 | |
840 var Parse = {}, CryptoJS, CONST, HLP | |
841 if (typeof module !== 'undefined' && module.exports) { | |
842 module.exports = Parse | |
843 CryptoJS = require('../vendor/crypto.js') | |
844 CONST = require('./const.js') | |
845 HLP = require('./helpers.js') | |
846 } else { | |
847 root.OTR.Parse = Parse | |
848 CryptoJS = root.CryptoJS | |
849 CONST = root.OTR.CONST | |
850 HLP = root.OTR.HLP | |
851 } | |
852 | |
853 // whitespace tags | |
854 var tags = {} | |
855 tags[CONST.WHITESPACE_TAG_V2] = CONST.OTR_VERSION_2 | |
856 tags[CONST.WHITESPACE_TAG_V3] = CONST.OTR_VERSION_3 | |
857 | |
858 Parse.parseMsg = function (otr, msg) { | |
859 | |
860 var ver = [] | |
861 | |
862 // is this otr? | |
863 var start = msg.indexOf(CONST.OTR_TAG) | |
864 if (!~start) { | |
865 | |
866 // restart fragments | |
867 this.initFragment(otr) | |
868 | |
869 // whitespace tags | |
870 ind = msg.indexOf(CONST.WHITESPACE_TAG) | |
871 | |
872 if (~ind) { | |
873 | |
874 msg = msg.split('') | |
875 msg.splice(ind, 16) | |
876 | |
877 var tag, len = msg.length | |
878 for (; ind < len;) { | |
879 tag = msg.slice(ind, ind + 8).join('') | |
880 if (Object.hasOwnProperty.call(tags, tag)) { | |
881 msg.splice(ind, 8) | |
882 ver.push(tags[tag]) | |
883 continue | |
884 } | |
885 ind += 8 | |
886 } | |
887 | |
888 msg = msg.join('') | |
889 | |
890 } | |
891 | |
892 return { msg: msg, ver: ver } | |
893 } | |
894 | |
895 var ind = start + CONST.OTR_TAG.length | |
896 var com = msg[ind] | |
897 | |
898 // message fragment | |
899 if (com === ',' || com === '|') { | |
900 return this.msgFragment(otr, msg.substring(ind + 1), (com === '|')) | |
901 } | |
902 | |
903 this.initFragment(otr) | |
904 | |
905 // query message | |
906 if (~['?', 'v'].indexOf(com)) { | |
907 | |
908 // version 1 | |
909 if (msg[ind] === '?') { | |
910 ver.push(CONST.OTR_VERSION_1) | |
911 ind += 1 | |
912 } | |
913 | |
914 // other versions | |
915 var vers = { | |
916 '2': CONST.OTR_VERSION_2 | |
917 , '3': CONST.OTR_VERSION_3 | |
918 } | |
919 var qs = msg.substring(ind + 1) | |
920 var qi = qs.indexOf('?') | |
921 | |
922 if (qi >= 1) { | |
923 qs = qs.substring(0, qi).split('') | |
924 if (msg[ind] === 'v') { | |
925 qs.forEach(function (q) { | |
926 if (Object.hasOwnProperty.call(vers, q)) ver.push(vers[q]) | |
927 }) | |
928 } | |
929 } | |
930 | |
931 return { cls: 'query', ver: ver } | |
932 } | |
933 | |
934 // otr message | |
935 if (com === ':') { | |
936 | |
937 ind += 1 | |
938 | |
939 var info = msg.substring(ind, ind + 4) | |
940 if (info.length < 4) return { msg: msg } | |
941 info = CryptoJS.enc.Base64.parse(info).toString(CryptoJS.enc.Latin1) | |
942 | |
943 var version = info.substring(0, 2) | |
944 var type = info.substring(2) | |
945 | |
946 // supporting otr versions 2 and 3 | |
947 if (!otr['ALLOW_V' + HLP.unpackSHORT(version)]) return { msg: msg } | |
948 | |
949 ind += 4 | |
950 | |
951 var end = msg.substring(ind).indexOf('.') | |
952 if (!~end) return { msg: msg } | |
953 | |
954 msg = CryptoJS.enc.Base64.parse(msg.substring(ind, ind + end)) | |
955 msg = CryptoJS.enc.Latin1.stringify(msg) | |
956 | |
957 // instance tags | |
958 var instance_tags | |
959 if (version === CONST.OTR_VERSION_3) { | |
960 instance_tags = msg.substring(0, 8) | |
961 msg = msg.substring(8) | |
962 } | |
963 | |
964 var cls | |
965 if (~['\x02', '\x0a', '\x11', '\x12'].indexOf(type)) { | |
966 cls = 'ake' | |
967 } else if (type === '\x03') { | |
968 cls = 'data' | |
969 } | |
970 | |
971 return { | |
972 version: version | |
973 , type: type | |
974 , msg: msg | |
975 , cls: cls | |
976 , instance_tags: instance_tags | |
977 } | |
978 } | |
979 | |
980 // error message | |
981 if (msg.substring(ind, ind + 7) === ' Error:') { | |
982 if (otr.ERROR_START_AKE) { | |
983 otr.sendQueryMsg() | |
984 } | |
985 return { msg: msg.substring(ind + 7), cls: 'error' } | |
986 } | |
987 | |
988 return { msg: msg } | |
989 } | |
990 | |
991 Parse.initFragment = function (otr) { | |
992 otr.fragment = { s: '', j: 0, k: 0 } | |
993 } | |
994 | |
995 Parse.msgFragment = function (otr, msg, v3) { | |
996 | |
997 msg = msg.split(',') | |
998 | |
999 // instance tags | |
1000 if (v3) { | |
1001 var its = msg.shift().split('|') | |
1002 var their_it = HLP.packINT(parseInt(its[0], 16)) | |
1003 var our_it = HLP.packINT(parseInt(its[1], 16)) | |
1004 if (otr.checkInstanceTags(their_it + our_it)) return // ignore | |
1005 } | |
1006 | |
1007 if (msg.length < 4 || | |
1008 isNaN(parseInt(msg[0], 10)) || | |
1009 isNaN(parseInt(msg[1], 10)) | |
1010 ) return | |
1011 | |
1012 var k = parseInt(msg[0], 10) | |
1013 var n = parseInt(msg[1], 10) | |
1014 msg = msg[2] | |
1015 | |
1016 if (n < k || n === 0 || k === 0) { | |
1017 this.initFragment(otr) | |
1018 return | |
1019 } | |
1020 | |
1021 if (k === 1) { | |
1022 this.initFragment(otr) | |
1023 otr.fragment = { k: 1, n: n, s: msg } | |
1024 } else if (n === otr.fragment.n && k === (otr.fragment.k + 1)) { | |
1025 otr.fragment.s += msg | |
1026 otr.fragment.k += 1 | |
1027 } else { | |
1028 this.initFragment(otr) | |
1029 } | |
1030 | |
1031 if (n === k) { | |
1032 msg = otr.fragment.s | |
1033 this.initFragment(otr) | |
1034 return this.parseMsg(otr, msg) | |
1035 } | |
1036 | |
1037 return | |
1038 } | |
1039 | |
1040 }).call(this) | |
1041 ;(function () { | |
1042 "use strict"; | |
1043 | |
1044 var root = this | |
1045 | |
1046 var CryptoJS, BigInt, CONST, HLP, DSA | |
1047 if (typeof module !== 'undefined' && module.exports) { | |
1048 module.exports = AKE | |
1049 CryptoJS = require('../vendor/crypto.js') | |
1050 BigInt = require('../vendor/bigint.js') | |
1051 CONST = require('./const.js') | |
1052 HLP = require('./helpers.js') | |
1053 DSA = require('./dsa.js') | |
1054 } else { | |
1055 root.OTR.AKE = AKE | |
1056 CryptoJS = root.CryptoJS | |
1057 BigInt = root.BigInt | |
1058 CONST = root.OTR.CONST | |
1059 HLP = root.OTR.HLP | |
1060 DSA = root.DSA | |
1061 } | |
1062 | |
1063 // diffie-hellman modulus | |
1064 // see group 5, RFC 3526 | |
1065 var N = BigInt.str2bigInt(CONST.N, 16) | |
1066 var N_MINUS_2 = BigInt.sub(N, BigInt.str2bigInt('2', 10)) | |
1067 | |
1068 function hMac(gx, gy, pk, kid, m) { | |
1069 var pass = CryptoJS.enc.Latin1.parse(m) | |
1070 var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, pass) | |
1071 hmac.update(CryptoJS.enc.Latin1.parse(HLP.packMPI(gx))) | |
1072 hmac.update(CryptoJS.enc.Latin1.parse(HLP.packMPI(gy))) | |
1073 hmac.update(CryptoJS.enc.Latin1.parse(pk)) | |
1074 hmac.update(CryptoJS.enc.Latin1.parse(kid)) | |
1075 return (hmac.finalize()).toString(CryptoJS.enc.Latin1) | |
1076 } | |
1077 | |
1078 // AKE constructor | |
1079 function AKE(otr) { | |
1080 if (!(this instanceof AKE)) return new AKE(otr) | |
1081 | |
1082 // otr instance | |
1083 this.otr = otr | |
1084 | |
1085 // our keys | |
1086 this.our_dh = otr.our_old_dh | |
1087 this.our_keyid = otr.our_keyid - 1 | |
1088 | |
1089 // their keys | |
1090 this.their_y = null | |
1091 this.their_keyid = null | |
1092 this.their_priv_pk = null | |
1093 | |
1094 // state | |
1095 this.ssid = null | |
1096 this.transmittedRS = false | |
1097 this.r = null | |
1098 | |
1099 // bind methods | |
1100 var self = this | |
1101 ;['sendMsg'].forEach(function (meth) { | |
1102 self[meth] = self[meth].bind(self) | |
1103 }) | |
1104 } | |
1105 | |
1106 AKE.prototype = { | |
1107 | |
1108 constructor: AKE, | |
1109 | |
1110 createKeys: function(g) { | |
1111 var s = BigInt.powMod(g, this.our_dh.privateKey, N) | |
1112 var secbytes = HLP.packMPI(s) | |
1113 this.ssid = HLP.mask(HLP.h2('\x00', secbytes), 0, 64) // first 64-bits | |
1114 var tmp = HLP.h2('\x01', secbytes) | |
1115 this.c = HLP.mask(tmp, 0, 128) // first 128-bits | |
1116 this.c_prime = HLP.mask(tmp, 128, 128) // second 128-bits | |
1117 this.m1 = HLP.h2('\x02', secbytes) | |
1118 this.m2 = HLP.h2('\x03', secbytes) | |
1119 this.m1_prime = HLP.h2('\x04', secbytes) | |
1120 this.m2_prime = HLP.h2('\x05', secbytes) | |
1121 }, | |
1122 | |
1123 verifySignMac: function (mac, aesctr, m2, c, their_y, our_dh_pk, m1, ctr) { | |
1124 // verify mac | |
1125 var vmac = HLP.makeMac(aesctr, m2) | |
1126 if (!HLP.compare(mac, vmac)) | |
1127 return ['MACs do not match.'] | |
1128 | |
1129 // decrypt x | |
1130 var x = HLP.decryptAes(aesctr.substring(4), c, ctr) | |
1131 x = HLP.splitype(['PUBKEY', 'INT', 'SIG'], x.toString(CryptoJS.enc.Latin1)) | |
1132 | |
1133 var m = hMac(their_y, our_dh_pk, x[0], x[1], m1) | |
1134 var pub = DSA.parsePublic(x[0]) | |
1135 | |
1136 var r = HLP.bits2bigInt(x[2].substring(0, 20)) | |
1137 var s = HLP.bits2bigInt(x[2].substring(20)) | |
1138 | |
1139 // verify sign m | |
1140 if (!DSA.verify(pub, m, r, s)) return ['Cannot verify signature of m.'] | |
1141 | |
1142 return [null, HLP.readLen(x[1]), pub] | |
1143 }, | |
1144 | |
1145 makeM: function (their_y, m1, c, m2) { | |
1146 var pk = this.otr.priv.packPublic() | |
1147 var kid = HLP.packINT(this.our_keyid) | |
1148 var m = hMac(this.our_dh.publicKey, their_y, pk, kid, m1) | |
1149 m = this.otr.priv.sign(m) | |
1150 var msg = pk + kid | |
1151 msg += BigInt.bigInt2bits(m[0], 20) // pad to 20 bytes | |
1152 msg += BigInt.bigInt2bits(m[1], 20) | |
1153 msg = CryptoJS.enc.Latin1.parse(msg) | |
1154 var aesctr = HLP.packData(HLP.encryptAes(msg, c, HLP.packCtr(0))) | |
1155 var mac = HLP.makeMac(aesctr, m2) | |
1156 return aesctr + mac | |
1157 }, | |
1158 | |
1159 akeSuccess: function (version) { | |
1160 HLP.debug.call(this.otr, 'success') | |
1161 | |
1162 if (BigInt.equals(this.their_y, this.our_dh.publicKey)) | |
1163 return this.otr.error('equal keys - we have a problem.', true) | |
1164 | |
1165 this.otr.our_old_dh = this.our_dh | |
1166 this.otr.their_priv_pk = this.their_priv_pk | |
1167 | |
1168 if (!( | |
1169 (this.their_keyid === this.otr.their_keyid && | |
1170 BigInt.equals(this.their_y, this.otr.their_y)) || | |
1171 (this.their_keyid === (this.otr.their_keyid - 1) && | |
1172 BigInt.equals(this.their_y, this.otr.their_old_y)) | |
1173 )) { | |
1174 | |
1175 this.otr.their_y = this.their_y | |
1176 this.otr.their_old_y = null | |
1177 this.otr.their_keyid = this.their_keyid | |
1178 | |
1179 // rotate keys | |
1180 this.otr.sessKeys[0] = [ new this.otr.DHSession( | |
1181 this.otr.our_dh | |
1182 , this.otr.their_y | |
1183 ), null ] | |
1184 this.otr.sessKeys[1] = [ new this.otr.DHSession( | |
1185 this.otr.our_old_dh | |
1186 , this.otr.their_y | |
1187 ), null ] | |
1188 | |
1189 } | |
1190 | |
1191 // ake info | |
1192 this.otr.ssid = this.ssid | |
1193 this.otr.transmittedRS = this.transmittedRS | |
1194 this.otr_version = version | |
1195 | |
1196 // go encrypted | |
1197 this.otr.authstate = CONST.AUTHSTATE_NONE | |
1198 this.otr.msgstate = CONST.MSGSTATE_ENCRYPTED | |
1199 | |
1200 // null out values | |
1201 this.r = null | |
1202 this.myhashed = null | |
1203 this.dhcommit = null | |
1204 this.encrypted = null | |
1205 this.hashed = null | |
1206 | |
1207 this.otr.trigger('status', [CONST.STATUS_AKE_SUCCESS]) | |
1208 | |
1209 // send stored msgs | |
1210 this.otr.sendStored() | |
1211 }, | |
1212 | |
1213 handleAKE: function (msg) { | |
1214 var send, vsm, type | |
1215 var version = msg.version | |
1216 | |
1217 switch (msg.type) { | |
1218 | |
1219 case '\x02': | |
1220 HLP.debug.call(this.otr, 'd-h key message') | |
1221 | |
1222 msg = HLP.splitype(['DATA', 'DATA'], msg.msg) | |
1223 | |
1224 if (this.otr.authstate === CONST.AUTHSTATE_AWAITING_DHKEY) { | |
1225 var ourHash = HLP.readMPI(this.myhashed) | |
1226 var theirHash = HLP.readMPI(msg[1]) | |
1227 if (BigInt.greater(ourHash, theirHash)) { | |
1228 type = '\x02' | |
1229 send = this.dhcommit | |
1230 break // ignore | |
1231 } else { | |
1232 // forget | |
1233 this.our_dh = this.otr.dh() | |
1234 this.otr.authstate = CONST.AUTHSTATE_NONE | |
1235 this.r = null | |
1236 this.myhashed = null | |
1237 } | |
1238 } else if ( | |
1239 this.otr.authstate === CONST.AUTHSTATE_AWAITING_SIG | |
1240 ) this.our_dh = this.otr.dh() | |
1241 | |
1242 this.otr.authstate = CONST.AUTHSTATE_AWAITING_REVEALSIG | |
1243 | |
1244 this.encrypted = msg[0].substring(4) | |
1245 this.hashed = msg[1].substring(4) | |
1246 | |
1247 type = '\x0a' | |
1248 send = HLP.packMPI(this.our_dh.publicKey) | |
1249 break | |
1250 | |
1251 case '\x0a': | |
1252 HLP.debug.call(this.otr, 'reveal signature message') | |
1253 | |
1254 msg = HLP.splitype(['MPI'], msg.msg) | |
1255 | |
1256 if (this.otr.authstate !== CONST.AUTHSTATE_AWAITING_DHKEY) { | |
1257 if (this.otr.authstate === CONST.AUTHSTATE_AWAITING_SIG) { | |
1258 if (!BigInt.equals(this.their_y, HLP.readMPI(msg[0]))) return | |
1259 } else { | |
1260 return // ignore | |
1261 } | |
1262 } | |
1263 | |
1264 this.otr.authstate = CONST.AUTHSTATE_AWAITING_SIG | |
1265 | |
1266 this.their_y = HLP.readMPI(msg[0]) | |
1267 | |
1268 // verify gy is legal 2 <= gy <= N-2 | |
1269 if (!HLP.checkGroup(this.their_y, N_MINUS_2)) | |
1270 return this.otr.error('Illegal g^y.', true) | |
1271 | |
1272 this.createKeys(this.their_y) | |
1273 | |
1274 type = '\x11' | |
1275 send = HLP.packMPI(this.r) | |
1276 send += this.makeM(this.their_y, this.m1, this.c, this.m2) | |
1277 | |
1278 this.m1 = null | |
1279 this.m2 = null | |
1280 this.c = null | |
1281 break | |
1282 | |
1283 case '\x11': | |
1284 HLP.debug.call(this.otr, 'signature message') | |
1285 | |
1286 if (this.otr.authstate !== CONST.AUTHSTATE_AWAITING_REVEALSIG) | |
1287 return // ignore | |
1288 | |
1289 msg = HLP.splitype(['DATA', 'DATA', 'MAC'], msg.msg) | |
1290 | |
1291 this.r = HLP.readMPI(msg[0]) | |
1292 | |
1293 // decrypt their_y | |
1294 var key = CryptoJS.enc.Hex.parse(BigInt.bigInt2str(this.r, 16)) | |
1295 key = CryptoJS.enc.Latin1.stringify(key) | |
1296 | |
1297 var gxmpi = HLP.decryptAes(this.encrypted, key, HLP.packCtr(0)) | |
1298 gxmpi = gxmpi.toString(CryptoJS.enc.Latin1) | |
1299 | |
1300 this.their_y = HLP.readMPI(gxmpi) | |
1301 | |
1302 // verify hash | |
1303 var hash = CryptoJS.SHA256(CryptoJS.enc.Latin1.parse(gxmpi)) | |
1304 | |
1305 if (!HLP.compare(this.hashed, hash.toString(CryptoJS.enc.Latin1))) | |
1306 return this.otr.error('Hashed g^x does not match.', true) | |
1307 | |
1308 // verify gx is legal 2 <= g^x <= N-2 | |
1309 if (!HLP.checkGroup(this.their_y, N_MINUS_2)) | |
1310 return this.otr.error('Illegal g^x.', true) | |
1311 | |
1312 this.createKeys(this.their_y) | |
1313 | |
1314 vsm = this.verifySignMac( | |
1315 msg[2] | |
1316 , msg[1] | |
1317 , this.m2 | |
1318 , this.c | |
1319 , this.their_y | |
1320 , this.our_dh.publicKey | |
1321 , this.m1 | |
1322 , HLP.packCtr(0) | |
1323 ) | |
1324 if (vsm[0]) return this.otr.error(vsm[0], true) | |
1325 | |
1326 // store their key | |
1327 this.their_keyid = vsm[1] | |
1328 this.their_priv_pk = vsm[2] | |
1329 | |
1330 send = this.makeM( | |
1331 this.their_y | |
1332 , this.m1_prime | |
1333 , this.c_prime | |
1334 , this.m2_prime | |
1335 ) | |
1336 | |
1337 this.m1 = null | |
1338 this.m2 = null | |
1339 this.m1_prime = null | |
1340 this.m2_prime = null | |
1341 this.c = null | |
1342 this.c_prime = null | |
1343 | |
1344 this.sendMsg(version, '\x12', send) | |
1345 this.akeSuccess(version) | |
1346 return | |
1347 | |
1348 case '\x12': | |
1349 HLP.debug.call(this.otr, 'data message') | |
1350 | |
1351 if (this.otr.authstate !== CONST.AUTHSTATE_AWAITING_SIG) | |
1352 return // ignore | |
1353 | |
1354 msg = HLP.splitype(['DATA', 'MAC'], msg.msg) | |
1355 | |
1356 vsm = this.verifySignMac( | |
1357 msg[1] | |
1358 , msg[0] | |
1359 , this.m2_prime | |
1360 , this.c_prime | |
1361 , this.their_y | |
1362 , this.our_dh.publicKey | |
1363 , this.m1_prime | |
1364 , HLP.packCtr(0) | |
1365 ) | |
1366 if (vsm[0]) return this.otr.error(vsm[0], true) | |
1367 | |
1368 // store their key | |
1369 this.their_keyid = vsm[1] | |
1370 this.their_priv_pk = vsm[2] | |
1371 | |
1372 this.m1_prime = null | |
1373 this.m2_prime = null | |
1374 this.c_prime = null | |
1375 | |
1376 this.transmittedRS = true | |
1377 this.akeSuccess(version) | |
1378 return | |
1379 | |
1380 default: | |
1381 return // ignore | |
1382 | |
1383 } | |
1384 | |
1385 this.sendMsg(version, type, send) | |
1386 }, | |
1387 | |
1388 sendMsg: function (version, type, msg) { | |
1389 var send = version + type | |
1390 var v3 = (version === CONST.OTR_VERSION_3) | |
1391 | |
1392 // instance tags for v3 | |
1393 if (v3) { | |
1394 HLP.debug.call(this.otr, 'instance tags') | |
1395 send += this.otr.our_instance_tag | |
1396 send += this.otr.their_instance_tag | |
1397 } | |
1398 | |
1399 send += msg | |
1400 | |
1401 // fragment message if necessary | |
1402 send = HLP.wrapMsg( | |
1403 send | |
1404 , this.otr.fragment_size | |
1405 , v3 | |
1406 , this.otr.our_instance_tag | |
1407 , this.otr.their_instance_tag | |
1408 ) | |
1409 if (send[0]) return this.otr.error(send[0]) | |
1410 | |
1411 this.otr.io(send[1]) | |
1412 }, | |
1413 | |
1414 initiateAKE: function (version) { | |
1415 HLP.debug.call(this.otr, 'd-h commit message') | |
1416 | |
1417 this.otr.trigger('status', [CONST.STATUS_AKE_INIT]) | |
1418 | |
1419 this.otr.authstate = CONST.AUTHSTATE_AWAITING_DHKEY | |
1420 | |
1421 var gxmpi = HLP.packMPI(this.our_dh.publicKey) | |
1422 gxmpi = CryptoJS.enc.Latin1.parse(gxmpi) | |
1423 | |
1424 this.r = BigInt.randBigInt(128) | |
1425 var key = CryptoJS.enc.Hex.parse(BigInt.bigInt2str(this.r, 16)) | |
1426 key = CryptoJS.enc.Latin1.stringify(key) | |
1427 | |
1428 this.myhashed = CryptoJS.SHA256(gxmpi) | |
1429 this.myhashed = HLP.packData(this.myhashed.toString(CryptoJS.enc.Latin1)) | |
1430 | |
1431 this.dhcommit = HLP.packData(HLP.encryptAes(gxmpi, key, HLP.packCtr(0))) | |
1432 this.dhcommit += this.myhashed | |
1433 | |
1434 this.sendMsg(version, '\x02', this.dhcommit) | |
1435 } | |
1436 | |
1437 } | |
1438 | |
1439 }).call(this) | |
1440 ;(function () { | |
1441 "use strict"; | |
1442 | |
1443 var root = this | |
1444 | |
1445 var CryptoJS, BigInt, EventEmitter, CONST, HLP | |
1446 if (typeof module !== 'undefined' && module.exports) { | |
1447 module.exports = SM | |
1448 CryptoJS = require('../vendor/crypto.js') | |
1449 BigInt = require('../vendor/bigint.js') | |
1450 EventEmitter = require('../vendor/eventemitter.js') | |
1451 CONST = require('./const.js') | |
1452 HLP = require('./helpers.js') | |
1453 } else { | |
1454 root.OTR.SM = SM | |
1455 CryptoJS = root.CryptoJS | |
1456 BigInt = root.BigInt | |
1457 EventEmitter = root.EventEmitter | |
1458 CONST = root.OTR.CONST | |
1459 HLP = root.OTR.HLP | |
1460 } | |
1461 | |
1462 // diffie-hellman modulus and generator | |
1463 // see group 5, RFC 3526 | |
1464 var G = BigInt.str2bigInt(CONST.G, 10) | |
1465 var N = BigInt.str2bigInt(CONST.N, 16) | |
1466 var N_MINUS_2 = BigInt.sub(N, BigInt.str2bigInt('2', 10)) | |
1467 | |
1468 // to calculate D's for zero-knowledge proofs | |
1469 var Q = BigInt.sub(N, BigInt.str2bigInt('1', 10)) | |
1470 BigInt.divInt_(Q, 2) // meh | |
1471 | |
1472 function SM(reqs) { | |
1473 if (!(this instanceof SM)) return new SM(reqs) | |
1474 | |
1475 this.version = 1 | |
1476 | |
1477 this.our_fp = reqs.our_fp | |
1478 this.their_fp = reqs.their_fp | |
1479 this.ssid = reqs.ssid | |
1480 | |
1481 this.debug = !!reqs.debug | |
1482 | |
1483 // initial state | |
1484 this.init() | |
1485 } | |
1486 | |
1487 // inherit from EE | |
1488 HLP.extend(SM, EventEmitter) | |
1489 | |
1490 // set the initial values | |
1491 // also used when aborting | |
1492 SM.prototype.init = function () { | |
1493 this.smpstate = CONST.SMPSTATE_EXPECT1 | |
1494 this.secret = null | |
1495 } | |
1496 | |
1497 SM.prototype.makeSecret = function (our, secret) { | |
1498 var sha256 = CryptoJS.algo.SHA256.create() | |
1499 sha256.update(CryptoJS.enc.Latin1.parse(HLP.packBytes(this.version, 1))) | |
1500 sha256.update(CryptoJS.enc.Hex.parse(our ? this.our_fp : this.their_fp)) | |
1501 sha256.update(CryptoJS.enc.Hex.parse(our ? this.their_fp : this.our_fp)) | |
1502 sha256.update(CryptoJS.enc.Latin1.parse(this.ssid)) | |
1503 sha256.update(CryptoJS.enc.Latin1.parse(secret)) | |
1504 var hash = sha256.finalize() | |
1505 this.secret = HLP.bits2bigInt(hash.toString(CryptoJS.enc.Latin1)) | |
1506 } | |
1507 | |
1508 SM.prototype.makeG2s = function () { | |
1509 this.a2 = HLP.randomExponent() | |
1510 this.a3 = HLP.randomExponent() | |
1511 this.g2a = BigInt.powMod(G, this.a2, N) | |
1512 this.g3a = BigInt.powMod(G, this.a3, N) | |
1513 if ( !HLP.checkGroup(this.g2a, N_MINUS_2) || | |
1514 !HLP.checkGroup(this.g3a, N_MINUS_2) | |
1515 ) this.makeG2s() | |
1516 } | |
1517 | |
1518 SM.prototype.computeGs = function (g2a, g3a) { | |
1519 this.g2 = BigInt.powMod(g2a, this.a2, N) | |
1520 this.g3 = BigInt.powMod(g3a, this.a3, N) | |
1521 } | |
1522 | |
1523 SM.prototype.computePQ = function (r) { | |
1524 this.p = BigInt.powMod(this.g3, r, N) | |
1525 this.q = HLP.multPowMod(G, r, this.g2, this.secret, N) | |
1526 } | |
1527 | |
1528 SM.prototype.computeR = function () { | |
1529 this.r = BigInt.powMod(this.QoQ, this.a3, N) | |
1530 } | |
1531 | |
1532 SM.prototype.computeRab = function (r) { | |
1533 return BigInt.powMod(r, this.a3, N) | |
1534 } | |
1535 | |
1536 SM.prototype.computeC = function (v, r) { | |
1537 return HLP.smpHash(v, BigInt.powMod(G, r, N)) | |
1538 } | |
1539 | |
1540 SM.prototype.computeD = function (r, a, c) { | |
1541 return BigInt.subMod(r, BigInt.multMod(a, c, Q), Q) | |
1542 } | |
1543 | |
1544 // the bulk of the work | |
1545 SM.prototype.handleSM = function (msg) { | |
1546 var send, r2, r3, r7, t1, t2, t3, t4, rab, tmp2, cR, d7, ms, trust | |
1547 | |
1548 var expectStates = { | |
1549 2: CONST.SMPSTATE_EXPECT1 | |
1550 , 3: CONST.SMPSTATE_EXPECT2 | |
1551 , 4: CONST.SMPSTATE_EXPECT3 | |
1552 , 5: CONST.SMPSTATE_EXPECT4 | |
1553 , 7: CONST.SMPSTATE_EXPECT1 | |
1554 } | |
1555 | |
1556 if (msg.type === 6) { | |
1557 this.init() | |
1558 this.trigger('abort') | |
1559 return | |
1560 } | |
1561 | |
1562 // abort! there was an error | |
1563 if (this.smpstate !== expectStates[msg.type]) | |
1564 return this.abort() | |
1565 | |
1566 switch (this.smpstate) { | |
1567 | |
1568 case CONST.SMPSTATE_EXPECT1: | |
1569 HLP.debug.call(this, 'smp tlv 2') | |
1570 | |
1571 // user specified question | |
1572 var ind, question | |
1573 if (msg.type === 7) { | |
1574 ind = msg.msg.indexOf('\x00') | |
1575 question = msg.msg.substring(0, ind) | |
1576 msg.msg = msg.msg.substring(ind + 1) | |
1577 } | |
1578 | |
1579 // 0:g2a, 1:c2, 2:d2, 3:g3a, 4:c3, 5:d3 | |
1580 ms = HLP.readLen(msg.msg.substr(0, 4)) | |
1581 if (ms !== 6) return this.abort() | |
1582 msg = HLP.unpackMPIs(6, msg.msg.substring(4)) | |
1583 | |
1584 if ( !HLP.checkGroup(msg[0], N_MINUS_2) || | |
1585 !HLP.checkGroup(msg[3], N_MINUS_2) | |
1586 ) return this.abort() | |
1587 | |
1588 // verify znp's | |
1589 if (!HLP.ZKP(1, msg[1], HLP.multPowMod(G, msg[2], msg[0], msg[1], N))) | |
1590 return this.abort() | |
1591 | |
1592 if (!HLP.ZKP(2, msg[4], HLP.multPowMod(G, msg[5], msg[3], msg[4], N))) | |
1593 return this.abort() | |
1594 | |
1595 this.g3ao = msg[3] // save for later | |
1596 | |
1597 this.makeG2s() | |
1598 | |
1599 // zero-knowledge proof that the exponents | |
1600 // associated with g2a & g3a are known | |
1601 r2 = HLP.randomExponent() | |
1602 r3 = HLP.randomExponent() | |
1603 this.c2 = this.computeC(3, r2) | |
1604 this.c3 = this.computeC(4, r3) | |
1605 this.d2 = this.computeD(r2, this.a2, this.c2) | |
1606 this.d3 = this.computeD(r3, this.a3, this.c3) | |
1607 | |
1608 this.computeGs(msg[0], msg[3]) | |
1609 | |
1610 this.smpstate = CONST.SMPSTATE_EXPECT0 | |
1611 | |
1612 // assume utf8 question | |
1613 question = CryptoJS.enc.Latin1 | |
1614 .parse(question) | |
1615 .toString(CryptoJS.enc.Utf8) | |
1616 | |
1617 // invoke question | |
1618 this.trigger('question', [question]) | |
1619 return | |
1620 | |
1621 case CONST.SMPSTATE_EXPECT2: | |
1622 HLP.debug.call(this, 'smp tlv 3') | |
1623 | |
1624 // 0:g2a, 1:c2, 2:d2, 3:g3a, 4:c3, 5:d3, 6:p, 7:q, 8:cP, 9:d5, 10:d6 | |
1625 ms = HLP.readLen(msg.msg.substr(0, 4)) | |
1626 if (ms !== 11) return this.abort() | |
1627 msg = HLP.unpackMPIs(11, msg.msg.substring(4)) | |
1628 | |
1629 if ( !HLP.checkGroup(msg[0], N_MINUS_2) || | |
1630 !HLP.checkGroup(msg[3], N_MINUS_2) || | |
1631 !HLP.checkGroup(msg[6], N_MINUS_2) || | |
1632 !HLP.checkGroup(msg[7], N_MINUS_2) | |
1633 ) return this.abort() | |
1634 | |
1635 // verify znp of c3 / c3 | |
1636 if (!HLP.ZKP(3, msg[1], HLP.multPowMod(G, msg[2], msg[0], msg[1], N))) | |
1637 return this.abort() | |
1638 | |
1639 if (!HLP.ZKP(4, msg[4], HLP.multPowMod(G, msg[5], msg[3], msg[4], N))) | |
1640 return this.abort() | |
1641 | |
1642 this.g3ao = msg[3] // save for later | |
1643 | |
1644 this.computeGs(msg[0], msg[3]) | |
1645 | |
1646 // verify znp of cP | |
1647 t1 = HLP.multPowMod(this.g3, msg[9], msg[6], msg[8], N) | |
1648 t2 = HLP.multPowMod(G, msg[9], this.g2, msg[10], N) | |
1649 t2 = BigInt.multMod(t2, BigInt.powMod(msg[7], msg[8], N), N) | |
1650 | |
1651 if (!HLP.ZKP(5, msg[8], t1, t2)) | |
1652 return this.abort() | |
1653 | |
1654 var r4 = HLP.randomExponent() | |
1655 this.computePQ(r4) | |
1656 | |
1657 // zero-knowledge proof that P & Q | |
1658 // were generated according to the protocol | |
1659 var r5 = HLP.randomExponent() | |
1660 var r6 = HLP.randomExponent() | |
1661 var tmp = HLP.multPowMod(G, r5, this.g2, r6, N) | |
1662 var cP = HLP.smpHash(6, BigInt.powMod(this.g3, r5, N), tmp) | |
1663 var d5 = this.computeD(r5, r4, cP) | |
1664 var d6 = this.computeD(r6, this.secret, cP) | |
1665 | |
1666 // store these | |
1667 this.QoQ = BigInt.divMod(this.q, msg[7], N) | |
1668 this.PoP = BigInt.divMod(this.p, msg[6], N) | |
1669 | |
1670 this.computeR() | |
1671 | |
1672 // zero-knowledge proof that R | |
1673 // was generated according to the protocol | |
1674 r7 = HLP.randomExponent() | |
1675 tmp2 = BigInt.powMod(this.QoQ, r7, N) | |
1676 cR = HLP.smpHash(7, BigInt.powMod(G, r7, N), tmp2) | |
1677 d7 = this.computeD(r7, this.a3, cR) | |
1678 | |
1679 this.smpstate = CONST.SMPSTATE_EXPECT4 | |
1680 | |
1681 send = HLP.packINT(8) + HLP.packMPIs([ | |
1682 this.p | |
1683 , this.q | |
1684 , cP | |
1685 , d5 | |
1686 , d6 | |
1687 , this.r | |
1688 , cR | |
1689 , d7 | |
1690 ]) | |
1691 | |
1692 // TLV | |
1693 send = HLP.packTLV(4, send) | |
1694 break | |
1695 | |
1696 case CONST.SMPSTATE_EXPECT3: | |
1697 HLP.debug.call(this, 'smp tlv 4') | |
1698 | |
1699 // 0:p, 1:q, 2:cP, 3:d5, 4:d6, 5:r, 6:cR, 7:d7 | |
1700 ms = HLP.readLen(msg.msg.substr(0, 4)) | |
1701 if (ms !== 8) return this.abort() | |
1702 msg = HLP.unpackMPIs(8, msg.msg.substring(4)) | |
1703 | |
1704 if ( !HLP.checkGroup(msg[0], N_MINUS_2) || | |
1705 !HLP.checkGroup(msg[1], N_MINUS_2) || | |
1706 !HLP.checkGroup(msg[5], N_MINUS_2) | |
1707 ) return this.abort() | |
1708 | |
1709 // verify znp of cP | |
1710 t1 = HLP.multPowMod(this.g3, msg[3], msg[0], msg[2], N) | |
1711 t2 = HLP.multPowMod(G, msg[3], this.g2, msg[4], N) | |
1712 t2 = BigInt.multMod(t2, BigInt.powMod(msg[1], msg[2], N), N) | |
1713 | |
1714 if (!HLP.ZKP(6, msg[2], t1, t2)) | |
1715 return this.abort() | |
1716 | |
1717 // verify znp of cR | |
1718 t3 = HLP.multPowMod(G, msg[7], this.g3ao, msg[6], N) | |
1719 this.QoQ = BigInt.divMod(msg[1], this.q, N) // save Q over Q | |
1720 t4 = HLP.multPowMod(this.QoQ, msg[7], msg[5], msg[6], N) | |
1721 | |
1722 if (!HLP.ZKP(7, msg[6], t3, t4)) | |
1723 return this.abort() | |
1724 | |
1725 this.computeR() | |
1726 | |
1727 // zero-knowledge proof that R | |
1728 // was generated according to the protocol | |
1729 r7 = HLP.randomExponent() | |
1730 tmp2 = BigInt.powMod(this.QoQ, r7, N) | |
1731 cR = HLP.smpHash(8, BigInt.powMod(G, r7, N), tmp2) | |
1732 d7 = this.computeD(r7, this.a3, cR) | |
1733 | |
1734 send = HLP.packINT(3) + HLP.packMPIs([ this.r, cR, d7 ]) | |
1735 send = HLP.packTLV(5, send) | |
1736 | |
1737 rab = this.computeRab(msg[5]) | |
1738 trust = !!BigInt.equals(rab, BigInt.divMod(msg[0], this.p, N)) | |
1739 | |
1740 this.trigger('trust', [trust, 'answered']) | |
1741 this.init() | |
1742 break | |
1743 | |
1744 case CONST.SMPSTATE_EXPECT4: | |
1745 HLP.debug.call(this, 'smp tlv 5') | |
1746 | |
1747 // 0:r, 1:cR, 2:d7 | |
1748 ms = HLP.readLen(msg.msg.substr(0, 4)) | |
1749 if (ms !== 3) return this.abort() | |
1750 msg = HLP.unpackMPIs(3, msg.msg.substring(4)) | |
1751 | |
1752 if (!HLP.checkGroup(msg[0], N_MINUS_2)) return this.abort() | |
1753 | |
1754 // verify znp of cR | |
1755 t3 = HLP.multPowMod(G, msg[2], this.g3ao, msg[1], N) | |
1756 t4 = HLP.multPowMod(this.QoQ, msg[2], msg[0], msg[1], N) | |
1757 if (!HLP.ZKP(8, msg[1], t3, t4)) | |
1758 return this.abort() | |
1759 | |
1760 rab = this.computeRab(msg[0]) | |
1761 trust = !!BigInt.equals(rab, this.PoP) | |
1762 | |
1763 this.trigger('trust', [trust, 'asked']) | |
1764 this.init() | |
1765 return | |
1766 | |
1767 } | |
1768 | |
1769 this.sendMsg(send) | |
1770 } | |
1771 | |
1772 // send a message | |
1773 SM.prototype.sendMsg = function (send) { | |
1774 this.trigger('send', [this.ssid, '\x00' + send]) | |
1775 } | |
1776 | |
1777 SM.prototype.rcvSecret = function (secret, question) { | |
1778 HLP.debug.call(this, 'receive secret') | |
1779 | |
1780 var fn, our = false | |
1781 if (this.smpstate === CONST.SMPSTATE_EXPECT0) { | |
1782 fn = this.answer | |
1783 } else { | |
1784 fn = this.initiate | |
1785 our = true | |
1786 } | |
1787 | |
1788 this.makeSecret(our, secret) | |
1789 fn.call(this, question) | |
1790 } | |
1791 | |
1792 SM.prototype.answer = function () { | |
1793 HLP.debug.call(this, 'smp answer') | |
1794 | |
1795 var r4 = HLP.randomExponent() | |
1796 this.computePQ(r4) | |
1797 | |
1798 // zero-knowledge proof that P & Q | |
1799 // were generated according to the protocol | |
1800 var r5 = HLP.randomExponent() | |
1801 var r6 = HLP.randomExponent() | |
1802 var tmp = HLP.multPowMod(G, r5, this.g2, r6, N) | |
1803 var cP = HLP.smpHash(5, BigInt.powMod(this.g3, r5, N), tmp) | |
1804 var d5 = this.computeD(r5, r4, cP) | |
1805 var d6 = this.computeD(r6, this.secret, cP) | |
1806 | |
1807 this.smpstate = CONST.SMPSTATE_EXPECT3 | |
1808 | |
1809 var send = HLP.packINT(11) + HLP.packMPIs([ | |
1810 this.g2a | |
1811 , this.c2 | |
1812 , this.d2 | |
1813 , this.g3a | |
1814 , this.c3 | |
1815 , this.d3 | |
1816 , this.p | |
1817 , this.q | |
1818 , cP | |
1819 , d5 | |
1820 , d6 | |
1821 ]) | |
1822 | |
1823 this.sendMsg(HLP.packTLV(3, send)) | |
1824 } | |
1825 | |
1826 SM.prototype.initiate = function (question) { | |
1827 HLP.debug.call(this, 'smp initiate') | |
1828 | |
1829 if (this.smpstate !== CONST.SMPSTATE_EXPECT1) | |
1830 this.abort() // abort + restart | |
1831 | |
1832 this.makeG2s() | |
1833 | |
1834 // zero-knowledge proof that the exponents | |
1835 // associated with g2a & g3a are known | |
1836 var r2 = HLP.randomExponent() | |
1837 var r3 = HLP.randomExponent() | |
1838 this.c2 = this.computeC(1, r2) | |
1839 this.c3 = this.computeC(2, r3) | |
1840 this.d2 = this.computeD(r2, this.a2, this.c2) | |
1841 this.d3 = this.computeD(r3, this.a3, this.c3) | |
1842 | |
1843 // set the next expected state | |
1844 this.smpstate = CONST.SMPSTATE_EXPECT2 | |
1845 | |
1846 var send = '' | |
1847 var type = 2 | |
1848 | |
1849 if (question) { | |
1850 send += question | |
1851 send += '\x00' | |
1852 type = 7 | |
1853 } | |
1854 | |
1855 send += HLP.packINT(6) + HLP.packMPIs([ | |
1856 this.g2a | |
1857 , this.c2 | |
1858 , this.d2 | |
1859 , this.g3a | |
1860 , this.c3 | |
1861 , this.d3 | |
1862 ]) | |
1863 | |
1864 this.sendMsg(HLP.packTLV(type, send)) | |
1865 } | |
1866 | |
1867 SM.prototype.abort = function () { | |
1868 this.init() | |
1869 this.sendMsg(HLP.packTLV(6, '')) | |
1870 this.trigger('abort') | |
1871 } | |
1872 | |
1873 }).call(this) | |
1874 ;(function () { | |
1875 "use strict"; | |
1876 | |
1877 var root = this | |
1878 | |
1879 var CryptoJS, BigInt, EventEmitter, Worker, SMWPath | |
1880 , CONST, HLP, Parse, AKE, SM, DSA | |
1881 if (typeof module !== 'undefined' && module.exports) { | |
1882 module.exports = OTR | |
1883 CryptoJS = require('../vendor/crypto.js') | |
1884 BigInt = require('../vendor/bigint.js') | |
1885 EventEmitter = require('../vendor/eventemitter.js') | |
1886 SMWPath = require('path').join(__dirname, '/sm-webworker.js') | |
1887 CONST = require('./const.js') | |
1888 HLP = require('./helpers.js') | |
1889 Parse = require('./parse.js') | |
1890 AKE = require('./ake.js') | |
1891 SM = require('./sm.js') | |
1892 DSA = require('./dsa.js') | |
1893 // expose CONST for consistency with docs | |
1894 OTR.CONST = CONST | |
1895 } else { | |
1896 // copy over and expose internals | |
1897 Object.keys(root.OTR).forEach(function (k) { | |
1898 OTR[k] = root.OTR[k] | |
1899 }) | |
1900 root.OTR = OTR | |
1901 CryptoJS = root.CryptoJS | |
1902 BigInt = root.BigInt | |
1903 EventEmitter = root.EventEmitter | |
1904 Worker = root.Worker | |
1905 SMWPath = 'sm-webworker.js' | |
1906 CONST = OTR.CONST | |
1907 HLP = OTR.HLP | |
1908 Parse = OTR.Parse | |
1909 AKE = OTR.AKE | |
1910 SM = OTR.SM | |
1911 DSA = root.DSA | |
1912 } | |
1913 | |
1914 // diffie-hellman modulus and generator | |
1915 // see group 5, RFC 3526 | |
1916 var G = BigInt.str2bigInt(CONST.G, 10) | |
1917 var N = BigInt.str2bigInt(CONST.N, 16) | |
1918 | |
1919 // JavaScript integers | |
1920 var MAX_INT = Math.pow(2, 53) - 1 // doubles | |
1921 var MAX_UINT = Math.pow(2, 31) - 1 // bitwise operators | |
1922 | |
1923 // OTR contructor | |
1924 function OTR(options) { | |
1925 if (!(this instanceof OTR)) return new OTR(options) | |
1926 | |
1927 // options | |
1928 options = options || {} | |
1929 | |
1930 // private keys | |
1931 if (options.priv && !(options.priv instanceof DSA)) | |
1932 throw new Error('Requires long-lived DSA key.') | |
1933 | |
1934 this.priv = options.priv ? options.priv : new DSA() | |
1935 | |
1936 this.fragment_size = options.fragment_size || 0 | |
1937 if (this.fragment_size < 0) | |
1938 throw new Error('Fragment size must be a positive integer.') | |
1939 | |
1940 this.send_interval = options.send_interval || 0 | |
1941 if (this.send_interval < 0) | |
1942 throw new Error('Send interval must be a positive integer.') | |
1943 | |
1944 this.outgoing = [] | |
1945 | |
1946 // instance tag | |
1947 this.our_instance_tag = options.instance_tag || OTR.makeInstanceTag() | |
1948 | |
1949 // debug | |
1950 this.debug = !!options.debug | |
1951 | |
1952 // smp in webworker options | |
1953 // this is still experimental and undocumented | |
1954 this.smw = options.smw | |
1955 | |
1956 // init vals | |
1957 this.init() | |
1958 | |
1959 // bind methods | |
1960 var self = this | |
1961 ;['sendMsg', 'receiveMsg'].forEach(function (meth) { | |
1962 self[meth] = self[meth].bind(self) | |
1963 }) | |
1964 | |
1965 EventEmitter.call(this) | |
1966 } | |
1967 | |
1968 // inherit from EE | |
1969 HLP.extend(OTR, EventEmitter) | |
1970 | |
1971 // add to prototype | |
1972 OTR.prototype.init = function () { | |
1973 | |
1974 this.msgstate = CONST.MSGSTATE_PLAINTEXT | |
1975 this.authstate = CONST.AUTHSTATE_NONE | |
1976 | |
1977 this.ALLOW_V2 = true | |
1978 this.ALLOW_V3 = true | |
1979 | |
1980 this.REQUIRE_ENCRYPTION = false | |
1981 this.SEND_WHITESPACE_TAG = false | |
1982 this.WHITESPACE_START_AKE = false | |
1983 this.ERROR_START_AKE = false | |
1984 | |
1985 Parse.initFragment(this) | |
1986 | |
1987 // their keys | |
1988 this.their_y = null | |
1989 this.their_old_y = null | |
1990 this.their_keyid = 0 | |
1991 this.their_priv_pk = null | |
1992 this.their_instance_tag = '\x00\x00\x00\x00' | |
1993 | |
1994 // our keys | |
1995 this.our_dh = this.dh() | |
1996 this.our_old_dh = this.dh() | |
1997 this.our_keyid = 2 | |
1998 | |
1999 // session keys | |
2000 this.sessKeys = [ new Array(2), new Array(2) ] | |
2001 | |
2002 // saved | |
2003 this.storedMgs = [] | |
2004 this.oldMacKeys = [] | |
2005 | |
2006 // smp | |
2007 this.sm = null // initialized after AKE | |
2008 | |
2009 // when ake is complete | |
2010 // save their keys and the session | |
2011 this._akeInit() | |
2012 | |
2013 // receive plaintext message since switching to plaintext | |
2014 // used to decide when to stop sending pt tags when SEND_WHITESPACE_TAG | |
2015 this.receivedPlaintext = false | |
2016 | |
2017 } | |
2018 | |
2019 OTR.prototype._akeInit = function () { | |
2020 this.ake = new AKE(this) | |
2021 this.transmittedRS = false | |
2022 this.ssid = null | |
2023 } | |
2024 | |
2025 // smp over webworker | |
2026 OTR.prototype._SMW = function (otr, reqs) { | |
2027 this.otr = otr | |
2028 var opts = { | |
2029 path: SMWPath | |
2030 , seed: BigInt.getSeed | |
2031 } | |
2032 if (typeof otr.smw === 'object') | |
2033 Object.keys(otr.smw).forEach(function (k) { | |
2034 opts[k] = otr.smw[k] | |
2035 }) | |
2036 | |
2037 // load optional dep. in node | |
2038 if (typeof module !== 'undefined' && module.exports) | |
2039 Worker = require('webworker-threads').Worker | |
2040 | |
2041 this.worker = new Worker(opts.path) | |
2042 var self = this | |
2043 this.worker.onmessage = function (e) { | |
2044 var d = e.data | |
2045 if (!d) return | |
2046 self.trigger(d.method, d.args) | |
2047 } | |
2048 this.worker.postMessage({ | |
2049 type: 'seed' | |
2050 , seed: opts.seed() | |
2051 , imports: opts.imports | |
2052 }) | |
2053 this.worker.postMessage({ | |
2054 type: 'init' | |
2055 , reqs: reqs | |
2056 }) | |
2057 } | |
2058 | |
2059 // inherit from EE | |
2060 HLP.extend(OTR.prototype._SMW, EventEmitter) | |
2061 | |
2062 // shim sm methods | |
2063 ;['handleSM', 'rcvSecret', 'abort'].forEach(function (m) { | |
2064 OTR.prototype._SMW.prototype[m] = function () { | |
2065 this.worker.postMessage({ | |
2066 type: 'method' | |
2067 , method: m | |
2068 , args: Array.prototype.slice.call(arguments, 0) | |
2069 }) | |
2070 } | |
2071 }) | |
2072 | |
2073 OTR.prototype._smInit = function () { | |
2074 var reqs = { | |
2075 ssid: this.ssid | |
2076 , our_fp: this.priv.fingerprint() | |
2077 , their_fp: this.their_priv_pk.fingerprint() | |
2078 , debug: this.debug | |
2079 } | |
2080 if (this.smw) { | |
2081 if (this.sm) this.sm.worker.terminate() // destroy prev webworker | |
2082 this.sm = new this._SMW(this, reqs) | |
2083 } else { | |
2084 this.sm = new SM(reqs) | |
2085 } | |
2086 var self = this | |
2087 ;['trust', 'abort', 'question'].forEach(function (e) { | |
2088 self.sm.on(e, function () { | |
2089 self.trigger('smp', [e].concat(Array.prototype.slice.call(arguments))) | |
2090 }) | |
2091 }) | |
2092 this.sm.on('send', function (ssid, send) { | |
2093 if (self.ssid === ssid) { | |
2094 send = self.prepareMsg(send) | |
2095 self.io(send) | |
2096 } | |
2097 }) | |
2098 } | |
2099 | |
2100 OTR.prototype.io = function (msg, meta) { | |
2101 | |
2102 // buffer | |
2103 msg = ([].concat(msg)).map(function(m){ | |
2104 return { msg: m, meta: meta } | |
2105 }) | |
2106 this.outgoing = this.outgoing.concat(msg) | |
2107 | |
2108 var self = this | |
2109 ;(function send(first) { | |
2110 if (!first) { | |
2111 if (!self.outgoing.length) return | |
2112 var elem = self.outgoing.shift() | |
2113 self.trigger('io', [elem.msg, elem.meta]) | |
2114 } | |
2115 setTimeout(send, first ? 0 : self.send_interval) | |
2116 }(true)) | |
2117 | |
2118 } | |
2119 | |
2120 OTR.prototype.dh = function dh() { | |
2121 var keys = { privateKey: BigInt.randBigInt(320) } | |
2122 keys.publicKey = BigInt.powMod(G, keys.privateKey, N) | |
2123 return keys | |
2124 } | |
2125 | |
2126 // session constructor | |
2127 OTR.prototype.DHSession = function DHSession(our_dh, their_y) { | |
2128 if (!(this instanceof DHSession)) return new DHSession(our_dh, their_y) | |
2129 | |
2130 // shared secret | |
2131 var s = BigInt.powMod(their_y, our_dh.privateKey, N) | |
2132 var secbytes = HLP.packMPI(s) | |
2133 | |
2134 // session id | |
2135 this.id = HLP.mask(HLP.h2('\x00', secbytes), 0, 64) // first 64-bits | |
2136 | |
2137 // are we the high or low end of the connection? | |
2138 var sq = BigInt.greater(our_dh.publicKey, their_y) | |
2139 var sendbyte = sq ? '\x01' : '\x02' | |
2140 var rcvbyte = sq ? '\x02' : '\x01' | |
2141 | |
2142 // sending and receiving keys | |
2143 this.sendenc = HLP.mask(HLP.h1(sendbyte, secbytes), 0, 128) // f16 bytes | |
2144 this.sendmac = CryptoJS.SHA1(CryptoJS.enc.Latin1.parse(this.sendenc)) | |
2145 this.sendmac = this.sendmac.toString(CryptoJS.enc.Latin1) | |
2146 | |
2147 this.rcvenc = HLP.mask(HLP.h1(rcvbyte, secbytes), 0, 128) | |
2148 this.rcvmac = CryptoJS.SHA1(CryptoJS.enc.Latin1.parse(this.rcvenc)) | |
2149 this.rcvmac = this.rcvmac.toString(CryptoJS.enc.Latin1) | |
2150 this.rcvmacused = false | |
2151 | |
2152 // extra symmetric key | |
2153 this.extra_symkey = HLP.h2('\xff', secbytes) | |
2154 | |
2155 // counters | |
2156 this.send_counter = 0 | |
2157 this.rcv_counter = 0 | |
2158 } | |
2159 | |
2160 OTR.prototype.rotateOurKeys = function () { | |
2161 | |
2162 // reveal old mac keys | |
2163 var self = this | |
2164 this.sessKeys[1].forEach(function (sk) { | |
2165 if (sk && sk.rcvmacused) self.oldMacKeys.push(sk.rcvmac) | |
2166 }) | |
2167 | |
2168 // rotate our keys | |
2169 this.our_old_dh = this.our_dh | |
2170 this.our_dh = this.dh() | |
2171 this.our_keyid += 1 | |
2172 | |
2173 this.sessKeys[1][0] = this.sessKeys[0][0] | |
2174 this.sessKeys[1][1] = this.sessKeys[0][1] | |
2175 this.sessKeys[0] = [ | |
2176 this.their_y ? | |
2177 new this.DHSession(this.our_dh, this.their_y) : null | |
2178 , this.their_old_y ? | |
2179 new this.DHSession(this.our_dh, this.their_old_y) : null | |
2180 ] | |
2181 | |
2182 } | |
2183 | |
2184 OTR.prototype.rotateTheirKeys = function (their_y) { | |
2185 | |
2186 // increment their keyid | |
2187 this.their_keyid += 1 | |
2188 | |
2189 // reveal old mac keys | |
2190 var self = this | |
2191 this.sessKeys.forEach(function (sk) { | |
2192 if (sk[1] && sk[1].rcvmacused) self.oldMacKeys.push(sk[1].rcvmac) | |
2193 }) | |
2194 | |
2195 // rotate their keys / session | |
2196 this.their_old_y = this.their_y | |
2197 this.sessKeys[0][1] = this.sessKeys[0][0] | |
2198 this.sessKeys[1][1] = this.sessKeys[1][0] | |
2199 | |
2200 // new keys / sessions | |
2201 this.their_y = their_y | |
2202 this.sessKeys[0][0] = new this.DHSession(this.our_dh, this.their_y) | |
2203 this.sessKeys[1][0] = new this.DHSession(this.our_old_dh, this.their_y) | |
2204 | |
2205 } | |
2206 | |
2207 OTR.prototype.prepareMsg = function (msg, esk) { | |
2208 if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED || this.their_keyid === 0) | |
2209 return this.error('Not ready to encrypt.') | |
2210 | |
2211 var sessKeys = this.sessKeys[1][0] | |
2212 | |
2213 if (sessKeys.send_counter >= MAX_INT) | |
2214 return this.error('Should have rekeyed by now.') | |
2215 | |
2216 sessKeys.send_counter += 1 | |
2217 | |
2218 var ctr = HLP.packCtr(sessKeys.send_counter) | |
2219 | |
2220 var send = this.ake.otr_version + '\x03' // version and type | |
2221 var v3 = (this.ake.otr_version === CONST.OTR_VERSION_3) | |
2222 | |
2223 if (v3) { | |
2224 send += this.our_instance_tag | |
2225 send += this.their_instance_tag | |
2226 } | |
2227 | |
2228 send += '\x00' // flag | |
2229 send += HLP.packINT(this.our_keyid - 1) | |
2230 send += HLP.packINT(this.their_keyid) | |
2231 send += HLP.packMPI(this.our_dh.publicKey) | |
2232 send += ctr.substring(0, 8) | |
2233 | |
2234 if (Math.ceil(msg.length / 8) >= MAX_UINT) // * 16 / 128 | |
2235 return this.error('Message is too long.') | |
2236 | |
2237 var aes = HLP.encryptAes( | |
2238 CryptoJS.enc.Latin1.parse(msg) | |
2239 , sessKeys.sendenc | |
2240 , ctr | |
2241 ) | |
2242 | |
2243 send += HLP.packData(aes) | |
2244 send += HLP.make1Mac(send, sessKeys.sendmac) | |
2245 send += HLP.packData(this.oldMacKeys.splice(0).join('')) | |
2246 | |
2247 send = HLP.wrapMsg( | |
2248 send | |
2249 , this.fragment_size | |
2250 , v3 | |
2251 , this.our_instance_tag | |
2252 , this.their_instance_tag | |
2253 ) | |
2254 if (send[0]) return this.error(send[0]) | |
2255 | |
2256 // emit extra symmetric key | |
2257 if (esk) this.trigger('file', ['send', sessKeys.extra_symkey, esk]) | |
2258 | |
2259 return send[1] | |
2260 } | |
2261 | |
2262 OTR.prototype.handleDataMsg = function (msg) { | |
2263 var vt = msg.version + msg.type | |
2264 | |
2265 if (this.ake.otr_version === CONST.OTR_VERSION_3) | |
2266 vt += msg.instance_tags | |
2267 | |
2268 var types = ['BYTE', 'INT', 'INT', 'MPI', 'CTR', 'DATA', 'MAC', 'DATA'] | |
2269 msg = HLP.splitype(types, msg.msg) | |
2270 | |
2271 // ignore flag | |
2272 var ign = (msg[0] === '\x01') | |
2273 | |
2274 if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED || msg.length !== 8) { | |
2275 if (!ign) this.error('Received an unreadable encrypted message.', true) | |
2276 return | |
2277 } | |
2278 | |
2279 var our_keyid = this.our_keyid - HLP.readLen(msg[2]) | |
2280 var their_keyid = this.their_keyid - HLP.readLen(msg[1]) | |
2281 | |
2282 if (our_keyid < 0 || our_keyid > 1) { | |
2283 if (!ign) this.error('Not of our latest keys.', true) | |
2284 return | |
2285 } | |
2286 | |
2287 if (their_keyid < 0 || their_keyid > 1) { | |
2288 if (!ign) this.error('Not of your latest keys.', true) | |
2289 return | |
2290 } | |
2291 | |
2292 var their_y = their_keyid ? this.their_old_y : this.their_y | |
2293 | |
2294 if (their_keyid === 1 && !their_y) { | |
2295 if (!ign) this.error('Do not have that key.') | |
2296 return | |
2297 } | |
2298 | |
2299 var sessKeys = this.sessKeys[our_keyid][their_keyid] | |
2300 | |
2301 var ctr = HLP.unpackCtr(msg[4]) | |
2302 if (ctr <= sessKeys.rcv_counter) { | |
2303 if (!ign) this.error('Counter in message is not larger.') | |
2304 return | |
2305 } | |
2306 sessKeys.rcv_counter = ctr | |
2307 | |
2308 // verify mac | |
2309 vt += msg.slice(0, 6).join('') | |
2310 var vmac = HLP.make1Mac(vt, sessKeys.rcvmac) | |
2311 | |
2312 if (!HLP.compare(msg[6], vmac)) { | |
2313 if (!ign) this.error('MACs do not match.') | |
2314 return | |
2315 } | |
2316 sessKeys.rcvmacused = true | |
2317 | |
2318 var out = HLP.decryptAes( | |
2319 msg[5].substring(4) | |
2320 , sessKeys.rcvenc | |
2321 , HLP.padCtr(msg[4]) | |
2322 ) | |
2323 out = out.toString(CryptoJS.enc.Latin1) | |
2324 | |
2325 if (!our_keyid) this.rotateOurKeys() | |
2326 if (!their_keyid) this.rotateTheirKeys(HLP.readMPI(msg[3])) | |
2327 | |
2328 // parse TLVs | |
2329 var ind = out.indexOf('\x00') | |
2330 if (~ind) { | |
2331 this.handleTLVs(out.substring(ind + 1), sessKeys) | |
2332 out = out.substring(0, ind) | |
2333 } | |
2334 | |
2335 out = CryptoJS.enc.Latin1.parse(out) | |
2336 return out.toString(CryptoJS.enc.Utf8) | |
2337 } | |
2338 | |
2339 OTR.prototype.handleTLVs = function (tlvs, sessKeys) { | |
2340 var type, len, msg | |
2341 for (; tlvs.length; ) { | |
2342 type = HLP.unpackSHORT(tlvs.substr(0, 2)) | |
2343 len = HLP.unpackSHORT(tlvs.substr(2, 2)) | |
2344 | |
2345 msg = tlvs.substr(4, len) | |
2346 | |
2347 // TODO: handle pathological cases better | |
2348 if (msg.length < len) break | |
2349 | |
2350 switch (type) { | |
2351 case 1: | |
2352 // Disconnected | |
2353 this.msgstate = CONST.MSGSTATE_FINISHED | |
2354 this.trigger('status', [CONST.STATUS_END_OTR]) | |
2355 break | |
2356 case 2: case 3: case 4: | |
2357 case 5: case 6: case 7: | |
2358 // SMP | |
2359 if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED) { | |
2360 if (this.sm) this.sm.abort() | |
2361 return | |
2362 } | |
2363 if (!this.sm) this._smInit() | |
2364 this.sm.handleSM({ msg: msg, type: type }) | |
2365 break | |
2366 case 8: | |
2367 // utf8 filenames | |
2368 msg = msg.substring(4) // remove 4-byte indication | |
2369 msg = CryptoJS.enc.Latin1.parse(msg) | |
2370 msg = msg.toString(CryptoJS.enc.Utf8) | |
2371 | |
2372 // Extra Symkey | |
2373 this.trigger('file', ['receive', sessKeys.extra_symkey, msg]) | |
2374 break | |
2375 } | |
2376 | |
2377 tlvs = tlvs.substring(4 + len) | |
2378 } | |
2379 } | |
2380 | |
2381 OTR.prototype.smpSecret = function (secret, question) { | |
2382 if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED) | |
2383 return this.error('Must be encrypted for SMP.') | |
2384 | |
2385 if (typeof secret !== 'string' || secret.length < 1) | |
2386 return this.error('Secret is required.') | |
2387 | |
2388 if (!this.sm) this._smInit() | |
2389 | |
2390 // utf8 inputs | |
2391 secret = CryptoJS.enc.Utf8.parse(secret).toString(CryptoJS.enc.Latin1) | |
2392 question = CryptoJS.enc.Utf8.parse(question).toString(CryptoJS.enc.Latin1) | |
2393 | |
2394 this.sm.rcvSecret(secret, question) | |
2395 } | |
2396 | |
2397 OTR.prototype.sendQueryMsg = function () { | |
2398 var versions = {} | |
2399 , msg = CONST.OTR_TAG | |
2400 | |
2401 if (this.ALLOW_V2) versions['2'] = true | |
2402 if (this.ALLOW_V3) versions['3'] = true | |
2403 | |
2404 // but we don't allow v1 | |
2405 // if (versions['1']) msg += '?' | |
2406 | |
2407 var vs = Object.keys(versions) | |
2408 if (vs.length) { | |
2409 msg += 'v' | |
2410 vs.forEach(function (v) { | |
2411 if (v !== '1') msg += v | |
2412 }) | |
2413 msg += '?' | |
2414 } | |
2415 | |
2416 this.io(msg) | |
2417 this.trigger('status', [CONST.STATUS_SEND_QUERY]) | |
2418 } | |
2419 | |
2420 OTR.prototype.sendMsg = function (msg, meta) { | |
2421 if ( this.REQUIRE_ENCRYPTION || | |
2422 this.msgstate !== CONST.MSGSTATE_PLAINTEXT | |
2423 ) { | |
2424 msg = CryptoJS.enc.Utf8.parse(msg) | |
2425 msg = msg.toString(CryptoJS.enc.Latin1) | |
2426 } | |
2427 | |
2428 switch (this.msgstate) { | |
2429 case CONST.MSGSTATE_PLAINTEXT: | |
2430 if (this.REQUIRE_ENCRYPTION) { | |
2431 this.storedMgs.push({msg: msg, meta: meta}) | |
2432 this.sendQueryMsg() | |
2433 return | |
2434 } | |
2435 if (this.SEND_WHITESPACE_TAG && !this.receivedPlaintext) { | |
2436 msg += CONST.WHITESPACE_TAG // 16 byte tag | |
2437 if (this.ALLOW_V3) msg += CONST.WHITESPACE_TAG_V3 | |
2438 if (this.ALLOW_V2) msg += CONST.WHITESPACE_TAG_V2 | |
2439 } | |
2440 break | |
2441 case CONST.MSGSTATE_FINISHED: | |
2442 this.storedMgs.push({msg: msg, meta: meta}) | |
2443 this.error('Message cannot be sent at this time.') | |
2444 return | |
2445 case CONST.MSGSTATE_ENCRYPTED: | |
2446 msg = this.prepareMsg(msg) | |
2447 break | |
2448 default: | |
2449 throw new Error('Unknown message state.') | |
2450 } | |
2451 | |
2452 if (msg) this.io(msg, meta) | |
2453 } | |
2454 | |
2455 OTR.prototype.receiveMsg = function (msg) { | |
2456 | |
2457 // parse type | |
2458 msg = Parse.parseMsg(this, msg) | |
2459 | |
2460 if (!msg) return | |
2461 | |
2462 switch (msg.cls) { | |
2463 case 'error': | |
2464 this.error(msg.msg) | |
2465 return | |
2466 case 'ake': | |
2467 if ( msg.version === CONST.OTR_VERSION_3 && | |
2468 this.checkInstanceTags(msg.instance_tags) | |
2469 ) return // ignore | |
2470 this.ake.handleAKE(msg) | |
2471 return | |
2472 case 'data': | |
2473 if ( msg.version === CONST.OTR_VERSION_3 && | |
2474 this.checkInstanceTags(msg.instance_tags) | |
2475 ) return // ignore | |
2476 msg.msg = this.handleDataMsg(msg) | |
2477 msg.encrypted = true | |
2478 break | |
2479 case 'query': | |
2480 if (this.msgstate === CONST.MSGSTATE_ENCRYPTED) this._akeInit() | |
2481 this.doAKE(msg) | |
2482 break | |
2483 default: | |
2484 // check for encrypted | |
2485 if ( this.REQUIRE_ENCRYPTION || | |
2486 this.msgstate !== CONST.MSGSTATE_PLAINTEXT | |
2487 ) this.error('Received an unencrypted message.') | |
2488 | |
2489 // received a plaintext message | |
2490 // stop sending the whitespace tag | |
2491 this.receivedPlaintext = true | |
2492 | |
2493 // received a whitespace tag | |
2494 if (this.WHITESPACE_START_AKE && msg.ver.length > 0) | |
2495 this.doAKE(msg) | |
2496 } | |
2497 | |
2498 if (msg.msg) this.trigger('ui', [msg.msg, !!msg.encrypted]) | |
2499 } | |
2500 | |
2501 OTR.prototype.checkInstanceTags = function (it) { | |
2502 var their_it = HLP.readLen(it.substr(0, 4)) | |
2503 var our_it = HLP.readLen(it.substr(4, 4)) | |
2504 | |
2505 if (our_it && our_it !== HLP.readLen(this.our_instance_tag)) | |
2506 return true | |
2507 | |
2508 if (HLP.readLen(this.their_instance_tag)) { | |
2509 if (HLP.readLen(this.their_instance_tag) !== their_it) return true | |
2510 } else { | |
2511 if (their_it < 100) return true | |
2512 this.their_instance_tag = HLP.packINT(their_it) | |
2513 } | |
2514 } | |
2515 | |
2516 OTR.prototype.doAKE = function (msg) { | |
2517 if (this.ALLOW_V3 && ~msg.ver.indexOf(CONST.OTR_VERSION_3)) { | |
2518 this.ake.initiateAKE(CONST.OTR_VERSION_3) | |
2519 } else if (this.ALLOW_V2 && ~msg.ver.indexOf(CONST.OTR_VERSION_2)) { | |
2520 this.ake.initiateAKE(CONST.OTR_VERSION_2) | |
2521 } else { | |
2522 // is this an error? | |
2523 this.error('OTR conversation requested, ' + | |
2524 'but no compatible protocol version found.') | |
2525 } | |
2526 } | |
2527 | |
2528 OTR.prototype.error = function (err, send) { | |
2529 if (send) { | |
2530 if (!this.debug) err = "An OTR error has occurred." | |
2531 err = '?OTR Error:' + err | |
2532 this.io(err) | |
2533 return | |
2534 } | |
2535 this.trigger('error', [err]) | |
2536 } | |
2537 | |
2538 OTR.prototype.sendStored = function () { | |
2539 var self = this | |
2540 ;(this.storedMgs.splice(0)).forEach(function (elem) { | |
2541 var msg = self.prepareMsg(elem.msg) | |
2542 self.io(msg, elem.meta) | |
2543 }) | |
2544 } | |
2545 | |
2546 OTR.prototype.sendFile = function (filename) { | |
2547 if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED) | |
2548 return this.error('Not ready to encrypt.') | |
2549 | |
2550 if (this.ake.otr_version !== CONST.OTR_VERSION_3) | |
2551 return this.error('Protocol v3 required.') | |
2552 | |
2553 if (!filename) return this.error('Please specify a filename.') | |
2554 | |
2555 // utf8 filenames | |
2556 var l1name = CryptoJS.enc.Utf8.parse(filename) | |
2557 l1name = l1name.toString(CryptoJS.enc.Latin1) | |
2558 | |
2559 if (l1name.length >= 65532) return this.error('filename is too long.') | |
2560 | |
2561 var msg = '\x00' // null byte | |
2562 msg += '\x00\x08' // type 8 tlv | |
2563 msg += HLP.packSHORT(4 + l1name.length) // length of value | |
2564 msg += '\x00\x00\x00\x01' // four bytes indicating file | |
2565 msg += l1name | |
2566 | |
2567 msg = this.prepareMsg(msg, filename) | |
2568 this.io(msg) | |
2569 } | |
2570 | |
2571 OTR.prototype.endOtr = function () { | |
2572 if (this.msgstate === CONST.MSGSTATE_ENCRYPTED) { | |
2573 this.sendMsg('\x00\x00\x01\x00\x00') | |
2574 if (this.sm) { | |
2575 if (this.smw) this.sm.worker.terminate() // destroy webworker | |
2576 this.sm = null | |
2577 } | |
2578 } | |
2579 this.msgstate = CONST.MSGSTATE_PLAINTEXT | |
2580 this.receivedPlaintext = false | |
2581 this.trigger('status', [CONST.STATUS_END_OTR]) | |
2582 } | |
2583 | |
2584 // attach methods | |
2585 | |
2586 OTR.makeInstanceTag = function () { | |
2587 var num = BigInt.randBigInt(32) | |
2588 if (BigInt.greater(BigInt.str2bigInt('100', 16), num)) | |
2589 return OTR.makeInstanceTag() | |
2590 return HLP.packINT(parseInt(BigInt.bigInt2str(num, 10), 10)) | |
2591 } | |
2592 | |
2593 }).call(this) | |
2594 | |
2595 | |
2596 return { | |
2597 OTR: this.OTR | |
2598 , DSA: this.DSA | |
2599 } | |
2600 | |
2601 })) |