Fixed DevStudio 2003 build with memory check code.
[pwlib.git] / src / ptclib / cypher.cxx
blob4c00dad306b1cd9bd72327ad972ac5984edf2f98
1 /*
2 * cypher.cxx
4 * Encryption support classes.
6 * Portable Windows Library
8 * Copyright (c) 1993-2002 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
27 * Revision 1.47 2005/01/26 05:37:57 csoutheren
28 * Added ability to remove config file support
30 * Revision 1.46 2004/07/06 10:12:52 csoutheren
31 * Added static integer o factory template to assist in ensuring factories are instantiated
33 * Revision 1.45 2004/06/29 12:22:22 rjongbloed
34 * Fixed incorrect usage of result (now object rather than scalar), thanks Michal Zygmuntowicz
36 * Revision 1.44 2004/04/09 06:52:17 rjongbloed
37 * Removed #pargma linker command for /delayload of DLL as documentations sais that
38 * you cannot do this.
40 * Revision 1.43 2004/04/03 23:53:09 csoutheren
41 * Added various changes to improce compatibility with the Sun Forte compiler
42 * Thanks to Brian Cameron
43 * Added detection of readdir_r version
45 * Revision 1.42 2004/03/23 05:59:17 csoutheren
46 * Moved the Base64 routines into cypher.cxx, which is a more sensible
47 * place and reduces the inclusion of unrelated code
49 * Revision 1.41 2004/03/14 10:03:47 rjongbloed
50 * Fixed "security patch" that cleared entire object (including the vtable!) isntead of
51 * clearing the "sensitive" information it was supposed to clear.
53 * Revision 1.40 2004/03/02 12:08:27 rjongbloed
54 * Added missing pragmas to automatically include libraries for OpenSSL
56 * Revision 1.39 2004/02/23 23:52:19 csoutheren
57 * Added pragmas to avoid every Windows application needing to include libs explicitly
59 * Revision 1.38 2003/04/27 23:52:57 craigs
60 * Fixed problem with SHA1 not calling Start
62 * Revision 1.37 2003/04/17 12:12:59 robertj
63 * Added windows library inclusion for optional openssl.
65 * Revision 1.36 2003/04/17 07:34:46 robertj
66 * Fixed correct test for P_SSL
68 * Revision 1.35 2003/04/17 01:21:55 craigs
69 * Fixed problem with delete'ing a void *
71 * Revision 1.33 2003/04/10 07:14:27 craigs
72 * Fixed link problem in MD5 class
74 * Revision 1.32 2003/04/10 06:16:09 craigs
75 * Added SHA-1 digest
77 * Revision 1.31 2002/11/06 22:47:24 robertj
78 * Fixed header comment (copyright etc)
80 * Revision 1.30 2002/06/05 12:29:15 craigs
81 * Changes for gcc 3.1
83 * Revision 1.29 2001/03/01 03:55:59 robertj
84 * Fixed MSVC warnings.
86 * Revision 1.28 2001/02/28 21:10:47 craigs
87 * Fixed problem in Decode function
88 * Added randomizer to fill data in Decode
90 * Revision 1.27 2000/02/17 12:05:02 robertj
91 * Added better random number generator after finding major flaws in MSVCRT version.
93 * Revision 1.26 1998/11/30 04:50:45 robertj
94 * New directory structure
96 * Revision 1.25 1998/09/23 06:21:56 robertj
97 * Added open source copyright license.
99 * Revision 1.24 1998/07/24 06:58:13 robertj
100 * Improved robustness of encrypted data decoding, error on illegal tail block size.
102 * Revision 1.23 1998/02/16 00:14:36 robertj
103 * Fixed ability to register in one stage instead of always having to use 2.
105 * Revision 1.22 1998/01/26 02:49:14 robertj
106 * GNU support.
108 * Revision 1.21 1997/10/30 10:19:19 robertj
109 * Fixed bug with having empty string in encrypted text.
111 * Revision 1.20 1997/10/10 10:43:41 robertj
112 * Fixed bug in password encryption, missing string terminator.
114 * Revision 1.19 1997/08/04 10:39:53 robertj
115 * Fixed bug for decoding empty string.
117 * Revision 1.18 1997/07/26 11:35:38 robertj
118 * Fixed bug where illegal data errors were not propagated.
120 * Revision 1.17 1996/11/16 10:50:26 robertj
121 * ??
123 * Revision 1.16 1996/08/17 09:56:02 robertj
124 * Fixed big endian processor platform conformance.
126 * Revision 1.15 1996/07/15 10:33:42 robertj
127 * Changed memory block base64 conversion functions to be void *.
128 * Changed memory block cypher conversion functions to be void *.
129 * Changed endian classes to be memory mapped.
131 * Revision 1.14 1996/06/18 12:35:49 robertj
132 * Fixed bug in registration when language is not English.
134 * Revision 1.13 1996/06/10 10:01:23 robertj
135 * Fixed bug in getting cypher key, not copying all the bytes.
137 * Revision 1.12 1996/05/26 03:46:31 robertj
138 * Compatibility to GNU 2.7.x
140 * Revision 1.11 1996/04/09 03:32:45 robertj
141 * Fixed bug in registration so now works in time zones other than Eastern Australia.
143 * Revision 1.11 1996/04/08 05:18:38 robertj
144 * Fixed bug in registering programs in a different time zone.
146 * Revision 1.10 1996/03/17 05:47:19 robertj
147 * Changed secured config to allow for expiry dates.
149 * Revision 1.9 1996/03/16 04:37:20 robertj
150 * Redesign of secure config to accommodate expiry dates and option values passed in security key code.
152 * Revision 1.8 1996/03/11 10:28:53 robertj
153 * Fixed bug in C++ optimising compiler.
155 * Revision 1.7 1996/03/02 03:20:52 robertj
156 * Fixed secured config parameters so leading/trailing blanks not significant.
158 * Revision 1.6 1996/02/25 11:22:42 robertj
159 * Added assertion if try and SetValidation when not pending.
161 * Revision 1.5 1996/02/25 02:53:05 robertj
162 * Further secure config development.
164 * Revision 1.4 1996/02/15 14:43:28 robertj
165 * Allowed no secured config data at all to be "valid". All vars will then be guarenteed to default.
167 * Revision 1.3 1996/01/28 14:14:12 robertj
168 * Further implementation of secure config.
170 * Revision 1.2 1996/01/28 02:49:00 robertj
171 * Removal of MemoryPointer classes as usage didn't work for GNU.
172 * Added the secure configuration mechanism for protecting applications.
174 * Revision 1.1 1996/01/23 13:05:58 robertj
175 * Initial revision
179 #ifdef __GNUC__
180 #pragma implementation "cypher.h"
181 #endif
183 #define P_DISABLE_FACTORY_INSTANCES
185 #include <ptlib.h>
186 #include <ptclib/cypher.h>
187 #include <ptclib/mime.h>
188 #include <ptclib/random.h>
192 ///////////////////////////////////////////////////////////////////////////////
193 // PBase64
195 PBase64::PBase64()
197 StartEncoding();
198 StartDecoding();
202 void PBase64::StartEncoding(BOOL useCRLF)
204 encodedString = "";
205 encodeLength = nextLine = saveCount = 0;
206 useCRLFs = useCRLF;
210 void PBase64::ProcessEncoding(const PString & str)
212 ProcessEncoding((const char *)str);
216 void PBase64::ProcessEncoding(const char * cstr)
218 ProcessEncoding((const BYTE *)cstr, strlen(cstr));
222 void PBase64::ProcessEncoding(const PBYTEArray & data)
224 ProcessEncoding(data, data.GetSize());
228 static const char Binary2Base64[65] =
229 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
231 void PBase64::OutputBase64(const BYTE * data)
233 char * out = encodedString.GetPointer(((encodeLength+7)&~255) + 256);
235 out[encodeLength++] = Binary2Base64[data[0] >> 2];
236 out[encodeLength++] = Binary2Base64[((data[0]&3)<<4) | (data[1]>>4)];
237 out[encodeLength++] = Binary2Base64[((data[1]&15)<<2) | (data[2]>>6)];
238 out[encodeLength++] = Binary2Base64[data[2]&0x3f];
240 if (++nextLine > 18) { // 76 columns
241 if (useCRLFs)
242 out[encodeLength++] = '\r';
243 out[encodeLength++] = '\n';
244 nextLine = 0;
249 void PBase64::ProcessEncoding(const void * dataPtr, PINDEX length)
251 if (length == 0)
252 return;
254 const BYTE * data = (const BYTE *)dataPtr;
255 while (saveCount < 3) {
256 saveTriple[saveCount++] = *data++;
257 if (--length == 0)
258 return;
261 OutputBase64(saveTriple);
263 PINDEX i;
264 for (i = 0; i+2 < length; i += 3)
265 OutputBase64(data+i);
267 saveCount = length - i;
268 switch (saveCount) {
269 case 2 :
270 saveTriple[0] = data[i++];
271 saveTriple[1] = data[i];
272 break;
273 case 1 :
274 saveTriple[0] = data[i];
279 PString PBase64::GetEncodedString()
281 PString retval = encodedString;
282 encodedString = "";
283 encodeLength = 0;
284 return retval;
288 PString PBase64::CompleteEncoding()
290 char * out = encodedString.GetPointer(encodeLength + 5)+encodeLength;
292 switch (saveCount) {
293 case 1 :
294 *out++ = Binary2Base64[saveTriple[0] >> 2];
295 *out++ = Binary2Base64[(saveTriple[0]&3)<<4];
296 *out++ = '=';
297 *out = '=';
298 break;
300 case 2 :
301 *out++ = Binary2Base64[saveTriple[0] >> 2];
302 *out++ = Binary2Base64[((saveTriple[0]&3)<<4) | (saveTriple[1]>>4)];
303 *out++ = Binary2Base64[((saveTriple[1]&15)<<2)];
304 *out = '=';
307 return encodedString;
311 PString PBase64::Encode(const PString & str)
313 return Encode((const char *)str);
317 PString PBase64::Encode(const char * cstr)
319 return Encode((const BYTE *)cstr, strlen(cstr));
323 PString PBase64::Encode(const PBYTEArray & data)
325 return Encode(data, data.GetSize());
329 PString PBase64::Encode(const void * data, PINDEX length)
331 PBase64 encoder;
332 encoder.ProcessEncoding(data, length);
333 return encoder.CompleteEncoding();
337 void PBase64::StartDecoding()
339 perfectDecode = TRUE;
340 quadPosition = 0;
341 decodedData.SetSize(0);
342 decodeSize = 0;
346 BOOL PBase64::ProcessDecoding(const PString & str)
348 return ProcessDecoding((const char *)str);
352 BOOL PBase64::ProcessDecoding(const char * cstr)
354 static const BYTE Base642Binary[256] = {
355 96, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 99, 99, 98, 99, 99,
356 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
357 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 62, 99, 99, 99, 63,
358 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 99, 99, 99, 97, 99, 99,
359 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
360 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 99, 99, 99, 99, 99,
361 99, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
362 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 99, 99, 99, 99, 99,
363 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
364 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
365 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
366 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
367 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
368 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
369 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
370 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99
373 for (;;) {
374 BYTE value = Base642Binary[(BYTE)*cstr++];
375 switch (value) {
376 case 96 : // end of string
377 return FALSE;
379 case 97 : // '=' sign
380 if (quadPosition == 3 || (quadPosition == 2 && *cstr == '=')) {
381 quadPosition = 0; // Reset this to zero, as have a perfect decode
382 return TRUE; // Stop decoding now as must be at end of data
384 perfectDecode = FALSE; // Ignore '=' sign but flag decode as suspect
385 break;
387 case 98 : // CRLFs
388 break; // Ignore totally
390 case 99 : // Illegal characters
391 perfectDecode = FALSE; // Ignore rubbish but flag decode as suspect
392 break;
394 default : // legal value from 0 to 63
395 BYTE * out = decodedData.GetPointer(((decodeSize+1)&~255) + 256);
396 switch (quadPosition) {
397 case 0 :
398 out[decodeSize] = (BYTE)(value << 2);
399 break;
400 case 1 :
401 out[decodeSize++] |= (BYTE)(value >> 4);
402 out[decodeSize] = (BYTE)((value&15) << 4);
403 break;
404 case 2 :
405 out[decodeSize++] |= (BYTE)(value >> 2);
406 out[decodeSize] = (BYTE)((value&3) << 6);
407 break;
408 case 3 :
409 out[decodeSize++] |= (BYTE)value;
410 break;
412 quadPosition = (quadPosition+1)&3;
418 PBYTEArray PBase64::GetDecodedData()
420 perfectDecode = quadPosition == 0;
421 decodedData.SetSize(decodeSize);
422 PBYTEArray retval = decodedData;
423 retval.MakeUnique();
424 decodedData.SetSize(0);
425 decodeSize = 0;
426 return retval;
430 BOOL PBase64::GetDecodedData(void * dataBlock, PINDEX length)
432 perfectDecode = quadPosition == 0;
433 BOOL bigEnough = length >= decodeSize;
434 memcpy(dataBlock, decodedData, bigEnough ? decodeSize : length);
435 decodedData.SetSize(0);
436 decodeSize = 0;
437 return bigEnough;
441 PString PBase64::Decode(const PString & str)
443 PBYTEArray data;
444 Decode(str, data);
445 return PString((const char *)(const BYTE *)data, data.GetSize());
449 BOOL PBase64::Decode(const PString & str, PBYTEArray & data)
451 PBase64 decoder;
452 decoder.ProcessDecoding(str);
453 data = decoder.GetDecodedData();
454 return decoder.IsDecodeOK();
458 BOOL PBase64::Decode(const PString & str, void * dataBlock, PINDEX length)
460 PBase64 decoder;
461 decoder.ProcessDecoding(str);
462 return decoder.GetDecodedData(dataBlock, length);
466 ///////////////////////////////////////////////////////////////////////////////
467 // PMessageDigest
469 PMessageDigest::PMessageDigest()
473 void PMessageDigest::Process(const PString & str)
475 Process((const char *)str);
479 void PMessageDigest::Process(const char * cstr)
481 Process(cstr, strlen(cstr));
485 void PMessageDigest::Process(const PBYTEArray & data)
487 Process(data, data.GetSize());
490 void PMessageDigest::Process(const void * dataBlock, PINDEX length)
492 InternalProcess(dataBlock, length);
495 PString PMessageDigest::CompleteDigest()
497 Result result;
498 CompleteDigest(result);
499 return PBase64::Encode(result.GetPointer(), result.GetSize());
502 void PMessageDigest::CompleteDigest(Result & result)
504 InternalCompleteDigest(result);
508 ///////////////////////////////////////////////////////////////////////////////
509 // PMessageDigest5
511 PMessageDigest5::PMessageDigest5()
513 Start();
517 // Constants for MD5Transform routine.
518 #define S11 7
519 #define S12 12
520 #define S13 17
521 #define S14 22
522 #define S21 5
523 #define S22 9
524 #define S23 14
525 #define S24 20
526 #define S31 4
527 #define S32 11
528 #define S33 16
529 #define S34 23
530 #define S41 6
531 #define S42 10
532 #define S43 15
533 #define S44 21
535 // F, G, H and I are basic MD5 functions.
536 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
537 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
538 #define H(x, y, z) ((x) ^ (y) ^ (z))
539 #define I(x, y, z) ((y) ^ ((x) | (~z)))
541 // ROTATE_LEFT rotates x left n bits.
542 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
544 // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
545 // Rotation is separate from addition to prevent recomputation.
546 #define FF(a, b, c, d, x, s, ac) \
547 (a) += F ((b), (c), (d)) + (x) + (DWORD)(ac); \
548 (a) = ROTATE_LEFT ((a), (s)); \
549 (a) += (b); \
551 #define GG(a, b, c, d, x, s, ac) \
552 (a) += G ((b), (c), (d)) + (x) + (DWORD)(ac); \
553 (a) = ROTATE_LEFT ((a), (s)); \
554 (a) += (b); \
556 #define HH(a, b, c, d, x, s, ac) \
557 (a) += H ((b), (c), (d)) + (x) + (DWORD)(ac); \
558 (a) = ROTATE_LEFT ((a), (s)); \
559 (a) += (b); \
561 #define II(a, b, c, d, x, s, ac) \
562 (a) += I ((b), (c), (d)) + (x) + (DWORD)(ac); \
563 (a) = ROTATE_LEFT ((a), (s)); \
564 (a) += (b); \
567 void PMessageDigest5::Transform(const BYTE * block)
569 DWORD a = state[0];
570 DWORD b = state[1];
571 DWORD c = state[2];
572 DWORD d = state[3];
574 DWORD x[16];
575 for (PINDEX i = 0; i < 16; i++)
576 x[i] = ((PUInt32l*)block)[i];
578 /* Round 1 */
579 FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
580 FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
581 FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
582 FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
583 FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
584 FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
585 FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
586 FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
587 FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
588 FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
589 FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
590 FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
591 FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
592 FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
593 FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
594 FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
596 /* Round 2 */
597 GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
598 GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
599 GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
600 GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
601 GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
602 GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
603 GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
604 GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
605 GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
606 GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
607 GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
608 GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
609 GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
610 GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
611 GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
612 GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
614 /* Round 3 */
615 HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
616 HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
617 HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
618 HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
619 HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
620 HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
621 HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
622 HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
623 HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
624 HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
625 HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
626 HH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
627 HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
628 HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
629 HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
630 HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
632 /* Round 4 */
633 II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
634 II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
635 II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
636 II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
637 II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
638 II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
639 II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
640 II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
641 II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
642 II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
643 II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
644 II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
645 II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
646 II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
647 II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
648 II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
650 state[0] += a;
651 state[1] += b;
652 state[2] += c;
653 state[3] += d;
655 // Zeroize sensitive information.
656 memset(x, 0, sizeof(x));
660 void PMessageDigest5::Start()
662 // Load magic initialization constants.
663 state[0] = 0x67452301;
664 state[1] = 0xefcdab89;
665 state[2] = 0x98badcfe;
666 state[3] = 0x10325476;
668 count = 0;
671 void PMessageDigest5::InternalProcess(const void * dataPtr, PINDEX length)
673 const BYTE * data = (const BYTE *)dataPtr;
675 // Compute number of bytes mod 64
676 PINDEX index = (PINDEX)((count >> 3) & 0x3F);
677 PINDEX partLen = 64 - index;
679 // Update number of bits
680 count += (PUInt64)length << 3;
682 // See if have a buffer full
683 PINDEX i;
684 if (length < partLen)
685 i = 0;
686 else {
687 // Transform as many times as possible.
688 memcpy(&buffer[index], data, partLen);
689 Transform(buffer);
690 for (i = partLen; i + 63 < length; i += 64)
691 Transform(&data[i]);
692 index = 0;
695 // Buffer remaining input
696 memcpy(&buffer[index], &data[i], length-i);
700 void PMessageDigest5::InternalCompleteDigest(Result & result)
702 // Put the count into bytes platform independently
703 PUInt64l countBytes = count;
705 // Pad out to 56 mod 64.
706 PINDEX index = (PINDEX)((count >> 3) & 0x3f);
707 PINDEX padLen = (index < 56) ? (56 - index) : (120 - index);
708 static BYTE const padding[64] = {
709 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
710 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
711 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
713 Process(padding, padLen);
715 // Append length
716 Process(&countBytes, sizeof(countBytes));
718 // Store state in digest
719 PUInt32l * valuep = (PUInt32l *)result.value.GetPointer(4 * sizeof(PUInt32l));
720 for (PINDEX i = 0; i < PARRAYSIZE(state); i++)
721 valuep[i] = state[i];
723 // Zeroize sensitive information.
724 memset(buffer, 0, sizeof(buffer));
725 memset(state, 0, sizeof(state));
729 PString PMessageDigest5::Encode(const PString & str)
731 return Encode((const char *)str);
735 void PMessageDigest5::Encode(const PString & str, Result & result)
737 Encode((const char *)str, result);
741 PString PMessageDigest5::Encode(const char * cstr)
743 return Encode((const BYTE *)cstr, strlen(cstr));
747 void PMessageDigest5::Encode(const char * cstr, Result & result)
749 Encode((const BYTE *)cstr, strlen(cstr), result);
753 PString PMessageDigest5::Encode(const PBYTEArray & data)
755 return Encode(data, data.GetSize());
759 void PMessageDigest5::Encode(const PBYTEArray & data, Result & result)
761 Encode(data, data.GetSize(), result);
765 PString PMessageDigest5::Encode(const void * data, PINDEX length)
767 Result result;
768 Encode(data, length, result);
769 return PBase64::Encode(result.GetPointer(), result.GetSize());
773 void PMessageDigest5::Encode(const void * data, PINDEX len, Result & result)
775 PMessageDigest5 stomach;
776 stomach.Process(data, len);
777 stomach.CompleteDigest(result);
780 //// backwards compatability functions
782 void PMessageDigest5::Encode(const PString & str, Code & result)
784 Encode((const char *)str, result);
787 void PMessageDigest5::Encode(const char * cstr, Code & result)
789 Encode((const BYTE *)cstr, strlen(cstr), result);
792 void PMessageDigest5::Encode(const PBYTEArray & data, Code & result)
794 Encode(data, data.GetSize(), result);
797 void PMessageDigest5::Encode(const void * data, PINDEX len, Code & codeResult)
799 PMessageDigest5 stomach;
800 stomach.Process(data, len);
801 stomach.Complete(codeResult);
804 PString PMessageDigest5::Complete()
806 Code result;
807 Complete(result);
808 return PBase64::Encode(&result, sizeof(result));
811 void PMessageDigest5::Complete(Code & codeResult)
813 Result result;
814 InternalCompleteDigest(result);
815 memcpy(codeResult.value, result.GetPointer(), sizeof(codeResult.value));
818 ///////////////////////////////////////////////////////////////////////////////
819 // PMessageDigestSHA1
821 #if P_SSL
823 #include <openssl/sha.h>
825 #ifdef _MSC_VER
827 #pragma comment(lib, P_SSL_LIB1)
828 #pragma comment(lib, P_SSL_LIB2)
830 #endif
833 PMessageDigestSHA1::PMessageDigestSHA1()
835 shaContext = NULL;
836 Start();
839 PMessageDigestSHA1::~PMessageDigestSHA1()
841 delete (SHA_CTX *)shaContext;
844 void PMessageDigestSHA1::Start()
846 delete (SHA_CTX *)shaContext;
847 shaContext = new SHA_CTX;
849 SHA1_Init((SHA_CTX *)shaContext);
852 void PMessageDigestSHA1::InternalProcess(const void * data, PINDEX len)
854 if (shaContext == NULL)
855 return;
857 SHA1_Update((SHA_CTX *)shaContext, data, (unsigned long)len);
860 void PMessageDigestSHA1::InternalCompleteDigest(Result & result)
862 if (shaContext == NULL)
863 return;
865 SHA1_Final(result.value.GetPointer(20), (SHA_CTX *)shaContext);
866 delete ((SHA_CTX *)shaContext);
867 shaContext = NULL;
871 PString PMessageDigestSHA1::Encode(const PString & str)
873 return Encode((const char *)str);
877 void PMessageDigestSHA1::Encode(const PString & str, Result & result)
879 Encode((const char *)str, result);
883 PString PMessageDigestSHA1::Encode(const char * cstr)
885 return Encode((const BYTE *)cstr, strlen(cstr));
889 void PMessageDigestSHA1::Encode(const char * cstr, Result & result)
891 Encode((const BYTE *)cstr, strlen(cstr), result);
895 PString PMessageDigestSHA1::Encode(const PBYTEArray & data)
897 return Encode(data, data.GetSize());
901 void PMessageDigestSHA1::Encode(const PBYTEArray & data, Result & result)
903 Encode(data, data.GetSize(), result);
907 PString PMessageDigestSHA1::Encode(const void * data, PINDEX length)
909 Result result;
910 Encode(data, length, result);
911 return PBase64::Encode(result.GetPointer(), result.GetSize());
915 void PMessageDigestSHA1::Encode(const void * data, PINDEX len, Result & result)
917 PMessageDigestSHA1 stomach;
918 stomach.Process(data, len);
919 stomach.CompleteDigest(result);
922 #endif
924 ///////////////////////////////////////////////////////////////////////////////
925 // PCypher
927 PCypher::PCypher(PINDEX blkSize, BlockChainMode mode)
928 : blockSize(blkSize),
929 chainMode(mode)
934 PCypher::PCypher(const void * keyData, PINDEX keyLength,
935 PINDEX blkSize, BlockChainMode mode)
936 : key((const BYTE *)keyData, keyLength),
937 blockSize(blkSize),
938 chainMode(mode)
943 PString PCypher::Encode(const PString & str)
945 return Encode((const char *)str, str.GetLength());
949 PString PCypher::Encode(const PBYTEArray & clear)
951 return Encode((const BYTE *)clear, clear.GetSize());
955 PString PCypher::Encode(const void * data, PINDEX length)
957 PBYTEArray coded;
958 Encode(data, length, coded);
959 return PBase64::Encode(coded);
963 void PCypher::Encode(const PBYTEArray & clear, PBYTEArray & coded)
965 Encode((const BYTE *)clear, clear.GetSize(), coded);
969 void PCypher::Encode(const void * data, PINDEX length, PBYTEArray & coded)
971 PAssert((blockSize%8) == 0, PUnsupportedFeature);
973 Initialise(TRUE);
975 const BYTE * in = (const BYTE *)data;
976 BYTE * out = coded.GetPointer(
977 blockSize > 1 ? (length/blockSize+1)*blockSize : length);
979 while (length >= blockSize) {
980 EncodeBlock(in, out);
981 in += blockSize;
982 out += blockSize;
983 length -= blockSize;
986 if (blockSize > 1) {
987 PBYTEArray extra(blockSize);
988 PINDEX i;
989 for (i = 0; i < length; i++)
990 extra[i] = *in++;
991 PTime now;
992 PRandom rand((DWORD)now.GetTimestamp());
993 for (; i < blockSize-1; i++)
994 extra[i] = (BYTE)rand.Generate();
995 extra[blockSize-1] = (BYTE)length;
996 EncodeBlock(extra, out);
1001 PString PCypher::Decode(const PString & cypher)
1003 PString clear;
1004 if (Decode(cypher, clear))
1005 return clear;
1006 return PString();
1010 BOOL PCypher::Decode(const PString & cypher, PString & clear)
1012 clear = PString();
1014 PBYTEArray clearText;
1015 if (!Decode(cypher, clearText))
1016 return FALSE;
1018 if (clearText.IsEmpty())
1019 return TRUE;
1021 PINDEX sz = clearText.GetSize();
1022 memcpy(clear.GetPointer(sz+1), (const BYTE *)clearText, sz);
1023 return TRUE;
1027 BOOL PCypher::Decode(const PString & cypher, PBYTEArray & clear)
1029 PBYTEArray coded;
1030 if (!PBase64::Decode(cypher, coded))
1031 return FALSE;
1032 return Decode(coded, clear);
1036 PINDEX PCypher::Decode(const PString & cypher, void * data, PINDEX length)
1038 PBYTEArray coded;
1039 PBase64::Decode(cypher, coded);
1040 PBYTEArray clear;
1041 if (!Decode(coded, clear))
1042 return 0;
1043 memcpy(data, clear, PMIN(length, clear.GetSize()));
1044 return clear.GetSize();
1048 PINDEX PCypher::Decode(const PBYTEArray & coded, void * data, PINDEX length)
1050 PBYTEArray clear;
1051 if (!Decode(coded, clear))
1052 return 0;
1053 memcpy(data, clear, PMIN(length, clear.GetSize()));
1054 return clear.GetSize();
1058 BOOL PCypher::Decode(const PBYTEArray & coded, PBYTEArray & clear)
1060 PAssert((blockSize%8) == 0, PUnsupportedFeature);
1061 if (coded.IsEmpty() || (coded.GetSize()%blockSize) != 0)
1062 return FALSE;
1064 Initialise(FALSE);
1066 const BYTE * in = coded;
1067 PINDEX length = coded.GetSize();
1068 BYTE * out = clear.GetPointer(length);
1070 for (PINDEX count = 0; count < length; count += blockSize) {
1071 DecodeBlock(in, out);
1072 in += blockSize;
1073 out += blockSize;
1076 if (blockSize != 1) {
1077 if (*--out >= blockSize)
1078 return FALSE;
1079 clear.SetSize(length - blockSize + *out);
1082 return TRUE;
1087 ///////////////////////////////////////////////////////////////////////////////
1088 // PTEACypher
1090 PTEACypher::PTEACypher(BlockChainMode chainMode)
1091 : PCypher(8, chainMode)
1093 GenerateKey(*(Key*)key.GetPointer(sizeof(Key)));
1097 PTEACypher::PTEACypher(const Key & keyData, BlockChainMode chainMode)
1098 : PCypher(&keyData, sizeof(Key), 8, chainMode)
1103 void PTEACypher::SetKey(const Key & newKey)
1105 memcpy(key.GetPointer(sizeof(Key)), &newKey, sizeof(Key));
1109 void PTEACypher::GetKey(Key & newKey) const
1111 memcpy(&newKey, key, sizeof(Key));
1115 void PTEACypher::GenerateKey(Key & newKey)
1117 static PRandom rand; //=1 // Explicitly set seed if need known random sequence
1118 for (size_t i = 0; i < sizeof(Key); i++)
1119 newKey.value[i] = (BYTE)rand;
1123 static const DWORD TEADelta = 0x9e3779b9; // Magic number for key schedule
1125 void PTEACypher::Initialise(BOOL)
1127 k0 = ((const PUInt32l *)(const BYTE *)key)[0];
1128 k1 = ((const PUInt32l *)(const BYTE *)key)[1];
1129 k2 = ((const PUInt32l *)(const BYTE *)key)[2];
1130 k3 = ((const PUInt32l *)(const BYTE *)key)[3];
1134 void PTEACypher::EncodeBlock(const void * in, void * out)
1136 DWORD y = ((PUInt32b*)in)[0];
1137 DWORD z = ((PUInt32b*)in)[1];
1138 DWORD sum = 0;
1139 for (PINDEX count = 32; count > 0; count--) {
1140 sum += TEADelta; // Magic number for key schedule
1141 y += (z<<4)+k0 ^ z+sum ^ (z>>5)+k1;
1142 z += (y<<4)+k2 ^ y+sum ^ (y>>5)+k3; /* end cycle */
1144 ((PUInt32b*)out)[0] = y;
1145 ((PUInt32b*)out)[1] = z;
1149 void PTEACypher::DecodeBlock(const void * in, void * out)
1151 DWORD y = ((PUInt32b*)in)[0];
1152 DWORD z = ((PUInt32b*)in)[1];
1153 DWORD sum = TEADelta<<5;
1154 for (PINDEX count = 32; count > 0; count--) {
1155 z -= (y<<4)+k2 ^ y+sum ^ (y>>5)+k3;
1156 y -= (z<<4)+k0 ^ z+sum ^ (z>>5)+k1;
1157 sum -= TEADelta; // Magic number for key schedule
1159 ((PUInt32b*)out)[0] = y;
1160 ((PUInt32b*)out)[1] = z;
1164 ///////////////////////////////////////////////////////////////////////////////
1165 // PSecureConfig
1167 #ifdef P_CONFIG_FILE
1169 static const char DefaultSecuredOptions[] = "Secured Options";
1170 static const char DefaultSecurityKey[] = "Validation";
1171 static const char DefaultExpiryDateKey[] = "Expiry Date";
1172 static const char DefaultOptionBitsKey[] = "Option Bits";
1173 static const char DefaultPendingPrefix[] = "Pending:";
1175 PSecureConfig::PSecureConfig(const PTEACypher::Key & prodKey,
1176 const PStringArray & secKeys,
1177 Source src)
1178 : PConfig(PString(DefaultSecuredOptions), src),
1179 securedKeys(secKeys),
1180 securityKey(DefaultSecurityKey),
1181 expiryDateKey(DefaultExpiryDateKey),
1182 optionBitsKey(DefaultOptionBitsKey),
1183 pendingPrefix(DefaultPendingPrefix)
1185 productKey = prodKey;
1189 PSecureConfig::PSecureConfig(const PTEACypher::Key & prodKey,
1190 const char * const * secKeys,
1191 PINDEX count,
1192 Source src)
1193 : PConfig(PString(DefaultSecuredOptions), src),
1194 securedKeys(count, secKeys),
1195 securityKey(DefaultSecurityKey),
1196 expiryDateKey(DefaultExpiryDateKey),
1197 optionBitsKey(DefaultOptionBitsKey),
1198 pendingPrefix(DefaultPendingPrefix)
1200 productKey = prodKey;
1204 void PSecureConfig::GetProductKey(PTEACypher::Key & prodKey) const
1206 prodKey = productKey;
1210 PSecureConfig::ValidationState PSecureConfig::GetValidation() const
1212 PString str;
1213 BOOL allEmpty = TRUE;
1214 PMessageDigest5 digestor;
1215 for (PINDEX i = 0; i < securedKeys.GetSize(); i++) {
1216 str = GetString(securedKeys[i]);
1217 if (!str.IsEmpty()) {
1218 digestor.Process(str.Trim());
1219 allEmpty = FALSE;
1222 str = GetString(expiryDateKey);
1223 if (!str.IsEmpty()) {
1224 digestor.Process(str);
1225 allEmpty = FALSE;
1227 str = GetString(optionBitsKey);
1228 if (!str.IsEmpty()) {
1229 digestor.Process(str);
1230 allEmpty = FALSE;
1233 PString vkey = GetString(securityKey);
1234 if (allEmpty)
1235 return (!vkey || GetBoolean(pendingPrefix + securityKey)) ? Pending : Defaults;
1237 PMessageDigest5::Code code;
1238 digestor.Complete(code);
1240 if (vkey.IsEmpty())
1241 return Invalid;
1243 BYTE info[sizeof(code)+1+sizeof(DWORD)];
1244 PTEACypher crypt(productKey);
1245 if (crypt.Decode(vkey, info, sizeof(info)) != sizeof(info))
1246 return Invalid;
1248 if (memcmp(info, &code, sizeof(code)) != 0)
1249 return Invalid;
1251 PTime now;
1252 if (now > GetTime(expiryDateKey))
1253 return Expired;
1255 return IsValid;
1259 BOOL PSecureConfig::ValidatePending()
1261 if (GetValidation() != Pending)
1262 return FALSE;
1264 PString vkey = GetString(securityKey);
1265 if (vkey.IsEmpty())
1266 return TRUE;
1268 PMessageDigest5::Code code;
1269 BYTE info[sizeof(code)+1+sizeof(DWORD)];
1270 PTEACypher crypt(productKey);
1271 if (crypt.Decode(vkey, info, sizeof(info)) != sizeof(info))
1272 return FALSE;
1274 PTime expiryDate(0, 0, 0,
1275 1, info[sizeof(code)]&15, (info[sizeof(code)]>>4)+1996, PTime::GMT);
1276 PString expiry = expiryDate.AsString("d MMME yyyy", PTime::GMT);
1278 // This is for alignment problems on processors that care about such things
1279 PUInt32b opt;
1280 void * dst = &opt;
1281 void * src = &info[sizeof(code)+1];
1282 memcpy(dst, src, sizeof(opt));
1283 PString options(PString::Unsigned, (DWORD)opt);
1285 PMessageDigest5 digestor;
1286 PINDEX i;
1287 for (i = 0; i < securedKeys.GetSize(); i++)
1288 digestor.Process(GetString(pendingPrefix + securedKeys[i]).Trim());
1289 digestor.Process(expiry);
1290 digestor.Process(options);
1291 digestor.Complete(code);
1293 if (memcmp(info, &code, sizeof(code)) != 0)
1294 return FALSE;
1296 SetString(expiryDateKey, expiry);
1297 SetString(optionBitsKey, options);
1299 for (i = 0; i < securedKeys.GetSize(); i++) {
1300 PString str = GetString(pendingPrefix + securedKeys[i]);
1301 if (!str.IsEmpty())
1302 SetString(securedKeys[i], str);
1303 DeleteKey(pendingPrefix + securedKeys[i]);
1305 DeleteKey(pendingPrefix + securityKey);
1307 return TRUE;
1311 void PSecureConfig::ResetPending()
1313 if (GetBoolean(pendingPrefix + securityKey)) {
1314 for (PINDEX i = 0; i < securedKeys.GetSize(); i++)
1315 DeleteKey(securedKeys[i]);
1317 else {
1318 SetBoolean(pendingPrefix + securityKey, TRUE);
1320 for (PINDEX i = 0; i < securedKeys.GetSize(); i++) {
1321 PString str = GetString(securedKeys[i]);
1322 if (!str.IsEmpty())
1323 SetString(pendingPrefix + securedKeys[i], str);
1324 DeleteKey(securedKeys[i]);
1327 DeleteKey(expiryDateKey);
1328 DeleteKey(optionBitsKey);
1331 #endif // P_CONFIG_FILE
1333 ///////////////////////////////////////////////////////////////////////////////