Line data Source code
1 : // base64 encodig and decoding. 2 : // 3 : // Based on the implementations by 4 : // Jouni Malinen <j@w1.fi> and contributors from wpa_supplicant and hostapd in 5 : // http://web.mit.edu/freebsd/head/contrib/wpa/ and 6 : // http://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.c and 7 : // http://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.h 8 : // 9 : // Published under a 3-clause BSD license 10 : // 11 : 12 : #include <string> 13 : #include <cstring> 14 : #include <stdexcept> 15 : 16 : #include "crpropa/base64.h" 17 : 18 : namespace crpropa 19 : { 20 : 21 : //Alphabet used 22 : static const unsigned char encode_alphabet[65] = 23 : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 24 : static int decode_alphabet[256] = {-1}; 25 : 26 : /// Encodes data 27 99 : std::string Base64::encode(const unsigned char *src, size_t len) 28 : { 29 99 : size_t olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */ 30 : 31 99 : if (olen < len) 32 0 : throw std::runtime_error("Integer overflow in Base64::encoding, data to large!"); 33 : 34 : std::string outStr; 35 : outStr.resize(olen); 36 : 37 : unsigned char *out = (unsigned char*) outStr.c_str(); 38 : unsigned char *pos = out; 39 : const unsigned char *end, *in; 40 : 41 99 : end = src + len; 42 : in = src; 43 6666 : while (end - in >= 3) { 44 6567 : *pos++ = encode_alphabet[in[0] >> 2]; 45 6567 : *pos++ = encode_alphabet[((in[0] & 0x03) << 4) | (in[1] >> 4)]; 46 6567 : *pos++ = encode_alphabet[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; 47 6567 : *pos++ = encode_alphabet[in[2] & 0x3f]; 48 6567 : in += 3; 49 : } 50 : 51 99 : if (end - in) { 52 66 : *pos++ = encode_alphabet[in[0] >> 2]; 53 66 : if (end - in == 1) { 54 33 : *pos++ = encode_alphabet[(in[0] & 0x03) << 4]; 55 33 : *pos++ = '='; 56 : } 57 : else { 58 33 : *pos++ = encode_alphabet[((in[0] & 0x03) << 4) | 59 33 : (in[1] >> 4)]; 60 33 : *pos++ = encode_alphabet[(in[1] & 0x0f) << 2]; 61 : } 62 66 : *pos++ = '='; 63 : } 64 : 65 99 : return outStr; 66 : } 67 : 68 : 69 100 : std::string Base64::decode(const std::string &data) 70 : { 71 : const unsigned char *src = (unsigned char*) data.c_str(); 72 : size_t len = data.size(); 73 : 74 100 : if (decode_alphabet[0] == -1) 75 : { // build decode alphabet 76 : std::memset(decode_alphabet, 0x80, 256); 77 65 : for (size_t i = 0; i < sizeof(encode_alphabet) - 1; i++) 78 64 : decode_alphabet[encode_alphabet[i]] = (unsigned char) i; 79 1 : decode_alphabet['='] = 0; 80 : } 81 : 82 : size_t olen = 0; 83 26656 : for (size_t i = 0; i < len; i++) { 84 26556 : if (decode_alphabet[src[i]] != 0x80) 85 26556 : olen++; 86 : } 87 : 88 100 : if (olen == 0 || olen % 4) 89 0 : throw std::runtime_error("Base64 decode, invalid input size"); 90 : 91 100 : olen = olen / 4 * 3; 92 : std::string str; 93 : str.resize(olen); 94 : 95 : unsigned char *out = (unsigned char*) str.c_str(); 96 : unsigned char *pos = out; 97 : 98 : size_t count = 0; 99 : int pad = 0; 100 : unsigned char block[4]; 101 26589 : for (size_t i = 0; i < len; i++) { 102 26556 : unsigned char tmp = decode_alphabet[src[i]]; 103 26556 : if (tmp == 0x80) 104 0 : continue; 105 : 106 26556 : if (src[i] == '=') 107 101 : pad++; 108 26556 : block[count] = tmp; 109 26556 : count++; 110 26556 : if (count == 4) { 111 6639 : *pos++ = (block[0] << 2) | (block[1] >> 4); 112 6639 : *pos++ = (block[1] << 4) | (block[2] >> 2); 113 6639 : *pos++ = (block[2] << 6) | block[3]; 114 : count = 0; 115 6639 : if (pad) { 116 67 : if (pad == 1) 117 : pos--; 118 34 : else if (pad == 2) 119 : pos -= 2; 120 : else { 121 0 : throw std::runtime_error("Base64 decode, invalid padding"); 122 : } 123 : break; 124 : } 125 : } 126 : } 127 100 : return str; 128 : } 129 : };