#include "base64.h" unsigned char binary_to_base64(unsigned char v) { // Capital letters - 'A' is ascii 65 and base64 0 if(v < 26) return v + 'A'; // Lowercase letters - 'a' is ascii 97 and base64 26 if(v < 52) return v + 71; // Digits - '0' is ascii 48 and base64 52 if(v < 62) return v - 4; // '+' is ascii 43 and base64 62 if(v == 62) return '-'; // '/' is ascii 47 and base64 63 if(v == 63) return '_'; return 64; } unsigned char base64_to_binary(unsigned char c) { // Capital letters - 'A' is ascii 65 and base64 0 if('A' <= c && c <= 'Z') return c - 'A'; // Lowercase letters - 'a' is ascii 97 and base64 26 if('a' <= c && c <= 'z') return c - 71; // Digits - '0' is ascii 48 and base64 52 if('0' <= c && c <= '9') return c + 4; // '+' is ascii 43 and base64 62 if(c == '-') return 62; // '/' is ascii 47 and base64 63 if(c == '_') return 63; return 255; } unsigned int encode_base64_length(unsigned int input_length) { return (input_length + 2)/3*4; } unsigned int decode_base64_length(unsigned char input[]) { unsigned char *start = input; while(base64_to_binary(input[0]) < 64) { ++input; } unsigned int input_length = input - start; unsigned int output_length = input_length/4*3; switch(input_length % 4) { default: return output_length; case 2: return output_length + 1; case 3: return output_length + 2; } } unsigned int encode_base64(unsigned char input[], unsigned int input_length, unsigned char output[]) { unsigned int full_sets = input_length/3; // While there are still full sets of 24 bits... for(unsigned int i = 0; i < full_sets; ++i) { output[0] = binary_to_base64( input[0] >> 2); output[1] = binary_to_base64((input[0] & 0x03) << 4 | input[1] >> 4); output[2] = binary_to_base64((input[1] & 0x0F) << 2 | input[2] >> 6); output[3] = binary_to_base64( input[2] & 0x3F); input += 3; output += 4; } switch(input_length % 3) { case 0: output[0] = '\0'; break; case 1: output[0] = binary_to_base64( input[0] >> 2); output[1] = binary_to_base64((input[0] & 0x03) << 4); output[2] = '='; output[3] = '='; output[4] = '\0'; break; case 2: output[0] = binary_to_base64( input[0] >> 2); output[1] = binary_to_base64((input[0] & 0x03) << 4 | input[1] >> 4); output[2] = binary_to_base64((input[1] & 0x0F) << 2); output[3] = '='; output[4] = '\0'; break; } return encode_base64_length(input_length); } unsigned int decode_base64(unsigned char input[], unsigned char output[]) { unsigned int output_length = decode_base64_length(input); // While there are still full sets of 24 bits... for(unsigned int i = 2; i < output_length; i += 3) { output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4; output[1] = base64_to_binary(input[1]) << 4 | base64_to_binary(input[2]) >> 2; output[2] = base64_to_binary(input[2]) << 6 | base64_to_binary(input[3]); input += 4; output += 3; } switch(output_length % 3) { case 1: output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4; break; case 2: output[0] = base64_to_binary(input[0]) << 2 | base64_to_binary(input[1]) >> 4; output[1] = base64_to_binary(input[1]) << 4 | base64_to_binary(input[2]) >> 2; break; } return output_length; }