How to encode and decode Base64 strings in C?

Asked

Viewed 850 times

5

I need to encode (and decode) a JSON to be transmitted from the Web to a microcontroller. The JSON that I am sending is encrypted with the AES 128, but the cyphertext It contains non-printable characters and I got some problems with it. For example, when I try to receive this data on the microcontroller the decryption does not take place correctly. However, if I encrypt and decrypt a string within the microcontroller, the process normally occurs.

I believe that the problem is the character encoding, because there are non-printable characters that are not transmitted. Then I need to do the following steps, exactly in this order:

  1. Encrypt a text using the AES 128
  2. Encode the cyphertext in Base64 to be transmitted via web
  3. Receive data on microcontroller
  4. Decode the cyphertext in Base64, for its natural representation
  5. Decrypt the cyphertext using the AES 128

My question is: how to encode and decode strings base64 in C? Is there a library for this?

Edit: Is there an optimized way to do this? I found an example that contains the algorithm that decodes, but it uses a huge matrix to do this.

  • 1

    If you are using Openssl to encrypt with AES 128, you can also use it to Base64.

  • glib also has functions for base46 http://developer.gnome.org/glib/2.28/glib-Base64-Encoding.html

1 answer

5

Avelino, don’t judge a code by its matrices!

The example you found is based on the file ap_base64.c of the project APR - Apache Portable Runtime (see here the original code), which in turn is quite widespread and used in several other projects. It has been implemented in pure C and does not depend on any other external library.

This huge array full of magic numbers that you mentioned is able to provide a considerable increase in data processing performance in base64, which makes it quite viable.

My suggestion is: Don’t be prejudiced by this code, it is fast, portable and quite efficient.

Follows (therefore) the code itself rewritten to work only with ASCII:

Header base64.h:

/*
    base64.h
*/

#ifndef __BASE64_H__
#define __BASE64_H__

int base64decode_len( const char * bufcoded );
int base64decode( char * bufplain, const char * bufcoded );

int base64encode_len( int len );
int base64encode( char * encoded, const char * string, int len );

#endif

/* fim-de-arquivo */

Implementation base64.c:

/*
    base64.c
*/

#include <string.h>

#include "base64.h"


static int base64decode_binary( unsigned char * bufplain, const char * bufcoded );
static int base64encode_binary( char * encoded, const unsigned char * string, int len );


static const char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static const unsigned char pr2six[256] =
{
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
    64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
    64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};


static int base64decode_binary( unsigned char * bufplain, const char * bufcoded )
{
    int nbytesdecoded;
    register const unsigned char *bufin;
    register unsigned char *bufout;
    register int nprbytes;

    bufin = (const unsigned char *) bufcoded;

    while (pr2six[*(bufin++)] <= 63);

    nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
    nbytesdecoded = ((nprbytes + 3) / 4) * 3;

    bufout = (unsigned char *) bufplain;
    bufin = (const unsigned char *) bufcoded;

    while (nprbytes > 4)
    {
        *(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
        *(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
        *(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);

        bufin += 4;
        nprbytes -= 4;
    }

    /* Note: (nprbytes == 1) would be an error, so just ingore that case */
    if (nprbytes > 1)
    {
        *(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
    }

    if (nprbytes > 2)
    {
        *(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
    }

    if (nprbytes > 3)
    {
        *(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
    }

    *(bufout++) = '\0';
    nbytesdecoded -= (4 - nprbytes) & 3;

    return nbytesdecoded;
}


static int base64encode_binary(char *encoded, const unsigned char *string, int len )
{
    int i;
    char *p;

    p = encoded;

    for (i = 0; i < len - 2; i += 3)
    {
        *p++ = basis_64[(string[i] >> 2) & 0x3F];
        *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)];
        *p++ = basis_64[((string[i + 1] & 0xF) << 2) | ((int) (string[i + 2] & 0xC0) >> 6)];
        *p++ = basis_64[string[i + 2] & 0x3F];
    }

    if (i < len)
    {
        *p++ = basis_64[(string[i] >> 2) & 0x3F];

        if (i == (len - 1))
        {
            *p++ = basis_64[((string[i] & 0x3) << 4)];
            *p++ = '=';
        }
        else
        {
            *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)];
            *p++ = basis_64[((string[i + 1] & 0xF) << 2)];
        }

        *p++ = '=';
    }

    *p++ = '\0';

    return p - encoded;
}


int base64decode_len( const char * bufcoded )
{
    int nbytesdecoded;
    register const unsigned char *bufin;
    register int nprbytes;

    bufin = (const unsigned char *) bufcoded;

    while (pr2six[*(bufin++)] <= 63);

    nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
    nbytesdecoded = ((nprbytes + 3) / 4) * 3;

    return nbytesdecoded + 1;
}


int base64decode( char * bufplain, const char * bufcoded )
{
    int len;
    len = base64decode_binary((unsigned char *) bufplain, bufcoded);
    return len;
}


int base64encode_len( int len )
{
    return ((len + 2) / 3 * 4) + 1;
}


int base64encode( char * encoded, const char * string, int len )
{
    return base64encode_binary(encoded, (const unsigned char *) string, len);
}

/* fim-de-arquivo */

Browser other questions tagged

You are not signed in. Login or sign up in order to post.