GCC Code Coverage Report


Directory: ./
File: libs/capy/src/bcrypt/base64.cpp
Date: 2025-12-30 20:31:36
Exec Total Coverage
Lines: 64 69 92.8%
Functions: 2 2 100.0%
Branches: 13 20 65.0%

Line Branch Exec Source
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/capy
8 //
9
10 #include "base64.hpp"
11
12 namespace boost {
13 namespace capy {
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 31 base64_encode(
63 char* dest,
64 std::uint8_t const* src,
65 std::size_t n)
66 {
67 31 char* out = dest;
68
69
2/2
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 31 times.
210 while (n >= 3)
70 {
71 179 std::uint32_t v =
72 179 (static_cast<std::uint32_t>(src[0]) << 16) |
73 179 (static_cast<std::uint32_t>(src[1]) << 8) |
74 179 static_cast<std::uint32_t>(src[2]);
75
76 179 *out++ = encode_table[(v >> 18) & 0x3F];
77 179 *out++ = encode_table[(v >> 12) & 0x3F];
78 179 *out++ = encode_table[(v >> 6) & 0x3F];
79 179 *out++ = encode_table[v & 0x3F];
80
81 179 src += 3;
82 179 n -= 3;
83 }
84
85
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 19 times.
31 if (n == 2)
86 {
87 12 std::uint32_t v =
88 12 (static_cast<std::uint32_t>(src[0]) << 16) |
89 12 (static_cast<std::uint32_t>(src[1]) << 8);
90
91 12 *out++ = encode_table[(v >> 18) & 0x3F];
92 12 *out++ = encode_table[(v >> 12) & 0x3F];
93 12 *out++ = encode_table[(v >> 6) & 0x3F];
94 }
95
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 else if (n == 1)
96 {
97 19 std::uint32_t v =
98 19 static_cast<std::uint32_t>(src[0]) << 16;
99
100 19 *out++ = encode_table[(v >> 18) & 0x3F];
101 19 *out++ = encode_table[(v >> 12) & 0x3F];
102 }
103
104 31 return static_cast<std::size_t>(out - dest);
105 }
106
107 int
108 17 base64_decode(
109 std::uint8_t* dest,
110 char const* src,
111 std::size_t n)
112 {
113 17 std::uint8_t* out = dest;
114 17 std::size_t i = 0;
115
116
2/2
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 17 times.
114 while (i + 4 <= n)
117 {
118 97 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])];
119 97 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])];
120 97 std::uint8_t c = decode_table[static_cast<unsigned char>(src[i + 2])];
121 97 std::uint8_t d = decode_table[static_cast<unsigned char>(src[i + 3])];
122
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
97 if ((a | b | c | d) & 0x80)
124 return -1;
125
126 97 std::uint32_t v =
127 97 (static_cast<std::uint32_t>(a) << 18) |
128 97 (static_cast<std::uint32_t>(b) << 12) |
129 97 (static_cast<std::uint32_t>(c) << 6) |
130 97 static_cast<std::uint32_t>(d);
131
132 97 *out++ = static_cast<std::uint8_t>(v >> 16);
133 97 *out++ = static_cast<std::uint8_t>(v >> 8);
134 97 *out++ = static_cast<std::uint8_t>(v);
135
136 97 i += 4;
137 }
138
139 // Handle remaining 2 or 3 characters
140
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 11 times.
17 if (i + 3 == n)
141 {
142 6 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])];
143 6 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])];
144 6 std::uint8_t c = decode_table[static_cast<unsigned char>(src[i + 2])];
145
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if ((a | b | c) & 0x80)
147 return -1;
148
149 6 std::uint32_t v =
150 6 (static_cast<std::uint32_t>(a) << 18) |
151 6 (static_cast<std::uint32_t>(b) << 12) |
152 6 (static_cast<std::uint32_t>(c) << 6);
153
154 6 *out++ = static_cast<std::uint8_t>(v >> 16);
155 6 *out++ = static_cast<std::uint8_t>(v >> 8);
156 }
157
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 else if (i + 2 == n)
158 {
159 11 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])];
160 11 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])];
161
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ((a | b) & 0x80)
163 return -1;
164
165 11 std::uint32_t v =
166 11 (static_cast<std::uint32_t>(a) << 18) |
167 11 (static_cast<std::uint32_t>(b) << 12);
168
169 11 *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 17 return static_cast<int>(out - dest);
178 }
179
180 } // detail
181 } // bcrypt
182 } // capy
183 } // boost
184
185