source: box/trunk/test/crypto/testcrypto.cpp @ 219

Revision 219, 11.1 KB checked in by martin, 6 years ago (diff)

Merged 210:218 from chris/win32/merge/07-win32-fixes to trunk

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    testcrypto.cpp
5//              Purpose: test lib/crypto
6//              Created: 1/12/03
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#include <string.h>
13#include <strings.h>
14#include <openssl/rand.h>
15
16#include "Test.h"
17#include "CipherContext.h"
18#include "CipherBlowfish.h"
19#include "CipherAES.h"
20#include "CipherException.h"
21#include "RollingChecksum.h"
22#include "Random.h"
23
24#include "MemLeakFindOn.h"
25
26#define STRING1 "Mary had a little lamb"
27#define STRING2 "Skjdf sdjf sjksd fjkhsdfjk hsdfuiohcverfg sdfnj sdfgkljh sdfjb jlhdfvghsdip vjsdfv bsdfhjvg yuiosdvgpvj kvbn m,sdvb sdfuiovg sdfuivhsdfjkv"
28
29#define KEY "0123456701234567012345670123456"
30#define KEY2 "1234567012345670123456A"
31
32#define CHECKSUM_DATA_SIZE                      (128*1024)
33#define CHECKSUM_BLOCK_SIZE_BASE        (65*1024)
34#define CHECKSUM_BLOCK_SIZE_LAST        (CHECKSUM_BLOCK_SIZE_BASE + 64)
35#define CHECKSUM_ROLLS                          16
36
37void check_random_int(uint32_t max)
38{
39        for(int c = 0; c < 1024; ++c)
40        {
41                uint32_t v = Random::RandomInt(max);
42                TEST_THAT(v >= 0 && v <= max);
43        }
44}
45
46#define ZERO_BUFFER(x) ::memset(x, 0, sizeof(x));
47
48template<typename CipherType, int BLOCKSIZE>
49void test_cipher()
50{
51        {
52                // Make a couple of cipher contexts
53                CipherContext encrypt1;
54                encrypt1.Reset();
55                encrypt1.Init(CipherContext::Encrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY)));
56                TEST_CHECK_THROWS(encrypt1.Init(CipherContext::Encrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY))),
57                        CipherException, AlreadyInitialised);
58                // Encrpt something
59                char buf1[256];
60                unsigned int buf1_used = encrypt1.TransformBlock(buf1, sizeof(buf1), STRING1, sizeof(STRING1));
61                TEST_THAT(buf1_used >= sizeof(STRING1));
62                // Decrypt it
63                CipherContext decrypt1;
64                decrypt1.Init(CipherContext::Decrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY)));
65                char buf1_de[256];
66                unsigned int buf1_de_used = decrypt1.TransformBlock(buf1_de, sizeof(buf1_de), buf1, buf1_used);
67                TEST_THAT(buf1_de_used == sizeof(STRING1));
68                TEST_THAT(memcmp(STRING1, buf1_de, sizeof(STRING1)) == 0);
69               
70                // Use them again...
71                char buf1_de2[256];
72                unsigned int buf1_de2_used = decrypt1.TransformBlock(buf1_de2, sizeof(buf1_de2), buf1, buf1_used);
73                TEST_THAT(buf1_de2_used == sizeof(STRING1));
74                TEST_THAT(memcmp(STRING1, buf1_de2, sizeof(STRING1)) == 0);
75               
76                // Test the interface
77                char buf2[256];
78                TEST_CHECK_THROWS(encrypt1.Transform(buf2, sizeof(buf2), STRING1, sizeof(STRING1)),
79                        CipherException, BeginNotCalled);
80                TEST_CHECK_THROWS(encrypt1.Final(buf2, sizeof(buf2)),
81                        CipherException, BeginNotCalled);
82                encrypt1.Begin();
83                int e = 0;
84                e = encrypt1.Transform(buf2, sizeof(buf2), STRING2, sizeof(STRING2) - 16);
85                e += encrypt1.Transform(buf2 + e, sizeof(buf2) - e, STRING2 + sizeof(STRING2) - 16, 16);
86                e += encrypt1.Final(buf2 + e, sizeof(buf2) - e);
87                TEST_THAT(e >= (int)sizeof(STRING2));
88               
89                // Then decrypt
90                char buf2_de[256];
91                decrypt1.Begin();
92                TEST_CHECK_THROWS(decrypt1.Transform(buf2_de, 2, buf2, e), CipherException, OutputBufferTooSmall);
93                TEST_CHECK_THROWS(decrypt1.Final(buf2_de, 2), CipherException, OutputBufferTooSmall);
94                int d = decrypt1.Transform(buf2_de, sizeof(buf2_de), buf2, e - 48);
95                d += decrypt1.Transform(buf2_de + d, sizeof(buf2_de) - d, buf2 + e - 48, 48);
96                d += decrypt1.Final(buf2_de + d, sizeof(buf2_de) - d);
97                TEST_THAT(d == sizeof(STRING2));
98                TEST_THAT(memcmp(STRING2, buf2_de, sizeof(STRING2)) == 0);
99               
100                // Try a reset and rekey
101                encrypt1.Reset();
102                encrypt1.Init(CipherContext::Encrypt, CipherType(CipherDescription::Mode_CBC, KEY2, sizeof(KEY2)));
103                buf1_used = encrypt1.TransformBlock(buf1, sizeof(buf1), STRING1, sizeof(STRING1));
104        }
105       
106        // Test initialisation vectors
107        {
108                // Init with random IV
109                CipherContext encrypt2;
110                encrypt2.Init(CipherContext::Encrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY)));
111                int ivLen;
112                char iv2[BLOCKSIZE];
113                const void *ivGen = encrypt2.SetRandomIV(ivLen);
114                TEST_THAT(ivLen == BLOCKSIZE);  // block size
115                TEST_THAT(ivGen != 0);
116                memcpy(iv2, ivGen, ivLen);
117               
118                char buf3[256];
119                unsigned int buf3_used = encrypt2.TransformBlock(buf3, sizeof(buf3), STRING2, sizeof(STRING2));
120               
121                // Encrypt again with different IV
122                char iv3[BLOCKSIZE];
123                int ivLen3;
124                const void *ivGen3 = encrypt2.SetRandomIV(ivLen3);
125                TEST_THAT(ivLen3 == BLOCKSIZE); // block size
126                TEST_THAT(ivGen3 != 0);
127                memcpy(iv3, ivGen3, ivLen3);
128                // Check the two generated IVs are different
129                TEST_THAT(memcmp(iv2, iv3, BLOCKSIZE) != 0);
130
131                char buf4[256];
132                unsigned int buf4_used = encrypt2.TransformBlock(buf4, sizeof(buf4), STRING2, sizeof(STRING2));
133
134                // check encryptions are different
135                TEST_THAT(buf3_used == buf4_used);
136                TEST_THAT(memcmp(buf3, buf4, buf3_used) != 0);
137               
138                // Test that decryption with the right IV works
139                CipherContext decrypt2;
140                decrypt2.Init(CipherContext::Decrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY), iv2));
141                char buf3_de[256];
142                unsigned int buf3_de_used = decrypt2.TransformBlock(buf3_de, sizeof(buf3_de), buf3, buf3_used);
143                TEST_THAT(buf3_de_used == sizeof(STRING2));
144                TEST_THAT(memcmp(STRING2, buf3_de, sizeof(STRING2)) == 0);
145               
146                // And that using the wrong one doesn't
147                decrypt2.SetIV(iv3);
148                buf3_de_used = decrypt2.TransformBlock(buf3_de, sizeof(buf3_de), buf3, buf3_used);
149                TEST_THAT(buf3_de_used == sizeof(STRING2));
150                TEST_THAT(memcmp(STRING2, buf3_de, sizeof(STRING2)) != 0);             
151        }
152       
153        // Test with padding off.
154        {
155                CipherContext encrypt3;
156                encrypt3.Init(CipherContext::Encrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY)));
157                encrypt3.UsePadding(false);
158               
159                // Should fail because the encrypted size is not a multiple of the block size
160                char buf4[256];
161                encrypt3.Begin();
162                ZERO_BUFFER(buf4);
163                int buf4_used = encrypt3.Transform(buf4, sizeof(buf4), STRING2, 6);
164                TEST_CHECK_THROWS(encrypt3.Final(buf4, sizeof(buf4)), CipherException, EVPFinalFailure);
165               
166                // Check a nice encryption with the correct block size
167                CipherContext encrypt4;
168                encrypt4.Init(CipherContext::Encrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY)));
169                encrypt4.UsePadding(false);
170                encrypt4.Begin();
171                ZERO_BUFFER(buf4);
172                buf4_used = encrypt4.Transform(buf4, sizeof(buf4), STRING2, 16);
173                buf4_used += encrypt4.Final(buf4+buf4_used, sizeof(buf4));
174                TEST_THAT(buf4_used == 16);
175
176                // Check it's encrypted to the same thing as when there's padding on
177                CipherContext encrypt4b;
178                encrypt4b.Init(CipherContext::Encrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY)));
179                encrypt4b.Begin();
180                char buf4b[256];
181                ZERO_BUFFER(buf4b);
182                int buf4b_used = encrypt4b.Transform(buf4b, sizeof(buf4b), STRING2, 16);
183                buf4b_used += encrypt4b.Final(buf4b + buf4b_used, sizeof(buf4b));
184                TEST_THAT(buf4b_used == 16+BLOCKSIZE);
185                TEST_THAT(::memcmp(buf4, buf4b, 16) == 0);
186
187                // Decrypt
188                char buf4_de[256];
189                CipherContext decrypt4;
190                decrypt4.Init(CipherContext::Decrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY)));
191                decrypt4.UsePadding(false);
192                decrypt4.Begin();
193                ZERO_BUFFER(buf4_de);
194                int buf4_de_used = decrypt4.Transform(buf4_de, sizeof(buf4_de), buf4, 16);
195                buf4_de_used += decrypt4.Final(buf4_de+buf4_de_used, sizeof(buf4_de));
196                TEST_THAT(buf4_de_used == 16);
197                TEST_THAT(::memcmp(buf4_de, STRING2, 16) == 0);
198               
199                // Test that the TransformBlock thing works as expected too with blocks the same size as the input
200                TEST_THAT(encrypt4.TransformBlock(buf4, 16, STRING2, 16) == 16);
201                // But that it exceptions if we try the trick with padding on
202                encrypt4.UsePadding(true);
203                TEST_CHECK_THROWS(encrypt4.TransformBlock(buf4, 16, STRING2, 16), CipherException, OutputBufferTooSmall);
204        }
205
206        // And again, but with different string size
207        {
208                char buf4[256];
209                int buf4_used;
210
211                // Check a nice encryption with the correct block size
212                CipherContext encrypt4;
213                encrypt4.Init(CipherContext::Encrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY)));
214                encrypt4.UsePadding(false);
215                encrypt4.Begin();
216                ZERO_BUFFER(buf4);
217                buf4_used = encrypt4.Transform(buf4, sizeof(buf4), STRING2, (BLOCKSIZE*3)); // do three blocks worth
218                buf4_used += encrypt4.Final(buf4+buf4_used, sizeof(buf4));
219                TEST_THAT(buf4_used == (BLOCKSIZE*3));
220
221                // Check it's encrypted to the same thing as when there's padding on
222                CipherContext encrypt4b;
223                encrypt4b.Init(CipherContext::Encrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY)));
224                encrypt4b.Begin();
225                char buf4b[256];
226                ZERO_BUFFER(buf4b);
227                int buf4b_used = encrypt4b.Transform(buf4b, sizeof(buf4b), STRING2, (BLOCKSIZE*3));
228                buf4b_used += encrypt4b.Final(buf4b + buf4b_used, sizeof(buf4b));
229                TEST_THAT(buf4b_used == (BLOCKSIZE*4));
230                TEST_THAT(::memcmp(buf4, buf4b, (BLOCKSIZE*3)) == 0);
231
232                // Decrypt
233                char buf4_de[256];
234                CipherContext decrypt4;
235                decrypt4.Init(CipherContext::Decrypt, CipherType(CipherDescription::Mode_CBC, KEY, sizeof(KEY)));
236                decrypt4.UsePadding(false);
237                decrypt4.Begin();
238                ZERO_BUFFER(buf4_de);
239                int buf4_de_used = decrypt4.Transform(buf4_de, sizeof(buf4_de), buf4, (BLOCKSIZE*3));
240                buf4_de_used += decrypt4.Final(buf4_de+buf4_de_used, sizeof(buf4_de));
241                TEST_THAT(buf4_de_used == (BLOCKSIZE*3));
242                TEST_THAT(::memcmp(buf4_de, STRING2, (BLOCKSIZE*3)) == 0);
243               
244                // Test that the TransformBlock thing works as expected too with blocks the same size as the input
245                TEST_THAT(encrypt4.TransformBlock(buf4, (BLOCKSIZE*3), STRING2, (BLOCKSIZE*3)) == (BLOCKSIZE*3));
246                // But that it exceptions if we try the trick with padding on
247                encrypt4.UsePadding(true);
248                TEST_CHECK_THROWS(encrypt4.TransformBlock(buf4, (BLOCKSIZE*3), STRING2, (BLOCKSIZE*3)), CipherException, OutputBufferTooSmall);
249        }
250}
251
252int test(int argc, const char *argv[])
253{
254        Random::Initialise();
255
256        // Cipher type
257        ::printf("Blowfish...\n");
258        test_cipher<CipherBlowfish, 8>();
259#ifndef HAVE_OLD_SSL
260        ::printf("AES...\n");
261        test_cipher<CipherAES, 16>();
262#else
263        ::printf("Skipping AES -- not supported by version of OpenSSL in use.\n");
264#endif
265       
266        ::printf("Misc...\n");
267        // Check rolling checksums
268        uint8_t *checkdata_blk = (uint8_t *)malloc(CHECKSUM_DATA_SIZE);
269        uint8_t *checkdata = checkdata_blk;
270        RAND_pseudo_bytes(checkdata, CHECKSUM_DATA_SIZE);
271        for(int size = CHECKSUM_BLOCK_SIZE_BASE; size <= CHECKSUM_BLOCK_SIZE_LAST; ++size)
272        {
273                // Test skip-roll code
274                RollingChecksum rollFast(checkdata, size);
275                rollFast.RollForwardSeveral(checkdata, checkdata+size, size, CHECKSUM_ROLLS/2);
276                RollingChecksum calc(checkdata + (CHECKSUM_ROLLS/2), size);
277                TEST_THAT(calc.GetChecksum() == rollFast.GetChecksum());
278
279                //printf("size = %d\n", size);
280                // Checksum to roll
281                RollingChecksum roll(checkdata, size);
282               
283                // Roll forward
284                for(int l = 0; l < CHECKSUM_ROLLS; ++l)
285                {                       
286                        // Calculate new one
287                        RollingChecksum calc(checkdata, size);
288
289                        //printf("%08X %08X %d %d\n", roll.GetChecksum(), calc.GetChecksum(), checkdata[0], checkdata[size]);
290
291                        // Compare them!
292                        TEST_THAT(calc.GetChecksum() == roll.GetChecksum());
293                       
294                        // Roll it onwards
295                        roll.RollForward(checkdata[0], checkdata[size], size);
296       
297                        // increment
298                        ++checkdata;
299                }
300        }
301        ::free(checkdata_blk);
302
303        // Random integers
304        check_random_int(0);
305        check_random_int(1);
306        check_random_int(5);
307        check_random_int(15);   // all 1's
308        check_random_int(1022);
309
310        return 0;
311}
312
313
314
Note: See TracBrowser for help on using the repository browser.