summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/lib/utils/codec_base.h
diff options
context:
space:
mode:
Diffstat (limited to 'comm/third_party/botan/src/lib/utils/codec_base.h')
-rw-r--r--comm/third_party/botan/src/lib/utils/codec_base.h220
1 files changed, 220 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/utils/codec_base.h b/comm/third_party/botan/src/lib/utils/codec_base.h
new file mode 100644
index 0000000000..2338fdfd7e
--- /dev/null
+++ b/comm/third_party/botan/src/lib/utils/codec_base.h
@@ -0,0 +1,220 @@
+/*
+* Base Encoding and Decoding
+* (C) 2018 Erwan Chaussy
+* (C) 2018 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_BASE_CODEC_H_
+#define BOTAN_BASE_CODEC_H_
+
+#include <botan/secmem.h>
+#include <botan/exceptn.h>
+#include <vector>
+#include <string>
+
+namespace Botan {
+
+/**
+* Perform encoding using the base provided
+* @param base object giving access to the encodings specifications
+* @param output an array of at least base.encode_max_output bytes
+* @param input is some binary data
+* @param input_length length of input in bytes
+* @param input_consumed is an output parameter which says how many
+* bytes of input were actually consumed. If less than
+* input_length, then the range input[consumed:length]
+* should be passed in later along with more input.
+* @param final_inputs true iff this is the last input, in which case
+ padding chars will be applied if needed
+* @return number of bytes written to output
+*/
+template <class Base>
+size_t base_encode(Base&& base,
+ char output[],
+ const uint8_t input[],
+ size_t input_length,
+ size_t& input_consumed,
+ bool final_inputs)
+ {
+ input_consumed = 0;
+
+ const size_t encoding_bytes_in = base.encoding_bytes_in();
+ const size_t encoding_bytes_out = base.encoding_bytes_out();
+
+ size_t input_remaining = input_length;
+ size_t output_produced = 0;
+
+ while(input_remaining >= encoding_bytes_in)
+ {
+ base.encode(output + output_produced, input + input_consumed);
+
+ input_consumed += encoding_bytes_in;
+ output_produced += encoding_bytes_out;
+ input_remaining -= encoding_bytes_in;
+ }
+
+ if(final_inputs && input_remaining)
+ {
+ std::vector<uint8_t> remainder(encoding_bytes_in, 0);
+ for(size_t i = 0; i != input_remaining; ++i)
+ { remainder[i] = input[input_consumed + i]; }
+
+ base.encode(output + output_produced, remainder.data());
+
+ const size_t bits_consumed = base.bits_consumed();
+ const size_t remaining_bits_before_padding = base.remaining_bits_before_padding();
+
+ size_t empty_bits = 8 * (encoding_bytes_in - input_remaining);
+ size_t index = output_produced + encoding_bytes_out - 1;
+ while(empty_bits >= remaining_bits_before_padding)
+ {
+ output[index--] = '=';
+ empty_bits -= bits_consumed;
+ }
+
+ input_consumed += input_remaining;
+ output_produced += encoding_bytes_out;
+ }
+
+ return output_produced;
+ }
+
+
+template <typename Base>
+std::string base_encode_to_string(Base&& base, const uint8_t input[], size_t input_length)
+ {
+ const size_t output_length = base.encode_max_output(input_length);
+ std::string output(output_length, 0);
+
+ size_t consumed = 0;
+ size_t produced = 0;
+
+ if(output_length > 0)
+ {
+ produced = base_encode(base, &output.front(),
+ input, input_length,
+ consumed, true);
+ }
+
+ BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input");
+ BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size");
+
+ return output;
+ }
+
+/**
+* Perform decoding using the base provided
+* @param base object giving access to the encodings specifications
+* @param output an array of at least Base::decode_max_output bytes
+* @param input some base input
+* @param input_length length of input in bytes
+* @param input_consumed is an output parameter which says how many
+* bytes of input were actually consumed. If less than
+* input_length, then the range input[consumed:length]
+* should be passed in later along with more input.
+* @param final_inputs true iff this is the last input, in which case
+ padding is allowed
+* @param ignore_ws ignore whitespace on input; if false, throw an
+ exception if whitespace is encountered
+* @return number of bytes written to output
+*/
+template <typename Base>
+size_t base_decode(Base&& base,
+ uint8_t output[],
+ const char input[],
+ size_t input_length,
+ size_t& input_consumed,
+ bool final_inputs,
+ bool ignore_ws = true)
+ {
+ const size_t decoding_bytes_in = base.decoding_bytes_in();
+ const size_t decoding_bytes_out = base.decoding_bytes_out();
+
+ uint8_t* out_ptr = output;
+ std::vector<uint8_t> decode_buf(decoding_bytes_in, 0);
+ size_t decode_buf_pos = 0;
+ size_t final_truncate = 0;
+
+ clear_mem(output, base.decode_max_output(input_length));
+
+ for(size_t i = 0; i != input_length; ++i)
+ {
+ const uint8_t bin = base.lookup_binary_value(input[i]);
+
+ if(base.check_bad_char(bin, input[i], ignore_ws)) // May throw Invalid_Argument
+ {
+ decode_buf[decode_buf_pos] = bin;
+ ++decode_buf_pos;
+ }
+
+ /*
+ * If we're at the end of the input, pad with 0s and truncate
+ */
+ if(final_inputs && (i == input_length - 1))
+ {
+ if(decode_buf_pos)
+ {
+ for(size_t j = decode_buf_pos; j < decoding_bytes_in; ++j)
+ { decode_buf[j] = 0; }
+
+ final_truncate = decoding_bytes_in - decode_buf_pos;
+ decode_buf_pos = decoding_bytes_in;
+ }
+ }
+
+ if(decode_buf_pos == decoding_bytes_in)
+ {
+ base.decode(out_ptr, decode_buf.data());
+
+ out_ptr += decoding_bytes_out;
+ decode_buf_pos = 0;
+ input_consumed = i+1;
+ }
+ }
+
+ while(input_consumed < input_length &&
+ base.lookup_binary_value(input[input_consumed]) == 0x80)
+ {
+ ++input_consumed;
+ }
+
+ size_t written = (out_ptr - output) - base.bytes_to_remove(final_truncate);
+
+ return written;
+ }
+
+template<typename Base>
+size_t base_decode_full(Base&& base, uint8_t output[], const char input[], size_t input_length, bool ignore_ws)
+ {
+ size_t consumed = 0;
+ const size_t written = base_decode(base, output, input, input_length, consumed, true, ignore_ws);
+
+ if(consumed != input_length)
+ {
+ throw Invalid_Argument(base.name() + " decoding failed, input did not have full bytes");
+ }
+
+ return written;
+ }
+
+template<typename Vector, typename Base>
+Vector base_decode_to_vec(Base&& base,
+ const char input[],
+ size_t input_length,
+ bool ignore_ws)
+ {
+ const size_t output_length = base.decode_max_output(input_length);
+ Vector bin(output_length);
+
+ const size_t written =
+ base_decode_full(base, bin.data(), input, input_length, ignore_ws);
+
+ bin.resize(written);
+ return bin;
+ }
+
+}
+
+#endif