Botan  1.11.15
src/lib/codec/base64/base64.cpp
Go to the documentation of this file.
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 }