Compare commits

...

14 Commits

Author SHA1 Message Date
Tim van der Meij
81baa16c8b
Merge pull request #19629 from Snuffleupagus/split-crypto
Re-factor the `src/core/crypto.js` file
2025-03-09 13:08:40 +01:00
Tim van der Meij
621258f85c
Merge pull request #19623 from Snuffleupagus/PDFFunctionFactory-rm-createFromArray
Remove the `PDFFunctionFactory.createFromArray` method
2025-03-09 12:58:55 +01:00
Tim van der Meij
66af403f10
Merge pull request #19628 from Snuffleupagus/MathClamp-2
Use the `MathClamp` helper function more (PR 19617 follow-up)
2025-03-09 12:49:53 +01:00
Jonas Jenwald
0a2c176027 Remove the unused or/shiftLeft methods from the Word64 class (PR 4938 follow-up)
These methods were introduced in *the first* commit of PR 4938, however they became unused in *the second* commit of that PR.
Hence it seems that we've been accidentally shipping, a small amount of, unused code for over a decade.
2025-03-08 17:33:16 +01:00
Jonas Jenwald
67065e43f5 Replace loops with TypedArray.prototype.set in the CipherTransformFactory class
Also, adds `TypedArray.prototype.fill` usage in one spot.
2025-03-08 16:17:45 +01:00
Jonas Jenwald
c65f1b0dae Move a couple of AESBaseCipher fields from the constructors
Thanks to modern JS class features we can, ever so slightly, shorten some class field definitions.
2025-03-08 16:06:30 +01:00
Jonas Jenwald
461488cb16 Initialize the defaultPasswordBytes, in CipherTransformFactory, lazily 2025-03-08 16:06:30 +01:00
Jonas Jenwald
139d27aa7d Simplify various calculate... methods a tiny bit
While initializing the `padded` Uint8Arrays we're manually assigning zeros to some entries, which is completely unnecessary since that's the default value for a TypedArray, and instead we can just increment the index.
2025-03-08 16:06:27 +01:00
Jonas Jenwald
facf34606f Move the calculateSHA384 and calculateSHA512 functions into their own file
This allows us to remove a closure, and we also change the code to initialize various constants lazily.
2025-03-08 15:56:22 +01:00
Jonas Jenwald
a1eac86037 Move the calculateSHA256 function into its own file
This allows us to remove a closure, and we also change the code to initialize various constants lazily.
2025-03-08 15:56:16 +01:00
Jonas Jenwald
3e8d01ad7c Move the calculateMD5 function into its own file
This allows us to remove a closure, and we also change the code to initialize various constants lazily.
2025-03-08 15:56:05 +01:00
Jonas Jenwald
1b5151f969 Remove pointless Math.min usage in the XFA parsing
When creating the `StyleMapping` for the "xfa-font-horizontal-scale" and "xfa-font-vertical-scale" properties there's currently pointless `Math.min` usage, since we're not actually comparing with anything.
2025-03-08 12:22:33 +01:00
Jonas Jenwald
bee0f53c65 Use the MathClamp helper function more (PR 19617 follow-up)
There's a few spots that I accidentally missed in PR 19617.
2025-03-08 12:19:56 +01:00
Jonas Jenwald
17d7943758 Remove the PDFFunctionFactory.createFromArray method
This combines the `PDFFunctionFactory.create` and `PDFFunctionFactory.createFromArray` methods, which helps simplify and shorten the code.
Additionally, to simplify the parameter handling we pass the `PDFFunctionFactory`-instance directly to the various `PDFFunction`-methods.
2025-03-07 12:28:14 +01:00
11 changed files with 917 additions and 871 deletions

128
src/core/calculate_md5.js Normal file
View File

@ -0,0 +1,128 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { shadow } from "../shared/util.js";
const PARAMS = {
get r() {
return shadow(
this,
"r",
new Uint8Array([
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, 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,
])
);
},
get k() {
return shadow(
this,
"k",
new Int32Array([
-680876936, -389564586, 606105819, -1044525330, -176418897, 1200080426,
-1473231341, -45705983, 1770035416, -1958414417, -42063, -1990404162,
1804603682, -40341101, -1502002290, 1236535329, -165796510, -1069501632,
643717713, -373897302, -701558691, 38016083, -660478335, -405537848,
568446438, -1019803690, -187363961, 1163531501, -1444681467, -51403784,
1735328473, -1926607734, -378558, -2022574463, 1839030562, -35309556,
-1530992060, 1272893353, -155497632, -1094730640, 681279174, -358537222,
-722521979, 76029189, -640364487, -421815835, 530742520, -995338651,
-198630844, 1126891415, -1416354905, -57434055, 1700485571, -1894986606,
-1051523, -2054922799, 1873313359, -30611744, -1560198380, 1309151649,
-145523070, -1120210379, 718787259, -343485551,
])
);
},
};
function calculateMD5(data, offset, length) {
let h0 = 1732584193,
h1 = -271733879,
h2 = -1732584194,
h3 = 271733878;
// pre-processing
const paddedLength = (length + 72) & ~63; // data + 9 extra bytes
const padded = new Uint8Array(paddedLength);
let i, j;
for (i = 0; i < length; ++i) {
padded[i] = data[offset++];
}
padded[i++] = 0x80;
const n = paddedLength - 8;
if (i < n) {
i = n;
}
padded[i++] = (length << 3) & 0xff;
padded[i++] = (length >> 5) & 0xff;
padded[i++] = (length >> 13) & 0xff;
padded[i++] = (length >> 21) & 0xff;
padded[i++] = (length >>> 29) & 0xff;
i += 3;
const w = new Int32Array(16);
const { k, r } = PARAMS;
for (i = 0; i < paddedLength; ) {
for (j = 0; j < 16; ++j, i += 4) {
w[j] =
padded[i] |
(padded[i + 1] << 8) |
(padded[i + 2] << 16) |
(padded[i + 3] << 24);
}
let a = h0,
b = h1,
c = h2,
d = h3,
f,
g;
for (j = 0; j < 64; ++j) {
if (j < 16) {
f = (b & c) | (~b & d);
g = j;
} else if (j < 32) {
f = (d & b) | (~d & c);
g = (5 * j + 1) & 15;
} else if (j < 48) {
f = b ^ c ^ d;
g = (3 * j + 5) & 15;
} else {
f = c ^ (b | ~d);
g = (7 * j) & 15;
}
const tmp = d,
rotateArg = (a + f + k[j] + w[g]) | 0,
rotate = r[j];
d = c;
c = b;
b = (b + ((rotateArg << rotate) | (rotateArg >>> (32 - rotate)))) | 0;
a = tmp;
}
h0 = (h0 + a) | 0;
h1 = (h1 + b) | 0;
h2 = (h2 + c) | 0;
h3 = (h3 + d) | 0;
}
// prettier-ignore
return new Uint8Array([
h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >>> 24) & 0xFF,
h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >>> 24) & 0xFF,
h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >>> 24) & 0xFF,
h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >>> 24) & 0xFF
]);
}
export { calculateMD5 };

View File

@ -0,0 +1,161 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { shadow } from "../shared/util.js";
const PARAMS = {
get k() {
return shadow(
this,
"k",
[
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
]
);
},
};
function rotr(x, n) {
return (x >>> n) | (x << (32 - n));
}
function ch(x, y, z) {
return (x & y) ^ (~x & z);
}
function maj(x, y, z) {
return (x & y) ^ (x & z) ^ (y & z);
}
function sigma(x) {
return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22);
}
function sigmaPrime(x) {
return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25);
}
function littleSigma(x) {
return rotr(x, 7) ^ rotr(x, 18) ^ (x >>> 3);
}
function littleSigmaPrime(x) {
return rotr(x, 17) ^ rotr(x, 19) ^ (x >>> 10);
}
function calculateSHA256(data, offset, length) {
// initial hash values
let h0 = 0x6a09e667,
h1 = 0xbb67ae85,
h2 = 0x3c6ef372,
h3 = 0xa54ff53a,
h4 = 0x510e527f,
h5 = 0x9b05688c,
h6 = 0x1f83d9ab,
h7 = 0x5be0cd19;
// pre-processing
const paddedLength = Math.ceil((length + 9) / 64) * 64;
const padded = new Uint8Array(paddedLength);
let i, j;
for (i = 0; i < length; ++i) {
padded[i] = data[offset++];
}
padded[i++] = 0x80;
const n = paddedLength - 8;
if (i < n) {
i = n;
}
i += 3;
padded[i++] = (length >>> 29) & 0xff;
padded[i++] = (length >> 21) & 0xff;
padded[i++] = (length >> 13) & 0xff;
padded[i++] = (length >> 5) & 0xff;
padded[i++] = (length << 3) & 0xff;
const w = new Uint32Array(64);
const { k } = PARAMS;
// for each 512 bit block
for (i = 0; i < paddedLength; ) {
for (j = 0; j < 16; ++j) {
w[j] =
(padded[i] << 24) |
(padded[i + 1] << 16) |
(padded[i + 2] << 8) |
padded[i + 3];
i += 4;
}
for (j = 16; j < 64; ++j) {
w[j] =
(littleSigmaPrime(w[j - 2]) +
w[j - 7] +
littleSigma(w[j - 15]) +
w[j - 16]) |
0;
}
let a = h0,
b = h1,
c = h2,
d = h3,
e = h4,
f = h5,
g = h6,
h = h7,
t1,
t2;
for (j = 0; j < 64; ++j) {
t1 = h + sigmaPrime(e) + ch(e, f, g) + k[j] + w[j];
t2 = sigma(a) + maj(a, b, c);
h = g;
g = f;
f = e;
e = (d + t1) | 0;
d = c;
c = b;
b = a;
a = (t1 + t2) | 0;
}
h0 = (h0 + a) | 0;
h1 = (h1 + b) | 0;
h2 = (h2 + c) | 0;
h3 = (h3 + d) | 0;
h4 = (h4 + e) | 0;
h5 = (h5 + f) | 0;
h6 = (h6 + g) | 0;
h7 = (h7 + h) | 0;
}
// prettier-ignore
return new Uint8Array([
(h0 >> 24) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 8) & 0xFF, (h0) & 0xFF,
(h1 >> 24) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 8) & 0xFF, (h1) & 0xFF,
(h2 >> 24) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 8) & 0xFF, (h2) & 0xFF,
(h3 >> 24) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 8) & 0xFF, (h3) & 0xFF,
(h4 >> 24) & 0xFF, (h4 >> 16) & 0xFF, (h4 >> 8) & 0xFF, (h4) & 0xFF,
(h5 >> 24) & 0xFF, (h5 >> 16) & 0xFF, (h5 >> 8) & 0xFF, (h5) & 0xFF,
(h6 >> 24) & 0xFF, (h6 >> 16) & 0xFF, (h6 >> 8) & 0xFF, (h6) & 0xFF,
(h7 >> 24) & 0xFF, (h7 >> 16) & 0xFF, (h7 >> 8) & 0xFF, (h7) & 0xFF
]);
}
export { calculateSHA256 };

View File

@ -0,0 +1,400 @@
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { shadow } from "../shared/util.js";
class Word64 {
constructor(highInteger, lowInteger) {
this.high = highInteger | 0;
this.low = lowInteger | 0;
}
and(word) {
this.high &= word.high;
this.low &= word.low;
}
xor(word) {
this.high ^= word.high;
this.low ^= word.low;
}
shiftRight(places) {
if (places >= 32) {
this.low = (this.high >>> (places - 32)) | 0;
this.high = 0;
} else {
this.low = (this.low >>> places) | (this.high << (32 - places));
this.high = (this.high >>> places) | 0;
}
}
rotateRight(places) {
let low, high;
if (places & 32) {
high = this.low;
low = this.high;
} else {
low = this.low;
high = this.high;
}
places &= 31;
this.low = (low >>> places) | (high << (32 - places));
this.high = (high >>> places) | (low << (32 - places));
}
not() {
this.high = ~this.high;
this.low = ~this.low;
}
add(word) {
const lowAdd = (this.low >>> 0) + (word.low >>> 0);
let highAdd = (this.high >>> 0) + (word.high >>> 0);
if (lowAdd > 0xffffffff) {
highAdd += 1;
}
this.low = lowAdd | 0;
this.high = highAdd | 0;
}
copyTo(bytes, offset) {
bytes[offset] = (this.high >>> 24) & 0xff;
bytes[offset + 1] = (this.high >> 16) & 0xff;
bytes[offset + 2] = (this.high >> 8) & 0xff;
bytes[offset + 3] = this.high & 0xff;
bytes[offset + 4] = (this.low >>> 24) & 0xff;
bytes[offset + 5] = (this.low >> 16) & 0xff;
bytes[offset + 6] = (this.low >> 8) & 0xff;
bytes[offset + 7] = this.low & 0xff;
}
assign(word) {
this.high = word.high;
this.low = word.low;
}
}
const PARAMS = {
get k() {
return shadow(this, "k", [
new Word64(0x428a2f98, 0xd728ae22),
new Word64(0x71374491, 0x23ef65cd),
new Word64(0xb5c0fbcf, 0xec4d3b2f),
new Word64(0xe9b5dba5, 0x8189dbbc),
new Word64(0x3956c25b, 0xf348b538),
new Word64(0x59f111f1, 0xb605d019),
new Word64(0x923f82a4, 0xaf194f9b),
new Word64(0xab1c5ed5, 0xda6d8118),
new Word64(0xd807aa98, 0xa3030242),
new Word64(0x12835b01, 0x45706fbe),
new Word64(0x243185be, 0x4ee4b28c),
new Word64(0x550c7dc3, 0xd5ffb4e2),
new Word64(0x72be5d74, 0xf27b896f),
new Word64(0x80deb1fe, 0x3b1696b1),
new Word64(0x9bdc06a7, 0x25c71235),
new Word64(0xc19bf174, 0xcf692694),
new Word64(0xe49b69c1, 0x9ef14ad2),
new Word64(0xefbe4786, 0x384f25e3),
new Word64(0x0fc19dc6, 0x8b8cd5b5),
new Word64(0x240ca1cc, 0x77ac9c65),
new Word64(0x2de92c6f, 0x592b0275),
new Word64(0x4a7484aa, 0x6ea6e483),
new Word64(0x5cb0a9dc, 0xbd41fbd4),
new Word64(0x76f988da, 0x831153b5),
new Word64(0x983e5152, 0xee66dfab),
new Word64(0xa831c66d, 0x2db43210),
new Word64(0xb00327c8, 0x98fb213f),
new Word64(0xbf597fc7, 0xbeef0ee4),
new Word64(0xc6e00bf3, 0x3da88fc2),
new Word64(0xd5a79147, 0x930aa725),
new Word64(0x06ca6351, 0xe003826f),
new Word64(0x14292967, 0x0a0e6e70),
new Word64(0x27b70a85, 0x46d22ffc),
new Word64(0x2e1b2138, 0x5c26c926),
new Word64(0x4d2c6dfc, 0x5ac42aed),
new Word64(0x53380d13, 0x9d95b3df),
new Word64(0x650a7354, 0x8baf63de),
new Word64(0x766a0abb, 0x3c77b2a8),
new Word64(0x81c2c92e, 0x47edaee6),
new Word64(0x92722c85, 0x1482353b),
new Word64(0xa2bfe8a1, 0x4cf10364),
new Word64(0xa81a664b, 0xbc423001),
new Word64(0xc24b8b70, 0xd0f89791),
new Word64(0xc76c51a3, 0x0654be30),
new Word64(0xd192e819, 0xd6ef5218),
new Word64(0xd6990624, 0x5565a910),
new Word64(0xf40e3585, 0x5771202a),
new Word64(0x106aa070, 0x32bbd1b8),
new Word64(0x19a4c116, 0xb8d2d0c8),
new Word64(0x1e376c08, 0x5141ab53),
new Word64(0x2748774c, 0xdf8eeb99),
new Word64(0x34b0bcb5, 0xe19b48a8),
new Word64(0x391c0cb3, 0xc5c95a63),
new Word64(0x4ed8aa4a, 0xe3418acb),
new Word64(0x5b9cca4f, 0x7763e373),
new Word64(0x682e6ff3, 0xd6b2b8a3),
new Word64(0x748f82ee, 0x5defb2fc),
new Word64(0x78a5636f, 0x43172f60),
new Word64(0x84c87814, 0xa1f0ab72),
new Word64(0x8cc70208, 0x1a6439ec),
new Word64(0x90befffa, 0x23631e28),
new Word64(0xa4506ceb, 0xde82bde9),
new Word64(0xbef9a3f7, 0xb2c67915),
new Word64(0xc67178f2, 0xe372532b),
new Word64(0xca273ece, 0xea26619c),
new Word64(0xd186b8c7, 0x21c0c207),
new Word64(0xeada7dd6, 0xcde0eb1e),
new Word64(0xf57d4f7f, 0xee6ed178),
new Word64(0x06f067aa, 0x72176fba),
new Word64(0x0a637dc5, 0xa2c898a6),
new Word64(0x113f9804, 0xbef90dae),
new Word64(0x1b710b35, 0x131c471b),
new Word64(0x28db77f5, 0x23047d84),
new Word64(0x32caab7b, 0x40c72493),
new Word64(0x3c9ebe0a, 0x15c9bebc),
new Word64(0x431d67c4, 0x9c100d4c),
new Word64(0x4cc5d4be, 0xcb3e42b6),
new Word64(0x597f299c, 0xfc657e2a),
new Word64(0x5fcb6fab, 0x3ad6faec),
new Word64(0x6c44198c, 0x4a475817),
]);
},
};
function ch(result, x, y, z, tmp) {
result.assign(x);
result.and(y);
tmp.assign(x);
tmp.not();
tmp.and(z);
result.xor(tmp);
}
function maj(result, x, y, z, tmp) {
result.assign(x);
result.and(y);
tmp.assign(x);
tmp.and(z);
result.xor(tmp);
tmp.assign(y);
tmp.and(z);
result.xor(tmp);
}
function sigma(result, x, tmp) {
result.assign(x);
result.rotateRight(28);
tmp.assign(x);
tmp.rotateRight(34);
result.xor(tmp);
tmp.assign(x);
tmp.rotateRight(39);
result.xor(tmp);
}
function sigmaPrime(result, x, tmp) {
result.assign(x);
result.rotateRight(14);
tmp.assign(x);
tmp.rotateRight(18);
result.xor(tmp);
tmp.assign(x);
tmp.rotateRight(41);
result.xor(tmp);
}
function littleSigma(result, x, tmp) {
result.assign(x);
result.rotateRight(1);
tmp.assign(x);
tmp.rotateRight(8);
result.xor(tmp);
tmp.assign(x);
tmp.shiftRight(7);
result.xor(tmp);
}
function littleSigmaPrime(result, x, tmp) {
result.assign(x);
result.rotateRight(19);
tmp.assign(x);
tmp.rotateRight(61);
result.xor(tmp);
tmp.assign(x);
tmp.shiftRight(6);
result.xor(tmp);
}
function calculateSHA512(data, offset, length, mode384 = false) {
// initial hash values
let h0, h1, h2, h3, h4, h5, h6, h7;
if (!mode384) {
h0 = new Word64(0x6a09e667, 0xf3bcc908);
h1 = new Word64(0xbb67ae85, 0x84caa73b);
h2 = new Word64(0x3c6ef372, 0xfe94f82b);
h3 = new Word64(0xa54ff53a, 0x5f1d36f1);
h4 = new Word64(0x510e527f, 0xade682d1);
h5 = new Word64(0x9b05688c, 0x2b3e6c1f);
h6 = new Word64(0x1f83d9ab, 0xfb41bd6b);
h7 = new Word64(0x5be0cd19, 0x137e2179);
} else {
// SHA384 is exactly the same
// except with different starting values and a trimmed result
h0 = new Word64(0xcbbb9d5d, 0xc1059ed8);
h1 = new Word64(0x629a292a, 0x367cd507);
h2 = new Word64(0x9159015a, 0x3070dd17);
h3 = new Word64(0x152fecd8, 0xf70e5939);
h4 = new Word64(0x67332667, 0xffc00b31);
h5 = new Word64(0x8eb44a87, 0x68581511);
h6 = new Word64(0xdb0c2e0d, 0x64f98fa7);
h7 = new Word64(0x47b5481d, 0xbefa4fa4);
}
// pre-processing
const paddedLength = Math.ceil((length + 17) / 128) * 128;
const padded = new Uint8Array(paddedLength);
let i, j;
for (i = 0; i < length; ++i) {
padded[i] = data[offset++];
}
padded[i++] = 0x80;
const n = paddedLength - 16;
if (i < n) {
i = n;
}
i += 11;
padded[i++] = (length >>> 29) & 0xff;
padded[i++] = (length >> 21) & 0xff;
padded[i++] = (length >> 13) & 0xff;
padded[i++] = (length >> 5) & 0xff;
padded[i++] = (length << 3) & 0xff;
const w = new Array(80);
for (i = 0; i < 80; i++) {
w[i] = new Word64(0, 0);
}
const { k } = PARAMS;
let a = new Word64(0, 0),
b = new Word64(0, 0),
c = new Word64(0, 0);
let d = new Word64(0, 0),
e = new Word64(0, 0),
f = new Word64(0, 0);
let g = new Word64(0, 0),
h = new Word64(0, 0);
const t1 = new Word64(0, 0),
t2 = new Word64(0, 0);
const tmp1 = new Word64(0, 0),
tmp2 = new Word64(0, 0);
let tmp3;
// for each 1024 bit block
for (i = 0; i < paddedLength; ) {
for (j = 0; j < 16; ++j) {
w[j].high =
(padded[i] << 24) |
(padded[i + 1] << 16) |
(padded[i + 2] << 8) |
padded[i + 3];
w[j].low =
(padded[i + 4] << 24) |
(padded[i + 5] << 16) |
(padded[i + 6] << 8) |
padded[i + 7];
i += 8;
}
for (j = 16; j < 80; ++j) {
tmp3 = w[j];
littleSigmaPrime(tmp3, w[j - 2], tmp2);
tmp3.add(w[j - 7]);
littleSigma(tmp1, w[j - 15], tmp2);
tmp3.add(tmp1);
tmp3.add(w[j - 16]);
}
a.assign(h0);
b.assign(h1);
c.assign(h2);
d.assign(h3);
e.assign(h4);
f.assign(h5);
g.assign(h6);
h.assign(h7);
for (j = 0; j < 80; ++j) {
t1.assign(h);
sigmaPrime(tmp1, e, tmp2);
t1.add(tmp1);
ch(tmp1, e, f, g, tmp2);
t1.add(tmp1);
t1.add(k[j]);
t1.add(w[j]);
sigma(t2, a, tmp2);
maj(tmp1, a, b, c, tmp2);
t2.add(tmp1);
tmp3 = h;
h = g;
g = f;
f = e;
d.add(t1);
e = d;
d = c;
c = b;
b = a;
tmp3.assign(t1);
tmp3.add(t2);
a = tmp3;
}
h0.add(a);
h1.add(b);
h2.add(c);
h3.add(d);
h4.add(e);
h5.add(f);
h6.add(g);
h7.add(h);
}
let result;
if (!mode384) {
result = new Uint8Array(64);
h0.copyTo(result, 0);
h1.copyTo(result, 8);
h2.copyTo(result, 16);
h3.copyTo(result, 24);
h4.copyTo(result, 32);
h5.copyTo(result, 40);
h6.copyTo(result, 48);
h7.copyTo(result, 56);
} else {
result = new Uint8Array(48);
h0.copyTo(result, 0);
h1.copyTo(result, 8);
h2.copyTo(result, 16);
h3.copyTo(result, 24);
h4.copyTo(result, 32);
h5.copyTo(result, 40);
}
return result;
}
function calculateSHA384(data, offset, length) {
return calculateSHA512(data, offset, length, /* mode384 = */ true);
}
export { calculateSHA384, calculateSHA512 };

File diff suppressed because it is too large Load Diff

View File

@ -60,7 +60,7 @@ import {
} from "./primitives.js";
import { getXfaFontDict, getXfaFontName } from "./xfa_fonts.js";
import { BaseStream } from "./base_stream.js";
import { calculateMD5 } from "./crypto.js";
import { calculateMD5 } from "./calculate_md5.js";
import { Catalog } from "./catalog.js";
import { clearGlobalCaches } from "./cleanup_helper.js";
import { DatasetReader } from "./dataset_reader.js";

View File

@ -33,78 +33,41 @@ class PDFFunctionFactory {
this.isEvalSupported = isEvalSupported !== false;
}
create(fn) {
const cachedFunction = this.getCached(fn);
if (cachedFunction) {
return cachedFunction;
}
const parsedFunction = PDFFunction.parse({
xref: this.xref,
isEvalSupported: this.isEvalSupported,
fn: fn instanceof Ref ? this.xref.fetch(fn) : fn,
});
create(fn, parseArray = false) {
let fnRef, parsedFn;
// Attempt to cache the parsed Function, by reference.
this._cache(fn, parsedFunction);
return parsedFunction;
}
createFromArray(fnObj) {
const cachedFunction = this.getCached(fnObj);
if (cachedFunction) {
return cachedFunction;
}
const parsedFunction = PDFFunction.parseArray({
xref: this.xref,
isEvalSupported: this.isEvalSupported,
fnObj: fnObj instanceof Ref ? this.xref.fetch(fnObj) : fnObj,
});
// Attempt to cache the parsed Function, by reference.
this._cache(fnObj, parsedFunction);
return parsedFunction;
}
getCached(cacheKey) {
let fnRef;
if (cacheKey instanceof Ref) {
fnRef = cacheKey;
} else if (cacheKey instanceof Dict) {
fnRef = cacheKey.objId;
} else if (cacheKey instanceof BaseStream) {
fnRef = cacheKey.dict?.objId;
// Check if the Function is cached first, to avoid re-parsing it.
if (fn instanceof Ref) {
fnRef = fn;
} else if (fn instanceof Dict) {
fnRef = fn.objId;
} else if (fn instanceof BaseStream) {
fnRef = fn.dict?.objId;
}
if (fnRef) {
const localFunction = this._localFunctionCache.getByRef(fnRef);
if (localFunction) {
return localFunction;
const cachedFn = this._localFunctionCache.getByRef(fnRef);
if (cachedFn) {
return cachedFn;
}
}
return null;
}
/**
* @private
*/
_cache(cacheKey, parsedFunction) {
if (!parsedFunction) {
throw new Error(
'PDFFunctionFactory._cache - expected "parsedFunction" argument.'
);
}
let fnRef;
if (cacheKey instanceof Ref) {
fnRef = cacheKey;
} else if (cacheKey instanceof Dict) {
fnRef = cacheKey.objId;
} else if (cacheKey instanceof BaseStream) {
fnRef = cacheKey.dict?.objId;
const fnObj = this.xref.fetchIfRef(fn);
if (Array.isArray(fnObj)) {
if (!parseArray) {
throw new Error(
'PDFFunctionFactory.create - expected "parseArray" argument.'
);
}
parsedFn = PDFFunction.parseArray(this, fnObj);
} else {
parsedFn = PDFFunction.parse(this, fnObj);
}
// Attempt to cache the parsed Function, by reference.
if (fnRef) {
this._localFunctionCache.set(/* name = */ null, fnRef, parsedFunction);
this._localFunctionCache.set(/* name = */ null, fnRef, parsedFn);
}
return parsedFn;
}
/**
@ -156,36 +119,31 @@ class PDFFunction {
return array;
}
static parse({ xref, isEvalSupported, fn }) {
static parse(factory, fn) {
const dict = fn.dict || fn;
const typeNum = dict.get("FunctionType");
switch (typeNum) {
case 0:
return this.constructSampled({ xref, isEvalSupported, fn, dict });
return this.constructSampled(factory, fn, dict);
case 1:
break;
case 2:
return this.constructInterpolated({ xref, isEvalSupported, dict });
return this.constructInterpolated(factory, dict);
case 3:
return this.constructStiched({ xref, isEvalSupported, dict });
return this.constructStiched(factory, dict);
case 4:
return this.constructPostScript({ xref, isEvalSupported, fn, dict });
return this.constructPostScript(factory, fn, dict);
}
throw new FormatError("Unknown type of function");
}
static parseArray({ xref, isEvalSupported, fnObj }) {
if (!Array.isArray(fnObj)) {
// not an array -- parsing as regular function
return this.parse({ xref, isEvalSupported, fn: fnObj });
}
static parseArray(factory, fnObj) {
const { xref } = factory;
const fnArray = [];
for (const fn of fnObj) {
fnArray.push(
this.parse({ xref, isEvalSupported, fn: xref.fetchIfRef(fn) })
);
fnArray.push(this.parse(factory, xref.fetchIfRef(fn)));
}
return function (src, srcOffset, dest, destOffset) {
for (let i = 0, ii = fnArray.length; i < ii; i++) {
@ -194,7 +152,7 @@ class PDFFunction {
};
}
static constructSampled({ xref, isEvalSupported, fn, dict }) {
static constructSampled(factory, fn, dict) {
function toMultiArray(arr) {
const inputLength = arr.length;
const out = [];
@ -317,7 +275,7 @@ class PDFFunction {
};
}
static constructInterpolated({ xref, isEvalSupported, dict }) {
static constructInterpolated(factory, dict) {
const c0 = toNumberArray(dict.getArray("C0")) || [0];
const c1 = toNumberArray(dict.getArray("C1")) || [1];
const n = dict.get("N");
@ -337,7 +295,7 @@ class PDFFunction {
};
}
static constructStiched({ xref, isEvalSupported, dict }) {
static constructStiched(factory, dict) {
const domain = toNumberArray(dict.getArray("Domain"));
if (!domain) {
@ -348,10 +306,11 @@ class PDFFunction {
if (inputSize !== 1) {
throw new FormatError("Bad domain for stiched function");
}
const { xref } = factory;
const fns = [];
for (const fn of dict.get("Functions")) {
fns.push(this.parse({ xref, isEvalSupported, fn: xref.fetchIfRef(fn) }));
fns.push(this.parse(factory, xref.fetchIfRef(fn)));
}
const bounds = toNumberArray(dict.getArray("Bounds"));
@ -395,7 +354,7 @@ class PDFFunction {
};
}
static constructPostScript({ xref, isEvalSupported, fn, dict }) {
static constructPostScript(factory, fn, dict) {
const domain = toNumberArray(dict.getArray("Domain"));
const range = toNumberArray(dict.getArray("Range"));
@ -411,7 +370,7 @@ class PDFFunction {
const parser = new PostScriptParser(lexer);
const code = parser.parse();
if (isEvalSupported && FeatureTest.isEvalSupported) {
if (factory.isEvalSupported && FeatureTest.isEvalSupported) {
const compiled = new PostScriptCompiler().compile(code, domain, range);
if (compiled) {
// Compiled function consists of simple expressions such as addition,

View File

@ -18,6 +18,7 @@ import {
FormatError,
IDENTITY_MATRIX,
info,
MathClamp,
unreachable,
Util,
warn,
@ -178,7 +179,7 @@ class RadialAxialShading extends BaseShading {
this.extendEnd = extendEnd;
const fnObj = dict.getRaw("Function");
const fn = pdfFunctionFactory.createFromArray(fnObj);
const fn = pdfFunctionFactory.create(fnObj, /* parseArray = */ true);
// Use lcm(1,2,3,4,5,6,7,8,10) = 840 (including 9 increases this to 2520)
// to catch evenly spaced stops. oeis.org/A003418
@ -486,7 +487,9 @@ class MeshShading extends BaseShading {
: null;
const fnObj = dict.getRaw("Function");
const fn = fnObj ? pdfFunctionFactory.createFromArray(fnObj) : null;
const fn = fnObj
? pdfFunctionFactory.create(fnObj, /* parseArray = */ true)
: null;
this.coords = [];
this.colors = [];
@ -843,17 +846,19 @@ class MeshShading extends BaseShading {
((figureMaxX - figureMinX) * MeshShading.TRIANGLE_DENSITY) /
(this.bounds[2] - this.bounds[0])
);
splitXBy = Math.max(
splitXBy = MathClamp(
splitXBy,
MeshShading.MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
Math.min(MeshShading.MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitXBy)
MeshShading.MAX_SPLIT_PATCH_CHUNKS_AMOUNT
);
let splitYBy = Math.ceil(
((figureMaxY - figureMinY) * MeshShading.TRIANGLE_DENSITY) /
(this.bounds[3] - this.bounds[1])
);
splitYBy = Math.max(
splitYBy = MathClamp(
splitYBy,
MeshShading.MIN_SPLIT_PATCH_CHUNKS_AMOUNT,
Math.min(MeshShading.MAX_SPLIT_PATCH_CHUNKS_AMOUNT, splitYBy)
MeshShading.MAX_SPLIT_PATCH_CHUNKS_AMOUNT
);
const verticesPerRow = splitXBy + 1;

View File

@ -25,7 +25,7 @@ import {
import { SimpleDOMNode, SimpleXMLParser } from "./xml_parser.js";
import { Stream, StringStream } from "./stream.js";
import { BaseStream } from "./base_stream.js";
import { calculateMD5 } from "./crypto.js";
import { calculateMD5 } from "./calculate_md5.js";
async function writeObject(ref, obj, buffer, { encrypt = null }) {
const transform = encrypt?.createCipherTransform(ref.num, ref.gen);

View File

@ -21,6 +21,7 @@ import {
$isSplittable,
$isThereMoreWidth,
} from "./symbol_utils.js";
import { MathClamp } from "../../shared/util.js";
import { measureToString } from "./html_utils.js";
// Subform and ExclGroup have a layout so they share these functions.
@ -141,7 +142,7 @@ function addHTML(node, html, bbox) {
break;
}
case "table": {
extra.width = Math.min(availableSpace.width, Math.max(extra.width, w));
extra.width = MathClamp(w, extra.width, availableSpace.width);
extra.height += h;
extra.children.push(html);
break;
@ -150,7 +151,7 @@ function addHTML(node, html, bbox) {
// Even if the subform can possibly take all the available width,
// we must compute the final width as it is in order to be able
// for example to center the subform within its parent.
extra.width = Math.min(availableSpace.width, Math.max(extra.width, w));
extra.width = MathClamp(w, extra.width, availableSpace.width);
extra.height += h;
extra.children.push(html);
break;

View File

@ -81,13 +81,11 @@ const StyleMapping = new Map([
["kerning-mode", value => (value === "none" ? "none" : "normal")],
[
"xfa-font-horizontal-scale",
value =>
`scaleX(${Math.max(0, Math.min(parseInt(value) / 100)).toFixed(2)})`,
value => `scaleX(${Math.max(0, parseInt(value) / 100).toFixed(2)})`,
],
[
"xfa-font-vertical-scale",
value =>
`scaleY(${Math.max(0, Math.min(parseInt(value) / 100)).toFixed(2)})`,
value => `scaleY(${Math.max(0, parseInt(value) / 100).toFixed(2)})`,
],
["xfa-spacerun", ""],
["xfa-tab-stops", ""],

View File

@ -17,20 +17,22 @@ import {
AES128Cipher,
AES256Cipher,
ARCFourCipher,
calculateMD5,
calculateSHA256,
calculateSHA384,
calculateSHA512,
CipherTransformFactory,
PDF17,
PDF20,
} from "../../src/core/crypto.js";
import {
calculateSHA384,
calculateSHA512,
} from "../../src/core/calculate_sha_other.js";
import { Dict, Name } from "../../src/core/primitives.js";
import {
PasswordException,
PasswordResponses,
stringToBytes,
} from "../../src/shared/util.js";
import { calculateMD5 } from "../../src/core/calculate_md5.js";
import { calculateSHA256 } from "../../src/core/calculate_sha256.js";
describe("crypto", function () {
function hex2binary(s) {