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