diff -cNr xpdf-0.90/README.decryption xpdf-0.90-fefe/README.decryption *** xpdf-0.90/README.decryption Thu Jan 1 01:00:00 1970 --- xpdf-0.90-fefe/README.decryption Thu Aug 12 00:27:12 1999 *************** *** 0 **** --- 1,103 ---- + xpdf version 0.80 with decryption patches + + With the release of version 0.80 of xpdf, I have retaken the decryption patch + for this new version. + + Due to the changes that came with the 0.80 release, some re-working of parts of + the decryption code became necessary in order to make it all work. + + Most of the comments (below) for version 0.7a still apply. + + DISCLAIMER: I know next to nothing about decryption. All I did was hack the + code to make it work. + + Tony Nugent + December 1998 + + ========================================================================== + + xpdf version 0.7a with decryption patches + + Author: Derek B. Noonburg + URL: http://www.foolabs.com/xpdf/ + Sources: ftp://ftp.foolabs.com/pub/xpdf/xpdf-0.7a.tar.gz + ftp://ftp.foolabs.com/pub/xpdf/xpdf-0.7a-patch1 + ftp://ftp.foolabs.com/pub/xpdf/xpdf-0.7a-patch2 + ftp://ftp.sci.usq.edu.au/pub/linux/xpdf/xpdf-0.7a-patch3 + Packager: Tony Nugent + + This is a xpdf version 0.7a, but with the Makefile, divide-by-zero, and + decryption patches added to it. + + For the reasons why xpdf, as distributed, is not capable of handling + encrypted pdf files, please see: + + http://www.foolabs.com/xpdf/decryption.html + + What I have done is to add the decryption patches, and make all the sources + available in a place off the US continent. + + This was born out of personal necessity... I had an encrypted pdf file that + I *HAD* to read, so I went off to get the decryption patches for it from: + + http://people.a2000.nl/lsmiers/pdf/xpdf.html + + The patches were made available by Leo Smiers (in + Europe, a place that also avoids problems with the senseless US exportation + laws on encryption code). Everything that was needed was in a file called + "encryption.tar.gz", but I found that they didn't apply easily or cleanly, + and it also involved "dropping in" some files into the xpdf source tree. + + Once I got it working, I simply retook the patch again so that all the + source files and patches were all included in one file. + + Now all that is needed is "patch -p1 < patchfile" and everything is done. + (Then you "configure" and "make" as usual). + + I then grabbed xpdf-0.7a-1.src.rpm from RedHat's "rawhide" ("5.2-beta") + distribution and made some minor changes to it so that a decryption-capable + version could be easily rebuilt from a .spec file. + + So that's what I did, and this is the result. It seems to work just fine. + + I did some minor changes to RedHat's .spec file in the rpm so that it is + installed into /usr/X11R6/bin rather than /usr/bin and also to put the + ANNOUNCE file into the /usr/doc/xpdf-0.7a/ directory. + + I have contacted Derek (the author of xpdf) and got his blessing for what + I've done. I've also tried to contact Leo (from who's web site I got the + decryption patches), but in almost two months he has not replied. + + I wrote this README file to document what I've done, then did some + some teaking of the rpm spec file to get this added to the installation + documation directory. + + From my understanding of the US laws on the export of encryption code, + export of the sources for this patched version of the package is not + permitted from the United States in electronic format. (If you do this, + you are considered to be an arms dealer!) As I understand it, the + restrictions apply to taking such code *out* of the US in electronic + format, not importing it nor taking it out in printed format. + + I don't live in the United States and we don't have silly laws like this + here in Australia, so I can do what I like with these sources. + + I'm quite happy to put the resulting patch and the source and (glibc6) + binary RPM files up on our web site and ftp server for general + distribution. + + I will submitted the rpm packages to RedHat, leaving it up to them to do + what they want (err... can) with it. They might be able to use the binary + version, but the probably won't be legally able to redistribute it (to + places outside the US). + + Derek's web pages for xpdf are an excellent resource which I would strongly + recommend a visit to it: + + http://www.foolabs.com/xpdf/ + + -=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=- + Tony Nugent + Computer Systems Officer Faculty of Science + University of Southern Queensland, Toowoomba Oueensland Australia + -=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=- diff -cNr xpdf-0.90/ltk/LTKButtonDialog.cc xpdf-0.90-fefe/ltk/LTKButtonDialog.cc *** xpdf-0.90/ltk/LTKButtonDialog.cc Tue Aug 3 06:37:20 1999 --- xpdf-0.90-fefe/ltk/LTKButtonDialog.cc Thu Aug 12 00:27:12 1999 *************** *** 93,103 **** labelBox = new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, new LTKEmpty()); } ! trueBtn = new LTKButton(NULL, 1, trueBtnLabel ? trueBtnLabel : "Ok", ltkButtonClick, &buttonCbk); trueBtnBox = new LTKBox(NULL, 1, 1, 0, 0, 0, 0, ltkBorderNone, 0, 0, trueBtn); ! falseBtn = new LTKButton(NULL, 0, falseBtnLabel ? falseBtnLabel : "Cancel", ltkButtonClick, &buttonCbk); falseBtnBox = new LTKBox(NULL, 1, 1, 0, 0, 0, 0, ltkBorderNone, 0, 0, falseBtn); --- 93,103 ---- labelBox = new LTKBox(NULL, 1, 1, 2, 2, 2, 2, ltkBorderNone, 0, 0, new LTKEmpty()); } ! trueBtn = new LTKButton(NULL, 1, trueBtnLabel ? trueBtnLabel : (char *)"Ok", ltkButtonClick, &buttonCbk); trueBtnBox = new LTKBox(NULL, 1, 1, 0, 0, 0, 0, ltkBorderNone, 0, 0, trueBtn); ! falseBtn = new LTKButton(NULL, 0, falseBtnLabel ? falseBtnLabel : (char *)"Cancel", ltkButtonClick, &buttonCbk); falseBtnBox = new LTKBox(NULL, 1, 1, 0, 0, 0, 0, ltkBorderNone, 0, 0, falseBtn); diff -cNr xpdf-0.90/xpdf/Makefile.in xpdf-0.90-fefe/xpdf/Makefile.in *** xpdf-0.90/xpdf/Makefile.in Tue Aug 3 06:44:36 1999 --- xpdf-0.90-fefe/xpdf/Makefile.in Thu Aug 12 00:27:12 1999 *************** *** 85,91 **** FontFile.o Gfx.o GfxFont.o GfxState.o Lexer.o Link.o \ LTKOutputDev.o Object.o OutputDev.o Page.o Params.o \ Parser.o PDFDoc.o PSOutputDev.o Stream.o TextOutputDev.o \ ! XOutputDev.o XRef.o xpdf.o XPDF_LIBS = -L$(LTKLIBDIR) -lLTK -L$(GOOLIBDIR) -lGoo $(XLIBS) $(OTHERLIBS) -lm xpdf$(EXE): $(XPDF_OBJS) \ --- 85,91 ---- FontFile.o Gfx.o GfxFont.o GfxState.o Lexer.o Link.o \ LTKOutputDev.o Object.o OutputDev.o Page.o Params.o \ Parser.o PDFDoc.o PSOutputDev.o Stream.o TextOutputDev.o \ ! XOutputDev.o XRef.o xpdf.o md5.o rc4.o XPDF_LIBS = -L$(LTKLIBDIR) -lLTK -L$(GOOLIBDIR) -lGoo $(XLIBS) $(OTHERLIBS) -lm xpdf$(EXE): $(XPDF_OBJS) \ *************** *** 102,108 **** PDFTOPS_OBJS = Array.o Catalog.o Dict.o Error.o FontEncoding.o \ FontFile.o Gfx.o GfxFont.o GfxState.o Lexer.o Link.o \ Object.o OutputDev.o Page.o Params.o Parser.o PDFDoc.o \ ! PSOutputDev.o Stream.o XRef.o pdftops.o PDFTOPS_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdftops$(EXE): $(PDFTOPS_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a --- 102,108 ---- PDFTOPS_OBJS = Array.o Catalog.o Dict.o Error.o FontEncoding.o \ FontFile.o Gfx.o GfxFont.o GfxState.o Lexer.o Link.o \ Object.o OutputDev.o Page.o Params.o Parser.o PDFDoc.o \ ! PSOutputDev.o Stream.o XRef.o pdftops.o md5.o rc4.o PDFTOPS_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdftops$(EXE): $(PDFTOPS_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a *************** *** 114,120 **** PDFTOTEXT_OBJS = Array.o Catalog.o Dict.o Error.o FontEncoding.o \ FontFile.o Gfx.o GfxFont.o GfxState.o Lexer.o Link.o \ Object.o OutputDev.o Page.o Params.o Parser.o PDFDoc.o \ ! TextOutputDev.o Stream.o XRef.o pdftotext.o PDFTOTEXT_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdftotext$(EXE): $(PDFTOTEXT_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a --- 114,120 ---- PDFTOTEXT_OBJS = Array.o Catalog.o Dict.o Error.o FontEncoding.o \ FontFile.o Gfx.o GfxFont.o GfxState.o Lexer.o Link.o \ Object.o OutputDev.o Page.o Params.o Parser.o PDFDoc.o \ ! TextOutputDev.o Stream.o XRef.o pdftotext.o md5.o rc4.o PDFTOTEXT_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdftotext$(EXE): $(PDFTOTEXT_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a *************** *** 126,132 **** PDFINFO_OBJS = Array.o Catalog.o Dict.o Error.o FontEncoding.o \ FontFile.o Gfx.o GfxFont.o GfxState.o Lexer.o Link.o \ Object.o OutputDev.o Page.o Params.o Parser.o PDFDoc.o \ ! Stream.o XRef.o pdfinfo.o PDFINFO_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdfinfo$(EXE): $(PDFINFO_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a --- 126,132 ---- PDFINFO_OBJS = Array.o Catalog.o Dict.o Error.o FontEncoding.o \ FontFile.o Gfx.o GfxFont.o GfxState.o Lexer.o Link.o \ Object.o OutputDev.o Page.o Params.o Parser.o PDFDoc.o \ ! Stream.o XRef.o pdfinfo.o md5.o rc4.o PDFINFO_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdfinfo$(EXE): $(PDFINFO_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a *************** *** 139,145 **** FontFile.o Gfx.o GfxFont.o GfxState.o Lexer.o Link.o \ Object.o OutputDev.o PBMOutputDev.o Page.o Params.o \ Parser.o PDFDoc.o Stream.o TextOutputDev.o XOutputDev.o \ ! XRef.o pdftopbm.o PDFTOPBM_LIBS = -L$(GOOLIBDIR) -lGoo $(XLIBS) $(OTHERLIBS) -lm pdftopbm$(EXE): $(PDFTOPBM_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a --- 139,145 ---- FontFile.o Gfx.o GfxFont.o GfxState.o Lexer.o Link.o \ Object.o OutputDev.o PBMOutputDev.o Page.o Params.o \ Parser.o PDFDoc.o Stream.o TextOutputDev.o XOutputDev.o \ ! XRef.o pdftopbm.o md5.o rc4.o PDFTOPBM_LIBS = -L$(GOOLIBDIR) -lGoo $(XLIBS) $(OTHERLIBS) -lm pdftopbm$(EXE): $(PDFTOPBM_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a *************** *** 151,157 **** PDFIMAGES_OBJS = Array.o Catalog.o Dict.o Error.o FontEncoding.o \ FontFile.o Gfx.o GfxFont.o GfxState.o ImageOutputDev.o \ Lexer.o Link.o Object.o OutputDev.o Page.o Params.o \ ! Parser.o PDFDoc.o Stream.o XRef.o pdfimages.o PDFIMAGES_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdfimages$(EXE): $(PDFIMAGES_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a --- 151,157 ---- PDFIMAGES_OBJS = Array.o Catalog.o Dict.o Error.o FontEncoding.o \ FontFile.o Gfx.o GfxFont.o GfxState.o ImageOutputDev.o \ Lexer.o Link.o Object.o OutputDev.o Page.o Params.o \ ! Parser.o PDFDoc.o Stream.o XRef.o pdfimages.o md5.o rc4.o PDFIMAGES_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdfimages$(EXE): $(PDFIMAGES_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a diff -cNr xpdf-0.90/xpdf/PSOutputDev.cc xpdf-0.90-fefe/xpdf/PSOutputDev.cc *** xpdf-0.90/xpdf/PSOutputDev.cc Tue Aug 3 06:37:46 1999 --- xpdf-0.90-fefe/xpdf/PSOutputDev.cc Thu Aug 12 00:27:12 1999 *************** *** 481,492 **** writePS("/F%d_%d /%s %g\n", font->getID().num, font->getID().gen, psName, scale); for (i = 0; i < 256; i += 8) { ! writePS((i == 0) ? "[ " : " "); for (j = 0; j < 8; ++j) { charName = font->getCharName(i+j); ! writePS("/%s", charName ? charName : ".notdef"); } ! writePS((i == 256-8) ? "]\n" : "\n"); } writePS("pdfMakeFont\n"); } --- 481,492 ---- writePS("/F%d_%d /%s %g\n", font->getID().num, font->getID().gen, psName, scale); for (i = 0; i < 256; i += 8) { ! writePS((char *)((i == 0) ? "[ " : " ")); for (j = 0; j < 8; ++j) { charName = font->getCharName(i+j); ! writePS("/%s", charName ? charName : (char *)".notdef"); } ! writePS((char *)((i == 256-8) ? "]\n" : "\n")); } writePS("pdfMakeFont\n"); } diff -cNr xpdf-0.90/xpdf/Parser.cc xpdf-0.90-fefe/xpdf/Parser.cc *** xpdf-0.90/xpdf/Parser.cc Tue Aug 3 06:39:57 1999 --- xpdf-0.90-fefe/xpdf/Parser.cc Thu Aug 12 00:27:12 1999 *************** *** 16,21 **** --- 16,23 ---- #include "Dict.h" #include "Parser.h" #include "Error.h" + #include "md5.h" + #include "XRef.h" Parser::Parser(Lexer *lexer1) { lexer = lexer1; *************** *** 159,161 **** --- 161,281 ---- else lexer->getObj(&buf2); } + + Object *Parser::getEncryptedObj(Object *obj, int num, int gen) { + char *key; + Stream *str; + Object obj2; + MD5 context; + RC4KEY rc4Key; + GString MD5Key; + GString Key; + + // refill buffer after inline image data + if (inlineImg == 2) { + buf1.free(); + buf2.free(); + lexer->getObj(&buf1); + lexer->getObj(&buf2); + inlineImg = 0; + } + + // array + if (buf1.isCmd("[")) { + shift(); + obj->initArray(); + while (!buf1.isCmd("]") && !buf1.isEOF()) + obj->arrayAdd(getEncryptedObj(&obj2, num, gen)); + if (buf1.isEOF()) + error(getPos(), "End of file inside array"); + shift(); + + // dictionary or stream + } else if (buf1.isCmd("<<")) { + shift(); + obj->initDict(); + while (!buf1.isCmd(">>") && !buf1.isEOF()) { + if (!buf1.isName()) { + error(getPos(), "Dictionary key must be a name object"); + shift(); + } else { + key = copyString(buf1.getName()); + shift(); + if (buf1.isEOF() || buf1.isError()) + break; + obj->dictAdd(key, getEncryptedObj(&obj2, num, gen)); + } + } + if (buf1.isEOF()) + error(getPos(), "End of file inside dictionary"); + if (buf2.isCmd("stream")) { + if ((str = makeStream(obj))) { + obj->initStream(str); + // enable Decryption on base File Stream + str = obj->getStream()->getBaseStream(); + Key.append(xref->getEncryptionKey()); + Key.append((char)( num & 0xff)); + Key.append((char)((num >> 8) & 0xff)); + Key.append((char)((num >>16) & 0xff)); + Key.append((char)( gen & 0xff)); + Key.append((char)((gen >> 8) & 0xff)); + context.update((unsigned char *)Key.getCString(), 10); + context.finalize(); + MD5Key.clear(); + char *p = (char *)context.raw_digest(); + MD5Key.append(p,10); + delete p; + // determine rc4Key + rc4ExpandKey(&rc4Key, (unsigned char *)MD5Key.getCString(), 10); + str->enableEncryption(&rc4Key); + } else { + obj->free(); + obj->initError(); + } + } else { + shift(); + } + + // indirect reference or integer + } else if (buf1.isInt()) { + num = buf1.getInt(); + shift(); + if (buf1.isInt() && buf2.isCmd("R")) { + obj->initRef(num, buf1.getInt()); + shift(); + shift(); + } else { + obj->initInt(num); + } + + // decrypt strings + } else if (buf1.isString()) { + buf1.copy(obj); + GString *s; + s = obj->getString(); + Key.append(xref->getEncryptionKey()); + Key.append((char)( num & 0xff)); + Key.append((char)((num >> 8) & 0xff)); + Key.append((char)((num >>16) & 0xff)); + Key.append((char)( gen & 0xff)); + Key.append((char)((gen >> 8) & 0xff)); + context.update((unsigned char *)Key.getCString(),10); + context.finalize(); + MD5Key.clear(); + char *p = (char *)context.raw_digest(); + MD5Key.append(p,10); + delete p; + // determine rc4Key + rc4ExpandKey(&rc4Key, (unsigned char *)MD5Key.getCString(),10); + rc4Crypt (&rc4Key, + (unsigned char *) obj->getString()->getCString(), + obj->getString()->getLength()); + shift(); + + } else { + buf1.copy(obj); + shift(); + } + + return obj; + } diff -cNr xpdf-0.90/xpdf/Parser.h xpdf-0.90-fefe/xpdf/Parser.h *** xpdf-0.90/xpdf/Parser.h Tue Aug 3 06:40:03 1999 --- xpdf-0.90-fefe/xpdf/Parser.h Thu Aug 12 00:27:12 1999 *************** *** 30,35 **** --- 30,37 ---- // Get the next object from the input stream. Object *getObj(Object *obj); + // if encrypted... + Object *getEncryptedObj(Object *obj, int num, int gen); // Get stream. Stream *getStream() { return lexer->getStream(); } diff -cNr xpdf-0.90/xpdf/Stream.cc xpdf-0.90-fefe/xpdf/Stream.cc *** xpdf-0.90/xpdf/Stream.cc Tue Aug 3 06:40:17 1999 --- xpdf-0.90-fefe/xpdf/Stream.cc Thu Aug 12 00:27:12 1999 *************** *** 519,524 **** --- 519,525 ---- bufPos = start; savePos = -1; dict = *dict1; + encryption = gFalse; } FileStream::~FileStream() { *************** *** 547,557 **** --- 548,568 ---- n = 256; n = fread(buf, 1, n, f); bufEnd = buf + n; + if (encryption == gTrue) { + rc4Crypt(&rc4Key, (unsigned char *)buf, n); + } if (bufPtr >= bufEnd) return gFalse; return gTrue; } + void FileStream::enableEncryption(RC4KEY *prc4Key) + { + // prepare RC4 key + rc4Key = *prc4Key; + encryption = gTrue; + } + void FileStream::setPos(int pos1) { long size; diff -cNr xpdf-0.90/xpdf/Stream.h xpdf-0.90-fefe/xpdf/Stream.h *** xpdf-0.90/xpdf/Stream.h Tue Aug 3 06:40:26 1999 --- xpdf-0.90-fefe/xpdf/Stream.h Thu Aug 12 00:27:12 1999 *************** *** 16,21 **** --- 16,23 ---- #include #include "gtypes.h" #include "Object.h" + #include "Error.h" + #include "rc4.h" //------------------------------------------------------------------------ *************** *** 95,100 **** --- 97,104 ---- // Returns the new stream. Stream *addFilters(Object *dict); + virtual void enableEncryption(RC4KEY *rc4Key) {error(-1, "No FileStream, no decryption");}; + private: Stream *makeFilter(char *name, Stream *str, Object *params); *************** *** 201,208 **** --- 205,216 ---- private: + void enableEncryption(RC4KEY *rc4Key); + GBool fillBuf(); + RC4KEY rc4Key; + GBool encryption; FILE *f; int start; int length; diff -cNr xpdf-0.90/xpdf/XRef.cc xpdf-0.90-fefe/xpdf/XRef.cc *** xpdf-0.90/xpdf/XRef.cc Tue Aug 3 06:40:49 1999 --- xpdf-0.90-fefe/xpdf/XRef.cc Thu Aug 12 00:27:12 1999 *************** *** 22,27 **** --- 22,29 ---- #include "Dict.h" #include "Error.h" #include "XRef.h" + #include "md5.h" + #include "rc4.h" //------------------------------------------------------------------------ *************** *** 46,51 **** --- 48,54 ---- ok = gTrue; size = 0; entries = NULL; + encrypted = gFalse; // get rid of old xref (otherwise it will try to fetch the Root object // in the new document, using the old xref) *************** *** 91,106 **** xref = this; // check for encryption if (checkEncrypted()) { ! ok = gFalse; ! xref = oldXref; ! return; } } XRef::~XRef() { gfree(entries); trailerDict.free(); } // Read startxref position, xref table size, and root. Returns --- 94,116 ---- xref = this; // check for encryption + m_okToPrint = gTrue; + m_okToCopy = gTrue; + m_okToChange = gTrue; + m_okToAddNotes = gTrue; if (checkEncrypted()) { ! if (setupDecryption() == gFalse) { ! ok = gFalse; ! xref = oldXref; ! return; ! } } } XRef::~XRef() { gfree(entries); trailerDict.free(); + encryptionDict.free(); } // Read startxref position, xref table size, and root. Returns *************** *** 380,405 **** } GBool XRef::checkEncrypted() { ! Object obj; ! GBool encrypted; ! ! trailerDict.dictLookup("Encrypt", &obj); ! if ((encrypted = !obj.isNull())) { ! error(-1, "PDF file is encrypted and cannot be displayed"); ! error(-1, "* Decryption support is currently not included in xpdf"); ! error(-1, "* due to legal restrictions: the U.S.A. still has bogus"); ! error(-1, "* export controls on cryptography software."); ! } ! obj.free(); return encrypted; } GBool XRef::okToPrint() { ! return gTrue; } GBool XRef::okToCopy() { ! return gTrue; } Object *XRef::fetch(int num, int gen, Object *obj) { --- 390,414 ---- } GBool XRef::checkEncrypted() { ! trailerDict.dictLookup("Encrypt", &encryptionDict); ! encrypted = encryptionDict.isDict(); return encrypted; } GBool XRef::okToPrint() { ! return m_okToPrint; } GBool XRef::okToCopy() { ! return m_okToCopy; ! } ! ! GBool XRef::okToChange() { ! return m_okToChange; ! } ! ! GBool XRef::okToAddNotes() { ! return m_okToAddNotes; } Object *XRef::fetch(int num, int gen, Object *obj) { *************** *** 424,430 **** if (obj1.isInt() && obj1.getInt() == num && obj2.isInt() && obj2.getInt() == gen && obj3.isCmd("obj")) { ! parser->getObj(obj); } else { obj->initNull(); } --- 433,443 ---- if (obj1.isInt() && obj1.getInt() == num && obj2.isInt() && obj2.getInt() == gen && obj3.isCmd("obj")) { ! if (encrypted) { ! parser->getEncryptedObj(obj, num, gen); ! } else { ! parser->getObj(obj); ! } } else { obj->initNull(); } *************** *** 441,443 **** --- 454,601 ---- Object *XRef::getDocInfo(Object *obj) { return trailerDict.dictLookup("Info", obj); } + + GBool XRef::setupDecryption() { + Object obj; + GBool encrypted; + GBool passwordOk; + GString userPassword; + + // check filter + encryptionDict.dictLookupNF("Filter", &obj); + if (!obj.isName()) { + error(-1, "No filter specified, asume Standard filter"); + } else if (strcmp(obj.getName(), "Standard") != 0) { + error(-1, "File is encrypted with a non Standard Filter.\ + xpdf supports only the standard encryption filter"); + obj.free(); + return gFalse; + } + obj.free(); + + // check for no user password + userPassword.clear(); + if (checkUserPassword(&userPassword) == gFalse) { + // ask for user password ... check with user password + error(-1, "pdf file is encrypted with a user password.\ + xpdf does not support passwords please contact the author of the pdf file\ + and ask him for a non password encrypted version"); + return gFalse; + } + + // set permissions + encryptionDict.dictLookupNF("P", &obj); + if (obj.isNull() || !obj.isInt()) { + error(-1, "No permissions specified"); + return gFalse; + } + int Permissions = obj.getInt(); + obj.free(); + m_okToPrint = Permissions & 0x04 ? gTrue : gFalse; + m_okToChange = Permissions & 0x08 ? gTrue : gFalse; + m_okToCopy = Permissions & 0x10 ? gTrue : gFalse; + m_okToAddNotes = Permissions & 0x20 ? gTrue : gFalse; + + return gTrue; + } + + GBool + XRef::checkUserPassword(GString *userPassword) + { + GString preparedPassword; + RC4KEY rc4Key; + Object obj; + char localPassword[32]; + + if (preparePassword(userPassword, &preparedPassword) == gFalse) { + return gFalse; + } + if (MakeEncryptionKey(&preparedPassword, &encryptionKey) == gFalse) { + return gFalse; + } + // get the User password + encryptionDict.dictLookupNF("U", &obj); + if (obj.isNull() || !obj.isString()) { + error(-1, "No user password specified"); + return gFalse; + } + memcpy(localPassword, obj.getString()->getCString(), 32); + obj.free(); + // prepary RC4 key + rc4ExpandKey(&rc4Key, (unsigned char *)encryptionKey.getCString(), 5); + // encrypt User password + rc4Crypt(&rc4Key, (unsigned char *)&localPassword[0], 32); + // compare preparedPassword and decryptedPassword + for (int i=0; i<32; i++) { + if (localPassword[i] != preparedPassword.getChar(i)) { + // not equal + return gFalse; + } + } + // password OK + return gTrue; + } + + GBool + XRef::MakeEncryptionKey(GString *password, GString *encryptionKey) + { + MD5 context; + Object obj, obj1; + unsigned char Pkey[4]; + + context.update((unsigned char *)password->getCString(), 32); + // others owner key + encryptionDict.dictLookupNF("O", &obj); + if (obj.isNull() || !obj.isString()) { + error(-1, "No owner password specified"); + return gFalse; + } + context.update((unsigned char *)obj.getString()->getCString(), 32); + obj.free(); + // permissions + encryptionDict.dictLookupNF("P", &obj); + if (obj.isNull() || !obj.isInt()) { + error(-1, "No permissions specified"); + return gFalse; + } + int Permissions = obj.getInt(); + Pkey[0] = Permissions & 0xff; + Pkey[1] = (Permissions >> 8 ) & 0xff; + Pkey[2] = (Permissions >> 16) & 0xff; + Pkey[3] = (Permissions >> 24) & 0xff; + context.update(&Pkey[0], 4); + obj.free(); + // first element from ID + trailerDict.dictLookupNF("ID", &obj); + if (obj.isNull() || !obj.isArray()) { + error(-1, "No ID specified"); + return gFalse; + } + obj.arrayGet(0, &obj1); + if (obj1.isNull() || !obj1.isString()) { + error(-1, "No ID elements specified"); + return gFalse; + } + context.update((unsigned char *)(obj1.getString()->getCString()), (int)(obj1.getString()->getLength())); + obj1.free(); + obj.free(); + context.finalize(); + encryptionKey->clear(); + char *p = (char *)context.raw_digest(); + encryptionKey->append(p,5); + delete p; + return gTrue; + } + + GBool + XRef::preparePassword(GString *password, GString *preparedPassword) + { + static char acFill[32] = {0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41, + 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08, + 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80, + 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a}; + preparedPassword->clear(); + preparedPassword->append(password); + preparedPassword->append(&acFill[0], 32); + return gTrue; + } diff -cNr xpdf-0.90/xpdf/XRef.h xpdf-0.90-fefe/xpdf/XRef.h *** xpdf-0.90/xpdf/XRef.h Tue Aug 3 06:40:56 1999 --- xpdf-0.90-fefe/xpdf/XRef.h Thu Aug 12 00:27:12 1999 *************** *** 43,57 **** GBool isOk() { return ok; } // Is the file encrypted? ! GBool isEncrypted() { return gFalse; } // Are printing and copying allowed? If not, print an error message. GBool okToPrint(); GBool okToCopy(); // Get catalog object. Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); } // Fetch an indirect reference. Object *fetch(int num, int gen, Object *obj); --- 43,62 ---- GBool isOk() { return ok; } // Is the file encrypted? ! GBool isEncrypted() { return encrypted; } // Are printing and copying allowed? If not, print an error message. GBool okToPrint(); GBool okToCopy(); + GBool okToChange(); + GBool okToAddNotes(); // Get catalog object. Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); } + // Get encryption key + GString *getEncryptionKey() { return &encryptionKey; }; + // Fetch an indirect reference. Object *fetch(int num, int gen, Object *obj); *************** *** 69,74 **** --- 74,92 ---- GBool ok; // true if xref table is valid Object trailerDict; // trailer dictionary + GBool m_okToPrint; + GBool m_okToCopy; + GBool m_okToChange; + GBool m_okToAddNotes; + Object encryptionDict; // encryption dictionary + GBool encrypted; + GString encryptionKey; + + GBool setupDecryption(); + GBool checkUserPassword(GString *userPassword); + GBool MakeEncryptionKey(GString *password, GString *encryptionKey); + GBool preparePassword(GString *password, GString *preparedPassword); + int readTrailer(FileStream *str); GBool readXRef(FileStream *str, int *pos); GBool constructXRef(FileStream *str); diff -cNr xpdf-0.90/xpdf/config.h xpdf-0.90-fefe/xpdf/config.h *** xpdf-0.90/xpdf/config.h Tue Aug 3 06:37:48 1999 --- xpdf-0.90-fefe/xpdf/config.h Thu Aug 12 00:27:12 1999 *************** *** 4,9 **** --- 4,12 ---- // // Copyright 1996 Derek B. Noonburg // + // original decryption patch by Leo J.B. Smiers + // patch re-taken for v0.7a and reworked for v0.80 by Tony Nugent + // //======================================================================== #ifndef CONFIG_H *************** *** 14,20 **** //------------------------------------------------------------------------ // xpdf version ! #define xpdfVersion "0.90" // supported PDF version #define pdfVersion "1.3" --- 17,23 ---- //------------------------------------------------------------------------ // xpdf version ! #define xpdfVersion "0.90 (decryption)" // supported PDF version #define pdfVersion "1.3" *************** *** 22,27 **** --- 25,31 ---- // copyright notice #define xpdfCopyright "Copyright \251 1996-1999 Derek B. Noonburg" + #define xpdfCopyright_Encryption "Decryption (originally) by Leo J.B. Smiers" // default paper size (in points) for PostScript output #ifdef A4_PAPER diff -cNr xpdf-0.90/xpdf/md5.cc xpdf-0.90-fefe/xpdf/md5.cc *** xpdf-0.90/xpdf/md5.cc Thu Jan 1 01:00:00 1970 --- xpdf-0.90-fefe/xpdf/md5.cc Thu Aug 12 00:27:12 1999 *************** *** 0 **** --- 1,544 ---- + // MD5.CC - source code for the C++/object oriented translation and + // modification of MD5. + + // Translation and modification (c) 1995 by Mordechai T. Abzug + + // This translation/ modification is provided "as is," without express or + // implied warranty of any kind. + + // The translator/ modifier does not claim (1) that MD5 will do what you think + // it does; (2) that this translation/ modification is accurate; or (3) that + // this software is "merchantible." (Language for this disclaimer partially + // copied from the disclaimer below). + + /* based on: + + MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + MDDRIVER.C - test driver for MD2, MD4 and MD5 + + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + + */ + + + + + + + #include "md5.h" + + #include + #include + #include + + + + + // MD5 simple initialization method + + MD5::MD5(){ + + init(); + + } + + + + + // MD5 block update operation. Continues an MD5 message-digest + // operation, processing another message block, and updating the + // context. + + void MD5::update (uint1 *input, uint4 input_length) { + + uint4 input_index, buffer_index; + uint4 buffer_space; // how much space is left in buffer + + if (finalized){ // so we can't update! + cerr << "MD5::update: Can't update a finalized digest!" << endl; + return; + } + + // Compute number of bytes mod 64 + buffer_index = (unsigned int)((count[0] >> 3) & 0x3F); + + // Update number of bits + if ( (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) ) + count[1]++; + + count[1] += ((uint4)input_length >> 29); + + + buffer_space = 64 - buffer_index; // how much space is left in buffer + + // Transform as many times as possible. + if (input_length >= buffer_space) { // ie. we have enough to fill the buffer + // fill the rest of the buffer and transform + memcpy (buffer + buffer_index, input, buffer_space); + transform (buffer); + + // now, transform each 64-byte piece of the input, bypassing the buffer + for (input_index = buffer_space; input_index + 63 < input_length; + input_index += 64) + transform (input+input_index); + + buffer_index = 0; // so we can buffer remaining + } + else + input_index=0; // so we can buffer the whole input + + + // and here we do the buffering: + memcpy(buffer+buffer_index, input+input_index, input_length-input_index); + } + + + + // MD5 update for files. + // Like above, except that it works on files (and uses above as a primitive.) + + void MD5::update(FILE *file){ + + unsigned char buffer[1024]; + int len; + + while (len=fread(buffer, 1, 1024, file)) + update(buffer, len); + + fclose (file); + + } + + + + + + + // MD5 update for istreams. + // Like update for files; see above. + + void MD5::update(istream& stream){ + + unsigned char buffer[1024]; + int len; + + while (stream.good()){ + stream.read(buffer, 1024); // note that return value of read is unusable. + len=stream.gcount(); + update(buffer, len); + } + + } + + + + + + + // MD5 update for ifstreams. + // Like update for files; see above. + + void MD5::update(ifstream& stream){ + + unsigned char buffer[1024]; + int len; + + while (stream.good()){ + stream.read(buffer, 1024); // note that return value of read is unusable. + len=stream.gcount(); + update(buffer, len); + } + + } + + + + + + + // MD5 finalization. Ends an MD5 message-digest operation, writing the + // the message digest and zeroizing the context. + + + void MD5::finalize (){ + + unsigned char bits[8]; + unsigned int index, padLen; + static uint1 PADDING[64]={ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (finalized){ + cerr << "MD5::finalize: Already finalized this digest!" << endl; + return; + } + + // Save number of bits + encode (bits, count, 8); + + // Pad out to 56 mod 64. + index = (uint4) ((count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + update (PADDING, padLen); + + // Append length (before padding) + update (bits, 8); + + // Store state in digest + encode (digest, state, 16); + + // Zeroize sensitive information + memset (buffer, 0, sizeof(*buffer)); + + finalized=1; + + } + + + + + MD5::MD5(FILE *file){ + + init(); // must be called be all constructors + update(file); + finalize (); + } + + + + + MD5::MD5(istream& stream){ + + init(); // must called by all constructors + update (stream); + finalize(); + } + + + + MD5::MD5(ifstream& stream){ + + init(); // must called by all constructors + update (stream); + finalize(); + } + + + + unsigned char *MD5::raw_digest(){ + + uint1 *s = new uint1[16]; + + if (!finalized){ + cerr << "MD5::raw_digest: Can't get digest if you haven't "<< + "finalized the digest!" <> 8) & 0xff); + output[j+2] = (uint1) ((input[i] >> 16) & 0xff); + output[j+3] = (uint1) ((input[i] >> 24) & 0xff); + } + } + + + + + // Decodes input (unsigned char) into output (UINT4). Assumes len is + // a multiple of 4. + void MD5::decode (uint4 *output, uint1 *input, uint4 len){ + + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) | + (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24); + } + + + + + + // Note: Replace "for loop" with standard memcpy if possible. + void MD5::memcpy (uint1 *output, uint1 *input, uint4 len){ + + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; + } + + + + // Note: Replace "for loop" with standard memset if possible. + void MD5::memset (uint1 *output, uint1 value, uint4 len){ + + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = value; + } + + + + // ROTATE_LEFT rotates x left n bits. + + inline unsigned int MD5::rotate_left (uint4 x, uint4 n){ + return (x << n) | (x >> (32-n)) ; + } + + + + + // F, G, H and I are basic MD5 functions. + + inline unsigned int MD5::F (uint4 x, uint4 y, uint4 z){ + return (x & y) | (~x & z); + } + + inline unsigned int MD5::G (uint4 x, uint4 y, uint4 z){ + return (x & z) | (y & ~z); + } + + inline unsigned int MD5::H (uint4 x, uint4 y, uint4 z){ + return x ^ y ^ z; + } + + inline unsigned int MD5::I (uint4 x, uint4 y, uint4 z){ + return y ^ (x | ~z); + } + + + + // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + // Rotation is separate from addition to prevent recomputation. + + + inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac){ + a += F(b, c, d) + x + ac; + a = rotate_left (a, s) +b; + } + + inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac){ + a += G(b, c, d) + x + ac; + a = rotate_left (a, s) +b; + } + + inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac){ + a += H(b, c, d) + x + ac; + a = rotate_left (a, s) +b; + } + + inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac){ + a += I(b, c, d) + x + ac; + a = rotate_left (a, s) +b; + } diff -cNr xpdf-0.90/xpdf/md5.h xpdf-0.90-fefe/xpdf/md5.h *** xpdf-0.90/xpdf/md5.h Thu Jan 1 01:00:00 1970 --- xpdf-0.90-fefe/xpdf/md5.h Thu Aug 12 00:27:12 1999 *************** *** 0 **** --- 1,109 ---- + // MD5.CC - source code for the C++/object oriented translation and + // modification of MD5. + + // Translation and modification (c) 1995 by Mordechai T. Abzug + + // This translation/ modification is provided "as is," without express or + // implied warranty of any kind. + + // The translator/ modifier does not claim (1) that MD5 will do what you think + // it does; (2) that this translation/ modification is accurate; or (3) that + // this software is "merchantible." (Language for this disclaimer partially + // copied from the disclaimer below). + + /* based on: + + MD5.H - header file for MD5C.C + MDDRIVER.C - test driver for MD2, MD4 and MD5 + + Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + rights reserved. + + License to copy and use this software is granted provided that it + is identified as the "RSA Data Security, Inc. MD5 Message-Digest + Algorithm" in all material mentioning or referencing this software + or this function. + + License is also granted to make and use derivative works provided + that such works are identified as "derived from the RSA Data + Security, Inc. MD5 Message-Digest Algorithm" in all material + mentioning or referencing the derived work. + + RSA Data Security, Inc. makes no representations concerning either + the merchantability of this software or the suitability of this + software for any particular purpose. It is provided "as is" + without express or implied warranty of any kind. + + These notices must be retained in any copies of any part of this + documentation and/or software. + + */ + + #include + #include + #include + + class MD5 { + + public: + // methods for controlled operation: + MD5 (); // simple initializer + void update (unsigned char *input, unsigned int input_length); + void update (istream& stream); + void update (FILE *file); + void update (ifstream& stream); + void finalize (); + + // constructors for special circumstances. All these constructors finalize + // the MD5 context. + MD5 (unsigned char *string); // digest string, finalize + MD5 (istream& stream); // digest stream, finalize + MD5 (FILE *file); // digest file, close, finalize + MD5 (ifstream& stream); // digest stream, close, finalize + + // methods to acquire finalized result + unsigned char *raw_digest (); // digest as a 16-byte binary array + char * hex_digest (); // digest as a 33-byte ascii-hex string + friend ostream& operator<< (ostream&, MD5 context); + + + + private: + + // first, some types: + typedef unsigned int uint4; // assumes integer is 4 words long + typedef unsigned short int uint2; // assumes short integer is 2 words long + typedef unsigned char uint1; // assumes char is 1 word long + + // next, the private data: + uint4 state[4]; + uint4 count[2]; // number of *bits*, mod 2^64 + uint1 buffer[64]; // input buffer + uint1 digest[16]; + uint1 finalized; + + // last, the private methods, mostly static: + void init (); // called by all constructors + void transform (uint1 *buffer); // does the real update work. Note + // that length is implied to be 64. + + static void encode (uint1 *dest, uint4 *src, uint4 length); + static void decode (uint4 *dest, uint1 *src, uint4 length); + static void memcpy (uint1 *dest, uint1 *src, uint4 length); + static void memset (uint1 *start, uint1 val, uint4 length); + + static inline uint4 rotate_left (uint4 x, uint4 n); + static inline uint4 F (uint4 x, uint4 y, uint4 z); + static inline uint4 G (uint4 x, uint4 y, uint4 z); + static inline uint4 H (uint4 x, uint4 y, uint4 z); + static inline uint4 I (uint4 x, uint4 y, uint4 z); + static inline void FF (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac); + static inline void GG (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac); + static inline void HH (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac); + static inline void II (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, + uint4 s, uint4 ac); + + }; diff -cNr xpdf-0.90/xpdf/pdftops.cc xpdf-0.90-fefe/xpdf/pdftops.cc *** xpdf-0.90/xpdf/pdftops.cc Tue Aug 3 06:37:46 1999 --- xpdf-0.90-fefe/xpdf/pdftops.cc Thu Aug 12 00:27:12 1999 *************** *** 70,75 **** --- 70,76 ---- if (!ok || argc < 2 || argc > 3 || printHelp) { fprintf(stderr, "pdftops version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); + fprintf(stderr, "%s\n", xpdfCopyright_Encryption); printUsage("pdftops", " []", argDesc); exit(1); } diff -cNr xpdf-0.90/xpdf/pdftotext.cc xpdf-0.90-fefe/xpdf/pdftotext.cc *** xpdf-0.90/xpdf/pdftotext.cc Tue Aug 3 06:37:46 1999 --- xpdf-0.90-fefe/xpdf/pdftotext.cc Thu Aug 12 00:27:12 1999 *************** *** 71,76 **** --- 71,77 ---- if (!ok || argc < 2 || argc > 3 || printHelp) { fprintf(stderr, "pdftotext version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); + fprintf(stderr, "%s\n", xpdfCopyright_Encryption); printUsage("pdftotext", " []", argDesc); exit(1); } diff -cNr xpdf-0.90/xpdf/rc4.cc xpdf-0.90-fefe/xpdf/rc4.cc *** xpdf-0.90/xpdf/rc4.cc Thu Jan 1 01:00:00 1970 --- xpdf-0.90-fefe/xpdf/rc4.cc Thu Aug 12 00:27:12 1999 *************** *** 0 **** --- 1,70 ---- + /************************************************************************ + * * + * RC4 Encryption Algorithm * + * Copyright Peter Gutmann 1995-1996 * + * * + ************************************************************************/ + + /* Optimized RC4 code, from an unknown source ("and they knew not from whence + it had come...") */ + + #include "rc4.h" + + void + rc4ExpandKey( RC4KEY *rc4, unsigned char const *key, int keylen ) + { + int x, keypos = 0; + rc4word sx, y = 0; + rc4word *state = &rc4->state[ 0 ]; + + rc4->x = rc4->y = 0; + + for( x = 0; x < 256; x++ ) + state[ x ] = x; + + for( x = 0; x < 256; x++ ) + { + sx = state[ x ]; + y += sx + key[ keypos ]; + #ifdef USE_LONG_RC4 + y &= 0xFF; + #endif /* USE_LONG_RC4 */ + state[ x ] = state[ y ]; + state[ y ] = sx; + + if( ++keypos == keylen ) + keypos = 0; + } + } + + void + rc4Crypt( RC4KEY *rc4, unsigned char *data, int len ) + { + rc4word x = rc4->x, y = rc4->y; + rc4word sx, sy; + rc4word *state = &rc4->state[ 0 ]; + + while (len--) { + x++; + #ifdef USE_LONG_RC4 + x &= 0xFF; + #endif /* USE_LONG_RC4 */ + sx = state[ x ]; + y += sx; + #ifdef USE_LONG_RC4 + y &= 0xFF; + #endif /* USE_LONG_RC4 */ + sy = state[ y ]; + state[ y ] = sx; + state[ x ] = sy; + + #ifdef USE_LONG_RC4 + *data++ ^= state[ ( unsigned char ) ( sx+sy ) ]; + #else + *data++ ^= state[ ( sx+sy ) & 0xFF ]; + #endif /* USE_LONG_RC4 */ + } + + rc4->x = x; + rc4->y = y; + } diff -cNr xpdf-0.90/xpdf/rc4.h xpdf-0.90-fefe/xpdf/rc4.h *** xpdf-0.90/xpdf/rc4.h Thu Jan 1 01:00:00 1970 --- xpdf-0.90-fefe/xpdf/rc4.h Thu Aug 12 00:27:12 1999 *************** *** 0 **** --- 1,25 ---- + #include + + #if !defined(__RC4_H__) + #define __RC4_H__ + /* If the system can handle byte ops, we use those so we don't have to do a + lot of masking. Otherwise, we use machine-word-size ops which will be + faster on RISC machines */ + + #if UINT_MAX > 0xFFFFL /* System has 32-bit ints */ + #define USE_LONG_RC4 + typedef unsigned int rc4word; + #else + typedef unsigned char rc4word; + #endif /* UINT_MAX > 0xFFFFL */ + + /* The scheduled RC4 key */ + + typedef struct { + rc4word state[ 256 ]; + rc4word x, y; + } RC4KEY ; + + void rc4ExpandKey( RC4KEY *rc4, unsigned char const *key, int keylen ); + void rc4Crypt( RC4KEY *rc4, unsigned char *data, int len ); + #endif diff -cNr xpdf-0.90/xpdf/xpdf.cc xpdf-0.90-fefe/xpdf/xpdf.cc *** xpdf-0.90/xpdf/xpdf.cc Tue Aug 3 06:37:46 1999 --- xpdf-0.90-fefe/xpdf/xpdf.cc Thu Aug 12 00:27:12 1999 *************** *** 373,378 **** --- 373,379 ---- if (!ok || printHelp) { fprintf(stderr, "xpdf version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); + fprintf(stderr, "%s\n", xpdfCopyright_Encryption); printUsage("xpdf", "[ []]", argDesc); ret = 1; goto done2; diff -cNr xpdf-0.90/xpdf-0.90/README.decryption xpdf-0.90-fefe/xpdf-0.90/README.decryption *** xpdf-0.90/xpdf-0.90/README.decryption Thu Jan 1 01:00:00 1970 --- xpdf-0.90-fefe/xpdf-0.90/README.decryption Thu Aug 12 00:27:09 1999 *************** *** 0 **** --- 1,103 ---- + xpdf version 0.80 with decryption patches + + With the release of version 0.80 of xpdf, I have retaken the decryption patch + for this new version. + + Due to the changes that came with the 0.80 release, some re-working of parts of + the decryption code became necessary in order to make it all work. + + Most of the comments (below) for version 0.7a still apply. + + DISCLAIMER: I know next to nothing about decryption. All I did was hack the + code to make it work. + + Tony Nugent + December 1998 + + ========================================================================== + + xpdf version 0.7a with decryption patches + + Author: Derek B. Noonburg + URL: http://www.foolabs.com/xpdf/ + Sources: ftp://ftp.foolabs.com/pub/xpdf/xpdf-0.7a.tar.gz + ftp://ftp.foolabs.com/pub/xpdf/xpdf-0.7a-patch1 + ftp://ftp.foolabs.com/pub/xpdf/xpdf-0.7a-patch2 + ftp://ftp.sci.usq.edu.au/pub/linux/xpdf/xpdf-0.7a-patch3 + Packager: Tony Nugent + + This is a xpdf version 0.7a, but with the Makefile, divide-by-zero, and + decryption patches added to it. + + For the reasons why xpdf, as distributed, is not capable of handling + encrypted pdf files, please see: + + http://www.foolabs.com/xpdf/decryption.html + + What I have done is to add the decryption patches, and make all the sources + available in a place off the US continent. + + This was born out of personal necessity... I had an encrypted pdf file that + I *HAD* to read, so I went off to get the decryption patches for it from: + + http://people.a2000.nl/lsmiers/pdf/xpdf.html + + The patches were made available by Leo Smiers (in + Europe, a place that also avoids problems with the senseless US exportation + laws on encryption code). Everything that was needed was in a file called + "encryption.tar.gz", but I found that they didn't apply easily or cleanly, + and it also involved "dropping in" some files into the xpdf source tree. + + Once I got it working, I simply retook the patch again so that all the + source files and patches were all included in one file. + + Now all that is needed is "patch -p1 < patchfile" and everything is done. + (Then you "configure" and "make" as usual). + + I then grabbed xpdf-0.7a-1.src.rpm from RedHat's "rawhide" ("5.2-beta") + distribution and made some minor changes to it so that a decryption-capable + version could be easily rebuilt from a .spec file. + + So that's what I did, and this is the result. It seems to work just fine. + + I did some minor changes to RedHat's .spec file in the rpm so that it is + installed into /usr/X11R6/bin rather than /usr/bin and also to put the + ANNOUNCE file into the /usr/doc/xpdf-0.7a/ directory. + + I have contacted Derek (the author of xpdf) and got his blessing for what + I've done. I've also tried to contact Leo (from who's web site I got the + decryption patches), but in almost two months he has not replied. + + I wrote this README file to document what I've done, then did some + some teaking of the rpm spec file to get this added to the installation + documation directory. + + From my understanding of the US laws on the export of encryption code, + export of the sources for this patched version of the package is not + permitted from the United States in electronic format. (If you do this, + you are considered to be an arms dealer!) As I understand it, the + restrictions apply to taking such code *out* of the US in electronic + format, not importing it nor taking it out in printed format. + + I don't live in the United States and we don't have silly laws like this + here in Australia, so I can do what I like with these sources. + + I'm quite happy to put the resulting patch and the source and (glibc6) + binary RPM files up on our web site and ftp server for general + distribution. + + I will submitted the rpm packages to RedHat, leaving it up to them to do + what they want (err... can) with it. They might be able to use the binary + version, but the probably won't be legally able to redistribute it (to + places outside the US). + + Derek's web pages for xpdf are an excellent resource which I would strongly + recommend a visit to it: + + http://www.foolabs.com/xpdf/ + + -=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=- + Tony Nugent + Computer Systems Officer Faculty of Science + University of Southern Queensland, Toowoomba Oueensland Australia + -=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-=*#*=-