2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 13:37:55 +00:00

[#3209] Remove internal bool vectors

src/lib/util/encode/encode.cc
    BaseNEncoder::encode()
    BaseNEncoder::decode() - eliminate use of bool vectors
    as "bit streams"
This commit is contained in:
Thomas Markwalder 2024-01-31 14:00:37 -05:00
parent 6949dd94a3
commit 06fc63c9f5

View File

@ -70,38 +70,37 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
return(encoded_output);
}
// Turn the input data into a "bit stream"
/// @todo Can we devise a bit-stream class that can iterate over the input
/// without copying it? The weakness here is inbits could be rather large
/// for long strings since it input size * 8 bytes.
bool inbits[input.size() * 8];
bool* inbit = &inbits[0];
for (auto b : input) {
for (auto i = 0; i < 8; i++) {
bool val = b & 0x80;
*inbit++ = val;
b <<= 1;
}
}
// Now encode the bit stream.
uint8_t cur_bit = 0x0;
int cnt = 0;
int digit_idx = 0;
auto inbit_end = inbit;
inbit = &inbits[0];
for (inbit = &inbits[0]; inbit != inbit_end; ++inbit) {
int cur_byte = 0;
auto bytes = input.begin();
while (1) {
if (!cur_bit) {
if (bytes == input.end()) {
break;
}
cur_byte = *bytes;
cur_bit = 0x80;
++bytes;
}
if (cnt < bits_per_digit_) {
// Shift the index one to accommodate next bit.
digit_idx <<= 1;
} else {
// Have a complete digit index, look it the digit and add it.
// Have a complete digit index, look up digit and add it.
encoded_output.push_back(bitsToDigit(digit_idx));
digit_idx = 0;
cnt = 0;
}
// Add the current bit to the digit index.
digit_idx |= *inbit;
if (cur_byte & cur_bit) {
digit_idx |= 1;
}
cur_bit >>= 1;
++cnt;
}
@ -128,52 +127,84 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
void
BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& output) {
output.clear();
bool inbits[encoded_str.size() * bits_per_digit_];
bool* inbit = &inbits[0];
size_t dig_cnt = 0;
size_t pad_cnt = 0;
size_t shift_bits = 8 - bits_per_digit_;
uint8_t cur_byte = 0;
size_t cur_bit_cnt = 0;
for (const auto enc_digit : encoded_str) {
if (pad_char_ && enc_digit == pad_char_) {
pad_cnt++;
continue;
}
// translate the b64 digit to bits.
// Translate the b64 digit to bits.
uint8_t dig_bits = digitToBits(enc_digit);
// Skip whitespace.
if (dig_bits == 0xee) {
// skip whitespace
continue;
}
// Error on invalid characters.
if (dig_bits == 0xff) {
isc_throw(isc::BadValue, "attempt to decode a value not in "
<< algorithm_ << " char set" << ": " << encoded_str);
}
// Error if pads are in the middle.
if (pad_cnt) {
isc_throw(isc::BadValue, "pad mixed with digits in "
<< algorithm_ << ": " << encoded_str);
}
// Bump the valid character count.
dig_cnt++;
// Shift off what we don't need.
dig_bits <<= shift_bits;
// Add digit's decoded bits to current byte.
for (auto i = 0; i < bits_per_digit_; ++i) {
*inbit++ = ((dig_bits & 0x80) == 0x80);
if (cur_bit_cnt < 8) {
// Shift contents to make room for next gbit.
cur_byte <<= 1;
} else {
// Add the completed byte to the output.
output.push_back(cur_byte);
cur_byte = 0;
cur_bit_cnt = 0;
}
// Add the next bit if its set.
if (dig_bits & 0x80) {
cur_byte |= 1;
}
// Shift the decoded bits over.
dig_bits <<= 1;
// Update the current byte bit count.
++cur_bit_cnt;
}
}
if (cur_bit_cnt == 8) {
// Whole one left to add.
output.push_back(cur_byte);
} else if (cur_bit_cnt && cur_byte) {
// Left over bits that are not zero.
isc_throw(BadValue, "non-zero bits left over " << encoded_str);
}
if (pad_char_) {
// Check for invalid number of pad characters.
// Check for too many pad characters.
if (pad_cnt > max_pad_) {
isc_throw(isc::BadValue, "too many pad characters for "
<< algorithm_ << ": " << encoded_str);
}
// Check for invalid number of pad characters.
/// @todo is this valid
const size_t padbits = ((pad_cnt * bits_per_digit_) + 7) & ~7;
if (padbits > bits_per_digit_ * (pad_cnt + 1)) {
isc_throw(isc::BadValue, "Invalid padding for "
@ -186,32 +217,6 @@ BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& outpu
isc_throw (isc::BadValue, "Incomplete input for "
<< algorithm_ << ": " << encoded_str);
}
int cnt = 0;
int digit_idx = 0;
auto inbit_end = inbit;
inbit = &inbits[0];
for (inbit = &inbits[0]; inbit != inbit_end; ++inbit) {
if (cnt < 8) {
digit_idx <<= 1;
} else {
output.push_back(digit_idx);
digit_idx = 0;
cnt = 0;
}
digit_idx |= *inbit;
++cnt;
}
if (cnt == 8) {
// Whole one left to add.
output.push_back(digit_idx);
} else if (cnt && digit_idx) {
// Left over bits that are not zero.
isc_throw(BadValue, "non-zero bits left over " << encoded_str);
}
}
const char* Base64Encoder::DIGIT_SET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
@ -282,40 +287,41 @@ const std::vector<uint8_t> Base16Encoder::BITS_TABLE = {
string
encodeBase64(const vector<uint8_t>& binary) {
Base64Encoder encoder;
static Base64Encoder encoder;
return(encoder.encode(binary));
}
void
decodeBase64 (const std::string& encoded_str, std::vector<uint8_t>& output) {
Base64Encoder encoder;
static Base64Encoder encoder;
encoder.decode(encoded_str, output);
}
string
encodeBase32Hex(const vector<uint8_t>& binary) {
Base32HexEncoder encoder;
static Base32HexEncoder encoder;
return(encoder.encode(binary));
}
void
decodeBase32Hex(const std::string& encoded_str, std::vector<uint8_t>& output) {
Base32HexEncoder encoder;
static Base32HexEncoder encoder;
encoder.decode(encoded_str, output);
}
string
encodeHex(const vector<uint8_t>& binary) {
Base16Encoder encoder;
static Base16Encoder encoder;
return(encoder.encode(binary));
}
void
decodeHex(const string& encoded_str, vector<uint8_t>& output) {
Base16Encoder encoder;
static Base16Encoder encoder;
encoder.decode(encoded_str, output);
}
} // namespace encode
} // namespace util
} // namespace isc