Home Reference Source

src/crypt/decrypter.js

  1. import AESCrypto from './aes-crypto';
  2. import FastAESKey from './fast-aes-key';
  3. import AESDecryptor from './aes-decryptor';
  4.  
  5. import { ErrorTypes, ErrorDetails } from '../errors';
  6. import { logger } from '../utils/logger';
  7.  
  8. import Event from '../events';
  9.  
  10. import { getSelfScope } from '../utils/get-self-scope';
  11.  
  12. // see https://stackoverflow.com/a/11237259/589493
  13. const global = getSelfScope(); // safeguard for code that might run both on worker and main thread
  14.  
  15. class Decrypter {
  16. constructor (observer, config, { removePKCS7Padding = true } = {}) {
  17. this.logEnabled = true;
  18. this.observer = observer;
  19. this.config = config;
  20. this.removePKCS7Padding = removePKCS7Padding;
  21. // built in decryptor expects PKCS7 padding
  22. if (removePKCS7Padding) {
  23. try {
  24. const browserCrypto = global.crypto;
  25. if (browserCrypto) {
  26. this.subtle = browserCrypto.subtle || browserCrypto.webkitSubtle;
  27. }
  28. } catch (e) {}
  29. }
  30. this.disableWebCrypto = !this.subtle;
  31. }
  32.  
  33. isSync () {
  34. return (this.disableWebCrypto && this.config.enableSoftwareAES);
  35. }
  36.  
  37. decrypt (data, key, iv, callback) {
  38. if (this.disableWebCrypto && this.config.enableSoftwareAES) {
  39. if (this.logEnabled) {
  40. logger.log('JS AES decrypt');
  41. this.logEnabled = false;
  42. }
  43. let decryptor = this.decryptor;
  44. if (!decryptor) {
  45. this.decryptor = decryptor = new AESDecryptor();
  46. }
  47.  
  48. decryptor.expandKey(key);
  49. callback(decryptor.decrypt(data, 0, iv, this.removePKCS7Padding));
  50. } else {
  51. if (this.logEnabled) {
  52. logger.log('WebCrypto AES decrypt');
  53. this.logEnabled = false;
  54. }
  55. const subtle = this.subtle;
  56. if (this.key !== key) {
  57. this.key = key;
  58. this.fastAesKey = new FastAESKey(subtle, key);
  59. }
  60.  
  61. this.fastAesKey.expandKey()
  62. .then((aesKey) => {
  63. // decrypt using web crypto
  64. let crypto = new AESCrypto(subtle, iv);
  65. crypto.decrypt(data, aesKey)
  66. .catch((err) => {
  67. this.onWebCryptoError(err, data, key, iv, callback);
  68. })
  69. .then((result) => {
  70. callback(result);
  71. });
  72. })
  73. .catch((err) => {
  74. this.onWebCryptoError(err, data, key, iv, callback);
  75. });
  76. }
  77. }
  78.  
  79. onWebCryptoError (err, data, key, iv, callback) {
  80. if (this.config.enableSoftwareAES) {
  81. logger.log('WebCrypto Error, disable WebCrypto API');
  82. this.disableWebCrypto = true;
  83. this.logEnabled = true;
  84. this.decrypt(data, key, iv, callback);
  85. } else {
  86. logger.error(`decrypting error : ${err.message}`);
  87. this.observer.trigger(Event.ERROR, { type: ErrorTypes.MEDIA_ERROR, details: ErrorDetails.FRAG_DECRYPT_ERROR, fatal: true, reason: err.message });
  88. }
  89. }
  90.  
  91. destroy () {
  92. let decryptor = this.decryptor;
  93. if (decryptor) {
  94. decryptor.destroy();
  95. this.decryptor = undefined;
  96. }
  97. }
  98. }
  99.  
  100. export default Decrypter;