Quantcast

Howto base64 decode with C/C++ and OpenSSL

Someone asked for an example of decoding with OpenSSL on the Howto base64 encode with C/C++ and OpenSSL post. So here it is:

#include <string.h>

#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>

char *unbase64(unsigned char *input, int length);

int main(int argc, char **argv)
{
  char *output = unbase64("WU9ZTyEA\n\0", strlen("WU9ZTyEA\n\0"));
  printf("Unbase64: *%s*\n", output);
  free(output);
}

char *unbase64(unsigned char *input, int length)
{
  BIO *b64, *bmem;

  char *buffer = (char *)malloc(length);
  memset(buffer, 0, length);

  b64 = BIO_new(BIO_f_base64());
  bmem = BIO_new_mem_buf(input, length);
  bmem = BIO_push(b64, bmem);

  BIO_read(bmem, buffer, length);

  BIO_free_all(bmem);

  return buffer;
}

Tags: , ,

This entry was posted in programming and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

8 Comments

  1. saleem
    Posted April 16, 2008 at 12:05 am | Permalink

    Hi,
    Thanks for the code.

    Could you please share some code, on how to decode base64 encode DER format to X509.

    Any help will be great.

    Thanks,
    Saleem

  2. G
    Posted December 31, 2008 at 5:06 am | Permalink

    Used this for a project of mine and had a bit of trouble getting it to work. If anyone is tearing their hair out wondering why no errors are being reported but no data is being delivered, try changing

    bmem = BIO_push(b64, bmem);

    to

    BIO_push(b64, bmem);

  3. Carlo Pires
    Posted June 18, 2009 at 8:11 pm | Permalink

    This doesn't work to me. BIO_read always returns 0 bytes readed.

  4. Posted June 22, 2009 at 8:39 am | Permalink

    @Carlo

    Can you provide more information? I've tested to make sure it works with the latest version of OpenSSL.

  5. Lucas
    Posted June 24, 2009 at 9:58 am | Permalink

    Same Problem here! nothing readed!

  6. roxaz
    Posted September 19, 2009 at 7:41 am | Permalink

    add:
    BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
    after:
    b64 = BIO_new(BIO_f_base64());

    and this will work.

  7. Posted October 1, 2009 at 8:03 am | Permalink

    Hi
    I had some trouble with the openssl base 64 de/encoding too. This was because openssl does no 'pure' base64 encoding by default but uses the pem standard base64 encoding scheme ( this is why adding the lines from roxas will make it work in the most cases because the newlines are ignored ) but if you want to decode base64 that is used inside a certificate or mail it will be encoded after the pem standard which requires a newline after 64 bytes of base64 data. This makes encoding a bit tricky because you have to calculate the lenght of the encoded data yourself ( or i yust did not find the propper openssl routine to do that ;)

    However here is some code i wrote that does the job. Feel free to use it ..

    size_t MPSCalculateBase64Size(size_t inLen,int iLineSize)
    {
    double dInLen = inLen;
    double dLineSize = iLineSize;
    double dAdd = 0.0;
    double dLen = 0.0;
    size_t iResult = 0;

    double dModIn = fmod( dInLen,3.0);

    if( dModIn )
    dLen = ( ((( dInLen + 3.0 ) – fmod( dInLen, 3.0 )) / 3.0 ) * 4.0 );
    else
    dLen = ( ( dInLen / 3.0 ) * 4.0 ) ;

    dAdd = dLen;

    // If line size is != 0 the we must add the newlines to our resulting
    // data length
    if( iLineSize != 0)
    {
    // Add the newlines required after the pem/base64 standard
    // (after 64 chars)
    dAdd += ( dLen / dLineSize );

    // Check for incomplete line which is although terminated with a
    // \n (PEM Base64).
    double dModLine = fmod(dLen,dLineSize);
    if( dModLine )
    {
    dAdd += 1.0;
    }
    }

    iResult = (size_t) dAdd;
    return iResult;
    }

    int MPSBase64EncodeStr(const MPSCharType* ptrDataIn,size_t inLen,MPSStringType& strResult,size_t& stResultSize)
    {
    if(! ptrDataIn)
    return MPS_ERR_PARAM;

    BIO *bio = NULL;
    BIO *b64 = NULL;

    b64 = BIO_new(BIO_f_base64());
    bio = BIO_new( BIO_s_mem() );
    bio = BIO_push(b64, bio);

    size_t rLen = BIO_write(bio, ptrDataIn, (int) inLen);
    BIO_flush(bio);

    char* ptrOut = NULL;
    BIO_get_mem_data(bio, &ptrOut);

    if(ptrOut)
    {
    // Calculate line size
    std::string strData(ptrOut);
    size_t lineLen = strData.find("\n");
    if(lineLen == (size_t) MPSStringType::npos)
    {
    lineLen = 0;
    }

    int size = (int) MPSCalculateBase64Size( inLen, (int)lineLen ) ;

    strResult.insert(0,ptrOut,size);
    stResultSize = size;
    }

    BIO_free_all(bio);

    return MPS_OK;
    }

    int MPSBase64DecodeStr(const MPSCharType* ptrDataIn,size_t inLen,MPSStringType& strResult,size_t& stResultSize)
    {
    if(! ptrDataIn)
    return MPS_ERR_PARAM;

    BIO* b64 = NULL;
    BIO* bmem = NULL;
    char *buffer = (char *) malloc(inLen);
    if(buffer)
    {
    memset(buffer, 0, inLen);
    b64 = BIO_new(BIO_f_base64());
    bmem = BIO_new_mem_buf((void*) ptrDataIn, (int) inLen);
    bmem = BIO_push(b64, bmem);

    size_t rLen = BIO_read(bmem, buffer,(int) inLen);

    strResult.insert(0, (const char*) buffer, rLen);
    stResultSize = rLen;

    BIO_free_all(bmem);
    delete [] buffer,buffer = NULL;

    return MPS_OK;
    }
    return MPS_ERR;

    }

  8. Posted October 1, 2009 at 11:32 am | Permalink

    I like to add that doing that :

    // Calculate line size
    std::string strData(ptrOut);
    size_t lineLen = strData.find("\n");
    if(lineLen == (size_t) MPSStringType::npos)

    is a verry dangerous thing which will probably crash under a lot of circumstances. So it is a lot safer to just input the line len into the function.It can differ between 64 = PEM newline padding,and 72 for some other standard i cant recall right now X). Although there are some type mißmatches i forgot to clean out.
    The input types i used where:
    typedef std::string MPSStringType and
    typedef char MPSCharType

    Have fun ;)

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>