RSA BSAFE Crypto-C

Cryptographic Components for C

Search

pkcs5v2pbe.c

/* $Id: pkcs5v2pbe.c,v 1.6.4.1 2005/02/23 05:08:59 spatel 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 is a Password-Based Encryption program.  This sample demonstrates
 *  the use of AI_PKCS5_V2_PBE to do PKCS #5v2 pbe.
 */

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

#define SALT_LEN 8
#define MAX_PW_LEN 20
#define BLOCK_SIZE 8
#define KEY_BITS 24*8

B_ALGORITHM_METHOD *PBE_CHOOSER[] = {
  &AM_SHA,
  &AM_RC2_CBC_ENCRYPT,
  &AM_RC2_CBC_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
};


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

int MAIN(int argc, char *argv[])
{
  B_ALGORITHM_OBJ pbEncrypter = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ pbDecrypter = (B_ALGORITHM_OBJ)NULL_PTR;
  B_ALGORITHM_OBJ randomAlgorithm = (B_ALGORITHM_OBJ)NULL_PTR;

  B_KEY_OBJ pbeKey = (B_KEY_OBJ)NULL_PTR;

  B_PKCS5_V2_PBE_PARAMS pbeParams;
  B_DIGEST_SPECIFIER prfParams;
  A_RC2_CBC_PARAMS rc2Params;

  unsigned char saltData[SALT_LEN];

  unsigned char iv[8] = {
    0x17, 0x7D, 0x65, 0xB6, 0x70, 0xF9, 0xE2, 0xEE
  };

  unsigned char enteredPassword[MAX_PW_LEN];
  ITEM keyItem;

  unsigned char dataToEncrypt[] = "Encrypt this sentence.";
  unsigned int dataToEncryptLen;
  unsigned char *encryptedData = NULL_PTR;
  unsigned int outputLenUpdate, outputLenFinal;
  unsigned int encryptedDataLen, decryptedDataLen;

  unsigned char *decryptedData = NULL_PTR;
  unsigned int decryptedLenUpdate, decryptedLenFinal;

  int status;

  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 ("Password-Based algorithm:  Encryption phase\n");
    RSA_PrintMessage ("===========================================\n");

    dataToEncryptLen = T_strlen ((char *)dataToEncrypt) + 1;

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

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

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

    /*  Set the algorithm to AI_PKCS5_V2_PBE.  */

    /*  Generate the bytes to get an 8-byte random "salt" */
    if ((status = B_GenerateRandomBytes (randomAlgorithm, saltData, SALT_LEN,
                                         (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    rc2Params.effectiveKeyBits = 80;
    rc2Params.iv = iv;

    /*  The digestInfoType can be either AI_SHA1 or AI_SHA256*/
    prfParams.digestInfoType = AI_SHA1;
    prfParams.digestInfoParams = NULL_PTR;

    pbeParams.salt.data = saltData;
    pbeParams.salt.len = 8;
    pbeParams.iterationCount = 1000;
    pbeParams.keyLenOctets = KEY_BITS/8;

    /*  The pseudoRandomFunction must be AI_HMAC */
    pbeParams.pseudoRandomFunction = AI_HMAC;
    pbeParams.prfParams = (POINTER)&prfParams;
    pbeParams.prfBER = AI_HMAC_BER;

    pbeParams.encryptionAlgorithm = AI_RC2_CBCPad;
    pbeParams.encAlgParams = (POINTER)&rc2Params;
    pbeParams.encAlgBER = AI_RC2_CBCPadBER;


    RSA_PrintBuf ("Salt", saltData, BLOCK_SIZE);

    if ((status = B_SetAlgorithmInfo (pbEncrypter, AI_PKCS5_V2_PBE,
                                      (POINTER)&pbeParams)) != 0)
       break;

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

    /*  Set the key object -- The data portion of the struct
                  is the password.  An insecure method for entering the
                  password would be the following.  This is simply for
                  illustrative purposes, not for duplication.  (A real
                  application would not allow the password to be echoed
                  to the screen)  */
    if ((status = RSA_GetCommand ((char *)enteredPassword,
                                  sizeof (enteredPassword),
                                  "Enter a password for encryption")) != 0)
      break;

    keyItem.data = enteredPassword;
    keyItem.len = T_strlen ((char *)enteredPassword);

    if ((status = B_SetKeyInfo (pbeKey, KI_Item, (POINTER)&keyItem)) != 0)
      break;

    /*  Zeroize the memory and free it up immediately after
        setting the key for security reasons.  */
    T_memset (enteredPassword, 0, sizeof (enteredPassword));

    /*  Init -- A key is needed before the algorithm object can
                be initialized for encryption.  In PBE, the password is
                the key.  */
    if ((status = B_EncryptInit (pbEncrypter, pbeKey, PBE_CHOOSER,
                                 (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Update  */
    encryptedDataLen = dataToEncryptLen + BLOCK_SIZE;
    encryptedData = T_malloc (encryptedDataLen);
    if (encryptedData == NULL_PTR) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

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

    /*  Final  */
    if ((status = B_EncryptFinal (pbEncrypter, encryptedData + outputLenUpdate,
                                  &outputLenFinal,
                                  encryptedDataLen - outputLenUpdate,
                                  (B_ALGORITHM_OBJ)NULL_PTR,
                                  (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    encryptedDataLen = outputLenUpdate + outputLenFinal;

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

    /* Destroy the key object now, rebuild a new one for decryption. */
    B_DestroyKeyObject (&pbeKey);

    RSA_PrintMessage ("\nPassword-Based algorithm:  Decryption phase\n");
    RSA_PrintMessage ("===========================================\n");

    if ((status = B_CreateAlgorithmObject (&pbDecrypter)) != 0)
      break;

    /* Use the same parameters that were set for encryption  */
    if ((status = B_SetAlgorithmInfo (pbDecrypter, AI_PKCS5_V2_PBE,
                                      (POINTER)&pbeParams)) != 0)
      break;

    /* Build a key from a new password. If it is the same password (and
       salt), the key will work  */
    if ((status = B_CreateKeyObject (&pbeKey)) != 0)
      break;

    if ((status = RSA_GetCommand ((char *)enteredPassword,
                                  sizeof (enteredPassword),
                                  "Enter a password for decryption")) != 0)
      break;

    keyItem.data = enteredPassword;
    keyItem.len = T_strlen ((char *)keyItem.data);

    if ((status = B_SetKeyInfo (pbeKey, KI_Item, (POINTER)&keyItem)) != 0)
      break;

    /*  Zeroize the memory and free it up immediately after
        setting the key for security reasons.   */
    T_memset (enteredPassword, 0, sizeof (enteredPassword));

    if ((status = B_DecryptInit (pbDecrypter, pbeKey, PBE_CHOOSER,
                                 (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  The size of the decrypted data can be no larger than the size of the
        encrypted data.  */
    decryptedDataLen = encryptedDataLen;
    decryptedData = T_malloc (decryptedDataLen);
    if (decryptedData == NULL_PTR) {
      status = RSA_DEMO_E_ALLOC;
      break;
    }

    if ((status = B_DecryptUpdate (pbDecrypter, decryptedData,
                                   &decryptedLenUpdate, decryptedDataLen,
                                   encryptedData, encryptedDataLen,
                                   (B_ALGORITHM_OBJ)NULL_PTR,
                                   (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    if ((status = B_DecryptFinal (pbDecrypter,
                                  decryptedData + decryptedLenUpdate,
                                  &decryptedLenFinal,
                                  decryptedDataLen - decryptedLenUpdate,
                                  (B_ALGORITHM_OBJ)NULL_PTR,
                                  (A_SURRENDER_CTX *)NULL_PTR)) != 0)
      break;

    /*  Now we know how long the decrypted data actually is.  */
    decryptedDataLen = decryptedLenUpdate + decryptedLenFinal;

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

    if ((decryptedDataLen == dataToEncryptLen) &&
        (T_memcmp (dataToEncrypt, decryptedData, decryptedDataLen)) == 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 ("pkcs5v2pbe", status);

  /*  Destroy the key and algorithm objects.  */
  B_DestroyKeyObject (&pbeKey);
  B_DestroyAlgorithmObject (&pbEncrypter);
  B_DestroyAlgorithmObject (&randomAlgorithm);
  B_DestroyAlgorithmObject (&pbDecrypter);

  /*  Free up any memory allocated, save it to a file or print it out first
      if you need to save it.  */
  if (encryptedData != NULL_PTR) {
    T_free (encryptedData);
    encryptedData = NULL_PTR;
  }

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

  return (status);
} /*  end main  */

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