RSA BSAFE Crypto-C

Cryptographic Components for C

Search

Converting Data Between Base64 and Binary

This sample converts a file containing binary data to ASCII, or a file containing base-64-encoded (ASCII-encoded) data to binary.

/* $Id: b64.c,v 1.6 2004/12/03 02:08:34 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 will convert a file containing 
 * base-64-encoded (ascii-encoded) data to binary.
 */

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

/*  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.
 */
int RSA_GetBinaryFileToAscii ();

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

/*  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.
 *  as Crypto-C does not do this automatically.  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);

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

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

  status = RSA_SetOptions (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");
    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 '\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 */

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
     there is only one binary byte to encode */
  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, 76, &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 */

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);

  return status;
}  /* end RSA_GetAsciiFileToBinary */

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

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

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

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