18 #include <boost/archive/iterators/base64_from_binary.hpp>
19 #include <boost/archive/iterators/binary_from_base64.hpp>
20 #include <boost/archive/iterators/transform_width.hpp>
21 #include <boost/math/common_factor.hpp>
39 namespace clang_unnamed_namespace_workaround {
94 const char BASE_PADDING_CHAR =
'=';
95 const uint8_t BINARY_ZERO_CODE = 0;
111 class EncodeNormalizer :
public iterator<input_iterator_tag, uint8_t> {
113 EncodeNormalizer(
const vector<uint8_t>::const_iterator& base,
114 const vector<uint8_t>::const_iterator& base_end) :
115 base_(base), base_end_(base_end), in_pad_(false)
117 EncodeNormalizer& operator++() {
121 EncodeNormalizer operator++(
int) {
122 const EncodeNormalizer
copy = *
this;
126 const uint8_t& operator*()
const {
128 return (BINARY_ZERO_CODE);
133 bool operator==(
const EncodeNormalizer& other)
const {
134 return (base_ == other.base_);
141 if (base_ == base_end_) {
145 vector<uint8_t>::const_iterator base_;
146 const vector<uint8_t>::const_iterator base_end_;
166 class DecodeNormalizer :
public iterator<input_iterator_tag, char> {
168 DecodeNormalizer(
const char base_zero_code,
169 const string::const_iterator& base,
170 const string::const_iterator& base_beginpad,
171 const string::const_iterator& base_end,
172 size_t* char_count) :
173 base_zero_code_(base_zero_code),
174 base_(base), base_beginpad_(base_beginpad), base_end_(base_end),
175 in_pad_(false), char_count_(char_count)
181 DecodeNormalizer& operator++() {
182 if (base_ < base_end_) {
187 if (base_ == base_beginpad_) {
201 while (base_ != base_end_ && *base_ > 0 && isspace(*base_)) {
205 const char& operator*()
const {
206 if (base_ == base_end_) {
220 throw clang_unnamed_namespace_workaround::IncompleteBaseInput();
222 if (*base_ == BASE_PADDING_CHAR) {
228 return (base_zero_code_);
230 isc_throw(BadValue,
"Intermediate padding found");
236 bool operator==(
const DecodeNormalizer& other)
const {
237 return (base_ == other.base_);
240 const char base_zero_code_;
241 string::const_iterator base_;
242 const string::const_iterator base_beginpad_;
243 const string::const_iterator base_end_;
258 template <
int BitsPerChunk,
char BaseZeroCode,
259 typename Encoder,
typename Decoder>
260 struct BaseNTransformer {
261 static string encode(
const vector<uint8_t>& binary);
262 static void decode(
const char* algorithm,
263 const string& base64, vector<uint8_t>& result);
269 static const int BITS_PER_GROUP =
270 boost::math::static_lcm<BitsPerChunk, 8>::value;
281 static const int MAX_PADDING_CHARS =
282 BITS_PER_GROUP / BitsPerChunk -
283 (8 / BitsPerChunk + ((8 % BitsPerChunk) == 0 ? 0 : 1));
286 template <
int BitsPerChunk,
char BaseZeroCode,
287 typename Encoder,
typename Decoder>
289 BaseNTransformer<BitsPerChunk, BaseZeroCode, Encoder, Decoder>::encode(
290 const vector<uint8_t>& binary)
293 size_t bits = binary.size() * 8;
294 if (bits % BITS_PER_GROUP > 0) {
295 bits += (BITS_PER_GROUP - (bits % BITS_PER_GROUP));
297 const size_t len = bits / BitsPerChunk;
301 result.assign(Encoder(EncodeNormalizer(binary.begin(), binary.end())),
302 Encoder(EncodeNormalizer(binary.end(), binary.end())));
303 assert(len >= result.length());
304 result.append(len - result.length(), BASE_PADDING_CHAR);
308 template <
int BitsPerChunk,
char BaseZeroCode,
309 typename Encoder,
typename Decoder>
311 BaseNTransformer<BitsPerChunk, BaseZeroCode, Encoder, Decoder>::decode(
312 const char*
const algorithm,
314 vector<uint8_t>& result)
320 string::const_reverse_iterator srit = input.rbegin();
321 string::const_reverse_iterator srit_end = input.rend();
322 while (srit != srit_end) {
324 if (ch == BASE_PADDING_CHAR) {
325 if (++padchars > MAX_PADDING_CHARS) {
326 isc_throw(BadValue,
"Too many " << algorithm
327 <<
" padding characters: " << input);
329 }
else if (!(ch > 0 && isspace(ch))) {
349 const size_t padbits = (padchars * BitsPerChunk + 7) & ~7;
361 if (padbits > BitsPerChunk * (padchars + 1)) {
362 isc_throw(BadValue,
"Invalid " << algorithm <<
" padding: " << input);
366 const size_t padbytes = padbits / 8;
369 size_t char_count = 0;
370 result.assign(Decoder(DecodeNormalizer(BaseZeroCode, input.begin(),
371 srit.base(), input.end(),
373 Decoder(DecodeNormalizer(BaseZeroCode, input.end(),
374 input.end(), input.end(),
380 if (((char_count * BitsPerChunk) % 8) != 0) {
382 throw clang_unnamed_namespace_workaround::IncompleteBaseInput();
384 }
catch (
const clang_unnamed_namespace_workaround::IncompleteBaseInput&) {
386 isc_throw(BadValue,
"Incomplete input for " << algorithm
388 }
catch (
const dataflow_exception& ex) {
397 assert(result.size() >= padbytes);
398 if (padbytes > 0 && *(result.end() - padbytes) != 0) {
399 isc_throw(BadValue,
"Non 0 bits included in " << algorithm
400 <<
" padding: " << input);
404 result.resize(result.size() - padbytes);
411 base64_from_binary<transform_width<EncodeNormalizer, 6, 8> > base64_encoder;
413 transform_width<binary_from_base64<DecodeNormalizer>, 8, 6> base64_decoder;
414 typedef BaseNTransformer<6, 'A', base64_encoder, base64_decoder>
424 transform_width<binary_from_base32hex<DecodeNormalizer>, 8, 5>
426 typedef BaseNTransformer<5, '0', base32hex_encoder, base32hex_decoder>
427 Base32HexTransformer;
435 transform_width<binary_from_base16<DecodeNormalizer>, 8, 4> base16_decoder;
436 typedef BaseNTransformer<4, '0', base16_encoder, base16_decoder>
442 return (Base64Transformer::encode(binary));
447 Base64Transformer::decode(
"base64", input, result);
452 return (Base32HexTransformer::encode(binary));
457 Base32HexTransformer::decode(
"base32hex", input, result);
462 return (Base16Transformer::encode(binary));
466 decodeHex(
const string& input, vector<uint8_t>& result) {
467 Base16Transformer::decode(
"base16", input, result);