decode.ts 2.1 KB

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