Botan
1.11.15
|
00001 /* 00002 * Base64 Encoding and Decoding 00003 * (C) 2010,2015 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/base64.h> 00009 #include <botan/mem_ops.h> 00010 #include <botan/internal/rounding.h> 00011 #include <stdexcept> 00012 00013 namespace Botan { 00014 00015 namespace { 00016 00017 static const byte BIN_TO_BASE64[64] = { 00018 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 00019 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 00020 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 00021 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 00022 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' 00023 }; 00024 00025 void do_base64_encode(char out[4], const byte in[3]) 00026 { 00027 out[0] = BIN_TO_BASE64[((in[0] & 0xFC) >> 2)]; 00028 out[1] = BIN_TO_BASE64[((in[0] & 0x03) << 4) | (in[1] >> 4)]; 00029 out[2] = BIN_TO_BASE64[((in[1] & 0x0F) << 2) | (in[2] >> 6)]; 00030 out[3] = BIN_TO_BASE64[((in[2] & 0x3F) )]; 00031 } 00032 00033 } 00034 00035 size_t base64_encode(char out[], 00036 const byte in[], 00037 size_t input_length, 00038 size_t& input_consumed, 00039 bool final_inputs) 00040 { 00041 input_consumed = 0; 00042 00043 size_t input_remaining = input_length; 00044 size_t output_produced = 0; 00045 00046 while(input_remaining >= 3) 00047 { 00048 do_base64_encode(out + output_produced, in + input_consumed); 00049 00050 input_consumed += 3; 00051 output_produced += 4; 00052 input_remaining -= 3; 00053 } 00054 00055 if(final_inputs && input_remaining) 00056 { 00057 byte remainder[3] = { 0 }; 00058 for(size_t i = 0; i != input_remaining; ++i) 00059 remainder[i] = in[input_consumed + i]; 00060 00061 do_base64_encode(out + output_produced, remainder); 00062 00063 size_t empty_bits = 8 * (3 - input_remaining); 00064 size_t index = output_produced + 4 - 1; 00065 while(empty_bits >= 8) 00066 { 00067 out[index--] = '='; 00068 empty_bits -= 6; 00069 } 00070 00071 input_consumed += input_remaining; 00072 output_produced += 4; 00073 } 00074 00075 return output_produced; 00076 } 00077 00078 std::string base64_encode(const byte input[], 00079 size_t input_length) 00080 { 00081 const size_t output_length = (input_length == 0) 00082 ? 0 00083 : (round_up<size_t>(input_length, 3) / 3) * 4; 00084 std::string output(output_length, 0); 00085 00086 size_t consumed = 0; 00087 size_t produced = base64_encode(&output[0], 00088 input, input_length, 00089 consumed, true); 00090 00091 BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input"); 00092 BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size"); 00093 00094 return output; 00095 } 00096 00097 size_t base64_decode(byte output[], 00098 const char input[], 00099 size_t input_length, 00100 size_t& input_consumed, 00101 bool final_inputs, 00102 bool ignore_ws) 00103 { 00104 /* 00105 * Base64 Decoder Lookup Table 00106 * Warning: assumes ASCII encodings 00107 */ 00108 static const byte BASE64_TO_BIN[256] = { 00109 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 00110 0x80, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00111 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00112 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00113 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 00114 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 00115 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 00116 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 00117 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 00118 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 00119 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 00120 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 00121 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00122 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00123 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00124 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00125 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00126 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00127 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00128 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00129 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00130 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00131 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00132 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00133 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 00134 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 00135 00136 byte* out_ptr = output; 00137 byte decode_buf[4]; 00138 size_t decode_buf_pos = 0; 00139 size_t final_truncate = 0; 00140 00141 clear_mem(output, input_length * 3 / 4); 00142 00143 for(size_t i = 0; i != input_length; ++i) 00144 { 00145 const byte bin = BASE64_TO_BIN[static_cast<byte>(input[i])]; 00146 00147 if(bin <= 0x3F) 00148 { 00149 decode_buf[decode_buf_pos] = bin; 00150 decode_buf_pos += 1; 00151 } 00152 else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws))) 00153 { 00154 std::string bad_char(1, input[i]); 00155 if(bad_char == "\t") 00156 bad_char = "\\t"; 00157 else if(bad_char == "\n") 00158 bad_char = "\\n"; 00159 else if(bad_char == "\r") 00160 bad_char = "\\r"; 00161 00162 throw std::invalid_argument( 00163 std::string("base64_decode: invalid base64 character '") + 00164 bad_char + "'"); 00165 } 00166 00167 /* 00168 * If we're at the end of the input, pad with 0s and truncate 00169 */ 00170 if(final_inputs && (i == input_length - 1)) 00171 { 00172 if(decode_buf_pos) 00173 { 00174 for(size_t j = decode_buf_pos; j != 4; ++j) 00175 decode_buf[j] = 0; 00176 final_truncate = (4 - decode_buf_pos); 00177 decode_buf_pos = 4; 00178 } 00179 } 00180 00181 if(decode_buf_pos == 4) 00182 { 00183 out_ptr[0] = (decode_buf[0] << 2) | (decode_buf[1] >> 4); 00184 out_ptr[1] = (decode_buf[1] << 4) | (decode_buf[2] >> 2); 00185 out_ptr[2] = (decode_buf[2] << 6) | decode_buf[3]; 00186 00187 out_ptr += 3; 00188 decode_buf_pos = 0; 00189 input_consumed = i+1; 00190 } 00191 } 00192 00193 while(input_consumed < input_length && 00194 BASE64_TO_BIN[static_cast<byte>(input[input_consumed])] == 0x80) 00195 { 00196 ++input_consumed; 00197 } 00198 00199 size_t written = (out_ptr - output) - final_truncate; 00200 00201 return written; 00202 } 00203 00204 size_t base64_decode(byte output[], 00205 const char input[], 00206 size_t input_length, 00207 bool ignore_ws) 00208 { 00209 size_t consumed = 0; 00210 size_t written = base64_decode(output, input, input_length, 00211 consumed, true, ignore_ws); 00212 00213 if(consumed != input_length) 00214 throw std::invalid_argument("base64_decode: input did not have full bytes"); 00215 00216 return written; 00217 } 00218 00219 size_t base64_decode(byte output[], 00220 const std::string& input, 00221 bool ignore_ws) 00222 { 00223 return base64_decode(output, input.data(), input.length(), ignore_ws); 00224 } 00225 00226 secure_vector<byte> base64_decode(const char input[], 00227 size_t input_length, 00228 bool ignore_ws) 00229 { 00230 const size_t output_length = (input_length == 0) 00231 ? 0 00232 : (round_up<size_t>(input_length, 4) * 3) / 4; 00233 secure_vector<byte> bin(output_length); 00234 00235 size_t written = base64_decode(&bin[0], 00236 input, 00237 input_length, 00238 ignore_ws); 00239 00240 bin.resize(written); 00241 return bin; 00242 } 00243 00244 secure_vector<byte> base64_decode(const std::string& input, 00245 bool ignore_ws) 00246 { 00247 return base64_decode(input.data(), input.size(), ignore_ws); 00248 } 00249 00250 00251 }