decode.ts 2.1 KB

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