Enable the no-var linting rule in src/core/crypto.js

This is done automatically with `gulp lint --fix`.
This commit is contained in:
Tim van der Meij 2021-05-01 20:12:16 +02:00
parent 58e568fe62
commit 1f8b452354
No known key found for this signature in database
GPG Key ID: 8C3FD2925A5F2762

View File

@ -12,7 +12,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
/* eslint-disable no-var */
import { import {
bytesToString, bytesToString,
@ -32,8 +31,8 @@ class ARCFourCipher {
constructor(key) { constructor(key) {
this.a = 0; this.a = 0;
this.b = 0; this.b = 0;
var s = new Uint8Array(256); const s = new Uint8Array(256);
var i, let i,
j = 0, j = 0,
tmp, tmp,
keyLength = key.length; keyLength = key.length;
@ -50,14 +49,14 @@ class ARCFourCipher {
} }
encryptBlock(data) { encryptBlock(data) {
var i, let i,
n = data.length, n = data.length,
tmp, tmp,
tmp2; tmp2;
var a = this.a, let a = this.a,
b = this.b, b = this.b,
s = this.s; s = this.s;
var output = new Uint8Array(n); const output = new Uint8Array(n);
for (i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
a = (a + 1) & 0xff; a = (a + 1) & 0xff;
tmp = s[a]; tmp = s[a];
@ -81,16 +80,16 @@ class ARCFourCipher {
} }
} }
var calculateMD5 = (function calculateMD5Closure() { const calculateMD5 = (function calculateMD5Closure() {
// prettier-ignore // prettier-ignore
var r = new Uint8Array([ const r = new Uint8Array([
7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]); 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]);
// prettier-ignore // prettier-ignore
var k = new Int32Array([ const k = new Int32Array([
-680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426, -680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426,
-1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162, -1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162,
1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632, 1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632,
@ -104,14 +103,14 @@ var calculateMD5 = (function calculateMD5Closure() {
-145523070, -1120210379, 718787259, -343485551]); -145523070, -1120210379, 718787259, -343485551]);
function hash(data, offset, length) { function hash(data, offset, length) {
var h0 = 1732584193, let h0 = 1732584193,
h1 = -271733879, h1 = -271733879,
h2 = -1732584194, h2 = -1732584194,
h3 = 271733878; h3 = 271733878;
// pre-processing // pre-processing
var paddedLength = (length + 72) & ~63; // data + 9 extra bytes const paddedLength = (length + 72) & ~63; // data + 9 extra bytes
var padded = new Uint8Array(paddedLength); const padded = new Uint8Array(paddedLength);
var i, j, n; let i, j, n;
for (i = 0; i < length; ++i) { for (i = 0; i < length; ++i) {
padded[i] = data[offset++]; padded[i] = data[offset++];
} }
@ -128,7 +127,7 @@ var calculateMD5 = (function calculateMD5Closure() {
padded[i++] = 0; padded[i++] = 0;
padded[i++] = 0; padded[i++] = 0;
padded[i++] = 0; padded[i++] = 0;
var w = new Int32Array(16); const w = new Int32Array(16);
for (i = 0; i < paddedLength; ) { for (i = 0; i < paddedLength; ) {
for (j = 0; j < 16; ++j, i += 4) { for (j = 0; j < 16; ++j, i += 4) {
w[j] = w[j] =
@ -157,7 +156,7 @@ var calculateMD5 = (function calculateMD5Closure() {
f = c ^ (b | ~d); f = c ^ (b | ~d);
g = (7 * j) & 15; g = (7 * j) & 15;
} }
var tmp = d, const tmp = d,
rotateArg = (a + f + k[j] + w[g]) | 0, rotateArg = (a + f + k[j] + w[g]) | 0,
rotate = r[j]; rotate = r[j];
d = c; d = c;
@ -224,7 +223,7 @@ class Word64 {
} }
rotateRight(places) { rotateRight(places) {
var low, high; let low, high;
if (places & 32) { if (places & 32) {
high = this.low; high = this.low;
low = this.high; low = this.high;
@ -243,8 +242,8 @@ class Word64 {
} }
add(word) { add(word) {
var lowAdd = (this.low >>> 0) + (word.low >>> 0); const lowAdd = (this.low >>> 0) + (word.low >>> 0);
var highAdd = (this.high >>> 0) + (word.high >>> 0); let highAdd = (this.high >>> 0) + (word.high >>> 0);
if (lowAdd > 0xffffffff) { if (lowAdd > 0xffffffff) {
highAdd += 1; highAdd += 1;
} }
@ -269,7 +268,7 @@ class Word64 {
} }
} }
var calculateSHA256 = (function calculateSHA256Closure() { const calculateSHA256 = (function calculateSHA256Closure() {
function rotr(x, n) { function rotr(x, n) {
return (x >>> n) | (x << (32 - n)); return (x >>> n) | (x << (32 - n));
} }
@ -299,7 +298,7 @@ var calculateSHA256 = (function calculateSHA256Closure() {
} }
// prettier-ignore // prettier-ignore
var k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, const k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
@ -318,7 +317,7 @@ var calculateSHA256 = (function calculateSHA256Closure() {
function hash(data, offset, length) { function hash(data, offset, length) {
// initial hash values // initial hash values
var h0 = 0x6a09e667, let h0 = 0x6a09e667,
h1 = 0xbb67ae85, h1 = 0xbb67ae85,
h2 = 0x3c6ef372, h2 = 0x3c6ef372,
h3 = 0xa54ff53a, h3 = 0xa54ff53a,
@ -327,9 +326,9 @@ var calculateSHA256 = (function calculateSHA256Closure() {
h6 = 0x1f83d9ab, h6 = 0x1f83d9ab,
h7 = 0x5be0cd19; h7 = 0x5be0cd19;
// pre-processing // pre-processing
var paddedLength = Math.ceil((length + 9) / 64) * 64; const paddedLength = Math.ceil((length + 9) / 64) * 64;
var padded = new Uint8Array(paddedLength); const padded = new Uint8Array(paddedLength);
var i, j, n; let i, j, n;
for (i = 0; i < length; ++i) { for (i = 0; i < length; ++i) {
padded[i] = data[offset++]; padded[i] = data[offset++];
} }
@ -346,7 +345,7 @@ var calculateSHA256 = (function calculateSHA256Closure() {
padded[i++] = (length >> 13) & 0xff; padded[i++] = (length >> 13) & 0xff;
padded[i++] = (length >> 5) & 0xff; padded[i++] = (length >> 5) & 0xff;
padded[i++] = (length << 3) & 0xff; padded[i++] = (length << 3) & 0xff;
var w = new Uint32Array(64); const w = new Uint32Array(64);
// for each 512 bit block // for each 512 bit block
for (i = 0; i < paddedLength; ) { for (i = 0; i < paddedLength; ) {
for (j = 0; j < 16; ++j) { for (j = 0; j < 16; ++j) {
@ -413,7 +412,7 @@ var calculateSHA256 = (function calculateSHA256Closure() {
return hash; return hash;
})(); })();
var calculateSHA512 = (function calculateSHA512Closure() { const calculateSHA512 = (function calculateSHA512Closure() {
function ch(result, x, y, z, tmp) { function ch(result, x, y, z, tmp) {
result.assign(x); result.assign(x);
result.and(y); result.and(y);
@ -479,7 +478,7 @@ var calculateSHA512 = (function calculateSHA512Closure() {
} }
// prettier-ignore // prettier-ignore
var k = [ const k = [
new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd), new Word64(0x428a2f98, 0xd728ae22), new Word64(0x71374491, 0x23ef65cd),
new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc), new Word64(0xb5c0fbcf, 0xec4d3b2f), new Word64(0xe9b5dba5, 0x8189dbbc),
new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019), new Word64(0x3956c25b, 0xf348b538), new Word64(0x59f111f1, 0xb605d019),
@ -523,7 +522,7 @@ var calculateSHA512 = (function calculateSHA512Closure() {
function hash(data, offset, length, mode384 = false) { function hash(data, offset, length, mode384 = false) {
// initial hash values // initial hash values
var h0, h1, h2, h3, h4, h5, h6, h7; let h0, h1, h2, h3, h4, h5, h6, h7;
if (!mode384) { if (!mode384) {
h0 = new Word64(0x6a09e667, 0xf3bcc908); h0 = new Word64(0x6a09e667, 0xf3bcc908);
h1 = new Word64(0xbb67ae85, 0x84caa73b); h1 = new Word64(0xbb67ae85, 0x84caa73b);
@ -547,9 +546,9 @@ var calculateSHA512 = (function calculateSHA512Closure() {
} }
// pre-processing // pre-processing
var paddedLength = Math.ceil((length + 17) / 128) * 128; const paddedLength = Math.ceil((length + 17) / 128) * 128;
var padded = new Uint8Array(paddedLength); const padded = new Uint8Array(paddedLength);
var i, j, n; let i, j, n;
for (i = 0; i < length; ++i) { for (i = 0; i < length; ++i) {
padded[i] = data[offset++]; padded[i] = data[offset++];
} }
@ -575,21 +574,21 @@ var calculateSHA512 = (function calculateSHA512Closure() {
padded[i++] = (length >> 5) & 0xff; padded[i++] = (length >> 5) & 0xff;
padded[i++] = (length << 3) & 0xff; padded[i++] = (length << 3) & 0xff;
var w = new Array(80); const w = new Array(80);
for (i = 0; i < 80; i++) { for (i = 0; i < 80; i++) {
w[i] = new Word64(0, 0); w[i] = new Word64(0, 0);
} }
var a = new Word64(0, 0), let a = new Word64(0, 0),
b = new Word64(0, 0), b = new Word64(0, 0),
c = new Word64(0, 0); c = new Word64(0, 0);
var d = new Word64(0, 0), let d = new Word64(0, 0),
e = new Word64(0, 0), e = new Word64(0, 0),
f = new Word64(0, 0); f = new Word64(0, 0);
var g = new Word64(0, 0), let g = new Word64(0, 0),
h = new Word64(0, 0); h = new Word64(0, 0);
var t1 = new Word64(0, 0), const t1 = new Word64(0, 0),
t2 = new Word64(0, 0); t2 = new Word64(0, 0);
var tmp1 = new Word64(0, 0), let tmp1 = new Word64(0, 0),
tmp2 = new Word64(0, 0), tmp2 = new Word64(0, 0),
tmp3; tmp3;
@ -661,7 +660,7 @@ var calculateSHA512 = (function calculateSHA512Closure() {
h7.add(h); h7.add(h);
} }
var result; let result;
if (!mode384) { if (!mode384) {
result = new Uint8Array(64); result = new Uint8Array(64);
h0.copyTo(result, 0); h0.copyTo(result, 0);
@ -1255,49 +1254,49 @@ class AES256Cipher extends AESBaseCipher {
class PDF17 { class PDF17 {
checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) { checkOwnerPassword(password, ownerValidationSalt, userBytes, ownerPassword) {
var hashData = new Uint8Array(password.length + 56); const hashData = new Uint8Array(password.length + 56);
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(ownerValidationSalt, password.length); hashData.set(ownerValidationSalt, password.length);
hashData.set(userBytes, password.length + ownerValidationSalt.length); hashData.set(userBytes, password.length + ownerValidationSalt.length);
var result = calculateSHA256(hashData, 0, hashData.length); const result = calculateSHA256(hashData, 0, hashData.length);
return isArrayEqual(result, ownerPassword); return isArrayEqual(result, ownerPassword);
} }
checkUserPassword(password, userValidationSalt, userPassword) { checkUserPassword(password, userValidationSalt, userPassword) {
var hashData = new Uint8Array(password.length + 8); const hashData = new Uint8Array(password.length + 8);
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(userValidationSalt, password.length); hashData.set(userValidationSalt, password.length);
var result = calculateSHA256(hashData, 0, hashData.length); const result = calculateSHA256(hashData, 0, hashData.length);
return isArrayEqual(result, userPassword); return isArrayEqual(result, userPassword);
} }
getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) { getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) {
var hashData = new Uint8Array(password.length + 56); const hashData = new Uint8Array(password.length + 56);
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(ownerKeySalt, password.length); hashData.set(ownerKeySalt, password.length);
hashData.set(userBytes, password.length + ownerKeySalt.length); hashData.set(userBytes, password.length + ownerKeySalt.length);
var key = calculateSHA256(hashData, 0, hashData.length); const key = calculateSHA256(hashData, 0, hashData.length);
var cipher = new AES256Cipher(key); const cipher = new AES256Cipher(key);
return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16)); return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16));
} }
getUserKey(password, userKeySalt, userEncryption) { getUserKey(password, userKeySalt, userEncryption) {
var hashData = new Uint8Array(password.length + 8); const hashData = new Uint8Array(password.length + 8);
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(userKeySalt, password.length); hashData.set(userKeySalt, password.length);
// `key` is the decryption key for the UE string. // `key` is the decryption key for the UE string.
var key = calculateSHA256(hashData, 0, hashData.length); const key = calculateSHA256(hashData, 0, hashData.length);
var cipher = new AES256Cipher(key); const cipher = new AES256Cipher(key);
return cipher.decryptBlock(userEncryption, false, new Uint8Array(16)); return cipher.decryptBlock(userEncryption, false, new Uint8Array(16));
} }
} }
var PDF20 = (function PDF20Closure() { const PDF20 = (function PDF20Closure() {
function calculatePDF20Hash(password, input, userBytes) { function calculatePDF20Hash(password, input, userBytes) {
// This refers to Algorithm 2.B as defined in ISO 32000-2. // This refers to Algorithm 2.B as defined in ISO 32000-2.
var k = calculateSHA256(input, 0, input.length).subarray(0, 32); let k = calculateSHA256(input, 0, input.length).subarray(0, 32);
var e = [0]; let e = [0];
var i = 0; let i = 0;
while (i < 64 || e[e.length - 1] > i - 32) { while (i < 64 || e[e.length - 1] > i - 32) {
const combinedLength = password.length + k.length + userBytes.length, const combinedLength = password.length + k.length + userBytes.length,
combinedArray = new Uint8Array(combinedLength); combinedArray = new Uint8Array(combinedLength);
@ -1308,20 +1307,20 @@ var PDF20 = (function PDF20Closure() {
writeOffset += k.length; writeOffset += k.length;
combinedArray.set(userBytes, writeOffset); combinedArray.set(userBytes, writeOffset);
var k1 = new Uint8Array(combinedLength * 64); const k1 = new Uint8Array(combinedLength * 64);
for (var j = 0, pos = 0; j < 64; j++, pos += combinedLength) { for (let j = 0, pos = 0; j < 64; j++, pos += combinedLength) {
k1.set(combinedArray, pos); k1.set(combinedArray, pos);
} }
// AES128 CBC NO PADDING with first 16 bytes of k as the key // AES128 CBC NO PADDING with first 16 bytes of k as the key
// and the second 16 as the iv. // and the second 16 as the iv.
var cipher = new AES128Cipher(k.subarray(0, 16)); const cipher = new AES128Cipher(k.subarray(0, 16));
e = cipher.encrypt(k1, k.subarray(16, 32)); e = cipher.encrypt(k1, k.subarray(16, 32));
// Now we have to take the first 16 bytes of an unsigned big endian // Now we have to take the first 16 bytes of an unsigned big endian
// integer and compute the remainder modulo 3. That is a fairly large // integer and compute the remainder modulo 3. That is a fairly large
// number and JavaScript isn't going to handle that well, so we're using // number and JavaScript isn't going to handle that well, so we're using
// a trick that allows us to perform modulo math byte by byte. // a trick that allows us to perform modulo math byte by byte.
var remainder = 0; let remainder = 0;
for (var z = 0; z < 16; z++) { for (let z = 0; z < 16; z++) {
remainder *= 256 % 3; remainder *= 256 % 3;
remainder %= 3; remainder %= 3;
remainder += (e[z] >>> 0) % 3; remainder += (e[z] >>> 0) % 3;
@ -1351,39 +1350,39 @@ var PDF20 = (function PDF20Closure() {
userBytes, userBytes,
ownerPassword ownerPassword
) { ) {
var hashData = new Uint8Array(password.length + 56); const hashData = new Uint8Array(password.length + 56);
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(ownerValidationSalt, password.length); hashData.set(ownerValidationSalt, password.length);
hashData.set(userBytes, password.length + ownerValidationSalt.length); hashData.set(userBytes, password.length + ownerValidationSalt.length);
var result = calculatePDF20Hash(password, hashData, userBytes); const result = calculatePDF20Hash(password, hashData, userBytes);
return isArrayEqual(result, ownerPassword); return isArrayEqual(result, ownerPassword);
} }
checkUserPassword(password, userValidationSalt, userPassword) { checkUserPassword(password, userValidationSalt, userPassword) {
var hashData = new Uint8Array(password.length + 8); const hashData = new Uint8Array(password.length + 8);
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(userValidationSalt, password.length); hashData.set(userValidationSalt, password.length);
var result = calculatePDF20Hash(password, hashData, []); const result = calculatePDF20Hash(password, hashData, []);
return isArrayEqual(result, userPassword); return isArrayEqual(result, userPassword);
} }
getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) { getOwnerKey(password, ownerKeySalt, userBytes, ownerEncryption) {
var hashData = new Uint8Array(password.length + 56); const hashData = new Uint8Array(password.length + 56);
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(ownerKeySalt, password.length); hashData.set(ownerKeySalt, password.length);
hashData.set(userBytes, password.length + ownerKeySalt.length); hashData.set(userBytes, password.length + ownerKeySalt.length);
var key = calculatePDF20Hash(password, hashData, userBytes); const key = calculatePDF20Hash(password, hashData, userBytes);
var cipher = new AES256Cipher(key); const cipher = new AES256Cipher(key);
return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16)); return cipher.decryptBlock(ownerEncryption, false, new Uint8Array(16));
} }
getUserKey(password, userKeySalt, userEncryption) { getUserKey(password, userKeySalt, userEncryption) {
var hashData = new Uint8Array(password.length + 8); const hashData = new Uint8Array(password.length + 8);
hashData.set(password, 0); hashData.set(password, 0);
hashData.set(userKeySalt, password.length); hashData.set(userKeySalt, password.length);
// `key` is the decryption key for the UE string. // `key` is the decryption key for the UE string.
var key = calculatePDF20Hash(password, hashData, []); const key = calculatePDF20Hash(password, hashData, []);
var cipher = new AES256Cipher(key); const cipher = new AES256Cipher(key);
return cipher.decryptBlock(userEncryption, false, new Uint8Array(16)); return cipher.decryptBlock(userEncryption, false, new Uint8Array(16));
} }
} }
@ -1398,7 +1397,7 @@ class CipherTransform {
} }
createStream(stream, length) { createStream(stream, length) {
var cipher = new this.StreamCipherConstructor(); const cipher = new this.StreamCipherConstructor();
return new DecryptStream( return new DecryptStream(
stream, stream,
length, length,
@ -1409,8 +1408,8 @@ class CipherTransform {
} }
decryptString(s) { decryptString(s) {
var cipher = new this.StringCipherConstructor(); const cipher = new this.StringCipherConstructor();
var data = stringToBytes(s); let data = stringToBytes(s);
data = cipher.decryptBlock(data, true); data = cipher.decryptBlock(data, true);
return bytesToString(data); return bytesToString(data);
} }
@ -1453,9 +1452,9 @@ class CipherTransform {
} }
} }
var CipherTransformFactory = (function CipherTransformFactoryClosure() { const CipherTransformFactory = (function CipherTransformFactoryClosure() {
// prettier-ignore // prettier-ignore
var defaultPasswordBytes = new Uint8Array([ const defaultPasswordBytes = new Uint8Array([
0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
@ -1476,12 +1475,12 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
perms perms
) { ) {
if (password) { if (password) {
var passwordLength = Math.min(127, password.length); const passwordLength = Math.min(127, password.length);
password = password.subarray(0, passwordLength); password = password.subarray(0, passwordLength);
} else { } else {
password = []; password = [];
} }
var pdfAlgorithm; let pdfAlgorithm;
if (revision === 6) { if (revision === 6) {
pdfAlgorithm = new PDF20(); pdfAlgorithm = new PDF20();
} else { } else {
@ -1522,8 +1521,8 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
keyLength, keyLength,
encryptMetadata encryptMetadata
) { ) {
var hashDataSize = 40 + ownerPassword.length + fileId.length; const hashDataSize = 40 + ownerPassword.length + fileId.length;
var hashData = new Uint8Array(hashDataSize), let hashData = new Uint8Array(hashDataSize),
i = 0, i = 0,
j, j,
n; n;
@ -1554,15 +1553,15 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
hashData[i++] = 0xff; hashData[i++] = 0xff;
hashData[i++] = 0xff; hashData[i++] = 0xff;
} }
var hash = calculateMD5(hashData, 0, i); let hash = calculateMD5(hashData, 0, i);
var keyLengthInBytes = keyLength >> 3; const keyLengthInBytes = keyLength >> 3;
if (revision >= 3) { if (revision >= 3) {
for (j = 0; j < 50; ++j) { for (j = 0; j < 50; ++j) {
hash = calculateMD5(hash, 0, keyLengthInBytes); hash = calculateMD5(hash, 0, keyLengthInBytes);
} }
} }
var encryptionKey = hash.subarray(0, keyLengthInBytes); const encryptionKey = hash.subarray(0, keyLengthInBytes);
var cipher, checkData; let cipher, checkData;
if (revision >= 3) { if (revision >= 3) {
for (i = 0; i < 32; ++i) { for (i = 0; i < 32; ++i) {
@ -1574,7 +1573,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
cipher = new ARCFourCipher(encryptionKey); cipher = new ARCFourCipher(encryptionKey);
checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i)); checkData = cipher.encryptBlock(calculateMD5(hashData, 0, i));
n = encryptionKey.length; n = encryptionKey.length;
var derivedKey = new Uint8Array(n), let derivedKey = new Uint8Array(n),
k; k;
for (j = 1; j <= 19; ++j) { for (j = 1; j <= 19; ++j) {
for (k = 0; k < n; ++k) { for (k = 0; k < n; ++k) {
@ -1601,7 +1600,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
} }
function decodeUserPassword(password, ownerPassword, revision, keyLength) { function decodeUserPassword(password, ownerPassword, revision, keyLength) {
var hashData = new Uint8Array(32), let hashData = new Uint8Array(32),
i = 0, i = 0,
j, j,
n; n;
@ -1613,18 +1612,18 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
while (i < 32) { while (i < 32) {
hashData[i++] = defaultPasswordBytes[j++]; hashData[i++] = defaultPasswordBytes[j++];
} }
var hash = calculateMD5(hashData, 0, i); let hash = calculateMD5(hashData, 0, i);
var keyLengthInBytes = keyLength >> 3; const keyLengthInBytes = keyLength >> 3;
if (revision >= 3) { if (revision >= 3) {
for (j = 0; j < 50; ++j) { for (j = 0; j < 50; ++j) {
hash = calculateMD5(hash, 0, hash.length); hash = calculateMD5(hash, 0, hash.length);
} }
} }
var cipher, userPassword; let cipher, userPassword;
if (revision >= 3) { if (revision >= 3) {
userPassword = ownerPassword; userPassword = ownerPassword;
var derivedKey = new Uint8Array(keyLengthInBytes), let derivedKey = new Uint8Array(keyLengthInBytes),
k; k;
for (j = 19; j >= 0; j--) { for (j = 19; j >= 0; j--) {
for (k = 0; k < keyLengthInBytes; ++k) { for (k = 0; k < keyLengthInBytes; ++k) {
@ -1640,10 +1639,10 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
return userPassword; return userPassword;
} }
var identityName = Name.get("Identity"); const identityName = Name.get("Identity");
function buildObjectKey(num, gen, encryptionKey, isAes = false) { function buildObjectKey(num, gen, encryptionKey, isAes = false) {
var key = new Uint8Array(encryptionKey.length + 9), let key = new Uint8Array(encryptionKey.length + 9),
i, i,
n; n;
for (i = 0, n = encryptionKey.length; i < n; ++i) { for (i = 0, n = encryptionKey.length; i < n; ++i) {
@ -1660,7 +1659,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
key[i++] = 0x6c; key[i++] = 0x6c;
key[i++] = 0x54; key[i++] = 0x54;
} }
var hash = calculateMD5(key, 0, i); const hash = calculateMD5(key, 0, i);
return hash.subarray(0, Math.min(encryptionKey.length + 5, 16)); return hash.subarray(0, Math.min(encryptionKey.length + 5, 16));
} }
@ -1668,8 +1667,8 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
if (!isName(name)) { if (!isName(name)) {
throw new FormatError("Invalid crypt filter name."); throw new FormatError("Invalid crypt filter name.");
} }
var cryptFilter = cf.get(name.name); const cryptFilter = cf.get(name.name);
var cfm; let cfm;
if (cryptFilter !== null && cryptFilter !== undefined) { if (cryptFilter !== null && cryptFilter !== undefined) {
cfm = cryptFilter.get("CFM"); cfm = cryptFilter.get("CFM");
} }
@ -1703,12 +1702,12 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
// eslint-disable-next-line no-shadow // eslint-disable-next-line no-shadow
class CipherTransformFactory { class CipherTransformFactory {
constructor(dict, fileId, password) { constructor(dict, fileId, password) {
var filter = dict.get("Filter"); const filter = dict.get("Filter");
if (!isName(filter, "Standard")) { if (!isName(filter, "Standard")) {
throw new FormatError("unknown encryption method"); throw new FormatError("unknown encryption method");
} }
this.dict = dict; this.dict = dict;
var algorithm = dict.get("V"); const algorithm = dict.get("V");
if ( if (
!Number.isInteger(algorithm) || !Number.isInteger(algorithm) ||
(algorithm !== 1 && (algorithm !== 1 &&
@ -1719,7 +1718,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
throw new FormatError("unsupported encryption algorithm"); throw new FormatError("unsupported encryption algorithm");
} }
this.algorithm = algorithm; this.algorithm = algorithm;
var keyLength = dict.get("Length"); let keyLength = dict.get("Length");
if (!keyLength) { if (!keyLength) {
// Spec asks to rely on encryption dictionary's Length entry, however // Spec asks to rely on encryption dictionary's Length entry, however
// some PDFs don't have it. Trying to recover. // some PDFs don't have it. Trying to recover.
@ -1728,11 +1727,11 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
keyLength = 40; keyLength = 40;
} else { } else {
// Trying to find default handler -- it usually has Length. // Trying to find default handler -- it usually has Length.
var cfDict = dict.get("CF"); const cfDict = dict.get("CF");
var streamCryptoName = dict.get("StmF"); const streamCryptoName = dict.get("StmF");
if (isDict(cfDict) && isName(streamCryptoName)) { if (isDict(cfDict) && isName(streamCryptoName)) {
cfDict.suppressEncryption = true; // See comment below. cfDict.suppressEncryption = true; // See comment below.
var handlerDict = cfDict.get(streamCryptoName.name); const handlerDict = cfDict.get(streamCryptoName.name);
keyLength = (handlerDict && handlerDict.get("Length")) || 128; keyLength = (handlerDict && handlerDict.get("Length")) || 128;
if (keyLength < 40) { if (keyLength < 40) {
// Sometimes it's incorrect value of bits, generators specify // Sometimes it's incorrect value of bits, generators specify
@ -1751,18 +1750,18 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
} }
// prepare keys // prepare keys
var ownerPassword = stringToBytes(dict.get("O")).subarray(0, 32); const ownerPassword = stringToBytes(dict.get("O")).subarray(0, 32);
var userPassword = stringToBytes(dict.get("U")).subarray(0, 32); const userPassword = stringToBytes(dict.get("U")).subarray(0, 32);
var flags = dict.get("P"); const flags = dict.get("P");
var revision = dict.get("R"); const revision = dict.get("R");
// meaningful when V is 4 or 5 // meaningful when V is 4 or 5
var encryptMetadata = const encryptMetadata =
(algorithm === 4 || algorithm === 5) && (algorithm === 4 || algorithm === 5) &&
dict.get("EncryptMetadata") !== false; dict.get("EncryptMetadata") !== false;
this.encryptMetadata = encryptMetadata; this.encryptMetadata = encryptMetadata;
var fileIdBytes = stringToBytes(fileId); const fileIdBytes = stringToBytes(fileId);
var passwordBytes; let passwordBytes;
if (password) { if (password) {
if (revision === 6) { if (revision === 6) {
try { try {
@ -1777,7 +1776,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
passwordBytes = stringToBytes(password); passwordBytes = stringToBytes(password);
} }
var encryptionKey; let encryptionKey;
if (algorithm !== 5) { if (algorithm !== 5) {
encryptionKey = prepareKeyData( encryptionKey = prepareKeyData(
fileIdBytes, fileIdBytes,
@ -1790,14 +1789,20 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
encryptMetadata encryptMetadata
); );
} else { } else {
var ownerValidationSalt = stringToBytes(dict.get("O")).subarray(32, 40); const ownerValidationSalt = stringToBytes(dict.get("O")).subarray(
var ownerKeySalt = stringToBytes(dict.get("O")).subarray(40, 48); 32,
var uBytes = stringToBytes(dict.get("U")).subarray(0, 48); 40
var userValidationSalt = stringToBytes(dict.get("U")).subarray(32, 40); );
var userKeySalt = stringToBytes(dict.get("U")).subarray(40, 48); const ownerKeySalt = stringToBytes(dict.get("O")).subarray(40, 48);
var ownerEncryption = stringToBytes(dict.get("OE")); const uBytes = stringToBytes(dict.get("U")).subarray(0, 48);
var userEncryption = stringToBytes(dict.get("UE")); const userValidationSalt = stringToBytes(dict.get("U")).subarray(
var perms = stringToBytes(dict.get("Perms")); 32,
40
);
const userKeySalt = stringToBytes(dict.get("U")).subarray(40, 48);
const ownerEncryption = stringToBytes(dict.get("OE"));
const userEncryption = stringToBytes(dict.get("UE"));
const perms = stringToBytes(dict.get("Perms"));
encryptionKey = createEncryptionKey20( encryptionKey = createEncryptionKey20(
revision, revision,
passwordBytes, passwordBytes,
@ -1820,7 +1825,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
); );
} else if (!encryptionKey && password) { } else if (!encryptionKey && password) {
// Attempting use the password as an owner password // Attempting use the password as an owner password
var decodedPassword = decodeUserPassword( const decodedPassword = decodeUserPassword(
passwordBytes, passwordBytes,
ownerPassword, ownerPassword,
revision, revision,
@ -1848,7 +1853,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
this.encryptionKey = encryptionKey; this.encryptionKey = encryptionKey;
if (algorithm >= 4) { if (algorithm >= 4) {
var cf = dict.get("CF"); const cf = dict.get("CF");
if (isDict(cf)) { if (isDict(cf)) {
// The 'CF' dictionary itself should not be encrypted, and by setting // The 'CF' dictionary itself should not be encrypted, and by setting
// `suppressEncryption` we can prevent an infinite loop inside of // `suppressEncryption` we can prevent an infinite loop inside of
@ -1883,13 +1888,13 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() {
); );
} }
// algorithms 1 and 2 // algorithms 1 and 2
var key = buildObjectKey( const key = buildObjectKey(
num, num,
gen, gen,
this.encryptionKey, this.encryptionKey,
/* isAes = */ false /* isAes = */ false
); );
var cipherConstructor = function buildCipherCipherConstructor() { const cipherConstructor = function buildCipherCipherConstructor() {
return new ARCFourCipher(key); return new ARCFourCipher(key);
}; };
return new CipherTransform(cipherConstructor, cipherConstructor); return new CipherTransform(cipherConstructor, cipherConstructor);