1*a7d2cdddSEd Tanous #include "base64.h" 2*a7d2cdddSEd Tanous #include "edk/BaseTypes.h" 3*a7d2cdddSEd Tanous 4*a7d2cdddSEd Tanous #include <stdlib.h> 5*a7d2cdddSEd Tanous #include <string.h> 6*a7d2cdddSEd Tanous #include <stdio.h> 7*a7d2cdddSEd Tanous #include <assert.h> 8*a7d2cdddSEd Tanous 9*a7d2cdddSEd Tanous static const UINT8 encode_table[65] = 10*a7d2cdddSEd Tanous "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 11*a7d2cdddSEd Tanous 12*a7d2cdddSEd Tanous /** 13*a7d2cdddSEd Tanous * 14*a7d2cdddSEd Tanous * Caller is responsible for freeing the returned buffer. 15*a7d2cdddSEd Tanous */ base64_encode(const UINT8 * src,INT32 len,INT32 * out_len)16*a7d2cdddSEd TanousCHAR8 *base64_encode(const UINT8 *src, INT32 len, INT32 *out_len) 17*a7d2cdddSEd Tanous { 18*a7d2cdddSEd Tanous CHAR8 *out; 19*a7d2cdddSEd Tanous CHAR8 *out_pos; 20*a7d2cdddSEd Tanous const UINT8 *src_end; 21*a7d2cdddSEd Tanous const UINT8 *in_pos; 22*a7d2cdddSEd Tanous 23*a7d2cdddSEd Tanous if (!out_len) { 24*a7d2cdddSEd Tanous return NULL; 25*a7d2cdddSEd Tanous } 26*a7d2cdddSEd Tanous 27*a7d2cdddSEd Tanous // 3 byte blocks to 4 byte blocks plus up to 2 bytes of padding 28*a7d2cdddSEd Tanous *out_len = 4 * ((len + 2) / 3); 29*a7d2cdddSEd Tanous 30*a7d2cdddSEd Tanous // Handle overflows 31*a7d2cdddSEd Tanous if (*out_len < len) { 32*a7d2cdddSEd Tanous return NULL; 33*a7d2cdddSEd Tanous } 34*a7d2cdddSEd Tanous 35*a7d2cdddSEd Tanous out = malloc(*out_len); 36*a7d2cdddSEd Tanous if (out == NULL) { 37*a7d2cdddSEd Tanous return NULL; 38*a7d2cdddSEd Tanous } 39*a7d2cdddSEd Tanous 40*a7d2cdddSEd Tanous src_end = src + len; 41*a7d2cdddSEd Tanous in_pos = src; 42*a7d2cdddSEd Tanous out_pos = out; 43*a7d2cdddSEd Tanous while (src_end - in_pos >= 3) { 44*a7d2cdddSEd Tanous *out_pos++ = encode_table[in_pos[0] >> 2]; 45*a7d2cdddSEd Tanous *out_pos++ = encode_table[((in_pos[0] & 0x03) << 4) | 46*a7d2cdddSEd Tanous (in_pos[1] >> 4)]; 47*a7d2cdddSEd Tanous *out_pos++ = encode_table[((in_pos[1] & 0x0f) << 2) | 48*a7d2cdddSEd Tanous (in_pos[2] >> 6)]; 49*a7d2cdddSEd Tanous *out_pos++ = encode_table[in_pos[2] & 0x3f]; 50*a7d2cdddSEd Tanous in_pos += 3; 51*a7d2cdddSEd Tanous } 52*a7d2cdddSEd Tanous 53*a7d2cdddSEd Tanous if (src_end - in_pos) { 54*a7d2cdddSEd Tanous *out_pos++ = encode_table[in_pos[0] >> 2]; 55*a7d2cdddSEd Tanous if (src_end - in_pos == 1) { 56*a7d2cdddSEd Tanous *out_pos++ = encode_table[(in_pos[0] & 0x03) << 4]; 57*a7d2cdddSEd Tanous *out_pos++ = '='; 58*a7d2cdddSEd Tanous } else { 59*a7d2cdddSEd Tanous *out_pos++ = encode_table[((in_pos[0] & 0x03) << 4) | 60*a7d2cdddSEd Tanous (in_pos[1] >> 4)]; 61*a7d2cdddSEd Tanous *out_pos++ = encode_table[(in_pos[1] & 0x0f) << 2]; 62*a7d2cdddSEd Tanous } 63*a7d2cdddSEd Tanous *out_pos++ = '='; 64*a7d2cdddSEd Tanous } 65*a7d2cdddSEd Tanous 66*a7d2cdddSEd Tanous return out; 67*a7d2cdddSEd Tanous } 68*a7d2cdddSEd Tanous 69*a7d2cdddSEd Tanous // Base64 decode table. Invalid values are specified with 0x80. 70*a7d2cdddSEd Tanous UINT8 decode_table[256] = 71*a7d2cdddSEd Tanous "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 72*a7d2cdddSEd Tanous "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 73*a7d2cdddSEd Tanous "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x3e\x80\x80\x80\x3f" 74*a7d2cdddSEd Tanous "\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x80\x80\x80\x00\x80\x80" 75*a7d2cdddSEd Tanous "\x80\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e" 76*a7d2cdddSEd Tanous "\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x80\x80\x80\x80\x80" 77*a7d2cdddSEd Tanous "\x80\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28" 78*a7d2cdddSEd Tanous "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x80\x80\x80\x80\x80" 79*a7d2cdddSEd Tanous "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 80*a7d2cdddSEd Tanous "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 81*a7d2cdddSEd Tanous "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 82*a7d2cdddSEd Tanous "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 83*a7d2cdddSEd Tanous "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 84*a7d2cdddSEd Tanous "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 85*a7d2cdddSEd Tanous "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80" 86*a7d2cdddSEd Tanous "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"; 87*a7d2cdddSEd Tanous 88*a7d2cdddSEd Tanous /** 89*a7d2cdddSEd Tanous * 90*a7d2cdddSEd Tanous * Caller is responsible for freeing the returned buffer. 91*a7d2cdddSEd Tanous */ base64_decode(const CHAR8 * src,INT32 len,INT32 * out_len)92*a7d2cdddSEd TanousUINT8 *base64_decode(const CHAR8 *src, INT32 len, INT32 *out_len) 93*a7d2cdddSEd Tanous { 94*a7d2cdddSEd Tanous UINT8 *out; 95*a7d2cdddSEd Tanous UINT8 *pos; 96*a7d2cdddSEd Tanous UINT8 block[4]; 97*a7d2cdddSEd Tanous UINT8 tmp; 98*a7d2cdddSEd Tanous INT32 block_index; 99*a7d2cdddSEd Tanous INT32 src_index; 100*a7d2cdddSEd Tanous UINT32 pad_count = 0; 101*a7d2cdddSEd Tanous 102*a7d2cdddSEd Tanous if (!out_len) { 103*a7d2cdddSEd Tanous return NULL; 104*a7d2cdddSEd Tanous } 105*a7d2cdddSEd Tanous 106*a7d2cdddSEd Tanous // Malloc might be up to 2 larger dependent on padding 107*a7d2cdddSEd Tanous *out_len = len / 4 * 3; 108*a7d2cdddSEd Tanous pos = out = malloc(*out_len); 109*a7d2cdddSEd Tanous if (out == NULL) { 110*a7d2cdddSEd Tanous return NULL; 111*a7d2cdddSEd Tanous } 112*a7d2cdddSEd Tanous 113*a7d2cdddSEd Tanous block_index = 0; 114*a7d2cdddSEd Tanous for (src_index = 0; src_index < len; src_index++) { 115*a7d2cdddSEd Tanous tmp = decode_table[(UINT8)src[src_index]]; 116*a7d2cdddSEd Tanous if (tmp == 0x80) { 117*a7d2cdddSEd Tanous free(out); 118*a7d2cdddSEd Tanous return NULL; 119*a7d2cdddSEd Tanous } 120*a7d2cdddSEd Tanous 121*a7d2cdddSEd Tanous if (src[src_index] == '=') { 122*a7d2cdddSEd Tanous pad_count++; 123*a7d2cdddSEd Tanous } 124*a7d2cdddSEd Tanous 125*a7d2cdddSEd Tanous block[block_index] = tmp; 126*a7d2cdddSEd Tanous block_index++; 127*a7d2cdddSEd Tanous if (block_index == 4) { 128*a7d2cdddSEd Tanous *pos++ = (block[0] << 2) | (block[1] >> 4); 129*a7d2cdddSEd Tanous *pos++ = (block[1] << 4) | (block[2] >> 2); 130*a7d2cdddSEd Tanous *pos++ = (block[2] << 6) | block[3]; 131*a7d2cdddSEd Tanous if (pad_count > 0) { 132*a7d2cdddSEd Tanous if (pad_count == 1) { 133*a7d2cdddSEd Tanous pos--; 134*a7d2cdddSEd Tanous } else if (pad_count == 2) { 135*a7d2cdddSEd Tanous pos -= 2; 136*a7d2cdddSEd Tanous } else { 137*a7d2cdddSEd Tanous /* Invalid pad_counting */ 138*a7d2cdddSEd Tanous free(out); 139*a7d2cdddSEd Tanous return NULL; 140*a7d2cdddSEd Tanous } 141*a7d2cdddSEd Tanous break; 142*a7d2cdddSEd Tanous } 143*a7d2cdddSEd Tanous block_index = 0; 144*a7d2cdddSEd Tanous } 145*a7d2cdddSEd Tanous } 146*a7d2cdddSEd Tanous 147*a7d2cdddSEd Tanous *out_len = pos - out; 148*a7d2cdddSEd Tanous return out; 149*a7d2cdddSEd Tanous } 150