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 andlm
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
}
|
Note the following:
- Given a string of length
n
, the resulting Base64 string is length 4∗⌈n3⌉. This is performed on line 12. - On line 13,
*buffer
is malloc'd toencodedSize+1
. The+1
is because an extra character is needed for theNULL
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
}
|
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);
}
|
Compile it with this MakeFile:
12 |
all:
gcc -o base64 Main.c Base64Encode.c Base64Decode.c -lcrypto -lm
|
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.
출처 : http://doctrina.org/Base64-With-OpenSSL-C-API.html
'IT > programming' 카테고리의 다른 글
[C/C++] pthread condition 설명 (0) | 2020.03.30 |
---|---|
[C/C++] pthread_mutex_lock 설명 (0) | 2020.03.30 |
[C/C++] C언어 출력에 색깔 입히기 예제 (1) | 2015.12.16 |
[C/C++] 음수에서 양수로 변환 예제 (0) | 2014.12.19 |
[C/C++] C99 구조체 초기화 하는 방법 (0) | 2014.12.19 |
댓글