RSA BSAFE Crypto-C

Cryptographic Components for C

Search

rc5ofb.c

/* $Id: rc5ofb.c,v 1.7 2004/12/03 02:08:42 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 RC5.
 *  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, descbc.c, and rc2ecb.c
 */

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

/*  Feedback Mode  */
#define FB_MODE "ofb"

/*  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 "rc5"  /* or "rc5_64" for a 64-bit word size */
#define VERSION 0x10
#define ROUNDS 12
#define KEY_BYTES 24  /*  RC5 key can be anywhere between 0 and 255 bytes  */
#define BLOCK_SIZE 8  /*  divide this by 2 for the word size in bytes */

/*  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.
 */

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

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

  static B_ALGORITHM_METHOD *RC5_OFB_Chooser[] = {
    &AM_OFB_ENCRYPT,
    &AM_OFB_DECRYPT,
    &AM_OFB_PIPELINED_ENCRYPT,
    &AM_OFB_PIPELINED_DECRYPT,
    &AM_RC5_ENCRYPT,
    &AM_RC5_DECRYPT,
    &AM_RC5_64ENCRYPT,
    &AM_RC5_64DECRYPT,
    (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);

  A_RC5_PARAMS rc5Params;
  ITEM rc5KeyItem = {NULL, 0}, ivItem = {NULL, 0};
  unsigned char keyData[KEY_BYTES];
  unsigned char ivBytes[BLOCK_SIZE];

  B_KEY_OBJ rc5Key = (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 = 0, 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 ("RC5 Feedback Cipher Example\n");
    RSA_PrintMessage ("===========================\n");
    RSA_PrintMessage ("\nFeedback method:  %s\n\n", FB_MODE);

    if ((status = RSA_CreateRandomAlgorithmObject (&randomAlgorithm)) != 0)
      break;

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

    /*  Set the key object  */
    if ((status = B_GenerateRandomBytes (randomAlgorithm, keyData, KEY_BYTES,
                                         (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    RSA_PrintBuf ("Key Bytes", keyData, KEY_BYTES);

    rc5KeyItem.data = keyData;
    rc5KeyItem.len = KEY_BYTES;
    if ((status = B_SetKeyInfo (rc5Key, KI_Item, (POINTER)&rc5KeyItem)) != 0)
      break;

    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  */
    /*  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_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);

    rc5Params.version = VERSION;
    rc5Params.rounds = ROUNDS;
    /* double the word size to get the block size */
    rc5Params.wordSizeInBits = BLOCK_SIZE * 4;

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

    if ((status = B_SetAlgorithmInfo (encryptionObject, AI_FeedbackCipher,
                                      (POINTER)&fbParams)) != 0)
      break;

    /*  Initialize the algorithm object to perform encryption  */
    if ((status = B_EncryptInit (encryptionObject, rc5Key, RC5_OFB_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 ((status = (encryptedData == NULL_PTR)) != 0) {
      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, rc5Key, RC5_OFB_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 ((status = (decryptedData == NULL_PTR)) != 0) {
      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 ("RC5 OFB example", status);

  /*  Destroy all key and algorithm objects  */
  B_DestroyKeyObject (&rc5Key);
  B_DestroyAlgorithmObject (&randomAlgorithm);
  B_DestroyAlgorithmObject (&encryptionObject);
  B_DestroyAlgorithmObject (&decryptionObject);

  /*  Free up any memory used */
  if (encryptedData != NULL_PTR) {
    T_memset (encryptedData, 0, encryptedDataLen);
    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