92.75% Lines (64/69) 100.00% Functions (2/2)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3   // 3   //
4   // Distributed under the Boost Software License, Version 1.0. (See accompanying 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) 5   // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6   // 6   //
7   // Official repository: https://github.com/cppalliance/http 7   // Official repository: https://github.com/cppalliance/http
8   // 8   //
9   9  
10   #include "base64.hpp" 10   #include "base64.hpp"
11   11  
12   namespace boost { 12   namespace boost {
13   namespace http { 13   namespace http {
14   namespace bcrypt { 14   namespace bcrypt {
15   namespace detail { 15   namespace detail {
16   16  
17   namespace { 17   namespace {
18   18  
19   // bcrypt's non-standard base64 alphabet 19   // bcrypt's non-standard base64 alphabet
20   constexpr char encode_table[] = 20   constexpr char encode_table[] =
21   "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 21   "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
22   22  
23   // Decode table: maps ASCII char to 6-bit value, or 0xFF for invalid 23   // Decode table: maps ASCII char to 6-bit value, or 0xFF for invalid
24   constexpr std::uint8_t decode_table[256] = { 24   constexpr std::uint8_t decode_table[256] = {
25   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0-7 25   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 0-7
26   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8-15 26   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 8-15
27   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 16-23 27   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 16-23
28   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 24-31 28   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 24-31
29   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 32-39 29   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 32-39
30   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, // 40-47 (. /) 30   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, // 40-47 (. /)
31   0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, // 48-55 (0-7) 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) 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) 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) 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) 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) 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) 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) 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) 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) 40   0x33, 0x34, 0x35, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 120-127 (x-z)
41   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 41   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
42   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, 43   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
44   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, 45   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
46   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, 47   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
48   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, 49   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
50   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, 51   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
52   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, 53   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
54   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, 55   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
56   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 56   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
57   }; 57   };
58   58  
59   } // namespace 59   } // namespace
60   60  
61   std::size_t 61   std::size_t
HITCBC 62   43 base64_encode( 62   43 base64_encode(
63   char* dest, 63   char* dest,
64   std::uint8_t const* src, 64   std::uint8_t const* src,
65   std::size_t n) 65   std::size_t n)
66   { 66   {
HITCBC 67   43 char* out = dest; 67   43 char* out = dest;
68   68  
HITCBC 69   294 while (n >= 3) 69   294 while (n >= 3)
70   { 70   {
HITCBC 71   251 std::uint32_t v = 71   251 std::uint32_t v =
HITCBC 72   251 (static_cast<std::uint32_t>(src[0]) << 16) | 72   251 (static_cast<std::uint32_t>(src[0]) << 16) |
HITCBC 73   251 (static_cast<std::uint32_t>(src[1]) << 8) | 73   251 (static_cast<std::uint32_t>(src[1]) << 8) |
HITCBC 74   251 static_cast<std::uint32_t>(src[2]); 74   251 static_cast<std::uint32_t>(src[2]);
75   75  
HITCBC 76   251 *out++ = encode_table[(v >> 18) & 0x3F]; 76   251 *out++ = encode_table[(v >> 18) & 0x3F];
HITCBC 77   251 *out++ = encode_table[(v >> 12) & 0x3F]; 77   251 *out++ = encode_table[(v >> 12) & 0x3F];
HITCBC 78   251 *out++ = encode_table[(v >> 6) & 0x3F]; 78   251 *out++ = encode_table[(v >> 6) & 0x3F];
HITCBC 79   251 *out++ = encode_table[v & 0x3F]; 79   251 *out++ = encode_table[v & 0x3F];
80   80  
HITCBC 81   251 src += 3; 81   251 src += 3;
HITCBC 82   251 n -= 3; 82   251 n -= 3;
83   } 83   }
84   84  
HITCBC 85   43 if (n == 2) 85   43 if (n == 2)
86   { 86   {
HITCBC 87   18 std::uint32_t v = 87   18 std::uint32_t v =
HITCBC 88   18 (static_cast<std::uint32_t>(src[0]) << 16) | 88   18 (static_cast<std::uint32_t>(src[0]) << 16) |
HITCBC 89   18 (static_cast<std::uint32_t>(src[1]) << 8); 89   18 (static_cast<std::uint32_t>(src[1]) << 8);
90   90  
HITCBC 91   18 *out++ = encode_table[(v >> 18) & 0x3F]; 91   18 *out++ = encode_table[(v >> 18) & 0x3F];
HITCBC 92   18 *out++ = encode_table[(v >> 12) & 0x3F]; 92   18 *out++ = encode_table[(v >> 12) & 0x3F];
HITCBC 93   18 *out++ = encode_table[(v >> 6) & 0x3F]; 93   18 *out++ = encode_table[(v >> 6) & 0x3F];
94   } 94   }
HITCBC 95   25 else if (n == 1) 95   25 else if (n == 1)
96   { 96   {
HITCBC 97   25 std::uint32_t v = 97   25 std::uint32_t v =
HITCBC 98   25 static_cast<std::uint32_t>(src[0]) << 16; 98   25 static_cast<std::uint32_t>(src[0]) << 16;
99   99  
HITCBC 100   25 *out++ = encode_table[(v >> 18) & 0x3F]; 100   25 *out++ = encode_table[(v >> 18) & 0x3F];
HITCBC 101   25 *out++ = encode_table[(v >> 12) & 0x3F]; 101   25 *out++ = encode_table[(v >> 12) & 0x3F];
102   } 102   }
103   103  
HITCBC 104   43 return static_cast<std::size_t>(out - dest); 104   43 return static_cast<std::size_t>(out - dest);
105   } 105   }
106   106  
107   int 107   int
HITCBC 108   25 base64_decode( 108   25 base64_decode(
109   std::uint8_t* dest, 109   std::uint8_t* dest,
110   char const* src, 110   char const* src,
111   std::size_t n) 111   std::size_t n)
112   { 112   {
HITCBC 113   25 std::uint8_t* out = dest; 113   25 std::uint8_t* out = dest;
HITCBC 114   25 std::size_t i = 0; 114   25 std::size_t i = 0;
115   115  
HITCBC 116   170 while (i + 4 <= n) 116   170 while (i + 4 <= n)
117   { 117   {
HITCBC 118   145 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])]; 118   145 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])];
HITCBC 119   145 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])]; 119   145 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])];
HITCBC 120   145 std::uint8_t c = decode_table[static_cast<unsigned char>(src[i + 2])]; 120   145 std::uint8_t c = decode_table[static_cast<unsigned char>(src[i + 2])];
HITCBC 121   145 std::uint8_t d = decode_table[static_cast<unsigned char>(src[i + 3])]; 121   145 std::uint8_t d = decode_table[static_cast<unsigned char>(src[i + 3])];
122   122  
HITCBC 123   145 if ((a | b | c | d) & 0x80) 123   145 if ((a | b | c | d) & 0x80)
MISUBC 124   return -1; 124   return -1;
125   125  
HITCBC 126   145 std::uint32_t v = 126   145 std::uint32_t v =
HITCBC 127   145 (static_cast<std::uint32_t>(a) << 18) | 127   145 (static_cast<std::uint32_t>(a) << 18) |
HITCBC 128   145 (static_cast<std::uint32_t>(b) << 12) | 128   145 (static_cast<std::uint32_t>(b) << 12) |
HITCBC 129   145 (static_cast<std::uint32_t>(c) << 6) | 129   145 (static_cast<std::uint32_t>(c) << 6) |
HITCBC 130   145 static_cast<std::uint32_t>(d); 130   145 static_cast<std::uint32_t>(d);
131   131  
HITCBC 132   145 *out++ = static_cast<std::uint8_t>(v >> 16); 132   145 *out++ = static_cast<std::uint8_t>(v >> 16);
HITCBC 133   145 *out++ = static_cast<std::uint8_t>(v >> 8); 133   145 *out++ = static_cast<std::uint8_t>(v >> 8);
HITCBC 134   145 *out++ = static_cast<std::uint8_t>(v); 134   145 *out++ = static_cast<std::uint8_t>(v);
135   135  
HITCBC 136   145 i += 4; 136   145 i += 4;
137   } 137   }
138   138  
139   // Handle remaining 2 or 3 characters 139   // Handle remaining 2 or 3 characters
HITCBC 140   25 if (i + 3 == n) 140   25 if (i + 3 == n)
141   { 141   {
HITCBC 142   10 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])]; 142   10 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])];
HITCBC 143   10 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])]; 143   10 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])];
HITCBC 144   10 std::uint8_t c = decode_table[static_cast<unsigned char>(src[i + 2])]; 144   10 std::uint8_t c = decode_table[static_cast<unsigned char>(src[i + 2])];
145   145  
HITCBC 146   10 if ((a | b | c) & 0x80) 146   10 if ((a | b | c) & 0x80)
MISUBC 147   return -1; 147   return -1;
148   148  
HITCBC 149   10 std::uint32_t v = 149   10 std::uint32_t v =
HITCBC 150   10 (static_cast<std::uint32_t>(a) << 18) | 150   10 (static_cast<std::uint32_t>(a) << 18) |
HITCBC 151   10 (static_cast<std::uint32_t>(b) << 12) | 151   10 (static_cast<std::uint32_t>(b) << 12) |
HITCBC 152   10 (static_cast<std::uint32_t>(c) << 6); 152   10 (static_cast<std::uint32_t>(c) << 6);
153   153  
HITCBC 154   10 *out++ = static_cast<std::uint8_t>(v >> 16); 154   10 *out++ = static_cast<std::uint8_t>(v >> 16);
HITCBC 155   10 *out++ = static_cast<std::uint8_t>(v >> 8); 155   10 *out++ = static_cast<std::uint8_t>(v >> 8);
156   } 156   }
HITCBC 157   15 else if (i + 2 == n) 157   15 else if (i + 2 == n)
158   { 158   {
HITCBC 159   15 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])]; 159   15 std::uint8_t a = decode_table[static_cast<unsigned char>(src[i])];
HITCBC 160   15 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])]; 160   15 std::uint8_t b = decode_table[static_cast<unsigned char>(src[i + 1])];
161   161  
HITCBC 162   15 if ((a | b) & 0x80) 162   15 if ((a | b) & 0x80)
MISUBC 163   return -1; 163   return -1;
164   164  
HITCBC 165   15 std::uint32_t v = 165   15 std::uint32_t v =
HITCBC 166   15 (static_cast<std::uint32_t>(a) << 18) | 166   15 (static_cast<std::uint32_t>(a) << 18) |
HITCBC 167   15 (static_cast<std::uint32_t>(b) << 12); 167   15 (static_cast<std::uint32_t>(b) << 12);
168   168  
HITCBC 169   15 *out++ = static_cast<std::uint8_t>(v >> 16); 169   15 *out++ = static_cast<std::uint8_t>(v >> 16);
170   } 170   }
MISUBC 171   else if (i + 1 == n) 171   else if (i + 1 == n)
172   { 172   {
173   // Single trailing character is invalid 173   // Single trailing character is invalid
MISUBC 174   return -1; 174   return -1;
175   } 175   }
176   176  
HITCBC 177   25 return static_cast<int>(out - dest); 177   25 return static_cast<int>(out - dest);
178   } 178   }
179   179  
180   } // detail 180   } // detail
181   } // bcrypt 181   } // bcrypt
182   } // http 182   } // http
183   } // boost 183   } // boost