aes-decrypter.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. /*! @name aes-decrypter @version 4.0.1 @license Apache-2.0 */
  2. (function (global, factory) {
  3. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  4. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  5. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.aesDecrypter = {}));
  6. })(this, (function (exports) { 'use strict';
  7. /**
  8. * @file aes.js
  9. *
  10. * This file contains an adaptation of the AES decryption algorithm
  11. * from the Standford Javascript Cryptography Library. That work is
  12. * covered by the following copyright and permissions notice:
  13. *
  14. * Copyright 2009-2010 Emily Stark, Mike Hamburg, Dan Boneh.
  15. * All rights reserved.
  16. *
  17. * Redistribution and use in source and binary forms, with or without
  18. * modification, are permitted provided that the following conditions are
  19. * met:
  20. *
  21. * 1. Redistributions of source code must retain the above copyright
  22. * notice, this list of conditions and the following disclaimer.
  23. *
  24. * 2. Redistributions in binary form must reproduce the above
  25. * copyright notice, this list of conditions and the following
  26. * disclaimer in the documentation and/or other materials provided
  27. * with the distribution.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
  30. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  31. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  32. * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
  33. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  34. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  35. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  36. * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  37. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  38. * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  39. * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  40. *
  41. * The views and conclusions contained in the software and documentation
  42. * are those of the authors and should not be interpreted as representing
  43. * official policies, either expressed or implied, of the authors.
  44. */
  45. /**
  46. * Expand the S-box tables.
  47. *
  48. * @private
  49. */
  50. const precompute = function () {
  51. const tables = [[[], [], [], [], []], [[], [], [], [], []]];
  52. const encTable = tables[0];
  53. const decTable = tables[1];
  54. const sbox = encTable[4];
  55. const sboxInv = decTable[4];
  56. let i;
  57. let x;
  58. let xInv;
  59. const d = [];
  60. const th = [];
  61. let x2;
  62. let x4;
  63. let x8;
  64. let s;
  65. let tEnc;
  66. let tDec; // Compute double and third tables
  67. for (i = 0; i < 256; i++) {
  68. th[(d[i] = i << 1 ^ (i >> 7) * 283) ^ i] = i;
  69. }
  70. for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
  71. // Compute sbox
  72. s = xInv ^ xInv << 1 ^ xInv << 2 ^ xInv << 3 ^ xInv << 4;
  73. s = s >> 8 ^ s & 255 ^ 99;
  74. sbox[x] = s;
  75. sboxInv[s] = x; // Compute MixColumns
  76. x8 = d[x4 = d[x2 = d[x]]];
  77. tDec = x8 * 0x1010101 ^ x4 * 0x10001 ^ x2 * 0x101 ^ x * 0x1010100;
  78. tEnc = d[s] * 0x101 ^ s * 0x1010100;
  79. for (i = 0; i < 4; i++) {
  80. encTable[i][x] = tEnc = tEnc << 24 ^ tEnc >>> 8;
  81. decTable[i][s] = tDec = tDec << 24 ^ tDec >>> 8;
  82. }
  83. } // Compactify. Considerable speedup on Firefox.
  84. for (i = 0; i < 5; i++) {
  85. encTable[i] = encTable[i].slice(0);
  86. decTable[i] = decTable[i].slice(0);
  87. }
  88. return tables;
  89. };
  90. let aesTables = null;
  91. /**
  92. * Schedule out an AES key for both encryption and decryption. This
  93. * is a low-level class. Use a cipher mode to do bulk encryption.
  94. *
  95. * @class AES
  96. * @param key {Array} The key as an array of 4, 6 or 8 words.
  97. */
  98. class AES {
  99. constructor(key) {
  100. /**
  101. * The expanded S-box and inverse S-box tables. These will be computed
  102. * on the client so that we don't have to send them down the wire.
  103. *
  104. * There are two tables, _tables[0] is for encryption and
  105. * _tables[1] is for decryption.
  106. *
  107. * The first 4 sub-tables are the expanded S-box with MixColumns. The
  108. * last (_tables[01][4]) is the S-box itself.
  109. *
  110. * @private
  111. */
  112. // if we have yet to precompute the S-box tables
  113. // do so now
  114. if (!aesTables) {
  115. aesTables = precompute();
  116. } // then make a copy of that object for use
  117. this._tables = [[aesTables[0][0].slice(), aesTables[0][1].slice(), aesTables[0][2].slice(), aesTables[0][3].slice(), aesTables[0][4].slice()], [aesTables[1][0].slice(), aesTables[1][1].slice(), aesTables[1][2].slice(), aesTables[1][3].slice(), aesTables[1][4].slice()]];
  118. let i;
  119. let j;
  120. let tmp;
  121. const sbox = this._tables[0][4];
  122. const decTable = this._tables[1];
  123. const keyLen = key.length;
  124. let rcon = 1;
  125. if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
  126. throw new Error('Invalid aes key size');
  127. }
  128. const encKey = key.slice(0);
  129. const decKey = [];
  130. this._key = [encKey, decKey]; // schedule encryption keys
  131. for (i = keyLen; i < 4 * keyLen + 28; i++) {
  132. tmp = encKey[i - 1]; // apply sbox
  133. if (i % keyLen === 0 || keyLen === 8 && i % keyLen === 4) {
  134. tmp = sbox[tmp >>> 24] << 24 ^ sbox[tmp >> 16 & 255] << 16 ^ sbox[tmp >> 8 & 255] << 8 ^ sbox[tmp & 255]; // shift rows and add rcon
  135. if (i % keyLen === 0) {
  136. tmp = tmp << 8 ^ tmp >>> 24 ^ rcon << 24;
  137. rcon = rcon << 1 ^ (rcon >> 7) * 283;
  138. }
  139. }
  140. encKey[i] = encKey[i - keyLen] ^ tmp;
  141. } // schedule decryption keys
  142. for (j = 0; i; j++, i--) {
  143. tmp = encKey[j & 3 ? i : i - 4];
  144. if (i <= 4 || j < 4) {
  145. decKey[j] = tmp;
  146. } else {
  147. decKey[j] = decTable[0][sbox[tmp >>> 24]] ^ decTable[1][sbox[tmp >> 16 & 255]] ^ decTable[2][sbox[tmp >> 8 & 255]] ^ decTable[3][sbox[tmp & 255]];
  148. }
  149. }
  150. }
  151. /**
  152. * Decrypt 16 bytes, specified as four 32-bit words.
  153. *
  154. * @param {number} encrypted0 the first word to decrypt
  155. * @param {number} encrypted1 the second word to decrypt
  156. * @param {number} encrypted2 the third word to decrypt
  157. * @param {number} encrypted3 the fourth word to decrypt
  158. * @param {Int32Array} out the array to write the decrypted words
  159. * into
  160. * @param {number} offset the offset into the output array to start
  161. * writing results
  162. * @return {Array} The plaintext.
  163. */
  164. decrypt(encrypted0, encrypted1, encrypted2, encrypted3, out, offset) {
  165. const key = this._key[1]; // state variables a,b,c,d are loaded with pre-whitened data
  166. let a = encrypted0 ^ key[0];
  167. let b = encrypted3 ^ key[1];
  168. let c = encrypted2 ^ key[2];
  169. let d = encrypted1 ^ key[3];
  170. let a2;
  171. let b2;
  172. let c2; // key.length === 2 ?
  173. const nInnerRounds = key.length / 4 - 2;
  174. let i;
  175. let kIndex = 4;
  176. const table = this._tables[1]; // load up the tables
  177. const table0 = table[0];
  178. const table1 = table[1];
  179. const table2 = table[2];
  180. const table3 = table[3];
  181. const sbox = table[4]; // Inner rounds. Cribbed from OpenSSL.
  182. for (i = 0; i < nInnerRounds; i++) {
  183. a2 = table0[a >>> 24] ^ table1[b >> 16 & 255] ^ table2[c >> 8 & 255] ^ table3[d & 255] ^ key[kIndex];
  184. b2 = table0[b >>> 24] ^ table1[c >> 16 & 255] ^ table2[d >> 8 & 255] ^ table3[a & 255] ^ key[kIndex + 1];
  185. c2 = table0[c >>> 24] ^ table1[d >> 16 & 255] ^ table2[a >> 8 & 255] ^ table3[b & 255] ^ key[kIndex + 2];
  186. d = table0[d >>> 24] ^ table1[a >> 16 & 255] ^ table2[b >> 8 & 255] ^ table3[c & 255] ^ key[kIndex + 3];
  187. kIndex += 4;
  188. a = a2;
  189. b = b2;
  190. c = c2;
  191. } // Last round.
  192. for (i = 0; i < 4; i++) {
  193. out[(3 & -i) + offset] = sbox[a >>> 24] << 24 ^ sbox[b >> 16 & 255] << 16 ^ sbox[c >> 8 & 255] << 8 ^ sbox[d & 255] ^ key[kIndex++];
  194. a2 = a;
  195. a = b;
  196. b = c;
  197. c = d;
  198. d = a2;
  199. }
  200. }
  201. }
  202. /**
  203. * @file stream.js
  204. */
  205. /**
  206. * A lightweight readable stream implemention that handles event dispatching.
  207. *
  208. * @class Stream
  209. */
  210. var Stream = /*#__PURE__*/function () {
  211. function Stream() {
  212. this.listeners = {};
  213. }
  214. /**
  215. * Add a listener for a specified event type.
  216. *
  217. * @param {string} type the event name
  218. * @param {Function} listener the callback to be invoked when an event of
  219. * the specified type occurs
  220. */
  221. var _proto = Stream.prototype;
  222. _proto.on = function on(type, listener) {
  223. if (!this.listeners[type]) {
  224. this.listeners[type] = [];
  225. }
  226. this.listeners[type].push(listener);
  227. }
  228. /**
  229. * Remove a listener for a specified event type.
  230. *
  231. * @param {string} type the event name
  232. * @param {Function} listener a function previously registered for this
  233. * type of event through `on`
  234. * @return {boolean} if we could turn it off or not
  235. */
  236. ;
  237. _proto.off = function off(type, listener) {
  238. if (!this.listeners[type]) {
  239. return false;
  240. }
  241. var index = this.listeners[type].indexOf(listener); // TODO: which is better?
  242. // In Video.js we slice listener functions
  243. // on trigger so that it does not mess up the order
  244. // while we loop through.
  245. //
  246. // Here we slice on off so that the loop in trigger
  247. // can continue using it's old reference to loop without
  248. // messing up the order.
  249. this.listeners[type] = this.listeners[type].slice(0);
  250. this.listeners[type].splice(index, 1);
  251. return index > -1;
  252. }
  253. /**
  254. * Trigger an event of the specified type on this stream. Any additional
  255. * arguments to this function are passed as parameters to event listeners.
  256. *
  257. * @param {string} type the event name
  258. */
  259. ;
  260. _proto.trigger = function trigger(type) {
  261. var callbacks = this.listeners[type];
  262. if (!callbacks) {
  263. return;
  264. } // Slicing the arguments on every invocation of this method
  265. // can add a significant amount of overhead. Avoid the
  266. // intermediate object creation for the common case of a
  267. // single callback argument
  268. if (arguments.length === 2) {
  269. var length = callbacks.length;
  270. for (var i = 0; i < length; ++i) {
  271. callbacks[i].call(this, arguments[1]);
  272. }
  273. } else {
  274. var args = Array.prototype.slice.call(arguments, 1);
  275. var _length = callbacks.length;
  276. for (var _i = 0; _i < _length; ++_i) {
  277. callbacks[_i].apply(this, args);
  278. }
  279. }
  280. }
  281. /**
  282. * Destroys the stream and cleans up.
  283. */
  284. ;
  285. _proto.dispose = function dispose() {
  286. this.listeners = {};
  287. }
  288. /**
  289. * Forwards all `data` events on this stream to the destination stream. The
  290. * destination stream should provide a method `push` to receive the data
  291. * events as they arrive.
  292. *
  293. * @param {Stream} destination the stream that will receive all `data` events
  294. * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
  295. */
  296. ;
  297. _proto.pipe = function pipe(destination) {
  298. this.on('data', function (data) {
  299. destination.push(data);
  300. });
  301. };
  302. return Stream;
  303. }();
  304. /**
  305. * @file async-stream.js
  306. */
  307. /**
  308. * A wrapper around the Stream class to use setTimeout
  309. * and run stream "jobs" Asynchronously
  310. *
  311. * @class AsyncStream
  312. * @extends Stream
  313. */
  314. class AsyncStream extends Stream {
  315. constructor() {
  316. super(Stream);
  317. this.jobs = [];
  318. this.delay = 1;
  319. this.timeout_ = null;
  320. }
  321. /**
  322. * process an async job
  323. *
  324. * @private
  325. */
  326. processJob_() {
  327. this.jobs.shift()();
  328. if (this.jobs.length) {
  329. this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay);
  330. } else {
  331. this.timeout_ = null;
  332. }
  333. }
  334. /**
  335. * push a job into the stream
  336. *
  337. * @param {Function} job the job to push into the stream
  338. */
  339. push(job) {
  340. this.jobs.push(job);
  341. if (!this.timeout_) {
  342. this.timeout_ = setTimeout(this.processJob_.bind(this), this.delay);
  343. }
  344. }
  345. }
  346. /*! @name pkcs7 @version 1.0.4 @license Apache-2.0 */
  347. /**
  348. * Returns the subarray of a Uint8Array without PKCS#7 padding.
  349. *
  350. * @param padded {Uint8Array} unencrypted bytes that have been padded
  351. * @return {Uint8Array} the unpadded bytes
  352. * @see http://tools.ietf.org/html/rfc5652
  353. */
  354. function unpad(padded) {
  355. return padded.subarray(0, padded.byteLength - padded[padded.byteLength - 1]);
  356. }
  357. /**
  358. * @file decrypter.js
  359. *
  360. * An asynchronous implementation of AES-128 CBC decryption with
  361. * PKCS#7 padding.
  362. */
  363. /**
  364. * Convert network-order (big-endian) bytes into their little-endian
  365. * representation.
  366. */
  367. const ntoh = function (word) {
  368. return word << 24 | (word & 0xff00) << 8 | (word & 0xff0000) >> 8 | word >>> 24;
  369. };
  370. /**
  371. * Decrypt bytes using AES-128 with CBC and PKCS#7 padding.
  372. *
  373. * @param {Uint8Array} encrypted the encrypted bytes
  374. * @param {Uint32Array} key the bytes of the decryption key
  375. * @param {Uint32Array} initVector the initialization vector (IV) to
  376. * use for the first round of CBC.
  377. * @return {Uint8Array} the decrypted bytes
  378. *
  379. * @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
  380. * @see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29
  381. * @see https://tools.ietf.org/html/rfc2315
  382. */
  383. const decrypt = function (encrypted, key, initVector) {
  384. // word-level access to the encrypted bytes
  385. const encrypted32 = new Int32Array(encrypted.buffer, encrypted.byteOffset, encrypted.byteLength >> 2);
  386. const decipher = new AES(Array.prototype.slice.call(key)); // byte and word-level access for the decrypted output
  387. const decrypted = new Uint8Array(encrypted.byteLength);
  388. const decrypted32 = new Int32Array(decrypted.buffer); // temporary variables for working with the IV, encrypted, and
  389. // decrypted data
  390. let init0;
  391. let init1;
  392. let init2;
  393. let init3;
  394. let encrypted0;
  395. let encrypted1;
  396. let encrypted2;
  397. let encrypted3; // iteration variable
  398. let wordIx; // pull out the words of the IV to ensure we don't modify the
  399. // passed-in reference and easier access
  400. init0 = initVector[0];
  401. init1 = initVector[1];
  402. init2 = initVector[2];
  403. init3 = initVector[3]; // decrypt four word sequences, applying cipher-block chaining (CBC)
  404. // to each decrypted block
  405. for (wordIx = 0; wordIx < encrypted32.length; wordIx += 4) {
  406. // convert big-endian (network order) words into little-endian
  407. // (javascript order)
  408. encrypted0 = ntoh(encrypted32[wordIx]);
  409. encrypted1 = ntoh(encrypted32[wordIx + 1]);
  410. encrypted2 = ntoh(encrypted32[wordIx + 2]);
  411. encrypted3 = ntoh(encrypted32[wordIx + 3]); // decrypt the block
  412. decipher.decrypt(encrypted0, encrypted1, encrypted2, encrypted3, decrypted32, wordIx); // XOR with the IV, and restore network byte-order to obtain the
  413. // plaintext
  414. decrypted32[wordIx] = ntoh(decrypted32[wordIx] ^ init0);
  415. decrypted32[wordIx + 1] = ntoh(decrypted32[wordIx + 1] ^ init1);
  416. decrypted32[wordIx + 2] = ntoh(decrypted32[wordIx + 2] ^ init2);
  417. decrypted32[wordIx + 3] = ntoh(decrypted32[wordIx + 3] ^ init3); // setup the IV for the next round
  418. init0 = encrypted0;
  419. init1 = encrypted1;
  420. init2 = encrypted2;
  421. init3 = encrypted3;
  422. }
  423. return decrypted;
  424. };
  425. /**
  426. * The `Decrypter` class that manages decryption of AES
  427. * data through `AsyncStream` objects and the `decrypt`
  428. * function
  429. *
  430. * @param {Uint8Array} encrypted the encrypted bytes
  431. * @param {Uint32Array} key the bytes of the decryption key
  432. * @param {Uint32Array} initVector the initialization vector (IV) to
  433. * @param {Function} done the function to run when done
  434. * @class Decrypter
  435. */
  436. class Decrypter {
  437. constructor(encrypted, key, initVector, done) {
  438. const step = Decrypter.STEP;
  439. const encrypted32 = new Int32Array(encrypted.buffer);
  440. const decrypted = new Uint8Array(encrypted.byteLength);
  441. let i = 0;
  442. this.asyncStream_ = new AsyncStream(); // split up the encryption job and do the individual chunks asynchronously
  443. this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted));
  444. for (i = step; i < encrypted32.length; i += step) {
  445. initVector = new Uint32Array([ntoh(encrypted32[i - 4]), ntoh(encrypted32[i - 3]), ntoh(encrypted32[i - 2]), ntoh(encrypted32[i - 1])]);
  446. this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted));
  447. } // invoke the done() callback when everything is finished
  448. this.asyncStream_.push(function () {
  449. // remove pkcs#7 padding from the decrypted bytes
  450. done(null, unpad(decrypted));
  451. });
  452. }
  453. /**
  454. * a getter for step the maximum number of bytes to process at one time
  455. *
  456. * @return {number} the value of step 32000
  457. */
  458. static get STEP() {
  459. // 4 * 8000;
  460. return 32000;
  461. }
  462. /**
  463. * @private
  464. */
  465. decryptChunk_(encrypted, key, initVector, decrypted) {
  466. return function () {
  467. const bytes = decrypt(encrypted, key, initVector);
  468. decrypted.set(bytes, encrypted.byteOffset);
  469. };
  470. }
  471. }
  472. exports.AsyncStream = AsyncStream;
  473. exports.Decrypter = Decrypter;
  474. exports.decrypt = decrypt;
  475. Object.defineProperty(exports, '__esModule', { value: true });
  476. }));