Correctly pad strings when saving an encrypted pdf (bug 1726789)
This commit is contained in:
parent
2ed133bd99
commit
9619bf92be
@ -1407,11 +1407,12 @@ class CipherTransform {
|
||||
// Append some chars equal to "16 - (M mod 16)"
|
||||
// where M is the string length (see section 7.6.2 in PDF specification)
|
||||
// to have a final string where the length is a multiple of 16.
|
||||
// Special note:
|
||||
// "Note that the pad is present when M is evenly divisible by 16;
|
||||
// it contains 16 bytes of 0x10."
|
||||
const strLen = s.length;
|
||||
const pad = 16 - (strLen % 16);
|
||||
if (pad !== 16) {
|
||||
s = s.padEnd(16 * Math.ceil(strLen / 16), String.fromCharCode(pad));
|
||||
}
|
||||
s += String.fromCharCode(pad).repeat(pad);
|
||||
|
||||
// Generate an initialization vector
|
||||
const iv = new Uint8Array(16);
|
||||
|
@ -581,6 +581,30 @@ describe("CipherTransformFactory", function () {
|
||||
}
|
||||
}
|
||||
|
||||
function ensureAESEncryptedStringHasCorrectLength(
|
||||
dict,
|
||||
fileId,
|
||||
password,
|
||||
string
|
||||
) {
|
||||
const factory = new CipherTransformFactory(dict, fileId, password);
|
||||
const cipher = factory.createCipherTransform(123, 0);
|
||||
const encrypted = cipher.encryptString(string);
|
||||
|
||||
// The final length is a multiple of 16.
|
||||
// If the initial string has a length which is a multiple of 16
|
||||
// then 16 chars of padding are added.
|
||||
// So we've the mapping:
|
||||
// - length: [0-15] => new length: 16
|
||||
// - length: [16-31] => new length: 32
|
||||
// - length: [32-47] => new length: 48
|
||||
// ...
|
||||
expect(encrypted.length).toEqual(
|
||||
16 /* initialization vector length */ +
|
||||
16 * Math.ceil((string.length + 1) / 16)
|
||||
);
|
||||
}
|
||||
|
||||
function ensureEncryptDecryptIsIdentity(dict, fileId, password, string) {
|
||||
const factory = new CipherTransformFactory(dict, fileId, password);
|
||||
const cipher = factory.createCipherTransform(123, 0);
|
||||
@ -807,6 +831,8 @@ describe("CipherTransformFactory", function () {
|
||||
}),
|
||||
});
|
||||
const dict = buildDict(dict3);
|
||||
// 0 char
|
||||
ensureEncryptDecryptIsIdentity(dict, fileId1, "user", "");
|
||||
// 1 char
|
||||
ensureEncryptDecryptIsIdentity(dict, fileId1, "user", "a");
|
||||
// 2 chars
|
||||
@ -828,6 +854,8 @@ describe("CipherTransformFactory", function () {
|
||||
}),
|
||||
});
|
||||
const dict = buildDict(dict3);
|
||||
// 0 chars
|
||||
ensureEncryptDecryptIsIdentity(dict, fileId1, "user", "");
|
||||
// 4 chars
|
||||
ensureEncryptDecryptIsIdentity(dict, fileId1, "user", "aaaa");
|
||||
// 5 chars
|
||||
@ -842,5 +870,61 @@ describe("CipherTransformFactory", function () {
|
||||
"aaaaaaaaaaaaaaaaaaaaaa"
|
||||
);
|
||||
});
|
||||
it("should encrypt and have the correct length using AES128", function () {
|
||||
dict3.CF = buildDict({
|
||||
Identity: buildDict({
|
||||
CFM: Name.get("AESV2"),
|
||||
}),
|
||||
});
|
||||
const dict = buildDict(dict3);
|
||||
// 0 char
|
||||
ensureAESEncryptedStringHasCorrectLength(dict, fileId1, "user", "");
|
||||
// 1 char
|
||||
ensureAESEncryptedStringHasCorrectLength(dict, fileId1, "user", "a");
|
||||
// 2 chars
|
||||
ensureAESEncryptedStringHasCorrectLength(dict, fileId1, "user", "aa");
|
||||
// 16 chars
|
||||
ensureAESEncryptedStringHasCorrectLength(
|
||||
dict,
|
||||
fileId1,
|
||||
"user",
|
||||
"aaaaaaaaaaaaaaaa"
|
||||
);
|
||||
// 19 chars
|
||||
ensureAESEncryptedStringHasCorrectLength(
|
||||
dict,
|
||||
fileId1,
|
||||
"user",
|
||||
"aaaaaaaaaaaaaaaaaaa"
|
||||
);
|
||||
});
|
||||
it("should encrypt and have the correct length using AES256", function () {
|
||||
dict3.CF = buildDict({
|
||||
Identity: buildDict({
|
||||
CFM: Name.get("AESV3"),
|
||||
}),
|
||||
});
|
||||
const dict = buildDict(dict3);
|
||||
// 0 char
|
||||
ensureAESEncryptedStringHasCorrectLength(dict, fileId1, "user", "");
|
||||
// 4 chars
|
||||
ensureAESEncryptedStringHasCorrectLength(dict, fileId1, "user", "aaaa");
|
||||
// 5 chars
|
||||
ensureAESEncryptedStringHasCorrectLength(dict, fileId1, "user", "aaaaa");
|
||||
// 16 chars
|
||||
ensureAESEncryptedStringHasCorrectLength(
|
||||
dict,
|
||||
fileId1,
|
||||
"user",
|
||||
"aaaaaaaaaaaaaaaa"
|
||||
);
|
||||
// 22 chars
|
||||
ensureAESEncryptedStringHasCorrectLength(
|
||||
dict,
|
||||
fileId1,
|
||||
"user",
|
||||
"aaaaaaaaaaaaaaaaaaaaaa"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user