Merge pull request #19629 from Snuffleupagus/split-crypto

Re-factor the `src/core/crypto.js` file
This commit is contained in:
Tim van der Meij 2025-03-09 13:08:40 +01:00 committed by GitHub
commit 81baa16c8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 860 additions and 777 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 };

View File

@ -19,12 +19,16 @@ import {
isArrayEqual, isArrayEqual,
PasswordException, PasswordException,
PasswordResponses, PasswordResponses,
shadow,
stringToBytes, stringToBytes,
unreachable, unreachable,
utf8StringToString, utf8StringToString,
warn, warn,
} from "../shared/util.js"; } from "../shared/util.js";
import { calculateSHA384, calculateSHA512 } from "./calculate_sha_other.js";
import { Dict, isName, Name } from "./primitives.js"; import { Dict, isName, Name } from "./primitives.js";
import { calculateMD5 } from "./calculate_md5.js";
import { calculateSHA256 } from "./calculate_sha256.js";
import { DecryptStream } from "./decrypt_stream.js"; import { DecryptStream } from "./decrypt_stream.js";
class ARCFourCipher { class ARCFourCipher {
@ -75,612 +79,6 @@ class ARCFourCipher {
} }
} }
const calculateMD5 = (function calculateMD5Closure() {
const 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,
]);
const 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 hash(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;
while (i < n) {
padded[i++] = 0;
}
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;
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
const w = new Int32Array(16);
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
]);
}
return hash;
})();
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;
}
or(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;
}
}
shiftLeft(places) {
if (places >= 32) {
this.high = this.low << (places - 32);
this.low = 0;
} else {
this.high = (this.high << places) | (this.low >>> (32 - places));
this.low <<= places;
}
}
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 calculateSHA256 = (function calculateSHA256Closure() {
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);
}
const 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 hash(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;
while (i < n) {
padded[i++] = 0;
}
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
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);
// 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
]);
}
return hash;
})();
const calculateSHA512 = (function calculateSHA512Closure() {
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);
}
// prettier-ignore
const 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 hash(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;
while (i < n) {
padded[i++] = 0;
}
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
padded[i++] = 0;
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);
}
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;
}
return hash;
})();
function calculateSHA384(data, offset, length) {
return calculateSHA512(data, offset, length, /* mode384 = */ true);
}
class NullCipher { class NullCipher {
decryptBlock(data) { decryptBlock(data) {
return data; return data;
@ -692,15 +90,7 @@ class NullCipher {
} }
class AESBaseCipher { class AESBaseCipher {
constructor() { _s = new Uint8Array([
if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
this.constructor === AESBaseCipher
) {
unreachable("Cannot initialize AESBaseCipher.");
}
this._s = new Uint8Array([
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
@ -725,7 +115,7 @@ class AESBaseCipher {
0xb0, 0x54, 0xbb, 0x16, 0xb0, 0x54, 0xbb, 0x16,
]); ]);
this._inv_s = new Uint8Array([ _inv_s = new Uint8Array([
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
@ -750,7 +140,7 @@ class AESBaseCipher {
0x55, 0x21, 0x0c, 0x7d, 0x55, 0x21, 0x0c, 0x7d,
]); ]);
this._mix = new Uint32Array([ _mix = new Uint32Array([
0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927,
0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45,
0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb,
@ -796,11 +186,17 @@ class AESBaseCipher {
0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3,
]); ]);
this._mixCol = new Uint8Array(256); _mixCol = new Uint8Array(256).map((_, i) =>
for (let i = 0; i < 256; i++) { i < 128 ? i << 1 : (i << 1) ^ 0x1b
this._mixCol[i] = i < 128 ? i << 1 : (i << 1) ^ 0x1b; );
}
constructor() {
if (
(typeof PDFJSDev === "undefined" || PDFJSDev.test("TESTING")) &&
this.constructor === AESBaseCipher
) {
unreachable("Cannot initialize AESBaseCipher.");
}
this.buffer = new Uint8Array(16); this.buffer = new Uint8Array(16);
this.bufferPosition = 0; this.bufferPosition = 0;
} }
@ -932,12 +328,12 @@ class AESBaseCipher {
state[15] = t; state[15] = t;
// MixColumns // MixColumns
for (let j = 0; j < 16; j += 4) { for (let j = 0; j < 16; j += 4) {
const s0 = state[j + 0]; const s0 = state[j];
const s1 = state[j + 1]; const s1 = state[j + 1];
const s2 = state[j + 2]; const s2 = state[j + 2];
const s3 = state[j + 3]; const s3 = state[j + 3];
t = s0 ^ s1 ^ s2 ^ s3; t = s0 ^ s1 ^ s2 ^ s3;
state[j + 0] ^= t ^ this._mixCol[s0 ^ s1]; state[j] ^= t ^ this._mixCol[s0 ^ s1];
state[j + 1] ^= t ^ this._mixCol[s1 ^ s2]; state[j + 1] ^= t ^ this._mixCol[s1 ^ s2];
state[j + 2] ^= t ^ this._mixCol[s2 ^ s3]; state[j + 2] ^= t ^ this._mixCol[s2 ^ s3];
state[j + 3] ^= t ^ this._mixCol[s3 ^ s0]; state[j + 3] ^= t ^ this._mixCol[s3 ^ s0];
@ -1071,9 +467,7 @@ class AESBaseCipher {
bufferLength = this.bufferPosition; bufferLength = this.bufferPosition;
const result = []; const result = [];
if (!iv) { iv ||= new Uint8Array(16);
iv = new Uint8Array(16);
}
for (let i = 0; i < sourceLength; ++i) { for (let i = 0; i < sourceLength; ++i) {
buffer[bufferLength] = data[i]; buffer[bufferLength] = data[i];
++bufferLength; ++bufferLength;
@ -1110,13 +504,7 @@ class AESBaseCipher {
} }
class AES128Cipher extends AESBaseCipher { class AES128Cipher extends AESBaseCipher {
constructor(key) { _rcon = new Uint8Array([
super();
this._cyclesOfRepetition = 10;
this._keySize = 160; // bits
this._rcon = new Uint8Array([
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c,
0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a,
0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
@ -1141,6 +529,12 @@ class AES128Cipher extends AESBaseCipher {
0x74, 0xe8, 0xcb, 0x8d, 0x74, 0xe8, 0xcb, 0x8d,
]); ]);
constructor(key) {
super();
this._cyclesOfRepetition = 10;
this._keySize = 160; // bits
this._key = this._expandKey(key); this._key = this._expandKey(key);
} }
@ -1278,7 +672,7 @@ class PDF17 {
} }
class PDF20 { class PDF20 {
_hash(password, input, userBytes) { #hash(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.
let k = calculateSHA256(input, 0, input.length).subarray(0, 32); let k = calculateSHA256(input, 0, input.length).subarray(0, 32);
let e = [0]; let e = [0];
@ -1325,7 +719,7 @@ class PDF20 {
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);
const result = this._hash(password, hashData, userBytes); const result = this.#hash(password, hashData, userBytes);
return isArrayEqual(result, ownerPassword); return isArrayEqual(result, ownerPassword);
} }
@ -1333,7 +727,7 @@ class PDF20 {
const 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);
const result = this._hash(password, hashData, []); const result = this.#hash(password, hashData, []);
return isArrayEqual(result, userPassword); return isArrayEqual(result, userPassword);
} }
@ -1342,7 +736,7 @@ class PDF20 {
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);
const key = this._hash(password, hashData, userBytes); const key = this.#hash(password, hashData, userBytes);
const 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));
} }
@ -1352,7 +746,7 @@ class PDF20 {
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.
const key = this._hash(password, hashData, []); const key = this.#hash(password, hashData, []);
const 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));
} }
@ -1416,11 +810,17 @@ class CipherTransform {
} }
class CipherTransformFactory { class CipherTransformFactory {
static #defaultPasswordBytes = new Uint8Array([ static get _defaultPasswordBytes() {
return shadow(
this,
"_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,
]); ])
);
}
#createEncryptionKey20( #createEncryptionKey20(
revision, revision,
@ -1491,24 +891,20 @@ class CipherTransformFactory {
} }
j = 0; j = 0;
while (i < 32) { while (i < 32) {
hashData[i++] = CipherTransformFactory.#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) { hashData.set(ownerPassword, i);
hashData[i++] = ownerPassword[j]; i += ownerPassword.length;
}
hashData[i++] = flags & 0xff; hashData[i++] = flags & 0xff;
hashData[i++] = (flags >> 8) & 0xff; hashData[i++] = (flags >> 8) & 0xff;
hashData[i++] = (flags >> 16) & 0xff; hashData[i++] = (flags >> 16) & 0xff;
hashData[i++] = (flags >>> 24) & 0xff; hashData[i++] = (flags >>> 24) & 0xff;
for (j = 0, n = fileId.length; j < n; ++j) { hashData.set(fileId, i);
hashData[i++] = fileId[j]; i += fileId.length;
}
if (revision >= 4 && !encryptMetadata) { if (revision >= 4 && !encryptMetadata) {
hashData[i++] = 0xff; hashData.fill(0xff, i, i + 4);
hashData[i++] = 0xff; i += 4;
hashData[i++] = 0xff;
hashData[i++] = 0xff;
} }
let hash = calculateMD5(hashData, 0, i); let hash = calculateMD5(hashData, 0, i);
const keyLengthInBytes = keyLength >> 3; const keyLengthInBytes = keyLength >> 3;
@ -1521,12 +917,12 @@ class CipherTransformFactory {
let cipher, checkData; let cipher, checkData;
if (revision >= 3) { if (revision >= 3) {
for (i = 0; i < 32; ++i) { i = 0;
hashData[i] = CipherTransformFactory.#defaultPasswordBytes[i]; hashData.set(CipherTransformFactory._defaultPasswordBytes, i);
} i += 32;
for (j = 0, n = fileId.length; j < n; ++j) { hashData.set(fileId, i);
hashData[i++] = fileId[j]; i += fileId.length;
}
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;
@ -1546,7 +942,7 @@ class CipherTransformFactory {
} else { } else {
cipher = new ARCFourCipher(encryptionKey); cipher = new ARCFourCipher(encryptionKey);
checkData = cipher.encryptBlock( checkData = cipher.encryptBlock(
CipherTransformFactory.#defaultPasswordBytes 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]) {
@ -1566,7 +962,7 @@ class CipherTransformFactory {
} }
let j = 0; let j = 0;
while (i < 32) { while (i < 32) {
hashData[i++] = CipherTransformFactory.#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;
@ -1849,10 +1245,6 @@ export {
AES128Cipher, AES128Cipher,
AES256Cipher, AES256Cipher,
ARCFourCipher, ARCFourCipher,
calculateMD5,
calculateSHA256,
calculateSHA384,
calculateSHA512,
CipherTransformFactory, CipherTransformFactory,
PDF17, PDF17,
PDF20, PDF20,

View File

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

View File

@ -25,7 +25,7 @@ import {
import { SimpleDOMNode, SimpleXMLParser } from "./xml_parser.js"; import { SimpleDOMNode, SimpleXMLParser } from "./xml_parser.js";
import { Stream, StringStream } from "./stream.js"; import { Stream, StringStream } from "./stream.js";
import { BaseStream } from "./base_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 }) { async function writeObject(ref, obj, buffer, { encrypt = null }) {
const transform = encrypt?.createCipherTransform(ref.num, ref.gen); const transform = encrypt?.createCipherTransform(ref.num, ref.gen);

View File

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