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.46 2004/07/06 10:12:52 csoutheren
28 * Added static integer o factory template to assist in ensuring factories are instantiated
30 * Revision 1.45 2004/06/29 12:22:22 rjongbloed
31 * Fixed incorrect usage of result (now object rather than scalar), thanks Michal Zygmuntowicz
33 * Revision 1.44 2004/04/09 06:52:17 rjongbloed
34 * Removed #pargma linker command for /delayload of DLL as documentations sais that
37 * Revision 1.43 2004/04/03 23:53:09 csoutheren
38 * Added various changes to improce compatibility with the Sun Forte compiler
39 * Thanks to Brian Cameron
40 * Added detection of readdir_r version
42 * Revision 1.42 2004/03/23 05:59:17 csoutheren
43 * Moved the Base64 routines into cypher.cxx, which is a more sensible
44 * place and reduces the inclusion of unrelated code
46 * Revision 1.41 2004/03/14 10:03:47 rjongbloed
47 * Fixed "security patch" that cleared entire object (including the vtable!) isntead of
48 * clearing the "sensitive" information it was supposed to clear.
50 * Revision 1.40 2004/03/02 12:08:27 rjongbloed
51 * Added missing pragmas to automatically include libraries for OpenSSL
53 * Revision 1.39 2004/02/23 23:52:19 csoutheren
54 * Added pragmas to avoid every Windows application needing to include libs explicitly
56 * Revision 1.38 2003/04/27 23:52:57 craigs
57 * Fixed problem with SHA1 not calling Start
59 * Revision 1.37 2003/04/17 12:12:59 robertj
60 * Added windows library inclusion for optional openssl.
62 * Revision 1.36 2003/04/17 07:34:46 robertj
63 * Fixed correct test for P_SSL
65 * Revision 1.35 2003/04/17 01:21:55 craigs
66 * Fixed problem with delete'ing a void *
68 * Revision 1.33 2003/04/10 07:14:27 craigs
69 * Fixed link problem in MD5 class
71 * Revision 1.32 2003/04/10 06:16:09 craigs
74 * Revision 1.31 2002/11/06 22:47:24 robertj
75 * Fixed header comment (copyright etc)
77 * Revision 1.30 2002/06/05 12:29:15 craigs
80 * Revision 1.29 2001/03/01 03:55:59 robertj
81 * Fixed MSVC warnings.
83 * Revision 1.28 2001/02/28 21:10:47 craigs
84 * Fixed problem in Decode function
85 * Added randomizer to fill data in Decode
87 * Revision 1.27 2000/02/17 12:05:02 robertj
88 * Added better random number generator after finding major flaws in MSVCRT version.
90 * Revision 1.26 1998/11/30 04:50:45 robertj
91 * New directory structure
93 * Revision 1.25 1998/09/23 06:21:56 robertj
94 * Added open source copyright license.
96 * Revision 1.24 1998/07/24 06:58:13 robertj
97 * Improved robustness of encrypted data decoding, error on illegal tail block size.
99 * Revision 1.23 1998/02/16 00:14:36 robertj
100 * Fixed ability to register in one stage instead of always having to use 2.
102 * Revision 1.22 1998/01/26 02:49:14 robertj
105 * Revision 1.21 1997/10/30 10:19:19 robertj
106 * Fixed bug with having empty string in encrypted text.
108 * Revision 1.20 1997/10/10 10:43:41 robertj
109 * Fixed bug in password encryption, missing string terminator.
111 * Revision 1.19 1997/08/04 10:39:53 robertj
112 * Fixed bug for decoding empty string.
114 * Revision 1.18 1997/07/26 11:35:38 robertj
115 * Fixed bug where illegal data errors were not propagated.
117 * Revision 1.17 1996/11/16 10:50:26 robertj
120 * Revision 1.16 1996/08/17 09:56:02 robertj
121 * Fixed big endian processor platform conformance.
123 * Revision 1.15 1996/07/15 10:33:42 robertj
124 * Changed memory block base64 conversion functions to be void *.
125 * Changed memory block cypher conversion functions to be void *.
126 * Changed endian classes to be memory mapped.
128 * Revision 1.14 1996/06/18 12:35:49 robertj
129 * Fixed bug in registration when language is not English.
131 * Revision 1.13 1996/06/10 10:01:23 robertj
132 * Fixed bug in getting cypher key, not copying all the bytes.
134 * Revision 1.12 1996/05/26 03:46:31 robertj
135 * Compatibility to GNU 2.7.x
137 * Revision 1.11 1996/04/09 03:32:45 robertj
138 * Fixed bug in registration so now works in time zones other than Eastern Australia.
140 * Revision 1.11 1996/04/08 05:18:38 robertj
141 * Fixed bug in registering programs in a different time zone.
143 * Revision 1.10 1996/03/17 05:47:19 robertj
144 * Changed secured config to allow for expiry dates.
146 * Revision 1.9 1996/03/16 04:37:20 robertj
147 * Redesign of secure config to accommodate expiry dates and option values passed in security key code.
149 * Revision 1.8 1996/03/11 10:28:53 robertj
150 * Fixed bug in C++ optimising compiler.
152 * Revision 1.7 1996/03/02 03:20:52 robertj
153 * Fixed secured config parameters so leading/trailing blanks not significant.
155 * Revision 1.6 1996/02/25 11:22:42 robertj
156 * Added assertion if try and SetValidation when not pending.
158 * Revision 1.5 1996/02/25 02:53:05 robertj
159 * Further secure config development.
161 * Revision 1.4 1996/02/15 14:43:28 robertj
162 * Allowed no secured config data at all to be "valid". All vars will then be guarenteed to default.
164 * Revision 1.3 1996/01/28 14:14:12 robertj
165 * Further implementation of secure config.
167 * Revision 1.2 1996/01/28 02:49:00 robertj
168 * Removal of MemoryPointer classes as usage didn't work for GNU.
169 * Added the secure configuration mechanism for protecting applications.
171 * Revision 1.1 1996/01/23 13:05:58 robertj
177 #pragma implementation "cypher.h"
180 #define P_DISABLE_FACTORY_INSTANCES
183 #include <ptclib/cypher.h>
184 #include <ptclib/mime.h>
185 #include <ptclib/random.h>
189 ///////////////////////////////////////////////////////////////////////////////
199 void PBase64::StartEncoding(BOOL useCRLF
)
202 encodeLength
= nextLine
= saveCount
= 0;
207 void PBase64::ProcessEncoding(const PString
& str
)
209 ProcessEncoding((const char *)str
);
213 void PBase64::ProcessEncoding(const char * cstr
)
215 ProcessEncoding((const BYTE
*)cstr
, strlen(cstr
));
219 void PBase64::ProcessEncoding(const PBYTEArray
& data
)
221 ProcessEncoding(data
, data
.GetSize());
225 static const char Binary2Base64
[65] =
226 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
228 void PBase64::OutputBase64(const BYTE
* data
)
230 char * out
= encodedString
.GetPointer(((encodeLength
+7)&~255) + 256);
232 out
[encodeLength
++] = Binary2Base64
[data
[0] >> 2];
233 out
[encodeLength
++] = Binary2Base64
[((data
[0]&3)<<4) | (data
[1]>>4)];
234 out
[encodeLength
++] = Binary2Base64
[((data
[1]&15)<<2) | (data
[2]>>6)];
235 out
[encodeLength
++] = Binary2Base64
[data
[2]&0x3f];
237 if (++nextLine
> 18) { // 76 columns
239 out
[encodeLength
++] = '\r';
240 out
[encodeLength
++] = '\n';
246 void PBase64::ProcessEncoding(const void * dataPtr
, PINDEX length
)
251 const BYTE
* data
= (const BYTE
*)dataPtr
;
252 while (saveCount
< 3) {
253 saveTriple
[saveCount
++] = *data
++;
258 OutputBase64(saveTriple
);
261 for (i
= 0; i
+2 < length
; i
+= 3)
262 OutputBase64(data
+i
);
264 saveCount
= length
- i
;
267 saveTriple
[0] = data
[i
++];
268 saveTriple
[1] = data
[i
];
271 saveTriple
[0] = data
[i
];
276 PString
PBase64::GetEncodedString()
278 PString retval
= encodedString
;
285 PString
PBase64::CompleteEncoding()
287 char * out
= encodedString
.GetPointer(encodeLength
+ 5)+encodeLength
;
291 *out
++ = Binary2Base64
[saveTriple
[0] >> 2];
292 *out
++ = Binary2Base64
[(saveTriple
[0]&3)<<4];
298 *out
++ = Binary2Base64
[saveTriple
[0] >> 2];
299 *out
++ = Binary2Base64
[((saveTriple
[0]&3)<<4) | (saveTriple
[1]>>4)];
300 *out
++ = Binary2Base64
[((saveTriple
[1]&15)<<2)];
304 return encodedString
;
308 PString
PBase64::Encode(const PString
& str
)
310 return Encode((const char *)str
);
314 PString
PBase64::Encode(const char * cstr
)
316 return Encode((const BYTE
*)cstr
, strlen(cstr
));
320 PString
PBase64::Encode(const PBYTEArray
& data
)
322 return Encode(data
, data
.GetSize());
326 PString
PBase64::Encode(const void * data
, PINDEX length
)
329 encoder
.ProcessEncoding(data
, length
);
330 return encoder
.CompleteEncoding();
334 void PBase64::StartDecoding()
336 perfectDecode
= TRUE
;
338 decodedData
.SetSize(0);
343 BOOL
PBase64::ProcessDecoding(const PString
& str
)
345 return ProcessDecoding((const char *)str
);
349 BOOL
PBase64::ProcessDecoding(const char * cstr
)
351 static const BYTE Base642Binary
[256] = {
352 96, 99, 99, 99, 99, 99, 99, 99, 99, 99, 98, 99, 99, 98, 99, 99,
353 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
354 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 62, 99, 99, 99, 63,
355 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 99, 99, 99, 97, 99, 99,
356 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
357 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 99, 99, 99, 99, 99,
358 99, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
359 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 99, 99, 99, 99, 99,
360 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
361 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
362 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 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
371 BYTE value
= Base642Binary
[(BYTE
)*cstr
++];
373 case 96 : // end of string
376 case 97 : // '=' sign
377 if (quadPosition
== 3 || (quadPosition
== 2 && *cstr
== '=')) {
378 quadPosition
= 0; // Reset this to zero, as have a perfect decode
379 return TRUE
; // Stop decoding now as must be at end of data
381 perfectDecode
= FALSE
; // Ignore '=' sign but flag decode as suspect
385 break; // Ignore totally
387 case 99 : // Illegal characters
388 perfectDecode
= FALSE
; // Ignore rubbish but flag decode as suspect
391 default : // legal value from 0 to 63
392 BYTE
* out
= decodedData
.GetPointer(((decodeSize
+1)&~255) + 256);
393 switch (quadPosition
) {
395 out
[decodeSize
] = (BYTE
)(value
<< 2);
398 out
[decodeSize
++] |= (BYTE
)(value
>> 4);
399 out
[decodeSize
] = (BYTE
)((value
&15) << 4);
402 out
[decodeSize
++] |= (BYTE
)(value
>> 2);
403 out
[decodeSize
] = (BYTE
)((value
&3) << 6);
406 out
[decodeSize
++] |= (BYTE
)value
;
409 quadPosition
= (quadPosition
+1)&3;
415 PBYTEArray
PBase64::GetDecodedData()
417 perfectDecode
= quadPosition
== 0;
418 decodedData
.SetSize(decodeSize
);
419 PBYTEArray retval
= decodedData
;
421 decodedData
.SetSize(0);
427 BOOL
PBase64::GetDecodedData(void * dataBlock
, PINDEX length
)
429 perfectDecode
= quadPosition
== 0;
430 BOOL bigEnough
= length
>= decodeSize
;
431 memcpy(dataBlock
, decodedData
, bigEnough
? decodeSize
: length
);
432 decodedData
.SetSize(0);
438 PString
PBase64::Decode(const PString
& str
)
442 return PString((const char *)(const BYTE
*)data
, data
.GetSize());
446 BOOL
PBase64::Decode(const PString
& str
, PBYTEArray
& data
)
449 decoder
.ProcessDecoding(str
);
450 data
= decoder
.GetDecodedData();
451 return decoder
.IsDecodeOK();
455 BOOL
PBase64::Decode(const PString
& str
, void * dataBlock
, PINDEX length
)
458 decoder
.ProcessDecoding(str
);
459 return decoder
.GetDecodedData(dataBlock
, length
);
463 ///////////////////////////////////////////////////////////////////////////////
466 PMessageDigest::PMessageDigest()
470 void PMessageDigest::Process(const PString
& str
)
472 Process((const char *)str
);
476 void PMessageDigest::Process(const char * cstr
)
478 Process(cstr
, strlen(cstr
));
482 void PMessageDigest::Process(const PBYTEArray
& data
)
484 Process(data
, data
.GetSize());
487 void PMessageDigest::Process(const void * dataBlock
, PINDEX length
)
489 InternalProcess(dataBlock
, length
);
492 PString
PMessageDigest::CompleteDigest()
495 CompleteDigest(result
);
496 return PBase64::Encode(result
.GetPointer(), result
.GetSize());
499 void PMessageDigest::CompleteDigest(Result
& result
)
501 InternalCompleteDigest(result
);
505 ///////////////////////////////////////////////////////////////////////////////
508 PMessageDigest5::PMessageDigest5()
514 // Constants for MD5Transform routine.
532 // F, G, H and I are basic MD5 functions.
533 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
534 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
535 #define H(x, y, z) ((x) ^ (y) ^ (z))
536 #define I(x, y, z) ((y) ^ ((x) | (~z)))
538 // ROTATE_LEFT rotates x left n bits.
539 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
541 // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
542 // Rotation is separate from addition to prevent recomputation.
543 #define FF(a, b, c, d, x, s, ac) \
544 (a) += F ((b), (c), (d)) + (x) + (DWORD)(ac); \
545 (a) = ROTATE_LEFT ((a), (s)); \
548 #define GG(a, b, c, d, x, s, ac) \
549 (a) += G ((b), (c), (d)) + (x) + (DWORD)(ac); \
550 (a) = ROTATE_LEFT ((a), (s)); \
553 #define HH(a, b, c, d, x, s, ac) \
554 (a) += H ((b), (c), (d)) + (x) + (DWORD)(ac); \
555 (a) = ROTATE_LEFT ((a), (s)); \
558 #define II(a, b, c, d, x, s, ac) \
559 (a) += I ((b), (c), (d)) + (x) + (DWORD)(ac); \
560 (a) = ROTATE_LEFT ((a), (s)); \
564 void PMessageDigest5::Transform(const BYTE * block)
572 for (PINDEX i
= 0; i
< 16; i
++)
573 x
[i
] = ((PUInt32l
*)block
)[i
];
576 FF(a
, b
, c
, d
, x
[ 0], S11
, 0xd76aa478); /* 1 */
577 FF(d
, a
, b
, c
, x
[ 1], S12
, 0xe8c7b756); /* 2 */
578 FF(c
, d
, a
, b
, x
[ 2], S13
, 0x242070db); /* 3 */
579 FF(b
, c
, d
, a
, x
[ 3], S14
, 0xc1bdceee); /* 4 */
580 FF(a
, b
, c
, d
, x
[ 4], S11
, 0xf57c0faf); /* 5 */
581 FF(d
, a
, b
, c
, x
[ 5], S12
, 0x4787c62a); /* 6 */
582 FF(c
, d
, a
, b
, x
[ 6], S13
, 0xa8304613); /* 7 */
583 FF(b
, c
, d
, a
, x
[ 7], S14
, 0xfd469501); /* 8 */
584 FF(a
, b
, c
, d
, x
[ 8], S11
, 0x698098d8); /* 9 */
585 FF(d
, a
, b
, c
, x
[ 9], S12
, 0x8b44f7af); /* 10 */
586 FF(c
, d
, a
, b
, x
[10], S13
, 0xffff5bb1); /* 11 */
587 FF(b
, c
, d
, a
, x
[11], S14
, 0x895cd7be); /* 12 */
588 FF(a
, b
, c
, d
, x
[12], S11
, 0x6b901122); /* 13 */
589 FF(d
, a
, b
, c
, x
[13], S12
, 0xfd987193); /* 14 */
590 FF(c
, d
, a
, b
, x
[14], S13
, 0xa679438e); /* 15 */
591 FF(b
, c
, d
, a
, x
[15], S14
, 0x49b40821); /* 16 */
594 GG(a
, b
, c
, d
, x
[ 1], S21
, 0xf61e2562); /* 17 */
595 GG(d
, a
, b
, c
, x
[ 6], S22
, 0xc040b340); /* 18 */
596 GG(c
, d
, a
, b
, x
[11], S23
, 0x265e5a51); /* 19 */
597 GG(b
, c
, d
, a
, x
[ 0], S24
, 0xe9b6c7aa); /* 20 */
598 GG(a
, b
, c
, d
, x
[ 5], S21
, 0xd62f105d); /* 21 */
599 GG(d
, a
, b
, c
, x
[10], S22
, 0x2441453); /* 22 */
600 GG(c
, d
, a
, b
, x
[15], S23
, 0xd8a1e681); /* 23 */
601 GG(b
, c
, d
, a
, x
[ 4], S24
, 0xe7d3fbc8); /* 24 */
602 GG(a
, b
, c
, d
, x
[ 9], S21
, 0x21e1cde6); /* 25 */
603 GG(d
, a
, b
, c
, x
[14], S22
, 0xc33707d6); /* 26 */
604 GG(c
, d
, a
, b
, x
[ 3], S23
, 0xf4d50d87); /* 27 */
605 GG(b
, c
, d
, a
, x
[ 8], S24
, 0x455a14ed); /* 28 */
606 GG(a
, b
, c
, d
, x
[13], S21
, 0xa9e3e905); /* 29 */
607 GG(d
, a
, b
, c
, x
[ 2], S22
, 0xfcefa3f8); /* 30 */
608 GG(c
, d
, a
, b
, x
[ 7], S23
, 0x676f02d9); /* 31 */
609 GG(b
, c
, d
, a
, x
[12], S24
, 0x8d2a4c8a); /* 32 */
612 HH(a
, b
, c
, d
, x
[ 5], S31
, 0xfffa3942); /* 33 */
613 HH(d
, a
, b
, c
, x
[ 8], S32
, 0x8771f681); /* 34 */
614 HH(c
, d
, a
, b
, x
[11], S33
, 0x6d9d6122); /* 35 */
615 HH(b
, c
, d
, a
, x
[14], S34
, 0xfde5380c); /* 36 */
616 HH(a
, b
, c
, d
, x
[ 1], S31
, 0xa4beea44); /* 37 */
617 HH(d
, a
, b
, c
, x
[ 4], S32
, 0x4bdecfa9); /* 38 */
618 HH(c
, d
, a
, b
, x
[ 7], S33
, 0xf6bb4b60); /* 39 */
619 HH(b
, c
, d
, a
, x
[10], S34
, 0xbebfbc70); /* 40 */
620 HH(a
, b
, c
, d
, x
[13], S31
, 0x289b7ec6); /* 41 */
621 HH(d
, a
, b
, c
, x
[ 0], S32
, 0xeaa127fa); /* 42 */
622 HH(c
, d
, a
, b
, x
[ 3], S33
, 0xd4ef3085); /* 43 */
623 HH(b
, c
, d
, a
, x
[ 6], S34
, 0x4881d05); /* 44 */
624 HH(a
, b
, c
, d
, x
[ 9], S31
, 0xd9d4d039); /* 45 */
625 HH(d
, a
, b
, c
, x
[12], S32
, 0xe6db99e5); /* 46 */
626 HH(c
, d
, a
, b
, x
[15], S33
, 0x1fa27cf8); /* 47 */
627 HH(b
, c
, d
, a
, x
[ 2], S34
, 0xc4ac5665); /* 48 */
630 II(a
, b
, c
, d
, x
[ 0], S41
, 0xf4292244); /* 49 */
631 II(d
, a
, b
, c
, x
[ 7], S42
, 0x432aff97); /* 50 */
632 II(c
, d
, a
, b
, x
[14], S43
, 0xab9423a7); /* 51 */
633 II(b
, c
, d
, a
, x
[ 5], S44
, 0xfc93a039); /* 52 */
634 II(a
, b
, c
, d
, x
[12], S41
, 0x655b59c3); /* 53 */
635 II(d
, a
, b
, c
, x
[ 3], S42
, 0x8f0ccc92); /* 54 */
636 II(c
, d
, a
, b
, x
[10], S43
, 0xffeff47d); /* 55 */
637 II(b
, c
, d
, a
, x
[ 1], S44
, 0x85845dd1); /* 56 */
638 II(a
, b
, c
, d
, x
[ 8], S41
, 0x6fa87e4f); /* 57 */
639 II(d
, a
, b
, c
, x
[15], S42
, 0xfe2ce6e0); /* 58 */
640 II(c
, d
, a
, b
, x
[ 6], S43
, 0xa3014314); /* 59 */
641 II(b
, c
, d
, a
, x
[13], S44
, 0x4e0811a1); /* 60 */
642 II(a
, b
, c
, d
, x
[ 4], S41
, 0xf7537e82); /* 61 */
643 II(d
, a
, b
, c
, x
[11], S42
, 0xbd3af235); /* 62 */
644 II(c
, d
, a
, b
, x
[ 2], S43
, 0x2ad7d2bb); /* 63 */
645 II(b
, c
, d
, a
, x
[ 9], S44
, 0xeb86d391); /* 64 */
652 // Zeroize sensitive information.
653 memset(x
, 0, sizeof(x
));
657 void PMessageDigest5::Start()
659 // Load magic initialization constants.
660 state
[0] = 0x67452301;
661 state
[1] = 0xefcdab89;
662 state
[2] = 0x98badcfe;
663 state
[3] = 0x10325476;
668 void PMessageDigest5::InternalProcess(const void * dataPtr
, PINDEX length
)
670 const BYTE
* data
= (const BYTE
*)dataPtr
;
672 // Compute number of bytes mod 64
673 PINDEX index
= (PINDEX
)((count
>> 3) & 0x3F);
674 PINDEX partLen
= 64 - index
;
676 // Update number of bits
677 count
+= (PUInt64
)length
<< 3;
679 // See if have a buffer full
681 if (length
< partLen
)
684 // Transform as many times as possible.
685 memcpy(&buffer
[index
], data
, partLen
);
687 for (i
= partLen
; i
+ 63 < length
; i
+= 64)
692 // Buffer remaining input
693 memcpy(&buffer
[index
], &data
[i
], length
-i
);
697 void PMessageDigest5::InternalCompleteDigest(Result
& result
)
699 // Put the count into bytes platform independently
700 PUInt64l countBytes
= count
;
702 // Pad out to 56 mod 64.
703 PINDEX index
= (PINDEX
)((count
>> 3) & 0x3f);
704 PINDEX padLen
= (index
< 56) ? (56 - index
) : (120 - index
);
705 static BYTE
const padding
[64] = {
706 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
707 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
708 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
710 Process(padding
, padLen
);
713 Process(&countBytes
, sizeof(countBytes
));
715 // Store state in digest
716 PUInt32l
* valuep
= (PUInt32l
*)result
.value
.GetPointer(4 * sizeof(PUInt32l
));
717 for (PINDEX i
= 0; i
< PARRAYSIZE(state
); i
++)
718 valuep
[i
] = state
[i
];
720 // Zeroize sensitive information.
721 memset(buffer
, 0, sizeof(buffer
));
722 memset(state
, 0, sizeof(state
));
726 PString
PMessageDigest5::Encode(const PString
& str
)
728 return Encode((const char *)str
);
732 void PMessageDigest5::Encode(const PString
& str
, Result
& result
)
734 Encode((const char *)str
, result
);
738 PString
PMessageDigest5::Encode(const char * cstr
)
740 return Encode((const BYTE
*)cstr
, strlen(cstr
));
744 void PMessageDigest5::Encode(const char * cstr
, Result
& result
)
746 Encode((const BYTE
*)cstr
, strlen(cstr
), result
);
750 PString
PMessageDigest5::Encode(const PBYTEArray
& data
)
752 return Encode(data
, data
.GetSize());
756 void PMessageDigest5::Encode(const PBYTEArray
& data
, Result
& result
)
758 Encode(data
, data
.GetSize(), result
);
762 PString
PMessageDigest5::Encode(const void * data
, PINDEX length
)
765 Encode(data
, length
, result
);
766 return PBase64::Encode(result
.GetPointer(), result
.GetSize());
770 void PMessageDigest5::Encode(const void * data
, PINDEX len
, Result
& result
)
772 PMessageDigest5 stomach
;
773 stomach
.Process(data
, len
);
774 stomach
.CompleteDigest(result
);
777 //// backwards compatability functions
779 void PMessageDigest5::Encode(const PString
& str
, Code
& result
)
781 Encode((const char *)str
, result
);
784 void PMessageDigest5::Encode(const char * cstr
, Code
& result
)
786 Encode((const BYTE
*)cstr
, strlen(cstr
), result
);
789 void PMessageDigest5::Encode(const PBYTEArray
& data
, Code
& result
)
791 Encode(data
, data
.GetSize(), result
);
794 void PMessageDigest5::Encode(const void * data
, PINDEX len
, Code
& codeResult
)
796 PMessageDigest5 stomach
;
797 stomach
.Process(data
, len
);
798 stomach
.Complete(codeResult
);
801 PString
PMessageDigest5::Complete()
805 return PBase64::Encode(&result
, sizeof(result
));
808 void PMessageDigest5::Complete(Code
& codeResult
)
811 InternalCompleteDigest(result
);
812 memcpy(codeResult
.value
, result
.GetPointer(), sizeof(codeResult
.value
));
815 ///////////////////////////////////////////////////////////////////////////////
816 // PMessageDigestSHA1
820 #include <openssl/sha.h>
824 #pragma comment(lib, P_SSL_LIB1)
825 #pragma comment(lib, P_SSL_LIB2)
830 PMessageDigestSHA1::PMessageDigestSHA1()
836 PMessageDigestSHA1::~PMessageDigestSHA1()
838 delete (SHA_CTX
*)shaContext
;
841 void PMessageDigestSHA1::Start()
843 delete (SHA_CTX
*)shaContext
;
844 shaContext
= new SHA_CTX
;
846 SHA1_Init((SHA_CTX
*)shaContext
);
849 void PMessageDigestSHA1::InternalProcess(const void * data
, PINDEX len
)
851 if (shaContext
== NULL
)
854 SHA1_Update((SHA_CTX
*)shaContext
, data
, (unsigned long)len
);
857 void PMessageDigestSHA1::InternalCompleteDigest(Result
& result
)
859 if (shaContext
== NULL
)
862 SHA1_Final(result
.value
.GetPointer(20), (SHA_CTX
*)shaContext
);
863 delete ((SHA_CTX
*)shaContext
);
868 PString
PMessageDigestSHA1::Encode(const PString
& str
)
870 return Encode((const char *)str
);
874 void PMessageDigestSHA1::Encode(const PString
& str
, Result
& result
)
876 Encode((const char *)str
, result
);
880 PString
PMessageDigestSHA1::Encode(const char * cstr
)
882 return Encode((const BYTE
*)cstr
, strlen(cstr
));
886 void PMessageDigestSHA1::Encode(const char * cstr
, Result
& result
)
888 Encode((const BYTE
*)cstr
, strlen(cstr
), result
);
892 PString
PMessageDigestSHA1::Encode(const PBYTEArray
& data
)
894 return Encode(data
, data
.GetSize());
898 void PMessageDigestSHA1::Encode(const PBYTEArray
& data
, Result
& result
)
900 Encode(data
, data
.GetSize(), result
);
904 PString
PMessageDigestSHA1::Encode(const void * data
, PINDEX length
)
907 Encode(data
, length
, result
);
908 return PBase64::Encode(result
.GetPointer(), result
.GetSize());
912 void PMessageDigestSHA1::Encode(const void * data
, PINDEX len
, Result
& result
)
914 PMessageDigestSHA1 stomach
;
915 stomach
.Process(data
, len
);
916 stomach
.CompleteDigest(result
);
921 ///////////////////////////////////////////////////////////////////////////////
924 PCypher::PCypher(PINDEX blkSize
, BlockChainMode mode
)
925 : blockSize(blkSize
),
931 PCypher::PCypher(const void * keyData
, PINDEX keyLength
,
932 PINDEX blkSize
, BlockChainMode mode
)
933 : key((const BYTE
*)keyData
, keyLength
),
940 PString
PCypher::Encode(const PString
& str
)
942 return Encode((const char *)str
, str
.GetLength());
946 PString
PCypher::Encode(const PBYTEArray
& clear
)
948 return Encode((const BYTE
*)clear
, clear
.GetSize());
952 PString
PCypher::Encode(const void * data
, PINDEX length
)
955 Encode(data
, length
, coded
);
956 return PBase64::Encode(coded
);
960 void PCypher::Encode(const PBYTEArray
& clear
, PBYTEArray
& coded
)
962 Encode((const BYTE
*)clear
, clear
.GetSize(), coded
);
966 void PCypher::Encode(const void * data
, PINDEX length
, PBYTEArray
& coded
)
968 PAssert((blockSize
%8) == 0, PUnsupportedFeature
);
972 const BYTE
* in
= (const BYTE
*)data
;
973 BYTE
* out
= coded
.GetPointer(
974 blockSize
> 1 ? (length
/blockSize
+1)*blockSize
: length
);
976 while (length
>= blockSize
) {
977 EncodeBlock(in
, out
);
984 PBYTEArray
extra(blockSize
);
986 for (i
= 0; i
< length
; i
++)
989 PRandom
rand((DWORD
)now
.GetTimestamp());
990 for (; i
< blockSize
-1; i
++)
991 extra
[i
] = (BYTE
)rand
.Generate();
992 extra
[blockSize
-1] = (BYTE
)length
;
993 EncodeBlock(extra
, out
);
998 PString
PCypher::Decode(const PString
& cypher
)
1001 if (Decode(cypher
, clear
))
1007 BOOL
PCypher::Decode(const PString
& cypher
, PString
& clear
)
1011 PBYTEArray clearText
;
1012 if (!Decode(cypher
, clearText
))
1015 if (clearText
.IsEmpty())
1018 PINDEX sz
= clearText
.GetSize();
1019 memcpy(clear
.GetPointer(sz
+1), (const BYTE
*)clearText
, sz
);
1024 BOOL
PCypher::Decode(const PString
& cypher
, PBYTEArray
& clear
)
1027 if (!PBase64::Decode(cypher
, coded
))
1029 return Decode(coded
, clear
);
1033 PINDEX
PCypher::Decode(const PString
& cypher
, void * data
, PINDEX length
)
1036 PBase64::Decode(cypher
, coded
);
1038 if (!Decode(coded
, clear
))
1040 memcpy(data
, clear
, PMIN(length
, clear
.GetSize()));
1041 return clear
.GetSize();
1045 PINDEX
PCypher::Decode(const PBYTEArray
& coded
, void * data
, PINDEX length
)
1048 if (!Decode(coded
, clear
))
1050 memcpy(data
, clear
, PMIN(length
, clear
.GetSize()));
1051 return clear
.GetSize();
1055 BOOL
PCypher::Decode(const PBYTEArray
& coded
, PBYTEArray
& clear
)
1057 PAssert((blockSize
%8) == 0, PUnsupportedFeature
);
1058 if (coded
.IsEmpty() || (coded
.GetSize()%blockSize
) != 0)
1063 const BYTE
* in
= coded
;
1064 PINDEX length
= coded
.GetSize();
1065 BYTE
* out
= clear
.GetPointer(length
);
1067 for (PINDEX count
= 0; count
< length
; count
+= blockSize
) {
1068 DecodeBlock(in
, out
);
1073 if (blockSize
!= 1) {
1074 if (*--out
>= blockSize
)
1076 clear
.SetSize(length
- blockSize
+ *out
);
1084 ///////////////////////////////////////////////////////////////////////////////
1087 PTEACypher::PTEACypher(BlockChainMode chainMode
)
1088 : PCypher(8, chainMode
)
1090 GenerateKey(*(Key
*)key
.GetPointer(sizeof(Key
)));
1094 PTEACypher::PTEACypher(const Key
& keyData
, BlockChainMode chainMode
)
1095 : PCypher(&keyData
, sizeof(Key
), 8, chainMode
)
1100 void PTEACypher::SetKey(const Key
& newKey
)
1102 memcpy(key
.GetPointer(sizeof(Key
)), &newKey
, sizeof(Key
));
1106 void PTEACypher::GetKey(Key
& newKey
) const
1108 memcpy(&newKey
, key
, sizeof(Key
));
1112 void PTEACypher::GenerateKey(Key
& newKey
)
1114 static PRandom rand
; //=1 // Explicitly set seed if need known random sequence
1115 for (size_t i
= 0; i
< sizeof(Key
); i
++)
1116 newKey
.value
[i
] = (BYTE
)rand
;
1120 static const DWORD TEADelta
= 0x9e3779b9; // Magic number for key schedule
1122 void PTEACypher::Initialise(BOOL
)
1124 k0
= ((const PUInt32l
*)(const BYTE
*)key
)[0];
1125 k1
= ((const PUInt32l
*)(const BYTE
*)key
)[1];
1126 k2
= ((const PUInt32l
*)(const BYTE
*)key
)[2];
1127 k3
= ((const PUInt32l
*)(const BYTE
*)key
)[3];
1131 void PTEACypher::EncodeBlock(const void * in
, void * out
)
1133 DWORD y
= ((PUInt32b
*)in
)[0];
1134 DWORD z
= ((PUInt32b
*)in
)[1];
1136 for (PINDEX count
= 32; count
> 0; count
--) {
1137 sum
+= TEADelta
; // Magic number for key schedule
1138 y
+= (z
<<4)+k0
^ z
+sum
^ (z
>>5)+k1
;
1139 z
+= (y
<<4)+k2
^ y
+sum
^ (y
>>5)+k3
; /* end cycle */
1141 ((PUInt32b
*)out
)[0] = y
;
1142 ((PUInt32b
*)out
)[1] = z
;
1146 void PTEACypher::DecodeBlock(const void * in
, void * out
)
1148 DWORD y
= ((PUInt32b
*)in
)[0];
1149 DWORD z
= ((PUInt32b
*)in
)[1];
1150 DWORD sum
= TEADelta
<<5;
1151 for (PINDEX count
= 32; count
> 0; count
--) {
1152 z
-= (y
<<4)+k2
^ y
+sum
^ (y
>>5)+k3
;
1153 y
-= (z
<<4)+k0
^ z
+sum
^ (z
>>5)+k1
;
1154 sum
-= TEADelta
; // Magic number for key schedule
1156 ((PUInt32b
*)out
)[0] = y
;
1157 ((PUInt32b
*)out
)[1] = z
;
1161 ///////////////////////////////////////////////////////////////////////////////
1164 static const char DefaultSecuredOptions
[] = "Secured Options";
1165 static const char DefaultSecurityKey
[] = "Validation";
1166 static const char DefaultExpiryDateKey
[] = "Expiry Date";
1167 static const char DefaultOptionBitsKey
[] = "Option Bits";
1168 static const char DefaultPendingPrefix
[] = "Pending:";
1170 PSecureConfig::PSecureConfig(const PTEACypher::Key
& prodKey
,
1171 const PStringArray
& secKeys
,
1173 : PConfig(PString(DefaultSecuredOptions
), src
),
1174 securedKeys(secKeys
),
1175 securityKey(DefaultSecurityKey
),
1176 expiryDateKey(DefaultExpiryDateKey
),
1177 optionBitsKey(DefaultOptionBitsKey
),
1178 pendingPrefix(DefaultPendingPrefix
)
1180 productKey
= prodKey
;
1184 PSecureConfig::PSecureConfig(const PTEACypher::Key
& prodKey
,
1185 const char * const * secKeys
,
1188 : PConfig(PString(DefaultSecuredOptions
), src
),
1189 securedKeys(count
, secKeys
),
1190 securityKey(DefaultSecurityKey
),
1191 expiryDateKey(DefaultExpiryDateKey
),
1192 optionBitsKey(DefaultOptionBitsKey
),
1193 pendingPrefix(DefaultPendingPrefix
)
1195 productKey
= prodKey
;
1199 void PSecureConfig::GetProductKey(PTEACypher::Key
& prodKey
) const
1201 prodKey
= productKey
;
1205 PSecureConfig::ValidationState
PSecureConfig::GetValidation() const
1208 BOOL allEmpty
= TRUE
;
1209 PMessageDigest5 digestor
;
1210 for (PINDEX i
= 0; i
< securedKeys
.GetSize(); i
++) {
1211 str
= GetString(securedKeys
[i
]);
1212 if (!str
.IsEmpty()) {
1213 digestor
.Process(str
.Trim());
1217 str
= GetString(expiryDateKey
);
1218 if (!str
.IsEmpty()) {
1219 digestor
.Process(str
);
1222 str
= GetString(optionBitsKey
);
1223 if (!str
.IsEmpty()) {
1224 digestor
.Process(str
);
1228 PString vkey
= GetString(securityKey
);
1230 return (!vkey
|| GetBoolean(pendingPrefix
+ securityKey
)) ? Pending
: Defaults
;
1232 PMessageDigest5::Code code
;
1233 digestor
.Complete(code
);
1238 BYTE info
[sizeof(code
)+1+sizeof(DWORD
)];
1239 PTEACypher
crypt(productKey
);
1240 if (crypt
.Decode(vkey
, info
, sizeof(info
)) != sizeof(info
))
1243 if (memcmp(info
, &code
, sizeof(code
)) != 0)
1247 if (now
> GetTime(expiryDateKey
))
1254 BOOL
PSecureConfig::ValidatePending()
1256 if (GetValidation() != Pending
)
1259 PString vkey
= GetString(securityKey
);
1263 PMessageDigest5::Code code
;
1264 BYTE info
[sizeof(code
)+1+sizeof(DWORD
)];
1265 PTEACypher
crypt(productKey
);
1266 if (crypt
.Decode(vkey
, info
, sizeof(info
)) != sizeof(info
))
1269 PTime
expiryDate(0, 0, 0,
1270 1, info
[sizeof(code
)]&15, (info
[sizeof(code
)]>>4)+1996, PTime::GMT
);
1271 PString expiry
= expiryDate
.AsString("d MMME yyyy", PTime::GMT
);
1273 // This is for alignment problems on processors that care about such things
1276 void * src
= &info
[sizeof(code
)+1];
1277 memcpy(dst
, src
, sizeof(opt
));
1278 PString
options(PString::Unsigned
, (DWORD
)opt
);
1280 PMessageDigest5 digestor
;
1282 for (i
= 0; i
< securedKeys
.GetSize(); i
++)
1283 digestor
.Process(GetString(pendingPrefix
+ securedKeys
[i
]).Trim());
1284 digestor
.Process(expiry
);
1285 digestor
.Process(options
);
1286 digestor
.Complete(code
);
1288 if (memcmp(info
, &code
, sizeof(code
)) != 0)
1291 SetString(expiryDateKey
, expiry
);
1292 SetString(optionBitsKey
, options
);
1294 for (i
= 0; i
< securedKeys
.GetSize(); i
++) {
1295 PString str
= GetString(pendingPrefix
+ securedKeys
[i
]);
1297 SetString(securedKeys
[i
], str
);
1298 DeleteKey(pendingPrefix
+ securedKeys
[i
]);
1300 DeleteKey(pendingPrefix
+ securityKey
);
1306 void PSecureConfig::ResetPending()
1308 if (GetBoolean(pendingPrefix
+ securityKey
)) {
1309 for (PINDEX i
= 0; i
< securedKeys
.GetSize(); i
++)
1310 DeleteKey(securedKeys
[i
]);
1313 SetBoolean(pendingPrefix
+ securityKey
, TRUE
);
1315 for (PINDEX i
= 0; i
< securedKeys
.GetSize(); i
++) {
1316 PString str
= GetString(securedKeys
[i
]);
1318 SetString(pendingPrefix
+ securedKeys
[i
], str
);
1319 DeleteKey(securedKeys
[i
]);
1322 DeleteKey(expiryDateKey
);
1323 DeleteKey(optionBitsKey
);
1326 ///////////////////////////////////////////////////////////////////////////////