RSA BSAFE Crypto-C

Cryptographic Components for C

Search

descbc.c

/* $Id: descbc.c,v 1.6 2004/12/03 02:08:40 sparki Exp $ */
/*
 * Copyright (C) 1998-2004 RSA Security Inc.
 *
 * This file shall only be used to demonstrate how to interface to an
 * RSA Security Inc. licensed development product.
 *
 * You have a royalty-free right to use, reproduce and distribute this
 * demonstration file, provided that you agree that RSA Security Inc.
 * has no warranty, implied or otherwise, or liability for this
 * demonstration file (including any modified version).  This software
 * is provided "as is" without warranties or representations of any
 * kind. RSA Security disclaims all conditions and warranties, statutory
 * and otherwise, both express and implied, with respect to the software,
 * its quality and performance, including but not limited to, all
 * implied warranties of merchantability, fitness for a particular
 * purpose, title and noninfringement of third party rights. Without
 * limiting the foregoing, RSA Security does not warrant that the
 * software is error-free or that errors in the product will be
 * corrected. You agree that RSA Security shall not be liable for any
 * direct, indirect, incidental, special, consequential, punitive or
 * other damages whatsoever resulting from your use of this software
 * or any modified version.
 *
 *
 */

/*  This program demonstrates the use of AI_FeedbackCipher with DES.
 *  This program can be easily modified to use different feedback modes
 *  or block ciphers, by modifying the fbParams structure below.  For
 *  other related examples, see tdescfb.c, rc2ecb.c, and rc5ofb.c
 */

#include "bsafe.h"
#include "demoutil.h"  /* in samples/common/include */
#include "bsfutil.h"   /* in samples/common/include */

/*  Feedback Mode:  cbc or cbc_interleaved  */
#define FB_MODE "cbc"

/*  To use other feedback modes, add the new AM's to the chooser and
 *  modify the calls to B_SetAlgorithmInfo.  Specifically, the
 *  feedbackParams field of fbParams.
 */

#define PADDING "pad"  /*  Padding scheme:  pad or nopad  */

/*  Note that for "nopad", the input length must be a multiple of the
 *  block size.  The current dataToEncrypt will work for both padding
 *  options.
 */

#define BLOCK_CIPHER "des"
#define KEY_BYTES 8  /*  supply 64 bits for the DES key  */
#define BLOCK_SIZE 8  /*  8 byte block size  */

/*  To use other block ciphers, add the new AM's to the chooser and
 *  modify the calls to B_SetAlgorithmInfo.  Specifically, modify the
 *  encryptionParams field of fbParams as well as use the appropriate key.
 *  Be sure the iv is the same length as the block size.
 */

#ifdef CRYPTOC_APP
#define MAIN descbcMain
#else
#define MAIN main
#endif

int MAIN(int argc, char *argv[])
{
  int status;

  B_ALGORITHM_METHOD *DES_CBC_Chooser[] = {
    &AM_CBC_ENCRYPT,
    &AM_CBC_DECRYPT,
    &AM_CBC_INTER_LEAVED_ENCRYPT,
    &AM_CBC_INTER_LEAVED_DECRYPT,
    &AM_DES_ENCRYPT,
    &AM_DES_DECRYPT,
    (B_ALGORITHM_METHOD *)NULL_PTR
 /* This will fix a problem that the IA64 compiler finds when *
  * seeing a short chooser list */
 #ifdef IA64_FORCE_LARGE
                IA64_FORCE_LARGE
 #endif
  };



  unsigned char dataToEncrypt[] = {
    0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x20,
    0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x65, 0x6e,
    0x74, 0x65, 0x6e, 0x63, 0x65, 0x21, 0x20, 0x20,
    0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x20,
    0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x65, 0x6e,
    0x74, 0x65, 0x6e, 0x63, 0x65, 0x21, 0x20, 0x00
  };

  unsigned int dataToEncryptLen = sizeof(dataToEncrypt);

  ITEM *cryptocDESKey = NULL;
  unsigned char keyData[KEY_BYTES];
  unsigned char ivBytes[BLOCK_SIZE];
  ITEM ivItem = {NULL, 0};

  B_KEY_OBJ desKey = (B_KEY_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ randomAlgorithm = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ encryptionObject = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ decryptionObject = (B_ALGORITHM_OBJ)NULL_PTR;

  B_BLK_CIPHER_W_FEEDBACK_PARAMS fbParams;

  unsigned int outputLenUpdate, outputLenFinal, outputLenTotal;
  unsigned int encryptedDataLen, decryptedDataLen = 0;
  unsigned char *encryptedData = NULL_PTR;
  unsigned char *decryptedData = NULL_PTR;

  do {
    /* The RSA_* demo code utilities are described in
       common/include/demoutil.h.  This procedure simply checks the
       command-line arguments for input or output options. */
    if ((status = RSA_SetOptions (argc, argv)) != 0)
      break;

    RSA_PrintMessage ("DES Feedback Cipher Example\n");
    RSA_PrintMessage ("===========================\n");
    RSA_PrintMessage ("\nFeedback method:  %s\n\n", FB_MODE);

    /*  Initialize a random algorithm object using a procedure described in
        samples/common/include/bsfutil.h  */
    if ((status = RSA_CreateRandomAlgorithmObject (&randomAlgorithm)) != 0)
      break;

    /*  Create a key object  */
    if ((status = B_CreateKeyObject (&desKey)) != 0)
      break;

    /*  Set the key object  */
    /*  Generate 64 random bits for the DES key.  The key is parity
        adjusted when it is copied to the key object.  */
    if ((status = B_GenerateRandomBytes (randomAlgorithm, keyData, KEY_BYTES,
                                         (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    RSA_PrintBuf ("Random bytes supplied for the key", keyData, KEY_BYTES);

    if ((status = B_SetKeyInfo (desKey, KI_DES8Strong, (POINTER)keyData)) != 0)
      break;

    /*  desKey now contains the parity-adjusted DES key.  This symmetric key
        will be used for encryption and decryption.  */

    /*  Retrieve the parity-adjusted key. The returned pointer is to the 
            memory that belongs to Crypto-C.  In a real application, if wanting
                to transport the key for example, we would have to make our own 
            copy of this information.  */
    if ((status = B_GetKeyInfo ((POINTER *)&cryptocDESKey, desKey,
                                KI_Item)) != 0)
      break;

    RSA_PrintBuf ("Parity-adjusted DES key", cryptocDESKey->data,
                  cryptocDESKey->len);

    RSA_PrintBuf ("Data To Encrypt", dataToEncrypt, dataToEncryptLen);

    /*  Create an algorithm object  */
    if ((status = B_CreateAlgorithmObject (&encryptionObject)) != 0)
      break;

    /*  Set the algorithm object with the algorithm information  */
    if ((status = B_GenerateRandomBytes (randomAlgorithm, ivBytes, BLOCK_SIZE,
                                         (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    ivItem.data = ivBytes;
    ivItem.len = BLOCK_SIZE;

    RSA_PrintBuf ("Initialization Vector", ivItem.data, ivItem.len);

    fbParams.encryptionMethodName = (unsigned char *)BLOCK_CIPHER;
    fbParams.encryptionParams = NULL_PTR;
    fbParams.feedbackMethodName = (unsigned char *)FB_MODE;
    fbParams.feedbackParams = (POINTER)&ivItem;
    fbParams.paddingMethodName = (unsigned char *)PADDING;
    fbParams.paddingParams = NULL_PTR;

    /*  Set the algorithm information.  Note that this algorithm information
        applies to encryption and decryption, so at this point our algorithm
        object is not yet committed to performing encryption.  */
    if ((status = B_SetAlgorithmInfo (encryptionObject, AI_FeedbackCipher,
                                      (POINTER)&fbParams)) != 0)
      break;

    /*  Initialize the algorithm object to perform encryption  */
    if ((status = B_EncryptInit (encryptionObject, desKey, DES_CBC_Chooser,
                                 (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Update  */
    /*  Allocate space to store the encrypted data.  At most, we could end
        up with one block of padding.  However if no padding is used, the
        encrypted data will be the same length as the data to encrypt.  */
    encryptedDataLen = dataToEncryptLen + BLOCK_SIZE;
    encryptedData = T_malloc (encryptedDataLen);
    if (encryptedData == NULL_PTR) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    if ((status = B_EncryptUpdate (encryptionObject, encryptedData,
                                   &outputLenUpdate, encryptedDataLen,
                                   dataToEncrypt, dataToEncryptLen,
                                   (B_ALGORITHM_OBJ)NULL_PTR,
                                   (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Finalize the process  */
    if ((status = B_EncryptFinal (encryptionObject,
                                  encryptedData + outputLenUpdate,
                                  &outputLenFinal,
                                  encryptedDataLen - outputLenUpdate,
                                  (B_ALGORITHM_OBJ)NULL_PTR,
                                  (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    outputLenTotal = outputLenUpdate + outputLenFinal;

    RSA_PrintBuf ("Encrypted Data", encryptedData, outputLenTotal);

    RSA_PrintMessage ("\nDecrypting...\n\n");

    /*  Create an algorithm object  */
    if ((status = B_CreateAlgorithmObject (&decryptionObject)) != 0)
      break;

    /*  Set the algorithm object with the algorithm information  */
    /*  We'll use the same algorithm information and initialization vector
        that we used for encryption.  */
    if ((status = B_SetAlgorithmInfo (decryptionObject, AI_FeedbackCipher,
                                      (POINTER)&fbParams)) != 0)
      break;

    /*  Initialize the algorithm object to perform decryption  */
    /*  We'll use the same symmetric key that we used to encrypt with.  */
    if ((status = B_DecryptInit (decryptionObject, desKey, DES_CBC_Chooser,
                                 (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Update  */
    /*  Allocate space to store the decrypted data.  The decrypted data can
        not be longer than the encrypted data.  If we are not using padding,
        they will be the same length.  If we are using padding, the decrypted
        data can be anywhere from 1 to 7 bytes shorter than the length of the
        encrypted data.  */
    decryptedDataLen = encryptedDataLen;
    decryptedData = T_malloc (decryptedDataLen);
    if (decryptedData == NULL_PTR) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    if ((status = B_DecryptUpdate (decryptionObject, decryptedData,
                                   &outputLenUpdate, decryptedDataLen,
                                   encryptedData, outputLenTotal,
                                   (B_ALGORITHM_OBJ)NULL_PTR,
                                   (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Finalize the process  */
    if ((status = B_DecryptFinal (decryptionObject,
                                  decryptedData + outputLenUpdate,
                                  &outputLenFinal,
                                  decryptedDataLen - outputLenUpdate,
                                  (B_ALGORITHM_OBJ)NULL_PTR,
                                  (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    outputLenTotal = outputLenUpdate + outputLenFinal;

    RSA_PrintBuf ("Decrypted Data", decryptedData, outputLenTotal);

    if ((outputLenTotal == dataToEncryptLen) &&
        (T_memcmp (dataToEncrypt, decryptedData, outputLenTotal)) == 0) {
      RSA_PrintMessage ("Success!  ");
      RSA_PrintMessage ("The decrypted data matches the original data.\n");
    } else {
      RSA_PrintMessage ("The decrypted data does not match the original data.");
      status = RSA_DEMO_E_INFO_DOES_NOT_VERIFY;
    }
  } while(0);

  if (status != 0)
    RSA_PrintError ("descbc", status);

  /*  Destroy all objects and free memory  */
  B_DestroyKeyObject (&desKey);
  B_DestroyAlgorithmObject (&randomAlgorithm);
  B_DestroyAlgorithmObject (&encryptionObject);
  B_DestroyAlgorithmObject (&decryptionObject);

  if (encryptedData != NULL_PTR) {
    T_free(encryptedData);
    encryptedData = NULL_PTR;
  }

  if (decryptedData != NULL_PTR) {
    T_memset (decryptedData, 0, decryptedDataLen);
    T_free(decryptedData);
    decryptedData = NULL_PTR;
  }

  return (status);
}

Copyright (c) 1999-2005 RSA Security Inc. All rights reserved. 068-001001-6210-001-000 - 6.2.1