"Fossies" - the Fresh Open Source Software Archive

Member "xpdf-4.04/xpdf/SecurityHandler.cc" (18 Apr 2022, 10354 Bytes) of package /linux/misc/xpdf-4.04.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 //========================================================================
    2 //
    3 // SecurityHandler.cc
    4 //
    5 // Copyright 2004 Glyph & Cog, LLC
    6 //
    7 //========================================================================
    8 
    9 #include <aconf.h>
   10 
   11 #ifdef USE_GCC_PRAGMAS
   12 #pragma implementation
   13 #endif
   14 
   15 #include "gmempp.h"
   16 #include "GString.h"
   17 #include "PDFDoc.h"
   18 #include "Decrypt.h"
   19 #include "Error.h"
   20 #include "GlobalParams.h"
   21 #include "PDFCore.h"
   22 #include "SecurityHandler.h"
   23 
   24 //------------------------------------------------------------------------
   25 // SecurityHandler
   26 //------------------------------------------------------------------------
   27 
   28 SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) {
   29   Object filterObj;
   30   SecurityHandler *secHdlr;
   31 
   32   encryptDictA->dictLookup("Filter", &filterObj);
   33   if (filterObj.isName("Standard")) {
   34     secHdlr = new StandardSecurityHandler(docA, encryptDictA);
   35   } else if (filterObj.isName()) {
   36     error(errSyntaxError, -1, "Couldn't find the '{0:s}' security handler",
   37       filterObj.getName());
   38     secHdlr = NULL;
   39   } else {
   40     error(errSyntaxError, -1,
   41       "Missing or invalid 'Filter' entry in encryption dictionary");
   42     secHdlr = NULL;
   43   }
   44   filterObj.free();
   45   return secHdlr;
   46 }
   47 
   48 SecurityHandler::SecurityHandler(PDFDoc *docA) {
   49   doc = docA;
   50 }
   51 
   52 SecurityHandler::~SecurityHandler() {
   53 }
   54 
   55 GBool SecurityHandler::checkEncryption(GString *ownerPassword,
   56                        GString *userPassword) {
   57   void *authData;
   58   GBool ok;
   59   int i;
   60 
   61   if (ownerPassword || userPassword) {
   62     authData = makeAuthData(ownerPassword, userPassword);
   63   } else {
   64     authData = NULL;
   65   }
   66   ok = authorize(authData);
   67   if (authData) {
   68     freeAuthData(authData);
   69   }
   70   for (i = 0; !ok && i < 3; ++i) {
   71     if (!(authData = getAuthData())) {
   72       break;
   73     }
   74     ok = authorize(authData);
   75     if (authData) {
   76       freeAuthData(authData);
   77     }
   78   }
   79   if (!ok) {
   80     error(errCommandLine, -1, "Incorrect password");
   81   }
   82   return ok;
   83 }
   84 
   85 //------------------------------------------------------------------------
   86 // StandardSecurityHandler
   87 //------------------------------------------------------------------------
   88 
   89 class StandardAuthData {
   90 public:
   91 
   92   StandardAuthData(GString *ownerPasswordA, GString *userPasswordA) {
   93     ownerPassword = ownerPasswordA;
   94     userPassword = userPasswordA;
   95   }
   96 
   97   ~StandardAuthData() {
   98     if (ownerPassword) {
   99       delete ownerPassword;
  100     }
  101     if (userPassword) {
  102       delete userPassword;
  103     }
  104   }
  105 
  106   GString *ownerPassword;
  107   GString *userPassword;
  108 };
  109 
  110 StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
  111                          Object *encryptDictA):
  112   SecurityHandler(docA)
  113 {
  114   Object versionObj, revisionObj, lengthObj;
  115   Object ownerKeyObj, userKeyObj, ownerEncObj, userEncObj;
  116   Object permObj, fileIDObj, fileIDObj1;
  117   Object cryptFiltersObj, streamFilterObj, stringFilterObj;
  118   Object cryptFilterObj, cfmObj, cfLengthObj;
  119   Object encryptMetadataObj;
  120 
  121   ok = gFalse;
  122   fileID = NULL;
  123   ownerKey = NULL;
  124   userKey = NULL;
  125   ownerEnc = NULL;
  126   userEnc = NULL;
  127   fileKeyLength = 0;
  128 
  129   //--- get the main parameters
  130   encryptDictA->dictLookup("V", &versionObj);
  131   encryptDictA->dictLookup("R", &revisionObj);
  132   encryptDictA->dictLookup("Length", &lengthObj);
  133   encryptDictA->dictLookup("O", &ownerKeyObj);
  134   encryptDictA->dictLookup("U", &userKeyObj);
  135   encryptDictA->dictLookup("OE", &ownerEncObj);
  136   encryptDictA->dictLookup("UE", &userEncObj);
  137   encryptDictA->dictLookup("P", &permObj);
  138   doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj);
  139   if (!versionObj.isInt() ||
  140       !revisionObj.isInt() ||
  141       !permObj.isInt() ||
  142       !ownerKeyObj.isString() ||
  143       !userKeyObj.isString()) {
  144     error(errSyntaxError, -1, "Invalid encryption parameters");
  145     goto done;
  146   }
  147   encVersion = versionObj.getInt();
  148   encRevision = revisionObj.getInt();
  149   encAlgorithm = cryptRC4;
  150   // revision 2 forces a 40-bit key - some buggy PDF generators
  151   // set the Length value incorrectly
  152   if (encRevision == 2 || !lengthObj.isInt()) {
  153     fileKeyLength = 5;
  154   } else {
  155     fileKeyLength = lengthObj.getInt() / 8;
  156   }
  157   encryptMetadata = gTrue;
  158 
  159   //--- check for a crypt filter (which can modify the parameters)
  160   //~ this currently only handles a subset of crypt filter functionality
  161   //~ (in particular, it ignores the EFF entry in encryptDictA, and
  162   //~ doesn't handle the case where StmF, StrF, and EFF are not all the
  163   //~ same)
  164   if ((encVersion == 4 || encVersion == 5) &&
  165       (encRevision == 4 || encRevision == 5 || encRevision == 6)) {
  166     encryptDictA->dictLookup("CF", &cryptFiltersObj);
  167     encryptDictA->dictLookup("StmF", &streamFilterObj);
  168     encryptDictA->dictLookup("StrF", &stringFilterObj);
  169     if (cryptFiltersObj.isDict() &&
  170     streamFilterObj.isName() &&
  171     stringFilterObj.isName() &&
  172     !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) {
  173       if (!strcmp(streamFilterObj.getName(), "Identity")) {
  174     // no encryption on streams or strings
  175     stringFilterObj.free();
  176     streamFilterObj.free();
  177     cryptFiltersObj.free();
  178     goto done;
  179       }
  180       if (cryptFiltersObj.dictLookup(streamFilterObj.getName(),
  181                      &cryptFilterObj)->isDict()) {
  182     cryptFilterObj.dictLookup("CFM", &cfmObj);
  183     if (cfmObj.isName("V2")) {
  184       if (cryptFilterObj.dictLookup("Length",
  185                     &cfLengthObj)->isInt()) {
  186         fileKeyLength = cfLengthObj.getInt();
  187       }
  188       cfLengthObj.free();
  189       encVersion = 2;
  190       encRevision = 3;
  191     } else if (cfmObj.isName("AESV2")) {
  192       if (cryptFilterObj.dictLookup("Length",
  193                     &cfLengthObj)->isInt()) {
  194         fileKeyLength = cfLengthObj.getInt();
  195       }
  196       cfLengthObj.free();
  197       encVersion = 2;
  198       encRevision = 3;
  199       encAlgorithm = cryptAES;
  200     } else if (cfmObj.isName("AESV3")) {
  201       if (cryptFilterObj.dictLookup("Length",
  202                     &cfLengthObj)->isInt()) {
  203         fileKeyLength = cfLengthObj.getInt();
  204       }
  205       cfLengthObj.free();
  206       encVersion = 5;
  207       if (encRevision != 5 && encRevision != 6) {
  208         encRevision = 6;
  209       }
  210       encAlgorithm = cryptAES256;
  211       // The PDF 2.0 spec says Length and CF.Length are both deprecated.
  212       // Acrobat X honors Length and ignores CF.Length.
  213       // I think it's safest to ignore both.
  214       fileKeyLength = 32;
  215     }
  216     cfmObj.free();
  217       }
  218       cryptFilterObj.free();
  219     }
  220     stringFilterObj.free();
  221     streamFilterObj.free();
  222     cryptFiltersObj.free();
  223     if (encryptDictA->dictLookup("EncryptMetadata",
  224                  &encryptMetadataObj)->isBool()) {
  225       encryptMetadata = encryptMetadataObj.getBool();
  226     }
  227     encryptMetadataObj.free();
  228   }
  229 
  230   //--- version-specific parameters
  231   if (encRevision <= 4) {
  232     if (ownerKeyObj.getString()->getLength() != 32 ||
  233     userKeyObj.getString()->getLength() != 32) {
  234       error(errSyntaxError, -1, "Invalid encryption key length");
  235       // this is non-fatal -- see below
  236     }
  237   } else if (encRevision <= 6) {
  238     // the spec says 48 bytes, but Acrobat pads them out longer
  239     if (ownerKeyObj.getString()->getLength() < 48 ||
  240     userKeyObj.getString()->getLength() < 48 ||
  241     !ownerEncObj.isString() ||
  242     ownerEncObj.getString()->getLength() != 32 ||
  243     !userEncObj.isString() ||
  244     userEncObj.getString()->getLength() != 32) {
  245       error(errSyntaxError, -1, "Invalid encryption key length");
  246       goto done;
  247     }
  248   }
  249   permFlags = permObj.getInt();
  250   ownerKey = ownerKeyObj.getString()->copy();
  251   userKey = userKeyObj.getString()->copy();
  252   if (encRevision <= 4) {
  253     // Adobe apparently zero-pads the U value (and maybe the O value?)
  254     // if it's short
  255     while (ownerKey->getLength() < 32) {
  256       ownerKey->append((char)0x00);
  257     }
  258     while (userKey->getLength() < 32) {
  259       userKey->append((char)0x00);
  260     }
  261   }
  262   if (encVersion >= 1 && encVersion <= 2 &&
  263       encRevision >= 2 && encRevision <= 3) {
  264     if (fileIDObj.isArray()) {
  265       if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) {
  266     fileID = fileIDObj1.getString()->copy();
  267       } else {
  268     fileID = new GString();
  269       }
  270       fileIDObj1.free();
  271     } else {
  272       fileID = new GString();
  273     }
  274     if (fileKeyLength > 16 || fileKeyLength <= 0) {
  275       fileKeyLength = 16;
  276     }
  277     ok = gTrue;
  278   } else if (encVersion == 5 && (encRevision == 5 || encRevision == 6)) {
  279     fileID = new GString(); // unused for V=R=5
  280     ownerEnc = ownerEncObj.getString()->copy();
  281     userEnc = userEncObj.getString()->copy();
  282     if (fileKeyLength > 32 || fileKeyLength <= 0) {
  283       fileKeyLength = 32;
  284     }
  285     ok = gTrue;
  286   } else {
  287     error(errUnimplemented, -1,
  288       "Unsupported version/revision ({0:d}/{1:d}) of Standard security handler",
  289       encVersion, encRevision);
  290   }
  291 
  292  done:
  293   fileIDObj.free();
  294   permObj.free();
  295   userEncObj.free();
  296   ownerEncObj.free();
  297   userKeyObj.free();
  298   ownerKeyObj.free();
  299   lengthObj.free();
  300   revisionObj.free();
  301   versionObj.free();
  302 }
  303 
  304 StandardSecurityHandler::~StandardSecurityHandler() {
  305   if (fileID) {
  306     delete fileID;
  307   }
  308   if (ownerKey) {
  309     delete ownerKey;
  310   }
  311   if (userKey) {
  312     delete userKey;
  313   }
  314   if (ownerEnc) {
  315     delete ownerEnc;
  316   }
  317   if (userEnc) {
  318     delete userEnc;
  319   }
  320 }
  321 
  322 GBool StandardSecurityHandler::isUnencrypted() {
  323   return encVersion == -1 && encRevision == -1;
  324 }
  325 
  326 void *StandardSecurityHandler::makeAuthData(GString *ownerPassword,
  327                         GString *userPassword) {
  328   return new StandardAuthData(ownerPassword ? ownerPassword->copy()
  329                                 : (GString *)NULL,
  330                   userPassword ? userPassword->copy()
  331                                : (GString *)NULL);
  332 }
  333 
  334 void *StandardSecurityHandler::getAuthData() {
  335   PDFCore *core;
  336   GString *password;
  337 
  338   if (!(core = doc->getCore()) ||
  339       !(password = core->getPassword())) {
  340     return NULL;
  341   }
  342   return new StandardAuthData(password, password->copy());
  343 }
  344 
  345 void StandardSecurityHandler::freeAuthData(void *authData) {
  346   delete (StandardAuthData *)authData;
  347 }
  348 
  349 GBool StandardSecurityHandler::authorize(void *authData) {
  350   GString *ownerPassword, *userPassword;
  351 
  352   if (!ok) {
  353     return gFalse;
  354   }
  355   if (authData) {
  356     ownerPassword = ((StandardAuthData *)authData)->ownerPassword;
  357     userPassword = ((StandardAuthData *)authData)->userPassword;
  358   } else {
  359     ownerPassword = NULL;
  360     userPassword = NULL;
  361   }
  362   if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength,
  363                 ownerKey, userKey, ownerEnc, userEnc,
  364                 permFlags, fileID,
  365                 ownerPassword, userPassword, fileKey,
  366                 encryptMetadata, &ownerPasswordOk)) {
  367     return gFalse;
  368   }
  369   return gTrue;
  370 }