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