Merge pull request #16959 from Snuffleupagus/rm-CipherTransformFactory-closure
Remove the closure from the `CipherTransformFactory` class
This commit is contained in:
		
						commit
						98671c3618
					
				@ -1418,14 +1418,14 @@ class CipherTransform {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const CipherTransformFactory = (function CipherTransformFactoryClosure() {
 | 
					class CipherTransformFactory {
 | 
				
			||||||
  const defaultPasswordBytes = new Uint8Array([
 | 
					  static #defaultPasswordBytes = new Uint8Array([
 | 
				
			||||||
    0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56,
 | 
					    0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, 0x64, 0x00, 0x4e, 0x56,
 | 
				
			||||||
    0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,
 | 
					    0xff, 0xfa, 0x01, 0x08, 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,
 | 
				
			||||||
    0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a,
 | 
					    0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a,
 | 
				
			||||||
  ]);
 | 
					  ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function createEncryptionKey20(
 | 
					  #createEncryptionKey20(
 | 
				
			||||||
    revision,
 | 
					    revision,
 | 
				
			||||||
    password,
 | 
					    password,
 | 
				
			||||||
    ownerPassword,
 | 
					    ownerPassword,
 | 
				
			||||||
@ -1471,7 +1471,7 @@ const CipherTransformFactory = (function CipherTransformFactoryClosure() {
 | 
				
			|||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function prepareKeyData(
 | 
					  #prepareKeyData(
 | 
				
			||||||
    fileId,
 | 
					    fileId,
 | 
				
			||||||
    password,
 | 
					    password,
 | 
				
			||||||
    ownerPassword,
 | 
					    ownerPassword,
 | 
				
			||||||
@ -1494,7 +1494,7 @@ const CipherTransformFactory = (function CipherTransformFactoryClosure() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    j = 0;
 | 
					    j = 0;
 | 
				
			||||||
    while (i < 32) {
 | 
					    while (i < 32) {
 | 
				
			||||||
      hashData[i++] = defaultPasswordBytes[j++];
 | 
					      hashData[i++] = CipherTransformFactory.#defaultPasswordBytes[j++];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // as now the padded password in the hashData[0..i]
 | 
					    // as now the padded password in the hashData[0..i]
 | 
				
			||||||
    for (j = 0, n = ownerPassword.length; j < n; ++j) {
 | 
					    for (j = 0, n = ownerPassword.length; j < n; ++j) {
 | 
				
			||||||
@ -1525,7 +1525,7 @@ const CipherTransformFactory = (function CipherTransformFactoryClosure() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (revision >= 3) {
 | 
					    if (revision >= 3) {
 | 
				
			||||||
      for (i = 0; i < 32; ++i) {
 | 
					      for (i = 0; i < 32; ++i) {
 | 
				
			||||||
        hashData[i] = defaultPasswordBytes[i];
 | 
					        hashData[i] = CipherTransformFactory.#defaultPasswordBytes[i];
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      for (j = 0, n = fileId.length; j < n; ++j) {
 | 
					      for (j = 0, n = fileId.length; j < n; ++j) {
 | 
				
			||||||
        hashData[i++] = fileId[j];
 | 
					        hashData[i++] = fileId[j];
 | 
				
			||||||
@ -1548,7 +1548,9 @@ const CipherTransformFactory = (function CipherTransformFactoryClosure() {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      cipher = new ARCFourCipher(encryptionKey);
 | 
					      cipher = new ARCFourCipher(encryptionKey);
 | 
				
			||||||
      checkData = cipher.encryptBlock(defaultPasswordBytes);
 | 
					      checkData = cipher.encryptBlock(
 | 
				
			||||||
 | 
					        CipherTransformFactory.#defaultPasswordBytes
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
      for (j = 0, n = checkData.length; j < n; ++j) {
 | 
					      for (j = 0, n = checkData.length; j < n; ++j) {
 | 
				
			||||||
        if (userPassword[j] !== checkData[j]) {
 | 
					        if (userPassword[j] !== checkData[j]) {
 | 
				
			||||||
          return null;
 | 
					          return null;
 | 
				
			||||||
@ -1558,7 +1560,7 @@ const CipherTransformFactory = (function CipherTransformFactoryClosure() {
 | 
				
			|||||||
    return encryptionKey;
 | 
					    return encryptionKey;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function decodeUserPassword(password, ownerPassword, revision, keyLength) {
 | 
					  #decodeUserPassword(password, ownerPassword, revision, keyLength) {
 | 
				
			||||||
    const hashData = new Uint8Array(32);
 | 
					    const hashData = new Uint8Array(32);
 | 
				
			||||||
    let i = 0;
 | 
					    let i = 0;
 | 
				
			||||||
    const n = Math.min(32, password.length);
 | 
					    const n = Math.min(32, password.length);
 | 
				
			||||||
@ -1567,7 +1569,7 @@ const CipherTransformFactory = (function CipherTransformFactoryClosure() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    let j = 0;
 | 
					    let j = 0;
 | 
				
			||||||
    while (i < 32) {
 | 
					    while (i < 32) {
 | 
				
			||||||
      hashData[i++] = defaultPasswordBytes[j++];
 | 
					      hashData[i++] = CipherTransformFactory.#defaultPasswordBytes[j++];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let hash = calculateMD5(hashData, 0, i);
 | 
					    let hash = calculateMD5(hashData, 0, i);
 | 
				
			||||||
    const keyLengthInBytes = keyLength >> 3;
 | 
					    const keyLengthInBytes = keyLength >> 3;
 | 
				
			||||||
@ -1595,9 +1597,7 @@ const CipherTransformFactory = (function CipherTransformFactoryClosure() {
 | 
				
			|||||||
    return userPassword;
 | 
					    return userPassword;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const identityName = Name.get("Identity");
 | 
					  #buildObjectKey(num, gen, encryptionKey, isAes = false) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  function buildObjectKey(num, gen, encryptionKey, isAes = false) {
 | 
					 | 
				
			||||||
    const key = new Uint8Array(encryptionKey.length + 9);
 | 
					    const key = new Uint8Array(encryptionKey.length + 9);
 | 
				
			||||||
    const n = encryptionKey.length;
 | 
					    const n = encryptionKey.length;
 | 
				
			||||||
    let i;
 | 
					    let i;
 | 
				
			||||||
@ -1619,242 +1619,229 @@ const CipherTransformFactory = (function CipherTransformFactoryClosure() {
 | 
				
			|||||||
    return hash.subarray(0, Math.min(encryptionKey.length + 5, 16));
 | 
					    return hash.subarray(0, Math.min(encryptionKey.length + 5, 16));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  function buildCipherConstructor(cf, name, num, gen, key) {
 | 
					  #buildCipherConstructor(cf, name, num, gen, key) {
 | 
				
			||||||
    if (!(name instanceof Name)) {
 | 
					    if (!(name instanceof Name)) {
 | 
				
			||||||
      throw new FormatError("Invalid crypt filter name.");
 | 
					      throw new FormatError("Invalid crypt filter name.");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    const self = this;
 | 
				
			||||||
    const cryptFilter = cf.get(name.name);
 | 
					    const cryptFilter = cf.get(name.name);
 | 
				
			||||||
    let cfm;
 | 
					    const cfm = cryptFilter?.get("CFM");
 | 
				
			||||||
    if (cryptFilter !== null && cryptFilter !== undefined) {
 | 
					
 | 
				
			||||||
      cfm = cryptFilter.get("CFM");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!cfm || cfm.name === "None") {
 | 
					    if (!cfm || cfm.name === "None") {
 | 
				
			||||||
      return function cipherTransformFactoryBuildCipherConstructorNone() {
 | 
					      return function () {
 | 
				
			||||||
        return new NullCipher();
 | 
					        return new NullCipher();
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (cfm.name === "V2") {
 | 
					    if (cfm.name === "V2") {
 | 
				
			||||||
      return function cipherTransformFactoryBuildCipherConstructorV2() {
 | 
					      return function () {
 | 
				
			||||||
        return new ARCFourCipher(
 | 
					        return new ARCFourCipher(
 | 
				
			||||||
          buildObjectKey(num, gen, key, /* isAes = */ false)
 | 
					          self.#buildObjectKey(num, gen, key, /* isAes = */ false)
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (cfm.name === "AESV2") {
 | 
					    if (cfm.name === "AESV2") {
 | 
				
			||||||
      return function cipherTransformFactoryBuildCipherConstructorAESV2() {
 | 
					      return function () {
 | 
				
			||||||
        return new AES128Cipher(
 | 
					        return new AES128Cipher(
 | 
				
			||||||
          buildObjectKey(num, gen, key, /* isAes = */ true)
 | 
					          self.#buildObjectKey(num, gen, key, /* isAes = */ true)
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (cfm.name === "AESV3") {
 | 
					    if (cfm.name === "AESV3") {
 | 
				
			||||||
      return function cipherTransformFactoryBuildCipherConstructorAESV3() {
 | 
					      return function () {
 | 
				
			||||||
        return new AES256Cipher(key);
 | 
					        return new AES256Cipher(key);
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    throw new FormatError("Unknown crypto method");
 | 
					    throw new FormatError("Unknown crypto method");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // eslint-disable-next-line no-shadow
 | 
					  constructor(dict, fileId, password) {
 | 
				
			||||||
  class CipherTransformFactory {
 | 
					    const filter = dict.get("Filter");
 | 
				
			||||||
    constructor(dict, fileId, password) {
 | 
					    if (!isName(filter, "Standard")) {
 | 
				
			||||||
      const filter = dict.get("Filter");
 | 
					      throw new FormatError("unknown encryption method");
 | 
				
			||||||
      if (!isName(filter, "Standard")) {
 | 
					    }
 | 
				
			||||||
        throw new FormatError("unknown encryption method");
 | 
					    this.filterName = filter.name;
 | 
				
			||||||
      }
 | 
					    this.dict = dict;
 | 
				
			||||||
      this.filterName = filter.name;
 | 
					    const algorithm = dict.get("V");
 | 
				
			||||||
      this.dict = dict;
 | 
					    if (
 | 
				
			||||||
      const algorithm = dict.get("V");
 | 
					      !Number.isInteger(algorithm) ||
 | 
				
			||||||
      if (
 | 
					      (algorithm !== 1 && algorithm !== 2 && algorithm !== 4 && algorithm !== 5)
 | 
				
			||||||
        !Number.isInteger(algorithm) ||
 | 
					    ) {
 | 
				
			||||||
        (algorithm !== 1 &&
 | 
					      throw new FormatError("unsupported encryption algorithm");
 | 
				
			||||||
          algorithm !== 2 &&
 | 
					    }
 | 
				
			||||||
          algorithm !== 4 &&
 | 
					    this.algorithm = algorithm;
 | 
				
			||||||
          algorithm !== 5)
 | 
					    let keyLength = dict.get("Length");
 | 
				
			||||||
      ) {
 | 
					    if (!keyLength) {
 | 
				
			||||||
        throw new FormatError("unsupported encryption algorithm");
 | 
					      // Spec asks to rely on encryption dictionary's Length entry, however
 | 
				
			||||||
      }
 | 
					      // some PDFs don't have it. Trying to recover.
 | 
				
			||||||
      this.algorithm = algorithm;
 | 
					      if (algorithm <= 3) {
 | 
				
			||||||
      let keyLength = dict.get("Length");
 | 
					        // For 1 and 2 it's fixed to 40-bit, for 3 40-bit is a minimal value.
 | 
				
			||||||
      if (!keyLength) {
 | 
					        keyLength = 40;
 | 
				
			||||||
        // Spec asks to rely on encryption dictionary's Length entry, however
 | 
					 | 
				
			||||||
        // some PDFs don't have it. Trying to recover.
 | 
					 | 
				
			||||||
        if (algorithm <= 3) {
 | 
					 | 
				
			||||||
          // For 1 and 2 it's fixed to 40-bit, for 3 40-bit is a minimal value.
 | 
					 | 
				
			||||||
          keyLength = 40;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          // Trying to find default handler -- it usually has Length.
 | 
					 | 
				
			||||||
          const cfDict = dict.get("CF");
 | 
					 | 
				
			||||||
          const streamCryptoName = dict.get("StmF");
 | 
					 | 
				
			||||||
          if (cfDict instanceof Dict && streamCryptoName instanceof Name) {
 | 
					 | 
				
			||||||
            cfDict.suppressEncryption = true; // See comment below.
 | 
					 | 
				
			||||||
            const handlerDict = cfDict.get(streamCryptoName.name);
 | 
					 | 
				
			||||||
            keyLength = handlerDict?.get("Length") || 128;
 | 
					 | 
				
			||||||
            if (keyLength < 40) {
 | 
					 | 
				
			||||||
              // Sometimes it's incorrect value of bits, generators specify
 | 
					 | 
				
			||||||
              // bytes.
 | 
					 | 
				
			||||||
              keyLength <<= 3;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (
 | 
					 | 
				
			||||||
        !Number.isInteger(keyLength) ||
 | 
					 | 
				
			||||||
        keyLength < 40 ||
 | 
					 | 
				
			||||||
        keyLength % 8 !== 0
 | 
					 | 
				
			||||||
      ) {
 | 
					 | 
				
			||||||
        throw new FormatError("invalid key length");
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const ownerBytes = stringToBytes(dict.get("O")),
 | 
					 | 
				
			||||||
        userBytes = stringToBytes(dict.get("U"));
 | 
					 | 
				
			||||||
      // prepare keys
 | 
					 | 
				
			||||||
      const ownerPassword = ownerBytes.subarray(0, 32);
 | 
					 | 
				
			||||||
      const userPassword = userBytes.subarray(0, 32);
 | 
					 | 
				
			||||||
      const flags = dict.get("P");
 | 
					 | 
				
			||||||
      const revision = dict.get("R");
 | 
					 | 
				
			||||||
      // meaningful when V is 4 or 5
 | 
					 | 
				
			||||||
      const encryptMetadata =
 | 
					 | 
				
			||||||
        (algorithm === 4 || algorithm === 5) &&
 | 
					 | 
				
			||||||
        dict.get("EncryptMetadata") !== false;
 | 
					 | 
				
			||||||
      this.encryptMetadata = encryptMetadata;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      const fileIdBytes = stringToBytes(fileId);
 | 
					 | 
				
			||||||
      let passwordBytes;
 | 
					 | 
				
			||||||
      if (password) {
 | 
					 | 
				
			||||||
        if (revision === 6) {
 | 
					 | 
				
			||||||
          try {
 | 
					 | 
				
			||||||
            password = utf8StringToString(password);
 | 
					 | 
				
			||||||
          } catch {
 | 
					 | 
				
			||||||
            warn(
 | 
					 | 
				
			||||||
              "CipherTransformFactory: Unable to convert UTF8 encoded password."
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        passwordBytes = stringToBytes(password);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      let encryptionKey;
 | 
					 | 
				
			||||||
      if (algorithm !== 5) {
 | 
					 | 
				
			||||||
        encryptionKey = prepareKeyData(
 | 
					 | 
				
			||||||
          fileIdBytes,
 | 
					 | 
				
			||||||
          passwordBytes,
 | 
					 | 
				
			||||||
          ownerPassword,
 | 
					 | 
				
			||||||
          userPassword,
 | 
					 | 
				
			||||||
          flags,
 | 
					 | 
				
			||||||
          revision,
 | 
					 | 
				
			||||||
          keyLength,
 | 
					 | 
				
			||||||
          encryptMetadata
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        const ownerValidationSalt = ownerBytes.subarray(32, 40);
 | 
					        // Trying to find default handler -- it usually has Length.
 | 
				
			||||||
        const ownerKeySalt = ownerBytes.subarray(40, 48);
 | 
					        const cfDict = dict.get("CF");
 | 
				
			||||||
        const uBytes = userBytes.subarray(0, 48);
 | 
					        const streamCryptoName = dict.get("StmF");
 | 
				
			||||||
        const userValidationSalt = userBytes.subarray(32, 40);
 | 
					        if (cfDict instanceof Dict && streamCryptoName instanceof Name) {
 | 
				
			||||||
        const userKeySalt = userBytes.subarray(40, 48);
 | 
					          cfDict.suppressEncryption = true; // See comment below.
 | 
				
			||||||
        const ownerEncryption = stringToBytes(dict.get("OE"));
 | 
					          const handlerDict = cfDict.get(streamCryptoName.name);
 | 
				
			||||||
        const userEncryption = stringToBytes(dict.get("UE"));
 | 
					          keyLength = handlerDict?.get("Length") || 128;
 | 
				
			||||||
        const perms = stringToBytes(dict.get("Perms"));
 | 
					          if (keyLength < 40) {
 | 
				
			||||||
        encryptionKey = createEncryptionKey20(
 | 
					            // Sometimes it's incorrect value of bits, generators specify
 | 
				
			||||||
          revision,
 | 
					            // bytes.
 | 
				
			||||||
          passwordBytes,
 | 
					            keyLength <<= 3;
 | 
				
			||||||
          ownerPassword,
 | 
					          }
 | 
				
			||||||
          ownerValidationSalt,
 | 
					 | 
				
			||||||
          ownerKeySalt,
 | 
					 | 
				
			||||||
          uBytes,
 | 
					 | 
				
			||||||
          userPassword,
 | 
					 | 
				
			||||||
          userValidationSalt,
 | 
					 | 
				
			||||||
          userKeySalt,
 | 
					 | 
				
			||||||
          ownerEncryption,
 | 
					 | 
				
			||||||
          userEncryption,
 | 
					 | 
				
			||||||
          perms
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (!encryptionKey && !password) {
 | 
					 | 
				
			||||||
        throw new PasswordException(
 | 
					 | 
				
			||||||
          "No password given",
 | 
					 | 
				
			||||||
          PasswordResponses.NEED_PASSWORD
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
      } else if (!encryptionKey && password) {
 | 
					 | 
				
			||||||
        // Attempting use the password as an owner password
 | 
					 | 
				
			||||||
        const decodedPassword = decodeUserPassword(
 | 
					 | 
				
			||||||
          passwordBytes,
 | 
					 | 
				
			||||||
          ownerPassword,
 | 
					 | 
				
			||||||
          revision,
 | 
					 | 
				
			||||||
          keyLength
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
        encryptionKey = prepareKeyData(
 | 
					 | 
				
			||||||
          fileIdBytes,
 | 
					 | 
				
			||||||
          decodedPassword,
 | 
					 | 
				
			||||||
          ownerPassword,
 | 
					 | 
				
			||||||
          userPassword,
 | 
					 | 
				
			||||||
          flags,
 | 
					 | 
				
			||||||
          revision,
 | 
					 | 
				
			||||||
          keyLength,
 | 
					 | 
				
			||||||
          encryptMetadata
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (!encryptionKey) {
 | 
					 | 
				
			||||||
        throw new PasswordException(
 | 
					 | 
				
			||||||
          "Incorrect Password",
 | 
					 | 
				
			||||||
          PasswordResponses.INCORRECT_PASSWORD
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      this.encryptionKey = encryptionKey;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (algorithm >= 4) {
 | 
					 | 
				
			||||||
        const cf = dict.get("CF");
 | 
					 | 
				
			||||||
        if (cf instanceof Dict) {
 | 
					 | 
				
			||||||
          // The 'CF' dictionary itself should not be encrypted, and by setting
 | 
					 | 
				
			||||||
          // `suppressEncryption` we can prevent an infinite loop inside of
 | 
					 | 
				
			||||||
          // `XRef_fetchUncompressed` if the dictionary contains indirect
 | 
					 | 
				
			||||||
          // objects (fixes issue7665.pdf).
 | 
					 | 
				
			||||||
          cf.suppressEncryption = true;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        this.cf = cf;
 | 
					 | 
				
			||||||
        this.stmf = dict.get("StmF") || identityName;
 | 
					 | 
				
			||||||
        this.strf = dict.get("StrF") || identityName;
 | 
					 | 
				
			||||||
        this.eff = dict.get("EFF") || this.stmf;
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (!Number.isInteger(keyLength) || keyLength < 40 || keyLength % 8 !== 0) {
 | 
				
			||||||
 | 
					      throw new FormatError("invalid key length");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    createCipherTransform(num, gen) {
 | 
					    const ownerBytes = stringToBytes(dict.get("O")),
 | 
				
			||||||
      if (this.algorithm === 4 || this.algorithm === 5) {
 | 
					      userBytes = stringToBytes(dict.get("U"));
 | 
				
			||||||
        return new CipherTransform(
 | 
					    // prepare keys
 | 
				
			||||||
          buildCipherConstructor(
 | 
					    const ownerPassword = ownerBytes.subarray(0, 32);
 | 
				
			||||||
            this.cf,
 | 
					    const userPassword = userBytes.subarray(0, 32);
 | 
				
			||||||
            this.strf,
 | 
					    const flags = dict.get("P");
 | 
				
			||||||
            num,
 | 
					    const revision = dict.get("R");
 | 
				
			||||||
            gen,
 | 
					    // meaningful when V is 4 or 5
 | 
				
			||||||
            this.encryptionKey
 | 
					    const encryptMetadata =
 | 
				
			||||||
          ),
 | 
					      (algorithm === 4 || algorithm === 5) &&
 | 
				
			||||||
          buildCipherConstructor(
 | 
					      dict.get("EncryptMetadata") !== false;
 | 
				
			||||||
            this.cf,
 | 
					    this.encryptMetadata = encryptMetadata;
 | 
				
			||||||
            this.stmf,
 | 
					
 | 
				
			||||||
            num,
 | 
					    const fileIdBytes = stringToBytes(fileId);
 | 
				
			||||||
            gen,
 | 
					    let passwordBytes;
 | 
				
			||||||
            this.encryptionKey
 | 
					    if (password) {
 | 
				
			||||||
          )
 | 
					      if (revision === 6) {
 | 
				
			||||||
        );
 | 
					        try {
 | 
				
			||||||
 | 
					          password = utf8StringToString(password);
 | 
				
			||||||
 | 
					        } catch {
 | 
				
			||||||
 | 
					          warn(
 | 
				
			||||||
 | 
					            "CipherTransformFactory: Unable to convert UTF8 encoded password."
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      // algorithms 1 and 2
 | 
					      passwordBytes = stringToBytes(password);
 | 
				
			||||||
      const key = buildObjectKey(
 | 
					    }
 | 
				
			||||||
        num,
 | 
					
 | 
				
			||||||
        gen,
 | 
					    let encryptionKey;
 | 
				
			||||||
        this.encryptionKey,
 | 
					    if (algorithm !== 5) {
 | 
				
			||||||
        /* isAes = */ false
 | 
					      encryptionKey = this.#prepareKeyData(
 | 
				
			||||||
 | 
					        fileIdBytes,
 | 
				
			||||||
 | 
					        passwordBytes,
 | 
				
			||||||
 | 
					        ownerPassword,
 | 
				
			||||||
 | 
					        userPassword,
 | 
				
			||||||
 | 
					        flags,
 | 
				
			||||||
 | 
					        revision,
 | 
				
			||||||
 | 
					        keyLength,
 | 
				
			||||||
 | 
					        encryptMetadata
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      const cipherConstructor = function buildCipherCipherConstructor() {
 | 
					    } else {
 | 
				
			||||||
        return new ARCFourCipher(key);
 | 
					      const ownerValidationSalt = ownerBytes.subarray(32, 40);
 | 
				
			||||||
      };
 | 
					      const ownerKeySalt = ownerBytes.subarray(40, 48);
 | 
				
			||||||
      return new CipherTransform(cipherConstructor, cipherConstructor);
 | 
					      const uBytes = userBytes.subarray(0, 48);
 | 
				
			||||||
 | 
					      const userValidationSalt = userBytes.subarray(32, 40);
 | 
				
			||||||
 | 
					      const userKeySalt = userBytes.subarray(40, 48);
 | 
				
			||||||
 | 
					      const ownerEncryption = stringToBytes(dict.get("OE"));
 | 
				
			||||||
 | 
					      const userEncryption = stringToBytes(dict.get("UE"));
 | 
				
			||||||
 | 
					      const perms = stringToBytes(dict.get("Perms"));
 | 
				
			||||||
 | 
					      encryptionKey = this.#createEncryptionKey20(
 | 
				
			||||||
 | 
					        revision,
 | 
				
			||||||
 | 
					        passwordBytes,
 | 
				
			||||||
 | 
					        ownerPassword,
 | 
				
			||||||
 | 
					        ownerValidationSalt,
 | 
				
			||||||
 | 
					        ownerKeySalt,
 | 
				
			||||||
 | 
					        uBytes,
 | 
				
			||||||
 | 
					        userPassword,
 | 
				
			||||||
 | 
					        userValidationSalt,
 | 
				
			||||||
 | 
					        userKeySalt,
 | 
				
			||||||
 | 
					        ownerEncryption,
 | 
				
			||||||
 | 
					        userEncryption,
 | 
				
			||||||
 | 
					        perms
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!encryptionKey && !password) {
 | 
				
			||||||
 | 
					      throw new PasswordException(
 | 
				
			||||||
 | 
					        "No password given",
 | 
				
			||||||
 | 
					        PasswordResponses.NEED_PASSWORD
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else if (!encryptionKey && password) {
 | 
				
			||||||
 | 
					      // Attempting use the password as an owner password
 | 
				
			||||||
 | 
					      const decodedPassword = this.#decodeUserPassword(
 | 
				
			||||||
 | 
					        passwordBytes,
 | 
				
			||||||
 | 
					        ownerPassword,
 | 
				
			||||||
 | 
					        revision,
 | 
				
			||||||
 | 
					        keyLength
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      encryptionKey = this.#prepareKeyData(
 | 
				
			||||||
 | 
					        fileIdBytes,
 | 
				
			||||||
 | 
					        decodedPassword,
 | 
				
			||||||
 | 
					        ownerPassword,
 | 
				
			||||||
 | 
					        userPassword,
 | 
				
			||||||
 | 
					        flags,
 | 
				
			||||||
 | 
					        revision,
 | 
				
			||||||
 | 
					        keyLength,
 | 
				
			||||||
 | 
					        encryptMetadata
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!encryptionKey) {
 | 
				
			||||||
 | 
					      throw new PasswordException(
 | 
				
			||||||
 | 
					        "Incorrect Password",
 | 
				
			||||||
 | 
					        PasswordResponses.INCORRECT_PASSWORD
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.encryptionKey = encryptionKey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (algorithm >= 4) {
 | 
				
			||||||
 | 
					      const cf = dict.get("CF");
 | 
				
			||||||
 | 
					      if (cf instanceof Dict) {
 | 
				
			||||||
 | 
					        // The 'CF' dictionary itself should not be encrypted, and by setting
 | 
				
			||||||
 | 
					        // `suppressEncryption` we can prevent an infinite loop inside of
 | 
				
			||||||
 | 
					        // `XRef_fetchUncompressed` if the dictionary contains indirect
 | 
				
			||||||
 | 
					        // objects (fixes issue7665.pdf).
 | 
				
			||||||
 | 
					        cf.suppressEncryption = true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.cf = cf;
 | 
				
			||||||
 | 
					      this.stmf = dict.get("StmF") || Name.get("Identity");
 | 
				
			||||||
 | 
					      this.strf = dict.get("StrF") || Name.get("Identity");
 | 
				
			||||||
 | 
					      this.eff = dict.get("EFF") || this.stmf;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return CipherTransformFactory;
 | 
					  createCipherTransform(num, gen) {
 | 
				
			||||||
})();
 | 
					    if (this.algorithm === 4 || this.algorithm === 5) {
 | 
				
			||||||
 | 
					      return new CipherTransform(
 | 
				
			||||||
 | 
					        this.#buildCipherConstructor(
 | 
				
			||||||
 | 
					          this.cf,
 | 
				
			||||||
 | 
					          this.strf,
 | 
				
			||||||
 | 
					          num,
 | 
				
			||||||
 | 
					          gen,
 | 
				
			||||||
 | 
					          this.encryptionKey
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        this.#buildCipherConstructor(
 | 
				
			||||||
 | 
					          this.cf,
 | 
				
			||||||
 | 
					          this.stmf,
 | 
				
			||||||
 | 
					          num,
 | 
				
			||||||
 | 
					          gen,
 | 
				
			||||||
 | 
					          this.encryptionKey
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // algorithms 1 and 2
 | 
				
			||||||
 | 
					    const key = this.#buildObjectKey(
 | 
				
			||||||
 | 
					      num,
 | 
				
			||||||
 | 
					      gen,
 | 
				
			||||||
 | 
					      this.encryptionKey,
 | 
				
			||||||
 | 
					      /* isAes = */ false
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const cipherConstructor = function () {
 | 
				
			||||||
 | 
					      return new ARCFourCipher(key);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return new CipherTransform(cipherConstructor, cipherConstructor);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export {
 | 
					export {
 | 
				
			||||||
  AES128Cipher,
 | 
					  AES128Cipher,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user