home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / crypl200.zip / TESTLIB.C < prev    next >
Text File  |  1996-10-11  |  30KB  |  893 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "capi.h"
  5.  
  6. /* Define the following to enable/disable various blocks of tests */
  7.  
  8. #define TEST_LOWLEVEL        /* Test low-level functions */
  9. #define TEST_HIGHLEVEL        /* Test high-level functions */
  10. #define TEST_RANDOM            /* Test randomness functions */
  11.  
  12. /* Define the following to write the ASN.1-encoded cryptlib objects to disk
  13.    for analysis */
  14.  
  15. /*#define WRITE_OBJECTS    /**/
  16.  
  17. /* Various useful types.  These are also declared/defined in crypt.h, so we
  18.    use #defines in place of typedefs so we can undefine them before we
  19.    include crypt.h */
  20.  
  21. #define BOOLEAN    int
  22. #define BYTE    unsigned char
  23. #ifndef TRUE
  24.   #define FALSE    0
  25.   #define TRUE    !FALSE
  26. #endif /* TRUE */
  27.  
  28. /* The size of the test buffers */
  29.  
  30. #define TESTBUFFER_SIZE        256
  31.  
  32. /* The key size to use for the PKC routines */
  33.  
  34. #define PKC_KEYSIZE            512
  35.  
  36. /* There are a few OS's broken enough not to define the standard exit codes
  37.    (SunOS springs to mind) so we define some sort of equivalent here just
  38.    in case */
  39.  
  40. #ifndef EXIT_SUCCESS
  41.   #define EXIT_SUCCESS    0
  42.   #define EXIT_FAILURE    !EXIT_SUCCESS
  43. #endif /* EXIT_SUCCESS */
  44.  
  45. /* The output stream for the ASN.1-encoded cryptlib objects */
  46.  
  47. #ifdef WRITE_OBJECTS
  48.   static FILE *objectFile;
  49. #endif /* WRITE_OBJECTS */
  50.  
  51. /* Prototypes for functions in testhl.c */
  52.  
  53. int testDeriveKey( void );
  54. int testRandomRoutines( void );
  55. int testConventionalExportImport( void );
  56. int testKeyExportImport( void );
  57. int testSignData( void );
  58. int testKeyExchange( void );
  59. int testEncryptObject( void );
  60. int testSampleApp( void );
  61.  
  62. /* The key for testing the RSA implementation. This is the same 512-bit key
  63.    as the one used for the lib_rsa.c self-test.
  64.  
  65.    It would be nicer if we had a fixed encoded public key which we read in
  66.    via the keyset routines rather than using this messy indirect-loading,
  67.    but that would defeat the purpose of the self-test somewhat since it could
  68.    fail in the (rather complex) keyset access routines rather than in the RSA
  69.    code which is what we're really trying to test */
  70.  
  71. typedef struct {
  72.     int nLen; BYTE n[ 64 ];
  73.     int eLen; BYTE e[ 1 ];
  74.     int dLen; BYTE d[ 64 ];
  75.     int pLen; BYTE p[ 32 ];
  76.     int qLen; BYTE q[ 32 ];
  77.     int uLen; BYTE u[ 32 ];
  78.     int e1Len; BYTE e1[ 32 ];
  79.     int e2Len; BYTE e2[ 32 ];
  80.     } RSA_KEY;
  81.  
  82. static RSA_KEY rsaTestKey = {
  83.     /* n */
  84.     512,
  85.     { 0xE1, 0x95, 0x41, 0x17, 0xB4, 0xCB, 0xDC, 0xD0,
  86.       0xCB, 0x9B, 0x11, 0x19, 0x9C, 0xED, 0x04, 0x6F,
  87.       0xBD, 0x70, 0x2D, 0x5C, 0x8A, 0x32, 0xFF, 0x16,
  88.       0x22, 0x57, 0x30, 0x3B, 0xD4, 0x59, 0x9C, 0x01,
  89.       0xF0, 0xA3, 0x70, 0xA1, 0x6C, 0x16, 0xAC, 0xCC,
  90.       0x8C, 0xAD, 0xB0, 0xA0, 0xAF, 0xC7, 0xCC, 0x49,
  91.       0x4F, 0xD9, 0x5D, 0x32, 0x1C, 0x2A, 0xE8, 0x4E,
  92.       0x15, 0xE1, 0x26, 0x6C, 0xC4, 0xB8, 0x94, 0xE1 },
  93.     /* e */
  94.     5,
  95.     { 0x11 },
  96.     /* d */
  97.     509,
  98.     { 0x13, 0xE7, 0x85, 0xBE, 0x53, 0xB7, 0xA2, 0x8A,
  99.       0xE4, 0xC9, 0xEA, 0xEB, 0xAB, 0xF6, 0xCB, 0xAF,
  100.       0x81, 0xA8, 0x04, 0x00, 0xA2, 0xC8, 0x43, 0xAF,
  101.       0x21, 0x25, 0xCF, 0x8C, 0xCE, 0xF8, 0xD9, 0x0F,
  102.       0x10, 0x78, 0x4C, 0x1A, 0x26, 0x5D, 0x90, 0x18,
  103.       0x79, 0x90, 0x42, 0x83, 0x6E, 0xAE, 0x3E, 0x20,
  104.       0x0B, 0x0C, 0x5B, 0x6B, 0x8E, 0x31, 0xE5, 0xCF,
  105.       0xD6, 0xE0, 0xBB, 0x41, 0xC1, 0xB8, 0x2E, 0x17 },
  106.     /* p */
  107.     256,
  108.     { 0xED, 0xE4, 0x02, 0x90, 0xA4, 0xA4, 0x98, 0x0D,
  109.       0x45, 0xA2, 0xF3, 0x96, 0x09, 0xED, 0x7B, 0x40,
  110.       0xCD, 0xF6, 0x21, 0xCC, 0xC0, 0x1F, 0x83, 0x09,
  111.       0x56, 0x37, 0x97, 0xFB, 0x05, 0x5B, 0x87, 0xB7 },
  112.     /* q */
  113.     256,
  114.     { 0xF2, 0xC1, 0x64, 0xE8, 0x69, 0xF8, 0x5E, 0x54,
  115.       0x8F, 0xFD, 0x20, 0x8E, 0x6A, 0x23, 0x90, 0xF2, 
  116.       0xAF, 0x57, 0x2F, 0x4D, 0x10, 0x80, 0x8E, 0x11,
  117.       0x3C, 0x61, 0x44, 0x33, 0x2B, 0xE0, 0x58, 0x27 },
  118.     /* u */
  119.     255,
  120.     { 0x68, 0x45, 0x00, 0x64, 0x32, 0x9D, 0x09, 0x6E,
  121.       0x0A, 0xD3, 0xF3, 0x8A, 0xFE, 0x15, 0x8C, 0x79,
  122.       0xAD, 0x84, 0x35, 0x05, 0x19, 0x2C, 0x19, 0x51,
  123.       0xAB, 0x83, 0xC7, 0xE8, 0x5C, 0xAC, 0xAD, 0x7A },
  124.     /* exponent1 */
  125.     256,
  126.     { 0x99, 0xED, 0xE3, 0x8A, 0xC4, 0xE2, 0xF8, 0xF9,
  127.       0x87, 0x69, 0x70, 0x70, 0x24, 0x8A, 0x9B, 0x0B,
  128.       0xD0, 0x90, 0x33, 0xFC, 0xF4, 0xC9, 0x18, 0x8D,
  129.       0x92, 0x23, 0xF8, 0xED, 0xB8, 0x2C, 0x2A, 0xA3 },
  130.     /* exponent2 */
  131.     256,
  132.     { 0xB9, 0xA2, 0xF2, 0xCF, 0xD8, 0x90, 0xC0, 0x9B,
  133.       0x04, 0xB2, 0x82, 0x4E, 0xC9, 0xA2, 0xBA, 0x22,
  134.       0xFE, 0x8D, 0xF6, 0xFE, 0xB2, 0x44, 0x30, 0x67,
  135.       0x88, 0x86, 0x9D, 0x90, 0x8A, 0xF6, 0xD9, 0xFF }
  136.     };
  137.  
  138. /* There are some sizeable (for DOS) data structures used, so we increase the
  139.    stack size to allow for them */
  140.  
  141. #ifdef __MSDOS__
  142.   extern unsigned _stklen = 16384;
  143. #endif /* __MSDOS__ */
  144.  
  145. /****************************************************************************
  146. *                                                                            *
  147. *                                Utility Routines                            *
  148. *                                                                            *
  149. ****************************************************************************/
  150.  
  151. /* Work routines: Set a pair of encrypt/decrypt buffers to a known state,
  152.    and make sure they're still in that known state */
  153.  
  154. static void initTestBuffers( BYTE *buffer1, BYTE *buffer2 )
  155.     {
  156.     /* Set the buffers to a known state */
  157.     memset( buffer1, '*', TESTBUFFER_SIZE );
  158.     memcpy( buffer1, "12345678", 8 );        /* For endianness check */
  159.     memcpy( buffer2, buffer1, TESTBUFFER_SIZE );
  160.     }
  161.  
  162. static void checkTestBuffers( BYTE *buffer1, BYTE *buffer2 )
  163.     {
  164.     /* Make sure everything went OK */
  165.     if( memcmp( buffer1, buffer2, TESTBUFFER_SIZE ) )
  166.         {
  167.         puts( "Error: Decrypted data != original plaintext." );
  168.  
  169.         /* Try and guess at block chaining problems */
  170.         if( !memcmp( buffer1, "12345678****", 12 ) )
  171.             puts( "\t\bIt looks like there's a problem with block chaining." );
  172.         else
  173.             /* Try and guess at endianness problems - we want "1234" */
  174.             if( !memcmp( buffer1, "4321", 4 ) )
  175.                 puts( "\t\bIt looks like the 32-bit word endianness is "
  176.                       "reversed." );
  177.             else
  178.                 if( !memcmp( buffer1, "2143", 4 ) )
  179.                     puts( "\t\bIt looks like the 16-bit word endianness is "
  180.                           "reversed." );
  181.             else
  182.                 if( buffer1[ 0 ] >= '1' && buffer1[ 0 ] <= '9' )
  183.                     puts( "\t\bIt looks like there's some sort of endianness "
  184.                           "problem which is\n\t more complex than just a "
  185.                           "reversal." );
  186.                 else
  187.                     puts( "\t\bIt's probably more than just an endianness "
  188.                           "problem." );
  189.         }
  190.     }
  191.  
  192. /* Report information on the encryption algorithm */
  193.  
  194. static void reportAlgorithmInformation( CRYPT_QUERY_INFO *cryptQueryInfo )
  195.     {
  196.     char speedFactor[ 50 ];
  197.  
  198.     /* Determine the speed factor relative to a block copy */
  199.     if( cryptQueryInfo->speed == CRYPT_ERROR )
  200.         strcpy( speedFactor, "unknown speed factor" );
  201.     else
  202.         sprintf( speedFactor, "0.%03d times the speed of a block copy",
  203.                  cryptQueryInfo->speed );
  204.  
  205.     printf( "algorithm %s/%s is available with\n",
  206.             cryptQueryInfo->algoName, cryptQueryInfo->modeName );
  207.     printf(    "  name `%s', block size %d bits, %s,\n"
  208.             "  min keysize %d bits, recommended keysize %d bits, "
  209.                 "max keysize %d bits,\n"
  210.             "  min IV size %d bits, recommended IV size %d bits, "
  211.                 "max IV size %d bits.\n",
  212.             cryptQueryInfo->algoName,
  213.             bytesToBits( cryptQueryInfo->blockSize ), speedFactor,
  214.             bytesToBits( cryptQueryInfo->minKeySize ),
  215.             bytesToBits( cryptQueryInfo->keySize ),
  216.             bytesToBits( cryptQueryInfo->maxKeySize ),
  217.             bytesToBits( cryptQueryInfo->minIVsize ),
  218.             bytesToBits( cryptQueryInfo->ivSize ),
  219.             bytesToBits( cryptQueryInfo->maxIVsize ) );
  220.     }
  221.  
  222. /* Check the library for an algorithm/mode */
  223.  
  224. static BOOLEAN checkLibraryInfo( CRYPT_ALGO cryptAlgo, CRYPT_MODE cryptMode )
  225.     {
  226.     CRYPT_QUERY_INFO cryptQueryInfo;
  227.     int status;
  228.  
  229.     status = cryptModeAvailable( cryptAlgo, cryptMode );
  230.     if( cryptStatusError( status ) )
  231.         {
  232.         printf( "cryptModeAvailable() reports algorithm %d, mode %d is not "
  233.                 "available: Code %d.\n", cryptAlgo, cryptMode, status );
  234.         return( FALSE );
  235.         }
  236.     status = cryptQueryAlgoMode( cryptAlgo, cryptMode, &cryptQueryInfo );
  237.     printf( "cryptQueryMode() reports " );
  238.     if( cryptStatusOK( status ) )
  239.         reportAlgorithmInformation( &cryptQueryInfo );
  240.     else
  241.         {
  242.         printf( "no information available on algorithm %d, mode %d: Code %d.\n",
  243.                 cryptAlgo, cryptMode, status );
  244.         return( FALSE );
  245.         }
  246.  
  247.     return( TRUE );
  248.     }
  249.  
  250. /* Load the encryption contexts */
  251.  
  252. static BOOLEAN loadContexts( CRYPT_CONTEXT *cryptContext, CRYPT_CONTEXT *decryptContext,
  253.                              CRYPT_ALGO cryptAlgo, CRYPT_MODE cryptMode,
  254.                              BYTE *key, int length )
  255.     {
  256.     int status;
  257.  
  258.     /* Create the encryption context */
  259.     status = cryptCreateContext( cryptContext, cryptAlgo, cryptMode );
  260.     if( cryptStatusError( status ) )
  261.         {
  262.         printf( "cryptCreateContext() failed with error code %d.\n", status );
  263.         return( FALSE );
  264.         }
  265.     if( cryptMode != CRYPT_MODE_NONE )
  266.         {
  267.         status = cryptLoadContext( *cryptContext, key, length );
  268.         if( cryptStatusError( status ) )
  269.             {
  270.             printf( "cryptLoadContext() failed with error code %d.\n", status );
  271.             return( FALSE );
  272.             }
  273.         }
  274.  
  275.     /* Create the decryption context */
  276.     status = cryptCreateContext( decryptContext, cryptAlgo, cryptMode );
  277.     if( cryptStatusError( status ) )
  278.         {
  279.         printf( "cryptCreateContext() failed with error code %d.\n", status );
  280.         return( FALSE );
  281.         }
  282.     if( cryptMode != CRYPT_MODE_NONE )
  283.         {
  284.         status = cryptLoadContext( *decryptContext, key, length );
  285.         if( cryptStatusError( status ) )
  286.             {
  287.             printf( "cryptLoadContext() failed with error code %d.\n", status );
  288.             return( FALSE );
  289.             }
  290.         }
  291.  
  292.     return( TRUE );
  293.     }
  294.  
  295. /* Load RSA PKC encrytion contexts */
  296.  
  297. BOOLEAN loadRSAContexts( CRYPT_CONTEXT *cryptContext,
  298.                          CRYPT_CONTEXT *decryptContext )
  299.     {
  300.     CRYPT_PKCINFO_RSA *rsaKey;
  301.     int status;
  302.  
  303.     /* Allocate room for the public-key components */
  304.     if( ( rsaKey = ( CRYPT_PKCINFO_RSA * ) malloc( sizeof( CRYPT_PKCINFO_RSA ) ) ) == NULL )
  305.         return( CRYPT_NOMEM );
  306.  
  307.     /* Create the encryption context */
  308.     status = cryptCreateContext( cryptContext, CRYPT_ALGO_RSA, CRYPT_MODE_PKC );
  309.     if( cryptStatusError( status ) )
  310.         {
  311.         free( rsaKey );
  312.         printf( "cryptCreateContext() failed with error code %d.\n", status );
  313.         return( FALSE );
  314.         }
  315.     cryptInitComponents( rsaKey, CRYPT_COMPONENTS_BIGENDIAN,
  316.                          CRYPT_KEYTYPE_PUBLIC );
  317.     cryptSetComponent( rsaKey->n, rsaTestKey.n, rsaTestKey.nLen );
  318.     cryptSetComponent( rsaKey->e, rsaTestKey.e, rsaTestKey.eLen );
  319.     status = cryptLoadContext( *cryptContext, rsaKey, CRYPT_UNUSED );
  320.     cryptDestroyComponents( rsaKey );
  321.     if( cryptStatusError( status ) )
  322.         {
  323.         free( rsaKey );
  324.         cryptDestroyContext( *cryptContext );
  325.         printf( "cryptLoadContext() failed with error code %d.\n", status );
  326.         return( FALSE );
  327.         }
  328.  
  329.     /* Create the decryption context */
  330.     status = cryptCreateContext( decryptContext, CRYPT_ALGO_RSA, CRYPT_MODE_PKC );
  331.     if( cryptStatusError( status ) )
  332.         {
  333.         free( rsaKey );
  334.         cryptDestroyContext( *cryptContext );
  335.         printf( "cryptCreateContext() failed with error code %d.\n", status );
  336.         return( FALSE );
  337.         }
  338.     cryptInitComponents( rsaKey, CRYPT_COMPONENTS_BIGENDIAN,
  339.                          CRYPT_KEYTYPE_PRIVATE );
  340.     cryptSetComponent( rsaKey->n, rsaTestKey.n, rsaTestKey.nLen );
  341.     cryptSetComponent( rsaKey->e, rsaTestKey.e, rsaTestKey.eLen );
  342.     cryptSetComponent( rsaKey->d, rsaTestKey.d, rsaTestKey.dLen );
  343.     cryptSetComponent( rsaKey->p, rsaTestKey.p, rsaTestKey.pLen );
  344.     cryptSetComponent( rsaKey->q, rsaTestKey.q, rsaTestKey.qLen );
  345.     cryptSetComponent( rsaKey->u, rsaTestKey.u, rsaTestKey.uLen );
  346.     cryptSetComponent( rsaKey->e1, rsaTestKey.e1, rsaTestKey.e1Len );
  347.     cryptSetComponent( rsaKey->e2, rsaTestKey.e2, rsaTestKey.e2Len );
  348.     status = cryptLoadContext( *decryptContext, rsaKey, CRYPT_UNUSED );
  349.     cryptDestroyComponents( rsaKey );
  350.     free( rsaKey );
  351.     if( cryptStatusError( status ) )
  352.         {
  353.         cryptDestroyContext( *cryptContext );
  354.         cryptDestroyContext( *decryptContext );
  355.         printf( "cryptLoadContext() failed with error code %d.\n", status );
  356.         return( FALSE );
  357.         }
  358.  
  359.     return( TRUE );
  360.     }
  361.  
  362. /* Load Diffie-Hellman encrytion contexts */
  363.  
  364. BOOLEAN loadDHContexts( CRYPT_CONTEXT *cryptContext1,
  365.                         CRYPT_CONTEXT *cryptContext2, int keySize )
  366.     {
  367.     CRYPT_PKCINFO_DH *dhKey;
  368.     int status;
  369.  
  370.     /* Allocate room for the public-key components */
  371.     if( ( dhKey = ( CRYPT_PKCINFO_DH * ) malloc( sizeof( CRYPT_PKCINFO_DH ) ) ) == NULL )
  372.         return( CRYPT_NOMEM );
  373.  
  374.     /* Create the first encryption context */
  375.     status = cryptCreateContext( cryptContext1, CRYPT_ALGO_DH, CRYPT_MODE_PKC );
  376.     if( cryptStatusError( status ) )
  377.         {
  378.         free( dhKey );
  379.         printf( "cryptCreateContext() failed with error code %d.\n", status );
  380.         return( FALSE );
  381.         }
  382.     cryptInitComponents( dhKey, keySize, CRYPT_UNUSED );
  383.     status = cryptLoadContext( *cryptContext1, dhKey, CRYPT_UNUSED );
  384.     cryptDestroyComponents( dhKey );
  385.     if( cryptStatusError( status ) )
  386.         {
  387.         free( dhKey );
  388.         printf( "cryptLoadContext() failed with error code %d.\n", status );
  389.         return( FALSE );
  390.         }
  391.  
  392.     /* Create the second encryption context */
  393.     status = cryptCreateContext( cryptContext2, CRYPT_ALGO_DH, CRYPT_MODE_PKC );
  394.     if( cryptStatusError( status ) )
  395.         {
  396.         free( dhKey );
  397.         printf( "cryptCreateContext() failed with error code %d.\n", status );
  398.         return( FALSE );
  399.         }
  400.     cryptInitComponents( dhKey, keySize, CRYPT_UNUSED );
  401.     status = cryptLoadContext( *cryptContext2, dhKey, CRYPT_UNUSED );
  402.     cryptDestroyComponents( dhKey );
  403.     if( cryptStatusError( status ) )
  404.         {
  405.         free( dhKey );
  406.         printf( "cryptLoadContext() failed with error code %d.\n", status );
  407.         return( FALSE );
  408.         }
  409.  
  410.     return( TRUE );
  411.     }
  412.  
  413. /****************************************************************************
  414. *                                                                            *
  415. *                            Low-level Routines Test                            *
  416. *                                                                            *
  417. ****************************************************************************/
  418.  
  419. /* Perform a test en/decryption */
  420.  
  421. static void testCrypt( CRYPT_CONTEXT cryptContext, CRYPT_CONTEXT decryptContext,
  422.                        BYTE *buffer )
  423.     {
  424.     CRYPT_QUERY_INFO cryptQueryInfo;
  425.     BYTE iv[ CRYPT_MAX_IVSIZE ];
  426.     int status;
  427.  
  428.     /* Find out about the algorithm we're using */
  429.     cryptQueryContext( cryptContext, &cryptQueryInfo );
  430.     if( cryptQueryInfo.cryptMode == CRYPT_MODE_CFB ||
  431.         cryptQueryInfo.cryptMode == CRYPT_MODE_OFB ||
  432.         cryptQueryInfo.cryptMode == CRYPT_MODE_STREAM )
  433.         {
  434.         /* Encrypt the buffer in two odd-sized chunks */
  435.         status = cryptEncrypt( cryptContext, buffer, 79 );
  436.         if( cryptStatusError( status ) )
  437.             printf( "Couldn't encrypt data: Code %d.\n", status );
  438.         status = cryptEncrypt( cryptContext, buffer + 79, TESTBUFFER_SIZE - 79 );
  439.         if( cryptStatusError( status ) )
  440.             printf( "Couldn't encrypt data: Code %d.\n", status );
  441.  
  442.         /* Copy the IV from the encryption to the decryption context if
  443.            necessary */
  444.         if( cryptQueryInfo.cryptMode != CRYPT_MODE_STREAM )
  445.             {
  446.             status = cryptRetrieveIV( cryptContext, iv );
  447.             if( cryptStatusError( status ) )
  448.                 printf( "Couldn't retrieve IV after encryption: Code %d.\n",
  449.                         status );
  450.             status = cryptLoadIV( decryptContext, iv, cryptQueryInfo.ivSize );
  451.             if( cryptStatusError( status ) )
  452.                 printf( "Couldn't load IV for decryption: Code %d.\n", status );
  453.             }
  454.  
  455.         /* Decrypt the buffer in different odd-size chunks */
  456.         status = cryptDecrypt( decryptContext, buffer, 125 );
  457.         if( cryptStatusError( status ) )
  458.             printf( "Couldn't decrypt data: Code %d.\n", status );
  459.         status = cryptDecrypt( decryptContext, buffer + 125, TESTBUFFER_SIZE - 125 );
  460.         if( cryptStatusError( status ) )
  461.             printf( "Couldn't decrypt data: Code %d.\n", status );
  462.  
  463.         return;
  464.         }
  465.     if( cryptQueryInfo.cryptMode == CRYPT_MODE_ECB ||
  466.         cryptQueryInfo.cryptMode == CRYPT_MODE_CBC ||
  467.         cryptQueryInfo.cryptMode == CRYPT_MODE_PCBC )
  468.         {
  469.         /* Encrypt the buffer in two odd-sized chunks */
  470.         status = cryptEncrypt( cryptContext, buffer, 80 );
  471.         if( cryptStatusError( status ) )
  472.             printf( "Couldn't encrypt data: Code %d.\n", status );
  473.         status = cryptEncrypt( cryptContext, buffer + 80, TESTBUFFER_SIZE - 80 );
  474.         if( cryptStatusError( status ) )
  475.             printf( "Couldn't encrypt data: Code %d.\n", status );
  476.         status = cryptEncrypt( cryptContext, buffer + TESTBUFFER_SIZE, 0 );
  477.  
  478.         /* Copy the IV from the encryption to the decryption context if
  479.            necessary */
  480.         if( cryptQueryInfo.cryptMode != CRYPT_MODE_ECB )
  481.             {
  482.             status = cryptRetrieveIV( cryptContext, iv );
  483.             if( cryptStatusError( status ) )
  484.                 printf( "Couldn't retrieve IV after encryption: Code %d.\n",
  485.                         status );
  486.             status = cryptLoadIV( decryptContext, iv, cryptQueryInfo.ivSize );
  487.             if( cryptStatusError( status ) )
  488.                 printf( "Couldn't load IV for decryption: Code %d.\n", status );
  489.             status = cryptEncrypt( cryptContext, buffer + TESTBUFFER_SIZE, 0 );
  490.             }
  491.  
  492.         /* Decrypt the buffer in different odd-size chunks */
  493.         status = cryptDecrypt( decryptContext, buffer, 128 );
  494.         if( cryptStatusError( status ) )
  495.             printf( "Couldn't decrypt data: Code %d.\n", status );
  496.         status = cryptDecrypt( decryptContext, buffer + 128, TESTBUFFER_SIZE - 128 );
  497.         if( cryptStatusError( status ) )
  498.             printf( "Couldn't decrypt data: Code %d.\n", status );
  499.         status = cryptDecrypt( decryptContext, buffer + TESTBUFFER_SIZE, 0 );
  500.  
  501.         return;
  502.         }
  503.     if( cryptQueryInfo.cryptMode == CRYPT_MODE_PKC )
  504.         {
  505.         /* To ensure that the magnitude of the integer corresponding to the
  506.            data to be encrypted is less than the modulus, we set the first
  507.            byte of the buffer to 0.  This is only necessary for this test code
  508.            which uses a set pattern for its test data and wouldn't normally be
  509.            necessary */
  510.         int ch = buffer[ 0 ];
  511.  
  512.         /* Since the PKC algorithms only handle a single block, we only
  513.            perform a single encrypt and decrypt operation */
  514.         buffer[ 0 ] = 0;
  515.         status = cryptEncrypt( cryptContext, buffer, CRYPT_USE_DEFAULT );
  516.         if( cryptStatusError( status ) )
  517.             printf( "Couldn't encrypt data: Code %d.\n", status );
  518.         status = cryptDecrypt( decryptContext, buffer, CRYPT_USE_DEFAULT );
  519.         if( cryptStatusError( status ) )
  520.             printf( "Couldn't decrypt data: Code %d.\n", status );
  521.         buffer[ 0 ] = ch;
  522.         return;
  523.         }
  524.     if( cryptQueryInfo.cryptMode == CRYPT_MODE_NONE )
  525.         {
  526.         /* Hash the buffer in two odd-sized chunks */
  527.         status = cryptEncrypt( cryptContext, buffer, 80 );
  528.         if( cryptStatusError( status ) )
  529.             printf( "Couldn't hash data: Code %d.\n", status );
  530.         status = cryptEncrypt( cryptContext, buffer + 80, TESTBUFFER_SIZE - 80 );
  531.         if( cryptStatusError( status ) )
  532.             printf( "Couldn't hash data: Code %d.\n", status );
  533.         status = cryptEncrypt( cryptContext, buffer + TESTBUFFER_SIZE, 0 );
  534.  
  535.         /* Hash the buffer in different odd-size chunks */
  536.         status = cryptEncrypt( decryptContext, buffer, 128 );
  537.         if( cryptStatusError( status ) )
  538.             printf( "Couldn't hash data: Code %d.\n", status );
  539.         status = cryptEncrypt( decryptContext, buffer + 128, TESTBUFFER_SIZE - 128 );
  540.         if( cryptStatusError( status ) )
  541.             printf( "Couldn't hash data: Code %d.\n", status );
  542.         status = cryptEncrypt( decryptContext, buffer + TESTBUFFER_SIZE, 0 );
  543.  
  544.         return;
  545.         }
  546.  
  547.     puts( "Unknown encryption mode found in test code." );
  548.     }
  549.  
  550. /* Destroy the encryption contexts */
  551.  
  552. void destroyContexts( CRYPT_CONTEXT cryptContext, CRYPT_CONTEXT decryptContext )
  553.     {
  554.     int status;
  555.  
  556.     status = cryptDestroyContext( cryptContext );
  557.     if( cryptStatusError( status ) )
  558.         printf( "cryptDestroyContext() failed with error code %d.\n", status );
  559.     status = cryptDestroyContext( decryptContext );
  560.     if( cryptStatusError( status ) )
  561.         printf( "cryptDestroyContext() failed with error code %d.\n", status );
  562.     }
  563.  
  564. /* Sample code to test an algorithm/mode implementation */
  565.  
  566. static int testLibrary( CRYPT_ALGO cryptAlgo, CRYPT_MODE cryptMode )
  567.     {
  568.     BYTE buffer[ TESTBUFFER_SIZE ], testBuffer[ TESTBUFFER_SIZE ];
  569.     CRYPT_CONTEXT cryptContext, decryptContext;
  570.     CRYPT_INFO_MDCSHS cryptInfoEx;
  571.     CRYPT_QUERY_INFO cryptQueryInfo, decryptQueryInfo;
  572.     int status;
  573.  
  574.     /* Initialise the test buffers */
  575.     initTestBuffers( buffer, testBuffer );
  576.  
  577.     /* Check the capabilities of the library */
  578.     if( !checkLibraryInfo( cryptAlgo, cryptMode ) )
  579.         return( FALSE );
  580.  
  581.     /* Since DH only performs a key agreement rather than a true key
  582.        exchange and DSA is a bit unusual (it returns a struct with two
  583.        bignums rather than encrypting a buffer), we can't test their
  584.        encryption capabilities */
  585.     if( cryptAlgo == CRYPT_ALGO_DH || cryptAlgo == CRYPT_ALGO_DSA )
  586.         return( TRUE );
  587.  
  588.     /* Set up an encryption context, load a user key into it, and perform a
  589.        key setup */
  590.     switch( cryptAlgo )
  591.         {
  592.         case CRYPT_ALGO_MDCSHS:
  593.             /* We use an extended setup with reduced iteration count for
  594.                people who have to run this thing 2000 times while debugging */
  595.             cryptInfoEx.keySetupIterations = 10;
  596.             status = cryptCreateContextEx( &cryptContext, cryptAlgo, cryptMode,
  597.                                            &cryptInfoEx );
  598.             if( cryptStatusError( status ) )
  599.                 {
  600.                 printf( "cryptCreateContext() failed with error code %d.\n",
  601.                         status );
  602.                 return( FALSE );
  603.                 }
  604.             status = cryptLoadContext( cryptContext, "Test key", 8 );
  605.             if( cryptStatusError( status ) )
  606.                 {
  607.                 printf( "cryptLoadContext() failed with error code %d.\n",
  608.                         status );
  609.                 return( FALSE );
  610.                 }
  611.  
  612.             /* Create another crypt context for decryption.  The error
  613.                checking here is a bit less picky to save space */
  614.             cryptInfoEx.keySetupIterations = 10;
  615.             cryptCreateContextEx( &decryptContext, cryptAlgo, cryptMode,
  616.                                   &cryptInfoEx );
  617.             status = cryptLoadContext( decryptContext, "Test key", 8 );
  618.             if( cryptStatusError( status ) )
  619.                 {
  620.                 printf( "cryptLoadContext() failed with error code %d.\n",
  621.                         status );
  622.                 return( FALSE );
  623.                 }
  624.             break;
  625.  
  626.         case CRYPT_ALGO_DES:
  627.             if( !loadContexts( &cryptContext, &decryptContext, cryptAlgo, cryptMode,
  628.                                ( BYTE * ) "12345678", 8 ) )
  629.                 return( FALSE );
  630.             break;
  631.  
  632.         case CRYPT_ALGO_3DES:
  633.         case CRYPT_ALGO_IDEA:
  634.         case CRYPT_ALGO_SAFER:
  635.             if( !loadContexts( &cryptContext, &decryptContext, cryptAlgo, cryptMode,
  636.                                ( BYTE * ) "1234567887654321", 16 ) )
  637.                 return( FALSE );
  638.             break;
  639.  
  640.         case CRYPT_ALGO_RC2:
  641.         case CRYPT_ALGO_RC4:
  642.         case CRYPT_ALGO_RC5:
  643.         case CRYPT_ALGO_BLOWFISH:
  644.             if( !loadContexts( &cryptContext, &decryptContext, cryptAlgo, cryptMode,
  645.                                ( BYTE * ) "1234567890098765432112345678900987654321", 40 ) )
  646.                 return( FALSE );
  647.             break;
  648.  
  649.         case CRYPT_ALGO_MD2:
  650.         case CRYPT_ALGO_MD4:
  651.         case CRYPT_ALGO_MD5:
  652.         case CRYPT_ALGO_RIPEMD160:
  653.         case CRYPT_ALGO_SHA:
  654.             if( !loadContexts( &cryptContext, &decryptContext, cryptAlgo, cryptMode,
  655.                                ( BYTE * ) "", 0 ) )
  656.                 return( FALSE );
  657.             break;
  658.  
  659.         case CRYPT_ALGO_RSA:
  660.             if( !loadRSAContexts( &cryptContext, &decryptContext ) )
  661.                 return( FALSE );
  662.             break;
  663.  
  664.         default:
  665.             printf( "Unknown encryption algorithm = ID %d, cannot perform "
  666.                     "encryption test\n", cryptAlgo );
  667.             return( FALSE );
  668.         }
  669.  
  670.     /* Perform a test en/decryption */
  671.     testCrypt( cryptContext, decryptContext, buffer );
  672.  
  673.     /* Make sure everything went OK */
  674.     if( ( status = cryptQueryContext( cryptContext, &cryptQueryInfo ) ) == CRYPT_OK )
  675.         status = cryptQueryContext( decryptContext, &decryptQueryInfo );
  676.     if( cryptQueryInfo.cryptMode == CRYPT_MODE_NONE )
  677.         {
  678.         if( cryptStatusError( status ) )
  679.             printf( "Couldn't get hash information: Code %d\n", status );
  680.         else
  681.             if( memcmp( cryptQueryInfo.hashValue, decryptQueryInfo.hashValue, \
  682.                         cryptQueryInfo.blockSize ) )
  683.                 puts( "Error: Hash value of identical buffers differs." );
  684.         }
  685.     else
  686.         checkTestBuffers( buffer, testBuffer );
  687.  
  688.     /* Clean up */
  689.     destroyContexts( cryptContext, decryptContext );
  690.     return( TRUE );
  691.     }
  692.  
  693. /****************************************************************************
  694. *                                                                            *
  695. *                                Main Test Code                                *
  696. *                                                                            *
  697. ****************************************************************************/
  698.  
  699. #if defined( _WINDOWS ) || defined( WIN32 ) || defined( _WIN32 )
  700.   #define __WINDOWS__
  701.   #define INC_CHILD
  702. #endif /* _WINDOWS || WIN32 || _WIN32 */
  703.  
  704. /* Exercise various aspects of the encryption library */
  705.  
  706. int main( int argc, char **argv )
  707.     {
  708. #ifdef TEST_LOWLEVEL
  709.     CRYPT_ALGO cryptAlgo;
  710. #endif /* TEST_LOWLEVEL */
  711. #ifndef __WINDOWS__
  712.     int status;
  713. #endif /* !__WINDOWS__ */
  714.     void testSystemSpecific( void );
  715.  
  716.     /* Get rid of compiler warnings */
  717.     if( argc || argv );
  718.  
  719.     /* Make sure various system-specific features are set right */
  720.     testSystemSpecific();
  721.  
  722.     /* Initialise the library (not necessary for a DLL) */
  723. #ifndef __WINDOWS__
  724.     status = cryptInit();
  725.     if( cryptStatusError( status ) )
  726.         {
  727.         printf( "cryptInit() failed with error code %d.\n", status );
  728.         exit( EXIT_FAILURE );
  729.         }
  730. #endif /* !__WINDOWS__ */
  731.  
  732. #ifdef TEST_LOWLEVEL
  733.     /* Test the conventional encryption routines */
  734.     for( cryptAlgo = CRYPT_ALGO_FIRST_CONVENTIONAL;
  735.          cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL; cryptAlgo++ )
  736.         if( cryptStatusOK( cryptAlgoAvailable( cryptAlgo ) ) )
  737.             {
  738.             CRYPT_MODE cryptMode;
  739.  
  740.             for( cryptMode = CRYPT_MODE_FIRST_CONVENTIONAL;
  741.                  cryptMode <= CRYPT_MODE_LAST_CONVENTIONAL; cryptMode++ )
  742.                 if( cryptStatusOK( cryptModeAvailable( cryptAlgo, cryptMode ) ) && \
  743.                     !testLibrary( cryptAlgo, cryptMode ) )
  744.                     goto errorExit;
  745.             }
  746.  
  747.     /* Test the public-key encryption routines */
  748.     for( cryptAlgo = CRYPT_ALGO_FIRST_PKC;
  749.          cryptAlgo <= CRYPT_ALGO_LAST_PKC; cryptAlgo++ )
  750.         if( cryptStatusOK( cryptAlgoAvailable( cryptAlgo ) ) && \
  751.             !testLibrary( cryptAlgo, CRYPT_MODE_PKC ) )
  752.                 goto errorExit;
  753.  
  754.     /* Test the hash routines */
  755.     for( cryptAlgo = CRYPT_ALGO_FIRST_HASH;
  756.          cryptAlgo <= CRYPT_ALGO_LAST_HASH; cryptAlgo++ )
  757.         if( cryptStatusOK( cryptAlgoAvailable( cryptAlgo ) ) && \
  758.             !testLibrary( cryptAlgo, CRYPT_MODE_NONE ) )
  759.             goto errorExit;
  760.  
  761.     putchar( '\n' );
  762. #else
  763.     puts( "Skipping test of low-level encryption routines...\n" );
  764. #endif /* TEST_LOWLEVEL */
  765.  
  766.     /* Test the randomness-gathering routines in the library */
  767. #ifdef TEST_RANDOM
  768.     if( !testRandomRoutines() )
  769.         {
  770.         puts( "The self-test will proceed without using a strong random "
  771.               "number source.\n" );
  772.  
  773.         /* Kludge the randomness routines so we can continue the self-tests */
  774.         cryptAddRandom( "a", 1 );
  775.         }
  776. #else
  777.     /* In order to avoid having to do a randomness poll for every test run,
  778.        we bypass the randomness-handling by adding some junk - it doesn't
  779.        matter here because we're not worried about security, but should never
  780.        be done in production code */
  781.     cryptAddRandom( "a", 1 );
  782. #endif /* TEST_RANDOM */
  783.  
  784.     /* Test the high-level routines contained in the library.  This is
  785.        implemented as a series of separate function calls rather than a
  786.        monolithic if( a || b || c || ... ) block to make testing easier */
  787. #ifdef WRITE_OBJECTS
  788.     if( ( objectFile = fopen( "asn1objs.dat", "wb" ) ) == NULL )
  789.         {
  790.         puts( "Couldn't open output file to write cryptlib objects to." );
  791.         exit( EXIT_FAILURE );
  792.         }
  793. #endif /* WRITE_OBJECTS */
  794. #ifdef TEST_HIGHLEVEL
  795.     if( !testDeriveKey() )
  796.         goto errorExit;
  797.     if( !testConventionalExportImport() )
  798.         goto errorExit;
  799.     if( !testKeyExportImport() )
  800.         goto errorExit;
  801.     if( !testSignData() )
  802.         goto errorExit;
  803.     if( !testKeyExchange() )
  804.         goto errorExit;
  805.     if( !testEncryptObject() )
  806.         goto errorExit;
  807.     if( !testSampleApp() )
  808.         goto errorExit;
  809. #else
  810.     puts( "Skipping test of high-level encryption routines...\n" );
  811. #endif /* TEST_HIGHLEVEL */
  812. #ifdef WRITE_OBJECTS
  813.     fclose( objectFile );
  814. #endif /* WRITE_OBJECTS */
  815.  
  816.     /* Shut down the library (not necessary for a DLL) */
  817. #ifndef __WINDOWS__
  818.     status = cryptEnd();
  819.     if( cryptStatusError( status ) )
  820.         {
  821.         printf( "cryptEnd() failed with error code %d.\n", status );
  822.         exit( EXIT_FAILURE );
  823.         }
  824. #endif /* !__WINDOWS__ */
  825.  
  826.     return( EXIT_SUCCESS );
  827.  
  828.     /* All errors end up here */
  829. errorExit:
  830.     cryptEnd();
  831.     puts( "Tests aborted due to encryption library error." );
  832.     return( EXIT_FAILURE );
  833.     }
  834.  
  835. /* Test the system-specific defines in crypt.h.  This is the last function in
  836.    the file because we want to avoid any definitions in crypt.h messing with 
  837.    the rest of the test.c code.
  838.  
  839.    The following include is need only so we can check whether the defines are
  840.    set right.  crypt.h should not normally be included in a cryptlib program */
  841.  
  842. #undef __WINDOWS__
  843. #undef BOOLEAN
  844. #undef BYTE
  845. #undef FALSE
  846. #undef TRUE
  847. #include "crypt.h"
  848.  
  849. void testSystemSpecific( void )
  850.     {
  851.     int bigEndian;
  852.  
  853.     /* Make sure we've got the endianness set right.  If the machine is
  854.        big-endian (up to 64 bits) the following value will be signed,
  855.        otherwise it will be unsigned.  Unfortunately we can't test for
  856.        things like middle-endianness without knowing the size of the data
  857.        types */
  858.     bigEndian = ( *( long * ) "\x80\x00\x00\x00\x00\x00\x00\x00" < 0 );
  859. #ifdef LITTLE_ENDIAN
  860.     if( bigEndian )
  861.         {
  862.         puts( "The CPU endianness define is set wrong in crypt.h, this "
  863.               "machine appears to be\nbig-endian, not little-endian.  Edit "
  864.               "the file and rebuild the library." );
  865.         exit( EXIT_FAILURE );
  866.         }
  867. #else
  868.     if( !bigEndian )
  869.         {
  870.         puts( "The CPU endianness define is set wrong in crypt.h, this "
  871.               "machine appears to be\nlittle-endian, not big-endian.  Edit "
  872.               "the file and rebuild the library." );
  873.         exit( EXIT_FAILURE );
  874.         }
  875. #endif /* LITTLE_ENDIAN */
  876.  
  877.     /* If we're compiling under Windoze, make sure that this weeks version
  878.        of Visual C gets the LONG type right */
  879. #ifdef __WINDOWS__
  880.     {
  881.     LONG test = 0x80000000L;
  882.  
  883.     if( test < 0 )
  884.         {
  885.         puts( "typeof( LONG ) is incorrect.  It evaluates to a signed 32-bit "
  886.               "value rather\nthan an unsigned 32-bit value.  You need to edit "
  887.               "crypt.h and recompile the\nencryption library" );
  888.         exit( EXIT_FAILURE );
  889.         }
  890.     }
  891. #endif /* __WINDOWS__ */
  892.     }
  893.