Coverage Report

Created: 2023-01-25 06:35

/src/botan/src/lib/codec/hex/hex.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* Hex Encoding and Decoding
3
* (C) 2010,2020 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/hex.h>
9
#include <botan/mem_ops.h>
10
#include <botan/exceptn.h>
11
#include <botan/internal/charset.h>
12
#include <botan/internal/ct_utils.h>
13
#include <sstream>
14
15
namespace Botan {
16
17
namespace {
18
19
char hex_encode_nibble(uint8_t n, bool uppercase)
20
1.37M
   {
21
1.37M
   BOTAN_DEBUG_ASSERT(n <= 15);
22
23
1.37M
   const auto in_09 = CT::Mask<uint8_t>::is_lt(n, 10);
24
25
1.37M
   const char c_09 = n + '0';
26
1.37M
   const char c_af = n + (uppercase ? 'A' : 'a') - 10;
27
28
1.37M
   return in_09.select(c_09, c_af);
29
1.37M
   }
30
31
}
32
33
void hex_encode(char output[],
34
                const uint8_t input[],
35
                size_t input_length,
36
                bool uppercase)
37
26.4k
   {
38
714k
   for(size_t i = 0; i != input_length; ++i)
39
687k
      {
40
687k
      const uint8_t n0 = (input[i] >> 4) & 0xF;
41
687k
      const uint8_t n1 = (input[i]     ) & 0xF;
42
43
687k
      output[2*i  ] = hex_encode_nibble(n0, uppercase);
44
687k
      output[2*i+1] = hex_encode_nibble(n1, uppercase);
45
687k
      }
46
26.4k
   }
47
48
std::string hex_encode(const uint8_t input[],
49
                       size_t input_length,
50
                       bool uppercase)
51
26.4k
   {
52
26.4k
   std::string output(2 * input_length, 0);
53
54
26.4k
   if(input_length)
55
26.4k
      hex_encode(&output.front(), input, input_length, uppercase);
56
57
26.4k
   return output;
58
26.4k
   }
59
60
namespace {
61
62
uint8_t hex_char_to_bin(char input)
63
2.25M
   {
64
2.25M
   const uint8_t c = static_cast<uint8_t>(input);
65
66
2.25M
   const auto is_alpha_upper = CT::Mask<uint8_t>::is_within_range(c, uint8_t('A'), uint8_t('F'));
67
2.25M
   const auto is_alpha_lower = CT::Mask<uint8_t>::is_within_range(c, uint8_t('a'), uint8_t('f'));
68
2.25M
   const auto is_decimal     = CT::Mask<uint8_t>::is_within_range(c, uint8_t('0'), uint8_t('9'));
69
70
2.25M
   const auto is_whitespace  = CT::Mask<uint8_t>::is_any_of(c, {
71
2.25M
         uint8_t(' '), uint8_t('\t'), uint8_t('\n'), uint8_t('\r')
72
2.25M
      });
73
74
2.25M
   const uint8_t c_upper = c - uint8_t('A') + 10;
75
2.25M
   const uint8_t c_lower = c - uint8_t('a') + 10;
76
2.25M
   const uint8_t c_decim = c - uint8_t('0');
77
78
2.25M
   uint8_t ret = 0xFF; // default value
79
80
2.25M
   ret = is_alpha_upper.select(c_upper, ret);
81
2.25M
   ret = is_alpha_lower.select(c_lower, ret);
82
2.25M
   ret = is_decimal.select(c_decim, ret);
83
2.25M
   ret = is_whitespace.select(0x80, ret);
84
85
2.25M
   return ret;
86
2.25M
   }
87
88
}
89
90
91
size_t hex_decode(uint8_t output[],
92
                  const char input[],
93
                  size_t input_length,
94
                  size_t& input_consumed,
95
                  bool ignore_ws)
96
57.3k
   {
97
57.3k
   uint8_t* out_ptr = output;
98
57.3k
   bool top_nibble = true;
99
100
57.3k
   clear_mem(output, input_length / 2);
101
102
2.31M
   for(size_t i = 0; i != input_length; ++i)
103
2.25M
      {
104
2.25M
      const uint8_t bin = hex_char_to_bin(input[i]);
105
106
2.25M
      if(bin >= 0x10)
107
0
         {
108
0
         if(bin == 0x80 && ignore_ws)
109
0
            continue;
110
111
0
         std::ostringstream err;
112
0
         err << "hex_decode: invalid character " << format_char_for_display(input[i]);
113
0
         throw Invalid_Argument(err.str());
114
0
         }
115
116
2.25M
      if(top_nibble)
117
1.12M
         *out_ptr |= bin << 4;
118
1.12M
      else
119
1.12M
         *out_ptr |= bin;
120
121
2.25M
      top_nibble = !top_nibble;
122
2.25M
      if(top_nibble)
123
1.12M
         ++out_ptr;
124
2.25M
      }
125
126
57.3k
   input_consumed = input_length;
127
57.3k
   size_t written = (out_ptr - output);
128
129
   /*
130
   * We only got half of a uint8_t at the end; zap the half-written
131
   * output and mark it as unread
132
   */
133
57.3k
   if(!top_nibble)
134
0
      {
135
0
      *out_ptr = 0;
136
0
      input_consumed -= 1;
137
0
      }
138
139
57.3k
   return written;
140
57.3k
   }
141
142
size_t hex_decode(uint8_t output[],
143
                  const char input[],
144
                  size_t input_length,
145
                  bool ignore_ws)
146
57.3k
   {
147
57.3k
   size_t consumed = 0;
148
57.3k
   size_t written = hex_decode(output, input, input_length,
149
57.3k
                               consumed, ignore_ws);
150
151
57.3k
   if(consumed != input_length)
152
0
      throw Invalid_Argument("hex_decode: input did not have full bytes");
153
154
57.3k
   return written;
155
57.3k
   }
156
157
size_t hex_decode(uint8_t output[],
158
                  const std::string& input,
159
                  bool ignore_ws)
160
44.2k
   {
161
44.2k
   return hex_decode(output, input.data(), input.length(), ignore_ws);
162
44.2k
   }
163
164
secure_vector<uint8_t> hex_decode_locked(const char input[],
165
                                      size_t input_length,
166
                                      bool ignore_ws)
167
13.1k
   {
168
13.1k
   secure_vector<uint8_t> bin(1 + input_length / 2);
169
170
13.1k
   size_t written = hex_decode(bin.data(),
171
13.1k
                               input,
172
13.1k
                               input_length,
173
13.1k
                               ignore_ws);
174
175
13.1k
   bin.resize(written);
176
13.1k
   return bin;
177
13.1k
   }
178
179
secure_vector<uint8_t> hex_decode_locked(const std::string& input,
180
                                      bool ignore_ws)
181
0
   {
182
0
   return hex_decode_locked(input.data(), input.size(), ignore_ws);
183
0
   }
184
185
std::vector<uint8_t> hex_decode(const char input[],
186
                             size_t input_length,
187
                             bool ignore_ws)
188
0
   {
189
0
   std::vector<uint8_t> bin(1 + input_length / 2);
190
191
0
   size_t written = hex_decode(bin.data(),
192
0
                               input,
193
0
                               input_length,
194
0
                               ignore_ws);
195
196
0
   bin.resize(written);
197
0
   return bin;
198
0
   }
199
200
std::vector<uint8_t> hex_decode(const std::string& input,
201
                             bool ignore_ws)
202
0
   {
203
0
   return hex_decode(input.data(), input.size(), ignore_ws);
204
0
   }
205
206
}