000023923 - How to Base64 encode and decode in Crypto-C ME

Document created by RSA Customer Support Employee on Jun 16, 2016Last modified by RSA Customer Support Employee on Apr 21, 2017
Version 2Show Document
  • View in full screen mode

Article Content

Article Number000023923
Applies ToRSA BSAFE Crypto-C Micro Edition 2.1
IssueHow to Base64 encode and decode in Crypto-C ME
The documentation of R_BASE64_encode and R_BASE64_decode is missing in the 2.1 release.  This will be fixed in 3.0.
Resolution

Here is the missing documentation:

int R_CDECL R_BASE64_decodeunsigned int   dlen,


unsigned char *   dbuf,


int *   eol,


unsigned char *   obuf,


unsigned int *   olen

;
 

Base64 decodes the data in the buffer dbuf. If obuf is NULL then the (best approximation of the) output length will be returned in olen.

Parameters:
dlen[In] The length of the data to decode.
dbuf[In] The data to decode.
eol[Out] The end-of-line type.
See End Of Line Types for valid values.
obuf[Out] The buffer for the decoded data.
olen[Out] The length of the decoded data.
Returns:
R_ERROR_NONE indicates success.
See Error Management Identifiers for valid values.


int R_CDECL R_BASE64_encodeunsigned int   dlen,


unsigned char *   dbuf,


int   eol,


unsigned char *   obuf,


unsigned int *   olen

;

The "End Of Line Types" are defined like this:



#define R_BASE64_EOL_NONE
 Indicates that the data contains no end of line characters.
#define R_BASE64_EOL_CR
 Indicates that the data contains carriage return end of line characters.
#define R_BASE64_EOL_LF
 Indicates that the data contains line feed end of line characters.
#define R_BASE64_EOL_CR_LF
 Indicates that the data contains carriage return and line feed end of line characters.
 

This sample code shows how to use these methods:

#include "r_prod.h"
#include "cryp_mod.h"
BIO_METHOD *BIO_f_base64(void);

#include "r_base64.h"

void main(void)
{
    char *data = "encode this";
    int dataBytes = strlen(data);  /* note: don't use strlen() with binary data */
    int i = 0;
    // encode
    char encodedData[100];
    int encodedDataMaxLen = 100;
    int encodedBytes = 0;
    // decode
    int decodedBytes = 0;
    char decodedData[100];
    int decodedDataMaxLen = 100;
    int eol = 0;
    int ret = 0;

    /* Encode data into Base64 format: */

    encodedBytes = encodedDataMaxLen;

/*int R_CDECL R_BASE64_encode(unsigned int dlen, unsigned char *dbuf, int eol,
    unsigned char *obuf, unsigned int *olen);*/
/* If obuf is NULL then the (best approximation of the) output length will be returned in olen. */

    ret = R_BASE64_encode((unsigned int)(dataBytes),
                            (unsigned char *)(data),
                            R_BASE64_EOL_NONE,
                            (unsigned char *)(encodedData),
                            (unsigned int *)(&encodedBytes)
    );

    /* Output the Base64 encoded data. */
    printf("encodedBytes = %d\n", encodedBytes);
    printf("encodedBytes: ");
    for(i=0; i<encodedBytes; i++)
    {
        printf("%c", encodedData[i]);
    }

    /* Decode data from Base64 format. */

    decodedBytes = decodedDataMaxLen;

/*int R_CDECL R_BASE64_decode(unsigned int dlen, unsigned char *dbuf, int *eol,
    unsigned char *obuf, unsigned int *olen);*/
/* If obuf is NULL then the (best approximation of the) output length will be returned in olen. */

    ret = R_BASE64_decode((unsigned int)(encodedBytes),
                            (unsigned char *)(encodedData),
                            &eol,
                            (unsigned char *)(decodedData),
                            (unsigned int *)(&decodedBytes)
    );

    /* Output the decoded data. */
    printf("\ndecodedBytes = %d\n", decodedBytes);
    printf("decodedBytes: ");
    for(i=0; i<decodedBytes; i++)
    {
        printf("%c", decodedData[i]);
    }
}

Notes

For Base64 encoding the output size should usually look something like this:

(((length + 2)/3) * 4)

plus 1 if we need space for a terminating NULL character. (R_BASE64_encode() requires this extra byte as it always adds a NULL character to the end of the encoded data.)

R_BASE64_encode() uses internal functions which complicate this by allowing up to two carriage-return/line-feed characters for every 48 bytes of input (64 bytes of output) to support PEM format (RFC1113). Using R_BASE64_EOL_NONE as the third parameter to R_BASE64_encode() causes no carriage-return/line-feed characters to be added, but this is not accounted for in the estimated output buffer size.

The value that is actually returned when R_BASE64_encode() is called with NULL as the third parameter looks like this:

(((length + 2)/3) * 4 + (length/48 + 1) * 2) + 80.

The (length/48 + 1) * 2 accounts for the possible carriage-return/line-feed characters for every 48 input bytes, but the + 80 here appears to be overkill.

In summary, as long as you don't need the carriage-return/line-feed characters for PEM, R_BASE64_encode() requires an output buffer that looks like this:

(((length + 2)/3) * 4) + 1.

If you do require a carriage-return and line-feed, you will need a buffer that looks like this:

(((length + 2)/3) * 4) + (length/48 + 1) * 2) + 1.

For only a carriage-return or line-feed use a buffer like this:

(((length + 2)/3) * 4) + (length/48 + 1)  + 1.

 

Similarly, the value that is returned when R_BASE64_decode() is called with NULL as the third parameter looks like this:

((length+3)/4*3+80)

Again, this is overkill as Base64 encoded data should be a multiple of 4 bytes and there is no NULL added to the end of binary data. The buffer you need for decoded data should look like this:

(length/4)*3


R_BASE64_decode() doesn't check to ensure that the input data is valid base64 encoded data.  If the length of the data is not a multiple of 4 bytes (as all valid base64 encoded data should be), R_BASE64_decode() will simply decode as much as it can without returning an error code.  For example: 3 bytes of input will result in no output and no error code, while 7 bytes of input will result in 3 bytes of output and no error code.

Crypto-C ME 3.0 solves this problem by introducing R_BSASE64_decode_checked() which ensures that the input data is a multiple of 4 bytes.  If not, R_ERROR_BAD_LENGTH (10023) is returned and no decoded data will appear in the output buffer.

Legacy Article IDa36055

Attachments

    Outcomes