Added IsSupportingRTP function to simplify detecting when STUN supports RTP
[pwlib.git] / src / ptclib / cypher.cxx
blobe92551dfc9800c111c82fb96818c6daf6a51ff44
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.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
35 * you cannot do this.
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
72 * Added SHA-1 digest
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
78 * Changes for gcc 3.1
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
103 * GNU support.
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
118 * ??
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
172 * Initial revision
176 #ifdef __GNUC__
177 #pragma implementation "cypher.h"
178 #endif
180 #define P_DISABLE_FACTORY_INSTANCES
182 #include <ptlib.h>
183 #include <ptclib/cypher.h>
184 #include <ptclib/mime.h>
185 #include <ptclib/random.h>
189 ///////////////////////////////////////////////////////////////////////////////
190 // PBase64
192 PBase64::PBase64()
194 StartEncoding();
195 StartDecoding();
199 void PBase64::StartEncoding(BOOL useCRLF)
201 encodedString = "";
202 encodeLength = nextLine = saveCount = 0;
203 useCRLFs = useCRLF;
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
238 if (useCRLFs)
239 out[encodeLength++] = '\r';
240 out[encodeLength++] = '\n';
241 nextLine = 0;
246 void PBase64::ProcessEncoding(const void * dataPtr, PINDEX length)
248 if (length == 0)
249 return;
251 const BYTE * data = (const BYTE *)dataPtr;
252 while (saveCount < 3) {
253 saveTriple[saveCount++] = *data++;
254 if (--length == 0)
255 return;
258 OutputBase64(saveTriple);
260 PINDEX i;
261 for (i = 0; i+2 < length; i += 3)
262 OutputBase64(data+i);
264 saveCount = length - i;
265 switch (saveCount) {
266 case 2 :
267 saveTriple[0] = data[i++];
268 saveTriple[1] = data[i];
269 break;
270 case 1 :
271 saveTriple[0] = data[i];
276 PString PBase64::GetEncodedString()
278 PString retval = encodedString;
279 encodedString = "";
280 encodeLength = 0;
281 return retval;
285 PString PBase64::CompleteEncoding()
287 char * out = encodedString.GetPointer(encodeLength + 5)+encodeLength;
289 switch (saveCount) {
290 case 1 :
291 *out++ = Binary2Base64[saveTriple[0] >> 2];
292 *out++ = Binary2Base64[(saveTriple[0]&3)<<4];
293 *out++ = '=';
294 *out = '=';
295 break;
297 case 2 :
298 *out++ = Binary2Base64[saveTriple[0] >> 2];
299 *out++ = Binary2Base64[((saveTriple[0]&3)<<4) | (saveTriple[1]>>4)];
300 *out++ = Binary2Base64[((saveTriple[1]&15)<<2)];
301 *out = '=';
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)
328 PBase64 encoder;
329 encoder.ProcessEncoding(data, length);
330 return encoder.CompleteEncoding();
334 void PBase64::StartDecoding()
336 perfectDecode = TRUE;
337 quadPosition = 0;
338 decodedData.SetSize(0);
339 decodeSize = 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
370 for (;;) {
371 BYTE value = Base642Binary[(BYTE)*cstr++];
372 switch (value) {
373 case 96 : // end of string
374 return FALSE;
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
382 break;
384 case 98 : // CRLFs
385 break; // Ignore totally
387 case 99 : // Illegal characters
388 perfectDecode = FALSE; // Ignore rubbish but flag decode as suspect
389 break;
391 default : // legal value from 0 to 63
392 BYTE * out = decodedData.GetPointer(((decodeSize+1)&~255) + 256);
393 switch (quadPosition) {
394 case 0 :
395 out[decodeSize] = (BYTE)(value << 2);
396 break;
397 case 1 :
398 out[decodeSize++] |= (BYTE)(value >> 4);
399 out[decodeSize] = (BYTE)((value&15) << 4);
400 break;
401 case 2 :
402 out[decodeSize++] |= (BYTE)(value >> 2);
403 out[decodeSize] = (BYTE)((value&3) << 6);
404 break;
405 case 3 :
406 out[decodeSize++] |= (BYTE)value;
407 break;
409 quadPosition = (quadPosition+1)&3;
415 PBYTEArray PBase64::GetDecodedData()
417 perfectDecode = quadPosition == 0;
418 decodedData.SetSize(decodeSize);
419 PBYTEArray retval = decodedData;
420 retval.MakeUnique();
421 decodedData.SetSize(0);
422 decodeSize = 0;
423 return retval;
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);
433 decodeSize = 0;
434 return bigEnough;
438 PString PBase64::Decode(const PString & str)
440 PBYTEArray data;
441 Decode(str, data);
442 return PString((const char *)(const BYTE *)data, data.GetSize());
446 BOOL PBase64::Decode(const PString & str, PBYTEArray & data)
448 PBase64 decoder;
449 decoder.ProcessDecoding(str);
450 data = decoder.GetDecodedData();
451 return decoder.IsDecodeOK();
455 BOOL PBase64::Decode(const PString & str, void * dataBlock, PINDEX length)
457 PBase64 decoder;
458 decoder.ProcessDecoding(str);
459 return decoder.GetDecodedData(dataBlock, length);
463 ///////////////////////////////////////////////////////////////////////////////
464 // PMessageDigest
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()
494 Result result;
495 CompleteDigest(result);
496 return PBase64::Encode(result.GetPointer(), result.GetSize());
499 void PMessageDigest::CompleteDigest(Result & result)
501 InternalCompleteDigest(result);
505 ///////////////////////////////////////////////////////////////////////////////
506 // PMessageDigest5
508 PMessageDigest5::PMessageDigest5()
510 Start();
514 // Constants for MD5Transform routine.
515 #define S11 7
516 #define S12 12
517 #define S13 17
518 #define S14 22
519 #define S21 5
520 #define S22 9
521 #define S23 14
522 #define S24 20
523 #define S31 4
524 #define S32 11
525 #define S33 16
526 #define S34 23
527 #define S41 6
528 #define S42 10
529 #define S43 15
530 #define S44 21
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)); \
546 (a) += (b); \
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)); \
551 (a) += (b); \
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)); \
556 (a) += (b); \
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)); \
561 (a) += (b); \
564 void PMessageDigest5::Transform(const BYTE * block)
566 DWORD a = state[0];
567 DWORD b = state[1];
568 DWORD c = state[2];
569 DWORD d = state[3];
571 DWORD x[16];
572 for (PINDEX i = 0; i < 16; i++)
573 x[i] = ((PUInt32l*)block)[i];
575 /* Round 1 */
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 */
593 /* Round 2 */
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 */
611 /* Round 3 */
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 */
629 /* Round 4 */
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 */
647 state[0] += a;
648 state[1] += b;
649 state[2] += c;
650 state[3] += d;
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;
665 count = 0;
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
680 PINDEX i;
681 if (length < partLen)
682 i = 0;
683 else {
684 // Transform as many times as possible.
685 memcpy(&buffer[index], data, partLen);
686 Transform(buffer);
687 for (i = partLen; i + 63 < length; i += 64)
688 Transform(&data[i]);
689 index = 0;
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);
712 // Append length
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)
764 Result result;
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()
803 Code result;
804 Complete(result);
805 return PBase64::Encode(&result, sizeof(result));
808 void PMessageDigest5::Complete(Code & codeResult)
810 Result result;
811 InternalCompleteDigest(result);
812 memcpy(codeResult.value, result.GetPointer(), sizeof(codeResult.value));
815 ///////////////////////////////////////////////////////////////////////////////
816 // PMessageDigestSHA1
818 #if P_SSL
820 #include <openssl/sha.h>
822 #ifdef _MSC_VER
824 #pragma comment(lib, P_SSL_LIB1)
825 #pragma comment(lib, P_SSL_LIB2)
827 #endif
830 PMessageDigestSHA1::PMessageDigestSHA1()
832 shaContext = NULL;
833 Start();
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)
852 return;
854 SHA1_Update((SHA_CTX *)shaContext, data, (unsigned long)len);
857 void PMessageDigestSHA1::InternalCompleteDigest(Result & result)
859 if (shaContext == NULL)
860 return;
862 SHA1_Final(result.value.GetPointer(20), (SHA_CTX *)shaContext);
863 delete ((SHA_CTX *)shaContext);
864 shaContext = NULL;
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)
906 Result result;
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);
919 #endif
921 ///////////////////////////////////////////////////////////////////////////////
922 // PCypher
924 PCypher::PCypher(PINDEX blkSize, BlockChainMode mode)
925 : blockSize(blkSize),
926 chainMode(mode)
931 PCypher::PCypher(const void * keyData, PINDEX keyLength,
932 PINDEX blkSize, BlockChainMode mode)
933 : key((const BYTE *)keyData, keyLength),
934 blockSize(blkSize),
935 chainMode(mode)
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)
954 PBYTEArray coded;
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);
970 Initialise(TRUE);
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);
978 in += blockSize;
979 out += blockSize;
980 length -= blockSize;
983 if (blockSize > 1) {
984 PBYTEArray extra(blockSize);
985 PINDEX i;
986 for (i = 0; i < length; i++)
987 extra[i] = *in++;
988 PTime now;
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)
1000 PString clear;
1001 if (Decode(cypher, clear))
1002 return clear;
1003 return PString();
1007 BOOL PCypher::Decode(const PString & cypher, PString & clear)
1009 clear = PString();
1011 PBYTEArray clearText;
1012 if (!Decode(cypher, clearText))
1013 return FALSE;
1015 if (clearText.IsEmpty())
1016 return TRUE;
1018 PINDEX sz = clearText.GetSize();
1019 memcpy(clear.GetPointer(sz+1), (const BYTE *)clearText, sz);
1020 return TRUE;
1024 BOOL PCypher::Decode(const PString & cypher, PBYTEArray & clear)
1026 PBYTEArray coded;
1027 if (!PBase64::Decode(cypher, coded))
1028 return FALSE;
1029 return Decode(coded, clear);
1033 PINDEX PCypher::Decode(const PString & cypher, void * data, PINDEX length)
1035 PBYTEArray coded;
1036 PBase64::Decode(cypher, coded);
1037 PBYTEArray clear;
1038 if (!Decode(coded, clear))
1039 return 0;
1040 memcpy(data, clear, PMIN(length, clear.GetSize()));
1041 return clear.GetSize();
1045 PINDEX PCypher::Decode(const PBYTEArray & coded, void * data, PINDEX length)
1047 PBYTEArray clear;
1048 if (!Decode(coded, clear))
1049 return 0;
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)
1059 return FALSE;
1061 Initialise(FALSE);
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);
1069 in += blockSize;
1070 out += blockSize;
1073 if (blockSize != 1) {
1074 if (*--out >= blockSize)
1075 return FALSE;
1076 clear.SetSize(length - blockSize + *out);
1079 return TRUE;
1084 ///////////////////////////////////////////////////////////////////////////////
1085 // PTEACypher
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];
1135 DWORD sum = 0;
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 ///////////////////////////////////////////////////////////////////////////////
1162 // PSecureConfig
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,
1172 Source src)
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,
1186 PINDEX count,
1187 Source src)
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
1207 PString str;
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());
1214 allEmpty = FALSE;
1217 str = GetString(expiryDateKey);
1218 if (!str.IsEmpty()) {
1219 digestor.Process(str);
1220 allEmpty = FALSE;
1222 str = GetString(optionBitsKey);
1223 if (!str.IsEmpty()) {
1224 digestor.Process(str);
1225 allEmpty = FALSE;
1228 PString vkey = GetString(securityKey);
1229 if (allEmpty)
1230 return (!vkey || GetBoolean(pendingPrefix + securityKey)) ? Pending : Defaults;
1232 PMessageDigest5::Code code;
1233 digestor.Complete(code);
1235 if (vkey.IsEmpty())
1236 return Invalid;
1238 BYTE info[sizeof(code)+1+sizeof(DWORD)];
1239 PTEACypher crypt(productKey);
1240 if (crypt.Decode(vkey, info, sizeof(info)) != sizeof(info))
1241 return Invalid;
1243 if (memcmp(info, &code, sizeof(code)) != 0)
1244 return Invalid;
1246 PTime now;
1247 if (now > GetTime(expiryDateKey))
1248 return Expired;
1250 return IsValid;
1254 BOOL PSecureConfig::ValidatePending()
1256 if (GetValidation() != Pending)
1257 return FALSE;
1259 PString vkey = GetString(securityKey);
1260 if (vkey.IsEmpty())
1261 return TRUE;
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))
1267 return FALSE;
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
1274 PUInt32b opt;
1275 void * dst = &opt;
1276 void * src = &info[sizeof(code)+1];
1277 memcpy(dst, src, sizeof(opt));
1278 PString options(PString::Unsigned, (DWORD)opt);
1280 PMessageDigest5 digestor;
1281 PINDEX i;
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)
1289 return FALSE;
1291 SetString(expiryDateKey, expiry);
1292 SetString(optionBitsKey, options);
1294 for (i = 0; i < securedKeys.GetSize(); i++) {
1295 PString str = GetString(pendingPrefix + securedKeys[i]);
1296 if (!str.IsEmpty())
1297 SetString(securedKeys[i], str);
1298 DeleteKey(pendingPrefix + securedKeys[i]);
1300 DeleteKey(pendingPrefix + securityKey);
1302 return TRUE;
1306 void PSecureConfig::ResetPending()
1308 if (GetBoolean(pendingPrefix + securityKey)) {
1309 for (PINDEX i = 0; i < securedKeys.GetSize(); i++)
1310 DeleteKey(securedKeys[i]);
1312 else {
1313 SetBoolean(pendingPrefix + securityKey, TRUE);
1315 for (PINDEX i = 0; i < securedKeys.GetSize(); i++) {
1316 PString str = GetString(securedKeys[i]);
1317 if (!str.IsEmpty())
1318 SetString(pendingPrefix + securedKeys[i], str);
1319 DeleteKey(securedKeys[i]);
1322 DeleteKey(expiryDateKey);
1323 DeleteKey(optionBitsKey);
1326 ///////////////////////////////////////////////////////////////////////////////