Skip to content

Commit 73c493c

Browse files
committed
[#3209] Addressed review comments
Minor clean up, added commentary
1 parent 94ac8f4 commit 73c493c

File tree

4 files changed

+80
-58
lines changed

4 files changed

+80
-58
lines changed

src/bin/d2/tests/d2_simple_parser_unittest.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ TEST_F(TSIGKeyInfoParserTest, invalidEntry) {
641641
" \"digest-bits\": 120 , "
642642
" \"secret\": \"bogus\" "
643643
"}";
644-
PARSE_FAIL(config, "Cannot make D2TsigKey: Incomplete input for base64:"
644+
PARSE_FAIL(config, "Cannot make D2TsigKey: non-zero bits left over"
645645
" bogus (<string>:1:1)");
646646
}
647647

src/bin/d2/tests/testdata/d2_cfg_tests.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@
702702
#-----
703703
,{
704704
"description" : "D2.tsig-keys, invalid secret",
705-
"logic-error" : "Cannot make D2TsigKey: Incomplete input for base64: bogus (<string>:1:62)",
705+
"logic-error" : "Cannot make D2TsigKey: non-zero bits left over bogus (<string>:1:62)",
706706
"data" :
707707
{
708708
"forward-ddns" : {},

src/lib/util/encode/encode.cc

+78-44
Original file line numberDiff line numberDiff line change
@@ -70,61 +70,74 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
7070
return (encoded_output);
7171
}
7272

73-
uint8_t cur_bit = 0x0;
74-
int cnt = 0;
75-
int digit_idx = 0;
76-
int cur_byte = 0;
77-
auto bytes = input.begin();
73+
// Iterate over the input bytes as a bit stream. We add input bits
74+
// to a digit set index value until we have enough (bits_per_digit). We
75+
// look up a digit in the digit set add it to the encoded output and start over
76+
// on the next index value. When we have exhausted the bits in the current
77+
// byte, get the next byte from input and continue. In other words, we pull bits
78+
// from the left side of the input bit stream and push them into the right side of
79+
// the index value. Each time we have done bits_per_digit bits we look up
80+
// the digit and start the index value over.
81+
82+
int digit_idx = 0; // Digit index we are currently constructing.
83+
int cnt = 0; // How many bits we have in the current digit idx
84+
int cur_byte = 0; // Current input byte.
85+
uint8_t cur_bit_mask = 0x0; // Bitmask of the current bit in the current byte.
86+
auto bytes = input.begin(); // Start with the first byte.
7887
while (1) {
79-
if (!cur_bit) {
88+
// If the current bitmask is zero, it's time for the next input byte.
89+
if (!cur_bit_mask) {
8090
if (bytes == input.end()) {
8191
break;
8292
}
8393

94+
// Grab the next byte.
8495
cur_byte = *bytes;
85-
cur_bit = 0x80;
96+
// Start at the bitmask at the left-most bit.
97+
cur_bit_mask = 0x80;
98+
// Bump the iterator.
8699
++bytes;
87100
}
88101

102+
// Do we need more bits in this digit index?
89103
if (cnt < bits_per_digit_) {
104+
// Yes, so shift the index over to make room for the next bit.
90105
digit_idx <<= 1;
91106
} else {
92-
#if 0
93-
// Have a complete digit index, look up digit and add it.
94-
encoded_output.push_back(bitsToDigit(digit_idx));
95-
#else
107+
// No, the index is complete, lookup its digit and add it to the
108+
// output. Start over for the next index.
96109
encoded_output.push_back(digit_set_[digit_idx]);
97-
#endif
98-
99110
digit_idx = 0;
100111
cnt = 0;
101112
}
102113

103-
// Add the current bit to the digit index.
104-
if (cur_byte & cur_bit) {
114+
// If the current bit in the current byte is set,
115+
// set the right-most digit index bit to 1 (otherwise
116+
// its left as zero).
117+
if (cur_byte & cur_bit_mask) {
105118
digit_idx |= 1;
106119
}
107120

108-
cur_bit >>= 1;
121+
// Shift the cur_bit mask to select the next input bit and
122+
// bump the number of bits in the current index.
123+
cur_bit_mask >>= 1;
109124
++cnt;
110125
}
111126

112-
// We've exhausted bits, but have left over
113-
if (cnt) {
114-
digit_idx <<= (bits_per_digit_ - cnt);
115-
#if 0
116-
encoded_output.push_back(bitsToDigit(digit_idx));
117-
#else
118-
encoded_output.push_back(digit_set_[digit_idx]);
119-
#endif
120-
}
127+
// We've exhausted the input bits but have bits in the
128+
// digit index. This means the remaining bits in our
129+
// last index are zeros (pad bits). Shift "in" the
130+
// required number of bits and add the corresponding
131+
// digit.
132+
digit_idx <<= (bits_per_digit_ - cnt);
133+
encoded_output.push_back(bitsToDigit(digit_idx));
121134

122135
// Add padding as needed.
123136
if (digits_per_group_) {
124137
auto rem = encoded_output.size() % digits_per_group_;
125138
if (rem) {
126-
auto need = digits_per_group_ - rem + 1;
127-
while (--need) {
139+
auto need = digits_per_group_ - rem;
140+
while (need--) {
128141
encoded_output.push_back(pad_char_);
129142
}
130143
}
@@ -135,26 +148,34 @@ BaseNEncoder::encode(const std::vector<uint8_t>& input) {
135148

136149
void
137150
BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& output) {
151+
152+
// Mechanics are the essentially the same as encode(). We iterate over the encoded
153+
// string's digits, discarding whitespaces. We lookup the digit's binary value
154+
// in the lookup table, keeping only binary value's right-most, bits_per_digit bits.
155+
// The remaining bits are then shifted out from the left of binary value into the
156+
// right of the currently accumulating output byte until the byte is complete
157+
// (8 bits) or the value's bits are exhausted. Completed bytes are added to the
158+
// output buffer. We continue building bytes until we've exhausted the encoded
159+
// string.
160+
138161
output.clear();
139-
size_t dig_cnt = 0;
140-
size_t pad_cnt = 0;
141-
size_t shift_bits = 8 - bits_per_digit_;
142-
uint8_t cur_byte = 0;
143-
size_t cur_bit_cnt = 0;
162+
size_t dig_cnt = 0; // Tracks how many encoded digits we see.
163+
size_t pad_cnt = 0; // Tracks how many pad characters we see.
164+
size_t shift_bits = 8 - bits_per_digit_; // Number of unused bits in digit data values.
165+
uint8_t cur_byte = 0; // Current output byte.
166+
size_t cur_bit_cnt = 0; // How man bits we have added to the current byte.
167+
144168
for (const auto enc_digit : encoded_str) {
169+
// If it's a pad char, count it and go on.
145170
if (pad_char_ && enc_digit == pad_char_) {
146171
pad_cnt++;
147172
continue;
148173
}
149174

150-
// Translate the b64 digit to bits.
151-
#if 0
175+
// Translate the encoded digit to its binary bits.
152176
uint8_t dig_bits = digitToBits(enc_digit);
153-
#else
154-
uint8_t dig_bits = bits_table_[enc_digit];
155-
#endif
156177

157-
// Skip whitespace.
178+
// Skip whitespace. The choice of 0xee to signify white-space was arbitrary.
158179
if (dig_bits == 0xee) {
159180
continue;
160181
}
@@ -165,7 +186,7 @@ BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& outpu
165186
<< algorithm_ << " char set" << ": " << encoded_str);
166187
}
167188

168-
// Error if pads are in the middle.
189+
// Error if pad characters occur in the middle.
169190
if (pad_cnt) {
170191
isc_throw(isc::BadValue, "pad mixed with digits in "
171192
<< algorithm_ << ": " << encoded_str);
@@ -174,13 +195,13 @@ BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& outpu
174195
// Bump the valid character count.
175196
dig_cnt++;
176197

177-
// Shift off what we don't need.
198+
// Shift off the unused bits.
178199
dig_bits <<= shift_bits;
179200

180201
// Add digit's decoded bits to current byte.
181202
for (auto i = 0; i < bits_per_digit_; ++i) {
182203
if (cur_bit_cnt < 8) {
183-
// Shift contents to make room for next gbit.
204+
// Shift contents over one to make room for next bit.
184205
cur_byte <<= 1;
185206
} else {
186207
// Add the completed byte to the output.
@@ -217,8 +238,22 @@ BaseNEncoder::decode(const std::string& encoded_str, std::vector<uint8_t>& outpu
217238
<< algorithm_ << ": " << encoded_str);
218239
}
219240

220-
// Check for invalid number of pad characters.
221-
const size_t padbits = ((pad_cnt * bits_per_digit_) + 7) & ~7;
241+
// Check for an invalid number of pad bits.
242+
// Calculate the number of pad bits corresponding to the pad
243+
// characters. In general, the pad bits consist of all-zero
244+
// trailing bits of the last encoded character plus the zero bits
245+
// represented by each pad character.
246+
// 1st pad 2nd pad 3rd pad...
247+
// +++===== ======= ===... (+: from encoded chars, =: from pad chars)
248+
// 0000...0 0......0 000...
249+
// 0 7 8 15 16.... (bits)
250+
// The number of bits for the '==...' part is padchars * BitsPerChunk.
251+
// So the total number of pad bits is the smallest multiple of 8
252+
// that is >= padchars * BitsPerChunk.
253+
// (Below, note the common idiom of the bitwise AND with ~7. It clears the
254+
// lowest three bits, so has the effect of rounding the result down to the
255+
// nearest multiple of 8)
256+
const size_t padbits = ((pad_cnt * bits_per_digit_) + 0x07) & ~0x07;
222257
if (padbits > bits_per_digit_ * (pad_cnt + 1)) {
223258
isc_throw(isc::BadValue, "Invalid padding for "
224259
<< algorithm_ << ": " << encoded_str);
@@ -334,7 +369,6 @@ decodeHex(const string& encoded_str, vector<uint8_t>& output) {
334369
encoder.decode(encoded_str, output);
335370
}
336371

337-
338372
} // namespace encode
339373
} // namespace util
340374
} // namespace isc

src/lib/util/tests/encode_unittest.cc

-12
Original file line numberDiff line numberDiff line change
@@ -392,16 +392,4 @@ TEST_F(Base16Test, mappingCheck) {
392392
mapTest();
393393
}
394394

395-
TEST(toms,theirs64) {
396-
std::vector<uint8_t>input{ 'f', 'o', 'o', 'b', 'a', 'r' };
397-
398-
int limit = 1000000;
399-
for (int i = 0; i < limit; ++i) {
400-
std::string encoded = encodeBase64(input);
401-
std::vector<uint8_t>decoded;
402-
decodeBase64(encoded, decoded);
403-
EXPECT_EQ(decoded,input);
404-
}
405-
}
406-
407395
}

0 commit comments

Comments
 (0)