1 //========================================================================
5 // Copyright 2004 Glyph & Cog, LLC
7 //========================================================================
9 //========================================================================
11 // Modified under the Poppler project - http://poppler.freedesktop.org
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
16 // Copyright (C) 2010, 2012, 2015 Albert Astals Cid <aacid@kde.org>
17 // Copyright (C) 2013 Adrian Johnson <ajohnson@redneon.com>
18 // Copyright (C) 2014 Fabio D'Urso <fabiodurso@hotmail.it>
20 // To see a description of the changes please see the Changelog file that
21 // came with your tarball or type make ChangeLog if you are building from git
23 //========================================================================
27 #ifdef USE_GCC_PRAGMAS
28 #pragma implementation
31 #include "GooString.h"
35 #include "GlobalParams.h"
37 # include "XpdfPluginAPI.h"
39 #include "SecurityHandler.h"
43 //------------------------------------------------------------------------
45 //------------------------------------------------------------------------
47 SecurityHandler
*SecurityHandler::make(PDFDoc
*docA
, Object
*encryptDictA
) {
49 SecurityHandler
*secHdlr
;
51 XpdfSecurityHandler
*xsh
;
54 encryptDictA
->dictLookup("Filter", &filterObj
);
55 if (filterObj
.isName("Standard")) {
56 secHdlr
= new StandardSecurityHandler(docA
, encryptDictA
);
57 } else if (filterObj
.isName()) {
59 if ((xsh
= globalParams
->getSecurityHandler(filterObj
.getName()))) {
60 secHdlr
= new ExternalSecurityHandler(docA
, encryptDictA
, xsh
);
63 error(errSyntaxError
, -1, "Couldn't find the '{0:s}' security handler",
70 error(errSyntaxError
, -1,
71 "Missing or invalid 'Filter' entry in encryption dictionary");
78 SecurityHandler::SecurityHandler(PDFDoc
*docA
) {
82 SecurityHandler::~SecurityHandler() {
85 GBool
SecurityHandler::checkEncryption(GooString
*ownerPassword
,
86 GooString
*userPassword
) {
91 if (ownerPassword
|| userPassword
) {
92 authData
= makeAuthData(ownerPassword
, userPassword
);
96 ok
= authorize(authData
);
98 freeAuthData(authData
);
100 for (i
= 0; !ok
&& i
< 3; ++i
) {
101 if (!(authData
= getAuthData())) {
104 ok
= authorize(authData
);
106 freeAuthData(authData
);
110 if (!ownerPassword
&& !userPassword
) {
112 return checkEncryption(&dummy
, &dummy
);
114 error(errCommandLine
, -1, "Incorrect password");
120 //------------------------------------------------------------------------
121 // StandardSecurityHandler
122 //------------------------------------------------------------------------
124 class StandardAuthData
{
127 StandardAuthData(GooString
*ownerPasswordA
, GooString
*userPasswordA
) {
128 ownerPassword
= ownerPasswordA
;
129 userPassword
= userPasswordA
;
132 ~StandardAuthData() {
134 delete ownerPassword
;
141 GooString
*ownerPassword
;
142 GooString
*userPassword
;
145 StandardSecurityHandler::StandardSecurityHandler(PDFDoc
*docA
,
146 Object
*encryptDictA
):
147 SecurityHandler(docA
)
149 Object versionObj
, revisionObj
, lengthObj
;
150 Object ownerKeyObj
, userKeyObj
, ownerEncObj
, userEncObj
;
151 Object permObj
, fileIDObj
, fileIDObj1
;
152 Object cryptFiltersObj
, streamFilterObj
, stringFilterObj
;
153 Object cryptFilterObj
, cfmObj
, cfLengthObj
;
154 Object encryptMetadataObj
;
164 encryptDictA
->dictLookup("V", &versionObj
);
165 encryptDictA
->dictLookup("R", &revisionObj
);
166 encryptDictA
->dictLookup("Length", &lengthObj
);
167 encryptDictA
->dictLookup("O", &ownerKeyObj
);
168 encryptDictA
->dictLookup("U", &userKeyObj
);
169 encryptDictA
->dictLookup("OE", &ownerEncObj
);
170 encryptDictA
->dictLookup("UE", &userEncObj
);
171 encryptDictA
->dictLookup("P", &permObj
);
172 if (permObj
.isInt64()) {
173 unsigned int permUint
= permObj
.getInt64();
174 int perms
= permUint
- UINT_MAX
- 1;
176 permObj
.initInt(perms
);
178 doc
->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj
);
179 if (versionObj
.isInt() &&
180 revisionObj
.isInt() &&
182 ownerKeyObj
.isString() &&
183 userKeyObj
.isString()) {
184 encVersion
= versionObj
.getInt();
185 encRevision
= revisionObj
.getInt();
186 if ((encRevision
<= 4 &&
187 ownerKeyObj
.getString()->getLength() == 32 &&
188 userKeyObj
.getString()->getLength() == 32) ||
190 // the spec says 48 bytes, but Acrobat pads them out longer
191 ownerKeyObj
.getString()->getLength() >= 48 &&
192 userKeyObj
.getString()->getLength() >= 48 &&
193 ownerEncObj
.isString() &&
194 ownerEncObj
.getString()->getLength() == 32 &&
195 userEncObj
.isString() &&
196 userEncObj
.getString()->getLength() == 32)) {
197 encAlgorithm
= cryptRC4
;
198 // revision 2 forces a 40-bit key - some buggy PDF generators
199 // set the Length value incorrectly
200 if (encRevision
== 2 || !lengthObj
.isInt()) {
203 fileKeyLength
= lengthObj
.getInt() / 8;
205 encryptMetadata
= gTrue
;
206 //~ this currently only handles a subset of crypt filter functionality
207 //~ (in particular, it ignores the EFF entry in encryptDictA, and
208 //~ doesn't handle the case where StmF, StrF, and EFF are not all the
210 if ((encVersion
== 4 || encVersion
== 5) &&
211 (encRevision
== 4 || encRevision
== 5)) {
212 encryptDictA
->dictLookup("CF", &cryptFiltersObj
);
213 encryptDictA
->dictLookup("StmF", &streamFilterObj
);
214 encryptDictA
->dictLookup("StrF", &stringFilterObj
);
215 if (cryptFiltersObj
.isDict() &&
216 streamFilterObj
.isName() &&
217 stringFilterObj
.isName() &&
218 !strcmp(streamFilterObj
.getName(), stringFilterObj
.getName())) {
219 if (!strcmp(streamFilterObj
.getName(), "Identity")) {
220 // no encryption on streams or strings
221 encVersion
= encRevision
= -1;
223 if (cryptFiltersObj
.dictLookup(streamFilterObj
.getName(),
224 &cryptFilterObj
)->isDict()) {
225 cryptFilterObj
.dictLookup("CFM", &cfmObj
);
226 if (cfmObj
.isName("V2")) {
229 if (cryptFilterObj
.dictLookup("Length",
230 &cfLengthObj
)->isInt()) {
231 //~ according to the spec, this should be cfLengthObj / 8
232 fileKeyLength
= cfLengthObj
.getInt();
235 } else if (cfmObj
.isName("AESV2")) {
238 encAlgorithm
= cryptAES
;
239 if (cryptFilterObj
.dictLookup("Length",
240 &cfLengthObj
)->isInt()) {
241 //~ according to the spec, this should be cfLengthObj / 8
242 fileKeyLength
= cfLengthObj
.getInt();
245 } else if (cfmObj
.isName("AESV3")) {
248 encAlgorithm
= cryptAES256
;
249 if (cryptFilterObj
.dictLookup("Length",
250 &cfLengthObj
)->isInt()) {
251 //~ according to the spec, this should be cfLengthObj / 8
252 fileKeyLength
= cfLengthObj
.getInt();
258 cryptFilterObj
.free();
261 stringFilterObj
.free();
262 streamFilterObj
.free();
263 cryptFiltersObj
.free();
264 if (encryptDictA
->dictLookup("EncryptMetadata",
265 &encryptMetadataObj
)->isBool()) {
266 encryptMetadata
= encryptMetadataObj
.getBool();
268 encryptMetadataObj
.free();
270 permFlags
= permObj
.getInt();
271 ownerKey
= ownerKeyObj
.getString()->copy();
272 userKey
= userKeyObj
.getString()->copy();
273 if (encVersion
>= 1 && encVersion
<= 2 &&
274 encRevision
>= 2 && encRevision
<= 3) {
275 if (fileIDObj
.isArray()) {
276 if (fileIDObj
.arrayGet(0, &fileIDObj1
)->isString()) {
277 fileID
= fileIDObj1
.getString()->copy();
279 fileID
= new GooString();
283 fileID
= new GooString();
285 if (fileKeyLength
> 16 || fileKeyLength
< 0) {
289 } else if (encVersion
== 5 && encRevision
== 5) {
290 fileID
= new GooString(); // unused for V=R=5
291 if (ownerEncObj
.isString() && userEncObj
.isString()) {
292 ownerEnc
= ownerEncObj
.getString()->copy();
293 userEnc
= userEncObj
.getString()->copy();
294 if (fileKeyLength
> 32 || fileKeyLength
< 0) {
299 error(errSyntaxError
, -1, "Weird encryption owner/user info");
301 } else if (!(encVersion
== -1 && encRevision
== -1)) {
302 error(errUnimplemented
, -1,
303 "Unsupported version/revision ({0:d}/{1:d}) of Standard security handler",
304 encVersion
, encRevision
);
307 error(errSyntaxError
, -1, "Invalid encryption key length");
310 error(errSyntaxError
, -1, "Weird encryption info");
323 StandardSecurityHandler::~StandardSecurityHandler() {
341 GBool
StandardSecurityHandler::isUnencrypted() {
342 return encVersion
== -1 && encRevision
== -1;
345 void *StandardSecurityHandler::makeAuthData(GooString
*ownerPassword
,
346 GooString
*userPassword
) {
347 return new StandardAuthData(ownerPassword
? ownerPassword
->copy()
349 userPassword
? userPassword
->copy()
350 : (GooString
*)NULL
);
353 void *StandardSecurityHandler::getAuthData() {
357 void StandardSecurityHandler::freeAuthData(void *authData
) {
358 delete (StandardAuthData
*)authData
;
361 GBool
StandardSecurityHandler::authorize(void *authData
) {
362 GooString
*ownerPassword
, *userPassword
;
368 ownerPassword
= ((StandardAuthData
*)authData
)->ownerPassword
;
369 userPassword
= ((StandardAuthData
*)authData
)->userPassword
;
371 ownerPassword
= NULL
;
374 if (!Decrypt::makeFileKey(encVersion
, encRevision
, fileKeyLength
,
375 ownerKey
, userKey
, ownerEnc
, userEnc
,
377 ownerPassword
, userPassword
, fileKey
,
378 encryptMetadata
, &ownerPasswordOk
)) {
384 #ifdef ENABLE_PLUGINS
386 //------------------------------------------------------------------------
387 // ExternalSecurityHandler
388 //------------------------------------------------------------------------
390 ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc
*docA
,
391 Object
*encryptDictA
,
392 XpdfSecurityHandler
*xshA
):
393 SecurityHandler(docA
)
395 encryptDictA
->copy(&encryptDict
);
397 encAlgorithm
= cryptRC4
; //~ this should be obtained via getKey
400 if (!(*xsh
->newDoc
)(xsh
->handlerData
, (XpdfDoc
)docA
,
401 (XpdfObject
)encryptDictA
, &docData
)) {
408 ExternalSecurityHandler::~ExternalSecurityHandler() {
409 (*xsh
->freeDoc
)(xsh
->handlerData
, docData
);
413 void *ExternalSecurityHandler::makeAuthData(GooString
*ownerPassword
,
414 GooString
*userPassword
) {
418 opw
= ownerPassword
? ownerPassword
->getCString() : (char *)NULL
;
419 upw
= userPassword
? userPassword
->getCString() : (char *)NULL
;
420 if (!(*xsh
->makeAuthData
)(xsh
->handlerData
, docData
, opw
, upw
, &authData
)) {
426 void *ExternalSecurityHandler::getAuthData() {
429 if (!(*xsh
->getAuthData
)(xsh
->handlerData
, docData
, &authData
)) {
435 void ExternalSecurityHandler::freeAuthData(void *authData
) {
436 (*xsh
->freeAuthData
)(xsh
->handlerData
, docData
, authData
);
439 GBool
ExternalSecurityHandler::authorize(void *authData
) {
446 permFlags
= (*xsh
->authorize
)(xsh
->handlerData
, docData
, authData
);
447 if (!(permFlags
& xpdfPermissionOpen
)) {
450 if (!(*xsh
->getKey
)(xsh
->handlerData
, docData
, &key
, &length
, &encVersion
, &encRevision
)) {
453 if ((fileKeyLength
= length
) > 16) {
456 memcpy(fileKey
, key
, fileKeyLength
);
457 (*xsh
->freeKey
)(xsh
->handlerData
, docData
, key
, length
);
461 #endif // ENABLE_PLUGINS