19#include <boost/archive/iterators/base64_from_binary.hpp>
20#include <boost/archive/iterators/binary_from_base64.hpp>
21#include <boost/archive/iterators/transform_width.hpp>
22#ifdef HAVE_BOOST_INTEGER_COMMON_FACTOR_HPP
23#include <boost/integer/common_factor.hpp>
25#include <boost/math/common_factor.hpp>
43namespace clang_unnamed_namespace_workaround {
98const char BASE_PADDING_CHAR =
'=';
99const uint8_t BINARY_ZERO_CODE = 0;
115class EncodeNormalizer {
118 using iterator_category = input_iterator_tag;
119 using value_type = uint8_t;
120 using difference_type = ptrdiff_t;
121 using pointer = uint8_t*;
122 using reference = uint8_t&;
124 EncodeNormalizer(
const vector<uint8_t>::const_iterator& base,
125 const vector<uint8_t>::const_iterator& base_end) :
126 base_(base), base_end_(base_end), in_pad_(false)
128 EncodeNormalizer& operator++() {
132 EncodeNormalizer operator++(
int) {
133 const EncodeNormalizer
copy = *
this;
137 const uint8_t& operator*()
const {
139 return (BINARY_ZERO_CODE);
144 bool operator==(
const EncodeNormalizer& other)
const {
145 return (base_ == other.base_);
152 if (base_ == base_end_) {
156 vector<uint8_t>::const_iterator base_;
157 const vector<uint8_t>::const_iterator base_end_;
177class DecodeNormalizer {
180 using iterator_category = input_iterator_tag;
181 using value_type = char;
182 using difference_type = ptrdiff_t;
183 using pointer =
char*;
184 using reference =
char&;
186 DecodeNormalizer(
const char base_zero_code,
187 const string::const_iterator& base,
188 const string::const_iterator& base_beginpad,
189 const string::const_iterator& base_end,
190 size_t* char_count) :
191 base_zero_code_(base_zero_code),
192 base_(base), base_beginpad_(base_beginpad), base_end_(base_end),
193 in_pad_(false), char_count_(char_count)
199 DecodeNormalizer& operator++() {
200 if (base_ < base_end_) {
205 if (base_ == base_beginpad_) {
219 while (base_ != base_end_ && *base_ > 0 && isspace(*base_)) {
223 const char& operator*()
const {
224 if (base_ == base_end_) {
238 throw clang_unnamed_namespace_workaround::IncompleteBaseInput();
240 if (*base_ == BASE_PADDING_CHAR) {
246 return (base_zero_code_);
248 isc_throw(BadValue,
"Intermediate padding found");
254 bool operator==(
const DecodeNormalizer& other)
const {
255 return (base_ == other.base_);
258 const char base_zero_code_;
259 string::const_iterator base_;
260 const string::const_iterator base_beginpad_;
261 const string::const_iterator base_end_;
276template <
int BitsPerChunk,
char BaseZeroCode,
277 typename Encoder,
typename Decoder>
278struct BaseNTransformer {
279 static string encode(
const vector<uint8_t>& binary);
280 static void decode(
const char* algorithm,
281 const string& base64, vector<uint8_t>& result);
287 static const int BITS_PER_GROUP =
288#ifdef HAVE_BOOST_INTEGER_COMMON_FACTOR_HPP
289 boost::integer::static_lcm<BitsPerChunk, 8>::value;
291 boost::math::static_lcm<BitsPerChunk, 8>::value;
303 static const int MAX_PADDING_CHARS =
304 BITS_PER_GROUP / BitsPerChunk -
305 (8 / BitsPerChunk + ((8 % BitsPerChunk) == 0 ? 0 : 1));
308template <
int BitsPerChunk,
char BaseZeroCode,
309 typename Encoder,
typename Decoder>
311BaseNTransformer<BitsPerChunk, BaseZeroCode, Encoder, Decoder>::encode(
312 const vector<uint8_t>& binary)
315 size_t bits = binary.size() * 8;
316 if (bits % BITS_PER_GROUP > 0) {
317 bits += (BITS_PER_GROUP - (bits % BITS_PER_GROUP));
319 const size_t len = bits / BitsPerChunk;
323 result.assign(Encoder(EncodeNormalizer(binary.begin(), binary.end())),
324 Encoder(EncodeNormalizer(binary.end(), binary.end())));
326 result.append(len - result.length(), BASE_PADDING_CHAR);
330template <
int BitsPerChunk,
char BaseZeroCode,
331 typename Encoder,
typename Decoder>
333BaseNTransformer<BitsPerChunk, BaseZeroCode, Encoder, Decoder>::decode(
334 const char*
const algorithm,
336 vector<uint8_t>& result)
342 string::const_reverse_iterator srit = input.rbegin();
343 string::const_reverse_iterator srit_end = input.rend();
344 while (srit != srit_end) {
346 if (ch == BASE_PADDING_CHAR) {
347 if (++padchars > MAX_PADDING_CHARS) {
348 isc_throw(BadValue,
"Too many " << algorithm
349 <<
" padding characters: " << input);
351 }
else if (!(ch > 0 && isspace(ch))) {
371 const size_t padbits = (padchars * BitsPerChunk + 7) & ~7;
383 if (padbits > BitsPerChunk * (padchars + 1)) {
384 isc_throw(BadValue,
"Invalid " << algorithm <<
" padding: " << input);
388 const size_t padbytes = padbits / 8;
391 size_t char_count = 0;
392 result.assign(Decoder(DecodeNormalizer(BaseZeroCode, input.begin(),
393 srit.base(), input.end(),
395 Decoder(DecodeNormalizer(BaseZeroCode, input.end(),
396 input.end(), input.end(),
402 if (((char_count * BitsPerChunk) % 8) != 0) {
404 throw clang_unnamed_namespace_workaround::IncompleteBaseInput();
406 }
catch (
const clang_unnamed_namespace_workaround::IncompleteBaseInput&) {
408 isc_throw(BadValue,
"Incomplete input for " << algorithm
410 }
catch (
const dataflow_exception& ex) {
420 if (padbytes > 0 && *(result.end() - padbytes) != 0) {
421 isc_throw(BadValue,
"Non 0 bits included in " << algorithm
422 <<
" padding: " << input);
426 result.resize(result.size() - padbytes);
433base64_from_binary<transform_width<EncodeNormalizer, 6, 8> > base64_encoder;
435transform_width<binary_from_base64<DecodeNormalizer>, 8, 6> base64_decoder;
436typedef BaseNTransformer<6, 'A', base64_encoder, base64_decoder>
446transform_width<binary_from_base32hex<DecodeNormalizer>, 8, 5>
448typedef BaseNTransformer<5, '0', base32hex_encoder, base32hex_decoder>
457transform_width<binary_from_base16<DecodeNormalizer>, 8, 4> base16_decoder;
458typedef BaseNTransformer<4, '0', base16_encoder, base16_decoder>
464 return (Base64Transformer::encode(binary));
469 Base64Transformer::decode(
"base64", input, result);
474 return (Base32HexTransformer::encode(binary));
479 Base32HexTransformer::decode(
"base32hex", input, result);
484 return (Base16Transformer::encode(binary));
488decodeHex(
const string& input, vector<uint8_t>& result) {
489 Base16Transformer::decode(
"base16", input, result);
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#define isc_throw_assert(expr)
Replacement for assert() that throws if the expression is false.
ElementPtr copy(ConstElementPtr from, int level)
Copy the data up to a nesting level.
bool operator==(const Element &a, const Element &b)
void decodeBase64(const std::string &input, std::vector< uint8_t > &result)
Decode a text encoded in the base64 format into the original data.
std::string encodeBase64(const std::vector< uint8_t > &binary)
Encode binary data in the base64 format.
string encodeHex(const vector< uint8_t > &binary)
Encode binary data in the base16 ('hex') format.
void decodeBase32Hex(const std::string &input, std::vector< uint8_t > &result)
Decode a text encoded in the base32hex format into the original data.
void decodeHex(const string &input, vector< uint8_t > &result)
Decode a text encoded in the base16 ('hex') format into the original data.
std::string encodeBase32Hex(const std::vector< uint8_t > &binary)
Encode binary data in the base32hex format.
Defines the logger used by the top-level component of kea-lfc.