libs/http/src/bcrypt/base64.cpp

92.8% Lines (64/69) 100.0% Functions (2/2) 65.0% Branches (13/20)
libs/http/src/bcrypt/base64.cpp
Line Branch Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/http
8 //
9
10 #include "base64.hpp"
11
12 namespace boost {
13 namespace http {
14 namespace bcrypt {
15 namespace detail {
16
17 namespace {
18
19 // bcrypt's non-standard base64 alphabet
20 constexpr char encode_table[] =
21 "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
22
23 // Decode table: maps ASCII char to 6-bit value, or 0xFF for invalid
24 constexpr std::uint8_t decode_table[256] = {
25 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0-7
26 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8-15
27 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 16-23
28 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 24-31
29 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 32-39
30 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, // 40-47 (. /)
31 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, // 48-55 (0-7)
32 0x3E, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 56-63 (8-9)
33 0xFF, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 64-71 (A-G)
34 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, // 72-79 (H-O)
35 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, // 80-87 (P-W)
36 0x19, 0x1A, 0x1B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 88-95 (X-Z)
37 0xFF, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, // 96-103 (a-g)
38 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, // 104-111 (h-o)
39 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, // 112-119 (p-w)
40 0x33, 0x34, 0x35, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 120-127 (x-z)
41 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
42 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
43 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
44 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
45 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
46 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
47 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
48 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
49 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
50 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
51 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
52 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
53 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
54 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
55 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
56 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
57 };
58
59 } // namespace
60
61 std::size_t
62 43 base64_encode(
63 char* dest,
64 std::uint8_t const* src,
65 std::size_t n)
66 {
67 43 char* out = dest;
68
69
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 43 times.
294 while (n >= 3)
70 {
71 251 std::uint32_t v =
72 251 (static_cast<std::uint32_t>(src[0]) << 16) |
73 251 (static_cast<std::uint32_t>(src[1]) << 8) |
74 251 static_cast<std::uint32_t>(src[2]);
75
76 251 *out++ = encode_table[(v >> 18) & 0x3F];
77 251 *out++ = encode_table[(v >> 12) & 0x3F];
78 251 *out++ = encode_table[(v >> 6) & 0x3F];
79 251 *out++ = encode_table[v & 0x3F];
80
81 251 src += 3;
82 251 n -= 3;
83 }
84
85
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 25 times.
43 if (n == 2)
86 {
87 18 std::uint32_t v =
88 18 (static_cast<std::uint32_t>(src[0]) << 16) |
89 18 (static_cast<std::uint32_t>(src[1]) << 8);
90
91 18 *out++ = encode_table[(v >> 18) & 0x3F];
92 18 *out++ = encode_table[(v >> 12) & 0x3F];
93 18 *out++ = encode_table[(v >> 6) & 0x3F];
94 }
95
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 else if (n == 1)
96 {
97 25 std::uint32_t v =
98 25 static_cast<std::uint32_t>(src[0]) << 16;
99
100 25 *out++ = encode_table[(v >> 18) & 0x3F];
101 25 *out++ = encode_table[(v >> 12) & 0x3F];
102 }
103
104 43 return static_cast<std::size_t>(out - dest);
105 }
106
107 int
108 25 base64_decode(
109 std::uint8_t* dest,
110 char const* src,
111 std::size_t n)
112 {
113 25 std::uint8_t* out = dest;
114 25 std::size_t i = 0;
115
116
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 25 times.
170 while (i + 4 <= n)
117 {
118 145 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])];
119 145 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])];
120 145 std::uint8_t c = decode_table[static_cast<unsigned char>(src[i + 2])];
121 145 std::uint8_t d = decode_table[static_cast<unsigned char>(src[i + 3])];
122
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 145 times.
145 if ((a | b | c | d) & 0x80)
124 return -1;
125
126 145 std::uint32_t v =
127 145 (static_cast<std::uint32_t>(a) << 18) |
128 145 (static_cast<std::uint32_t>(b) << 12) |
129 145 (static_cast<std::uint32_t>(c) << 6) |
130 145 static_cast<std::uint32_t>(d);
131
132 145 *out++ = static_cast<std::uint8_t>(v >> 16);
133 145 *out++ = static_cast<std::uint8_t>(v >> 8);
134 145 *out++ = static_cast<std::uint8_t>(v);
135
136 145 i += 4;
137 }
138
139 // Handle remaining 2 or 3 characters
140
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 15 times.
25 if (i + 3 == n)
141 {
142 10 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])];
143 10 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])];
144 10 std::uint8_t c = decode_table[static_cast<unsigned char>(src[i + 2])];
145
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if ((a | b | c) & 0x80)
147 return -1;
148
149 10 std::uint32_t v =
150 10 (static_cast<std::uint32_t>(a) << 18) |
151 10 (static_cast<std::uint32_t>(b) << 12) |
152 10 (static_cast<std::uint32_t>(c) << 6);
153
154 10 *out++ = static_cast<std::uint8_t>(v >> 16);
155 10 *out++ = static_cast<std::uint8_t>(v >> 8);
156 }
157
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 else if (i + 2 == n)
158 {
159 15 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])];
160 15 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])];
161
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if ((a | b) & 0x80)
163 return -1;
164
165 15 std::uint32_t v =
166 15 (static_cast<std::uint32_t>(a) << 18) |
167 15 (static_cast<std::uint32_t>(b) << 12);
168
169 15 *out++ = static_cast<std::uint8_t>(v >> 16);
170 }
171 else if (i + 1 == n)
172 {
173 // Single trailing character is invalid
174 return -1;
175 }
176
177 25 return static_cast<int>(out - dest);
178 }
179
180 } // detail
181 } // bcrypt
182 } // http
183 } // boost
184