RSA BSAFE Cert-C

Certificate Components for C

Crypto-C 6.2.1 Developer's Guide
Search

b64.c

Converts a file containing binary data to ASCII, or converts a file containing base-64-encoded (ascii-encoded) data to binary

/* $Id: b64.c,v 1.6 2005/01/28 02:30:21 alockwoo Exp $ */
/* b64.c
** Copyright (c) 1999-2003, RSA Security Inc.
**
** This file is used to demonstrate how to interface to an RSA Security
** licensed development product.  You have a royalty-free right to use,
** modify, reproduce and distribute this demonstration file (including
** any modified version), provided that you agree that RSA Security has
** no warranty, implied or otherwise, or liability for this demonstration
** file or any modified version.
**
** This program will convert a file containing binary data to ascii, or
** convert a file containing base-64-encoded (ascii-encoded) data to binary.
** This really should be a Crypto-C sample, but is provided for convenience.
*/

#include "demoutil.h"

#ifdef _MSC_VER
# pragma warning (disable: 171) /* invalid type conversion (often of very similar ptrs) */
#endif

/*  Prompt the user for a file containing binary data.  Base-64 encode the
 *  binary data, display the ascii-encoded data, and save it to a file.
 */
static int RSA_GetBinaryFileToAscii (void);

/*  Prompt the user for a file containing ascii-encoded data.  Base-64 decode
 *  the ascii data and save the resulting binary to a file.
 */
static int RSA_GetAsciiFileToBinary (void);

/*  Base-64 decode ascii data.  The buffer supplied should be the same size as
 *  the input buffer.  This is just for simplicity; the output data will
 *  be smaller than the input data.
 */
static int AsciiDecode (ITEM *asciiEncoding, unsigned char *binary,
                        unsigned int binaryMaxLen, unsigned int *binaryLen);

/*  Base-64 encode binary data.  For simplicity, supply a buffer twice the
 *  size of the binary input to hold the ascii-encoded data.
 */
static int AsciiEncode
   (ITEM *binaryData, unsigned char *asciiEncoding,
    unsigned int asciiEncodingMaxLen, unsigned int *asciiEncodingLen);

/*  Given data produced by B_EncodeUpdate()/B_EncodeFinal, add the necessary
 *  carriage returns so that there are charsPerLine characters per line.
 *  Crypto-C (unlike Crypto-J) does not do this for you.  The string pointer
 *  will point to a null-terminated string.
 *
 *  The calling function should free the string buffer.
 */
static int BsafeAsciiToFormattedString (ITEM *ascii, unsigned int charsPerLine,
                                        char **string);

/*  Prompt the user for a file containing binary data.  Base-64 encode the
 *  binary data, display the ascii-encoded data, and save it to a file.  This
 *  function uses C_EncodeBase64.
 */
static int CertC_GetBinaryFileToAscii (void);

/*  Prompt the user for a file containing ascii-encoded data.  Base-64 decode
 *  the ascii data and save the resulting binary to a file.  This function
 *  uses C_DecodeBase64.
 */
static int CertC_GetAsciiFileToBinary (void);

int main (int argc, char *argv[])
{
  int status = 0;
  char command[RSA_DEMO_MAX_LINE_LEN];

  status = RSA_SetOptions (NULL, argc, argv);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Base-64 Encoding/Decoding Demo\n");
  RSA_PrintMessage ("==============================\n");

  for (;;) {
    RSA_PrintMessage ("  A - Convert a file from binary to ascii\n");
    RSA_PrintMessage ("  B - Convert a file from ascii to binary\n");
    RSA_PrintMessage ("  C - Use C_EncodeBase64 to go from binary to ascii\n");
    RSA_PrintMessage ("  D - Use C_DecodeBase64 to go from ascii to binary\n");
    status = RSA_GetCommand (command, sizeof (command),
                             "Enter choice (blank to quit)");
    if (status != 0)
      goto CLEANUP;

    switch (command[0]) {
      case 'a':
      case 'A':
        status = RSA_GetBinaryFileToAscii ();
        break;
      case 'b':
      case 'B':
        status = RSA_GetAsciiFileToBinary ();
        break;
      case 'c':
      case 'C':
        status = CertC_GetBinaryFileToAscii ();
        break;
      case 'd':
      case 'D':
        status = CertC_GetAsciiFileToBinary ();
        break;
      case '\0':
      case 'q':
      case 'Q':
        goto CLEANUP;
      default:
        RSA_PrintMessage ("Unrecognized Option: %c\n", command[0]);
        status = RSA_DEMO_E_INVALID_PARAMETER;
    }

    if (status != 0) {
      RSA_PrintMessage ("Operation not completed.\n");
      goto CLEANUP;
    }
    else {
      RSA_PrintMessage ("Operation successful!\n");
    }
  }      
  
CLEANUP:
  if (status != 0)
    RSA_PrintError ("b64.c", status);

  return status;
}  /* end main */

/* See function declaration at the top for a description */
int RSA_GetBinaryFileToAscii ()
{
  int status = 0;
  char *string = NULL;
  ITEM binaryData = {NULL, 0}, asciiData = {NULL, 0};

  status = RSA_GetFileToAllocBuffer
           (&binaryData.data, &binaryData.len,
            "Enter name of file containing binary data");
  if (status != 0)
    goto CLEANUP;

  /* ensure that there are at least 4 bytes for the ascii data, in case
     someone wants to encode one binary byte... */
  asciiData.len = (binaryData.len * 2) + 4;
  asciiData.data = T_malloc (asciiData.len);
  if (asciiData.data == NULL) {
    status = RSA_DEMO_E_ALLOC;
    goto CLEANUP;
  }

  status = AsciiEncode (&binaryData, asciiData.data, asciiData.len,
                        &asciiData.len);
  if (status != 0)
    goto CLEANUP;

  status = BsafeAsciiToFormattedString (&asciiData, 64, &string);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Binary data length = %u bytes\n", binaryData.len);
  RSA_PrintMessage ("Ascii data buffer size = %u bytes\n", asciiData.len);
  RSA_PrintMessage ("\nAscii-encoded data:\n%s\n", string);

  status = RSA_WriteDataToFile ((unsigned char *)string, T_strlen (string),
                                "Enter name of file to store ascii data");

CLEANUP:
  if (status != 0)
    RSA_PrintError ("RSA_GetBinaryFileToAscii", status);

  T_free (binaryData.data);
  T_free (asciiData.data);
  T_free ((unsigned char *)string);
  
  return status;
}  /* end RSA_GetBinaryFileToAscii */

/* See function declaration at the top for a description */
int RSA_GetAsciiFileToBinary ()
{
  int status = 0;
  ITEM asciiData = {NULL, 0}, binaryData = {NULL, 0};

  status = RSA_GetFileToAllocBuffer
           (&asciiData.data, &asciiData.len,
            "Enter name of file containing ascii data");
  if (status != 0)
    goto CLEANUP;

  binaryData.len = asciiData.len;
  binaryData.data = T_malloc (binaryData.len);
  if (binaryData.data == NULL) {
    status = RSA_DEMO_E_ALLOC;
    goto CLEANUP;
  }

  status = AsciiDecode (&asciiData, binaryData.data, binaryData.len,
                        &binaryData.len);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Ascii data buffer size = %u bytes\n", asciiData.len);
  RSA_PrintMessage ("Binary data length = %u bytes\n", binaryData.len);

  status = RSA_WriteDataToFile (binaryData.data, binaryData.len,
                                "Enter name of file to store binary data");

CLEANUP:
  if (status != 0)
    RSA_PrintError ("RSA_GetAsciiFileToBinary", status);

  T_free (binaryData.data);
  T_free (asciiData.data);

  return status;
}  /* end RSA_GetAsciiFileToBinary */

/* See function declaration at the top for a description */
static int AsciiDecode (ITEM *asciiEncoding, unsigned char *binary,
                        unsigned int binaryMaxLen, unsigned int *binaryLen)
{
  int status = 0;
  unsigned int outputLenUpdate = 0, outputLenFinal = 0;
  B_ALGORITHM_OBJ decoder = NULL;

  status = B_CreateAlgorithmObject (&decoder);
  if (status != 0)
    goto CLEANUP;

  status = B_SetAlgorithmInfo (decoder, AI_RFC1113Recode, NULL);
  if (status != 0)
    goto CLEANUP;

  status = B_DecodeInit (decoder);
  if (status != 0)
    goto CLEANUP;

  status = B_DecodeUpdate (decoder, binary, &outputLenUpdate, binaryMaxLen,
                           asciiEncoding->data, asciiEncoding->len);
  if (status != 0)
    goto CLEANUP;

  status = B_DecodeFinal (decoder, binary+outputLenUpdate, &outputLenFinal,
                          binaryMaxLen-outputLenUpdate);
  if (status != 0)
    goto CLEANUP;

  *binaryLen = outputLenUpdate + outputLenFinal;

CLEANUP:
  if (status != 0) {
    *binaryLen = 0;
    RSA_PrintError ("AsciiDecode", status);
  }

  B_DestroyAlgorithmObject (&decoder);

  return status;
}  /* end AsciiDecode */

/* See function declaration at the top for a description */
static int AsciiEncode
   (ITEM *binaryData, unsigned char *asciiEncoding,
    unsigned int asciiEncodingMaxLen, unsigned int *asciiEncodingLen)
{
  int status = 0;
  unsigned int outputLenUpdate = 0, outputLenFinal = 0;
  B_ALGORITHM_OBJ encoder = NULL;

  status = B_CreateAlgorithmObject (&encoder);
  if (status != 0)
    goto CLEANUP;

  status = B_SetAlgorithmInfo (encoder, AI_RFC1113Recode, NULL);
  if (status != 0)
    goto CLEANUP;

  status = B_EncodeInit (encoder);
  if (status != 0)
    goto CLEANUP;

  status = B_EncodeUpdate
           (encoder, asciiEncoding, &outputLenUpdate, asciiEncodingMaxLen,
            binaryData->data, binaryData->len);
  if (status != 0)
    goto CLEANUP;

  status = B_EncodeFinal
           (encoder, asciiEncoding+outputLenUpdate, &outputLenFinal,
            asciiEncodingMaxLen-outputLenUpdate);
  if (status != 0)
    goto CLEANUP;

  *asciiEncodingLen = outputLenUpdate + outputLenFinal;
  
CLEANUP:
  if (status != 0) {
    *asciiEncodingLen = 0;
    RSA_PrintError ("AsciiEncode", status);
  }

  B_DestroyAlgorithmObject (&encoder);
  
  return status;
}  /* end AsciiEncode */

/* See function declaration at the top for a description */
static int BsafeAsciiToFormattedString (ITEM *ascii, unsigned int charsPerLine,
                                        char **string)
{
  int status = 0, stringBytes = 0, stringIndex = 0;
  unsigned int asciiIndex = 0;

  stringBytes = (ascii->len + (ascii->len + charsPerLine - 1) / charsPerLine)
                + 1;

  *string = (char *)T_malloc (stringBytes);
  if (*string == NULL) {
    status = BE_ALLOC;
    goto CLEANUP;
  }

  T_memset ((unsigned char *)*string, 0, stringBytes);
  for (asciiIndex = 0; asciiIndex < ascii->len; asciiIndex++) {
    (*string)[stringIndex++] = ascii->data[asciiIndex];
    if ((asciiIndex % charsPerLine == charsPerLine - 1) ||
        (asciiIndex + 1 == ascii->len))
      (*string)[stringIndex++] = '\n';
  }

CLEANUP:
  if (status != 0) {
    T_free ((unsigned char *)*string);
    *string = NULL;
    RSA_PrintError ("BsafeAsciiToFormattedString", status);
  }

  return status;
}  /* end BsafeAsciiToFormattedString */

/* See function declaration at the top for a description */
int CertC_GetBinaryFileToAscii ()
{
  int status = 0;
  ITEM binaryData = {NULL, 0}, asciiData = {NULL, 0};

  status = RSA_GetFileToAllocBuffer
           (&binaryData.data, &binaryData.len,
            "Enter name of file containing binary data");
  if (status != 0)
    goto CLEANUP;

  status = C_EncodeBase64 (NULL, &asciiData.len, binaryData.data,
                           binaryData.len);
  if (status != 0)
    goto CLEANUP;

  asciiData.data = T_malloc (asciiData.len);
  if (asciiData.data == NULL) {
    status = RSA_DEMO_E_ALLOC;
    goto CLEANUP;
  }

  RSA_PrintMessage ("Binary data length = %u bytes\n", binaryData.len);
  RSA_PrintMessage ("Ascii data buffer size = %u bytes\n", asciiData.len);

  status = C_EncodeBase64 (asciiData.data, &asciiData.len, binaryData.data,
                           binaryData.len);
  if (status != 0)
    goto CLEANUP;

  status = RSA_WriteDataToFile (asciiData.data, asciiData.len,
                                "Enter name of file to store ascii data");

CLEANUP:
  if (status != 0)
    RSA_PrintError ("CertC_GetBinaryFileToAscii", status);

  T_free (binaryData.data);
  T_free (asciiData.data);

  return status;
}  /* end CertC_GetBinaryFileToAscii */

/* See function declaration at the top for a description */
int CertC_GetAsciiFileToBinary ()
{
  int status = 0;
  ITEM asciiData = {NULL, 0}, binaryData = {NULL, 0};

  status = RSA_GetFileToAllocBuffer
           (&asciiData.data, &asciiData.len,
            "Enter name of file containing ascii data");
  if (status != 0)
    goto CLEANUP;

  status = C_DecodeBase64 (NULL, &binaryData.len, asciiData.data,
                           asciiData.len);
  if (status != 0)
    goto CLEANUP;

  binaryData.data = T_malloc (binaryData.len);
  if (binaryData.data == NULL) {
    status = RSA_DEMO_E_ALLOC;
    goto CLEANUP;
  }

  status = C_DecodeBase64 (binaryData.data, &binaryData.len, asciiData.data,
                           asciiData.len);
  if (status != 0)
    goto CLEANUP;

  RSA_PrintMessage ("Ascii data buffer size = %u bytes\n", asciiData.len);
  RSA_PrintMessage ("Binary data length = %u bytes\n", binaryData.len);

  status = RSA_WriteDataToFile (binaryData.data, binaryData.len,
                                "Enter name of file to store binary data");

CLEANUP:
  if (status != 0)
    RSA_PrintError ("CertC_GetAsciiFileToBinary", status);

  T_free (binaryData.data);
  T_free (asciiData.data);

  return status;
}  /* end CertC_GetAsciiFileToBinary */

Copyright (c) 1999-2005 RSA Security Inc. All rights reserved. 067-001001-2720-001-000 - 2.7.2