decode.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. 'use strict';
  2. var crypto = require('crypto');
  3. var bigInt = require('big-integer');
  4. var zlib = require('zlib');
  5. /**
  6. * Decodes the data.
  7. * @param {number} id
  8. * @param {(Buffer|string)} iv
  9. * @param {(Buffer|string)} data
  10. * @param {function(Error, Buffer=)} done
  11. */
  12. module.exports = function(id, iv, data, done) {
  13. try {
  14. _decompress(_decrypt(id, iv, data), done);
  15. } catch(e) {
  16. done(e);
  17. }
  18. };
  19. /**
  20. * Decrypts the data.
  21. * @private
  22. * @param {number} id
  23. * @param {(Buffer|string)} iv
  24. * @param {(Buffer|string)} data
  25. * @return {Buffer}
  26. */
  27. function _decrypt(id, iv, data) {
  28. if (typeof iv === 'string') iv = new Buffer(iv, 'base64');
  29. if (typeof data === 'string') data = new Buffer(data, 'base64');
  30. var decipher = crypto.createDecipheriv('aes-256-cbc', _key(id), iv);
  31. decipher.setAutoPadding(false);
  32. return Buffer.concat([decipher.update(data), decipher.final()]);
  33. }
  34. /**
  35. * Decompresses the data.
  36. * @private
  37. * @param {Buffer} data
  38. * @param {function(Error, Buffer=)} done
  39. */
  40. function _decompress(data, done) {
  41. try {
  42. zlib.inflate(data, done);
  43. } catch(e) {
  44. done(undefined, data);
  45. }
  46. }
  47. /**
  48. * Generates a key.
  49. * @private
  50. * @param {number} subtitleId
  51. * @return {Buffer}
  52. */
  53. function _key(subtitleId) {
  54. var hash = _secret(20, 97, 1, 2) + _magic(subtitleId);
  55. var result = new Buffer(32);
  56. result.fill(0);
  57. crypto.createHash('sha1').update(hash).digest().copy(result);
  58. return result;
  59. }
  60. /**
  61. * Generates a magic number.
  62. * @private
  63. * @param {number} subtitleId
  64. * @return {number}
  65. */
  66. function _magic(subtitleId) {
  67. var base = Math.floor(Math.sqrt(6.9) * Math.pow(2, 25));
  68. var hash = bigInt(base).xor(subtitleId);
  69. var multipliedHash = bigInt(hash).multiply(32);
  70. return bigInt(hash).xor(hash >> 3).xor(multipliedHash).toJSNumber();
  71. }
  72. /**
  73. * Generates a secret string based on a Fibonacci sequence.
  74. * @private
  75. * @param {number} size
  76. * @param {number} modulo
  77. * @param {number} firstSeed
  78. * @param {number} secondSeed
  79. * @return {string}
  80. */
  81. function _secret(size, modulo, firstSeed, secondSeed) {
  82. var currentValue = firstSeed + secondSeed;
  83. var previousValue = secondSeed;
  84. var result = '';
  85. for (var i = 0; i < size; i += 1) {
  86. var oldValue = currentValue;
  87. result += String.fromCharCode(currentValue % modulo + 33);
  88. currentValue += previousValue;
  89. previousValue = oldValue;
  90. }
  91. return result;
  92. }