decrypter.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /**
  2. * @file decrypter.js
  3. *
  4. * An asynchronous implementation of AES-128 CBC decryption with
  5. * PKCS#7 padding.
  6. */
  7. 'use strict';
  8. Object.defineProperty(exports, '__esModule', {
  9. value: true
  10. });
  11. var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
  12. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  13. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
  14. var _aes = require('./aes');
  15. var _aes2 = _interopRequireDefault(_aes);
  16. var _asyncStream = require('./async-stream');
  17. var _asyncStream2 = _interopRequireDefault(_asyncStream);
  18. var _pkcs7 = require('pkcs7');
  19. /**
  20. * Convert network-order (big-endian) bytes into their little-endian
  21. * representation.
  22. */
  23. var ntoh = function ntoh(word) {
  24. return word << 24 | (word & 0xff00) << 8 | (word & 0xff0000) >> 8 | word >>> 24;
  25. };
  26. /**
  27. * Decrypt bytes using AES-128 with CBC and PKCS#7 padding.
  28. *
  29. * @param {Uint8Array} encrypted the encrypted bytes
  30. * @param {Uint32Array} key the bytes of the decryption key
  31. * @param {Uint32Array} initVector the initialization vector (IV) to
  32. * use for the first round of CBC.
  33. * @return {Uint8Array} the decrypted bytes
  34. *
  35. * @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
  36. * @see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29
  37. * @see https://tools.ietf.org/html/rfc2315
  38. */
  39. var decrypt = function decrypt(encrypted, key, initVector) {
  40. // word-level access to the encrypted bytes
  41. var encrypted32 = new Int32Array(encrypted.buffer, encrypted.byteOffset, encrypted.byteLength >> 2);
  42. var decipher = new _aes2['default'](Array.prototype.slice.call(key));
  43. // byte and word-level access for the decrypted output
  44. var decrypted = new Uint8Array(encrypted.byteLength);
  45. var decrypted32 = new Int32Array(decrypted.buffer);
  46. // temporary variables for working with the IV, encrypted, and
  47. // decrypted data
  48. var init0 = undefined;
  49. var init1 = undefined;
  50. var init2 = undefined;
  51. var init3 = undefined;
  52. var encrypted0 = undefined;
  53. var encrypted1 = undefined;
  54. var encrypted2 = undefined;
  55. var encrypted3 = undefined;
  56. // iteration variable
  57. var wordIx = undefined;
  58. // pull out the words of the IV to ensure we don't modify the
  59. // passed-in reference and easier access
  60. init0 = initVector[0];
  61. init1 = initVector[1];
  62. init2 = initVector[2];
  63. init3 = initVector[3];
  64. // decrypt four word sequences, applying cipher-block chaining (CBC)
  65. // to each decrypted block
  66. for (wordIx = 0; wordIx < encrypted32.length; wordIx += 4) {
  67. // convert big-endian (network order) words into little-endian
  68. // (javascript order)
  69. encrypted0 = ntoh(encrypted32[wordIx]);
  70. encrypted1 = ntoh(encrypted32[wordIx + 1]);
  71. encrypted2 = ntoh(encrypted32[wordIx + 2]);
  72. encrypted3 = ntoh(encrypted32[wordIx + 3]);
  73. // decrypt the block
  74. decipher.decrypt(encrypted0, encrypted1, encrypted2, encrypted3, decrypted32, wordIx);
  75. // XOR with the IV, and restore network byte-order to obtain the
  76. // plaintext
  77. decrypted32[wordIx] = ntoh(decrypted32[wordIx] ^ init0);
  78. decrypted32[wordIx + 1] = ntoh(decrypted32[wordIx + 1] ^ init1);
  79. decrypted32[wordIx + 2] = ntoh(decrypted32[wordIx + 2] ^ init2);
  80. decrypted32[wordIx + 3] = ntoh(decrypted32[wordIx + 3] ^ init3);
  81. // setup the IV for the next round
  82. init0 = encrypted0;
  83. init1 = encrypted1;
  84. init2 = encrypted2;
  85. init3 = encrypted3;
  86. }
  87. return decrypted;
  88. };
  89. exports.decrypt = decrypt;
  90. /**
  91. * The `Decrypter` class that manages decryption of AES
  92. * data through `AsyncStream` objects and the `decrypt`
  93. * function
  94. *
  95. * @param {Uint8Array} encrypted the encrypted bytes
  96. * @param {Uint32Array} key the bytes of the decryption key
  97. * @param {Uint32Array} initVector the initialization vector (IV) to
  98. * @param {Function} done the function to run when done
  99. * @class Decrypter
  100. */
  101. var Decrypter = (function () {
  102. function Decrypter(encrypted, key, initVector, done) {
  103. _classCallCheck(this, Decrypter);
  104. var step = Decrypter.STEP;
  105. var encrypted32 = new Int32Array(encrypted.buffer);
  106. var decrypted = new Uint8Array(encrypted.byteLength);
  107. var i = 0;
  108. this.asyncStream_ = new _asyncStream2['default']();
  109. // split up the encryption job and do the individual chunks asynchronously
  110. this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted));
  111. for (i = step; i < encrypted32.length; i += step) {
  112. initVector = new Uint32Array([ntoh(encrypted32[i - 4]), ntoh(encrypted32[i - 3]), ntoh(encrypted32[i - 2]), ntoh(encrypted32[i - 1])]);
  113. this.asyncStream_.push(this.decryptChunk_(encrypted32.subarray(i, i + step), key, initVector, decrypted));
  114. }
  115. // invoke the done() callback when everything is finished
  116. this.asyncStream_.push(function () {
  117. // remove pkcs#7 padding from the decrypted bytes
  118. done(null, (0, _pkcs7.unpad)(decrypted));
  119. });
  120. }
  121. /**
  122. * a getter for step the maximum number of bytes to process at one time
  123. *
  124. * @return {Number} the value of step 32000
  125. */
  126. _createClass(Decrypter, [{
  127. key: 'decryptChunk_',
  128. /**
  129. * @private
  130. */
  131. value: function decryptChunk_(encrypted, key, initVector, decrypted) {
  132. return function () {
  133. var bytes = decrypt(encrypted, key, initVector);
  134. decrypted.set(bytes, encrypted.byteOffset);
  135. };
  136. }
  137. }], [{
  138. key: 'STEP',
  139. get: function get() {
  140. // 4 * 8000;
  141. return 32000;
  142. }
  143. }]);
  144. return Decrypter;
  145. })();
  146. exports.Decrypter = Decrypter;
  147. exports['default'] = {
  148. Decrypter: Decrypter,
  149. decrypt: decrypt
  150. };