RSA BSAFE Crypto-C

Cryptographic Components for C

Search

aesfb.c

/* $Id: aesfb.c,v 1.7 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 AES.
 * The user must supply the feedback mode to be used to encrypt and
 * decrypt, as well as a key size from 1 to 255.
 */

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

/*  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 PADDING "pad"

#define BLOCK_CIPHER "aes"
#define KEY_SIZE 24
#define BLOCK_SIZE 16

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

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

  static B_ALGORITHM_METHOD *AESChooser[] = {
    &AM_AES_ENCRYPT,
    &AM_AES_DECRYPT,
    &AM_CBC_ENCRYPT,
    &AM_CBC_DECRYPT,
    &AM_CBC_INTER_LEAVED_ENCRYPT,
    &AM_CBC_INTER_LEAVED_DECRYPT,
    &AM_CFB_ENCRYPT,
    &AM_CFB_DECRYPT,
    &AM_CFB_PIPELINED_ENCRYPT,
    &AM_CFB_PIPELINED_DECRYPT,
    &AM_ECB_ENCRYPT,
    &AM_ECB_DECRYPT,
    &AM_OFB_ENCRYPT,
    &AM_OFB_DECRYPT,
    &AM_OFB_PIPELINED_ENCRYPT,
    &AM_OFB_PIPELINED_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
  };



  ITEM dataToEncrypt = {NULL_PTR, 0}, aesKeyItem = {NULL_PTR, 0};

  B_KEY_OBJ aesKey = (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;

  void (*destroyFbMethod) (B_BLK_CIPHER_W_FEEDBACK_PARAMS *fbParams) = NULL;

  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 ("AES Feedback Cipher Example\n");
    RSA_PrintMessage ("===========================\n");

    /*  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(&aesKey)) != 0)
      break;

    /*  Set the key object  */
    aesKeyItem.len = KEY_SIZE;
    aesKeyItem.data = T_malloc (aesKeyItem.len);
    if (aesKeyItem.data == NULL) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    if ((status = B_GenerateRandomBytes
                    (randomAlgorithm, aesKeyItem.data, aesKeyItem.len,
                     (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    RSA_PrintBuf ("Random Key Bytes", aesKeyItem.data, aesKeyItem.len);

    if ((status = B_SetKeyInfo (aesKey, KI_Item, (POINTER)&aesKeyItem)) != 0)
      break;

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

    fbParams.encryptionMethodName = (unsigned char *)BLOCK_CIPHER;
    fbParams.encryptionParams = NULL_PTR;
    fbParams.paddingMethodName = (unsigned char *)PADDING;
    fbParams.paddingParams = NULL_PTR;

    /* This sample procedure is described in samples/common/include/menuutil.h.
       It is used to obtain the user-supplied feedback method name, parameters,
       and the procedure used to clean up any space allocated for the
       feedback method parameters. This procedure populates the
       fbParams->feedbackMethodName and fbParams->feedbackParams fields. */
    if ((status = RSA_GetFeedbackMethod (&fbParams, randomAlgorithm,
                                         &destroyFbMethod)) != 0)
      break;

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

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

    /*  Update  */
    /*  The following function is described in common/include/demoutil.h and
        allocates a buffer to store the information read in from a file.  We
        must call T_free on dataToEncrypt.data later.  */
    if ((status = RSA_GetFileToAllocBuffer
                    (&dataToEncrypt.data, &dataToEncrypt.len,
                     "Enter name of file containing data to encrypt")) != 0)
      break;

    RSA_PrintBuf ("Data To Encrypt", dataToEncrypt.data, dataToEncrypt.len);

    /*  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 = dataToEncrypt.len + 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.data, dataToEncrypt.len,
                     NULL, NULL)) != 0)
      break;

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

    outputLenTotal = outputLenUpdate + outputLenFinal;

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

    RSA_PrintMessage ("\nDecrypting...\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 that we used for encryption.
        These parameters can be passed from the sender to the receiver in the
        clear, along with the encrypted message.  (The only data that must be
        kept private is the bytes which make up the key.  Possible ways to
        transmit those bytes from sender to recipient include encrypting those
        bytes with the recipient's public (RSA or ECC) key, or by using DH or
        ECDH.  */
    RSA_PrintMessage ("Setting algorithm object with same feedback ");
    RSA_PrintMessage ("parameters used to encrypt...\n\n");
    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.  Note
        that the chooser we use contains AMs for both encryption and
        decryption.  If an application only does encryption or only does
        decryption, the entries in the chooser should be adjusted accordingly */
    if ((status = B_DecryptInit (decryptionObject, aesKey, AESChooser,
                                 (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 16 bytes shorter than the length of the
        ciphertext (since there can be up to BLOCK_SIZE bytes of padding). */
    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,
                     NULL, NULL)) != 0)
      break;

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

    outputLenTotal = outputLenUpdate + outputLenFinal;

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

    if ((outputLenTotal == dataToEncrypt.len) &&
        (T_memcmp (dataToEncrypt.data, 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 ("AES Feedback Modes example", status);

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

  if (dataToEncrypt.data != NULL)
    T_free (dataToEncrypt.data);

  if (destroyFbMethod != NULL)
    (*destroyFbMethod) (&fbParams);

  if (aesKeyItem.data != NULL_PTR) {
    T_memset (aesKeyItem.data, 0, aesKeyItem.len);
    T_free (aesKeyItem.data);
  }

  if (encryptedData != NULL_PTR) {
    T_memset (encryptedData, 0, encryptedDataLen);
    T_free(encryptedData);
  }

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

  return (status);
}

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