1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: pdfencrypt.cpp
3 // Purpose:
4 // Author: Ulrich Telle
5 // Created: 2005-08-17
6 // Copyright: (c) Ulrich Telle
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 /// \file pdfencrypt.cpp Implementation of the wxPdfEncrypt class
11
12 // For compilers that support precompilation, includes <wx.h>.
13 #include <wx/wxprec.h>
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include <wx/wx.h>
21 #endif
22
23 // includes
24 #include <wx/log.h>
25
26 #include "wx/pdfencrypt.h"
27 #include "wx/pdfrijndael.h"
28 #include "wx/pdfutility.h"
29
30 #define MD5_HASHBYTES 16
31
32 /*
33 * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
34 * MD5 Message-Digest Algorithm (RFC 1321).
35 *
36 * Homepage:
37 * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
38 *
39 * Author:
40 * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
41 *
42 * This software was written by Alexander Peslyak in 2001. No copyright is
43 * claimed, and the software is hereby placed in the public domain.
44 * In case this attempt to disclaim copyright and place the software in the
45 * public domain is deemed null and void, then the software is
46 * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
47 * general public under the following terms:
48 *
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted.
51 *
52 * There's ABSOLUTELY NO WARRANTY, express or implied.
53 *
54 * (This is a heavily cut-down "BSD license".)
55 *
56 * This differs from Colin Plumb's older public domain implementation in that
57 * no exactly 32-bit integer data type is required (any 32-bit or wider
58 * unsigned integer data type will do), there's no compile-time endianness
59 * configuration, and the function prototypes match OpenSSL's. No code from
60 * Colin Plumb's implementation has been reused; this comment merely compares
61 * the properties of the two independent implementations.
62 *
63 * The primary goals of this implementation are portability and ease of use.
64 * It is meant to be fast, but not as fast as possible. Some known
65 * optimizations are not included to reduce source code size and avoid
66 * compile-time configuration.
67 */
68
69 #include <string.h>
70
71 /* Any 32-bit or wider unsigned integer data type will do */
72 typedef unsigned int MD5_u32plus;
73
74 typedef struct {
75 MD5_u32plus lo, hi;
76 MD5_u32plus a, b, c, d;
77 unsigned char buffer[64];
78 MD5_u32plus block[16];
79 } MD5_CTX;
80
81 static void MD5_Init(MD5_CTX *ctx);
82 static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
83 static void MD5_Final(unsigned char *result, MD5_CTX *ctx);
84
85 /*
86 * The basic MD5 functions.
87 *
88 * F and G are optimized compared to their RFC 1321 definitions for
89 * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
90 * implementation.
91 */
92 #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
93 #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
94 #define H(x, y, z) (((x) ^ (y)) ^ (z))
95 #define H2(x, y, z) ((x) ^ ((y) ^ (z)))
96 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
97
98 /*
99 * The MD5 transformation for all four rounds.
100 */
101 #define STEP(f, a, b, c, d, x, t, s) \
102 (a) += f((b), (c), (d)) + (x) + (t); \
103 (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
104 (a) += (b);
105
106 /*
107 * SET reads 4 input bytes in little-endian byte order and stores them
108 * in a properly aligned word in host byte order.
109 *
110 * The check for little-endian architectures that tolerate unaligned
111 * memory accesses is just an optimization. Nothing will break if it
112 * doesn't work.
113 */
114 #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
115 #define SET(n) \
116 (*(MD5_u32plus *)&ptr[(n) * 4])
117 #define GET(n) \
118 SET(n)
119 #else
120 #define SET(n) \
121 (ctx->block[(n)] = \
122 (MD5_u32plus)ptr[(n) * 4] | \
123 ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
124 ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
125 ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
126 #define GET(n) \
127 (ctx->block[(n)])
128 #endif
129
130 /*
131 * This processes one or more 64-byte data blocks, but does NOT update
132 * the bit counters. There are no alignment requirements.
133 */
body(MD5_CTX * ctx,const void * data,unsigned long size)134 static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
135 {
136 const unsigned char *ptr;
137 MD5_u32plus a, b, c, d;
138 MD5_u32plus saved_a, saved_b, saved_c, saved_d;
139
140 ptr = (const unsigned char *)data;
141
142 a = ctx->a;
143 b = ctx->b;
144 c = ctx->c;
145 d = ctx->d;
146
147 do {
148 saved_a = a;
149 saved_b = b;
150 saved_c = c;
151 saved_d = d;
152
153 /* Round 1 */
154 STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
155 STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
156 STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
157 STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
158 STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
159 STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
160 STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
161 STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
162 STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
163 STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
164 STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
165 STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
166 STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
167 STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
168 STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
169 STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
170
171 /* Round 2 */
172 STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
173 STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
174 STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
175 STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
176 STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
177 STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
178 STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
179 STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
180 STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
181 STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
182 STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
183 STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
184 STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
185 STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
186 STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
187 STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
188
189 /* Round 3 */
190 STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
191 STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
192 STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
193 STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
194 STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
195 STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
196 STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
197 STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
198 STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
199 STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
200 STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
201 STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
202 STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
203 STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
204 STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
205 STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
206
207 /* Round 4 */
208 STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
209 STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
210 STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
211 STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
212 STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
213 STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
214 STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
215 STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
216 STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
217 STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
218 STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
219 STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
220 STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
221 STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
222 STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
223 STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
224
225 a += saved_a;
226 b += saved_b;
227 c += saved_c;
228 d += saved_d;
229
230 ptr += 64;
231 } while (size -= 64);
232
233 ctx->a = a;
234 ctx->b = b;
235 ctx->c = c;
236 ctx->d = d;
237
238 return ptr;
239 }
240
MD5_Init(MD5_CTX * ctx)241 void MD5_Init(MD5_CTX *ctx)
242 {
243 ctx->a = 0x67452301;
244 ctx->b = 0xefcdab89;
245 ctx->c = 0x98badcfe;
246 ctx->d = 0x10325476;
247
248 ctx->lo = 0;
249 ctx->hi = 0;
250 }
251
MD5_Update(MD5_CTX * ctx,const void * data,unsigned long size)252 void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
253 {
254 MD5_u32plus saved_lo;
255 unsigned long used, available;
256
257 saved_lo = ctx->lo;
258 if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
259 ctx->hi++;
260 ctx->hi += size >> 29;
261
262 used = saved_lo & 0x3f;
263
264 if (used) {
265 available = 64 - used;
266
267 if (size < available) {
268 memcpy(&ctx->buffer[used], data, size);
269 return;
270 }
271
272 memcpy(&ctx->buffer[used], data, available);
273 data = (const unsigned char *)data + available;
274 size -= available;
275 body(ctx, ctx->buffer, 64);
276 }
277
278 if (size >= 64) {
279 data = body(ctx, data, size & ~(unsigned long)0x3f);
280 size &= 0x3f;
281 }
282
283 memcpy(ctx->buffer, data, size);
284 }
285
MD5_Final(unsigned char * result,MD5_CTX * ctx)286 void MD5_Final(unsigned char *result, MD5_CTX *ctx)
287 {
288 unsigned long used, available;
289
290 used = ctx->lo & 0x3f;
291
292 ctx->buffer[used++] = 0x80;
293
294 available = 64 - used;
295
296 if (available < 8) {
297 memset(&ctx->buffer[used], 0, available);
298 body(ctx, ctx->buffer, 64);
299 used = 0;
300 available = 64;
301 }
302
303 memset(&ctx->buffer[used], 0, available - 8);
304
305 ctx->lo <<= 3;
306 ctx->buffer[56] = ctx->lo;
307 ctx->buffer[57] = ctx->lo >> 8;
308 ctx->buffer[58] = ctx->lo >> 16;
309 ctx->buffer[59] = ctx->lo >> 24;
310 ctx->buffer[60] = ctx->hi;
311 ctx->buffer[61] = ctx->hi >> 8;
312 ctx->buffer[62] = ctx->hi >> 16;
313 ctx->buffer[63] = ctx->hi >> 24;
314
315 body(ctx, ctx->buffer, 64);
316
317 result[0] = ctx->a;
318 result[1] = ctx->a >> 8;
319 result[2] = ctx->a >> 16;
320 result[3] = ctx->a >> 24;
321 result[4] = ctx->b;
322 result[5] = ctx->b >> 8;
323 result[6] = ctx->b >> 16;
324 result[7] = ctx->b >> 24;
325 result[8] = ctx->c;
326 result[9] = ctx->c >> 8;
327 result[10] = ctx->c >> 16;
328 result[11] = ctx->c >> 24;
329 result[12] = ctx->d;
330 result[13] = ctx->d >> 8;
331 result[14] = ctx->d >> 16;
332 result[15] = ctx->d >> 24;
333
334 memset(ctx, 0, sizeof(*ctx));
335 }
336
337
338 // ---------------------------
339 // wxPdfEncrypt implementation
340 // ---------------------------
341
342 static unsigned char padding[] =
343 "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF\xFA\x01\x08\x2E\x2E\x00\xB6\xD0\x68\x3E\x80\x2F\x0C\xA9\xFE\x64\x53\x69\x7A";
344
wxPdfEncrypt(int revision,int keyLength)345 wxPdfEncrypt::wxPdfEncrypt(int revision, int keyLength)
346 {
347 switch (revision)
348 {
349 case 4:
350 m_rValue = 4;
351 m_keyLength = 128 / 8;
352 m_aes = new wxPdfRijndael();
353 break;
354 case 3:
355 keyLength = keyLength - keyLength % 8;
356 keyLength = (keyLength >= 40) ? ((keyLength <= 128) ? keyLength : 128) : 40;
357 m_rValue = 3;
358 m_keyLength = keyLength / 8;
359 break;
360 case 2:
361 default:
362 m_rValue = 2;
363 m_keyLength = 40 / 8;
364 break;
365 }
366
367 int j;
368 for (j = 0; j < 16; j++)
369 {
370 m_rc4key[j] = 0;
371 }
372 }
373
~wxPdfEncrypt()374 wxPdfEncrypt::~wxPdfEncrypt()
375 {
376 if (m_rValue == 4)
377 {
378 delete m_aes;
379 }
380 }
381
382 void
PadPassword(const wxString & password,unsigned char pswd[32])383 wxPdfEncrypt::PadPassword(const wxString& password, unsigned char pswd[32])
384 {
385 unsigned int m = (unsigned int) password.Length();
386 if (m > 32) m = 32;
387
388 unsigned int j;
389 unsigned int p = 0;
390 wxString::const_iterator ch = password.begin();
391 for (j = 0; j < m; j++)
392 {
393 pswd[p++] = (unsigned char) ((unsigned int) (*ch) & 0xff);
394 ++ch;
395 }
396 for (j = 0; p < 32 && j < 32; j++)
397 {
398 pswd[p++] = padding[j];
399 }
400 }
401
402 void
GenerateEncryptionKey(const wxString & userPassword,const wxString & ownerPassword,int protection,const wxString & documentId)403 wxPdfEncrypt::GenerateEncryptionKey(const wxString& userPassword,
404 const wxString& ownerPassword,
405 int protection,
406 const wxString& documentId)
407 {
408 unsigned char userpswd[32];
409 unsigned char ownerpswd[32];
410
411 // Pad passwords
412 PadPassword(userPassword, userpswd);
413 PadPassword(ownerPassword, ownerpswd);
414
415 // Compute P value
416 m_pValue = -((protection ^ 255) + 1);
417
418 // Compute O value
419 ComputeOwnerKey(userpswd, ownerpswd, m_keyLength*8, m_rValue, false, m_oValue);
420
421 // Compute encryption key and U value
422 if (documentId.IsEmpty())
423 {
424 m_documentId = CreateDocumentId();
425 }
426 else
427 {
428 m_documentId = documentId;
429 }
430 ComputeEncryptionKey(m_documentId, userpswd,
431 m_oValue, m_pValue, m_keyLength*8, m_rValue, m_uValue);
432 }
433
434 bool
Authenticate(const wxString & documentID,const wxString & password,const wxString & uValue,const wxString & oValue,int pValue,int lengthValue,int rValue)435 wxPdfEncrypt::Authenticate(const wxString& documentID, const wxString& password,
436 const wxString& uValue, const wxString& oValue,
437 int pValue, int lengthValue, int rValue)
438 {
439 unsigned char userKey[32];
440 bool ok = false;
441 int j;
442 wxString::const_iterator uChar = uValue.begin();
443 wxString::const_iterator oChar = oValue.begin();
444 for (j = 0; j < 32; j++)
445 {
446 m_uValue[j] = (unsigned char) ((unsigned int) (*uChar) & 0xff);
447 m_oValue[j] = (unsigned char) ((unsigned int) (*oChar) & 0xff);
448 ++uChar;
449 ++oChar;
450 }
451 m_pValue = pValue;
452 m_keyLength = lengthValue / 8;
453
454 // Pad password
455 unsigned char pswd[32];
456 PadPassword(password, pswd);
457
458 // Check password: 1) as user password, 2) as owner password
459 ComputeEncryptionKey(documentID, pswd, m_oValue, pValue, lengthValue, rValue, userKey);
460 ok = CheckKey(userKey, m_uValue);
461 if (!ok)
462 {
463 unsigned char userpswd[32];
464 ComputeOwnerKey(m_oValue, pswd, lengthValue, rValue, true, userpswd);
465 ComputeEncryptionKey(documentID, userpswd, m_oValue, pValue, lengthValue, rValue, userKey);
466 ok = CheckKey(userKey, m_uValue);
467 }
468 return ok;
469 }
470
471 void
ComputeOwnerKey(unsigned char userPad[32],unsigned char ownerPad[32],unsigned int keyLength,int revision,bool authenticate,unsigned char ownerKey[32])472 wxPdfEncrypt::ComputeOwnerKey(unsigned char userPad[32], unsigned char ownerPad[32],
473 unsigned int keyLength, int revision, bool authenticate,
474 unsigned char ownerKey[32])
475 {
476 unsigned char mkey[MD5_HASHBYTES];
477 unsigned char digest[MD5_HASHBYTES];
478 unsigned int length = keyLength / 8;
479
480 MD5_CTX ctx;
481 MD5_Init(&ctx);
482 MD5_Update(&ctx, ownerPad, 32);
483 MD5_Final(digest,&ctx);
484
485 if (revision == 3 || revision == 4)
486 {
487 // only use for the input as many bit as the key consists of
488 unsigned int k;
489 for (k = 0; k < 50; ++k)
490 {
491 MD5_Init(&ctx);
492 MD5_Update(&ctx, digest, length);
493 MD5_Final(digest,&ctx);
494 }
495 memcpy(ownerKey, userPad, 32);
496 unsigned int i;
497 unsigned int j;
498 for (i = 0; i < 20; ++i)
499 {
500 for (j = 0; j < length ; ++j)
501 {
502 if (authenticate)
503 {
504 mkey[j] = (digest[j] ^ (19-i));
505 }
506 else
507 {
508 mkey[j] = (digest[j] ^ i);
509 }
510 }
511 RC4(mkey, length, ownerKey, 32, ownerKey);
512 }
513 }
514 else
515 {
516 RC4(digest, 5, userPad, 32, ownerKey);
517 }
518 }
519
520 void
ComputeEncryptionKey(const wxString & documentId,unsigned char userPad[32],unsigned char ownerKey[32],int pValue,unsigned int keyLength,int revision,unsigned char userKey[32])521 wxPdfEncrypt::ComputeEncryptionKey(const wxString& documentId,
522 unsigned char userPad[32], unsigned char ownerKey[32],
523 int pValue, unsigned int keyLength, int revision,
524 unsigned char userKey[32])
525 {
526 unsigned int k;
527 m_keyLength = keyLength / 8;
528
529 MD5_CTX ctx;
530 MD5_Init(&ctx);
531 MD5_Update(&ctx, userPad, 32);
532 MD5_Update(&ctx, ownerKey, 32);
533
534 unsigned char ext[4];
535 ext[0] = (unsigned char) ( pValue & 0xff);
536 ext[1] = (unsigned char) ((pValue >> 8) & 0xff);
537 ext[2] = (unsigned char) ((pValue >> 16) & 0xff);
538 ext[3] = (unsigned char) ((pValue >> 24) & 0xff);
539 MD5_Update(&ctx, ext, 4);
540
541 unsigned int docIdLength = (unsigned int) documentId.Length();
542 unsigned char* docId = NULL;
543 if (docIdLength > 0)
544 {
545 docId = new unsigned char[docIdLength];
546 unsigned int j;
547 wxString::const_iterator dChar = documentId.begin();
548 for (j = 0; j < docIdLength; j++)
549 {
550 docId[j] = (unsigned char) ((unsigned int) (*dChar) & 0xff);
551 ++dChar;
552 }
553 MD5_Update(&ctx, docId, docIdLength);
554 }
555
556 // TODO: (Revision 3 or greater) If document metadata is not being encrypted,
557 // pass 4 bytes with the value 0xFFFFFFFF to the MD5 hash function.
558
559 unsigned char digest[MD5_HASHBYTES];
560 MD5_Final(digest,&ctx);
561
562 // only use the really needed bits as input for the hash
563 if (revision == 3 || revision == 4)
564 {
565 for (k = 0; k < 50; ++k)
566 {
567 MD5_Init(&ctx);
568 MD5_Update(&ctx, digest, m_keyLength);
569 MD5_Final(digest, &ctx);
570 }
571 }
572
573 memcpy(m_encryptionKey, digest, m_keyLength);
574
575 // Setup user key
576 if (revision == 3 || revision == 4)
577 {
578 MD5_Init(&ctx);
579 MD5_Update(&ctx, padding, 32);
580 if (docId != NULL)
581 {
582 MD5_Update(&ctx, docId, docIdLength);
583 }
584 MD5_Final(digest, &ctx);
585 memcpy(userKey, digest, 16);
586 for (k = 16; k < 32; ++k)
587 {
588 userKey[k] = 0;
589 }
590 for (k = 0; k < 20; k++)
591 {
592 unsigned int j;
593 for (j = 0; j < m_keyLength; ++j)
594 {
595 digest[j] = (unsigned char)(m_encryptionKey[j] ^ k);
596 }
597 RC4(digest, m_keyLength, userKey, 16, userKey);
598 }
599 }
600 else
601 {
602 RC4(m_encryptionKey, m_keyLength, padding, 32, userKey);
603 }
604 if (docId != NULL)
605 {
606 delete [] docId;
607 }
608 }
609
610 bool
CheckKey(unsigned char key1[32],unsigned char key2[32])611 wxPdfEncrypt::CheckKey(unsigned char key1[32], unsigned char key2[32])
612 {
613 // Check whether the right password had been given
614 bool ok = true;
615 int k;
616 int kmax = (m_rValue == 3) ? 16 : 32;
617 for (k = 0; ok && k < kmax; k++)
618 {
619 ok = ok && (key1[k] == key2[k]);
620 }
621 return ok;
622 }
623
624 void
Encrypt(int n,int g,wxString & str)625 wxPdfEncrypt::Encrypt(int n, int g, wxString& str)
626 {
627 unsigned int len = (unsigned int) str.Length();
628 unsigned char* data = new unsigned char[len];
629 unsigned int j;
630 for (j = 0; j < len; j++)
631 {
632 data[j] = (unsigned char) str.GetChar(j);
633 }
634 Encrypt(n, g, data, len);
635 for (j = 0; j < len; j++)
636 {
637 str.SetChar(j, data[j]);
638 }
639 delete [] data;
640 }
641
642 void
Encrypt(int n,int g,unsigned char * str,unsigned int len)643 wxPdfEncrypt::Encrypt(int n, int g, unsigned char* str, unsigned int len)
644 {
645 unsigned char objkey[MD5_HASHBYTES];
646 unsigned char nkey[MD5_HASHBYTES+5+4];
647 unsigned int nkeylen = m_keyLength + 5;
648 unsigned int j;
649 for (j = 0; j < m_keyLength; j++)
650 {
651 nkey[j] = m_encryptionKey[j];
652 }
653 nkey[m_keyLength+0] = 0xff & n;
654 nkey[m_keyLength+1] = 0xff & (n >> 8);
655 nkey[m_keyLength+2] = 0xff & (n >> 16);
656 nkey[m_keyLength+3] = 0xff & g;
657 nkey[m_keyLength+4] = 0xff & (g >> 8);
658
659 if (m_rValue == 4)
660 {
661 // AES encryption needs some 'salt'
662 nkeylen += 4;
663 nkey[m_keyLength+5] = 0x73;
664 nkey[m_keyLength+6] = 0x41;
665 nkey[m_keyLength+7] = 0x6c;
666 nkey[m_keyLength+8] = 0x54;
667 }
668
669 GetMD5Binary(nkey, nkeylen, objkey);
670 int keylen = (m_keyLength <= 11) ? m_keyLength+5 : 16;
671 switch (m_rValue)
672 {
673 case 4:
674 AES(objkey, keylen, str, len, str);
675 break;
676 case 3:
677 case 2:
678 default:
679 RC4(objkey, keylen, str, len, str);
680 break;
681 }
682 }
683
684 /**
685 * RC4 is the standard encryption algorithm used in PDF format
686 */
687
688 void
RC4(unsigned char * key,unsigned int keylen,unsigned char * textin,unsigned int textlen,unsigned char * textout)689 wxPdfEncrypt::RC4(unsigned char* key, unsigned int keylen,
690 unsigned char* textin, unsigned int textlen,
691 unsigned char* textout)
692 {
693 unsigned int i;
694 unsigned int j;
695 int t;
696 unsigned char rc4[256];
697
698 if (memcmp(key,m_rc4key,keylen) != 0)
699 {
700 for (i = 0; i < 256; i++)
701 {
702 rc4[i] = i;
703 }
704 j = 0;
705 for (i = 0; i < 256; i++)
706 {
707 t = rc4[i];
708 j = (j + t + key[i % keylen]) % 256;
709 rc4[i] = rc4[j];
710 rc4[j] = t;
711 }
712 memcpy(m_rc4key,key,keylen);
713 memcpy(m_rc4last,rc4,256);
714 }
715 else
716 {
717 memcpy(rc4,m_rc4last,256);
718 }
719
720 int a = 0;
721 int b = 0;
722 unsigned char k;
723 for (i = 0; i < textlen; i++)
724 {
725 a = (a + 1) % 256;
726 t = rc4[a];
727 b = (b + t) % 256;
728 rc4[a] = rc4[b];
729 rc4[b] = t;
730 k = rc4[(rc4[a] + rc4[b]) % 256];
731 textout[i] = textin[i] ^ k;
732 }
733 }
734
735 void
GetMD5Binary(const unsigned char * data,unsigned int length,unsigned char * digest)736 wxPdfEncrypt::GetMD5Binary(const unsigned char* data, unsigned int length, unsigned char* digest)
737 {
738 MD5_CTX ctx;
739 MD5_Init(&ctx);
740 MD5_Update(&ctx, data, length);
741 MD5_Final(digest,&ctx);
742 }
743
744 void
AES(unsigned char * key,unsigned int keylen,unsigned char * textin,unsigned int textlen,unsigned char * textout)745 wxPdfEncrypt::AES(unsigned char* key, unsigned int keylen,
746 unsigned char* textin, unsigned int textlen,
747 unsigned char* textout)
748 {
749 wxUnusedVar(keylen);
750 GenerateInitialVector(textout);
751 m_aes->init(wxPdfRijndael::CBC, wxPdfRijndael::Encrypt, key, wxPdfRijndael::Key16Bytes, textout);
752 size_t offset = CalculateStreamOffset();
753 int len = m_aes->padEncrypt(&textin[offset], textlen, &textout[offset]);
754
755 // It is a good idea to check the error code
756 if (len < 0)
757 {
758 wxLogError(wxString(wxS("wxPdfEncrypt::AES: ")) +
759 wxString(_("Error on encrypting.")));
760 }
761 }
762
763 void
GenerateInitialVector(unsigned char iv[16])764 wxPdfEncrypt::GenerateInitialVector(unsigned char iv[16])
765 {
766 wxString keyString = wxPdfUtility::GetUniqueId();
767 #if wxUSE_UNICODE
768 wxCharBuffer cb(keyString.ToAscii());
769 const char* key = (const char*) cb;
770 #else
771 const char* key = (const char*) keyString.c_str();
772 #endif
773 GetMD5Binary((const unsigned char*) key, (unsigned int) keyString.Length(), iv);
774 }
775
776 size_t
CalculateStreamLength(size_t length)777 wxPdfEncrypt::CalculateStreamLength(size_t length)
778 {
779 size_t realLength = length;
780 if (m_rValue == 4)
781 {
782 // realLength = (length % 0x7ffffff0) + 32;
783 realLength = ((length + 15) & ~15) + 16;
784 if (length % 16 == 0)
785 {
786 realLength += 16;
787 }
788 }
789 return realLength;
790 }
791
792 size_t
CalculateStreamOffset()793 wxPdfEncrypt::CalculateStreamOffset()
794 {
795 size_t offset = 0;
796 if (m_rValue == 4)
797 {
798 offset = 16;
799 }
800 return offset;
801 }
802
803 wxString
CreateDocumentId()804 wxPdfEncrypt::CreateDocumentId()
805 {
806 wxString documentId;
807 unsigned char id[16];
808 GenerateInitialVector(id);
809 int k;
810 for (k = 0; k < 16; k++)
811 {
812 documentId.Append(wxChar(id[k]));
813 }
814 return documentId;
815 }
816