Theory on base64 encoding and decoding
- Base64 encoding converts three octets into four encoded characters.
- 24 bits encoded to 32 bits
- 3 bytes encoded to 4 bytes
- 24 bits encoded to 32 bits
- 16 (3 x 5 + 1) bytes encoded to ( 4 x 5 + (1 + 3extra bytes)) = 24 bytes
- The final '==' sequence indicates that the last group contained only one byte, and '=' indicates that it contained two bytes.
Example
neelkanth_surekha#./base64 "neelkanth reddy 12"
Input string: neelkanth reddy 12encoded Output (base64): bmVlbGthbnRoIHJlZGR5IDEy length: 24 (no equal to padding)
Decoded Output: neelkanth reddy 12 string length: 18
neelkanth_surekha#./base64 "neelkanth reddy 123"
Input string: neelkanth reddy 123
encoded Output (base64): bmVlbGthbnRoIHJlZGR5IDEyMw== length: 28 (1 byte i.e. "=" padding)
Decoded Output: neelkanth reddy 123 string length: 19
neelkanth_surekha#./base64 "neelkanth reddy 1234"
Input string: neelkanth reddy 1234
encoded Output (base64): bmVlbGthbnRoIHJlZGR5IDEyMzQ= length: 28 (2 bytes i.e "==" padding)
Decoded Output: neelkanth reddy 1234 string length: 20
Program:
#include <openssl/conf.h>
#include <openssl/evp.h>#include <openssl/err.h>
#include <string.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <stdint.h>
#include <assert.h>
void handleErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}
size_t calcDecodeLength(const char* b64input) { //Calculates the length of a decoded string
size_t len = strlen(b64input),
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 (len*3)/4 - padding;
}
int Base64Decode(char* b64message, unsigned char** buffer, size_t* length) { //Decodes a base64 encoded string
BIO *bio, *b64;
int decodeLen = calcDecodeLength(b64message);
*buffer = (unsigned char*)malloc(decodeLen + 1);
(*buffer)[decodeLen] = '\0';
bio = BIO_new_mem_buf(b64message, -1);
b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer
*length = BIO_read(bio, *buffer, strlen(b64message));
assert(*length == decodeLen); //length should equal decodeLen, else something went horribly wrong
BIO_free_all(bio);
return (0); //success
}
int Base64Encode(const unsigned char* buffer, size_t length, char** b64text) { //Encodes a binary safe base 64 string
BIO *bio, *b64;
BUF_MEM *bufferPtr;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line
BIO_write(bio, buffer, length);
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bufferPtr);
BIO_set_close(bio, BIO_NOCLOSE);
BIO_free_all(bio);
*b64text=(*bufferPtr).data;
printf("%s\n", (*bufferPtr).data);
return (0); //success
}
int decrypt(unsigned char* base64DecodeOutput, unsigned char *key,
unsigned char *iv, unsigned char *plain_pwd_text, size_t length)
{
EVP_CIPHER_CTX *ctx;
int len;
int plain_pwd_text_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the decryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits */
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
handleErrors();
/* Provide the message to be decrypted, and obtain the plain_pwd_text output.
* EVP_DecryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_DecryptUpdate(ctx, plain_pwd_text, &len, base64DecodeOutput, length))
handleErrors();
plain_pwd_text_len = len;
/* Finalise the decryption. Further plain_pwd_text bytes may be written at
* this stage.
*/
if(1 != EVP_DecryptFinal_ex(ctx, plain_pwd_text + len, &len)) handleErrors();
plain_pwd_text_len += len;
plain_pwd_text[plain_pwd_text_len] = '\0';
/* Show the decrypted text */
printf("Decrypted text (original password) is: %s string length: %d\n",
plain_pwd_text, plain_pwd_text_len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return plain_pwd_text_len;
}
int encrypt(unsigned char *plain_pwd_text, int plain_pwd_text_len, unsigned char *key,
unsigned char *iv, unsigned char *encryp_pwd_txt)
{
EVP_CIPHER_CTX *ctx;
int len;
int encryp_pwd_txt_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
/* Initialise the encryption operation. IMPORTANT - ensure you use a key
* and IV size appropriate for your cipher
* In this example we are using 128 bit AES (i.e. a 128 bit key). The
* IV size for *most* modes is the same as the block size. For AES this
* is 128 bits */
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv))
handleErrors();
/* Provide the message to be encrypted, and obtain the encrypted output.
* EVP_EncryptUpdate can be called multiple times if necessary
*/
if(1 != EVP_EncryptUpdate(ctx, encryp_pwd_txt, &len, plain_pwd_text, plain_pwd_text_len))
handleErrors();
encryp_pwd_txt_len = len;
/* Finalise the encryption. Further encryp_pwd_txt bytes may be written at
* this stage.
*/
if(1 != EVP_EncryptFinal_ex(ctx, encryp_pwd_txt + len, &len)) handleErrors();
encryp_pwd_txt_len += len;
encryp_pwd_txt[encryp_pwd_txt_len] = '\0';
printf("encryp_pwd_txt is: %s Length: encryp_pwd_txt_len: %d \n" , encryp_pwd_txt, encryp_pwd_txt_len);
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
return encryp_pwd_txt_len;
}
int main (int argc, char *argv[])
{
/* A 128 bit = 16 bytes (max) private key */
unsigned char key[16] = "12345678";
/* A 128 bit IV */
unsigned char iv[16] = {0};
/* Buffer for encryp_pwd_txt. Ensure the buffer is long enough for the
* encryp_pwd_txt which may be longer than the plain_pwd_text, dependant on the
* algorithm and mode
*/
unsigned char encryp_pwd_txt[128] = {'\0'};
/* Message to be encrypted */
unsigned char plain_pwd_text[32] = {0};
/* Buffer for the decrypted text */
unsigned char decryptedtext[128] = {'\0'};
int decryptedtext_len, encryp_pwd_txt_len;
/* Command line argument : enter password */
if (argc != 2) {
printf("Enter Only 1 argument: Enter input (password)\n");
exit(1);
}
/* password length cannot exceed 32 bytes */
if (strlen(argv[1]) > 32)
{
printf("Password length cannot exceed beyond 32 bytes\n");
exit(1);
}
/* copy command line arguement into plain text */
strncpy(plain_pwd_text, argv[1], sizeof(plain_pwd_text)-1);
char base64EncodeOutput[100] = {'\0'};
char *base64EncodeOutput_ptr;
base64EncodeOutput_ptr = base64EncodeOutput;
unsigned char base64DecodeOutput[100] = {'\0'};
unsigned char* base64DecodeOutput_ptr;
base64DecodeOutput_ptr = base64DecodeOutput;
printf("************************************************************************\n");
printf("Original Password: %s string length: %ld\n", plain_pwd_text, strlen(plain_pwd_text));
printf("************************************************************************\n");
/* Encrypt the plain_pwd_text */
printf("************************************************************************\n");
encryp_pwd_txt_len = encrypt (plain_pwd_text, strlen ((char *)plain_pwd_text),
key, iv, encryp_pwd_txt);
printf("************************************************************************\n");
/* Encode the encrypted text */
printf("************************************************************************\n");
Base64Encode(encryp_pwd_txt, encryp_pwd_txt_len, &base64EncodeOutput_ptr);
printf("Encode Output (base64): %s string length: %ld\n",
base64EncodeOutput_ptr, strlen(base64EncodeOutput_ptr));
printf("************************************************************************\n");
/* Decode the encrypted text */
size_t length;
Base64Decode(base64EncodeOutput_ptr, &base64DecodeOutput_ptr, &length);
printf("************************************************************************\n");
printf("Decode Output: %s string length: %ld\n", base64DecodeOutput_ptr,
strlen(base64DecodeOutput_ptr));
printf("************************************************************************\n");
/* Decrypt the encrypted text back into plain text */
printf("************************************************************************\n");
decryptedtext_len = decrypt(base64DecodeOutput_ptr, key, iv, decryptedtext, length);
printf("************************************************************************\n");
return 0;
}
Output
neelkanth_surekha#./a.out 12345************************************************************************
Original Password: 12345 string length: 5
************************************************************************
************************************************************************
encryp_pwd_txt is: ����˱ꛎ-��� �� Length: encryp_pwd_txt_len: 16
************************************************************************
************************************************************************
rfKc28ux6puOLeGx5BGg3A==
Encode Output (base64): rfKc28ux6puOLeGx5BGg3A== string length: 24
************************************************************************
************************************************************************
Decode Output: ����˱ꛎ-��� �� string length: 16
************************************************************************
************************************************************************
Decrypted text (original password) is: 12345 string length: 5
************************************************************************
neelkanth_surekha#./a.out 12345fdsafsadfsdfsafsaf
************************************************************************
Original Password: 12345fdsafsadfsdfsafsaf string length: 23
************************************************************************
************************************************************************
encryp_pwd_txt is: ���t]陴p� %d w@}����������f }:K Length: encryp_pwd_txt_len: 32
************************************************************************
************************************************************************
sbmddF3pmbRwiRUlZBJ3QH3Bp7OBn4uS6tPYZhR9Oks=
Encode Output (base64): sbmddF3pmbRwiRUlZBJ3QH3Bp7OBn4uS6tPYZhR9Oks= string length: 44
************************************************************************
************************************************************************
Decode Output: ���t]陴p� %d w@}����������f }:K string length: 32
************************************************************************
************************************************************************
Decrypted text (original password) is: 12345fdsafsadfsdfsafsaf string length: 23
************************************************************************
neelkanth_surekha#./a.out 12345fdsafsadfsdfsafsafasfsdfsadfasd
Password length cannot exceed beyond 32 bytes