3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2013-2017 Nest Labs, Inc.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * Base-64 utility functions.
25 #ifndef __STDC_LIMIT_MACROS
26 #define __STDC_LIMIT_MACROS
35 // Convert a value in the range 0..63 to its equivalent base64 character.
36 // Return '=' for any value >= 64.
37 static char Base64ValToChar(uint8_t val)
40 return static_cast<char>('A' + val);
41 val = static_cast<uint8_t>(val - 26);
43 return static_cast<char>('a' + val);
44 val = static_cast<uint8_t>(val - 26);
46 return static_cast<char>('0' + val);
54 // Convert a base64 character to a value in the range 0..63, or UINT8_MAX if the character is invalid.
55 static uint8_t Base64CharToVal(uint8_t c)
61 // NOTE: c < 48 will fall through to return UINT8_MAX below.
62 c = static_cast<uint8_t>(c - 48);
64 return static_cast<uint8_t>(c + 52);
65 // NOTE: c < 17 here will fall through to return UINT8_MAX below.
66 c = static_cast<uint8_t>(c - 17);
69 // NOTE: c < 32 here will fall through to return UINT8_MAX below.
70 c = static_cast<uint8_t>(c - 32);
72 return static_cast<uint8_t>(c + 26);
76 // Convert a value in the range 0..63 to its equivalent base64url character (see RFC-4648, section 5).
77 // Return '=' for any value >= 64.
78 static char Base64URLValToChar(uint8_t val)
81 return static_cast<char>('A' + val);
82 val = static_cast<uint8_t>(val - 26);
84 return static_cast<char>('a' + val);
85 val = static_cast<uint8_t>(val - 26);
87 return static_cast<char>('0' + val);
95 // Convert a base64url character to a value in the range 0..63, or UINT8_MAX if the character is invalid.
96 static uint8_t Base64URLCharToVal(uint8_t c)
102 // NOTE: c < 48 will fall through to return UINT8_MAX below.
103 c = static_cast<uint8_t>(c - 48);
105 return static_cast<uint8_t>(c + 52);
106 // NOTE: c < 17 here will fall through to return UINT8_MAX below.
107 c = static_cast<uint8_t>(c - 17);
110 // NOTE: c < 32 here will fall through to return UINT8_MAX below.
111 c = static_cast<uint8_t>(c - 32);
113 return static_cast<uint8_t>(c + 26);
117 uint16_t Base64Encode(const uint8_t * in, uint16_t inLen, char * out, Base64ValToCharFunct valToCharFunct)
119 char * outStart = out;
123 uint8_t val1, val2, val3, val4;
125 val1 = static_cast<uint8_t>(*in >> 2);
126 val2 = (*in << 4) & 0x3F;
131 val2 = static_cast<uint8_t>(val2 | *in >> 4);
132 val3 = (*in << 2) & 0x3F;
137 val3 = static_cast<uint8_t>(val3 | *in >> 6);
146 val3 = val4 = UINT8_MAX;
148 *out++ = valToCharFunct(val1);
149 *out++ = valToCharFunct(val2);
150 *out++ = valToCharFunct(val3);
151 *out++ = valToCharFunct(val4);
154 return static_cast<uint16_t>(out - outStart);
157 uint16_t Base64Encode(const uint8_t * in, uint16_t inLen, char * out)
159 return Base64Encode(in, inLen, out, Base64ValToChar);
162 uint16_t Base64URLEncode(const uint8_t * in, uint16_t inLen, char * out)
164 return Base64Encode(in, inLen, out, Base64URLValToChar);
167 uint32_t Base64Encode32(const uint8_t * in, uint32_t inLen, char * out, Base64ValToCharFunct valToCharFunct)
171 // Maximum number of input bytes to convert to base-64 in a single call to Base64Encode.
172 // Number is the largest multiple of 3 bytes where the resulting number of base-64 characters
173 // fits within a uint16_t.
176 kMaxConvert = (UINT16_MAX / 4) * 3
181 uint16_t inChunkLen = (inLen > kMaxConvert) ? static_cast<uint16_t>(kMaxConvert) : static_cast<uint16_t>(inLen);
183 uint16_t outChunkLen = Base64Encode(in, inChunkLen, out, valToCharFunct);
186 outLen += outChunkLen;
198 uint32_t Base64Encode32(const uint8_t * in, uint32_t inLen, char * out)
200 return Base64Encode32(in, inLen, out, Base64ValToChar);
203 uint16_t Base64Decode(const char * in, uint16_t inLen, uint8_t * out, Base64CharToValFunct charToValFunct)
205 uint8_t * outStart = out;
207 // isgraph() returns false for space and ctrl chars
208 while (inLen > 0 && isgraph(*in))
213 uint8_t a = charToValFunct(static_cast<uint8_t>(*in++));
214 uint8_t b = charToValFunct(static_cast<uint8_t>(*in++));
215 inLen = static_cast<uint16_t>(inLen - 2);
217 if (a == UINT8_MAX || b == UINT8_MAX)
220 *out++ = static_cast<uint8_t>((a << 2) | (b >> 4));
222 if (inLen == 0 || *in == '=')
225 uint8_t c = charToValFunct(static_cast<uint8_t>(*in++));
231 *out++ = static_cast<uint8_t>((b << 4) | (c >> 2));
233 if (inLen == 0 || *in == '=')
236 uint8_t d = charToValFunct(static_cast<uint8_t>(*in++));
242 *out++ = static_cast<uint8_t>((c << 6) | d);
245 return static_cast<uint16_t>(out - outStart);
251 uint16_t Base64Decode(const char * in, uint16_t inLen, uint8_t * out)
253 return Base64Decode(in, inLen, out, Base64CharToVal);
256 uint16_t Base64URLDecode(const char * in, uint16_t inLen, uint8_t * out)
258 return Base64Decode(in, inLen, out, Base64URLCharToVal);
261 uint32_t Base64Decode32(const char * in, uint32_t inLen, uint8_t * out, Base64CharToValFunct charToValFunct)
265 // Maximum number of base-64 characters to convert in a single call to Base64Decode.
266 // Number is the largest multiple of 4 characters that fits in a uint16_t.
269 kMaxConvert = (UINT16_MAX / 4) * 4
274 uint16_t inChunkLen = (inLen > kMaxConvert) ? static_cast<uint16_t>(kMaxConvert) : static_cast<uint16_t>(inLen);
276 uint16_t outChunkLen = Base64Decode(in, inChunkLen, out, charToValFunct);
277 if (outChunkLen == UINT16_MAX)
281 outLen += outChunkLen;
293 uint32_t Base64Decode32(const char * in, uint32_t inLen, uint8_t * out)
295 return Base64Decode32(in, inLen, out, Base64CharToVal);
305 void TestBase64(const char * test, bool base64URL = false)
311 strcpy((char *) buf, test);
313 len = (base64URL) ? nl::Base64URLDecode((char *) buf, strlen((char *) buf), buf)
314 : nl::Base64Decode((char *) buf, strlen((char *) buf), buf);
315 printf("%s: ", test);
316 if (len != UINT16_MAX)
318 printf("(%d) ", len);
319 for (uint16_t i = 0; i < len; i++)
320 printf("%c", buf[i]);
322 len = (base64URL) ? nl::Base64URLEncode(buf, len, buf2) : nl::Base64Encode(buf, len, buf2);
323 printf(" (%d) ", len);
324 for (uint16_t i = 0; i < len; i++)
325 printf("%c", buf2[i]);
332 int main(int argc, char * argv[])
338 TestBase64("Zm9vYg==");
339 TestBase64("Zm9vYmE=");
340 TestBase64("Zm9vYmFy");
341 TestBase64("QmFzZTY0D+8xMjM0D/8=");
345 TestBase64("Zm9vYg");
346 TestBase64("Zm9vYmE");
348 TestBase64("QmFzZTY0D-8xMjM0D_8=", true);
352 TestBase64("Z\x019vYmFy");
354 TestBase64("Zm9vY;");
355 TestBase64("Zm9 vYg");