Skip to content

Commit e1cddb3

Browse files
committed
Add support for Info-Zip password check spec for ZipCrypto. (Uses high byte of header modified time, rather than crc). Updates current tests to handle.
1 parent 10242c3 commit e1cddb3

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed

headers/entryHeader.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ module.exports = function () {
8383
set time(val) {
8484
setTime(val);
8585
},
86-
86+
get timeHighByte() {
87+
return (_time >>> 8) & 0xff;
88+
},
8789
get crc() {
8890
return _crc;
8991
},

methods/zipcrypto.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,12 @@ function decrypt(/*Buffer*/ data, /*Object*/ header, /*String, Buffer*/ pwd) {
118118
// 2. decrypt salt what is always 12 bytes and is a part of file content
119119
const salt = decrypter(data.slice(0, 12));
120120

121-
// 3. does password meet expectations
122-
if (salt[11] !== header.crc >>> 24) {
121+
// if bit 3 (0x08) of the general-purpose flags field is set, check salt[11] with the high byte of the header time
122+
// 2 byte data block (as per Info-Zip spec), otherwise check with the high byte of the header entry
123+
const verifyByte = ((header.flags & 0x8) === 0x8) ? header.timeHighByte : header.crc >>> 24;
124+
125+
//3. does password meet expectations
126+
if (salt[11] !== verifyByte) {
123127
throw "ADM-ZIP: Wrong Password";
124128
}
125129

test/methods/zipcrypto.test.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ describe("method - zipcrypto decrypt", () => {
1515
md5: "wYHjota6dQNazueWO9/uDg==",
1616
pwdok: "secret",
1717
pwdbad: "Secret",
18+
flagsencrypted: 0x01,
19+
flagsinfozipencrypted: 0x09,
20+
timeHighByte: 0xD8,
1821
// result
1922
result: Buffer.from("test", "ascii")
2023
};
@@ -40,22 +43,33 @@ describe("method - zipcrypto decrypt", () => {
4043
// is error thrown if invalid password was provided
4144
it("should throw if invalid password is provided", () => {
4245
expect(function badpassword() {
43-
decrypt(source.data, { crc: source.crc }, source.pwdbad);
46+
decrypt(source.data, { crc: source.crc, flags: source.flagsencrypted }, source.pwdbad);
4447
}).to.throw();
4548

4649
expect(function okpassword() {
47-
decrypt(source.data, { crc: source.crc }, source.pwdok);
50+
decrypt(source.data, { crc: source.crc, flags: source.flagsencrypted }, source.pwdok);
51+
}).to.not.throw();
52+
});
53+
54+
// is error thrown if invalid password was provided
55+
it("should throw if invalid password is provided for Info-Zip bit 3 flag", () => {
56+
expect(function badpassword() {
57+
decrypt(source.data, { crc: source.crc, flags: source.flagsinfozipencrypted, timeHighByte: source.timeHighByte }, source.pwdbad);
58+
}).to.throw();
59+
60+
expect(function okpassword() {
61+
decrypt(source.data, { crc: source.crc, flags: source.flagsinfozipencrypted, timeHighByte: source.timeHighByte }, source.pwdok);
4862
}).to.not.throw();
4963
});
5064

5165
// test decryption with both password types
5266
it("test decrypted data with password", () => {
5367
// test password, string
54-
const result1 = decrypt(source.data, { crc: source.crc }, source.pwdok);
68+
const result1 = decrypt(source.data, { crc: source.crc, flags: source.flagsencrypted }, source.pwdok);
5569
expect(result1.compare(source.result)).to.equal(0);
5670

5771
// test password, buffer
58-
const result2 = decrypt(source.data, { crc: source.crc }, Buffer.from(source.pwdok, "ascii"));
72+
const result2 = decrypt(source.data, { crc: source.crc, flags: source.flagsencrypted }, Buffer.from(source.pwdok, "ascii"));
5973
expect(result2.compare(source.result)).to.equal(0);
6074
});
6175
});

0 commit comments

Comments
 (0)