"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. For more information about "SecurityHandler.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.03_vs_4.04.

    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 }