From 5e0722e4c262c13921176aa5f33df4b14d364595 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 23 Apr 2023 10:08:17 +0200 Subject: [PATCH 1/2] Remove the `PDF20` closure, in the `src/core/crypto.js` file To allow doing this the existing helper function was changed into a "private" method instead. --- src/core/crypto.js | 92 +++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 51 deletions(-) diff --git a/src/core/crypto.js b/src/core/crypto.js index 22bf8aac1..0cd5b7ade 100644 --- a/src/core/crypto.js +++ b/src/core/crypto.js @@ -1278,8 +1278,8 @@ class PDF17 { } } -const PDF20 = (function PDF20Closure() { - function calculatePDF20Hash(password, input, userBytes) { +class PDF20 { + _hash(password, input, userBytes) { // This refers to Algorithm 2.B as defined in ISO 32000-2. let k = calculateSHA256(input, 0, input.length).subarray(0, 32); let e = [0]; @@ -1321,57 +1321,47 @@ const PDF20 = (function PDF20Closure() { return k.subarray(0, 32); } - // eslint-disable-next-line no-shadow - class PDF20 { - hash(password, concatBytes, userBytes) { - return calculatePDF20Hash(password, concatBytes, userBytes); - } - - checkOwnerPassword( - password, - ownerValidationSalt, - userBytes, - ownerPassword - ) { - const hashData = new Uint8Array(password.length + 56); - hashData.set(password, 0); - hashData.set(ownerValidationSalt, password.length); - hashData.set(userBytes, password.length + ownerValidationSalt.length); - const result = calculatePDF20Hash(password, hashData, userBytes); - return isArrayEqual(result, ownerPassword); - } - - checkUserPassword(password, userValidationSalt, userPassword) { - const hashData = new Uint8Array(password.length + 8); - hashData.set(password, 0); - hashData.set(userValidationSalt, password.length); - const result = calculatePDF20Hash(password, hashData, []); - return isArrayEqual(result, userPassword); - } - - getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) { - const hashData = new Uint8Array(password.length + 56); - hashData.set(password, 0); - hashData.set(ownerKeySalt, password.length); - hashData.set(userBytes, password.length + ownerKeySalt.length); - const key = calculatePDF20Hash(password, hashData, userBytes); - const cipher = new AES256Cipher(key); - return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16)); - } - - getUserKey(password, userKeySalt, userEncryption) { - const hashData = new Uint8Array(password.length + 8); - hashData.set(password, 0); - hashData.set(userKeySalt, password.length); - // `key` is the decryption key for the UE string. - const key = calculatePDF20Hash(password, hashData, []); - const cipher = new AES256Cipher(key); - return cipher.decryptBlock(userEncryption, false, new Uint8Array(16)); - } + hash(password, concatBytes, userBytes) { + return this._hash(password, concatBytes, userBytes); } - return PDF20; -})(); + checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) { + const hashData = new Uint8Array(password.length + 56); + hashData.set(password, 0); + hashData.set(ownerValidationSalt, password.length); + hashData.set(userBytes, password.length + ownerValidationSalt.length); + const result = this._hash(password, hashData, userBytes); + return isArrayEqual(result, ownerPassword); + } + + checkUserPassword(password, userValidationSalt, userPassword) { + const hashData = new Uint8Array(password.length + 8); + hashData.set(password, 0); + hashData.set(userValidationSalt, password.length); + const result = this._hash(password, hashData, []); + return isArrayEqual(result, userPassword); + } + + getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) { + const hashData = new Uint8Array(password.length + 56); + hashData.set(password, 0); + hashData.set(ownerKeySalt, password.length); + hashData.set(userBytes, password.length + ownerKeySalt.length); + const key = this._hash(password, hashData, userBytes); + const cipher = new AES256Cipher(key); + return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16)); + } + + getUserKey(password, userKeySalt, userEncryption) { + const hashData = new Uint8Array(password.length + 8); + hashData.set(password, 0); + hashData.set(userKeySalt, password.length); + // `key` is the decryption key for the UE string. + const key = this._hash(password, hashData, []); + const cipher = new AES256Cipher(key); + return cipher.decryptBlock(userEncryption, false, new Uint8Array(16)); + } +} class CipherTransform { constructor(stringCipherConstructor, streamCipherConstructor) { From 74585c7c59df39cdea39c5440b2f318fe0579d7f Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 23 Apr 2023 10:13:46 +0200 Subject: [PATCH 2/2] Remove the unused `PDF20.hash` method This method was added in PR 4938, almost nine years ago, however it doesn't appear to ever have been used. Given the similarities between the `PDF17` and `PDF20` classes, and how they're used, if the `PDF20.hash` method was actually necessary you'd also expect a similiar method in the `PDF17` class. --- src/core/crypto.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/core/crypto.js b/src/core/crypto.js index 0cd5b7ade..c8e6f2bc9 100644 --- a/src/core/crypto.js +++ b/src/core/crypto.js @@ -1321,10 +1321,6 @@ class PDF20 { return k.subarray(0, 32); } - hash(password, concatBytes, userBytes) { - return this._hash(password, concatBytes, userBytes); - } - checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) { const hashData = new Uint8Array(password.length + 56); hashData.set(password, 0);