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.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
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
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
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
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
148 #pragma implementation "cypher.h"
152 #include <ptclib/cypher.h>
153 #include <ptclib/mime.h>
154 #include <ptclib/random.h>
158 ///////////////////////////////////////////////////////////////////////////////
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()
190 CompleteDigest(result
);
191 return PBase64::Encode(&result
, sizeof(result
));
194 void PMessageDigest::CompleteDigest(Result
& result
)
196 InternalCompleteDigest(result
);
200 ///////////////////////////////////////////////////////////////////////////////
203 PMessageDigest5::PMessageDigest5()
209 // Constants for MD5Transform routine.
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)); \
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)); \
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)); \
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)); \
259 void PMessageDigest5::Transform(const BYTE * block)
267 for (PINDEX i
= 0; i
< 16; i
++)
268 x
[i
] = ((PUInt32l
*)block
)[i
];
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 */
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 */
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 */
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 */
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;
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
376 if (length
< partLen
)
379 // Transform as many times as possible.
380 memcpy(&buffer
[index
], data
, partLen
);
382 for (i
= partLen
; i
+ 63 < length
; i
+= 64)
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
);
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
)
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()
499 return PBase64::Encode(&result
, sizeof(result
));
502 void PMessageDigest5::Complete(Code
& codeResult
)
505 InternalCompleteDigest(result
);
506 memcpy(codeResult
.value
, result
.GetPointer(), sizeof(codeResult
.value
));
509 ///////////////////////////////////////////////////////////////////////////////
510 // PMessageDigestSHA1
514 #include <openssl/sha.h>
518 #pragma comment(lib, P_SSL_LIB1)
519 #pragma comment(lib, P_SSL_LIB2)
524 PMessageDigestSHA1::PMessageDigestSHA1()
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
)
548 SHA1_Update((SHA_CTX
*)shaContext
, data
, (unsigned long)len
);
551 void PMessageDigestSHA1::InternalCompleteDigest(Result
& result
)
553 if (shaContext
== NULL
)
556 SHA1_Final(result
.value
.GetPointer(20), (SHA_CTX
*)shaContext
);
557 delete ((SHA_CTX
*)shaContext
);
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
)
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
);
615 ///////////////////////////////////////////////////////////////////////////////
618 PCypher::PCypher(PINDEX blkSize
, BlockChainMode mode
)
619 : blockSize(blkSize
),
625 PCypher::PCypher(const void * keyData
, PINDEX keyLength
,
626 PINDEX blkSize
, BlockChainMode mode
)
627 : key((const BYTE
*)keyData
, keyLength
),
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
)
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
);
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
);
678 PBYTEArray
extra(blockSize
);
680 for (i
= 0; i
< length
; i
++)
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
)
695 if (Decode(cypher
, clear
))
701 BOOL
PCypher::Decode(const PString
& cypher
, PString
& clear
)
705 PBYTEArray clearText
;
706 if (!Decode(cypher
, clearText
))
709 if (clearText
.IsEmpty())
712 PINDEX sz
= clearText
.GetSize();
713 memcpy(clear
.GetPointer(sz
+1), (const BYTE
*)clearText
, sz
);
718 BOOL
PCypher::Decode(const PString
& cypher
, PBYTEArray
& clear
)
721 if (!PBase64::Decode(cypher
, coded
))
723 return Decode(coded
, clear
);
727 PINDEX
PCypher::Decode(const PString
& cypher
, void * data
, PINDEX length
)
730 PBase64::Decode(cypher
, coded
);
732 if (!Decode(coded
, clear
))
734 memcpy(data
, clear
, PMIN(length
, clear
.GetSize()));
735 return clear
.GetSize();
739 PINDEX
PCypher::Decode(const PBYTEArray
& coded
, void * data
, PINDEX length
)
742 if (!Decode(coded
, clear
))
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)
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
);
767 if (blockSize
!= 1) {
768 if (*--out
>= blockSize
)
770 clear
.SetSize(length
- blockSize
+ *out
);
778 ///////////////////////////////////////////////////////////////////////////////
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];
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 ///////////////////////////////////////////////////////////////////////////////
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
,
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
,
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
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());
911 str
= GetString(expiryDateKey
);
912 if (!str
.IsEmpty()) {
913 digestor
.Process(str
);
916 str
= GetString(optionBitsKey
);
917 if (!str
.IsEmpty()) {
918 digestor
.Process(str
);
922 PString vkey
= GetString(securityKey
);
924 return (!vkey
|| GetBoolean(pendingPrefix
+ securityKey
)) ? Pending
: Defaults
;
926 PMessageDigest5::Code code
;
927 digestor
.Complete(code
);
932 BYTE info
[sizeof(code
)+1+sizeof(DWORD
)];
933 PTEACypher
crypt(productKey
);
934 if (crypt
.Decode(vkey
, info
, sizeof(info
)) != sizeof(info
))
937 if (memcmp(info
, &code
, sizeof(code
)) != 0)
941 if (now
> GetTime(expiryDateKey
))
948 BOOL
PSecureConfig::ValidatePending()
950 if (GetValidation() != Pending
)
953 PString vkey
= GetString(securityKey
);
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
))
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
970 void * src
= &info
[sizeof(code
)+1];
971 memcpy(dst
, src
, sizeof(opt
));
972 PString
options(PString::Unsigned
, (DWORD
)opt
);
974 PMessageDigest5 digestor
;
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)
985 SetString(expiryDateKey
, expiry
);
986 SetString(optionBitsKey
, options
);
988 for (i
= 0; i
< securedKeys
.GetSize(); i
++) {
989 PString str
= GetString(pendingPrefix
+ securedKeys
[i
]);
991 SetString(securedKeys
[i
], str
);
992 DeleteKey(pendingPrefix
+ securedKeys
[i
]);
994 DeleteKey(pendingPrefix
+ securityKey
);
1000 void PSecureConfig::ResetPending()
1002 if (GetBoolean(pendingPrefix
+ securityKey
)) {
1003 for (PINDEX i
= 0; i
< securedKeys
.GetSize(); i
++)
1004 DeleteKey(securedKeys
[i
]);
1007 SetBoolean(pendingPrefix
+ securityKey
, TRUE
);
1009 for (PINDEX i
= 0; i
< securedKeys
.GetSize(); i
++) {
1010 PString str
= GetString(securedKeys
[i
]);
1012 SetString(pendingPrefix
+ securedKeys
[i
], str
);
1013 DeleteKey(securedKeys
[i
]);
1016 DeleteKey(expiryDateKey
);
1017 DeleteKey(optionBitsKey
);
1021 ///////////////////////////////////////////////////////////////////////////////