본문 바로가기
IT/programming

Base64 With OpenSSL C API

by 어느해겨울 2014. 7. 14.

 

OpenSSL has the ability to perform Base64 encodings and decodings. There seems to be many queries for working examples on how to use this functionality. Unfortunately, theexample on the OpenSSL site is quite obtuse, and every other example I have come accross does not work. So here is some working code. Enjoy!

Get The Code

You can download this entire gist here. It consists of the following files:

  • Base64Decode.c - the decode function (takes Base64 encoded string as input).
  • Base64Encode.c - the encode function (takes a "normal" string as input).
  • Main.c - the main c file that demonstrates usage of the functionality in the two files above.
  • Makefile - the C makefile. Compilation has been tested on a linux ubuntu distribution, and links with lcrypto foropensll and lm for math.

Base64 Encoding

 

12345678910111213141516171819202122232425

//Encodes Base64
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
 
int Base64Encode(const char* message, char** buffer) { //Encodes a string to base64
BIO *bio, *b64;
FILE* stream;
int encodedSize = 4*ceil((double)strlen(message)/3);
*buffer = (char *)malloc(encodedSize+1);
 
stream = fmemopen(*buffer, encodedSize+1, "w");
b64 = BIO_new(BIO_f_base64());
bio = BIO_new_fp(stream, BIO_NOCLOSE);
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
BIO_write(bio, message, strlen(message));
BIO_flush(bio);
BIO_free_all(bio);
fclose(stream);
 
return (0); //success
}
view rawBase64Encode.c hosted with ❤ by GitHub

 

Note the following:

  • Given a string of length n, the resulting Base64 string is length 4n3. This is performed on line 12.
  • On line 13, *buffer is malloc'd to encodedSize+1. The +1 is because an extra character is needed for the NULL character ('\0') at the end of the string.

Base64 Decoding

 

1234567891011121314151617181920212223242526272829303132333435363738

//Decodes Base64
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <string.h>
#include <stdio.h>
 
int calcDecodeLength(const char* b64input) { //Calculates the length of a decoded base64 string
int len = strlen(b64input);
int padding = 0;
 
if (b64input[len-1] == '=' && b64input[len-2] == '=') //last two chars are =
padding = 2;
else if (b64input[len-1] == '=') //last char is =
padding = 1;
 
return (int)len*0.75 - padding;
}
 
int Base64Decode(char* b64message, char** buffer) { //Decodes a base64 encoded string
BIO *bio, *b64;
int decodeLen = calcDecodeLength(b64message),
len = 0;
*buffer = (char*)malloc(decodeLen+1);
FILE* stream = fmemopen(b64message, strlen(b64message), "r");
 
b64 = BIO_new(BIO_f_base64());
bio = BIO_new_fp(stream, BIO_NOCLOSE);
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
len = BIO_read(bio, *buffer, strlen(b64message));
//Can test here if len == decodeLen - if not, then return an error
(*buffer)[len] = '\0';
 
BIO_free_all(bio);
fclose(stream);
 
return (0); //success
}
view rawBase64Decode.c hosted with ❤ by GitHub

 

Note the following:

  • It is important to set the flag BIO_FLAGS_BASE64_NO_NL. If this is not done, the read operation will block until a newline character (\n) is encountered.
  • The function calcDecodeLength will, given a Base64 encoded input string, calculate the length of the decoded string. Base64 encodes a "normal" 8 bit character string by using only 6 bits (hence only 26=64 characters are needed). Therefore every 4 characters of Base64 decodes to three decoded characters, and multiplying the length of the Base64 string by 34 will typically suffice. There are however two exceptions due to padding denoted by the =character. For more information, read decoding base64 with padding.

Usage

The above functionality is used like so:

123456789101112131415

#include <stdio.h>
 
int main() {
//Encode To Base64
char* base64EncodeOutput;
Base64Encode("Hello World", &base64EncodeOutput);
printf("Output (base64): %s\n", base64EncodeOutput);
 
//Decode From Base64
char* base64DecodeOutput;
Base64Decode("SGVsbG8gV29ybGQ=", &base64DecodeOutput);
printf("Output: %s\n", base64DecodeOutput);
return(0);
}
view rawMain.c hosted with ❤ by GitHub

 

Compile it with this MakeFile:

12

all:
gcc -o base64 Main.c Base64Encode.c Base64Decode.c -lcrypto -lm
view rawMakefile hosted with ❤ by GitHub

 

Memory Stuff

The memory for buffer in both functions is created on the heap using malloc. Therefore, it must be managed. This is a tiny example, and the program ends before any memory leaks become a problem, but in production code, remember to free the heap memory occupied by buffer after it has been used. This is done with the free command.

Conclusion

The above functions should perform better error checking if used in production. It also only works for encoding and decoding of a strings (although it is not too difficult to get it to work for files as well). This should give the inquisitive (and frustrated) programmer a base from which to work from.

Published In Blog
Tags: DevelopmentOpenSSL

 

출처 : http://doctrina.org/Base64-With-OpenSSL-C-API.html

 

Doctrina - Base64 With OpenSSL C API

OpenSSL has the ability to perform Base64L1 encodings and decodings. There seems to be many queries for working examples on how to use this functionality. Unfortunately, the exampleL2 on the OpenSSL site is quite obtuse, and every other example I have come

doctrina.org

 

댓글