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
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
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
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
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
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
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
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
180 #pragma implementation "cypher.h"
183 #define P_DISABLE_FACTORY_INSTANCES
186 #include <ptclib/cypher.h>
187 #include <ptclib/mime.h>
188 #include <ptclib/random.h>
192 ///////////////////////////////////////////////////////////////////////////////
202 void PBase64::StartEncoding(BOOL useCRLF
)
205 encodeLength
= nextLine
= saveCount
= 0;
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
242 out
[encodeLength
++] = '\r';
243 out
[encodeLength
++] = '\n';
249 void PBase64::ProcessEncoding(const void * dataPtr
, PINDEX length
)
254 const BYTE
* data
= (const BYTE
*)dataPtr
;
255 while (saveCount
< 3) {
256 saveTriple
[saveCount
++] = *data
++;
261 OutputBase64(saveTriple
);
264 for (i
= 0; i
+2 < length
; i
+= 3)
265 OutputBase64(data
+i
);
267 saveCount
= length
- i
;
270 saveTriple
[0] = data
[i
++];
271 saveTriple
[1] = data
[i
];
274 saveTriple
[0] = data
[i
];
279 PString
PBase64::GetEncodedString()
281 PString retval
= encodedString
;
288 PString
PBase64::CompleteEncoding()
290 char * out
= encodedString
.GetPointer(encodeLength
+ 5)+encodeLength
;
294 *out
++ = Binary2Base64
[saveTriple
[0] >> 2];
295 *out
++ = Binary2Base64
[(saveTriple
[0]&3)<<4];
301 *out
++ = Binary2Base64
[saveTriple
[0] >> 2];
302 *out
++ = Binary2Base64
[((saveTriple
[0]&3)<<4) | (saveTriple
[1]>>4)];
303 *out
++ = Binary2Base64
[((saveTriple
[1]&15)<<2)];
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
)
332 encoder
.ProcessEncoding(data
, length
);
333 return encoder
.CompleteEncoding();
337 void PBase64::StartDecoding()
339 perfectDecode
= TRUE
;
341 decodedData
.SetSize(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
374 BYTE value
= Base642Binary
[(BYTE
)*cstr
++];
376 case 96 : // end of string
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
388 break; // Ignore totally
390 case 99 : // Illegal characters
391 perfectDecode
= FALSE
; // Ignore rubbish but flag decode as suspect
394 default : // legal value from 0 to 63
395 BYTE
* out
= decodedData
.GetPointer(((decodeSize
+1)&~255) + 256);
396 switch (quadPosition
) {
398 out
[decodeSize
] = (BYTE
)(value
<< 2);
401 out
[decodeSize
++] |= (BYTE
)(value
>> 4);
402 out
[decodeSize
] = (BYTE
)((value
&15) << 4);
405 out
[decodeSize
++] |= (BYTE
)(value
>> 2);
406 out
[decodeSize
] = (BYTE
)((value
&3) << 6);
409 out
[decodeSize
++] |= (BYTE
)value
;
412 quadPosition
= (quadPosition
+1)&3;
418 PBYTEArray
PBase64::GetDecodedData()
420 perfectDecode
= quadPosition
== 0;
421 decodedData
.SetSize(decodeSize
);
422 PBYTEArray retval
= decodedData
;
424 decodedData
.SetSize(0);
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);
441 PString
PBase64::Decode(const PString
& str
)
445 return PString((const char *)(const BYTE
*)data
, data
.GetSize());
449 BOOL
PBase64::Decode(const PString
& str
, PBYTEArray
& data
)
452 decoder
.ProcessDecoding(str
);
453 data
= decoder
.GetDecodedData();
454 return decoder
.IsDecodeOK();
458 BOOL
PBase64::Decode(const PString
& str
, void * dataBlock
, PINDEX length
)
461 decoder
.ProcessDecoding(str
);
462 return decoder
.GetDecodedData(dataBlock
, length
);
466 ///////////////////////////////////////////////////////////////////////////////
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()
498 CompleteDigest(result
);
499 return PBase64::Encode(result
.GetPointer(), result
.GetSize());
502 void PMessageDigest::CompleteDigest(Result
& result
)
504 InternalCompleteDigest(result
);
508 ///////////////////////////////////////////////////////////////////////////////
511 PMessageDigest5::PMessageDigest5()
517 // Constants for MD5Transform routine.
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)); \
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)); \
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)); \
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)); \
567 void PMessageDigest5::Transform(const BYTE * block)
575 for (PINDEX i
= 0; i
< 16; i
++)
576 x
[i
] = ((PUInt32l
*)block
)[i
];
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 */
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 */
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 */
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 */
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;
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
684 if (length
< partLen
)
687 // Transform as many times as possible.
688 memcpy(&buffer
[index
], data
, partLen
);
690 for (i
= partLen
; i
+ 63 < length
; i
+= 64)
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
);
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
)
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()
808 return PBase64::Encode(&result
, sizeof(result
));
811 void PMessageDigest5::Complete(Code
& codeResult
)
814 InternalCompleteDigest(result
);
815 memcpy(codeResult
.value
, result
.GetPointer(), sizeof(codeResult
.value
));
818 ///////////////////////////////////////////////////////////////////////////////
819 // PMessageDigestSHA1
823 #include <openssl/sha.h>
827 #pragma comment(lib, P_SSL_LIB1)
828 #pragma comment(lib, P_SSL_LIB2)
833 PMessageDigestSHA1::PMessageDigestSHA1()
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
)
857 SHA1_Update((SHA_CTX
*)shaContext
, data
, (unsigned long)len
);
860 void PMessageDigestSHA1::InternalCompleteDigest(Result
& result
)
862 if (shaContext
== NULL
)
865 SHA1_Final(result
.value
.GetPointer(20), (SHA_CTX
*)shaContext
);
866 delete ((SHA_CTX
*)shaContext
);
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
)
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
);
924 ///////////////////////////////////////////////////////////////////////////////
927 PCypher::PCypher(PINDEX blkSize
, BlockChainMode mode
)
928 : blockSize(blkSize
),
934 PCypher::PCypher(const void * keyData
, PINDEX keyLength
,
935 PINDEX blkSize
, BlockChainMode mode
)
936 : key((const BYTE
*)keyData
, keyLength
),
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
)
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
);
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
);
987 PBYTEArray
extra(blockSize
);
989 for (i
= 0; i
< length
; i
++)
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
)
1004 if (Decode(cypher
, clear
))
1010 BOOL
PCypher::Decode(const PString
& cypher
, PString
& clear
)
1014 PBYTEArray clearText
;
1015 if (!Decode(cypher
, clearText
))
1018 if (clearText
.IsEmpty())
1021 PINDEX sz
= clearText
.GetSize();
1022 memcpy(clear
.GetPointer(sz
+1), (const BYTE
*)clearText
, sz
);
1027 BOOL
PCypher::Decode(const PString
& cypher
, PBYTEArray
& clear
)
1030 if (!PBase64::Decode(cypher
, coded
))
1032 return Decode(coded
, clear
);
1036 PINDEX
PCypher::Decode(const PString
& cypher
, void * data
, PINDEX length
)
1039 PBase64::Decode(cypher
, coded
);
1041 if (!Decode(coded
, clear
))
1043 memcpy(data
, clear
, PMIN(length
, clear
.GetSize()));
1044 return clear
.GetSize();
1048 PINDEX
PCypher::Decode(const PBYTEArray
& coded
, void * data
, PINDEX length
)
1051 if (!Decode(coded
, clear
))
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)
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
);
1076 if (blockSize
!= 1) {
1077 if (*--out
>= blockSize
)
1079 clear
.SetSize(length
- blockSize
+ *out
);
1087 ///////////////////////////////////////////////////////////////////////////////
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];
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 ///////////////////////////////////////////////////////////////////////////////
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
,
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
,
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
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());
1222 str
= GetString(expiryDateKey
);
1223 if (!str
.IsEmpty()) {
1224 digestor
.Process(str
);
1227 str
= GetString(optionBitsKey
);
1228 if (!str
.IsEmpty()) {
1229 digestor
.Process(str
);
1233 PString vkey
= GetString(securityKey
);
1235 return (!vkey
|| GetBoolean(pendingPrefix
+ securityKey
)) ? Pending
: Defaults
;
1237 PMessageDigest5::Code code
;
1238 digestor
.Complete(code
);
1243 BYTE info
[sizeof(code
)+1+sizeof(DWORD
)];
1244 PTEACypher
crypt(productKey
);
1245 if (crypt
.Decode(vkey
, info
, sizeof(info
)) != sizeof(info
))
1248 if (memcmp(info
, &code
, sizeof(code
)) != 0)
1252 if (now
> GetTime(expiryDateKey
))
1259 BOOL
PSecureConfig::ValidatePending()
1261 if (GetValidation() != Pending
)
1264 PString vkey
= GetString(securityKey
);
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
))
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
1281 void * src
= &info
[sizeof(code
)+1];
1282 memcpy(dst
, src
, sizeof(opt
));
1283 PString
options(PString::Unsigned
, (DWORD
)opt
);
1285 PMessageDigest5 digestor
;
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)
1296 SetString(expiryDateKey
, expiry
);
1297 SetString(optionBitsKey
, options
);
1299 for (i
= 0; i
< securedKeys
.GetSize(); i
++) {
1300 PString str
= GetString(pendingPrefix
+ securedKeys
[i
]);
1302 SetString(securedKeys
[i
], str
);
1303 DeleteKey(pendingPrefix
+ securedKeys
[i
]);
1305 DeleteKey(pendingPrefix
+ securityKey
);
1311 void PSecureConfig::ResetPending()
1313 if (GetBoolean(pendingPrefix
+ securityKey
)) {
1314 for (PINDEX i
= 0; i
< securedKeys
.GetSize(); i
++)
1315 DeleteKey(securedKeys
[i
]);
1318 SetBoolean(pendingPrefix
+ securityKey
, TRUE
);
1320 for (PINDEX i
= 0; i
< securedKeys
.GetSize(); i
++) {
1321 PString str
= GetString(securedKeys
[i
]);
1323 SetString(pendingPrefix
+ securedKeys
[i
], str
);
1324 DeleteKey(securedKeys
[i
]);
1327 DeleteKey(expiryDateKey
);
1328 DeleteKey(optionBitsKey
);
1331 #endif // P_CONFIG_FILE
1333 ///////////////////////////////////////////////////////////////////////////////