Line data 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/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 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 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 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 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 97 : if ((a | b | c | d) & 0x80)
124 0 : 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 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 6 : if ((a | b | c) & 0x80)
147 0 : 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 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 11 : if ((a | b) & 0x80)
163 0 : 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 0 : else if (i + 1 == n)
172 : {
173 : // Single trailing character is invalid
174 0 : return -1;
175 : }
176 :
177 17 : return static_cast<int>(out - dest);
178 : }
179 :
180 : } // detail
181 : } // bcrypt
182 : } // capy
183 : } // boost
184 :
|