X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=pdf2swf%2Fxpdf%2FDecrypt.cc;h=dab075093c3b7ab5a16516a9026fb8d2952de89b;hb=c7432833fe3a6469d63fad135151a92e12877b94;hp=ae9b73239db692f92197f7191d4c1ceb5c1be874;hpb=fc554a43712b76d16b41ec77dd311b4a78b1ef6b;p=swftools.git diff --git a/pdf2swf/xpdf/Decrypt.cc b/pdf2swf/xpdf/Decrypt.cc index ae9b732..dab0750 100644 --- a/pdf2swf/xpdf/Decrypt.cc +++ b/pdf2swf/xpdf/Decrypt.cc @@ -2,11 +2,13 @@ // // Decrypt.cc // -// Copyright 1996 Derek B. Noonburg +// Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== -#ifdef __GNUC__ +#include + +#ifdef USE_GCC_PRAGMAS #pragma implementation #endif @@ -28,42 +30,109 @@ static Guchar passwordPad[32] = { // Decrypt //------------------------------------------------------------------------ -Decrypt::Decrypt(Guchar *fileKey, int objNum, int objGen) { +Decrypt::Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen) { + int i; + // construct object key - objKey[0] = fileKey[0]; - objKey[1] = fileKey[1]; - objKey[2] = fileKey[2]; - objKey[3] = fileKey[3]; - objKey[4] = fileKey[4]; - objKey[5] = objNum & 0xff; - objKey[6] = (objNum >> 8) & 0xff; - objKey[7] = (objNum >> 16) & 0xff; - objKey[8] = objGen & 0xff; - objKey[9] = (objGen >> 8) & 0xff; - md5(objKey, 10, objKey); + for (i = 0; i < keyLength; ++i) { + objKey[i] = fileKey[i]; + } + objKey[keyLength] = objNum & 0xff; + objKey[keyLength + 1] = (objNum >> 8) & 0xff; + objKey[keyLength + 2] = (objNum >> 16) & 0xff; + objKey[keyLength + 3] = objGen & 0xff; + objKey[keyLength + 4] = (objGen >> 8) & 0xff; + md5(objKey, keyLength + 5, objKey); // set up for decryption x = y = 0; - rc4InitKey(objKey, 10, state); + if ((objKeyLength = keyLength + 5) > 16) { + objKeyLength = 16; + } + rc4InitKey(objKey, objKeyLength, state); } void Decrypt::reset() { x = y = 0; - rc4InitKey(objKey, 10, state); + rc4InitKey(objKey, objKeyLength, state); } Guchar Decrypt::decryptByte(Guchar c) { return rc4DecryptByte(state, &x, &y, c); } -GBool Decrypt::makeFileKey(GString *ownerKey, GString *userKey, +GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, + GString *ownerKey, GString *userKey, int permissions, GString *fileID, - GString *userPassword, Guchar *fileKey) { + GString *ownerPassword, GString *userPassword, + Guchar *fileKey, GBool *ownerPasswordOk) { + Guchar test[32], test2[32]; + GString *userPassword2; + Guchar fState[256]; + Guchar tmpKey[16]; + Guchar fx, fy; + int len, i, j; + + // try using the supplied owner password to generate the user password + *ownerPasswordOk = gFalse; + if (ownerPassword) { + len = ownerPassword->getLength(); + if (len < 32) { + memcpy(test, ownerPassword->getCString(), len); + memcpy(test + len, passwordPad, 32 - len); + } else { + memcpy(test, ownerPassword->getCString(), 32); + } + md5(test, 32, test); + if (encRevision == 3) { + for (i = 0; i < 50; ++i) { + md5(test, 16, test); + } + } + if (encRevision == 2) { + rc4InitKey(test, keyLength, fState); + fx = fy = 0; + for (i = 0; i < 32; ++i) { + test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i)); + } + } else { + memcpy(test2, ownerKey->getCString(), 32); + for (i = 19; i >= 0; --i) { + for (j = 0; j < keyLength; ++j) { + tmpKey[j] = test[j] ^ i; + } + rc4InitKey(tmpKey, keyLength, fState); + fx = fy = 0; + for (j = 0; j < 32; ++j) { + test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]); + } + } + } + userPassword2 = new GString((char *)test2, 32); + if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, + permissions, fileID, userPassword2, fileKey)) { + *ownerPasswordOk = gTrue; + delete userPassword2; + return gTrue; + } + delete userPassword2; + } + + // try using the supplied user password + return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, + permissions, fileID, userPassword, fileKey); +} + +GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength, + GString *ownerKey, GString *userKey, + int permissions, GString *fileID, + GString *userPassword, Guchar *fileKey) { Guchar *buf; - Guchar userTest[32]; + Guchar test[32]; Guchar fState[256]; + Guchar tmpKey[16]; Guchar fx, fy; - int len, i; + int len, i, j; GBool ok; // generate file key @@ -86,16 +155,41 @@ GBool Decrypt::makeFileKey(GString *ownerKey, GString *userKey, buf[67] = (permissions >> 24) & 0xff; memcpy(buf + 68, fileID->getCString(), fileID->getLength()); md5(buf, 68 + fileID->getLength(), fileKey); + if (encRevision == 3) { + for (i = 0; i < 50; ++i) { + md5(fileKey, keyLength, fileKey); + } + } - // test user key - fx = fy = 0; - rc4InitKey(fileKey, 5, fState); - for (i = 0; i < 32; ++i) { - userTest[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i)); + // test user password + if (encRevision == 2) { + rc4InitKey(fileKey, keyLength, fState); + fx = fy = 0; + for (i = 0; i < 32; ++i) { + test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i)); + } + ok = memcmp(test, passwordPad, 32) == 0; + } else if (encRevision == 3) { + memcpy(test, userKey->getCString(), 32); + for (i = 19; i >= 0; --i) { + for (j = 0; j < keyLength; ++j) { + tmpKey[j] = fileKey[j] ^ i; + } + rc4InitKey(tmpKey, keyLength, fState); + fx = fy = 0; + for (j = 0; j < 32; ++j) { + test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]); + } + } + memcpy(buf, passwordPad, 32); + memcpy(buf + 32, fileID->getCString(), fileID->getLength()); + md5(buf, 32 + fileID->getLength(), buf); + ok = memcmp(test, buf, 16) == 0; + } else { + ok = gFalse; } - ok = memcmp(userTest, passwordPad, 32) == 0; - gfree(buf); + gfree(buf); return ok; } @@ -136,6 +230,7 @@ static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) { // MD5 message digest //------------------------------------------------------------------------ +// this works around a bug in older Sun compilers static inline Gulong rotateLeft(Gulong x, int r) { x &= 0xffffffff; return ((x << r) | (x >> (32 - r))) & 0xffffffff; @@ -285,20 +380,20 @@ static void md5(Guchar *msg, int msgLen, Guchar *digest) { } // break digest into bytes - digest[0] = a & 0xff; - digest[1] = (a >>= 8) & 0xff; - digest[2] = (a >>= 8) & 0xff; - digest[3] = (a >>= 8) & 0xff; - digest[4] = b & 0xff; - digest[5] = (b >>= 8) & 0xff; - digest[6] = (b >>= 8) & 0xff; - digest[7] = (b >>= 8) & 0xff; - digest[8] = c & 0xff; - digest[9] = (c >>= 8) & 0xff; - digest[10] = (c >>= 8) & 0xff; - digest[11] = (c >>= 8) & 0xff; - digest[12] = d & 0xff; - digest[13] = (d >>= 8) & 0xff; - digest[14] = (d >>= 8) & 0xff; - digest[15] = (d >>= 8) & 0xff; + digest[0] = (Guchar)(a & 0xff); + digest[1] = (Guchar)((a >>= 8) & 0xff); + digest[2] = (Guchar)((a >>= 8) & 0xff); + digest[3] = (Guchar)((a >>= 8) & 0xff); + digest[4] = (Guchar)(b & 0xff); + digest[5] = (Guchar)((b >>= 8) & 0xff); + digest[6] = (Guchar)((b >>= 8) & 0xff); + digest[7] = (Guchar)((b >>= 8) & 0xff); + digest[8] = (Guchar)(c & 0xff); + digest[9] = (Guchar)((c >>= 8) & 0xff); + digest[10] = (Guchar)((c >>= 8) & 0xff); + digest[11] = (Guchar)((c >>= 8) & 0xff); + digest[12] = (Guchar)(d & 0xff); + digest[13] = (Guchar)((d >>= 8) & 0xff); + digest[14] = (Guchar)((d >>= 8) & 0xff); + digest[15] = (Guchar)((d >>= 8) & 0xff); }