"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 }