cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
timing.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Timing Test Routines *
4 * Copyright Peter Gutmann 2003-2008 *
5 * *
6 ****************************************************************************/
7 
8 /* In order for the DH/DSA timing tests (which use cryptlib-internal
9  mechanisms) to work, it's necessary to add the following lines of code to
10  the start of cryptDeviceQueryCapability() in cryptapi.c, before any other
11  code:
12 
13  if( cryptAlgo == 1000 )
14  return( krnlSendMessage( device, IMESSAGE_SETATTRIBUTE_S,
15  cryptQueryInfo, CRYPT_IATTRIBUTE_KEY_SPKI ) );
16  if( cryptAlgo == 1001 )
17  return( krnlSendMessage( device, IMESSAGE_CTX_ENCRYPT,
18  cryptQueryInfo, sizeof( KEYAGREE_PARAMS ) ) );
19  if( cryptAlgo == 1002 )
20  return( krnlSendMessage( device, IMESSAGE_CTX_DECRYPT,
21  cryptQueryInfo, sizeof( KEYAGREE_PARAMS ) ) );
22  if( cryptAlgo == 1003 )
23  return( krnlSendMessage( device, IMESSAGE_CTX_SIGN,
24  cryptQueryInfo, sizeof( DLP_PARAMS ) ) );
25  if( cryptAlgo == 1004 )
26  return( krnlSendMessage( device, IMESSAGE_CTX_SIGCHECK,
27  cryptQueryInfo, sizeof( DLP_PARAMS ) ) );
28 
29  This is because the DH/DSA tests are handled by passing magic values into
30  the function (which is very rarely used normally). Remember to remove
31  the magic-values check code after use!
32 
33  Under Unix, the test code can be built with:
34 
35  cc -c -D__UNIX__ testtime.c
36  cc -o testtime -lpthread -lresolv testtime.o -L. -lcl
37 
38  */
39 
40 #if defined( _WIN32_WCE ) && _WIN32_WCE < 400
41  #define assert( x )
42 #else
43  #include <assert.h>
44 #endif /* Systems without assert() */
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <math.h> /* For sqrt() for standard deviation */
48 #ifdef _MSC_VER
49  #include "../cryptlib.h"
50 #else
51  #include "cryptlib.h"
52 #endif /* Braindamaged VC++ include handling */
53 #ifdef __UNIX__
54  #include <sys/time.h>
55 #endif /* __UNIX__ */
56 
57 /* It's useful to know if we're running under Windows to enable Windows-
58  specific processing */
59 
60 #if defined( _WINDOWS ) || defined( WIN32 ) || defined( _WIN32 ) || \
61  defined( _WIN32_WCE )
62  #define __WINDOWS__
63 #endif /* _WINDOWS || WIN32 || _WIN32 || _WIN32_WCE */
64 
65 /* Various useful types */
66 
67 #define BOOLEAN int
68 #define BYTE unsigned char
69 #ifndef TRUE
70  #define FALSE 0
71  #define TRUE !FALSE
72 #endif /* TRUE */
73 
74 /* Helper function for systems with no console */
75 
76 #ifdef _WIN32_WCE
77  #define printf wcPrintf
78  #define puts wcPuts
79 
80  void wcPrintf( const char *format, ... );
81  void wcPuts( const char *string );
82 #endif /* Console-less environments */
83 
84 /* Since high-precision timing is rather OS-dependent, we only enable this
85  under Windows where we've got guaranteed high-res timer access */
86 
87 #if defined( __WINDOWS__ ) || defined( __UNIX__ )
88 
89 /* The number of tests of each algorithm to perform */
90 
91 #define NO_TESTS 25
92 
93 /* Normally we use 32-bit time values, however there's also (partial)
94  support for 64-bit signed values on systems that support this */
95 
96 #define USE_32BIT_TIME
97 
98 #if defined( USE_32BIT_TIME )
99  typedef long HIRES_TIME;
100 #elif defined( _MSC_VER )
101  typedef __int64 HIRES_TIME;
102 #elif defined( __GNUC__ )
103  typedef long long HIRES_TIME;
104 #else
105  typedef unsigned long HIRES_TIME;
106 #endif /* 64-bit int values */
107 
108 /****************************************************************************
109 * *
110 * Utility Functions *
111 * *
112 ****************************************************************************/
113 
114 /* Helper functions for systems with no console. These just use the debug
115  console as stdout */
116 
117 #ifdef _WIN32_WCE
118 
119 void wcPrintf( const char *format, ... )
120  {
121  wchar_t wcBuffer[ 1024 ];
122  char buffer[ 1024 ];
123  va_list argPtr;
124 
125  va_start( argPtr, format );
126  vsprintf( buffer, format, argPtr );
127  va_end( argPtr );
128  mbstowcs( wcBuffer, buffer, strlen( buffer ) + 1 );
129  NKDbgPrintfW( wcBuffer );
130  }
131 
132 void wcPuts( const char *string )
133  {
134  wcPrintf( "%s\n", string );
135  }
136 #endif /* Console-less environments */
137 
138 /* Get high-resolution timing info */
139 
140 #ifdef USE_32BIT_TIME
141 
142 static HIRES_TIME timeDiff( HIRES_TIME startTime )
143  {
144  HIRES_TIME timeLSB, timeDifference;
145 
146 #ifdef __WINDOWS__
147  #if 1
148  LARGE_INTEGER performanceCount;
149 
150  /* Sensitive to context switches */
151  QueryPerformanceCounter( &performanceCount );
152  timeLSB = performanceCount.LowPart;
153  #else
154  FILETIME dummyTime, kernelTime, userTime;
155  int status;
156 
157  /* Only accurate to 10ms, returns constant values in VC++ debugger */
158  GetThreadTimes( GetCurrentThread(), &dummyTime, &dummyTime,
159  &kernelTime, &userTime );
160  timeLSB = userTime.dwLowDateTime;
161  #endif /* 0 */
162 #else
163  struct timeval tv;
164 
165  /* Only accurate to about 1us */
166  gettimeofday( &tv, NULL );
167  timeLSB = tv.tv_usec;
168 #endif /* Windows vs.Unix high-res timing */
169 
170  /* If we're getting an initial time, return an absolute value */
171  if( !startTime )
172  return( timeLSB );
173 
174  /* We're getting a time difference */
175  if( startTime < timeLSB )
176  timeDifference = timeLSB - startTime;
177  else
178 #ifdef __WINDOWS__
179  /* Windows rolls over at INT_MAX */
180  timeDifference = ( 0xFFFFFFFFUL - startTime ) + 1 + timeLSB;
181 #else
182  /* gettimeofday() rolls over at 1M us */
183  timeDifference = ( 1000000L - startTime ) + timeLSB;
184 #endif /* __WINDOWS__ */
185  if( timeDifference <= 0 )
186  {
187  printf( "Error: Time difference = %X, startTime = %X, endTime = %X.\n",
188  timeDifference, startTime, timeLSB );
189  return( 1 );
190  }
191  return( timeDifference );
192  }
193 
194 #else
195 
196 static HIRES_TIME timeDiff( HIRES_TIME startTime )
197  {
198  HIRES_TIME timeValue;
199 
200 #ifdef __WINDOWS__
201  #if 1
202  LARGE_INTEGER performanceCount;
203 
204  /* Sensitive to context switches */
205  QueryPerformanceCounter( &performanceCount );
206  timeValue = performanceCount.QuadPart;
207  #else
208  FILETIME dummyTime, kernelTime, userTime;
209  int status;
210 
211  /* Only accurate to 10ms, returns constant values in VC++ debugger */
212  GetThreadTimes( GetCurrentThread(), &dummyTime, &dummyTime,
213  &kernelTime, &userTime );
214  timeLSB = userTime.dwLowDateTime;
215  #endif /* 0 */
216 #else
217  struct timeval tv;
218 
219  /* Only accurate to about 1us */
220  gettimeofday( &tv, NULL );
221  timeValue = ( ( ( HIRES_TIME ) tv.tv_sec ) << 32 ) | tv.tv_usec;
222 #endif /* Windows vs.Unix high-res timing */
223 
224  if( !startTime )
225  return( timeValue );
226  return( timeValue - startTime );
227  }
228 #endif /* USE_32BIT_TIME */
229 
230 /* Check for an algorithm/mode */
231 
232 static BOOLEAN checkLowlevelInfo( const CRYPT_DEVICE cryptDevice,
234  const CRYPT_MODE_TYPE cryptMode )
235  {
236  CRYPT_QUERY_INFO cryptQueryInfo;
237  const BOOLEAN isDevice = ( cryptDevice != CRYPT_UNUSED ) ? TRUE : FALSE;
238  int status;
239 
240  if( isDevice )
241  status = cryptDeviceQueryCapability( cryptDevice, cryptAlgo,
242  &cryptQueryInfo );
243  else
244  status = cryptQueryCapability( cryptAlgo, &cryptQueryInfo );
245  if( cryptStatusError( status ) )
246  {
247  /* RC4 is a legacy algorithm that isn't usually enabled so we
248  silently skip this one */
249  if( cryptAlgo == CRYPT_ALGO_RC4 )
250  return( FALSE );
251 
252  printf( "crypt%sQueryCapability() reports algorithm %d is not "
253  "available, status = %d.\n", isDevice ? "Device" : "",
254  cryptAlgo, status );
255  return( FALSE );
256  }
257  if( cryptAlgo > CRYPT_ALGO_FIRST_HASH )
258  {
259  printf( "%s, ", cryptQueryInfo.algoName );
260  return( TRUE );
261  }
262  printf( "%s/%s, block size %d bits, keysize %d bits, ",
263  cryptQueryInfo.algoName,
264  ( cryptMode == CRYPT_MODE_ECB ) ? "ECB" : "CBC",
265  cryptQueryInfo.blockSize << 3, cryptQueryInfo.keySize << 3 );
266 
267  return( TRUE );
268  }
269 
270 /* Load the encryption contexts */
271 
272 static BOOLEAN loadContexts( CRYPT_CONTEXT *cryptContext, CRYPT_CONTEXT *decryptContext,
273  const CRYPT_DEVICE cryptDevice,
274  const CRYPT_ALGO_TYPE cryptAlgo,
275  const CRYPT_MODE_TYPE cryptMode,
276  const BYTE *key, const int length )
277  {
278  const BOOLEAN isDevice = ( cryptDevice != CRYPT_UNUSED ) ? TRUE : FALSE;
279  const BOOLEAN hasKey = ( cryptAlgo >= CRYPT_ALGO_FIRST_CONVENTIONAL && \
280  cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL ) || \
281  ( cryptAlgo >= CRYPT_ALGO_FIRST_MAC && \
282  cryptAlgo <= CRYPT_ALGO_LAST_MAC );
283  BOOLEAN adjustKey = FALSE;
284  int status;
285 
286  /* Create the encryption context */
287  if( isDevice )
288  status = cryptDeviceCreateContext( cryptDevice, cryptContext,
289  cryptAlgo );
290  else
291  status = cryptCreateContext( cryptContext, CRYPT_UNUSED, cryptAlgo );
292  if( cryptStatusError( status ) )
293  {
294  printf( "crypt%sCreateContext() failed with error code %d.\n",
295  isDevice ? "Device" : "", status );
296  return( FALSE );
297  }
298  if( cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL )
299  {
300  status = cryptSetAttribute( *cryptContext, CRYPT_CTXINFO_MODE,
301  cryptMode );
302  if( cryptStatusError( status ) )
303  {
304  cryptDestroyContext( *cryptContext );
305  if( status == CRYPT_ERROR_NOTAVAIL )
306  /* This mode isn't available, return a special-case value to
307  tell the calling code to continue */
308  return( status );
309  printf( "Encryption mode %d selection failed with status %d.\n",
310  cryptMode, status );
311  return( FALSE );
312  }
313  }
314  if( hasKey )
315  {
316  status = cryptSetAttributeString( *cryptContext, CRYPT_CTXINFO_KEY,
317  key, length );
318  if( length > 16 && status == CRYPT_ERROR_PARAM4 )
319  {
320  status = cryptSetAttributeString( *cryptContext, CRYPT_CTXINFO_KEY,
321  key, 16 );
322  if( cryptStatusOK( status ) )
323  {
324  puts( " Load of full-length key failed, using shorter 128-"
325  "bit key." );
326  adjustKey = TRUE;
327  }
328  }
329  if( cryptStatusError( status ) )
330  {
331  printf( "Key load failed with error code %d.\n", status );
332  return( FALSE );
333  }
334  }
335  if( decryptContext == NULL )
336  return( TRUE );
337 
338  /* Create the decryption context */
339  if( cryptDevice == CRYPT_UNUSED )
340  status = cryptCreateContext( decryptContext, CRYPT_UNUSED, cryptAlgo );
341  else
342  status = cryptDeviceCreateContext( cryptDevice, decryptContext,
343  cryptAlgo );
344  if( cryptStatusError( status ) )
345  {
346  printf( "crypt%sCreateContext() failed with error code %d.\n",
347  ( cryptDevice != CRYPT_UNUSED ) ? "Device" : "", status );
348  return( FALSE );
349  }
350  if( cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL )
351  {
352  status = cryptSetAttribute( *decryptContext, CRYPT_CTXINFO_MODE,
353  cryptMode );
354  if( cryptStatusError( status ) )
355  {
356  cryptDestroyContext( *cryptContext );
357  if( status == CRYPT_ERROR_NOTAVAIL )
358  /* This mode isn't available, return a special-case value to
359  tell the calling code to continue */
360  return( status );
361  printf( "Encryption mode %d selection failed with status %d.\n",
362  cryptMode, status );
363  return( FALSE );
364  }
365  }
366  if( hasKey )
367  {
368  status = cryptSetAttributeString( *decryptContext, CRYPT_CTXINFO_KEY,
369  key, adjustKey ? 16 : length );
370  if( cryptStatusError( status ) )
371  {
372  printf( "Key load failed with error code %d.\n", status );
373  return( FALSE );
374  }
375  }
376 
377  return( TRUE );
378  }
379 
380 /****************************************************************************
381 * *
382 * Timing Tests *
383 * *
384 ****************************************************************************/
385 
386 /* Print timing info. This gets a bit hairy because we're actually counting
387  timer ticks rather than thread times which means that we'll be affected
388  by things like context switches. There are two approaches to this:
389 
390  1. Take the fastest time, which will be the time least affected by
391  system overhead.
392 
393  2. Apply standard statistical techniques to weed out anomalies. Since
394  this is just for testing purposes all we do is discard any results
395  out by more than 10%, which is crude but reasonably effective. A
396  more rigorous approach is to discards results more than n standard
397  deviations out, but this gets screwed up by the fact that a single
398  context switch of 20K ticks can throw out results from an execution
399  time of only 50 ticks. In any case (modulo context switches) the
400  fastest, 10%-out, and 2 SD out times are all within about 1% of each
401  other so all methods are roughly equally accurate */
402 
403 static void printTimes( HIRES_TIME times[ NO_TESTS + 1 ][ 8 ],
404  const int noTimes, long ticksPerSec )
405  {
406  long pubTimeMS, privTimeMS, throughput;
407  int i;
408 
409  for( i = 0; i < noTimes; i++ )
410  {
411  HIRES_TIME timeSum = 0, timeAvg, timeDelta;
412  HIRES_TIME timeMin = 1000000L;
413  HIRES_TIME timeCorrSum10 = 0;
414  HIRES_TIME avgTime;
415 #ifdef USE_SD
416  HIRES_TIME timeCorrSumSD = 0;
417  double stdDev;
418  int timesCountSD = 0;
419 #endif /* USE_SD */
420  int j, timesCount10 = 0;
421 
422  /* Find the mean execution time */
423  for( j = 1; j < NO_TESTS + 1; j++ )
424  timeSum += times[ j ][ i ];
425  timeAvg = timeSum / NO_TESTS;
426  timeDelta = timeSum / 10; /* 10% variation */
427  if( timeSum == 0 )
428  {
429  /* Some ciphers can't provide results for some cases (e.g.
430  AES for 8-byte blocks) */
431  printf( " " );
432  continue;
433  }
434 
435  /* Find the fastest overall time */
436  for( j = 1; j < NO_TESTS + 1; j++ )
437  {
438  if( times[ j ][ i ] < timeMin )
439  timeMin = times[ j ][ i ];
440  }
441 
442  /* Find the mean time, discarding anomalous results more than 10%
443  out. We cast the values to longs in order to (portably) print
444  them, if we want to print the full 64-bit values we have to
445  use nonstandard extensions like "%I64d" (for Win32) */
446  for( j = 1; j < NO_TESTS + 1; j++ )
447  {
448  if( times[ j ][ i ] > timeAvg - timeDelta && \
449  times[ j ][ i ] < timeAvg + timeDelta )
450  {
451  timeCorrSum10 += times[ j ][ i ];
452  timesCount10++;
453  }
454  }
455  if( timesCount10 <= 0 )
456  {
457  printf( "Error: No times within +/-%d of %d.\n",
458  timeDelta, timeAvg );
459  continue;
460  }
461  avgTime = timeCorrSum10 / timesCount10;
462  if( noTimes <= 2 && i == 0 )
463  {
464  printf( "Pub: min.= %d, avg.= %d ", ( long ) timeMin,
465  ( long ) avgTime );
466  pubTimeMS = ( avgTime * 1000 ) / ticksPerSec;
467  }
468  else
469  if( noTimes <= 2 && i == 1 )
470  {
471  printf( "Priv: min.= %d, avg.= %d ", ( long ) timeMin,
472  ( long ) avgTime );
473  privTimeMS = ( avgTime * 1000 ) / ticksPerSec;
474  }
475  else
476  {
477  printf( "%7d", ( long ) avgTime );
478  if( i == 6 )
479  {
480  const long mbTime = ( long ) avgTime * 16; /* 64kB * 15 = 1MB */
481 
482  if( mbTime > ticksPerSec )
483  throughput = 0;
484  else
485  throughput = ticksPerSec / mbTime; /* In MB/sec */
486  }
487  }
488 #if 0 /* Print difference to fastest time, usually only around 1% */
489  printf( "(%4d)", ( timeCorrSum10 / timesCount10 ) - timeMin );
490 #endif /* 0 */
491 
492 #ifdef USE_SD
493  /* Find the standard deviation */
494  for( j = 1; j < NO_TESTS + 1; j++ )
495  {
496  const HIRES_TIME timeDev = times[ j ][ i ] - timeAvg;
497 
498  timeCorrSumSD += ( timeDev * timeDev );
499  }
500  stdDev = timeCorrSumSD / NO_TESTS;
501  stdDev = sqrt( stdDev );
502 
503  /* Find the mean time, discarding anomalous results more than two
504  standard deviations out */
505  timeCorrSumSD = 0;
506  timeDelta = ( HIRES_TIME ) stdDev * 2;
507  for( j = 1; j < NO_TESTS + 1; j++ )
508  {
509  if( times[ j ][ i ] > timeAvg - timeDelta && \
510  times[ j ][ i ] < timeAvg + timeDelta )
511  {
512  timeCorrSumSD += times[ j ][ i ];
513  timesCountSD++;
514  }
515  }
516  if( timesCountSD == 0 )
517  timesCountSD++; /* Context switch, fudge it */
518  printf( "%6d", timeCorrSumSD / timesCountSD );
519 
520 #if 1 /* Print difference to fastest and mean times, usually only around
521  1% */
522  printf( " (dF = %4d, dM = %4d)\n",
523  ( timeCorrSumSD / timesCountSD ) - timeMin,
524  abs( ( timeCorrSumSD / timesCountSD ) - \
525  ( timeCorrSum10 / timesCount10 ) ) );
526 #endif /* 0 */
527 #endif /* USE_SD */
528  }
529  /* If it's a PKC operation print the times in ms */
530  if( noTimes <= 2 )
531  {
532  printf( "\n Public-key op.time = " );
533  if( pubTimeMS <= 0 )
534  printf( "< 1" );
535  else
536  printf( "%ld", pubTimeMS );
537  printf( " ms, private-key op.time = %ld ms.\n", privTimeMS );
538  }
539  else
540  {
541  if( throughput <= 0 )
542  puts( ", throughput < 1 MB/s." );
543  else
544  printf( ", throughput %d MB/s.\n", throughput );
545  }
546  }
547 
548 static HIRES_TIME encOne( const CRYPT_CONTEXT cryptContext,
549  BYTE *buffer, const int length )
550  {
551  HIRES_TIME timeVal;
552 
553  memset( buffer, '*', length );
554  timeVal = timeDiff( 0 );
555  cryptEncrypt( cryptContext, buffer, length );
556  return( timeDiff( timeVal ) );
557  }
558 
559 static void encTest( const CRYPT_CONTEXT cryptContext,
560  const CRYPT_ALGO_TYPE cryptAlgo, BYTE *buffer,
561  HIRES_TIME times[] )
562  {
563  int index = 0;
564 
565  times[ index++ ] = ( cryptAlgo != CRYPT_ALGO_AES ) ? \
566  encOne( cryptContext, buffer, 8 ) : 0;
567  times[ index++ ] = encOne( cryptContext, buffer, 16 );
568  times[ index++ ] = encOne( cryptContext, buffer, 64 );
569  times[ index++ ] = encOne( cryptContext, buffer, 1024 );
570  times[ index++ ] = encOne( cryptContext, buffer, 4096 );
571  times[ index++ ] = encOne( cryptContext, buffer, 8192 );
572  times[ index++ ] = encOne( cryptContext, buffer, 65536L );
573  }
574 
575 static int encTests( const CRYPT_DEVICE cryptDevice,
576  const CRYPT_ALGO_TYPE cryptAlgo,
577  const CRYPT_ALGO_TYPE cryptMode,
578  BYTE *buffer, long ticksPerSec )
579  {
581  HIRES_TIME times[ NO_TESTS + 1 ][ 8 ], timeVal, timeSum = 0;
582  int i, status;
583 
584  memset( buffer, 0, 100000L );
585 
586  /* Set up the context for use */
587  if( !checkLowlevelInfo( cryptDevice, cryptAlgo, cryptMode ) )
588  return( FALSE );
589  for( i = 0; i < 10; i++ )
590  {
591  timeVal = timeDiff( 0 );
592  status = loadContexts( &cryptContext, NULL, cryptDevice,
593  cryptAlgo, cryptMode,
594  ( BYTE * ) "12345678901234567890",
595  ( cryptAlgo == CRYPT_ALGO_DES ) ? 8 : \
596  ( cryptAlgo == CRYPT_ALGO_3DES || \
597  cryptAlgo == CRYPT_ALGO_RC4 || \
598  cryptAlgo == CRYPT_ALGO_AES ) ? 16 : 0 );
599  timeVal = timeDiff( timeVal );
600  if( status == CRYPT_ERROR_NOTAVAIL || !status )
601  return( FALSE );
602  timeSum += timeVal;
603  if( i < 9 )
604  cryptDestroyContext( cryptContext );
605  }
606  printf( "setup time = %d ticks.\n", timeSum / 10 );
607  puts( " 8 16 64 1K 4K 8K 64K" );
608  puts( " ----- ----- ----- ----- ----- ----- -----" );
609 
610  /* Run the encryption tests NO_TESTS times, discarding the first set
611  of results since the cache will be empty at that point */
612  for( i = 0; i < NO_TESTS + 1; i++ )
613  encTest( cryptContext, cryptAlgo, buffer, times[ i ] );
614  printTimes( times, 7, ticksPerSec );
615 
616  /* Re-run the encryption tests with a 1-byte misalignment */
617  for( i = 0; i < NO_TESTS + 1; i++ )
618  encTest( cryptContext, cryptAlgo, buffer + 1, times[ i ] );
619  printTimes( times, 7, ticksPerSec );
620 
621  /* Re-run the encryption tests with a 4-byte misalignment */
622  for( i = 0; i < NO_TESTS + 1; i++ )
623  encTest( cryptContext, cryptAlgo, buffer + 4, times[ i ] );
624  printTimes( times, 7, ticksPerSec );
625 
626  /* Re-run the test 1000 times with various buffer alignments */
627  timeVal = 0;
628  for( i = 0; i < 1000; i++ )
629  timeVal += encOne( cryptContext, buffer, 1024 );
630  printf( "Aligned: %d, ", timeVal / 1000 );
631  timeVal = 0;
632  for( i = 0; i < 1000; i++ )
633  timeVal += encOne( cryptContext, buffer + 1, 1024 );
634  printf( "misaligned + 1: %d, ", timeVal / 1000 );
635  timeVal = 0;
636  for( i = 0; i < 1000; i++ )
637  timeVal += encOne( cryptContext, buffer + 4, 1024 );
638  printf( "misaligned + 4: %d.\n", timeVal / 1000 );
639 
640  return( TRUE );
641  }
642 
643 static void performanceTests( const CRYPT_DEVICE cryptDevice,
644  long ticksPerSec )
645  {
646  BYTE *buffer;
647 
648  if( ( buffer = malloc( 100000L ) ) == NULL )
649  {
650  puts( "Couldn't 100K allocate test buffer." );
651  return;
652  }
653  putchar( '\n' );
654  encTests( cryptDevice, CRYPT_ALGO_DES, CRYPT_MODE_ECB, buffer, ticksPerSec );
655  encTests( cryptDevice, CRYPT_ALGO_DES, CRYPT_MODE_CBC, buffer, ticksPerSec );
656  putchar( '\n' );
657  encTests( cryptDevice, CRYPT_ALGO_3DES, CRYPT_MODE_ECB, buffer, ticksPerSec );
658  encTests( cryptDevice, CRYPT_ALGO_3DES, CRYPT_MODE_CBC, buffer, ticksPerSec );
659  encTests( cryptDevice, CRYPT_ALGO_RC4, CRYPT_MODE_OFB, buffer, ticksPerSec );
660  putchar( '\n' );
661  encTests( cryptDevice, CRYPT_ALGO_AES, CRYPT_MODE_CBC, buffer, ticksPerSec );
662  putchar( '\n' );
663  encTests( cryptDevice, CRYPT_ALGO_MD5, CRYPT_MODE_NONE, buffer, ticksPerSec );
664  encTests( cryptDevice, CRYPT_ALGO_SHA, CRYPT_MODE_NONE, buffer, ticksPerSec );
665  free( buffer );
666  }
667 
668 /****************************************************************************
669 * *
670 * PKC Timing Tests *
671 * *
672 ****************************************************************************/
673 
674 /* Timing tests for PKC crypto operations. Since the DH operations aren't
675  visible externally, we have to use the kernel API to perform the timing
676  test. To get the necessary definitions and prototypes, we have to use
677  crypt.h, however since we've already included cryptlib.h the built-in
678  guards preclude us from pulling it in again with the internal-only values
679  defined, so we have to explicitly define things like attribute values
680  that normally aren't visible externally */
681 
682 #undef __WINDOWS__
683 #undef __WIN16__
684 #undef __WIN32__
685 #undef BYTE
686 #undef BOOLEAN
687 #ifdef _MSC_VER
688  #include "../crypt.h"
689 #else
690  #include "crypt.h"
691 #endif /* Braindamaged VC++ include handling */
692 
693 #define CRYPT_IATTRIBUTE_KEY_SPKI 8015
694 
695 static const BYTE dh1024SPKI[] = {
696  0x30, 0x82, 0x01, 0x21,
697  0x30, 0x82, 0x01, 0x17,
698  0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3E, 0x02, 0x01,
699  0x30, 0x82, 0x01, 0x0A,
700  0x02, 0x81, 0x81, 0x00, /* p */
701  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
702  0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
703  0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
704  0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
705  0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
706  0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
707  0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
708  0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
709  0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
710  0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
711  0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
712  0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
713  0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
714  0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
715  0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
716  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
717  0x02, 0x01, /* g */
718  0x02,
719  0x02, 0x81, 0x80, /* q */
720  0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
721  0xE4, 0x87, 0xED, 0x51, 0x10, 0xB4, 0x61, 0x1A,
722  0x62, 0x63, 0x31, 0x45, 0xC0, 0x6E, 0x0E, 0x68,
723  0x94, 0x81, 0x27, 0x04, 0x45, 0x33, 0xE6, 0x3A,
724  0x01, 0x05, 0xDF, 0x53, 0x1D, 0x89, 0xCD, 0x91,
725  0x28, 0xA5, 0x04, 0x3C, 0xC7, 0x1A, 0x02, 0x6E,
726  0xF7, 0xCA, 0x8C, 0xD9, 0xE6, 0x9D, 0x21, 0x8D,
727  0x98, 0x15, 0x85, 0x36, 0xF9, 0x2F, 0x8A, 0x1B,
728  0xA7, 0xF0, 0x9A, 0xB6, 0xB6, 0xA8, 0xE1, 0x22,
729  0xF2, 0x42, 0xDA, 0xBB, 0x31, 0x2F, 0x3F, 0x63,
730  0x7A, 0x26, 0x21, 0x74, 0xD3, 0x1B, 0xF6, 0xB5,
731  0x85, 0xFF, 0xAE, 0x5B, 0x7A, 0x03, 0x5B, 0xF6,
732  0xF7, 0x1C, 0x35, 0xFD, 0xAD, 0x44, 0xCF, 0xD2,
733  0xD7, 0x4F, 0x92, 0x08, 0xBE, 0x25, 0x8F, 0xF3,
734  0x24, 0x94, 0x33, 0x28, 0xF6, 0x73, 0x29, 0xC0,
735  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
736  0x03, 0x04, 0x00,
737  0x02, 0x01, 0x00 }; /* y */
738 
739 static BOOLEAN loadDHKey( CRYPT_CONTEXT *cryptContext )
740  {
741  int status;
742 
743  /* Create the DH context */
744  status = cryptCreateContext( cryptContext, CRYPT_UNUSED, CRYPT_ALGO_DH );
745  if( cryptStatusError( status ) )
746  {
747  printf( "cryptCreateContext() failed with error code %d.\n",
748  status );
749  return( FALSE );
750  }
752  "DH key", strlen( "DH key" ) );
753  if( cryptStatusOK( status ) )
754  {
756 
757  setMessageData( &msgData, ( void * ) dh1024SPKI,
758  sizeof( dh1024SPKI ) );
759  status = cryptDeviceQueryCapability( *cryptContext, 1000,
760  ( CRYPT_QUERY_INFO * ) &msgData );
761  }
762  if( cryptStatusError( status ) )
763  {
764  printf( "DH key load failed, status = %d, line %d.\n", status,
765  __LINE__ );
766  return( FALSE );
767  }
768  return( TRUE );
769  }
770 
771 typedef struct {
772  const int nLen; const BYTE n[ 128 ];
773  const int eLen; const BYTE e[ 3 ];
774  const int dLen; const BYTE d[ 128 ];
775  const int pLen; const BYTE p[ 64 ];
776  const int qLen; const BYTE q[ 64 ];
777  const int uLen; const BYTE u[ 64 ];
778  const int e1Len; const BYTE e1[ 64 ];
779  const int e2Len; const BYTE e2[ 64 ];
780  } RSA_KEY;
781 
782 static const RSA_KEY rsa1024Key = {
783  /* n */
784  1024,
785  { 0x9C, 0x4D, 0x98, 0x18, 0x67, 0xF9, 0x45, 0xBC,
786  0xB6, 0x75, 0x53, 0x5D, 0x2C, 0xFA, 0x55, 0xE4,
787  0x51, 0x54, 0x9F, 0x0C, 0x16, 0xB1, 0xAF, 0x89,
788  0xF6, 0xF3, 0xE7, 0x78, 0xB1, 0x2B, 0x07, 0xFB,
789  0xDC, 0xDE, 0x64, 0x23, 0x34, 0x87, 0xDA, 0x0B,
790  0xE5, 0xB3, 0x17, 0x16, 0xA4, 0xE3, 0x7F, 0x23,
791  0xDF, 0x96, 0x16, 0x28, 0xA6, 0xD2, 0xF0, 0x0A,
792  0x59, 0xEE, 0x06, 0xB3, 0x76, 0x6C, 0x64, 0x19,
793  0xD9, 0x76, 0x41, 0x25, 0x66, 0xD1, 0x93, 0x51,
794  0x52, 0x06, 0x6B, 0x71, 0x50, 0x0E, 0xAB, 0x30,
795  0xA5, 0xC8, 0x41, 0xFC, 0x30, 0xBC, 0x32, 0xD7,
796  0x4B, 0x22, 0xF2, 0x45, 0x4C, 0x94, 0x68, 0xF1,
797  0x92, 0x8A, 0x4C, 0xF9, 0xD4, 0x5E, 0x87, 0x92,
798  0xA8, 0x54, 0x93, 0x92, 0x94, 0x48, 0xA4, 0xA3,
799  0xEE, 0x19, 0x7F, 0x6E, 0xD3, 0x14, 0xB1, 0x48,
800  0xCE, 0x93, 0xD1, 0xEA, 0x4C, 0xE1, 0x9D, 0xEF },
801 
802  /* e */
803  17,
804  { 0x01, 0x00, 0x01 },
805 
806  /* d */
807  1022,
808  { 0x37, 0xE2, 0x66, 0x67, 0x13, 0x85, 0xC4, 0xB1,
809  0x5C, 0x6B, 0x46, 0x8B, 0x21, 0xF1, 0xBF, 0x94,
810  0x0A, 0xA0, 0x3E, 0xDD, 0x8B, 0x9F, 0xAC, 0x2B,
811  0x9F, 0xE8, 0x44, 0xF2, 0x9A, 0x25, 0xD0, 0x8C,
812  0xF4, 0xC3, 0x6E, 0xFA, 0x47, 0x65, 0xEB, 0x48,
813  0x25, 0xB0, 0x8A, 0xA8, 0xC5, 0xFB, 0xB1, 0x11,
814  0x9A, 0x77, 0x87, 0x24, 0xB1, 0xC0, 0xE9, 0xA2,
815  0x49, 0xD5, 0x19, 0x00, 0x41, 0x6F, 0x2F, 0xBA,
816  0x9F, 0x28, 0x47, 0xF9, 0xB8, 0xBA, 0xFF, 0xF4,
817  0x8B, 0x20, 0xC9, 0xC9, 0x39, 0xAB, 0x52, 0x0E,
818  0x8A, 0x5A, 0xAF, 0xB3, 0xA3, 0x93, 0x4D, 0xBB,
819  0xFE, 0x62, 0x9B, 0x02, 0xCC, 0xA7, 0xB4, 0xAE,
820  0x86, 0x65, 0x88, 0x19, 0xD7, 0x44, 0xA7, 0xE4,
821  0x18, 0xB6, 0xCE, 0x01, 0xCD, 0xDF, 0x36, 0x81,
822  0xD5, 0xE1, 0x62, 0xF8, 0xD0, 0x27, 0xF1, 0x86,
823  0xA8, 0x58, 0xA7, 0xEB, 0x39, 0x79, 0x56, 0x41 },
824 
825  /* p */
826  512,
827  { 0xCF, 0xDA, 0xF9, 0x99, 0x6F, 0x05, 0x95, 0x84,
828  0x09, 0x90, 0xB3, 0xAB, 0x39, 0xB7, 0xDD, 0x1D,
829  0x7B, 0xFC, 0xFD, 0x10, 0x35, 0xA0, 0x18, 0x1D,
830  0x9A, 0x11, 0x30, 0x90, 0xD4, 0x3B, 0xF0, 0x5A,
831  0xC1, 0xA6, 0xF4, 0x53, 0xD0, 0x94, 0xA0, 0xED,
832  0xE0, 0xE4, 0xE0, 0x8E, 0x44, 0x18, 0x42, 0x42,
833  0xE1, 0x2C, 0x0D, 0xF7, 0x30, 0xE2, 0xB8, 0x09,
834  0x73, 0x50, 0x28, 0xF6, 0x55, 0x85, 0x57, 0x03 },
835 
836  /* q */
837  512,
838  { 0xC0, 0x81, 0xC4, 0x82, 0x6E, 0xF6, 0x1C, 0x92,
839  0x83, 0xEC, 0x17, 0xFB, 0x30, 0x98, 0xED, 0x6E,
840  0x89, 0x92, 0xB2, 0xA1, 0x21, 0x0D, 0xC1, 0x95,
841  0x49, 0x99, 0xD3, 0x79, 0xD3, 0xBD, 0x94, 0x93,
842  0xB9, 0x28, 0x68, 0xFF, 0xDE, 0xEB, 0xE8, 0xD2,
843  0x0B, 0xED, 0x7C, 0x08, 0xD0, 0xD5, 0x59, 0xE3,
844  0xC1, 0x76, 0xEA, 0xC1, 0xCD, 0xB6, 0x8B, 0x39,
845  0x4E, 0x29, 0x59, 0x5F, 0xFA, 0xCE, 0x83, 0xA5 },
846 
847  /* u */
848  511,
849  { 0x4B, 0x87, 0x97, 0x1F, 0x27, 0xED, 0xAA, 0xAF,
850  0x42, 0xF4, 0x57, 0x82, 0x3F, 0xEC, 0x80, 0xED,
851  0x1E, 0x91, 0xF8, 0xB4, 0x33, 0xDA, 0xEF, 0xC3,
852  0x03, 0x53, 0x0F, 0xCE, 0xB9, 0x5F, 0xE4, 0x29,
853  0xCC, 0xEE, 0x6A, 0x5E, 0x11, 0x0E, 0xFA, 0x66,
854  0x85, 0xDC, 0xFC, 0x48, 0x31, 0x0C, 0x00, 0x97,
855  0xC6, 0x0A, 0xF2, 0x34, 0x60, 0x6B, 0xF7, 0x68,
856  0x09, 0x4E, 0xCF, 0xB1, 0x9E, 0x33, 0x9A, 0x41 },
857 
858  /* exponent1 */
859  511,
860  { 0x6B, 0x2A, 0x0D, 0xF8, 0x22, 0x7A, 0x71, 0x8C,
861  0xE2, 0xD5, 0x9D, 0x1C, 0x91, 0xA4, 0x8F, 0x37,
862  0x0D, 0x5E, 0xF1, 0x26, 0x73, 0x4F, 0x78, 0x3F,
863  0x82, 0xD8, 0x8B, 0xFE, 0x8F, 0xBD, 0xDB, 0x7D,
864  0x1F, 0x4C, 0xB1, 0xB9, 0xA8, 0xD7, 0x88, 0x65,
865  0x3C, 0xC7, 0x24, 0x53, 0x95, 0x1E, 0x20, 0xC3,
866  0x94, 0x8E, 0x7F, 0x20, 0xCC, 0x2E, 0x88, 0x0E,
867  0x2F, 0x4A, 0xCB, 0xE3, 0xBD, 0x52, 0x02, 0xFB },
868 
869  /* exponent2 */
870  509,
871  { 0x10, 0x27, 0xD3, 0xD2, 0x0E, 0x75, 0xE1, 0x17,
872  0xFA, 0xB2, 0x49, 0xA0, 0xEF, 0x07, 0x26, 0x85,
873  0xEC, 0x4D, 0xBF, 0x67, 0xFE, 0x5A, 0x25, 0x30,
874  0xDE, 0x28, 0x66, 0xB3, 0x06, 0xAE, 0x16, 0x55,
875  0xFF, 0x68, 0x00, 0xC7, 0xD8, 0x71, 0x7B, 0xEC,
876  0x84, 0xCB, 0xBD, 0x69, 0x0F, 0xFD, 0x97, 0xB9,
877  0xA1, 0x76, 0xD5, 0x64, 0xC6, 0x5A, 0xD7, 0x7C,
878  0x4B, 0xAE, 0xF4, 0xAD, 0x35, 0x63, 0x37, 0x71 }
879  };
880 
881 static BOOLEAN loadRSAKey( const CRYPT_DEVICE cryptDevice,
882  CRYPT_CONTEXT *cryptContext,
883  CRYPT_CONTEXT *decryptContext )
884  {
885  CRYPT_PKCINFO_RSA *rsaKey;
886  const RSA_KEY *rsaKeyTemplate = &rsa1024Key;
887  const BOOLEAN isDevice = ( cryptDevice != CRYPT_UNUSED ) ? TRUE : FALSE;
888  int status;
889 
890  /* Allocate room for the public-key components */
891  if( ( rsaKey = ( CRYPT_PKCINFO_RSA * ) malloc( sizeof( CRYPT_PKCINFO_RSA ) ) ) == NULL )
892  return( CRYPT_ERROR_MEMORY );
893 
894  /* Create the encryption context */
895  if( cryptContext != NULL )
896  {
897  if( isDevice )
898  status = cryptDeviceCreateContext( cryptDevice, cryptContext,
899  CRYPT_ALGO_RSA );
900  else
901  status = cryptCreateContext( cryptContext, CRYPT_UNUSED,
902  CRYPT_ALGO_RSA );
903  if( cryptStatusError( status ) )
904  {
905  printf( "crypt%sCreateContext() failed with error code %d.\n",
906  isDevice ? "Device" : "", status );
907  return( FALSE );
908  }
910  "RSA public key", strlen( "RSA public key" ) );
912  cryptSetComponent( rsaKey->n, rsaKeyTemplate->n, rsaKeyTemplate->nLen );
913  cryptSetComponent( rsaKey->e, rsaKeyTemplate->e, rsaKeyTemplate->eLen );
914  status = cryptSetAttributeString( *cryptContext,
916  sizeof( CRYPT_PKCINFO_RSA ) );
917  cryptDestroyComponents( rsaKey );
918  if( cryptStatusError( status ) )
919  {
920  printf( "Key load failed with error code %d.\n", status );
921  return( FALSE );
922  }
923  if( decryptContext == NULL )
924  {
925  /* We're only using a public-key context, return */
926  free( rsaKey );
927  return( TRUE );
928  }
929  }
930 
931  /* Create the decryption context */
932  if( isDevice )
933  status = cryptDeviceCreateContext( cryptDevice, decryptContext,
934  CRYPT_ALGO_RSA );
935  else
936  status = cryptCreateContext( decryptContext, CRYPT_UNUSED,
937  CRYPT_ALGO_RSA );
938  if( cryptStatusError( status ) )
939  {
940  printf( "crypt%sCreateContext() failed with error code %d.\n",
941  isDevice ? "Device" : "", status );
942  return( FALSE );
943  }
945  "RSA private key", strlen( "RSA private key" ) );
947  cryptSetComponent( rsaKey->n, rsaKeyTemplate->n, rsaKeyTemplate->nLen );
948  cryptSetComponent( rsaKey->e, rsaKeyTemplate->e, rsaKeyTemplate->eLen );
949  cryptSetComponent( rsaKey->d, rsaKeyTemplate->d, rsaKeyTemplate->dLen );
950  cryptSetComponent( rsaKey->p, rsaKeyTemplate->p, rsaKeyTemplate->pLen );
951  cryptSetComponent( rsaKey->q, rsaKeyTemplate->q, rsaKeyTemplate->qLen );
952  cryptSetComponent( rsaKey->u, rsaKeyTemplate->u, rsaKeyTemplate->uLen );
953  cryptSetComponent( rsaKey->e1, rsaKeyTemplate->e1, rsaKeyTemplate->e1Len );
954  cryptSetComponent( rsaKey->e2, rsaKeyTemplate->e2, rsaKeyTemplate->e2Len );
955  status = cryptSetAttributeString( *decryptContext,
957  sizeof( CRYPT_PKCINFO_RSA ) );
958  cryptDestroyComponents( rsaKey );
959  free( rsaKey );
960  if( cryptStatusError( status ) )
961  {
962  printf( "Key load failed with error code %d.\n", status );
963  return( FALSE );
964  }
965 
966  return( TRUE );
967  }
968 
969 typedef struct {
970  const int pLen; const BYTE p[ 128 ];
971  const int qLen; const BYTE q[ 20 ];
972  const int gLen; const BYTE g[ 128 ];
973  const int xLen; const BYTE x[ 20 ];
974  const int yLen; const BYTE y[ 128 ];
975  } DLP_KEY;
976 
977 static const DLP_KEY dlp1024Key = {
978  /* p */
979  1024,
980  { 0x03, 0x16, 0x6D, 0x9C, 0x64, 0x0C, 0x65, 0x25,
981  0xDB, 0x73, 0xD0, 0x7D, 0x8B, 0xB2, 0x48, 0xD3,
982  0x70, 0x53, 0xE1, 0x68, 0x0C, 0x2E, 0x98, 0xF7,
983  0xD9, 0xCA, 0x72, 0x10, 0x03, 0x7C, 0x8D, 0x30,
984  0x02, 0xFB, 0xF2, 0xA1, 0x57, 0x61, 0x0B, 0xA0,
985  0x4A, 0x6D, 0x5B, 0x99, 0xCC, 0xB8, 0xD9, 0x0F,
986  0x9F, 0xD4, 0x3C, 0x67, 0x97, 0x35, 0xDE, 0x8D,
987  0x48, 0xE4, 0x7B, 0x7C, 0xEB, 0x69, 0xA4, 0x9F,
988  0x5C, 0x67, 0xA3, 0x6B, 0x27, 0x49, 0xF9, 0x98,
989  0x0D, 0x3B, 0x85, 0xBC, 0xEC, 0x33, 0x39, 0xB1,
990  0x86, 0xFF, 0xAF, 0x98, 0x34, 0x88, 0x30, 0xC3,
991  0x58, 0x62, 0x65, 0xE0, 0xE4, 0xDF, 0xC7, 0xD3,
992  0x2E, 0x36, 0x4F, 0x21, 0x7C, 0x35, 0x86, 0x59,
993  0x02, 0x3C, 0x0D, 0x94, 0x86, 0xC7, 0xC6, 0x59,
994  0x9C, 0x02, 0x66, 0x55, 0x68, 0x1A, 0x77, 0xD2,
995  0x00, 0x6B, 0x61, 0x41, 0x52, 0x26, 0x18, 0x6B },
996 
997  /* q */
998  160,
999  { 0xE8, 0x5A, 0x93, 0xE9, 0x4D, 0x15, 0xB5, 0x96,
1000  0x7E, 0xE3, 0x2A, 0x47, 0x8E, 0xD4, 0xAC, 0x72,
1001  0x3D, 0x82, 0xB6, 0x49 },
1002 
1003  /* g */
1004  1024,
1005  { 0x00, 0xA0, 0xED, 0xFF, 0x76, 0x7C, 0x99, 0xA3,
1006  0x43, 0x81, 0x12, 0x78, 0x0F, 0x3D, 0x60, 0xCA,
1007  0xA7, 0x5D, 0xA4, 0xCF, 0xC7, 0x45, 0xDE, 0x99,
1008  0xAF, 0x2F, 0x5A, 0xD2, 0x2B, 0xF1, 0x49, 0xC7,
1009  0x6E, 0xA4, 0x29, 0x78, 0xD7, 0xB1, 0xC0, 0x96,
1010  0x06, 0x3F, 0x0E, 0xD5, 0x83, 0xCB, 0x41, 0x47,
1011  0x91, 0xFD, 0x93, 0x7C, 0xBA, 0x9A, 0x08, 0xBA,
1012  0xF0, 0xFE, 0xFE, 0xE1, 0x32, 0x64, 0x14, 0x80,
1013  0x46, 0x21, 0xAD, 0x11, 0xC7, 0x99, 0x3A, 0xB5,
1014  0x2E, 0xA4, 0xAD, 0xBE, 0xE2, 0x5E, 0x51, 0x3D,
1015  0xBB, 0xEA, 0x43, 0x8F, 0x4E, 0x38, 0x4C, 0xDC,
1016  0x11, 0x4D, 0xE4, 0x4E, 0x40, 0x48, 0x38, 0x40,
1017  0x23, 0x38, 0xC5, 0x86, 0x0E, 0x7B, 0xF0, 0xC7,
1018  0x9B, 0xBC, 0x20, 0x7B, 0x2E, 0x27, 0x5D, 0x2A,
1019  0x10, 0x4A, 0x7E, 0x30, 0x45, 0x8C, 0x6F, 0x2C,
1020  0x77, 0x31, 0x54, 0xA4, 0xCF, 0xEC, 0x36, 0x83 },
1021 
1022  /* x */
1023  160,
1024  { 0xDF, 0x75, 0x2D, 0x11, 0x5F, 0xDB, 0xF9, 0x7A,
1025  0x6F, 0x3F, 0x46, 0xC2, 0xE5, 0xBA, 0x19, 0xF8,
1026  0xD8, 0x07, 0xEB, 0x7C },
1027 
1028  /* y */
1029  1024,
1030  { 0x01, 0xFE, 0x13, 0x25, 0xBB, 0xBE, 0xC8, 0xAA,
1031  0x81, 0x0A, 0x67, 0x12, 0xB9, 0x2D, 0xE3, 0xD4,
1032  0x3C, 0xCD, 0x85, 0x5C, 0x86, 0xD3, 0x9E, 0xB7,
1033  0xE6, 0x06, 0x09, 0xA2, 0x94, 0x2D, 0xB3, 0x50,
1034  0x59, 0x9F, 0x19, 0x2A, 0x60, 0xA3, 0xD9, 0xC0,
1035  0x61, 0xE4, 0x8D, 0x13, 0xE1, 0x84, 0xC9, 0x43,
1036  0x62, 0x26, 0x8E, 0xD7, 0x91, 0xDC, 0xBD, 0xAA,
1037  0x21, 0x03, 0xA7, 0x96, 0xF2, 0x8F, 0x2F, 0xBF,
1038  0x22, 0x67, 0xAB, 0x54, 0xB4, 0x8E, 0x76, 0xDC,
1039  0x64, 0xCF, 0x6D, 0x21, 0xDD, 0x9B, 0x41, 0x53,
1040  0x11, 0x48, 0x93, 0x12, 0x75, 0x75, 0x1B, 0x1F,
1041  0xDA, 0x2B, 0x8E, 0x5C, 0x75, 0xDC, 0x5C, 0x77,
1042  0xE7, 0xBE, 0x25, 0x6B, 0xB9, 0x9B, 0x5F, 0x63,
1043  0x11, 0xAF, 0x54, 0xEC, 0xFE, 0x08, 0xDE, 0x1E,
1044  0x4D, 0x38, 0xE3, 0x77, 0x26, 0x2C, 0xDB, 0xDB,
1045  0xAB, 0xC8, 0x60, 0x5F, 0x88, 0x5C, 0x98, 0xFE }
1046  };
1047 
1048 static BOOLEAN loadDSAKey( const CRYPT_DEVICE cryptDevice,
1051  {
1052  CRYPT_PKCINFO_DLP *dsaKey;
1053  const DLP_KEY *dlpKeyTemplate = &dlp1024Key;
1054  const BOOLEAN isDevice = ( cryptDevice != CRYPT_UNUSED ) ? TRUE : FALSE;
1055  int status;
1056 
1057  /* Allocate room for the public-key components */
1058  if( ( dsaKey = ( CRYPT_PKCINFO_DLP * ) malloc( sizeof( CRYPT_PKCINFO_DLP ) ) ) == NULL )
1059  return( CRYPT_ERROR_MEMORY );
1060 
1061  /* Create the encryption context */
1062  if( signContext != NULL )
1063  {
1064  if( isDevice )
1065  status = cryptDeviceCreateContext( cryptDevice, signContext,
1066  CRYPT_ALGO_DSA );
1067  else
1068  status = cryptCreateContext( signContext, CRYPT_UNUSED,
1069  CRYPT_ALGO_DSA );
1070  if( cryptStatusError( status ) )
1071  {
1072  printf( "crypt%sCreateContext() failed with error code %d.\n",
1073  isDevice ? "Device" : "", status );
1074  return( FALSE );
1075  }
1077  "DSA private key", strlen( "DSA private key" ) );
1079  cryptSetComponent( dsaKey->p, dlpKeyTemplate->p, dlpKeyTemplate->pLen );
1080  cryptSetComponent( dsaKey->q, dlpKeyTemplate->q, dlpKeyTemplate->qLen );
1081  cryptSetComponent( dsaKey->g, dlpKeyTemplate->g, dlpKeyTemplate->gLen );
1082  cryptSetComponent( dsaKey->x, dlpKeyTemplate->x, dlpKeyTemplate->xLen );
1083  cryptSetComponent( dsaKey->y, dlpKeyTemplate->y, dlpKeyTemplate->yLen );
1084  status = cryptSetAttributeString( *signContext,
1086  sizeof( CRYPT_PKCINFO_DLP ) );
1087  cryptDestroyComponents( dsaKey );
1088  if( cryptStatusError( status ) )
1089  {
1090  printf( "Key load failed with error code %d.\n", status );
1091  return( FALSE );
1092  }
1093  if( sigCheckContext == NULL )
1094  {
1095  /* We're only using a public-key context, return */
1096  free( dsaKey );
1097  return( TRUE );
1098  }
1099  }
1100 
1101  /* Create the decryption context */
1102  if( isDevice )
1103  status = cryptDeviceCreateContext( cryptDevice, sigCheckContext,
1104  CRYPT_ALGO_DSA );
1105  else
1106  status = cryptCreateContext( sigCheckContext, CRYPT_UNUSED,
1107  CRYPT_ALGO_DSA );
1108  if( cryptStatusError( status ) )
1109  {
1110  printf( "crypt%sCreateContext() failed with error code %d.\n",
1111  isDevice ? "Device" : "", status );
1112  return( FALSE );
1113  }
1114  cryptSetAttributeString( *sigCheckContext, CRYPT_CTXINFO_LABEL,
1115  "DSA public key", strlen( "DSA public key" ) );
1117  cryptSetComponent( dsaKey->p, dlpKeyTemplate->p, dlpKeyTemplate->pLen );
1118  cryptSetComponent( dsaKey->q, dlpKeyTemplate->q, dlpKeyTemplate->qLen );
1119  cryptSetComponent( dsaKey->g, dlpKeyTemplate->g, dlpKeyTemplate->gLen );
1120  cryptSetComponent( dsaKey->y, dlpKeyTemplate->y, dlpKeyTemplate->yLen );
1121  status = cryptSetAttributeString( *sigCheckContext,
1123  sizeof( CRYPT_PKCINFO_DLP ) );
1124  cryptDestroyComponents( dsaKey );
1125  free( dsaKey );
1126  if( cryptStatusError( status ) )
1127  {
1128  printf( "Key load failed with error code %d.\n", status );
1129  return( FALSE );
1130  }
1131 
1132  return( TRUE );
1133  }
1134 
1135 /* Time the RSA operation speed */
1136 
1137 static int encRSATest( const CRYPT_CONTEXT cryptContext,
1138  const CRYPT_CONTEXT decryptContext,
1139  HIRES_TIME times[] )
1140  {
1141  BYTE buffer[ CRYPT_MAX_PKCSIZE ];
1142  HIRES_TIME timeVal;
1143  int status;
1144 
1145  memset( buffer, '*', 128 );
1146  buffer[ 0 ] = 1;
1147  timeVal = timeDiff( 0 );
1148  status = cryptEncrypt( cryptContext, buffer, 128 );
1149  times[ 0 ] = timeDiff( timeVal );
1150  if( cryptStatusError( status ) )
1151  {
1152  printf( "Couldn't encrypt data, status = %d.\n", status );
1153  return( FALSE );
1154  }
1155  timeVal = timeDiff( 0 );
1156  status = cryptDecrypt( decryptContext, buffer, 128 );
1157  times[ 1 ] = timeDiff( timeVal );
1158  if( cryptStatusError( status ) )
1159  {
1160  printf( "Couldn't decrypt data, status = %d.\n", status );
1161  return( FALSE );
1162  }
1163  return( TRUE );
1164  }
1165 
1166 static BOOLEAN testRSA( long ticksPerSec )
1167  {
1168  CRYPT_CONTEXT cryptContext, decryptContext;
1169  HIRES_TIME times[ NO_TESTS + 1 ][ 8 ];
1170  int i;
1171 
1172  memset( times, 0, sizeof( times ) );
1173 
1174  /* Load the RSA keys */
1175  if( !loadRSAKey( CRYPT_UNUSED, &cryptContext, &decryptContext ) )
1176  return( FALSE );
1177 
1178  /* Encrypt and decrypt a test buffer */
1179  printf( "RSA 1024-bit " );
1180  for( i = 0; i < NO_TESTS + 1; i++ )
1181  {
1182  int status;
1183 
1184  status = encRSATest( cryptContext, decryptContext, times[ i ] );
1185  if( !status )
1186  return( FALSE );
1187  }
1188  printTimes( times, 2, ticksPerSec );
1189 
1190  /* Clean up */
1191  cryptDestroyContext( cryptContext );
1192  cryptDestroyContext( decryptContext );
1193 
1194  return( TRUE );
1195  }
1196 
1197 /* Time the DSA operation speed */
1198 
1199 static BOOLEAN testDSA( long ticksPerSec )
1200  {
1202  HIRES_TIME times[ NO_TESTS + 1 ][ 8 ];
1203  int i;
1204 
1205  memset( times, 0, sizeof( times ) );
1206 
1207  /* Load the DSA keys */
1208  if( !loadDSAKey( CRYPT_UNUSED, &signContext, &sigCheckContext ) )
1209  return( FALSE );
1210 
1211  /* Sign and verify a test buffer */
1212  printf( "DSA 1024-bit " );
1213  for( i = 0; i < NO_TESTS + 1; i++ )
1214  {
1215  DLP_PARAMS dlpParams;
1216  HIRES_TIME timeVal;
1217  BYTE buffer[ 128 ];
1218  int sigSize, status;
1219 
1220  /* Perform the test sign/sig.check */
1221  setDLPParams( &dlpParams, "********************", 20, buffer, 128 );
1222  timeVal = timeDiff( 0 );
1223  status = cryptDeviceQueryCapability( signContext, 1002,
1224  ( CRYPT_QUERY_INFO * ) &dlpParams );
1225  times[ i ][ 0 ] = timeDiff( timeVal );
1226  if( cryptStatusError( status ) )
1227  {
1228  printf( "Couldn't create DSA signature, status = %d.\n",
1229  status );
1230  return( FALSE );
1231  }
1232  sigSize = dlpParams.outLen;
1233 
1234  timeVal = timeDiff( 0 );
1235  setDLPParams( &dlpParams, "********************", 20, NULL, 0 );
1236  dlpParams.inParam2 = buffer;
1237  dlpParams.inLen2 = sigSize;
1238  status = cryptDeviceQueryCapability( sigCheckContext, 1003,
1239  ( CRYPT_QUERY_INFO * ) &dlpParams );
1240  times[ i ][ 1 ] = timeDiff( timeVal );
1241  if( cryptStatusError( status ) )
1242  {
1243  printf( "Couldn't verify DSA signature, status = %d.\n",
1244  status );
1245  return( FALSE );
1246  }
1247  }
1248  printTimes( times, 2, ticksPerSec );
1249 
1250  /* Clean up */
1251  cryptDestroyContext( signContext );
1252  cryptDestroyContext( sigCheckContext );
1253 
1254  return( TRUE );
1255  }
1256 
1257 /* Time the DH operation speed */
1258 
1259 static BOOLEAN testDH( long ticksPerSec )
1260  {
1262  HIRES_TIME times[ NO_TESTS + 1 ][ 8 ];
1263  int i;
1264 
1265  memset( times, 0, sizeof( times ) );
1266 
1267  printf( "DH 1024-bit " );
1268  for( i = 0; i < NO_TESTS + 1; i++ )
1269  {
1270  KEYAGREE_PARAMS keyAgreeParams;
1271  HIRES_TIME timeVal;
1272  int status;
1273 
1274  /* Load the DH key */
1275  if( !loadDHKey( &cryptContext ) )
1276  return( FALSE );
1277 
1278  /* Perform the DH key agreement */
1279  memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) );
1280  memset( keyAgreeParams.publicValue, '*', 128 );
1281  keyAgreeParams.publicValueLen = 128;
1282  timeVal = timeDiff( 0 );
1283  status = cryptDeviceQueryCapability( cryptContext, 1001,
1284  ( CRYPT_QUERY_INFO * ) &keyAgreeParams );
1285  times[ i ][ 0 ] = timeDiff( timeVal );
1286  if( cryptStatusError( status ) )
1287  {
1288  printf( "Couldn't perform DH key agreement, status = %d.\n",
1289  status );
1290  return( FALSE );
1291  }
1292 
1293  /* Clean up */
1294  cryptDestroyContext( cryptContext );
1295  }
1296  printTimes( times, 1, ticksPerSec );
1297 
1298  return( TRUE );
1299  }
1300 
1301 /****************************************************************************
1302 * *
1303 * Standalone Runtime Support *
1304 * *
1305 ****************************************************************************/
1306 
1307 /* Standalone main when we're not called from testlib.c */
1308 
1309 int main( int argc, char **argv )
1310  {
1312 #ifdef __WINDOWS__
1313  LARGE_INTEGER performanceCount;
1314 #endif /* __WINDOWS__ */
1315  long ticksPerSec;
1316  int status;
1317 
1318  /* Get rid of compiler warnings */
1319  if( argc || argv );
1320 
1321  /* Initialise cryptlib */
1322  status = cryptInit();
1323  if( cryptStatusError( status ) )
1324  {
1325  printf( "cryptInit() failed with error code %d.\n", status );
1326  exit( EXIT_FAILURE );
1327  }
1328 
1329  /* Try and bypass the randomness-handling by adding some junk (this only
1330  works in the Windows debug build), then ensure that the randomness-
1331  polling has completed by performing a blocking operation that
1332  requires randomness */
1333 #ifndef __WINDOWS__
1334  puts( "Forcing RNG reseed, this may take a few seconds..." );
1335 #endif /* __WINDOWS__ */
1336  cryptAddRandom( "xyzzy", 5 );
1337  cryptCreateContext( &cryptContext, CRYPT_UNUSED, CRYPT_ALGO_DES );
1338  cryptGenerateKey( cryptContext );
1339  cryptDestroyContext( cryptContext );
1340 
1341  printf( "Times given in clock ticks of frequency " );
1342 #ifdef __WINDOWS__
1343  QueryPerformanceFrequency( &performanceCount );
1344  ticksPerSec = performanceCount.LowPart;
1345  printf( "%ld", ticksPerSec );
1346 #else
1347  printf( "~1M" );
1348  ticksPerSec = 1000000;
1349 #endif /* __WINDOWS__ */
1350  printf( " ticks per second,\nresult rows are alignment offsets +0, "
1351  "+1, +4 with %d tests per result.\n\n", NO_TESTS );
1352 
1353  status = testDH( ticksPerSec );
1354  if( !status )
1355  {
1356  puts( " (Did you make the cryptapi.c changes described at the "
1357  "start of timings.c?)" );
1358  }
1359  testRSA( ticksPerSec );
1360  status = testDSA( ticksPerSec );
1361  if( !status )
1362  {
1363  puts( " (Did you make the cryptapi.c changes described at the "
1364  "start of timings.c?)" );
1365  }
1366  performanceTests( CRYPT_UNUSED, ticksPerSec );
1367 
1368  /* Clean up */
1369  cryptEnd();
1370  return( EXIT_SUCCESS );
1371  }
1372 #endif /* __WINDOWS__ || __UNIX__ */