Added a parameter to semaphore constructor to avoid ambiguity
[pwlib.git] / src / ptclib / cypher.cxx
blobd385fd4973e883e4945015640a60e577b2ed9479
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.38 2003/04/27 23:52:57 craigs
28 * Fixed problem with SHA1 not calling Start
30 * Revision 1.37 2003/04/17 12:12:59 robertj
31 * Added windows library inclusion for optional openssl.
33 * Revision 1.36 2003/04/17 07:34:46 robertj
34 * Fixed correct test for P_SSL
36 * Revision 1.35 2003/04/17 01:21:55 craigs
37 * Fixed problem with delete'ing a void *
39 * Revision 1.33 2003/04/10 07:14:27 craigs
40 * Fixed link problem in MD5 class
42 * Revision 1.32 2003/04/10 06:16:09 craigs
43 * Added SHA-1 digest
45 * Revision 1.31 2002/11/06 22:47:24 robertj
46 * Fixed header comment (copyright etc)
48 * Revision 1.30 2002/06/05 12:29:15 craigs
49 * Changes for gcc 3.1
51 * Revision 1.29 2001/03/01 03:55:59 robertj
52 * Fixed MSVC warnings.
54 * Revision 1.28 2001/02/28 21:10:47 craigs
55 * Fixed problem in Decode function
56 * Added randomizer to fill data in Decode
58 * Revision 1.27 2000/02/17 12:05:02 robertj
59 * Added better random number generator after finding major flaws in MSVCRT version.
61 * Revision 1.26 1998/11/30 04:50:45 robertj
62 * New directory structure
64 * Revision 1.25 1998/09/23 06:21:56 robertj
65 * Added open source copyright license.
67 * Revision 1.24 1998/07/24 06:58:13 robertj
68 * Improved robustness of encrypted data decoding, error on illegal tail block size.
70 * Revision 1.23 1998/02/16 00:14:36 robertj
71 * Fixed ability to register in one stage instead of always having to use 2.
73 * Revision 1.22 1998/01/26 02:49:14 robertj
74 * GNU support.
76 * Revision 1.21 1997/10/30 10:19:19 robertj
77 * Fixed bug with having empty string in encrypted text.
79 * Revision 1.20 1997/10/10 10:43:41 robertj
80 * Fixed bug in password encryption, missing string terminator.
82 * Revision 1.19 1997/08/04 10:39:53 robertj
83 * Fixed bug for decoding empty string.
85 * Revision 1.18 1997/07/26 11:35:38 robertj
86 * Fixed bug where illegal data errors were not propagated.
88 * Revision 1.17 1996/11/16 10:50:26 robertj
89 * ??
91 * Revision 1.16 1996/08/17 09:56:02 robertj
92 * Fixed big endian processor platform conformance.
94 * Revision 1.15 1996/07/15 10:33:42 robertj
95 * Changed memory block base64 conversion functions to be void *.
96 * Changed memory block cypher conversion functions to be void *.
97 * Changed endian classes to be memory mapped.
99 * Revision 1.14 1996/06/18 12:35:49 robertj
100 * Fixed bug in registration when language is not English.
102 * Revision 1.13 1996/06/10 10:01:23 robertj
103 * Fixed bug in getting cypher key, not copying all the bytes.
105 * Revision 1.12 1996/05/26 03:46:31 robertj
106 * Compatibility to GNU 2.7.x
108 * Revision 1.11 1996/04/09 03:32:45 robertj
109 * Fixed bug in registration so now works in time zones other than Eastern Australia.
111 * Revision 1.11 1996/04/08 05:18:38 robertj
112 * Fixed bug in registering programs in a different time zone.
114 * Revision 1.10 1996/03/17 05:47:19 robertj
115 * Changed secured config to allow for expiry dates.
117 * Revision 1.9 1996/03/16 04:37:20 robertj
118 * Redesign of secure config to accommodate expiry dates and option values passed in security key code.
120 * Revision 1.8 1996/03/11 10:28:53 robertj
121 * Fixed bug in C++ optimising compiler.
123 * Revision 1.7 1996/03/02 03:20:52 robertj
124 * Fixed secured config parameters so leading/trailing blanks not significant.
126 * Revision 1.6 1996/02/25 11:22:42 robertj
127 * Added assertion if try and SetValidation when not pending.
129 * Revision 1.5 1996/02/25 02:53:05 robertj
130 * Further secure config development.
132 * Revision 1.4 1996/02/15 14:43:28 robertj
133 * Allowed no secured config data at all to be "valid". All vars will then be guarenteed to default.
135 * Revision 1.3 1996/01/28 14:14:12 robertj
136 * Further implementation of secure config.
138 * Revision 1.2 1996/01/28 02:49:00 robertj
139 * Removal of MemoryPointer classes as usage didn't work for GNU.
140 * Added the secure configuration mechanism for protecting applications.
142 * Revision 1.1 1996/01/23 13:05:58 robertj
143 * Initial revision
147 #ifdef __GNUC__
148 #pragma implementation "cypher.h"
149 #endif
151 #include <ptlib.h>
152 #include <ptclib/cypher.h>
153 #include <ptclib/mime.h>
154 #include <ptclib/random.h>
158 ///////////////////////////////////////////////////////////////////////////////
159 // PMessageDigest
161 PMessageDigest::PMessageDigest()
165 void PMessageDigest::Process(const PString & str)
167 Process((const char *)str);
171 void PMessageDigest::Process(const char * cstr)
173 Process(cstr, strlen(cstr));
177 void PMessageDigest::Process(const PBYTEArray & data)
179 Process(data, data.GetSize());
182 void PMessageDigest::Process(const void * dataBlock, PINDEX length)
184 InternalProcess(dataBlock, length);
187 PString PMessageDigest::CompleteDigest()
189 Result result;
190 CompleteDigest(result);
191 return PBase64::Encode(&result, sizeof(result));
194 void PMessageDigest::CompleteDigest(Result & result)
196 InternalCompleteDigest(result);
200 ///////////////////////////////////////////////////////////////////////////////
201 // PMessageDigest5
203 PMessageDigest5::PMessageDigest5()
205 Start();
209 // Constants for MD5Transform routine.
210 #define S11 7
211 #define S12 12
212 #define S13 17
213 #define S14 22
214 #define S21 5
215 #define S22 9
216 #define S23 14
217 #define S24 20
218 #define S31 4
219 #define S32 11
220 #define S33 16
221 #define S34 23
222 #define S41 6
223 #define S42 10
224 #define S43 15
225 #define S44 21
227 // F, G, H and I are basic MD5 functions.
228 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
229 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
230 #define H(x, y, z) ((x) ^ (y) ^ (z))
231 #define I(x, y, z) ((y) ^ ((x) | (~z)))
233 // ROTATE_LEFT rotates x left n bits.
234 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
236 // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
237 // Rotation is separate from addition to prevent recomputation.
238 #define FF(a, b, c, d, x, s, ac) \
239 (a) += F ((b), (c), (d)) + (x) + (DWORD)(ac); \
240 (a) = ROTATE_LEFT ((a), (s)); \
241 (a) += (b); \
243 #define GG(a, b, c, d, x, s, ac) \
244 (a) += G ((b), (c), (d)) + (x) + (DWORD)(ac); \
245 (a) = ROTATE_LEFT ((a), (s)); \
246 (a) += (b); \
248 #define HH(a, b, c, d, x, s, ac) \
249 (a) += H ((b), (c), (d)) + (x) + (DWORD)(ac); \
250 (a) = ROTATE_LEFT ((a), (s)); \
251 (a) += (b); \
253 #define II(a, b, c, d, x, s, ac) \
254 (a) += I ((b), (c), (d)) + (x) + (DWORD)(ac); \
255 (a) = ROTATE_LEFT ((a), (s)); \
256 (a) += (b); \
259 void PMessageDigest5::Transform(const BYTE * block)
261 DWORD a = state[0];
262 DWORD b = state[1];
263 DWORD c = state[2];
264 DWORD d = state[3];
266 DWORD x[16];
267 for (PINDEX i = 0; i < 16; i++)
268 x[i] = ((PUInt32l*)block)[i];
270 /* Round 1 */
271 FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
272 FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
273 FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
274 FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
275 FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
276 FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
277 FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
278 FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
279 FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
280 FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
281 FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
282 FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
283 FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
284 FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
285 FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
286 FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
288 /* Round 2 */
289 GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
290 GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
291 GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
292 GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
293 GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
294 GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
295 GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
296 GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
297 GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
298 GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
299 GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
300 GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
301 GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
302 GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
303 GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
304 GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
306 /* Round 3 */
307 HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
308 HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
309 HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
310 HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
311 HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
312 HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
313 HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
314 HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
315 HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
316 HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
317 HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
318 HH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
319 HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
320 HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
321 HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
322 HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
324 /* Round 4 */
325 II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
326 II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
327 II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
328 II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
329 II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
330 II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
331 II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
332 II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
333 II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
334 II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
335 II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
336 II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
337 II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
338 II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
339 II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
340 II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
342 state[0] += a;
343 state[1] += b;
344 state[2] += c;
345 state[3] += d;
347 // Zeroize sensitive information.
348 memset(x, 0, sizeof(x));
352 void PMessageDigest5::Start()
354 // Load magic initialization constants.
355 state[0] = 0x67452301;
356 state[1] = 0xefcdab89;
357 state[2] = 0x98badcfe;
358 state[3] = 0x10325476;
360 count = 0;
363 void PMessageDigest5::InternalProcess(const void * dataPtr, PINDEX length)
365 const BYTE * data = (const BYTE *)dataPtr;
367 // Compute number of bytes mod 64
368 PINDEX index = (PINDEX)((count >> 3) & 0x3F);
369 PINDEX partLen = 64 - index;
371 // Update number of bits
372 count += (PUInt64)length << 3;
374 // See if have a buffer full
375 PINDEX i;
376 if (length < partLen)
377 i = 0;
378 else {
379 // Transform as many times as possible.
380 memcpy(&buffer[index], data, partLen);
381 Transform(buffer);
382 for (i = partLen; i + 63 < length; i += 64)
383 Transform(&data[i]);
384 index = 0;
387 // Buffer remaining input
388 memcpy(&buffer[index], &data[i], length-i);
392 void PMessageDigest5::InternalCompleteDigest(Result & result)
394 // Put the count into bytes platform independently
395 PUInt64l countBytes = count;
397 // Pad out to 56 mod 64.
398 PINDEX index = (PINDEX)((count >> 3) & 0x3f);
399 PINDEX padLen = (index < 56) ? (56 - index) : (120 - index);
400 static BYTE const padding[64] = {
401 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
402 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
403 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
405 Process(padding, padLen);
407 // Append length
408 Process(&countBytes, sizeof(countBytes));
410 // Store state in digest
411 PUInt32l * valuep = (PUInt32l *)result.value.GetPointer(4 * sizeof(PUInt32l));
412 for (PINDEX i = 0; i < PARRAYSIZE(state); i++)
413 valuep[i] = state[i];
415 // Zeroize sensitive information.
416 memset(this, 0, sizeof(*this));
420 PString PMessageDigest5::Encode(const PString & str)
422 return Encode((const char *)str);
426 void PMessageDigest5::Encode(const PString & str, Result & result)
428 Encode((const char *)str, result);
432 PString PMessageDigest5::Encode(const char * cstr)
434 return Encode((const BYTE *)cstr, strlen(cstr));
438 void PMessageDigest5::Encode(const char * cstr, Result & result)
440 Encode((const BYTE *)cstr, strlen(cstr), result);
444 PString PMessageDigest5::Encode(const PBYTEArray & data)
446 return Encode(data, data.GetSize());
450 void PMessageDigest5::Encode(const PBYTEArray & data, Result & result)
452 Encode(data, data.GetSize(), result);
456 PString PMessageDigest5::Encode(const void * data, PINDEX length)
458 Result result;
459 Encode(data, length, result);
460 return PBase64::Encode(&result, sizeof(result));
464 void PMessageDigest5::Encode(const void * data, PINDEX len, Result & result)
466 PMessageDigest5 stomach;
467 stomach.Process(data, len);
468 stomach.CompleteDigest(result);
471 //// backwards compatability functions
473 void PMessageDigest5::Encode(const PString & str, Code & result)
475 Encode((const char *)str, result);
478 void PMessageDigest5::Encode(const char * cstr, Code & result)
480 Encode((const BYTE *)cstr, strlen(cstr), result);
483 void PMessageDigest5::Encode(const PBYTEArray & data, Code & result)
485 Encode(data, data.GetSize(), result);
488 void PMessageDigest5::Encode(const void * data, PINDEX len, Code & codeResult)
490 PMessageDigest5 stomach;
491 stomach.Process(data, len);
492 stomach.Complete(codeResult);
495 PString PMessageDigest5::Complete()
497 Code result;
498 Complete(result);
499 return PBase64::Encode(&result, sizeof(result));
502 void PMessageDigest5::Complete(Code & codeResult)
504 Result result;
505 InternalCompleteDigest(result);
506 memcpy(codeResult.value, result.GetPointer(), sizeof(codeResult.value));
509 ///////////////////////////////////////////////////////////////////////////////
510 // PMessageDigestSHA1
512 #if P_SSL
514 #include <openssl/sha.h>
517 #ifdef _MSC_VER
518 #pragma comment(lib, P_SSL_LIB1)
519 #pragma comment(lib, P_SSL_LIB2)
520 #endif
524 PMessageDigestSHA1::PMessageDigestSHA1()
526 shaContext = NULL;
527 Start();
530 PMessageDigestSHA1::~PMessageDigestSHA1()
532 delete (SHA_CTX *)shaContext;
535 void PMessageDigestSHA1::Start()
537 delete (SHA_CTX *)shaContext;
538 shaContext = new SHA_CTX;
540 SHA1_Init((SHA_CTX *)shaContext);
543 void PMessageDigestSHA1::InternalProcess(const void * data, PINDEX len)
545 if (shaContext == NULL)
546 return;
548 SHA1_Update((SHA_CTX *)shaContext, data, (unsigned long)len);
551 void PMessageDigestSHA1::InternalCompleteDigest(Result & result)
553 if (shaContext == NULL)
554 return;
556 SHA1_Final(result.value.GetPointer(20), (SHA_CTX *)shaContext);
557 delete ((SHA_CTX *)shaContext);
558 shaContext = NULL;
562 PString PMessageDigestSHA1::Encode(const PString & str)
564 return Encode((const char *)str);
568 void PMessageDigestSHA1::Encode(const PString & str, Result & result)
570 Encode((const char *)str, result);
574 PString PMessageDigestSHA1::Encode(const char * cstr)
576 return Encode((const BYTE *)cstr, strlen(cstr));
580 void PMessageDigestSHA1::Encode(const char * cstr, Result & result)
582 Encode((const BYTE *)cstr, strlen(cstr), result);
586 PString PMessageDigestSHA1::Encode(const PBYTEArray & data)
588 return Encode(data, data.GetSize());
592 void PMessageDigestSHA1::Encode(const PBYTEArray & data, Result & result)
594 Encode(data, data.GetSize(), result);
598 PString PMessageDigestSHA1::Encode(const void * data, PINDEX length)
600 Result result;
601 Encode(data, length, result);
602 return PBase64::Encode(&result, sizeof(result));
606 void PMessageDigestSHA1::Encode(const void * data, PINDEX len, Result & result)
608 PMessageDigestSHA1 stomach;
609 stomach.Process(data, len);
610 stomach.CompleteDigest(result);
613 #endif
615 ///////////////////////////////////////////////////////////////////////////////
616 // PCypher
618 PCypher::PCypher(PINDEX blkSize, BlockChainMode mode)
619 : blockSize(blkSize),
620 chainMode(mode)
625 PCypher::PCypher(const void * keyData, PINDEX keyLength,
626 PINDEX blkSize, BlockChainMode mode)
627 : key((const BYTE *)keyData, keyLength),
628 blockSize(blkSize),
629 chainMode(mode)
634 PString PCypher::Encode(const PString & str)
636 return Encode((const char *)str, str.GetLength());
640 PString PCypher::Encode(const PBYTEArray & clear)
642 return Encode((const BYTE *)clear, clear.GetSize());
646 PString PCypher::Encode(const void * data, PINDEX length)
648 PBYTEArray coded;
649 Encode(data, length, coded);
650 return PBase64::Encode(coded);
654 void PCypher::Encode(const PBYTEArray & clear, PBYTEArray & coded)
656 Encode((const BYTE *)clear, clear.GetSize(), coded);
660 void PCypher::Encode(const void * data, PINDEX length, PBYTEArray & coded)
662 PAssert((blockSize%8) == 0, PUnsupportedFeature);
664 Initialise(TRUE);
666 const BYTE * in = (const BYTE *)data;
667 BYTE * out = coded.GetPointer(
668 blockSize > 1 ? (length/blockSize+1)*blockSize : length);
670 while (length >= blockSize) {
671 EncodeBlock(in, out);
672 in += blockSize;
673 out += blockSize;
674 length -= blockSize;
677 if (blockSize > 1) {
678 PBYTEArray extra(blockSize);
679 PINDEX i;
680 for (i = 0; i < length; i++)
681 extra[i] = *in++;
682 PTime now;
683 PRandom rand((DWORD)now.GetTimestamp());
684 for (; i < blockSize-1; i++)
685 extra[i] = (BYTE)rand.Generate();
686 extra[blockSize-1] = (BYTE)length;
687 EncodeBlock(extra, out);
692 PString PCypher::Decode(const PString & cypher)
694 PString clear;
695 if (Decode(cypher, clear))
696 return clear;
697 return PString();
701 BOOL PCypher::Decode(const PString & cypher, PString & clear)
703 clear = PString();
705 PBYTEArray clearText;
706 if (!Decode(cypher, clearText))
707 return FALSE;
709 if (clearText.IsEmpty())
710 return TRUE;
712 PINDEX sz = clearText.GetSize();
713 memcpy(clear.GetPointer(sz+1), (const BYTE *)clearText, sz);
714 return TRUE;
718 BOOL PCypher::Decode(const PString & cypher, PBYTEArray & clear)
720 PBYTEArray coded;
721 if (!PBase64::Decode(cypher, coded))
722 return FALSE;
723 return Decode(coded, clear);
727 PINDEX PCypher::Decode(const PString & cypher, void * data, PINDEX length)
729 PBYTEArray coded;
730 PBase64::Decode(cypher, coded);
731 PBYTEArray clear;
732 if (!Decode(coded, clear))
733 return 0;
734 memcpy(data, clear, PMIN(length, clear.GetSize()));
735 return clear.GetSize();
739 PINDEX PCypher::Decode(const PBYTEArray & coded, void * data, PINDEX length)
741 PBYTEArray clear;
742 if (!Decode(coded, clear))
743 return 0;
744 memcpy(data, clear, PMIN(length, clear.GetSize()));
745 return clear.GetSize();
749 BOOL PCypher::Decode(const PBYTEArray & coded, PBYTEArray & clear)
751 PAssert((blockSize%8) == 0, PUnsupportedFeature);
752 if (coded.IsEmpty() || (coded.GetSize()%blockSize) != 0)
753 return FALSE;
755 Initialise(FALSE);
757 const BYTE * in = coded;
758 PINDEX length = coded.GetSize();
759 BYTE * out = clear.GetPointer(length);
761 for (PINDEX count = 0; count < length; count += blockSize) {
762 DecodeBlock(in, out);
763 in += blockSize;
764 out += blockSize;
767 if (blockSize != 1) {
768 if (*--out >= blockSize)
769 return FALSE;
770 clear.SetSize(length - blockSize + *out);
773 return TRUE;
778 ///////////////////////////////////////////////////////////////////////////////
779 // PTEACypher
781 PTEACypher::PTEACypher(BlockChainMode chainMode)
782 : PCypher(8, chainMode)
784 GenerateKey(*(Key*)key.GetPointer(sizeof(Key)));
788 PTEACypher::PTEACypher(const Key & keyData, BlockChainMode chainMode)
789 : PCypher(&keyData, sizeof(Key), 8, chainMode)
794 void PTEACypher::SetKey(const Key & newKey)
796 memcpy(key.GetPointer(sizeof(Key)), &newKey, sizeof(Key));
800 void PTEACypher::GetKey(Key & newKey) const
802 memcpy(&newKey, key, sizeof(Key));
806 void PTEACypher::GenerateKey(Key & newKey)
808 static PRandom rand; //=1 // Explicitly set seed if need known random sequence
809 for (size_t i = 0; i < sizeof(Key); i++)
810 newKey.value[i] = (BYTE)rand;
814 static const DWORD TEADelta = 0x9e3779b9; // Magic number for key schedule
816 void PTEACypher::Initialise(BOOL)
818 k0 = ((const PUInt32l *)(const BYTE *)key)[0];
819 k1 = ((const PUInt32l *)(const BYTE *)key)[1];
820 k2 = ((const PUInt32l *)(const BYTE *)key)[2];
821 k3 = ((const PUInt32l *)(const BYTE *)key)[3];
825 void PTEACypher::EncodeBlock(const void * in, void * out)
827 DWORD y = ((PUInt32b*)in)[0];
828 DWORD z = ((PUInt32b*)in)[1];
829 DWORD sum = 0;
830 for (PINDEX count = 32; count > 0; count--) {
831 sum += TEADelta; // Magic number for key schedule
832 y += (z<<4)+k0 ^ z+sum ^ (z>>5)+k1;
833 z += (y<<4)+k2 ^ y+sum ^ (y>>5)+k3; /* end cycle */
835 ((PUInt32b*)out)[0] = y;
836 ((PUInt32b*)out)[1] = z;
840 void PTEACypher::DecodeBlock(const void * in, void * out)
842 DWORD y = ((PUInt32b*)in)[0];
843 DWORD z = ((PUInt32b*)in)[1];
844 DWORD sum = TEADelta<<5;
845 for (PINDEX count = 32; count > 0; count--) {
846 z -= (y<<4)+k2 ^ y+sum ^ (y>>5)+k3;
847 y -= (z<<4)+k0 ^ z+sum ^ (z>>5)+k1;
848 sum -= TEADelta; // Magic number for key schedule
850 ((PUInt32b*)out)[0] = y;
851 ((PUInt32b*)out)[1] = z;
855 ///////////////////////////////////////////////////////////////////////////////
856 // PSecureConfig
858 static const char DefaultSecuredOptions[] = "Secured Options";
859 static const char DefaultSecurityKey[] = "Validation";
860 static const char DefaultExpiryDateKey[] = "Expiry Date";
861 static const char DefaultOptionBitsKey[] = "Option Bits";
862 static const char DefaultPendingPrefix[] = "Pending:";
864 PSecureConfig::PSecureConfig(const PTEACypher::Key & prodKey,
865 const PStringArray & secKeys,
866 Source src)
867 : PConfig(DefaultSecuredOptions, src),
868 securedKeys(secKeys),
869 securityKey(DefaultSecurityKey),
870 expiryDateKey(DefaultExpiryDateKey),
871 optionBitsKey(DefaultOptionBitsKey),
872 pendingPrefix(DefaultPendingPrefix)
874 productKey = prodKey;
878 PSecureConfig::PSecureConfig(const PTEACypher::Key & prodKey,
879 const char * const * secKeys,
880 PINDEX count,
881 Source src)
882 : PConfig(DefaultSecuredOptions, src),
883 securedKeys(count, secKeys),
884 securityKey(DefaultSecurityKey),
885 expiryDateKey(DefaultExpiryDateKey),
886 optionBitsKey(DefaultOptionBitsKey),
887 pendingPrefix(DefaultPendingPrefix)
889 productKey = prodKey;
893 void PSecureConfig::GetProductKey(PTEACypher::Key & prodKey) const
895 prodKey = productKey;
899 PSecureConfig::ValidationState PSecureConfig::GetValidation() const
901 PString str;
902 BOOL allEmpty = TRUE;
903 PMessageDigest5 digestor;
904 for (PINDEX i = 0; i < securedKeys.GetSize(); i++) {
905 str = GetString(securedKeys[i]);
906 if (!str.IsEmpty()) {
907 digestor.Process(str.Trim());
908 allEmpty = FALSE;
911 str = GetString(expiryDateKey);
912 if (!str.IsEmpty()) {
913 digestor.Process(str);
914 allEmpty = FALSE;
916 str = GetString(optionBitsKey);
917 if (!str.IsEmpty()) {
918 digestor.Process(str);
919 allEmpty = FALSE;
922 PString vkey = GetString(securityKey);
923 if (allEmpty)
924 return (!vkey || GetBoolean(pendingPrefix + securityKey)) ? Pending : Defaults;
926 PMessageDigest5::Code code;
927 digestor.Complete(code);
929 if (vkey.IsEmpty())
930 return Invalid;
932 BYTE info[sizeof(code)+1+sizeof(DWORD)];
933 PTEACypher crypt(productKey);
934 if (crypt.Decode(vkey, info, sizeof(info)) != sizeof(info))
935 return Invalid;
937 if (memcmp(info, &code, sizeof(code)) != 0)
938 return Invalid;
940 PTime now;
941 if (now > GetTime(expiryDateKey))
942 return Expired;
944 return IsValid;
948 BOOL PSecureConfig::ValidatePending()
950 if (GetValidation() != Pending)
951 return FALSE;
953 PString vkey = GetString(securityKey);
954 if (vkey.IsEmpty())
955 return TRUE;
957 PMessageDigest5::Code code;
958 BYTE info[sizeof(code)+1+sizeof(DWORD)];
959 PTEACypher crypt(productKey);
960 if (crypt.Decode(vkey, info, sizeof(info)) != sizeof(info))
961 return FALSE;
963 PTime expiryDate(0, 0, 0,
964 1, info[sizeof(code)]&15, (info[sizeof(code)]>>4)+1996, PTime::GMT);
965 PString expiry = expiryDate.AsString("d MMME yyyy", PTime::GMT);
967 // This is for alignment problems on processors that care about such things
968 PUInt32b opt;
969 void * dst = &opt;
970 void * src = &info[sizeof(code)+1];
971 memcpy(dst, src, sizeof(opt));
972 PString options(PString::Unsigned, (DWORD)opt);
974 PMessageDigest5 digestor;
975 PINDEX i;
976 for (i = 0; i < securedKeys.GetSize(); i++)
977 digestor.Process(GetString(pendingPrefix + securedKeys[i]).Trim());
978 digestor.Process(expiry);
979 digestor.Process(options);
980 digestor.Complete(code);
982 if (memcmp(info, &code, sizeof(code)) != 0)
983 return FALSE;
985 SetString(expiryDateKey, expiry);
986 SetString(optionBitsKey, options);
988 for (i = 0; i < securedKeys.GetSize(); i++) {
989 PString str = GetString(pendingPrefix + securedKeys[i]);
990 if (!str.IsEmpty())
991 SetString(securedKeys[i], str);
992 DeleteKey(pendingPrefix + securedKeys[i]);
994 DeleteKey(pendingPrefix + securityKey);
996 return TRUE;
1000 void PSecureConfig::ResetPending()
1002 if (GetBoolean(pendingPrefix + securityKey)) {
1003 for (PINDEX i = 0; i < securedKeys.GetSize(); i++)
1004 DeleteKey(securedKeys[i]);
1006 else {
1007 SetBoolean(pendingPrefix + securityKey, TRUE);
1009 for (PINDEX i = 0; i < securedKeys.GetSize(); i++) {
1010 PString str = GetString(securedKeys[i]);
1011 if (!str.IsEmpty())
1012 SetString(pendingPrefix + securedKeys[i], str);
1013 DeleteKey(securedKeys[i]);
1016 DeleteKey(expiryDateKey);
1017 DeleteKey(optionBitsKey);
1021 ///////////////////////////////////////////////////////////////////////////////