base64.c
Go to the documentation of this file.
1 /**
2  * @file base64.c
3  * @brief Base64 encoding scheme
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * Base64 is a encoding scheme that represents binary data in an ASCII string
30  * format by translating it into a radix-64 representation. Refer to RFC 4648
31  * for more details
32  *
33  * @author Oryx Embedded SARL (www.oryx-embedded.com)
34  * @version 2.4.4
35  **/
36 
37 //Switch to the appropriate trace level
38 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
39 
40 //Dependencies
41 #include "core/crypto.h"
42 #include "encoding/base64.h"
43 
44 //Check crypto library configuration
45 #if (BASE64_SUPPORT == ENABLED)
46 
47 //Base64 encoding table
48 static const char_t base64EncTable[64] =
49 {
50  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
51  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
52  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
53  'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
54 };
55 
56 //Base64 decoding table
57 static const uint8_t base64DecTable[128] =
58 {
59  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
60  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
61  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F,
62  0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
63  0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
64  0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
65  0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
66  0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
67 };
68 
69 
70 /**
71  * @brief Base64 multiline encoding
72  * @param[in] input Input data to encode
73  * @param[in] inputLen Length of the data to encode
74  * @param[out] output NULL-terminated string encoded with Base64 algorithm
75  * @param[out] outputLen Length of the encoded string (optional parameter)
76  * @param[in] lineWidth Number of characters per line
77  **/
78 
79 void base64EncodeMultiline(const void *input, size_t inputLen, char_t *output,
80  size_t *outputLen, size_t lineWidth)
81 {
82  size_t i;
83  size_t j;
84  size_t n;
85  size_t length;
86 
87  //Encode the input data using Base64
88  base64Encode(input, inputLen, output, &length);
89 
90  //Calculate the number of CRLF sequences to insert
91  if(length > 0 && lineWidth > 0)
92  {
93  n = (length - 1) / lineWidth;
94  }
95  else
96  {
97  n = 0;
98  }
99 
100  //If the output parameter is NULL, then the function calculates the length
101  //of the multiline string without copying any data
102  if(n != 0 && input != NULL && output != NULL)
103  {
104  //Initialize indexes
105  i = length;
106  j = length + 2 * n;
107 
108  //Properly terminate the string with a NULL character
109  output[j] = '\0';
110 
111  //Split the Base64 string into multiple lines
112  while(i > 0 && j > 0)
113  {
114  //Copy current character
115  output[--j] = output[--i];
116 
117  //Insert a CRLF sequence when necessary to limit the length of the line
118  if(j >= 2 && (i % lineWidth) == 0)
119  {
120  output[--j] = '\n';
121  output[--j] = '\r';
122  }
123  }
124  }
125 
126  //Length of the encoded string (excluding the terminating NULL)
127  if(outputLen != NULL)
128  {
129  *outputLen = length + 2 * n;
130  }
131 }
132 
133 
134 /**
135  * @brief Base64 encoding algorithm
136  * @param[in] input Input data to encode
137  * @param[in] inputLen Length of the data to encode
138  * @param[out] output NULL-terminated string encoded with Base64 algorithm
139  * @param[out] outputLen Length of the encoded string (optional parameter)
140  **/
141 
142 void base64Encode(const void *input, size_t inputLen, char_t *output,
143  size_t *outputLen)
144 {
145  size_t n;
146  uint8_t a;
147  uint8_t b;
148  uint8_t c;
149  uint8_t d;
150  const uint8_t *p;
151 
152  //Point to the first byte of the input data
153  p = (const uint8_t *) input;
154 
155  //Divide the input stream into blocks of 3 bytes
156  n = inputLen / 3;
157 
158  //A full encoding quantum is always completed at the end of a quantity
159  if(inputLen == (n * 3 + 1))
160  {
161  //The final quantum of encoding input is exactly 8 bits
162  if(input != NULL && output != NULL)
163  {
164  //Read input data
165  a = (p[n * 3] & 0xFC) >> 2;
166  b = (p[n * 3] & 0x03) << 4;
167 
168  //The final unit of encoded output will be two characters followed
169  //by two "=" padding characters
170  output[n * 4] = base64EncTable[a];
171  output[n * 4 + 1] = base64EncTable[b];
172  output[n * 4 + 2] = '=';
173  output[n * 4 + 3] = '=';
174  output[n * 4 + 4] = '\0';
175  }
176 
177  //Length of the encoded string (excluding the terminating NULL)
178  if(outputLen != NULL)
179  {
180  *outputLen = n * 4 + 4;
181  }
182  }
183  else if(inputLen == (n * 3 + 2))
184  {
185  //The final quantum of encoding input is exactly 16 bits
186  if(input != NULL && output != NULL)
187  {
188  //Read input data
189  a = (p[n * 3] & 0xFC) >> 2;
190  b = ((p[n * 3] & 0x03) << 4) | ((p[n * 3 + 1] & 0xF0) >> 4);
191  c = (p[n * 3 + 1] & 0x0F) << 2;
192 
193  //The final unit of encoded output will be three characters followed
194  //by one "=" padding character
195  output[n * 4] = base64EncTable[a];
196  output[n * 4 + 1] = base64EncTable[b];
197  output[n * 4 + 2] = base64EncTable[c];
198  output[n * 4 + 3] = '=';
199  output[n * 4 + 4] = '\0';
200  }
201 
202  //Length of the encoded string (excluding the terminating NULL)
203  if(outputLen != NULL)
204  {
205  *outputLen = n * 4 + 4;
206  }
207  }
208  else
209  {
210  //The final quantum of encoding input is an integral multiple of 24 bits
211  if(output != NULL)
212  {
213  //The final unit of encoded output will be an integral multiple of 4
214  //characters with no "=" padding
215  output[n * 4] = '\0';
216  }
217 
218  //Length of the encoded string (excluding the terminating NULL)
219  if(outputLen != NULL)
220  {
221  *outputLen = n * 4;
222  }
223  }
224 
225  //If the output parameter is NULL, then the function calculates the length
226  //of the resulting Base64 string without copying any data
227  if(input != NULL && output != NULL)
228  {
229  //The input data is processed block by block
230  while(n-- > 0)
231  {
232  //Read input data
233  a = (p[n * 3] & 0xFC) >> 2;
234  b = ((p[n * 3] & 0x03) << 4) | ((p[n * 3 + 1] & 0xF0) >> 4);
235  c = ((p[n * 3 + 1] & 0x0F) << 2) | ((p[n * 3 + 2] & 0xC0) >> 6);
236  d = p[n * 3 + 2] & 0x3F;
237 
238  //Map each 3-byte block to 4 printable characters using the Base64
239  //character set
240  output[n * 4] = base64EncTable[a];
241  output[n * 4 + 1] = base64EncTable[b];
242  output[n * 4 + 2] = base64EncTable[c];
243  output[n * 4 + 3] = base64EncTable[d];
244  }
245  }
246 }
247 
248 
249 /**
250  * @brief Base64 decoding algorithm
251  * @param[in] input Base64-encoded string
252  * @param[in] inputLen Length of the encoded string
253  * @param[out] output Resulting decoded data
254  * @param[out] outputLen Length of the decoded data
255  * @return Error code
256  **/
257 
258 error_t base64Decode(const char_t *input, size_t inputLen, void *output,
259  size_t *outputLen)
260 {
261  error_t error;
262  uint32_t value;
263  uint_t c;
264  size_t i;
265  size_t j;
266  size_t n;
267  size_t padLen;
268  uint8_t *p;
269 
270  //Check parameters
271  if(input == NULL && inputLen != 0)
273  if(outputLen == NULL)
275 
276  //Initialize status code
277  error = NO_ERROR;
278 
279  //Point to the buffer where to write the decoded data
280  p = (uint8_t *) output;
281 
282  //Initialize variables
283  j = 0;
284  n = 0;
285  value = 0;
286  padLen = 0;
287 
288  //Process the Base64-encoded string
289  for(i = 0; i < inputLen && !error; i++)
290  {
291  //Get current character
292  c = (uint_t) input[i];
293 
294  //Check the value of the current character
295  if(c == '\r' || c == '\n')
296  {
297  //CR and LF characters should be ignored
298  }
299  else if(c == '=')
300  {
301  //Increment the number of pad characters
302  padLen++;
303  }
304  else if(c < 128 && base64DecTable[c] < 64 && padLen == 0)
305  {
306  //Decode the current character
307  value = (value << 6) | base64DecTable[c];
308 
309  //Divide the input stream into blocks of 4 characters
310  if(++j == 4)
311  {
312  //Map each 4-character block to 3 bytes
313  if(p != NULL)
314  {
315  p[n] = (value >> 16) & 0xFF;
316  p[n + 1] = (value >> 8) & 0xFF;
317  p[n + 2] = value & 0xFF;
318  }
319 
320  //Adjust the length of the decoded data
321  n += 3;
322 
323  //Decode next block
324  j = 0;
325  value = 0;
326  }
327  }
328  else
329  {
330  //Implementations must reject the encoded data if it contains
331  //characters outside the base alphabet (refer to RFC 4648,
332  //section 3.3)
333  error = ERROR_INVALID_CHARACTER;
334  }
335  }
336 
337  //Check status code
338  if(!error)
339  {
340  //Check the number of pad characters
341  if(padLen == 0 && j == 0)
342  {
343  //No pad characters in this case
344  }
345  else if(padLen == 1 && j == 3)
346  {
347  //The "=" sequence indicates that the last block contains only 2 bytes
348  if(p != NULL)
349  {
350  //Decode the last two bytes
351  p[n] = (value >> 10) & 0xFF;
352  p[n + 1] = (value >> 2) & 0xFF;
353  }
354 
355  //Adjust the length of the decoded data
356  n += 2;
357  }
358  else if(padLen == 2 && j == 2)
359  {
360  //The "==" sequence indicates that the last block contains only 1 byte
361  if(p != NULL)
362  {
363  //Decode the last byte
364  p[n] = (value >> 4) & 0xFF;
365  }
366 
367  //Adjust the length of the decoded data
368  n++;
369  //Skip trailing pad characters
370  i++;
371  }
372  else
373  {
374  //The length of the input string must be a multiple of 4
375  error = ERROR_INVALID_LENGTH;
376  }
377  }
378 
379  //Total number of bytes that have been written
380  *outputLen = n;
381 
382  //Return status code
383  return error;
384 }
385 
386 #endif
uint8_t b
Definition: nbns_common.h:104
uint8_t a
Definition: ndp.h:411
uint8_t p
Definition: ndp.h:300
void base64Encode(const void *input, size_t inputLen, char_t *output, size_t *outputLen)
Base64 encoding algorithm.
Definition: base64.c:142
void base64EncodeMultiline(const void *input, size_t inputLen, char_t *output, size_t *outputLen, size_t lineWidth)
Base64 multiline encoding.
Definition: base64.c:79
error_t base64Decode(const char_t *input, size_t inputLen, void *output, size_t *outputLen)
Base64 decoding algorithm.
Definition: base64.c:258
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_LENGTH
Definition: error.h:111
General definitions for cryptographic algorithms.
Base64 encoding scheme.
uint8_t length
Definition: tcp.h:368
@ ERROR_INVALID_CHARACTER
Definition: error.h:110
char char_t
Definition: compiler_port.h:48
uint8_t n
uint8_t value[]
Definition: tcp.h:369
unsigned int uint_t
Definition: compiler_port.h:50
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514