xxtea.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /* eslint-disable no-useless-escape */
  2. /* eslint-disable no-control-regex */
  3. /** ********************************************************\
  4. | |
  5. | xxtea.js |
  6. | |
  7. | XXTEA encryption algorithm library for JavaScript. |
  8. | |
  9. | Encryption Algorithm Authors: |
  10. | David J. Wheeler |
  11. | Roger M. Needham |
  12. | |
  13. | Code Author: Ma Bingyao <mabingyao@gmail.com> |
  14. | LastModified: Oct 4, 2016 |
  15. | |
  16. \**********************************************************/
  17. (function (global) {
  18. 'use strict';
  19. if (typeof(global.btoa) == 'undefined') {
  20. global.btoa = function () {
  21. var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
  22. return function (str) {
  23. var buf, i, j, len, r, l, c;
  24. i = j = 0;
  25. len = str.length;
  26. r = len % 3;
  27. len = len - r;
  28. l = (len / 3) << 2;
  29. if (r > 0) {
  30. l += 4;
  31. }
  32. buf = new Array(l);
  33. while (i < len) {
  34. c = str.charCodeAt(i++) << 16 |
  35. str.charCodeAt(i++) << 8 |
  36. str.charCodeAt(i++);
  37. buf[j++] = base64EncodeChars[c >> 18] +
  38. base64EncodeChars[c >> 12 & 0x3f] +
  39. base64EncodeChars[c >> 6 & 0x3f] +
  40. base64EncodeChars[c & 0x3f] ;
  41. }
  42. if (r == 1) {
  43. c = str.charCodeAt(i++);
  44. buf[j++] = base64EncodeChars[c >> 2] +
  45. base64EncodeChars[(c & 0x03) << 4] +
  46. '==';
  47. }
  48. else if (r == 2) {
  49. c = str.charCodeAt(i++) << 8 |
  50. str.charCodeAt(i++);
  51. buf[j++] = base64EncodeChars[c >> 10] +
  52. base64EncodeChars[c >> 4 & 0x3f] +
  53. base64EncodeChars[(c & 0x0f) << 2] +
  54. '=';
  55. }
  56. return buf.join('');
  57. };
  58. }();
  59. }
  60. if (typeof(global.atob) == 'undefined') {
  61. global.atob = function () {
  62. var base64DecodeChars = [
  63. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  64. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  65. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
  66. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
  67. -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  68. 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
  69. -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  70. 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
  71. ];
  72. return function (str) {
  73. var c1, c2, c3, c4;
  74. var i, j, len, r, l, out;
  75. len = str.length;
  76. if (len % 4 !== 0) {
  77. return '';
  78. }
  79. if ((/[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\+\/\=]/).test(str)) {
  80. return '';
  81. }
  82. if (str.charAt(len - 2) == '=') {
  83. r = 1;
  84. }
  85. else if (str.charAt(len - 1) == '=') {
  86. r = 2;
  87. }
  88. else {
  89. r = 0;
  90. }
  91. l = len;
  92. if (r > 0) {
  93. l -= 4;
  94. }
  95. l = (l >> 2) * 3 + r;
  96. out = new Array(l);
  97. i = j = 0;
  98. while (i < len) {
  99. // c1
  100. c1 = base64DecodeChars[str.charCodeAt(i++)];
  101. if (c1 == -1)
  102. break;
  103. // c2
  104. c2 = base64DecodeChars[str.charCodeAt(i++)];
  105. if (c2 == -1)
  106. break;
  107. out[j++] = String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
  108. // c3
  109. c3 = base64DecodeChars[str.charCodeAt(i++)];
  110. if (c3 == -1)
  111. break;
  112. out[j++] = String.fromCharCode(((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2));
  113. // c4
  114. c4 = base64DecodeChars[str.charCodeAt(i++)];
  115. if (c4 == -1)
  116. break;
  117. out[j++] = String.fromCharCode(((c3 & 0x03) << 6) | c4);
  118. }
  119. return out.join('');
  120. };
  121. }();
  122. }
  123. var DELTA = 0x9E3779B9;
  124. function toBinaryString (v, includeLength) {
  125. var length = v.length;
  126. var n = length << 2;
  127. if (includeLength) {
  128. var m = v[length - 1];
  129. n -= 4;
  130. if ((m < n - 3) || (m > n)) {
  131. return null;
  132. }
  133. n = m;
  134. }
  135. for (var i = 0; i < length; i++) {
  136. v[i] = String.fromCharCode(
  137. v[i] & 0xFF,
  138. v[i] >>> 8 & 0xFF,
  139. v[i] >>> 16 & 0xFF,
  140. v[i] >>> 24 & 0xFF
  141. );
  142. }
  143. var result = v.join('');
  144. if (includeLength) {
  145. return result.substring(0, n);
  146. }
  147. return result;
  148. }
  149. function toUint32Array (bs, includeLength) {
  150. var length = bs.length;
  151. var n = length >> 2;
  152. if ((length & 3) !== 0) {
  153. ++n;
  154. }
  155. var v;
  156. if (includeLength) {
  157. v = new Array(n + 1);
  158. v[n] = length;
  159. }
  160. else {
  161. v = new Array(n);
  162. }
  163. for (var i = 0; i < length; ++i) {
  164. v[i >> 2] |= bs.charCodeAt(i) << ((i & 3) << 3);
  165. }
  166. return v;
  167. }
  168. function int32 (i) {
  169. return i & 0xFFFFFFFF;
  170. }
  171. function mx (sum, y, z, p, e, k) {
  172. return ((z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4)) ^ ((sum ^ y) + (k[p & 3 ^ e] ^ z));
  173. }
  174. function fixk (k) {
  175. if (k.length < 4)
  176. k.length = 4;
  177. return k;
  178. }
  179. function encryptUint32Array (v, k) {
  180. var length = v.length;
  181. var n = length - 1;
  182. var y, z, sum, e, p, q;
  183. z = v[n];
  184. sum = 0;
  185. for (q = Math.floor(6 + 52 / length) | 0; q > 0; --q) {
  186. sum = int32(sum + DELTA);
  187. e = sum >>> 2 & 3;
  188. for (p = 0; p < n; ++p) {
  189. y = v[p + 1];
  190. z = v[p] = int32(v[p] + mx(sum, y, z, p, e, k));
  191. }
  192. y = v[0];
  193. z = v[n] = int32(v[n] + mx(sum, y, z, n, e, k));
  194. }
  195. return v;
  196. }
  197. function decryptUint32Array (v, k) {
  198. var length = v.length;
  199. var n = length - 1;
  200. var y, z, sum, e, p, q;
  201. y = v[0];
  202. q = Math.floor(6 + 52 / length);
  203. for (sum = int32(q * DELTA); sum !== 0; sum = int32(sum - DELTA)) {
  204. e = sum >>> 2 & 3;
  205. for (p = n; p > 0; --p) {
  206. z = v[p - 1];
  207. y = v[p] = int32(v[p] - mx(sum, y, z, p, e, k));
  208. }
  209. z = v[n];
  210. y = v[0] = int32(v[0] - mx(sum, y, z, 0, e, k));
  211. }
  212. return v;
  213. }
  214. function utf8Encode (str) {
  215. if ((/^[\x00-\x7f]*$/).test(str)) {
  216. return str;
  217. }
  218. var buf = [];
  219. var n = str.length;
  220. for (var i = 0, j = 0; i < n; ++i, ++j) {
  221. var codeUnit = str.charCodeAt(i);
  222. if (codeUnit < 0x80) {
  223. buf[j] = str.charAt(i);
  224. }
  225. else if (codeUnit < 0x800) {
  226. buf[j] = String.fromCharCode(
  227. 0xC0 | (codeUnit >> 6),
  228. 0x80 | (codeUnit & 0x3F)
  229. );
  230. }
  231. else if (codeUnit < 0xD800 || codeUnit > 0xDFFF) {
  232. buf[j] = String.fromCharCode(
  233. 0xE0 | (codeUnit >> 12),
  234. 0x80 | ((codeUnit >> 6) & 0x3F),
  235. 0x80 | (codeUnit & 0x3F)
  236. );
  237. }
  238. else {
  239. if (i + 1 < n) {
  240. var nextCodeUnit = str.charCodeAt(i + 1);
  241. if (codeUnit < 0xDC00 && 0xDC00 <= nextCodeUnit && nextCodeUnit <= 0xDFFF) {
  242. var rune = (((codeUnit & 0x03FF) << 10) | (nextCodeUnit & 0x03FF)) + 0x010000;
  243. buf[j] = String.fromCharCode(
  244. 0xF0 | ((rune >> 18) & 0x3F),
  245. 0x80 | ((rune >> 12) & 0x3F),
  246. 0x80 | ((rune >> 6) & 0x3F),
  247. 0x80 | (rune & 0x3F)
  248. );
  249. ++i;
  250. continue;
  251. }
  252. }
  253. throw new Error('Malformed string');
  254. }
  255. }
  256. return buf.join('');
  257. }
  258. function utf8DecodeShortString (bs, n) {
  259. var charCodes = new Array(n);
  260. var i = 0, off = 0;
  261. for (var len = bs.length; i < n && off < len; i++) {
  262. var unit = bs.charCodeAt(off++);
  263. switch (unit >> 4) {
  264. case 0:
  265. case 1:
  266. case 2:
  267. case 3:
  268. case 4:
  269. case 5:
  270. case 6:
  271. case 7:
  272. charCodes[i] = unit;
  273. break;
  274. case 12:
  275. case 13:
  276. if (off < len) {
  277. charCodes[i] = ((unit & 0x1F) << 6) |
  278. (bs.charCodeAt(off++) & 0x3F);
  279. }
  280. else {
  281. throw new Error('Unfinished UTF-8 octet sequence');
  282. }
  283. break;
  284. case 14:
  285. if (off + 1 < len) {
  286. charCodes[i] = ((unit & 0x0F) << 12) |
  287. ((bs.charCodeAt(off++) & 0x3F) << 6) |
  288. (bs.charCodeAt(off++) & 0x3F);
  289. }
  290. else {
  291. throw new Error('Unfinished UTF-8 octet sequence');
  292. }
  293. break;
  294. case 15:
  295. if (off + 2 < len) {
  296. var rune = (((unit & 0x07) << 18) |
  297. ((bs.charCodeAt(off++) & 0x3F) << 12) |
  298. ((bs.charCodeAt(off++) & 0x3F) << 6) |
  299. (bs.charCodeAt(off++) & 0x3F)) - 0x10000;
  300. if (0 <= rune && rune <= 0xFFFFF) {
  301. charCodes[i++] = (((rune >> 10) & 0x03FF) | 0xD800);
  302. charCodes[i] = ((rune & 0x03FF) | 0xDC00);
  303. }
  304. else {
  305. throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16));
  306. }
  307. }
  308. else {
  309. throw new Error('Unfinished UTF-8 octet sequence');
  310. }
  311. break;
  312. default:
  313. throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16));
  314. }
  315. }
  316. if (i < n) {
  317. charCodes.length = i;
  318. }
  319. return String.fromCharCode.apply(String, charCodes);
  320. }
  321. function utf8DecodeLongString (bs, n) {
  322. var buf = [];
  323. var charCodes = new Array(0x8000);
  324. var i = 0, off = 0;
  325. for (var len = bs.length; i < n && off < len; i++) {
  326. var unit = bs.charCodeAt(off++);
  327. switch (unit >> 4) {
  328. case 0:
  329. case 1:
  330. case 2:
  331. case 3:
  332. case 4:
  333. case 5:
  334. case 6:
  335. case 7:
  336. charCodes[i] = unit;
  337. break;
  338. case 12:
  339. case 13:
  340. if (off < len) {
  341. charCodes[i] = ((unit & 0x1F) << 6) |
  342. (bs.charCodeAt(off++) & 0x3F);
  343. }
  344. else {
  345. throw new Error('Unfinished UTF-8 octet sequence');
  346. }
  347. break;
  348. case 14:
  349. if (off + 1 < len) {
  350. charCodes[i] = ((unit & 0x0F) << 12) |
  351. ((bs.charCodeAt(off++) & 0x3F) << 6) |
  352. (bs.charCodeAt(off++) & 0x3F);
  353. }
  354. else {
  355. throw new Error('Unfinished UTF-8 octet sequence');
  356. }
  357. break;
  358. case 15:
  359. if (off + 2 < len) {
  360. var rune = (((unit & 0x07) << 18) |
  361. ((bs.charCodeAt(off++) & 0x3F) << 12) |
  362. ((bs.charCodeAt(off++) & 0x3F) << 6) |
  363. (bs.charCodeAt(off++) & 0x3F)) - 0x10000;
  364. if (0 <= rune && rune <= 0xFFFFF) {
  365. charCodes[i++] = (((rune >> 10) & 0x03FF) | 0xD800);
  366. charCodes[i] = ((rune & 0x03FF) | 0xDC00);
  367. }
  368. else {
  369. throw new Error('Character outside valid Unicode range: 0x' + rune.toString(16));
  370. }
  371. }
  372. else {
  373. throw new Error('Unfinished UTF-8 octet sequence');
  374. }
  375. break;
  376. default:
  377. throw new Error('Bad UTF-8 encoding 0x' + unit.toString(16));
  378. }
  379. if (i >= 0x7FFF - 1) {
  380. var size = i + 1;
  381. charCodes.length = size;
  382. buf[buf.length] = String.fromCharCode.apply(String, charCodes);
  383. n -= size;
  384. i = -1;
  385. }
  386. }
  387. if (i > 0) {
  388. charCodes.length = i;
  389. buf[buf.length] = String.fromCharCode.apply(String, charCodes);
  390. }
  391. return buf.join('');
  392. }
  393. // n is UTF16 length
  394. function utf8Decode (bs, n) {
  395. if (n === undefined || n === null || (n < 0))
  396. n = bs.length;
  397. if (n === 0)
  398. return '';
  399. if ((/^[\x00-\x7f]*$/).test(bs) || !((/^[\x00-\xff]*$/).test(bs))) {
  400. if (n === bs.length)
  401. return bs;
  402. return bs.substr(0, n);
  403. }
  404. return ((n < 0xFFFF) ?
  405. utf8DecodeShortString(bs, n) :
  406. utf8DecodeLongString(bs, n));
  407. }
  408. function encrypt (data, key) {
  409. if (data === undefined || data === null || data.length === 0) {
  410. return data;
  411. }
  412. data = utf8Encode(data);
  413. key = utf8Encode(key);
  414. return toBinaryString(encryptUint32Array(toUint32Array(data, true), fixk(toUint32Array(key, false))), false);
  415. }
  416. function encryptToBase64 (data, key) {
  417. return global.btoa(encrypt(data, key));
  418. }
  419. function decrypt (data, key) {
  420. if (data === undefined || data === null || data.length === 0) {
  421. return data;
  422. }
  423. key = utf8Encode(key);
  424. return utf8Decode(toBinaryString(decryptUint32Array(toUint32Array(data, false), fixk(toUint32Array(key, false))), true));
  425. }
  426. function decryptFromBase64 (data, key) {
  427. if (data === undefined || data === null || data.length === 0) {
  428. return data;
  429. }
  430. return decrypt(global.atob(data), key);
  431. }
  432. global.XXTEA = {
  433. utf8Encode: utf8Encode,
  434. utf8Decode: utf8Decode,
  435. encrypt: encrypt,
  436. encryptToBase64: encryptToBase64,
  437. decrypt: decrypt,
  438. decryptFromBase64: decryptFromBase64
  439. };
  440. })(window);