ForumScriptz

Mega Crypto.js

Jan 19th, 2013
655
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. window.URL = window.URL || window.webkiURL;
  2. var have_ab = typeof ArrayBuffer != 'undefined' && typeof DataView != 'undefined';
  3. var use_workers = have_ab && typeof Worker != 'undefined';
  4.  
  5. if ((navigator.appVersion.indexOf('Safari') > 0) && (navigator.appVersion.indexOf('Version/5') > 0))
  6. {
  7.     use_workers=false;
  8.     have_ab=false;
  9. }
  10.  
  11. var ssl_off = [ 'Firefox/14', 'Firefox/15', 'Firefox/17', 'Safari', 'Firefox/16' ];
  12. var ssl_opt = [ 'Chrome/' ];
  13.  
  14. function ssl_needed()
  15. {
  16.     for (var i = ssl_opt.length; i--; ) if (navigator.userAgent.indexOf(ssl_opt[i]) >= 0) return 0;
  17.     for (var i = ssl_off.length; i--; ) if (navigator.userAgent.indexOf(ssl_off[i]) >= 0) return -1;
  18.     return 1;
  19. }
  20.  
  21. var use_ssl = ssl_needed();
  22. if (!use_ssl && localStorage.use_ssl) use_ssl = 1;
  23. else use_ssl++;
  24.  
  25. var chromehack = navigator.appVersion.indexOf('Chrome/');
  26. chromehack = chromehack >= 0 && parseInt(navigator.appVersion.substr(chromehack+7)) > 21;
  27.  
  28. // keyboard/mouse entropy
  29. eventsCollect();
  30.  
  31. var EINTERNAL = -1;
  32. var EARGS = -2;
  33. var EAGAIN = -3;
  34. var ERATELIMIT = -4;
  35. var EFAILED = -5;
  36. var ETOOMANY = -6;  // too many IP addresses
  37. var ERANGE = -7;    // file packet out of range
  38. var EEXPIRED = -8;
  39.  
  40. // FS access errors
  41. var ENOENT = -9;
  42. var ECIRCULAR = -10;
  43. var EACCESS = -11;
  44. var EEXIST = -12;
  45. var EINCOMPLETE = -13;
  46.  
  47. // crypto errors
  48. var EKEY = -14;
  49.  
  50. // user errors
  51. var ESID = -15;
  52. var EBLOCKED = -16;
  53. var EOVERQUOTA = -17;
  54. var ETEMPUNAVAIL = -18;
  55. var ETOOMANYCONNECTIONS = -19;
  56.  
  57. function benchmark()
  58. {
  59.     var a = Array(1048577).join('a');
  60.    
  61.     var ab = str_to_ab(a);
  62.    
  63.     var ab8 = new Uint8Array(ab);
  64.    
  65.     var aes = new sjcl.cipher.aes([0,1,2,3]);
  66.    
  67.     t = new Date().getTime();
  68.     for (var i = 16; i--; ) encrypt_ab_ctr(aes,ab8,[1,2],30000);
  69.     t = new Date().getTime()-t;
  70.    
  71.     console.log((a.length*16/1024)/(t/1000) + " KB/s");
  72. }
  73.  
  74. var seqno = rand(0x100000000);
  75.  
  76. // compute final MAC from block MACs
  77. function condenseMacs(macs,key)
  78. {
  79.     var i, aes;
  80.     mac = [0,0,0,0];
  81.  
  82.     aes = new sjcl.cipher.aes([key[0],key[1],key[2],key[3]]);
  83.    
  84.     for (i = 0; i < macs.length; i++)
  85.     {
  86.         mac[0] ^= macs[i][0];
  87.         mac[1] ^= macs[i][1];
  88.         mac[2] ^= macs[i][2];
  89.         mac[3] ^= macs[i][3];
  90.  
  91.         mac = aes.encrypt(mac);
  92.     }
  93.    
  94.     return mac;
  95. }
  96.  
  97. // convert user-supplied password array
  98. function prepare_key(a)
  99. {
  100.     var i, j, r;
  101.     var pkey = [0x93C467E3,0x7DB0C7A4,0xD1BE3F81,0x0152CB56];
  102.  
  103.     for (r = 65536; r--; )
  104.     {
  105.         for (j = 0; j < a.length; j += 4)
  106.         {
  107.             key = [0,0,0,0];
  108.            
  109.             for (i = 0; i < 4; i++) if (i+j < a.length) key[i] = a[i+j];
  110.  
  111.             aes = new sjcl.cipher.aes(key);
  112.             pkey = aes.encrypt(pkey);
  113.         }
  114.     }
  115.  
  116.     return pkey;
  117. }
  118.  
  119. // prepare_key with string input
  120. function prepare_key_pw(password)
  121. {
  122.     return prepare_key(str_to_a32(password));
  123. }
  124.  
  125. var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_=";
  126. var b64a = b64.split('');
  127.  
  128. // unsubstitute standard base64 special characters, restore padding
  129. function base64urldecode(data)
  130. {
  131.     data += '=='.substr((2-data.length*3)&3)
  132.  
  133.     if (typeof atob === 'function')
  134.     {
  135.         data = data.replace(/\-/g,'+').replace(/_/g,'/').replace(/,/g,'');
  136.        
  137.         try {
  138.             return atob(data);
  139.         } catch (e) {
  140.             return '';
  141.         }
  142.     }
  143.  
  144.   // http://kevin.vanzonneveld.net
  145.   // +   original by: Tyler Akins (http://rumkin.com)
  146.   // +   improved by: Thunder.m
  147.   // +      input by: Aman Gupta
  148.   // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  149.   // +   bugfixed by: Onno Marsman
  150.   // +   bugfixed by: Pellentesque Malesuada
  151.   // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  152.   // +      input by: Brett Zamir (http://brett-zamir.me)
  153.   // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  154.   // *     example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
  155.   // *     returns 1: 'Kevin van Zonneveld'
  156.   // mozilla has this native
  157.   // - but breaks in 2.0.0.12!
  158.   //if (typeof this.window['atob'] == 'function') {
  159.   //    return atob(data);
  160.   //}
  161.   var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
  162.     ac = 0,
  163.     dec = "",
  164.     tmp_arr = [];
  165.  
  166.   if (!data) {
  167.     return data;
  168.   }
  169.  
  170.   data += '';
  171.  
  172.   do { // unpack four hexets into three octets using index points in b64
  173.     h1 = b64.indexOf(data.charAt(i++));
  174.     h2 = b64.indexOf(data.charAt(i++));
  175.     h3 = b64.indexOf(data.charAt(i++));
  176.     h4 = b64.indexOf(data.charAt(i++));
  177.  
  178.     bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
  179.  
  180.     o1 = bits >> 16 & 0xff;
  181.     o2 = bits >> 8 & 0xff;
  182.     o3 = bits & 0xff;
  183.  
  184.     if (h3 == 64) {
  185.       tmp_arr[ac++] = String.fromCharCode(o1);
  186.     } else if (h4 == 64) {
  187.       tmp_arr[ac++] = String.fromCharCode(o1, o2);
  188.     } else {
  189.       tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
  190.     }
  191.   } while (i < data.length);
  192.  
  193.   dec = tmp_arr.join('');
  194.  
  195.   return dec;
  196. }
  197.  
  198. // substitute standard base64 special characters to prevent JSON escaping, remove padding
  199. function base64urlencode(data)
  200. {
  201.     if (typeof btoa === 'function') return btoa(data).replace(/\+/g,'-').replace(/\//g,'_').replace(/=/g,'');
  202.  
  203.     var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
  204.     ac = 0,
  205.     enc = "",
  206.     tmp_arr = [];
  207.  
  208.     do { // pack three octets into four hexets
  209.         o1 = data.charCodeAt(i++);
  210.         o2 = data.charCodeAt(i++);
  211.         o3 = data.charCodeAt(i++);
  212.  
  213.         bits = o1 << 16 | o2 << 8 | o3;
  214.  
  215.         h1 = bits >> 18 & 0x3f;
  216.         h2 = bits >> 12 & 0x3f;
  217.         h3 = bits >> 6 & 0x3f;
  218.         h4 = bits & 0x3f;
  219.  
  220.         // use hexets to index into b64, and append result to encoded string
  221.         tmp_arr[ac++] = b64a[h1] + b64a[h2] + b64a[h3] + b64a[h4];
  222.     } while (i < data.length);
  223.  
  224.     enc = tmp_arr.join('');
  225.     var r = data.length % 3;
  226.     return (r ? enc.slice(0, r - 3) : enc);
  227. }
  228.  
  229. // array of 32-bit words to string (big endian)
  230. function a32_to_str(a)
  231. {
  232.     var b = '';
  233.  
  234.     for (var i = 0; i < a.length*4; i++)
  235.         b = b+String.fromCharCode((a[i>>2] >>> (24-(i & 3)*8)) & 255);
  236.  
  237.     return b;
  238. }
  239.  
  240. function a32_to_base64(a)
  241. {
  242.     return base64urlencode(a32_to_str(a));
  243. }
  244.  
  245. // string to array of 32-bit words (big endian)
  246. function str_to_a32(b)
  247. {
  248.     var a = Array((b.length+3) >> 2);
  249.  
  250.     for (var i = 0; i < b.length; i++) a[i>>2] |= (b.charCodeAt(i) << (24-(i & 3)*8));
  251.  
  252.     return a;
  253. }
  254.  
  255. function base64_to_a32(s)
  256. {
  257.     return str_to_a32(base64urldecode(s));
  258. }
  259.  
  260. // ArrayBuffer to binary string
  261. function ab_to_str(ab)
  262. {
  263.     var b = '', i;
  264.    
  265.     if (have_ab)
  266.     {
  267.         var b = '';
  268.  
  269.         var ab8 = new Uint8Array(ab);
  270.  
  271.         for (i = 0; i < ab8.length; i++) b = b+String.fromCharCode(ab8[i]);
  272.     }
  273.     else
  274.     {
  275.         return ab.buffer;
  276.     }
  277.  
  278.     return b;
  279. }
  280.  
  281. // ArrayBuffer to binary string
  282. function ab_to_base64(ab)
  283. {
  284.     return base64urlencode(ab_to_str(ab));
  285. }
  286.  
  287. // ArrayBuffer to binary with depadding
  288. function ab_to_str_depad(ab)
  289. {
  290.     var b, i;
  291.  
  292.     if (have_ab)
  293.     {
  294.         b = '';
  295.  
  296.         var ab8 = new Uint8Array(ab);
  297.  
  298.         for (i = 0; i < ab8.length && ab8[i]; i++) b = b+String.fromCharCode(ab8[i]);
  299.     }
  300.     else
  301.     {
  302.         b = ab_to_str(ab);
  303.        
  304.         for (i = b.length; i-- && !b.charCodeAt(i); );
  305.        
  306.         b = b.substr(0,i+1);
  307.     }
  308.  
  309.     return b;
  310. }
  311.  
  312. // binary string to ArrayBuffer, 0-padded to AES block size
  313. function str_to_ab(b)
  314. {
  315.     var ab, i;
  316.    
  317.     if (have_ab)
  318.     {
  319.         ab = new ArrayBuffer((b.length+15)&-16);
  320.         var ab8 = new Uint8Array(ab);
  321.  
  322.         for (i = b.length; i--; ) ab8[i] = b.charCodeAt(i);
  323.  
  324.         return ab;
  325.     }
  326.     else
  327.     {
  328.         b += Array(16-((b.length-1)&15)).join(String.fromCharCode(0));
  329.  
  330.         ab = { buffer : b };
  331.     }
  332.  
  333.     return ab;
  334. }
  335.  
  336. // binary string to ArrayBuffer, 0-padded to AES block size
  337. function base64_to_ab(a)
  338. {
  339.     return str_to_ab(base64urldecode(a));
  340. }
  341.  
  342. // encrypt ArrayBuffer in CTR mode, return MAC
  343. function encrypt_ab_ctr(aes,ab,nonce,pos)
  344. {
  345.     var ctr = [nonce[0],nonce[1],(pos/0x1000000000) >>> 0,(pos/0x10) >>> 0];
  346.     var mac = [ctr[0],ctr[1],ctr[0],ctr[1]];
  347.  
  348.     var enc, i, j, len, v;
  349.    
  350.     if (have_ab)
  351.     {
  352.         var data0, data1, data2, data3;
  353.  
  354.         len = ab.buffer.byteLength-16;
  355.  
  356.         var v = new DataView(ab.buffer);
  357.        
  358.         for (i = 0; i < len; i += 16)
  359.         {
  360.             data0 = v.getUint32(i,false);
  361.             data1 = v.getUint32(i+4,false);
  362.             data2 = v.getUint32(i+8,false);
  363.             data3 = v.getUint32(i+12,false);
  364.  
  365.             // compute MAC
  366.             mac[0] ^= data0;
  367.             mac[1] ^= data1;
  368.             mac[2] ^= data2;
  369.             mac[3] ^= data3;
  370.             mac = aes.encrypt(mac);
  371.  
  372.             // encrypt using CTR
  373.             enc = aes.encrypt(ctr);
  374.             v.setUint32(i,data0 ^ enc[0],false);
  375.             v.setUint32(i+4,data1 ^ enc[1],false);
  376.             v.setUint32(i+8,data2 ^ enc[2],false);
  377.             v.setUint32(i+12,data3 ^ enc[3],false);
  378.  
  379.             if (!(++ctr[3])) ctr[2]++;
  380.         }
  381.  
  382.         if (i < ab.buffer.byteLength)
  383.         {
  384.             var fullbuf = new Uint8Array(ab.buffer);
  385.             var tmpbuf = new ArrayBuffer(16);
  386.             var tmparray = new Uint8Array(tmpbuf);
  387.  
  388.             tmparray.set(fullbuf.subarray(i));
  389.  
  390.             v = new DataView(tmpbuf);
  391.  
  392.             enc = aes.encrypt(ctr);
  393.  
  394.             data0 = v.getUint32(0,false);
  395.             data1 = v.getUint32(4,false);
  396.             data2 = v.getUint32(8,false);
  397.             data3 = v.getUint32(12,false);
  398.  
  399.             mac[0] ^= data0;
  400.             mac[1] ^= data1;
  401.             mac[2] ^= data2;
  402.             mac[3] ^= data3;
  403.             mac = aes.encrypt(mac);
  404.  
  405.             enc = aes.encrypt(ctr);
  406.             v.setUint32(0,data0 ^ enc[0],false);
  407.             v.setUint32(4,data1 ^ enc[1],false);
  408.             v.setUint32(8,data2 ^ enc[2],false);
  409.             v.setUint32(12,data3 ^ enc[3],false);
  410.  
  411.             fullbuf.set(tmparray.subarray(0,j = fullbuf.length-i),i);
  412.         }
  413.     }
  414.     else
  415.     {
  416.         var ab32 = _str_to_a32(ab.buffer);
  417.  
  418.         len = ab32.length-3;
  419.  
  420.         for (i = 0; i < len; i += 4)
  421.         {
  422.             mac[0] ^= ab32[i];
  423.             mac[1] ^= ab32[i+1];
  424.             mac[2] ^= ab32[i+2];
  425.             mac[3] ^= ab32[i+3];
  426.             mac = aes.encrypt(mac);
  427.            
  428.             enc = aes.encrypt(ctr);
  429.             ab32[i] ^= enc[0];
  430.             ab32[i+1] ^= enc[1];
  431.             ab32[i+2] ^= enc[2];
  432.             ab32[i+3] ^= enc[3];
  433.  
  434.             if (!(++ctr[3])) ctr[2]++;
  435.         }
  436.  
  437.         if (i < ab32.length)
  438.         {
  439.             var v = [0,0,0,0];
  440.            
  441.             for (j = i; j < ab32.length; j++) v[j-i] = ab32[j];
  442.  
  443.             mac[0] ^= v[0];
  444.             mac[1] ^= v[1];
  445.             mac[2] ^= v[2];
  446.             mac[3] ^= v[3];
  447.             mac = aes.encrypt(mac);
  448.  
  449.             enc = aes.encrypt(ctr);
  450.             v[0] ^= enc[0];
  451.             v[1] ^= enc[1];
  452.             v[2] ^= enc[2];
  453.             v[3] ^= enc[3];
  454.            
  455.             for (j = i; j < ab32.length; j++) ab32[j] = v[j-i];
  456.         }
  457.        
  458.         ab.buffer = _a32_to_str(ab32,ab.buffer.length);
  459.     }
  460.  
  461.     return mac;
  462. }
  463.  
  464. function _str_to_a32(b)
  465. {
  466.     var a = Array((b.length+3) >> 2);
  467.  
  468.     if (typeof b == 'string')
  469.     {
  470.         for (var i = 0; i < b.length; i++)
  471.             a[i>>2] |= (b.charCodeAt(i) & 255) << (24-(i & 3)*8);
  472.     }
  473.     else
  474.     {
  475.         for (var i = 0; i < b.length; i++)
  476.             a[i>>2] |= b[i] << ((i & 3)*8);
  477.     }
  478.  
  479.     return a;
  480. }
  481.  
  482. function _a32_to_str(a,len)
  483. {
  484.     var b = '';
  485.  
  486.     for (var i = 0; i < len; i++)
  487.         b = b+String.fromCharCode((a[i>>2] >>> (24-(i & 3)*8)) & 255);
  488.  
  489.     return b;
  490. }
  491.  
  492. // decrypt ArrayBuffer in CTR mode, return MAC
  493. function decrypt_ab_ctr(aes,ab,nonce,pos)
  494. {
  495.     var ctr = [nonce[0],nonce[1],(pos/0x1000000000) >>> 0,(pos/0x10) >>> 0];
  496.     var mac = [ctr[0],ctr[1],ctr[0],ctr[1]];
  497.    
  498.     var enc, len, i, j, v;
  499.  
  500.     if (have_ab)
  501.     {
  502.         var data0, data1, data2, data3;
  503.  
  504.         len = ab.buffer.byteLength-16;  // @@@ -15?
  505.  
  506.         var v = new DataView(ab.buffer);
  507.        
  508.         for (i = 0; i < len; i += 16)
  509.         {
  510.             enc = aes.encrypt(ctr);
  511.  
  512.             data0 = v.getUint32(i,false)^enc[0];
  513.             data1 = v.getUint32(i+4,false)^enc[1];
  514.             data2 = v.getUint32(i+8,false)^enc[2];
  515.             data3 = v.getUint32(i+12,false)^enc[3];
  516.  
  517.             v.setUint32(i,data0,false);
  518.             v.setUint32(i+4,data1,false);
  519.             v.setUint32(i+8,data2,false);
  520.             v.setUint32(i+12,data3,false);
  521.  
  522.             mac[0] ^= data0;
  523.             mac[1] ^= data1;
  524.             mac[2] ^= data2;
  525.             mac[3] ^= data3;
  526.  
  527.             mac = aes.encrypt(mac);
  528.  
  529.             if (!(++ctr[3])) ctr[2]++;
  530.         }
  531.  
  532.         if (i < ab.buffer.byteLength)
  533.         {
  534.             var fullbuf = new Uint8Array(ab.buffer);
  535.             var tmpbuf = new ArrayBuffer(16);
  536.             var tmparray = new Uint8Array(tmpbuf);
  537.  
  538.             tmparray.set(fullbuf.subarray(i));
  539.  
  540.             v = new DataView(tmpbuf);
  541.  
  542.             enc = aes.encrypt(ctr);
  543.             data0 = v.getUint32(0,false)^enc[0];
  544.             data1 = v.getUint32(4,false)^enc[1];
  545.             data2 = v.getUint32(8,false)^enc[2];
  546.             data3 = v.getUint32(12,false)^enc[3];
  547.  
  548.             v.setUint32(0,data0,false);
  549.             v.setUint32(4,data1,false);
  550.             v.setUint32(8,data2,false);
  551.             v.setUint32(12,data3,false);
  552.  
  553.             fullbuf.set(tmparray.subarray(0,j = fullbuf.length-i),i);
  554.  
  555.             while (j < 16) tmparray[j++] = 0;
  556.  
  557.             mac[0] ^= v.getUint32(0,false);
  558.             mac[1] ^= v.getUint32(4,false);
  559.             mac[2] ^= v.getUint32(8,false);
  560.             mac[3] ^= v.getUint32(12,false);
  561.             mac = aes.encrypt(mac);
  562.         }
  563.     }
  564.     else
  565.     {
  566.         var ab32 = _str_to_a32(ab.buffer);     
  567.         len = ab32.length-3;
  568.  
  569.         for (i = 0; i < len; i += 4)
  570.         {
  571.             enc = aes.encrypt(ctr);
  572.             mac[0] ^= (ab32[i] ^= enc[0]);
  573.             mac[1] ^= (ab32[i+1] ^= enc[1]);
  574.             mac[2] ^= (ab32[i+2] ^= enc[2]);
  575.             mac[3] ^= (ab32[i+3] ^= enc[3]);
  576.             mac = aes.encrypt(mac);
  577.  
  578.             if (!(++ctr[3])) ctr[2]++;
  579.         }
  580.  
  581.         if (i < ab32.length)
  582.         {
  583.             var v = [0,0,0,0];
  584.            
  585.             for (j = i; j < ab32.length; j++) v[j-i] = ab32[j];
  586.  
  587.             enc = aes.encrypt(ctr);
  588.             v[0] ^= enc[0];
  589.             v[1] ^= enc[1];
  590.             v[2] ^= enc[2];
  591.             v[3] ^= enc[3];
  592.  
  593.             var j = ab.buffer.length & 15;
  594.            
  595.             var m = _str_to_a32(Array(j+1).join(String.fromCharCode(255))+Array(17-j).join(String.fromCharCode(0)));
  596.  
  597.             mac[0] ^= v[0] & m[0];
  598.             mac[1] ^= v[1] & m[1];
  599.             mac[2] ^= v[2] & m[2];
  600.             mac[3] ^= v[3] & m[3];
  601.             mac = aes.encrypt(mac);
  602.            
  603.             for (j = i; j < ab32.length; j++) ab32[j] = v[j-i];
  604.         }
  605.  
  606.         ab.buffer = _a32_to_str(ab32,ab.buffer.length);
  607.     }
  608.  
  609.     return mac;
  610. }
  611.  
  612. // encrypt ArrayBuffer in CBC mode (zero IV)
  613. function encrypt_ab_cbc(cipher,ab)
  614. {
  615.     if (have_ab)
  616.     {
  617.         var v = new DataView(ab);
  618.         var iv = [0,0,0,0], d = Array(4);
  619.         var i;
  620.        
  621.         for (i = 0; i < ab.byteLength; i += 16)
  622.         {
  623.             d[0] = v.getUint32(i,false) ^ iv[0];
  624.             d[1] = v.getUint32(i+4,false) ^ iv[1];
  625.             d[2] = v.getUint32(i+8,false) ^ iv[2];
  626.             d[3] = v.getUint32(i+12,false) ^ iv[3];
  627.        
  628.             iv = cipher.encrypt(d);
  629.            
  630.             v.setUint32(i,iv[0],false);
  631.             v.setUint32(i+4,iv[1],false);
  632.             v.setUint32(i+8,iv[2],false);
  633.             v.setUint32(i+12,iv[3],false);
  634.         }
  635.     }
  636.     else
  637.     {
  638.         var ab32 = str_to_a32(ab.buffer);
  639.         var iv = [0,0,0,0], d = Array(4);
  640.         var i;
  641.        
  642.         for (i = 0; i < ab32.length; i += 4)
  643.         {
  644.             d[0] = ab32[i] ^ iv[0];
  645.             d[1] = ab32[i+1] ^ iv[1];
  646.             d[2] = ab32[i+2] ^ iv[2];
  647.             d[3] = ab32[i+3] ^ iv[3];
  648.        
  649.             iv = cipher.encrypt(d);
  650.            
  651.             ab32[i] = iv[0];
  652.             ab32[i+1] = iv[1];
  653.             ab32[i+2] = iv[2];
  654.             ab32[i+3] = iv[3];
  655.         }
  656.        
  657.         ab.buffer = a32_to_str(ab32);
  658.     }
  659. }
  660.  
  661. // decrypt ArrayBuffer in CBC mode (zero IV)
  662. function decrypt_ab_cbc(cipher,ab)
  663. {
  664.     if (have_ab)
  665.     {
  666.         var v = new DataView(ab);
  667.         var iv = [0,0,0,0], d = Array(4), t = Array(4);
  668.         var i;
  669.        
  670.         for (i = 0; i < ab.byteLength; i += 16)
  671.         {
  672.             d[0] = v.getUint32(i,false);
  673.             d[1] = v.getUint32(i+4,false);
  674.             d[2] = v.getUint32(i+8,false);
  675.             d[3] = v.getUint32(i+12,false);
  676.             t = d;
  677.        
  678.             d = cipher.decrypt(d);
  679.            
  680.             v.setUint32(i,d[0] ^ iv[0],false);
  681.             v.setUint32(i+4,d[1] ^ iv[1],false);
  682.             v.setUint32(i+8,d[2] ^ iv[2],false);
  683.             v.setUint32(i+12,d[3] ^ iv[3],false);
  684.             iv = t;
  685.         }
  686.     }
  687.     else
  688.     {
  689.         var ab32 = str_to_a32(ab.buffer);
  690.         var iv = [0,0,0,0], d = Array(4), t = Array(4);
  691.         var i;
  692.        
  693.         for (i = 0; i < ab32.length; i += 4)
  694.         {
  695.             d[0] = ab32[i];
  696.             d[1] = ab32[i+1];
  697.             d[2] = ab32[i+2];
  698.             d[3] = ab32[i+3];
  699.             t = d;
  700.        
  701.             d = cipher.decrypt(d);
  702.            
  703.             ab32[i] = d[0] ^ iv[0];
  704.             ab32[i+1] = d[1] ^ iv[1];
  705.             ab32[i+2] = d[2] ^ iv[2];
  706.             ab32[i+3] = d[3] ^ iv[3];
  707.             iv = t;
  708.         }
  709.  
  710.         ab.buffer = a32_to_str(ab32);
  711.     }
  712. }
  713.  
  714. // encrypt/decrypt 4- or 8-element 32-bit integer array
  715. function encrypt_key(cipher,a)
  716. {
  717.     if (a.length == 4) return cipher.encrypt(a);
  718.  
  719.     var x = [];
  720.     for (var i = 0; i < a.length; i += 4) x = x.concat(cipher.encrypt([a[i],a[i+1],a[i+2],a[i+3]]));
  721.     return x;
  722. }
  723.  
  724. function decrypt_key(cipher,a)
  725. {
  726.     if (a.length == 4) return cipher.decrypt(a);
  727.  
  728.     var x = [];
  729.     for (var i = 0; i < a.length; i += 4) x = x.concat(cipher.decrypt([a[i],a[i+1],a[i+2],a[i+3]]));
  730.     return x;
  731. }
  732.  
  733. // generate attributes block using AES-CBC with MEGA canary
  734. // attr = Object, key = [] (four-word random key will be generated) or Array(8) (lower four words will be used)
  735. // returns [ArrayBuffer data,Array key]
  736. function enc_attr(attr,key)
  737. {
  738.     var aes;
  739.     var ab;
  740.     var b;
  741.  
  742.     ab = str_to_ab('MEGA'+to8(JSON.stringify(attr)));
  743.  
  744.     // if no key supplied, generate a random one
  745.     if (!key.length) for (i = 4; i--; ) key[i] = rand(0x100000000);
  746.  
  747.     aes = new sjcl.cipher.aes([key[0]^key[4],key[1]^key[5],key[2]^key[6],key[3]^key[7]]);
  748.  
  749.     encrypt_ab_cbc(aes,ab);
  750.  
  751.     return [ab,key];
  752. }
  753.  
  754. // decrypt attributes block using AES-CBC, check for MEGA canary
  755. // attr = ab, key as with enc_attr
  756. // returns [Object] or false
  757. function dec_attr(attr,key)
  758. {
  759.     var aes;
  760.     var b;
  761.    
  762.     aes = new sjcl.cipher.aes([key[0]^key[4],key[1]^key[5],key[2]^key[6],key[3]^key[7]]);
  763.     decrypt_ab_cbc(aes,attr);
  764.  
  765.     b = ab_to_str_depad(attr);
  766.  
  767.     if (b.substr(0,6) != 'MEGA{"') return false;
  768.  
  769.     // @@@ protect against syntax errors
  770.     try {
  771.         return JSON.parse(from8(b.substr(4)));
  772.     } catch (e) {
  773.         return { n : 'MALFORMED_ATTRIBUTES' };
  774.     }
  775. }
  776.  
  777. function to8(unicode)
  778. {
  779.     return unescape(encodeURIComponent(unicode));
  780. }
  781.  
  782. function from8(utf8)
  783. {
  784.     return decodeURIComponent(escape(utf8));
  785. }
  786.  
  787. function getxhr()
  788. {
  789.     return (typeof XDomainRequest != 'undefined' && typeof ArrayBuffer == 'undefined') ? new XDomainRequest() : new XMLHttpRequest();
  790. }
  791.  
  792. // API command queueing
  793. // All commands are executed in sequence, with no overlap
  794. // @@@ user warning after backoff > 1000
  795.  
  796. var apiq = new Array;
  797. var apiqtimer = false;
  798. var apixhr = getxhr();
  799.  
  800. function api_req(req,params)
  801. {
  802.     apiq.push([typeof req == 'string' ? req : to8(JSON.stringify(req)),params,seqno++,0]);
  803.  
  804.     if (apiq.length == 1) api_proc();
  805. }
  806.  
  807. // execute first pending event
  808. function api_proc()
  809. {
  810.     if (apiqtimer)
  811.     {
  812.         // delete timer (should not ever happen)
  813.         clearTimeout(apiqtimer);
  814.         apiqtimer = false;
  815.     }
  816.  
  817.     if (apixhr.readyState && apixhr.readyState != apixhr.DONE)
  818.     {
  819.         // wait for apixhr to get ready
  820.         if (d) console.log("XHR not in DONE state: " + apixhr.readyState);
  821.         apiqtimer = setTimeout(api_proc,1000);
  822.         return;
  823.     }
  824.  
  825.     // no more commands pending?
  826.     if (!apiq.length) return;
  827.    
  828.     // request ready for (re)execution: execute
  829.     apixhr = getxhr();
  830.    
  831.  
  832.     apixhr.onerror = function(oEvent)
  833.     {
  834.         if (d) console.log("API request error - retrying");
  835.         api_result(-3);
  836.     }
  837.  
  838.     apixhr.onload = function(oEvent)
  839.     {      
  840.         var t;
  841.        
  842.         if (this.responseText) this.response = this.responseText;
  843.    
  844.         if (d) console.log('API response: ' + this.response);
  845.        
  846.         try {
  847.             t = JSON.parse(from8(this.response));
  848.         } catch (e) {
  849.             // bogus response, requeue
  850.             console.log("Bad JSON data in response: " + this.response);
  851.             t = -3;
  852.         }
  853.  
  854.         api_result(t);
  855.     }
  856.  
  857.     if (d) console.log("Making API request: " + apiq[0][0]);
  858.     apixhr.open('POST', (apiq[0][0].substr(0,4) == 'https') ? apiq[0][0] : ('https://eu.api.mega.co.nz/' + (apiq[0][0].substr(0,1) == '[' ? ('cs?id=' + apiq[0][2]) : apiq[0][0]) + (u_sid ? ('&sid=' + u_sid) : '')), true);
  859.     apixhr.send(apiq[0][0]);
  860. }
  861.  
  862. function api_result(res)
  863. {
  864.     if (res === -3)
  865.     {
  866.         // exponential backoff
  867.         if (apiq[0][3]) apiq[0][3] *= 2;
  868.         else apiq[0][3] = 125;
  869.        
  870.         if (d) console.log('Temporary error (' + res + ') - retrying after: ' + (apiq[0][3]/1000));
  871.  
  872.         apiqtimer = setTimeout(api_proc,apiq[0][3]);
  873.     }
  874.     else
  875.     {
  876.         if (apiq[0][1]) apiq[0][1].callback(res,apiq[0][1]);
  877.         apiq.shift();
  878.         api_proc();
  879.     }
  880. }
  881.  
  882. // calls execsc() with server-client requests received
  883. function getsc()
  884. {
  885.     ctx = {
  886.         callback : function(res,ctx)
  887.         {
  888.             if (res.w)
  889.             {
  890.                 waiturl = res.w;
  891.  
  892.                 if (waitbackoff > 1000) setTimeout(waitsc,waitbackoff);
  893.                 else waitsc();
  894.             }
  895.             else
  896.             {
  897.                 if (res.sn) maxaction = res.sn;
  898.                 execsc(res.a);
  899.             }
  900.         }
  901.     };
  902.  
  903.     api_req('sc?sn=' + maxaction + '&ssl=1',ctx);
  904. }
  905.  
  906. var waiturl;
  907. var waitxhr = getxhr();
  908. var waitbackoff = 125;
  909. var waitbegin;
  910.  
  911. function waitsc()
  912. {
  913.     if (waitxhr.readyState != apixhr.DONE) waitxhr = undefined;
  914.  
  915.     if (!waitxhr) waitxhr = getxhr();
  916.  
  917.     waitxhr.onerror = function(oEvent)
  918.     {
  919.         if (d) console.log("Error while waiting - retrying, backoff: " + waitbackoff);
  920.         getsc();
  921.     }
  922.  
  923.     waitxhr.onload = function(oEvent)
  924.     {
  925.         var t = new Date().getTime()-waitbegin;
  926.  
  927.         if (t < 1000) waitbackoff += waitbackoff;
  928.         else waitbackoff = 125;
  929.  
  930.         getsc();
  931.     }
  932.  
  933.     waitbegin = new Date().getTime();
  934.     waitxhr.open('POST',waiturl,true);
  935.     waitxhr.send();
  936. }
  937.  
  938. function api_create_u_k()
  939. {
  940.     u_k = Array(4); // static master key, will be stored at the server side encrypted with the master pw
  941.  
  942.     for (var i = 4; i--; ) u_k[i] = rand(0x100000000);
  943. }
  944.  
  945. // If the user triggers an action that requires an account, but hasn't logged in,
  946. // we create an anonymous preliminary account. Returns userhandle and passwordkey for permanent storage.
  947. function api_createuser(ctx,invitecode,invitename,uh)
  948. {
  949.     var i;
  950.     var ssc = Array(4);         // session self challenge, will be used to verify password
  951.     var req, res;
  952.  
  953.     if (!ctx.passwordkey)
  954.     {
  955.         ctx.passwordkey = Array(4);
  956.         for (i = 4; i--; ) ctx.passwordkey[i] = rand(0x100000000);
  957.     }
  958.  
  959.     if (!u_k) api_create_u_k();
  960.  
  961.     for (i = 4; i--; ) ssc[i] = rand(0x100000000);
  962.    
  963.     if (d) console.log("api_createuser - masterkey: " + u_k + " passwordkey: " + ctx.passwordkey);
  964.  
  965.     req = { a : 'up',
  966.             k : a32_to_base64(encrypt_key(new sjcl.cipher.aes(ctx.passwordkey),u_k)),
  967.             ts : base64urlencode(a32_to_str(ssc) + a32_to_str(encrypt_key(new sjcl.cipher.aes(u_k),ssc))) };
  968.  
  969.     if (invitecode)
  970.     {
  971.         req.uh = uh;
  972.         req.ic = invitecode;
  973.         req.name = invitename;
  974.     }
  975.  
  976.     //if (confirmcode) req.c = confirmcode;
  977.     if (d) console.log("Storing key: " + req.k);
  978.  
  979.     api_req([req],ctx);
  980. }
  981.  
  982. function api_checkconfirmcode(ctx,c)
  983. {
  984.     res = api_req([{ a : 'uc', c : c }],ctx);
  985. }
  986.  
  987. // We query the sid using the supplied user handle (or entered email address, if already attached)
  988. // and check the supplied password key.
  989. // Returns [decrypted master key,verified session ID(,RSA private key)] or false if API error or
  990. // supplied information incorrect
  991. function api_getsid(ctx,user,passwordkey,hash)
  992. {
  993.     ctx.callback = api_getsid2;
  994.     ctx.passwordkey = passwordkey;
  995.    
  996.     api_req([{ a : 'us', user : user, uh : hash }],ctx);
  997. }
  998.  
  999. function api_getsid2(res,ctx)
  1000. {
  1001.     console.log(new Date().getTime());
  1002.    
  1003.     var t, k;
  1004.     var r = false;
  1005.  
  1006.     if (typeof res == 'object')
  1007.     {
  1008.         var aes = new sjcl.cipher.aes(ctx.passwordkey);
  1009.        
  1010.         // decrypt master key
  1011.         if (typeof res[0].k == 'string')
  1012.         {
  1013.             k = base64_to_a32(res[0].k);
  1014.  
  1015.             if (k.length == 4)
  1016.             {
  1017.                 k = decrypt_key(aes,k);
  1018.  
  1019.                 aes = new sjcl.cipher.aes(k);
  1020.                
  1021.                 if (typeof res[0].tsid == 'string')
  1022.                 {
  1023.                     t = base64urldecode(res[0].tsid);
  1024.                     if (a32_to_str(encrypt_key(aes,str_to_a32(t.substr(0,16)))) == t.substr(-16)) r = [k,res[0].tsid];
  1025.                 }
  1026.                 else if (typeof res[0].csid == 'string')
  1027.                 {
  1028.                     var t = mpi2b(base64urldecode(res[0].csid));
  1029.  
  1030.                     var privk = a32_to_str(decrypt_key(aes,base64_to_a32(res[0].privk)));
  1031.  
  1032.                     var rsa_privk = Array(4);
  1033.                    
  1034.                     // decompose private key
  1035.                     for (var i = 0; i < 4; i++)
  1036.                     {
  1037.                         var l = ((privk.charCodeAt(0)*256+privk.charCodeAt(1)+7)>>3)+2;
  1038.  
  1039.                         rsa_privk[i] = mpi2b(privk.substr(0,l));
  1040.                         if (typeof rsa_privk[i] == 'number') break;
  1041.                         privk = privk.substr(l);
  1042.                     }
  1043.  
  1044.                     // check format
  1045.                     if (i == 4 && privk.length < 16)
  1046.                     {
  1047.                         // @@@ check remaining padding for added early wrong password detection likelihood
  1048.                         r = [k,base64urlencode(b2s(RSAdecrypt(t,rsa_privk[2],rsa_privk[0],rsa_privk[1],rsa_privk[3])).substr(0,43)),rsa_privk];
  1049.                     }
  1050.                 }
  1051.             }
  1052.         }
  1053.     }
  1054.    
  1055.     console.log(new Date().getTime());
  1056.  
  1057.     ctx.result(ctx,r);
  1058. }
  1059.  
  1060. // We call ug using the sid from setsid() and the user's master password to obtain the master key (and other credentials)
  1061. // Returns user credentials (.k being the decrypted master key) or false in case of an error.
  1062. function api_getuser(ctx)
  1063. {
  1064.     api_req([{ a : 'ug' }],ctx);
  1065. }
  1066.  
  1067. // User must be logged in, sid and passwordkey must be valid
  1068. // return values:
  1069. // 2 - old & new passwords are the same post-preparation
  1070. // 1 - old password incorrect
  1071. // userhandle - success
  1072. // false - processing error
  1073. // other negative values - API error
  1074. function api_changepw(ctx,passwordkey,masterkey,oldpw,newpw,email)
  1075. {
  1076.     var req, res;
  1077.     var oldkey;
  1078.  
  1079.     var newkey = prepare_key_pw(newpw);
  1080.  
  1081.     if (oldpw !== false)
  1082.     {
  1083.         var oldkey = prepare_key_pw(oldpw);
  1084.        
  1085.         // quick check of old pw
  1086.         if (oldkey[0] != passwordkey[0]
  1087.         || oldkey[1] != passwordkey[1]
  1088.         || oldkey[2] != passwordkey[2]
  1089.         || oldkey[3] != passwordkey[3]) return 1;
  1090.  
  1091.         if (oldkey[0] == newkey[0]
  1092.         && oldkey[1] == newkey[1]
  1093.         && oldkey[2] == newkey[2]
  1094.         && oldkey[3] == newkey[3]) return 2;
  1095.     }
  1096.  
  1097.     var aes = new sjcl.cipher.aes(newkey);
  1098.    
  1099.     // encrypt masterkey with the new password
  1100.     var cmasterkey = encrypt_key(aes,masterkey);
  1101.    
  1102.     req = { a : 'up',
  1103.         k : a32_to_base64(cmasterkey) };
  1104.  
  1105.     if (email.length) req.email = email;
  1106.  
  1107.     api_req([req],ctx);
  1108. }
  1109.  
  1110. function stringhash(s,aes)
  1111. {
  1112.     var s32 = str_to_a32(s);
  1113.     var h32 = [0,0,0,0];
  1114.    
  1115.     for (i = 0; i < s32.length; i++) h32[i&3] ^= s32[i];
  1116.    
  1117.     for (i = 16384; i--; ) h32 = aes.encrypt(h32);
  1118.  
  1119.     return a32_to_base64([h32[0],h32[2]]);
  1120. }
  1121.  
  1122. // Update user
  1123. // Can also be used to set keys and to confirm accounts (.c)
  1124. function api_updateuser(ctx,newuser)
  1125. {
  1126.     newuser.a = 'up';
  1127.    
  1128.     res = api_req([newuser],ctx);
  1129. }
  1130.  
  1131. var u_pubkeys = new Object;
  1132.  
  1133. // @@@ remove
  1134. // Encrypt data to a user's public key
  1135. // Returns false in case no public key is available
  1136. function api_cachepubkey(ctx,user)
  1137. {
  1138.     ctx.user = user;
  1139.     ctx.callback = api_cachepubkey2;
  1140.    
  1141.     if (u_pubkeys[user]) ctx.cachepubkeycomplete(ctx,u_pubkeys[user]);
  1142.     else api_req([{ a : 'uk', u : user }],ctx);
  1143. }
  1144.  
  1145. function api_cachepubkey2(res,ctx)
  1146. {
  1147.     if (typeof res == 'object' && typeof res[0].pubk == 'string')
  1148.     {
  1149.         var spubkey = base64urldecode(res[0].pubk);
  1150.         var keylen = spubkey.charCodeAt(0)*256+spubkey.charCodeAt(1);
  1151.         var pubkey = Array(3);
  1152.         var i;
  1153.  
  1154.         // decompose public key
  1155.         for (i = 0; i < 2; i++)
  1156.         {
  1157.             var l = ((spubkey.charCodeAt(0)*256+spubkey.charCodeAt(1)+7)>>3)+2;
  1158.  
  1159.             pubkey[i] = mpi2b(spubkey.substr(0,l));
  1160.             if (typeof pubkey[i] == 'number') break;
  1161.             spubkey = spubkey.substr(l);
  1162.         }
  1163.  
  1164.         // check format
  1165.         if (i == 2 && spubkey.length < 16)
  1166.         {
  1167.             pubkey[2] = keylen;
  1168.             u_pubkeys[ctx.user] = pubkey;
  1169.         }
  1170.         else pubkey = false;
  1171.     }
  1172.    
  1173.     ctx.cachepubkeycomplete(ctx,pubkey);
  1174. }
  1175.  
  1176. function encryptto(user,data)
  1177. {
  1178.     var i, data;
  1179.     var pubkey;
  1180.  
  1181.     if (pubkey = u_pubkeys[user])
  1182.     {
  1183.         // random padding
  1184.         for (i = (pubkey[2]>>3)-1-data.length; i-- > 0; ) data = data+String.fromCharCode(rand(256));
  1185.  
  1186.         i = data.length*8;
  1187.         data = String.fromCharCode(i >> 8) + String.fromCharCode(i & 255) + data;
  1188.  
  1189.         return b2mpi(RSAencrypt(mpi2b(data),pubkey[1],pubkey[0]));
  1190.     }
  1191.  
  1192.     return false;
  1193. }
  1194.  
  1195. // @@@ replace with actual data structure
  1196. var u_sharekeys = new Object;
  1197. var u_nodekeys = new Object;
  1198.  
  1199. // u_nodekeys must be set for all sharenodes
  1200. // Add/cancel share(s) to a set of users or email addresses
  1201. // targets is an array of {u,r} - if no r given, cancel share
  1202. // If no sharekey known, tentatively generates one and encrypts
  1203. // everything to it. In case of a mismatch, the API call returns
  1204. // an error, and the whole operation gets repeated (exceedingly
  1205. // rare race condition).
  1206. function api_setshare1(node,targets,sharenodes,ctx)
  1207. {
  1208.     var i, j, n, nk, sharekey, ssharekey;
  1209.     var req, res;
  1210.     var newkey = false;
  1211.  
  1212.     req = { a : 's',
  1213.             n : node,
  1214.             s : []
  1215.         };
  1216.  
  1217.     ctx.sharenodes = sharenodes;
  1218.     ctx.targets = targets;
  1219.    
  1220.     // we only need to generate a key if one or more shares are added
  1221.     for (i = targets.length; i--; )
  1222.     {
  1223.         if (typeof targets[i].r == 'undefined')
  1224.         {
  1225.             // share cancellation
  1226.             req.s.push({ u : targets[i].u });
  1227.         }
  1228.         else
  1229.         {
  1230.             if (!req.ok)
  1231.             {
  1232.                 if (u_sharekeys[node]) sharekey = u_sharekeys[node];
  1233.                 else
  1234.                 {
  1235.                     sharekey = Array(4);
  1236.                     for (j = 4; j--; ) sharekey[j] = rand(0x100000000);
  1237.                     u_sharekeys[node] = sharekey;
  1238.                     newkey = true;
  1239.                 }
  1240.  
  1241.                 req.ok = a32_to_base64(encrypt_key(u_k_aes,sharekey));
  1242.                 req.ha = crypto_handleauth(node);
  1243.                 ssharekey = a32_to_str(sharekey);
  1244.             }
  1245.         }
  1246.     }
  1247.  
  1248.     u_sharekeys[node] = sharekey;
  1249.  
  1250.     if (newkey) req.cr = crypto_makecr(sharenodes,[node],true);
  1251.  
  1252.     ctx.tried = -1;
  1253.     ctx.ssharekey = ssharekey;
  1254.     ctx.req = req;
  1255.     ctx.i = 0;
  1256.     ctx.node = node;
  1257.     ctx.targets = targets;
  1258.     ctx.sharenodes = sharenodes;
  1259.  
  1260.     ctx.callback = function(res,ctx)
  1261.     {
  1262.         var pubkey;
  1263.         var i;
  1264.  
  1265.         if (typeof res == 'object' && typeof res[0] == 'object')
  1266.         {
  1267.             if (typeof res[0].pubk == 'string') u_pubkeys[ctx.targets[ctx.i].u] = crypto_decodepubkey(res[0].pubk);
  1268.             else if (res[0].ok)
  1269.             {
  1270.                 u_sharekeys[node] = decrypt_key(u_k_aes,base64_to_a32(res[0].ok));
  1271.                 return api_setshare(ctx.node,ctx.targets,ctx.sharenodes,ctx);
  1272.             }
  1273.         }
  1274.        
  1275.         if (ctx.i == ctx.targets.length) ctx.done(ctx);
  1276.         else if (!(pubkey = u_pubkeys[ctx.targets[ctx.i].u]) && ctx.tried < ctx.i)
  1277.         {
  1278.             ctx.tried = ctx.i;
  1279.            
  1280.             // no public key cached for this user: get it!
  1281.             api_req([{ a : 'uk', u : ctx.targets[ctx.i].u }],ctx);
  1282.         }
  1283.         else
  1284.         {
  1285.             n = false;
  1286.            
  1287.             if (pubkey)
  1288.             {
  1289.                 // pubkey found: encrypt share key to it
  1290.                 n = crypto_rsaencrypt(pubkey,ctx.ssharekey);
  1291.             }
  1292.  
  1293.             if (n) ctx.req.s.push({ u : ctx.targets[ctx.i].u, r : ctx.targets[ctx.i].r, k : base64urlencode(n) });
  1294.             else ctx.req.s.push({ u : ctx.targets[ctx.i].u, r : ctx.targets[ctx.i].r });
  1295.            
  1296.             ctx.i++;
  1297.            
  1298.             ctx.callback(false,ctx);
  1299.         }
  1300.     }
  1301.    
  1302.     ctx.callback(false,ctx);
  1303. }
  1304.  
  1305. function api_setshare2(res,node)
  1306. {
  1307.     if (res[0].ok) u_sharekeys[node] = decrypt_key(u_k_aes,base64_to_a32(res[0].ok));
  1308. }
  1309.  
  1310. function api_setrsa(privk,pubk)
  1311. {
  1312.     var t;
  1313.    
  1314.     for (t = '', i = 0; i < privk.length; i++) t = t+b2mpi(privk[i]);
  1315.    
  1316.     // pad @@@ use random chars
  1317.     t = t + "---------------------------------".substr(0,(-t.length)&15);
  1318.  
  1319.     ctx = { callback : function(res,ctx)
  1320.         {
  1321.             console.log("RSA key put result=" + res);
  1322.            
  1323.             u_privk = ctx.privk;
  1324.             u_storage.privk = JSON.stringify(u_privk);
  1325.             u_type = 3;
  1326.            
  1327.             ui_keycomplete();
  1328.         },
  1329.         privk : privk
  1330.     };
  1331.        
  1332.     api_req([{ a : 'up', privk : a32_to_base64(encrypt_key(u_k_aes,str_to_a32(t))), pubk : base64urlencode(b2mpi(pubk[0])+b2mpi(pubk[1])) }],ctx);
  1333. }
  1334.  
  1335. function crypto_handleauth(h)
  1336. {
  1337.     return a32_to_base64(encrypt_key(u_k_aes,str_to_a32(h+h)));
  1338. }
  1339.  
  1340. function crypto_decodepubkey(pubk)
  1341. {
  1342.     var i;
  1343.    
  1344.     var spubkey = base64urldecode(pubk);
  1345.  
  1346.     var keylen = spubkey.charCodeAt(0)*256+spubkey.charCodeAt(1);
  1347.  
  1348.     var pubkey = Array(3);
  1349.  
  1350.     // decompose public key
  1351.     for (i = 0; i < 2; i++)
  1352.     {
  1353.         var l = ((spubkey.charCodeAt(0)*256+spubkey.charCodeAt(1)+7)>>3)+2;
  1354.  
  1355.         pubkey[i] = mpi2b(spubkey.substr(0,l));
  1356.         if (typeof pubkey[i] == 'number') break;
  1357.         spubkey = spubkey.substr(l);
  1358.     }
  1359.  
  1360.     // check format
  1361.     if (i == 2 && spubkey.length < 16)
  1362.     {
  1363.         pubkey[2] = keylen;
  1364.         return pubkey;
  1365.     }
  1366.     return false;
  1367. }
  1368.  
  1369. function crypto_rsaencrypt(pubkey,data)
  1370. {
  1371.     var i;
  1372.    
  1373.     // random padding
  1374.     for (i = (pubkey[2]>>3)-1-data.length; i-- > 0; ) data = data+String.fromCharCode(rand(256));
  1375.  
  1376.     i = data.length*8;
  1377.     data = String.fromCharCode(i >> 8) + String.fromCharCode(i & 255) + data;
  1378.  
  1379.     return b2mpi(RSAencrypt(mpi2b(data),pubkey[1],pubkey[0]));
  1380. }
  1381.  
  1382. // Complete upload
  1383. // We construct a special node put command that uses the upload token
  1384. // as the source handle
  1385. function api_completeupload(t,ut,path,n,k,ctx)
  1386. {
  1387.     ctx2 = { callback : api_completeupload2, t : base64urlencode(t), path : path, n : n, k : k, ctx : ctx };
  1388.  
  1389.     api_completeupload2(ctx2,ut);
  1390. }
  1391.  
  1392. function api_completeupload2(ctx,ut)
  1393. {
  1394.     var p;
  1395.  
  1396.     if (ctx.path && ctx.path != ctx.n && (p = ctx.path.indexOf('/')) > 0)
  1397.     {
  1398.         var pc = ctx.path.substr(0,p);
  1399.        
  1400.         ctx.path = ctx.path.substr(p+1);
  1401.  
  1402.         fm_requestfolderid(ut,pc,ctx);
  1403.     }
  1404.     else
  1405.     {
  1406.         a = { n : ctx.n };
  1407.  
  1408.         if (d) console.log(ctx.k);
  1409.  
  1410.         var ea = enc_attr(a,ctx.k);
  1411.        
  1412.         if (d) console.log(ea);
  1413.  
  1414.         var req = { a : 'p',
  1415.             t : ut,
  1416.             n : [{ h : ctx.t, t : 0, a : ab_to_base64(ea[0]), k : a32_to_base64(encrypt_key(u_k_aes,ctx.k)) }]
  1417.         };
  1418.  
  1419.  
  1420.         if (ut)
  1421.         {
  1422.             // a target has been supplied: encrypt to all relevant shares
  1423.             var sn = fm_getsharenodes(ut);
  1424.  
  1425.             if (sn.length)
  1426.             {
  1427.                 req.cr = crypto_makecr([ctx.k],sn,false);
  1428.                 req.cr[1][0] = ctx.t;
  1429.             }
  1430.         }
  1431.  
  1432.         api_req([req],ctx.ctx);
  1433.     }
  1434. }
  1435.  
  1436. // Generate crypto request response for the given nodes/shares matrix
  1437. function crypto_makecr(source,shares,source_is_nodes)
  1438. {
  1439.     var i, j, n;
  1440.     var cr = [shares,[],[]];
  1441.     var aes;
  1442.  
  1443.     // if we have node handles, include in cr - otherwise, we have node keys
  1444.     if (source_is_nodes) cr[1] = source;
  1445.  
  1446.     // @@@ optimization: keep track of pre-existing/sent keys, only send new ones
  1447.     for (i = shares.length; i--; )
  1448.     {
  1449.         if (u_sharekeys[shares[i]])
  1450.         {
  1451.             aes = new sjcl.cipher.aes(u_sharekeys[shares[i]]);
  1452.            
  1453.             for (j = source.length; j--; )
  1454.             {
  1455.                 if (source_is_nodes ? (nk = u_nodekeys[source[j]]) : (nk = source[j]))
  1456.                 {
  1457.                     if (nk.length == 8 || nk.length == 4) cr[2].push(i,j,a32_to_base64(encrypt_key(aes,nk)));
  1458.                 }
  1459.             }
  1460.         }
  1461.     }
  1462.  
  1463.     return cr;
  1464. }
  1465.  
  1466. // RSA-encrypt sharekey to newly RSA-equipped user
  1467. // @@@ check source/ownership of sharekeys, prevent forged requests
  1468. function crypto_procsr(sr)
  1469. {
  1470.     var ctx = new Object;
  1471.     ctx.sr = sr;
  1472.     ctx.i = -2;
  1473.  
  1474.     ctx.callback = function(res,ctx)
  1475.     {
  1476.         var pubkey;
  1477.  
  1478.         if (typeof res == 'object' && typeof res[0] == 'object' && typeof res[0].pubk == 'string') u_pubkeys[ctx.sr[ctx.i+1]] = crypto_decodepubkey(res[0].pubk);
  1479.  
  1480.         // collect all required pubkeys
  1481.         while (ctx.i < ctx.sr.length-2)
  1482.         {
  1483.             ctx.i += 2;
  1484.            
  1485.             if (ctx.sr[ctx.i+1].length == 11 && !(pubkey = u_pubkeys[ctx.sr[ctx.i+1]]))
  1486.             {
  1487.                 api_req([{ a : 'uk', u : ctx.sr[ctx.i+1] }],ctx);
  1488.                 return;
  1489.             }
  1490.         }
  1491.  
  1492.         var rsr = [];
  1493.         var sh;
  1494.         var n;
  1495.  
  1496.         for (var i = 0; i < ctx.sr.length; i += 2)
  1497.         {
  1498.             sh = ctx.sr[i];
  1499.  
  1500.             if (sh.length == 8)
  1501.             {
  1502.                 // @@@ check auth
  1503.                 if (u_sharekeys[sh])
  1504.                 {
  1505.                     if (d) console.log("Encrypting sharekey " + sh + " to user " + ctx.sr[i+1]);
  1506.  
  1507.                     if (pubkey = u_pubkeys[ctx.sr[i+1]])
  1508.                     {
  1509.                         // pubkey found: encrypt share key to it
  1510.                         if (n = crypto_rsaencrypt(pubkey,a32_to_str(u_sharekeys[sh]))) rsr.push(sh,ctx.sr[i+1],base64urlencode(n));
  1511.                     }
  1512.                 }
  1513.             }
  1514.  
  1515.             if (rsr.length) api_req([{ a : 'k', sr : rsr }]);
  1516.         }
  1517.     }
  1518.    
  1519.     ctx.callback(false,ctx);
  1520. }
  1521.  
  1522. function api_confirmuser(confirmcode)
  1523. {
  1524.    
  1525.  
  1526.  
  1527. }
  1528.  
  1529. var keycache = new Object;
  1530.  
  1531. var rsa2aes = new Object;
  1532.  
  1533. // Try to decrypt ufs node.
  1534. // Parameters: me - my user handle
  1535. // master_aes - my master password's AES cipher
  1536. // file - ufs node containing .k and .a
  1537. // Output: .key and .name set if successful
  1538. function crypto_processkey(me,master_aes,file)
  1539. {
  1540.     var id, key, k, n;
  1541.  
  1542.     if (!file.k)
  1543.     {
  1544.         if (!keycache[file.h]) return;
  1545.        
  1546.         file.k = keycache[file.h];
  1547.     }
  1548.  
  1549.     id = me;
  1550.  
  1551.     // do I own the file? (user key is guaranteed to be first in .k)
  1552.     var p = file.k.indexOf(id + ':');
  1553.    
  1554.     if (p)
  1555.     {
  1556.         // I don't - do I have a suitable sharekey?
  1557.         for (id in u_sharekeys)
  1558.         {
  1559.             p = file.k.indexOf(id + ':');
  1560.            
  1561.             if (p >= 0 && (!p || file.k.charAt(p-1) == '/')) break;
  1562.            
  1563.             p = -1;
  1564.         }
  1565.     }
  1566.  
  1567.     if (p >= 0)
  1568.     {
  1569.         delete keycache[file.h];
  1570.    
  1571.         var pp = file.k.indexOf('/',p);
  1572.  
  1573.         if (pp < 0) pp = file.k.length;
  1574.  
  1575.         p += id.length+1;
  1576.  
  1577.         key = file.k.substr(p,pp-p);
  1578.  
  1579.         // we have found a suitable key: decrypt!
  1580.         if (key.length < 46)
  1581.         {
  1582.             // short keys: AES
  1583.  
  1584.             k = base64_to_a32(key);
  1585.  
  1586.             // check for permitted key lengths (4 == folder, 8 == file)
  1587.             if (k.length == 4 || k.length == 8)
  1588.             {
  1589.                 // @@@ cache sharekeys aes
  1590.                 k = decrypt_key(id == me ? master_aes : new sjcl.cipher.aes(u_sharekeys[id]),k);
  1591.             }
  1592.             else
  1593.             {
  1594.                 if (d) console.log("Received invalid key length (" + k.length + "): " + file.h);
  1595.                 return;
  1596.             }
  1597.         }
  1598.         else
  1599.         {
  1600.             // long keys: RSA
  1601.             if (u_privk)
  1602.             {
  1603.                 var t = mpi2b(base64urldecode(key));
  1604.                 k = str_to_a32(b2s(RSAdecrypt(t,u_privk[2],u_privk[0],u_privk[1],u_privk[3])).substr(0,file.t ? 16 : 32));
  1605.             }
  1606.             else
  1607.             {
  1608.                 if (d) console.log("Received RSA key, but have no public key published: " + file.h);
  1609.                 return;
  1610.             }
  1611.         }
  1612.  
  1613.         var ab = base64_to_ab(file.a);
  1614.         var o = dec_attr(ab,k);
  1615.  
  1616.         if (typeof o == 'object')
  1617.         {
  1618.             if (typeof o.n == 'string')
  1619.             {
  1620.                 if (file.h)
  1621.                 {
  1622.                     u_nodekeys[file.h] = k;
  1623.                     if (key.length >= 46) rsa2aes[file.h] = a32_to_str(encrypt_key(u_k_aes,k));
  1624.                 }
  1625.  
  1626.                 file.key = k;
  1627.                 file.name = o.n;
  1628.             }
  1629.         }
  1630.     }
  1631.     else
  1632.     {
  1633.         if (d) console.log("Received no suitable key: " + file.h);
  1634.        
  1635.         if (!missingkeys[file.h])
  1636.         {
  1637.             newmissingkeys = true;
  1638.             missingkeys[file.h] = true;
  1639.         }
  1640.         keycache[file.h] = file.k;
  1641.     }
  1642. }
  1643.  
  1644. function crypto_sendrsa2aes()
  1645. {
  1646.     var n;
  1647.     var nk = [];
  1648.    
  1649.     for (n in rsa2aes) nk.push(n,base64urlencode(rsa2aes[n]));
  1650.        
  1651.     if (nk.length) api_req([{ a : 'k', nk : nk }]);
  1652.  
  1653.     rsa2aes = new Object;
  1654. }
  1655.  
  1656. var missingkeys = new Object;
  1657. var newmissingkeys = false;
  1658.  
  1659. function crypto_reqmissingkeys()
  1660. {
  1661.     if (!newmissingkeys)
  1662.     {
  1663.         if (d) console.log('No new missing keys.');
  1664.         return;
  1665.     }
  1666.  
  1667.     var i, j;
  1668.     var n, s, ni, si, sn;
  1669.     var cr = [[],[],[]];
  1670.  
  1671.     ni = new Object;
  1672.     si = new Object;
  1673.  
  1674.     for (n in missingkeys)
  1675.     {
  1676.         // TODO: optimization: don't request keys for own files
  1677.         sn = fm_getsharenodes(n);
  1678.  
  1679.         for (j = sn.length; j--; )
  1680.         {
  1681.             s = sn[j];
  1682.  
  1683.             if (typeof si[s] == 'undefined')
  1684.             {
  1685.                 si[s] = cr[0].length;
  1686.                 cr[0].push(s);
  1687.             }
  1688.            
  1689.             if (typeof ni[n] == 'undefined')
  1690.             {
  1691.                 ni[n] = cr[1].length;
  1692.                 cr[1].push(n);
  1693.             }
  1694.  
  1695.             cr[2].push(si[s],ni[n]);
  1696.         }
  1697.     }
  1698.  
  1699.     if (!cr[1].length /*&& !missingsharekeys.length*/)
  1700.     {
  1701.         if (d) console.log('No missing keys');
  1702.         return;
  1703.     }
  1704.  
  1705.     if (cr[0].length)
  1706.     {
  1707.         var ctx = new Object;
  1708.        
  1709.         ctx.callback = function(res,ctx)
  1710.         {
  1711.             if (d) console.log("Processing crypto response");
  1712.            
  1713.             if (typeof res == 'object' && typeof res[0] == 'object') crypto_proccr(res[0]);
  1714.         }
  1715.  
  1716.         res = api_req([{ a : 'k', cr : cr }],ctx);
  1717.     }
  1718.     else if (d) console.log("Keys " + cr[1] + " missing, but no related shares found.");
  1719. }
  1720.  
  1721. // process incoming cr, set fm keys and commit
  1722. function crypto_proccr(cr)
  1723. {
  1724.     var i;
  1725.  
  1726.     // received keys in response, add
  1727.     for (i = 0; i < cr[2].length; i += 3) fm_updatekey(cr[1][cr[2][i+1]],cr[0][cr[2][i]] + ":" + cr[2][i+2]);
  1728.  
  1729.     fm_commitkeyupdate();
  1730. }
  1731.  
  1732. // process incoming missing key cr
  1733. function crypto_procmcr(mcr)
  1734. {
  1735.     var i;
  1736.     var si = new Object, ni = new Object;
  1737.     var sh, nh;
  1738.     var sc = new Object;
  1739.     var cr = [[],[],[]];
  1740.  
  1741.     // received keys in response, add
  1742.     for (i = 0; i < mcr[2].length; i += 2)
  1743.     {
  1744.         sh = mcr[0][mcr[2][i]];
  1745.  
  1746.         if (u_sharekeys[sh])
  1747.         {
  1748.             nh = mcr[1][mcr[2][i+1]];
  1749.            
  1750.             if (u_nodekeys[nh])
  1751.             {
  1752.                 if (typeof si[sh] == 'undefined')
  1753.                 {
  1754.                     sc[sh] = new sjcl.cipher.aes(u_sharekeys[sh]);
  1755.                     si[sh] = cr[0].length;
  1756.                     cr[0].push(sh);
  1757.                 }
  1758.                
  1759.                 if (typeof ni[nh] == 'undefined')
  1760.                 {
  1761.                     ni[nh] = cr[1].length;
  1762.                     cr[1].push(nh);
  1763.                 }
  1764.  
  1765.                 cr[2].push(si[sh],ni[nh],a32_to_base64(encrypt_key(sc[sh],u_nodekeys[nh])));
  1766.             }
  1767.         }
  1768.     }
  1769.  
  1770.     if (cr[0].length) api_req([{ a : 'k', cr : cr }]);
  1771. }
  1772.  
  1773. var rsasharekeys = new Object;
  1774.  
  1775. function crypto_process_sharekey(handle,key)
  1776. {
  1777.     if (key.length > 22)
  1778.     {
  1779.         key = mpi2b(base64urldecode(key));
  1780.         var k = str_to_a32(b2s(RSAdecrypt(key,u_privk[2],u_privk[0],u_privk[1],u_privk[3])).substr(0,16));
  1781.         rsasharekeys[handle] = true;
  1782.         return k;
  1783.     }
  1784.     else return decrypt_key(u_k_aes,base64_to_a32(key));
  1785. }
  1786.  
  1787. function crypto_share_rsa2aes()
  1788. {
  1789.     var rsr = [];
  1790.  
  1791.     for (n in rsasharekeys)
  1792.     {
  1793.         if (u_sharekeys[n])
  1794.         {
  1795.             // pubkey found: encrypt share key to it
  1796.             rsr.push(n,u_handle,a32_to_base64(encrypt_key(u_k_aes,u_sharekeys[n])));
  1797.         }
  1798.     }
  1799.  
  1800.     if (rsr.length)
  1801.     {
  1802.         api_req([{ a : 'k', sr : rsr }]);
  1803.         rsasharekeys = new Object;
  1804.     }
  1805. }
Advertisement
Add Comment
Please, Sign In to add comment