home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / crypl200.zip / TESTHL.C < prev    next >
Text File  |  1996-09-24  |  33KB  |  962 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "capi.h"
  5.  
  6. /* The key size to use for the PKC routines */
  7.  
  8. #define PKC_KEYSIZE            512
  9.  
  10. /* Various useful types */
  11.  
  12. #define BOOLEAN    int
  13. #define BYTE    unsigned char
  14. #ifndef TRUE
  15.   #define FALSE    0
  16.   #define TRUE    !FALSE
  17. #endif /* TRUE */
  18.  
  19. /* Prototypes for functions in testlib.c */
  20.  
  21. BOOLEAN loadRSAContexts( CRYPT_CONTEXT *cryptContext,
  22.                          CRYPT_CONTEXT *decryptContext );
  23. BOOLEAN loadDHContexts( CRYPT_CONTEXT *cryptContext1,
  24.                         CRYPT_CONTEXT *cryptContext2, int keySize );
  25. void destroyContexts( CRYPT_CONTEXT cryptContext, CRYPT_CONTEXT decryptContext );
  26.  
  27. /****************************************************************************
  28. *                                                                            *
  29. *                            High-level Routines Test                        *
  30. *                                                                            *
  31. ****************************************************************************/
  32.  
  33. /* Print a cookie and key ID */
  34.  
  35. static void printCookie( CRYPT_OBJECT_INFO *cryptObjectInfo )
  36.     {
  37.     int i;
  38.  
  39.     for( i = 0; i < cryptObjectInfo->cookieSize; i++ )
  40.         printf( "%02X", cryptObjectInfo->cookie[ i ] );
  41.     putchar( '\n' );
  42.     }
  43.  
  44. static void printKeyID( CRYPT_OBJECT_INFO *cryptObjectInfo )
  45.     {
  46.     int i;
  47.  
  48.     for( i = 0; i < cryptObjectInfo->keyIDsize; i++ )
  49.         printf( "%02X", cryptObjectInfo->keyID[ i ] );
  50.     putchar( '\n' );
  51.     }
  52.  
  53. /* Test the randomness gathering routines */
  54.  
  55. int testRandomRoutines( void )
  56.     {
  57.     CRYPT_CONTEXT cryptContext;
  58.     int status;
  59.  
  60.     puts( "Testing randomness routines.  This may take a few seconds..." );
  61.  
  62.     /* Create an encryption context to generate a key into */
  63.     cryptCreateContext( &cryptContext, CRYPT_ALGO_DES, CRYPT_MODE_ECB );
  64.     status = cryptGenerateContext( cryptContext );
  65.     cryptDestroyContext( cryptContext );
  66.  
  67.     /* Check whether we got enough randomness */
  68.     if( status == CRYPT_NORANDOM )
  69.         {
  70.         puts( "The randomness-gathering routines in the library can't acquire enough" );
  71.         puts( "random information to allow key generation and public-key encryption to" );
  72.         puts( "function.  You will need to change lib_rand.c or reconfigure your system" );
  73.         puts( "to allow the randomness-gathering routines to function.\n" );
  74.         return( FALSE );
  75.         }
  76.  
  77.     puts( "Randomness-gathering self-test succeeded.\n" );
  78.     return( TRUE );
  79.     }
  80.  
  81. /* Test the high-level code to derive a fixed-length encryption key from a
  82.    variable-length user key */
  83.  
  84. int testDeriveKey( void )
  85.     {
  86.     CRYPT_CONTEXT cryptContext, decryptContext;
  87.     BYTE *userKey = ( BYTE * ) "This is a long user key for cryptDeriveKey()";
  88.     BYTE buffer[ 8 ];
  89.     int userKeyLength = strlen( ( char * ) userKey ), status;
  90.  
  91.     puts( "Testing key derivation..." );
  92.  
  93.     /* Create DES encryption and decryption contexts */
  94.     cryptCreateContext( &cryptContext, CRYPT_ALGO_DES, CRYPT_MODE_ECB );
  95.     cryptCreateContext( &decryptContext, CRYPT_ALGO_DES, CRYPT_MODE_ECB );
  96.  
  97.     /* Load a DES key derived from a user key into both contexts */
  98.     status = cryptDeriveKey( cryptContext, userKey, userKeyLength );
  99.     if( cryptStatusError( status ) )
  100.         {
  101.         printf( "cryptDeriveKey() failed with error code %d\n", status );
  102.         return( FALSE );
  103.         }
  104.     status = cryptDeriveKey( decryptContext, userKey, userKeyLength );
  105.     if( cryptStatusError( status ) )
  106.         {
  107.         printf( "cryptDeriveKey() failed with error code %d\n", status );
  108.         return( FALSE );
  109.         }
  110.  
  111.     /* Encrypt the data with one derived key and make sure it decrypts with
  112.        the other */
  113.     memcpy( buffer, "12345678", 8 );
  114.     status = cryptEncrypt( cryptContext, buffer, 8 );
  115.     if( cryptStatusError( status ) )
  116.         {
  117.         printf( "Encryption with derived key failed with error code %d\n",
  118.                 status );
  119.         return( FALSE );
  120.         }
  121.     status = cryptDecrypt( decryptContext, buffer, 8 );
  122.     if( cryptStatusError( status ) )
  123.         {
  124.         printf( "Decryption with derived key failed with error code %d\n",
  125.                 status );
  126.         return( FALSE );
  127.         }
  128.     destroyContexts( cryptContext, decryptContext );
  129.     if( memcmp( buffer, "12345678", 8 ) )
  130.         {
  131.         puts( "Data decrypted with derived key != plaintext encrypted with "
  132.               "derived key." );
  133.         return( FALSE );
  134.         }
  135.  
  136.     puts( "Generation of key via cryptDeriveKey() succeeded.\n" );
  137.     return( TRUE );
  138.     }
  139.  
  140. /* Test the high-level code to export/import an encrypted key via
  141.    conventional encryption.  This demonstrates the ability to use one context
  142.    type to export another - we export a triple DES key using Blowfish.  We're
  143.    not as picky with error-checking here since most of the functions have
  144.    just executed successfully */
  145.  
  146. int testConventionalExportImport( void )
  147.     {
  148.     CRYPT_OBJECT_INFO cryptObjectInfo;
  149.     CRYPT_CONTEXT cryptContext, decryptContext;
  150.     CRYPT_CONTEXT sessionKeyContext;
  151.     BYTE *userKey = ( BYTE * ) "This is a long user key for cryptDeriveKey()";
  152.     BYTE *buffer;
  153.     int userKeyLength = strlen( ( char * ) userKey );
  154.     int status, length;
  155.  
  156.     puts( "Testing conventional key export/import..." );
  157.  
  158.     /* Create a triple-DES encryption context for the session key */
  159.     cryptCreateContext( &sessionKeyContext, CRYPT_ALGO_3DES, CRYPT_MODE_CFB );
  160.     cryptGenerateContext( sessionKeyContext );
  161.  
  162.     /* Create a Blowfish encryption context to export the session key */
  163.     cryptCreateContext( &cryptContext, CRYPT_ALGO_BLOWFISH, CRYPT_MODE_CFB );
  164.     cryptDeriveKey( cryptContext, userKey, userKeyLength );
  165.  
  166.     /* Find out how big the exported key will be */
  167.     status = cryptExportKey( NULL, &length, cryptContext, sessionKeyContext );
  168.     if( cryptStatusError( status ) )
  169.         {
  170.         printf( "cryptExportKey() failed with error code %d\n", status );
  171.         return( FALSE );
  172.         }
  173.     printf( "cryptExportKey() reports exported key object will be %d bytes long\n",
  174.             length );
  175.     if( ( buffer = malloc( length ) ) == NULL )
  176.         return( FALSE );
  177.  
  178.     /* Export the session information */
  179.     status = cryptExportKey( buffer, &length, cryptContext, sessionKeyContext );
  180.     if( cryptStatusError( status ) )
  181.         {
  182.         printf( "cryptExportKey() failed with error code %d\n", status );
  183.         free( buffer );
  184.         return( FALSE );
  185.         }
  186.  
  187.     /* Query the encrypted key object */
  188.     status = cryptQueryObject( buffer, &cryptObjectInfo );
  189.     if( cryptStatusError( status ) )
  190.         {
  191.         printf( "cryptQueryObject() failed with error code %d\n", status );
  192.         free( buffer );
  193.         return( FALSE );
  194.         }
  195.     printf( "cryptQueryObject() reports object type %d, size %ld bytes,\n"
  196.             "\talgorithm %d, mode %d, key derivation done with %d iterations of\n"
  197.             "\talgorithm %d.\n", cryptObjectInfo.type,
  198.             cryptObjectInfo.size, cryptObjectInfo.cryptAlgo,
  199.             cryptObjectInfo.cryptMode, cryptObjectInfo.keySetupIterations,
  200.             cryptObjectInfo.keySetupAlgo );
  201. #ifdef WRITE_OBJECTS
  202.     fwrite( buffer, ( size_t ) cryptObjectInfo.size, 1, objectFile );
  203.     fflush( objectFile );
  204. #endif /* WRITE_OBJECTS */
  205.  
  206.     /* Destroy the session key encryption context, then recreate it by
  207.        importing the encrypted key */
  208.     cryptDestroyContext( sessionKeyContext );
  209.     status = cryptCreateContextEx( &decryptContext,
  210.                                    cryptObjectInfo.cryptAlgo,
  211.                                    cryptObjectInfo.cryptMode,
  212.                                    cryptObjectInfo.cryptContextExInfo );
  213.     if( cryptStatusError( status ) )
  214.         {
  215.         printf( "cryptCreateContext() failed with error code %d\n", status );
  216.         free( buffer );
  217.         return( FALSE );
  218.         }
  219.     cryptDeriveKeyEx( decryptContext, userKey, userKeyLength,
  220.                       cryptObjectInfo.keySetupAlgo,
  221.                       cryptObjectInfo.keySetupIterations );
  222.     memset( &cryptObjectInfo, 0, sizeof( CRYPT_OBJECT_INFO ) );
  223.  
  224.     status = cryptImportKey( buffer, decryptContext, &sessionKeyContext );
  225.     if( cryptStatusError( status ) )
  226.         {
  227.         printf( "cryptImportKey() failed with error code %d\n", status );
  228.         free( buffer );
  229.         return( FALSE );
  230.         }
  231.  
  232.     /* Clean up */
  233.     cryptDestroyContext( sessionKeyContext );
  234.     destroyContexts( cryptContext, decryptContext );
  235.     printf( "Export/import of Blowfish key via user-key-based triple DES "
  236.             "conventional\n  encryption succeeded.\n\n" );
  237.     free( buffer );
  238.     return( TRUE );
  239.     }
  240.  
  241. /* Test the high-level code to export/import an encrypted key.  We're not as
  242.    picky with error-checking here since most of the functions have just
  243.    executed successfully */
  244.  
  245. int testKeyExportImport( void )
  246.     {
  247.     CRYPT_OBJECT_INFO cryptObjectInfo;
  248.     CRYPT_CONTEXT cryptContext, decryptContext;
  249.     CRYPT_CONTEXT sessionKeyContext;
  250.     BYTE *buffer;
  251.     int status, length;
  252.  
  253.     puts( "Testing public-key export/import..." );
  254.  
  255.     /* Create a triple-DES encryption context for the session key */
  256.     cryptCreateContext( &sessionKeyContext, CRYPT_ALGO_3DES, CRYPT_MODE_CFB );
  257.     cryptGenerateContext( sessionKeyContext );
  258.  
  259.     /* Create the RSA en/decryption contexts */
  260.     if( !loadRSAContexts( &cryptContext, &decryptContext ) )
  261.         return( FALSE );
  262.  
  263.     /* Find out how big the exported key will be */
  264.     status = cryptExportKey( NULL, &length, cryptContext, sessionKeyContext );
  265.     if( cryptStatusError( status ) )
  266.         {
  267.         printf( "cryptExportKey() failed with error code %d\n", status );
  268.         return( FALSE );
  269.         }
  270.     printf( "cryptExportKey() reports exported key object will be %d bytes long\n",
  271.             length );
  272.     if( ( buffer = malloc( length ) ) == NULL )
  273.         return( FALSE );
  274.  
  275.     /* Export the session key */
  276.     status = cryptExportKey( buffer, &length, cryptContext, sessionKeyContext );
  277.     if( cryptStatusError( status ) )
  278.         {
  279.         printf( "cryptExportKey() failed with error code %d\n", status );
  280.         free( buffer );
  281.         return( FALSE );
  282.         }
  283.  
  284.     /* Query the encrypted key object */
  285.     status = cryptQueryObject( buffer, &cryptObjectInfo );
  286.     if( cryptStatusError( status ) )
  287.         {
  288.         printf( "cryptQueryObject() failed with error code %d\n", status );
  289.         free( buffer );
  290.         return( FALSE );
  291.         }
  292.     printf( "cryptQueryObject() reports object type %d, size %ld bytes,\n"
  293.             "\talgorithm %d, mode %d.\n", cryptObjectInfo.type,
  294.             cryptObjectInfo.size, cryptObjectInfo.cryptAlgo,
  295.             cryptObjectInfo.cryptMode );
  296.     printf( "Key ID for decryption is " );
  297.     printKeyID( &cryptObjectInfo );
  298. #ifdef WRITE_OBJECTS
  299.     fwrite( buffer, ( size_t ) cryptObjectInfo.size, 1, objectFile );
  300.     fflush( objectFile );
  301. #endif /* WRITE_OBJECTS */
  302.     memset( &cryptObjectInfo, 0, sizeof( CRYPT_OBJECT_INFO ) );
  303.  
  304.     /* Destroy the session key encryption context, then recreate it by
  305.        importing the encrypted key */
  306.     cryptDestroyContext( sessionKeyContext );
  307.     status = cryptImportKey( buffer, decryptContext, &sessionKeyContext );
  308.     if( cryptStatusError( status ) )
  309.         {
  310.         printf( "cryptImportKey() failed with error code %d\n", status );
  311.         free( buffer );
  312.         return( FALSE );
  313.         }
  314.  
  315.     /* Clean up */
  316.     cryptDestroyContext( sessionKeyContext );
  317.     destroyContexts( cryptContext, decryptContext );
  318.     printf( "Export/import of session key via %d-bit RSA-encrypted data "
  319.             "block succeeded.\n\n", PKC_KEYSIZE );
  320.     free( buffer );
  321.     return( TRUE );
  322.     }
  323.  
  324. /* Test the high-level code to sign data.  We're not as picky with
  325.    error-checking here since most of the functions have just executed
  326.    successfully */
  327.  
  328. int testSignData( void )
  329.     {
  330.     CRYPT_OBJECT_INFO cryptObjectInfo;
  331.     CRYPT_CONTEXT signContext, checkContext;
  332.     CRYPT_CONTEXT hashContext;
  333.     BYTE *buffer, hashBuffer[] = "abcdefghijklmnopqrstuvwxyz";
  334.     int status, length;
  335.  
  336.     puts( "Testing digital signatures..." );
  337.  
  338.     /* Create an SHA hash context and hash the test buffer */
  339.     cryptCreateContext( &hashContext, CRYPT_ALGO_SHA, CRYPT_MODE_NONE );
  340.     cryptEncrypt( hashContext, hashBuffer, 26 );
  341.     cryptEncrypt( hashContext, hashBuffer, 0 );
  342.  
  343.     /* Create the RSA en/decryption contexts */
  344.     if( !loadRSAContexts( &checkContext, &signContext ) )
  345.         return( FALSE );
  346.  
  347.     /* Find out how big the signature will be */
  348.     status = cryptCreateSignature( NULL, &length, signContext, hashContext );
  349.     if( cryptStatusError( status ) )
  350.         {
  351.         printf( "cryptCreateSignature() failed with error code %d\n", status );
  352.         return( FALSE );
  353.         }
  354.     printf( "cryptCreateSignature() reports signature object will be %d bytes long\n",
  355.             length );
  356.     if( ( buffer = malloc( length ) ) == NULL )
  357.         return( FALSE );
  358.  
  359.     /* Sign the hashed data */
  360.     status = cryptCreateSignature( buffer, &length, signContext, hashContext );
  361.     if( cryptStatusError( status ) )
  362.         {
  363.         printf( "cryptCreateSignature() failed with error code %d\n", status );
  364.         free( buffer );
  365.         return( FALSE );
  366.         }
  367.  
  368.     /* Query the signed object */
  369.     status = cryptQueryObject( buffer, &cryptObjectInfo );
  370.     if( cryptStatusError( status ) )
  371.         {
  372.         printf( "cryptQueryObject() failed with error code %d\n", status );
  373.         free( buffer );
  374.         return( FALSE );
  375.         }
  376.     printf( "cryptQueryObject() reports object type %d, size %ld bytes,\n"
  377.             "\talgorithm %d, mode %d.\n", cryptObjectInfo.type,
  378.             cryptObjectInfo.size, cryptObjectInfo.cryptAlgo,
  379.             cryptObjectInfo.cryptMode );
  380.     printf( "Key ID for signature check key is " );
  381.     printKeyID( &cryptObjectInfo );
  382. #ifdef WRITE_OBJECTS
  383.     fwrite( buffer, ( size_t ) cryptObjectInfo.size, 1, objectFile );
  384.     fflush( objectFile );
  385. #endif /* WRITE_OBJECTS */
  386.     memset( &cryptObjectInfo, 0, sizeof( CRYPT_OBJECT_INFO ) );
  387.  
  388.     /* Check the signature on the hash */
  389.     status = cryptCheckSignature( buffer, checkContext, hashContext );
  390.     if( cryptStatusError( status ) )
  391.         {
  392.         printf( "cryptCheckSignature() failed with error code %d\n", status );
  393.         free( buffer );
  394.         return( FALSE );
  395.         }
  396.  
  397.     /* Clean up */
  398.     cryptDestroyContext( hashContext );
  399.     destroyContexts( checkContext, signContext );
  400.     printf( "Generation and checking of RSA digital signature via %d-bit "
  401.             "data block\n  succeeded.\n\n", PKC_KEYSIZE );
  402.         free( buffer );
  403.     return( TRUE );
  404.     }
  405.  
  406. /* Test the high-level code to exchange a session key via Diffie-Hellman.
  407.    We're not as picky with error-checking here since most of the functions
  408.    have just executed successfully */
  409.  
  410. int testKeyExchange( void )
  411.     {
  412.     CRYPT_OBJECT_INFO cryptObjectInfo;
  413.     CRYPT_CONTEXT cryptContext1, cryptContext2;
  414.     CRYPT_CONTEXT sessionKeyContext1, sessionKeyContext2;
  415.     BYTE *buffer1, *buffer2;
  416.     int length1, length2, status1, status2;
  417.  
  418.     puts( "Testing key agreement..." );
  419.  
  420.     /* Create the DH encryption contexts */
  421.     if( !loadDHContexts( &cryptContext1, &cryptContext2, PKC_KEYSIZE ) )
  422.         return( FALSE );
  423.  
  424.     /* Create the session key context */
  425.     cryptCreateContext( &sessionKeyContext1, CRYPT_ALGO_3DES, CRYPT_MODE_CFB );
  426.  
  427.     /* Find out how big the exported key will be */
  428.     status1 = cryptExportKey( NULL, &length1, cryptContext1, sessionKeyContext1 );
  429.     if( cryptStatusError( status1 ) )
  430.         {
  431.         printf( "cryptExportKey() failed with error code %d\n", status1 );
  432.         return( FALSE );
  433.         }
  434.     printf( "cryptExportKey() reports exported key object will be %d bytes long\n",
  435.             length1 );
  436.     if( ( buffer1 = malloc( length1 ) ) == NULL || \
  437.         ( buffer2 = malloc( length1 ) ) == NULL )
  438.         return( FALSE );
  439.  
  440.     /* Create the integer public values */
  441.     status1 = cryptExportKey( buffer1, &length1, cryptContext1, sessionKeyContext1 );
  442.     status2 = cryptExportKey( buffer2, &length2, cryptContext2, sessionKeyContext1 );
  443.     cryptDestroyContext( sessionKeyContext1 );
  444.     if( cryptStatusError( status1 ) )
  445.         {
  446.         printf( "cryptExportKey() #1 failed with error code %d\n", status1 );
  447.         free( buffer1 );
  448.         free( buffer2 );
  449.         return( FALSE );
  450.         }
  451.     if( cryptStatusError( status2 ) )
  452.         {
  453.         printf( "cryptExportKey() #2 failed with error code %d\n", status2 );
  454.         free( buffer1 );
  455.         free( buffer2 );
  456.         return( FALSE );
  457.         }
  458.  
  459.     /* Query the encrypted key object */
  460.     status1 = cryptQueryObject( buffer1, &cryptObjectInfo );
  461.     if( cryptStatusError( status1 ) )
  462.         {
  463.         printf( "cryptQueryObject() failed with error code %d\n", status1 );
  464.         free( buffer1 );
  465.         free( buffer2 );
  466.         return( FALSE );
  467.         }
  468.     printf( "cryptQueryObject() reports object type %d, size %ld bytes,\n"
  469.             "\talgorithm %d, mode %d.\n", cryptObjectInfo.type,
  470.             cryptObjectInfo.size, cryptObjectInfo.cryptAlgo,
  471.             cryptObjectInfo.cryptMode );
  472.     printf( "Key ID for exchange key is " );
  473.     printKeyID( &cryptObjectInfo );
  474. #ifdef WRITE_OBJECTS
  475.     fwrite( buffer1, ( size_t ) cryptObjectInfo.size, 1, objectFile );
  476.     fwrite( buffer2, ( size_t ) cryptObjectInfo.size, 1, objectFile );
  477.     fflush( objectFile );
  478. #endif /* WRITE_OBJECTS */
  479.     memset( &cryptObjectInfo, 0, sizeof( CRYPT_OBJECT_INFO ) );
  480.  
  481.     /* Create the integer secret values */
  482.     status1 = cryptImportKey( buffer2, cryptContext1, &sessionKeyContext1 );
  483.     status2 = cryptImportKey( buffer1, cryptContext2, &sessionKeyContext2 );
  484.     if( cryptStatusError( status1 ) )
  485.         {
  486.         printf( "cryptImportKey() #1 failed with error code %d\n", status1 );
  487.         free( buffer1 );
  488.         free( buffer2 );
  489.         return( FALSE );
  490.         }
  491.     if( cryptStatusError( status2 ) )
  492.         {
  493.         printf( "cryptImportKey() #2 failed with error code %d\n", status2 );
  494.         free( buffer1 );
  495.         free( buffer2 );
  496.         return( FALSE );
  497.         }
  498.  
  499.     /* Clean up */
  500.     cryptDestroyContext( sessionKeyContext1 );
  501.     cryptDestroyContext( sessionKeyContext2 );
  502.     destroyContexts( cryptContext1, cryptContext2 );
  503.     printf( "Exchange of session key via %d-bit Diffie-Hellman succeeded.\n\n",
  504.             PKC_KEYSIZE );
  505.     free( buffer1 );
  506.     free( buffer2 );
  507.     return( TRUE );
  508.     }
  509.  
  510. /* Test the high-level code to encrypt an object via a PKC-encrypted session
  511.    key.  We're not as picky with error-checking here since most of the
  512.    functions have just executed successfully */
  513.  
  514. int testEncryptObject( void )
  515.     {
  516.     CRYPT_OBJECT_INFO cryptObjectInfo;
  517.     CRYPT_CONTEXT cryptContext, decryptContext;
  518.     CRYPT_CONTEXT sessionKeyContext;
  519.     BYTE *exportedKey, *encryptedData, *payload;
  520.     BYTE *data = ( BYTE * ) "This is a test string to encrypt";
  521.     int encryptedDataObjectSize, rawDataObjectSize, payloadStart;
  522.     int status, exportedKeyLength, dataLength = 33;
  523.     long payloadSize;
  524.  
  525.     puts( "Testing encrypted object exchange..." );
  526.  
  527.     /* Create a triple-DES encryption context for the session key */
  528.     cryptCreateContext( &sessionKeyContext, CRYPT_ALGO_3DES, CRYPT_MODE_CFB );
  529.     cryptGenerateContext( sessionKeyContext );
  530.  
  531.     /* Create the RSA en/decryption contexts */
  532.     if( !loadRSAContexts( &cryptContext, &decryptContext ) )
  533.         return( FALSE );
  534.  
  535.     /* Find out how big the exported key will be */
  536.     status = cryptExportKey( NULL, &exportedKeyLength, cryptContext,
  537.                              sessionKeyContext );
  538.     if( cryptStatusError( status ) )
  539.         {
  540.         printf( "cryptExportKey() failed with error code %d\n", status );
  541.         return( FALSE );
  542.         }
  543.     printf( "cryptExportKey() reports exported key object will be %d bytes long\n",
  544.             exportedKeyLength );
  545.     if( ( exportedKey = malloc( exportedKeyLength ) ) == NULL )
  546.         return( FALSE );
  547.  
  548.     /* Export the session key */
  549.     status = cryptExportKey( exportedKey, &exportedKeyLength, cryptContext,
  550.                              sessionKeyContext );
  551.     if( cryptStatusError( status ) )
  552.         {
  553.         printf( "cryptExportKey() failed with error code %d\n", status );
  554.         free( exportedKey );
  555.         return( FALSE );
  556.         }
  557.  
  558.     /* Find out how large the encrypted data object will be and allocate
  559.        room for it */
  560.     cryptExportObject( NULL, &rawDataObjectSize, CRYPT_OBJECT_RAW_DATA,
  561.                        dataLength );
  562.     cryptExportObjectEx( NULL, &encryptedDataObjectSize,
  563.                          CRYPT_OBJECT_ENCRYPTED_DATA, rawDataObjectSize +
  564.                          dataLength, sessionKeyContext );
  565.     if( ( encryptedData = malloc( encryptedDataObjectSize +
  566.                                   rawDataObjectSize + dataLength ) ) == NULL )
  567.         {
  568.         free( exportedKey );
  569.         return( FALSE );
  570.         }
  571.  
  572.     /* Wrap up the sample data inside the RawData object */
  573.     cryptExportObject( encryptedData + encryptedDataObjectSize,
  574.                        &rawDataObjectSize, CRYPT_OBJECT_RAW_DATA,
  575.                        dataLength );
  576.     memcpy( encryptedData + encryptedDataObjectSize + rawDataObjectSize,
  577.             data, dataLength );
  578.  
  579.     /* Then wrap it up in the EncryptedData object and encrypt the
  580.        encapsulated part */
  581.     cryptExportObjectEx( encryptedData, &encryptedDataObjectSize,
  582.                          CRYPT_OBJECT_ENCRYPTED_DATA, rawDataObjectSize +
  583.                          dataLength, sessionKeyContext );
  584.     cryptEncrypt( sessionKeyContext, encryptedData + encryptedDataObjectSize,
  585.                   rawDataObjectSize + dataLength );
  586.  
  587.     /* We're done, destroy the session key context */
  588.     cryptDestroyContext( sessionKeyContext );
  589.  
  590.     /* Query the encrypted key object */
  591.     status = cryptQueryObject( exportedKey, &cryptObjectInfo );
  592.     if( cryptStatusError( status ) )
  593.         {
  594.         printf( "cryptQueryObject() failed with error code %d\n", status );
  595.         free( exportedKey );
  596.         free( encryptedData );
  597.         return( FALSE );
  598.         }
  599.     printf( "cryptQueryObject() reports object type %d, size %ld bytes,\n"
  600.             "\talgorithm %d, mode %d.\n", cryptObjectInfo.type,
  601.             cryptObjectInfo.size, cryptObjectInfo.cryptAlgo,
  602.             cryptObjectInfo.cryptMode );
  603.     printf( "Key ID for decryption is " );
  604.     printKeyID( &cryptObjectInfo );
  605.     printf( "Session key cookie is " );
  606.     printCookie( &cryptObjectInfo );
  607. #ifdef WRITE_OBJECTS
  608.     fwrite( exportedKey, ( size_t ) cryptObjectInfo.size, 1, objectFile );
  609.     fflush( objectFile );
  610. #endif /* WRITE_OBJECTS */
  611.     memset( &cryptObjectInfo, 0, sizeof( CRYPT_OBJECT_INFO ) );
  612.  
  613.     /* Query the encrypted data object */
  614.     status = cryptQueryObject( encryptedData, &cryptObjectInfo );
  615.     if( cryptStatusError( status ) )
  616.         {
  617.         printf( "cryptQueryObject() failed with error code %d\n", status );
  618.         free( exportedKey );
  619.         free( encryptedData );
  620.         return( FALSE );
  621.         }
  622.     printf( "cryptQueryObject() reports object type %d, size %ld bytes.\n",
  623.             cryptObjectInfo.type, cryptObjectInfo.size );
  624.     printf( "Decryption key cookie is " );
  625.     printCookie( &cryptObjectInfo );
  626. #ifdef WRITE_OBJECTS
  627.     fwrite( encryptedData, ( size_t ) cryptObjectInfo.size, 1, objectFile );
  628.     fflush( objectFile );
  629. #endif /* WRITE_OBJECTS */
  630.  
  631.     /* Recreate the session key by importing the encrypted key */
  632.     status = cryptImportKey( exportedKey, decryptContext, &sessionKeyContext );
  633.     if( cryptStatusError( status ) )
  634.         {
  635.         printf( "cryptImportKey() failed with error code %d\n", status );
  636.         free( exportedKey );
  637.         free( encryptedData );
  638.         return( FALSE );
  639.         }
  640.  
  641.     /* Set up the session key to decrypt the encrypted data */
  642.     status = cryptImportObjectEx( encryptedData, &payloadStart, &payloadSize,
  643.                                   &sessionKeyContext );
  644.     if( cryptStatusError( status ) )
  645.         {
  646.         printf( "cryptImportObjectEx() failed with error code %d\n", status );
  647.         free( exportedKey );
  648.         free( encryptedData );
  649.         return( FALSE );
  650.         }
  651.  
  652.     /* Decrypt the encrypted data */
  653.     payload = encryptedData + payloadStart;
  654.     cryptDecrypt( sessionKeyContext, payload, ( int ) payloadSize );
  655.  
  656.     /* Query the raw data object */
  657.     status = cryptQueryObject( payload, &cryptObjectInfo );
  658.     if( cryptStatusError( status ) )
  659.         {
  660.         printf( "cryptQueryObject() failed with error code %d\n", status );
  661.         free( exportedKey );
  662.         free( encryptedData );
  663.         return( FALSE );
  664.         }
  665.     printf( "cryptQueryObject() reports object type %d, size %ld bytes.\n",
  666.             cryptObjectInfo.type, cryptObjectInfo.size );
  667. #ifdef WRITE_OBJECTS
  668.     fwrite( payload, ( size_t ) cryptObjectInfo.size, 1, objectFile );
  669.     fflush( objectFile );
  670. #endif /* WRITE_OBJECTS */
  671.  
  672.     /* Make sure the data matches what we originally encrypted */
  673.     if( memcmp( data, payload + cryptObjectInfo.headerSize,
  674.                 ( size_t ) cryptObjectInfo.payloadSize ) )
  675.         puts( "Decrypted data != original plaintext." );
  676.  
  677.     /* Clean up */
  678.     cryptDestroyContext( sessionKeyContext );
  679.     destroyContexts( cryptContext, decryptContext );
  680.     printf( "Exchange of encrypted data via RSA-encrypted session key "
  681.             "succeeded.\n\n" );
  682.     free( exportedKey );
  683.     free( encryptedData );
  684.     return( TRUE );
  685.     }
  686.  
  687. /****************************************************************************
  688. *                                                                            *
  689. *            Sample Mini-application - Encrypt and Sign a Memory Buffer        *
  690. *                                                                            *
  691. ****************************************************************************/
  692.  
  693. /* Create an encrypted, signed data object preceded by an exported key
  694.    object.  This looks like:
  695.  
  696.     [ PKCEncryptedKey|EncryptedKey ]
  697.     [ EncryptedData( SignedData( RawData ), Signature ) ] */
  698.  
  699. static int encryptSignBuffer( BYTE **outBuffer, int *outLength, BYTE *data,
  700.                               int dataLength, CRYPT_CONTEXT signContext,
  701.                               CRYPT_CONTEXT cryptContext,
  702.                               CRYPT_ALGO cryptAlgo )
  703.     {
  704.     CRYPT_CONTEXT sessionKeyContext, hashContext;
  705.     CRYPT_IOCTLINFO_COOKIE cryptIoctlInfo;
  706.     BYTE *objectBuffer, *encryptedObject, *signedObject, *dataObject, *signature;
  707.     int signatureSize, exportedKeySize;
  708.     int encryptedObjectSize, signedObjectSize, dataObjectSize;
  709.     int status;
  710.  
  711.     /* Ensure that if something goes wrong the caller won't try to use the
  712.        output data */
  713.     *outBuffer = NULL;
  714.     *outLength = 0;
  715.  
  716.     /* Create an encryption context for the session key and a hash context
  717.        for the signature.  Since the Signature object directly follows the
  718.        SignedData object we don't bother exporting the signature cookie */
  719.     status = cryptCreateContext( &sessionKeyContext, cryptAlgo, CRYPT_MODE_CFB );
  720.     if( cryptStatusError( status ) )
  721.         return( status );
  722.     cryptGenerateContext( sessionKeyContext );
  723.     status = cryptCreateContext( &hashContext, CRYPT_ALGO_SHA, CRYPT_MODE_NONE );
  724.     if( cryptStatusError( status ) )
  725.         {
  726.         cryptDestroyContext( sessionKeyContext );
  727.         return( status );
  728.         }
  729.     cryptIoctlInfo.exportCookie = 0;
  730.     cryptIoctl( CRYPT_IOCTL_SIGCOOKIE, &cryptIoctlInfo, hashContext );
  731.  
  732.     /* Find out how big the various objects will be.  Note the way we
  733.        determine the size of the nested objects: First the inner RawData
  734.        object, then the SignedData object surrounding it, then the
  735.        EncryptedData object surrounding that */
  736.     cryptExportKey( NULL, &exportedKeySize, cryptContext, sessionKeyContext );
  737.     cryptCreateSignature( NULL, &signatureSize, signContext, hashContext );
  738.     cryptExportObject( NULL, &dataObjectSize, CRYPT_OBJECT_RAW_DATA,
  739.                        dataLength );
  740.     cryptExportObjectEx( NULL, &signedObjectSize, CRYPT_OBJECT_SIGNED_DATA,
  741.                          dataObjectSize + dataLength, hashContext );
  742.     cryptExportObjectEx( NULL, &encryptedObjectSize,
  743.                          CRYPT_OBJECT_ENCRYPTED_DATA, signedObjectSize +
  744.                          dataObjectSize + dataLength + signatureSize,
  745.                          sessionKeyContext );
  746.  
  747.     /* Allocate a buffer for them and find the locations of each object in
  748.        the buffer */
  749.     if( ( objectBuffer = malloc( exportedKeySize + encryptedObjectSize +
  750.                                  signedObjectSize + dataObjectSize +
  751.                                  dataLength + signatureSize ) ) == NULL )
  752.         {
  753.         cryptDestroyContext( sessionKeyContext );
  754.         cryptDestroyContext( hashContext );
  755.         return( CRYPT_NOMEM );
  756.         }
  757.     encryptedObject = objectBuffer + exportedKeySize;
  758.     signedObject = encryptedObject + encryptedObjectSize;
  759.     dataObject = signedObject + signedObjectSize;
  760.     signature = dataObject + dataObjectSize + dataLength;
  761.  
  762.     /* Export the session key */
  763.     status = cryptExportKey( objectBuffer, &exportedKeySize, cryptContext,
  764.                              sessionKeyContext );
  765.     if( cryptStatusError( status ) )
  766.         {
  767.         cryptDestroyContext( sessionKeyContext );
  768.         cryptDestroyContext( hashContext );
  769.         free( objectBuffer );
  770.         return( status );
  771.         }
  772.  
  773.     /* Assemble the EncryptedData, SignedData, and RawData objects */
  774.     cryptExportObjectEx( encryptedObject, &encryptedObjectSize,
  775.                          CRYPT_OBJECT_ENCRYPTED_DATA, signedObjectSize +
  776.                          dataObjectSize + dataLength + signatureSize,
  777.                          sessionKeyContext );
  778.     cryptExportObjectEx( signedObject, &signedObjectSize,
  779.                          CRYPT_OBJECT_SIGNED_DATA, dataObjectSize +
  780.                          dataLength, hashContext );
  781.     cryptExportObject( dataObject, &dataObjectSize, CRYPT_OBJECT_RAW_DATA,
  782.                        dataLength );
  783.     memcpy( dataObject + dataObjectSize, data, dataLength );
  784.  
  785.     /* Hash the RawData object, sign the hash, and store the result in the
  786.        SignedData object */
  787.     cryptEncrypt( hashContext, dataObject, dataLength +  dataObjectSize );
  788.     cryptEncrypt( hashContext, dataObject, 0 );
  789.     status = cryptCreateSignature( signature, &signatureSize, signContext,
  790.                                    hashContext );
  791.     cryptDestroyContext( hashContext );
  792.     if( cryptStatusError( status ) )
  793.         {
  794.         cryptDestroyContext( sessionKeyContext );
  795.         free( objectBuffer );
  796.         return( status );
  797.         }
  798.  
  799.     /* Encrypt the SignedData and Signature objects */
  800.     status = cryptEncrypt( sessionKeyContext, signedObject, signedObjectSize
  801.                            + dataObjectSize + dataLength + signatureSize );
  802.     cryptDestroyContext( sessionKeyContext );
  803.     if( cryptStatusError( status ) )
  804.         {
  805.         free( objectBuffer );
  806.         return( status );
  807.         }
  808.  
  809.     /* Clean up */
  810.     *outBuffer = objectBuffer;
  811.     *outLength = exportedKeySize + encryptedObjectSize + signedObjectSize +
  812.                  dataObjectSize + dataLength + signatureSize;
  813.     return( CRYPT_OK );
  814.     }
  815.  
  816. /* Unwrap the data objects, decrypt the data we need, and check the
  817.    signature */
  818.  
  819. static int decryptSignBuffer( BYTE **outBuffer, int *outLength, BYTE *data,
  820.                               CRYPT_CONTEXT signContext,
  821.                               CRYPT_CONTEXT decryptContext )
  822.     {
  823.     CRYPT_CONTEXT sessionKeyContext, hashContext;
  824.     BYTE *exportedKey = data, *encryptedData, *signedData, *payload, *signature;
  825.     int payloadStart, status;
  826.     long payloadSize;
  827.  
  828.     /* Ensure that if something goes wrong the caller won't try to use the
  829.        output data */
  830.     *outBuffer = NULL;
  831.     *outLength = 0;
  832.  
  833.     /* Query the encrypted key object to find its size */
  834.     status = cryptImportObject( exportedKey, &payloadStart, &payloadSize );
  835.     if( cryptStatusError( status ) )
  836.         return( status );
  837.  
  838.     /* Recreate the session key by importing the encrypted key */
  839.     status = cryptImportKey( exportedKey, decryptContext, &sessionKeyContext );
  840.     if( cryptStatusError( status ) )
  841.         return( status );
  842.  
  843.     /* Set up the session key to decrypt the encrypted data */
  844.     encryptedData = exportedKey + payloadStart + ( int ) payloadSize;
  845.     status = cryptImportObjectEx( encryptedData, &payloadStart, &payloadSize,
  846.                                   &sessionKeyContext );
  847.     if( cryptStatusError( status ) )
  848.         {
  849.         cryptDestroyContext( sessionKeyContext );
  850.         return( status );
  851.         }
  852.  
  853.     /* Decrypt the encrypted data */
  854.     signedData = encryptedData + payloadStart;
  855.     status = cryptDecrypt( sessionKeyContext, signedData, ( int ) payloadSize );
  856.     cryptDestroyContext( sessionKeyContext );
  857.     if( cryptStatusError( status ) )
  858.         return( status );
  859.  
  860.     /* Import the signed data object */
  861.     status = cryptImportObjectEx( signedData, &payloadStart, &payloadSize,
  862.                                   &hashContext );
  863.     if( cryptStatusError( status ) )
  864.         return( status );
  865.  
  866.     /* Hash the signed data */
  867.     payload = signedData + payloadStart;
  868.     cryptEncrypt( hashContext, payload, ( int ) payloadSize );
  869.     cryptEncrypt( hashContext, payload, 0 );
  870.  
  871.     /* Check the signature */
  872.     signature = signedData + payloadStart + ( int ) payloadSize;
  873.     status = cryptCheckSignature( signature, signContext, hashContext );
  874.     cryptDestroyContext( hashContext );
  875.     if( cryptStatusError( status ) )
  876.         return( status );
  877.  
  878.     /* Import the raw data object */
  879.     status = cryptImportObject( payload, &payloadStart, &payloadSize );
  880.     if( cryptStatusError( status ) )
  881.         return( status );
  882.  
  883.     /* Clean up */
  884.     *outBuffer = payload + payloadStart;
  885.     *outLength = ( int ) payloadSize;
  886.     return( CRYPT_OK );
  887.     }
  888.  
  889. /****************************************************************************
  890. *                                                                            *
  891. *                            Sample Application Test Code                    *
  892. *                                                                            *
  893. ****************************************************************************/
  894.  
  895. /* Code to test the sample app to sign and encrypt a memory buffer.  This
  896.    uses a PKC-encrypted session key, although there's no reason you can't
  897.    use a conventionally-encrypted one */
  898.  
  899. int testSampleApp( void )
  900.     {
  901.     CRYPT_CONTEXT pkcContext, signContext;
  902.     BYTE *data = ( BYTE * ) "This is some sample plaintext to export";
  903.     BYTE *cipherText, *plainText;
  904.     int length = strlen( ( char * ) data ) + 1, outLength, status;
  905.  
  906.     /* Load the encryption and signature keys */
  907.     if( !loadRSAContexts( &pkcContext, &signContext ) )
  908.         return( FALSE );
  909.  
  910.     /* Encrypt and wrap the data */
  911.     status = encryptSignBuffer( &cipherText, &outLength, data, length,
  912.                                 signContext, pkcContext, CRYPT_ALGO_3DES );
  913.     cryptDestroyContext( pkcContext );
  914.     cryptDestroyContext( signContext );
  915.     if( cryptStatusError( status ) )
  916.         {
  917.         if( cipherText != NULL )
  918.             free( cipherText );
  919.         printf( "encryptSignBuffer() function failed with error code %d\n", status );
  920.         return( FALSE );
  921.         }
  922. #ifdef WRITE_OBJECTS
  923.     fwrite( cipherText, outLength, 1, objectFile );
  924.     fflush( objectFile );
  925. #endif /* WRITE_OBJECTS */
  926.  
  927.     /* Load the decryption and signature-check keys */
  928.     if( !loadRSAContexts( &signContext, &pkcContext ) )
  929.         {
  930.         free( cipherText );
  931.         return( FALSE );
  932.         }
  933.  
  934.     /* Unwrap and decrypt the data */
  935.     status = decryptSignBuffer( &plainText, &outLength, cipherText,
  936.                                 signContext, pkcContext );
  937.     cryptDestroyContext( pkcContext );
  938.     cryptDestroyContext( signContext );
  939.     if( cryptStatusError( status ) )
  940.         {
  941.         free( cipherText );
  942.         printf( "decryptSignBuffer() function failed with error code %d\n", status );
  943.         return( FALSE );
  944.         }
  945.  
  946.     /* Make sure everything went OK */
  947.     if( outLength != length || \
  948.         memcmp( plainText, data, length ) )
  949.         {
  950.         free( cipherText );
  951.         puts( "Recovered plaintext != original plaintext" );
  952.         return( FALSE );
  953.         }
  954.  
  955.     /* Clean up */
  956.     printf( "Exchange of signed and encrypted data using object-management "
  957.             "API's succeeded.\n\n" );
  958.     free( cipherText );
  959.     return( TRUE );
  960.     }
  961.  
  962.