Someone asked for an example of decoding with OpenSSL on the Howto base64 encode with C/C++ and OpenSSL post. So here it is:
[code lang=”c”]
#include
#include
#include
#include
#include
#include
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;
}
[/code]
[tags]C,C++,OpenSSL[/tags]
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
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);
This doesn’t work to me. BIO_read always returns 0 bytes readed.
@Carlo
Can you provide more information? I’ve tested to make sure it works with the latest version of OpenSSL.
Same Problem here! nothing readed!
add:
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
after:
b64 = BIO_new(BIO_f_base64());
and this will work.
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;
}
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 ;)
Thank you roxaz, that worked. I was able to write to a memory bio, encoding it as base64, but I wasn’t able to read from a base 64 encoded memory bio, decoding it.
the line
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
is only necessary when reading, I just didnt understand what it does, but it worked anyway =p