1 //========================================================================
5 // Copyright 2004 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
19 #include "GlobalParams.h"
21 # include "XPDFCore.h"
23 # include "WinPDFCore.h"
26 # include "XpdfPluginAPI.h"
28 #include "SecurityHandler.h"
30 //------------------------------------------------------------------------
32 //------------------------------------------------------------------------
34 SecurityHandler
*SecurityHandler::make(PDFDoc
*docA
, Object
*encryptDictA
) {
36 SecurityHandler
*secHdlr
;
38 XpdfSecurityHandler
*xsh
;
41 encryptDictA
->dictLookup("Filter", &filterObj
);
42 if (filterObj
.isName("Standard")) {
43 secHdlr
= new StandardSecurityHandler(docA
, encryptDictA
);
44 } else if (filterObj
.isName()) {
46 if ((xsh
= globalParams
->getSecurityHandler(filterObj
.getName()))) {
47 secHdlr
= new ExternalSecurityHandler(docA
, encryptDictA
, xsh
);
50 error(-1, "Couldn't find the '%s' security handler",
57 error(-1, "Missing or invalid 'Filter' entry in encryption dictionary");
64 SecurityHandler::SecurityHandler(PDFDoc
*docA
) {
68 SecurityHandler::~SecurityHandler() {
71 GBool
SecurityHandler::checkEncryption(GString
*ownerPassword
,
72 GString
*userPassword
) {
77 if (ownerPassword
|| userPassword
) {
78 authData
= makeAuthData(ownerPassword
, userPassword
);
82 ok
= authorize(authData
);
84 freeAuthData(authData
);
86 for (i
= 0; !ok
&& i
< 3; ++i
) {
87 if (!(authData
= getAuthData())) {
90 ok
= authorize(authData
);
92 freeAuthData(authData
);
96 error(-1, "Incorrect password");
101 //------------------------------------------------------------------------
102 // StandardSecurityHandler
103 //------------------------------------------------------------------------
105 class StandardAuthData
{
108 StandardAuthData(GString
*ownerPasswordA
, GString
*userPasswordA
) {
109 ownerPassword
= ownerPasswordA
;
110 userPassword
= userPasswordA
;
113 ~StandardAuthData() {
115 delete ownerPassword
;
122 GString
*ownerPassword
;
123 GString
*userPassword
;
126 StandardSecurityHandler::StandardSecurityHandler(PDFDoc
*docA
,
127 Object
*encryptDictA
):
128 SecurityHandler(docA
)
130 Object versionObj
, revisionObj
, lengthObj
;
131 Object ownerKeyObj
, userKeyObj
, permObj
, fileIDObj
;
133 Object cryptFiltersObj
, streamFilterObj
, stringFilterObj
;
134 Object cryptFilterObj
, cfmObj
, cfLengthObj
;
135 Object encryptMetadataObj
;
142 encryptDictA
->dictLookup("V", &versionObj
);
143 encryptDictA
->dictLookup("R", &revisionObj
);
144 encryptDictA
->dictLookup("Length", &lengthObj
);
145 encryptDictA
->dictLookup("O", &ownerKeyObj
);
146 encryptDictA
->dictLookup("U", &userKeyObj
);
147 encryptDictA
->dictLookup("P", &permObj
);
148 doc
->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj
);
149 if (versionObj
.isInt() &&
150 revisionObj
.isInt() &&
151 ownerKeyObj
.isString() && ownerKeyObj
.getString()->getLength() == 32 &&
152 userKeyObj
.isString() && userKeyObj
.getString()->getLength() == 32 &&
154 encVersion
= versionObj
.getInt();
155 encRevision
= revisionObj
.getInt();
156 // revision 2 forces a 40-bit key - some buggy PDF generators
157 // set the Length value incorrectly
158 if (encRevision
== 2 || !lengthObj
.isInt()) {
161 fileKeyLength
= lengthObj
.getInt() / 8;
163 encryptMetadata
= gTrue
;
164 //~ this currently only handles a subset of crypt filter functionality
165 if (encVersion
== 4 && encRevision
== 4) {
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 (cryptFiltersObj
.dictLookup(streamFilterObj
.getName(),
174 &cryptFilterObj
)->isDict()) {
175 if (cryptFilterObj
.dictLookup("CFM", &cfmObj
)->isName("V2")) {
178 if (cryptFilterObj
.dictLookup("Length", &cfLengthObj
)->isInt()) {
179 //~ according to the spec, this should be cfLengthObj / 8
180 fileKeyLength
= cfLengthObj
.getInt();
186 cryptFilterObj
.free();
188 stringFilterObj
.free();
189 streamFilterObj
.free();
190 cryptFiltersObj
.free();
191 if (encryptDictA
->dictLookup("EncryptMetadata",
192 &encryptMetadataObj
)->isBool()) {
193 encryptMetadata
= encryptMetadataObj
.getBool();
195 encryptMetadataObj
.free();
197 permFlags
= permObj
.getInt();
198 ownerKey
= ownerKeyObj
.getString()->copy();
199 userKey
= userKeyObj
.getString()->copy();
200 if (encVersion
>= 1 && encVersion
<= 2 &&
201 encRevision
>= 2 && encRevision
<= 3) {
202 if (fileIDObj
.isArray()) {
203 if (fileIDObj
.arrayGet(0, &fileIDObj1
)->isString()) {
204 fileID
= fileIDObj1
.getString()->copy();
206 fileID
= new GString();
210 fileID
= new GString();
214 error(-1, "Unsupported version/revision (%d/%d) of Standard security handler",
215 encVersion
, encRevision
);
218 error(-1, "Weird encryption info");
220 if (fileKeyLength
> 16) {
232 StandardSecurityHandler::~StandardSecurityHandler() {
244 void *StandardSecurityHandler::makeAuthData(GString
*ownerPassword
,
245 GString
*userPassword
) {
246 return new StandardAuthData(ownerPassword
? ownerPassword
->copy()
248 userPassword
? userPassword
->copy()
252 void *StandardSecurityHandler::getAuthData() {
257 if (!(core
= (XPDFCore
*)doc
->getGUIData()) ||
258 !(password
= core
->getPassword())) {
261 return new StandardAuthData(password
, password
->copy());
262 #elif HAVE_WINPDFCORE
266 if (!(core
= (WinPDFCore
*)doc
->getGUIData()) ||
267 !(password
= core
->getPassword())) {
270 return new StandardAuthData(password
, password
->copy());
276 void StandardSecurityHandler::freeAuthData(void *authData
) {
277 delete (StandardAuthData
*)authData
;
280 GBool
StandardSecurityHandler::authorize(void *authData
) {
281 GString
*ownerPassword
, *userPassword
;
287 ownerPassword
= ((StandardAuthData
*)authData
)->ownerPassword
;
288 userPassword
= ((StandardAuthData
*)authData
)->userPassword
;
290 ownerPassword
= NULL
;
293 if (!Decrypt::makeFileKey(encVersion
, encRevision
, fileKeyLength
,
294 ownerKey
, userKey
, permFlags
, fileID
,
295 ownerPassword
, userPassword
, fileKey
,
296 encryptMetadata
, &ownerPasswordOk
)) {
302 #ifdef ENABLE_PLUGINS
304 //------------------------------------------------------------------------
305 // ExternalSecurityHandler
306 //------------------------------------------------------------------------
308 ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc
*docA
,
309 Object
*encryptDictA
,
310 XpdfSecurityHandler
*xshA
):
311 SecurityHandler(docA
)
313 encryptDictA
->copy(&encryptDict
);
317 if (!(*xsh
->newDoc
)(xsh
->handlerData
, (XpdfDoc
)docA
,
318 (XpdfObject
)encryptDictA
, &docData
)) {
325 ExternalSecurityHandler::~ExternalSecurityHandler() {
326 (*xsh
->freeDoc
)(xsh
->handlerData
, docData
);
330 void *ExternalSecurityHandler::makeAuthData(GString
*ownerPassword
,
331 GString
*userPassword
) {
335 opw
= ownerPassword
? ownerPassword
->getCString() : (char *)NULL
;
336 upw
= userPassword
? userPassword
->getCString() : (char *)NULL
;
337 if (!(*xsh
->makeAuthData
)(xsh
->handlerData
, docData
, opw
, upw
, &authData
)) {
343 void *ExternalSecurityHandler::getAuthData() {
346 if (!(*xsh
->getAuthData
)(xsh
->handlerData
, docData
, &authData
)) {
352 void ExternalSecurityHandler::freeAuthData(void *authData
) {
353 (*xsh
->freeAuthData
)(xsh
->handlerData
, docData
, authData
);
356 GBool
ExternalSecurityHandler::authorize(void *authData
) {
363 permFlags
= (*xsh
->authorize
)(xsh
->handlerData
, docData
, authData
);
364 if (!(permFlags
& xpdfPermissionOpen
)) {
367 if (!(*xsh
->getKey
)(xsh
->handlerData
, docData
, &key
, &length
, &encVersion
)) {
370 if ((fileKeyLength
= length
) > 16) {
373 memcpy(fileKey
, key
, fileKeyLength
);
374 (*xsh
->freeKey
)(xsh
->handlerData
, docData
, key
, length
);
378 #endif // ENABLE_PLUGINS