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-2020 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 1.9.8
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 encoding algorithm
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  **/
77 
78 void base64Encode(const void *input, size_t inputLen, char_t *output,
79  size_t *outputLen)
80 {
81  size_t n;
82  uint8_t a;
83  uint8_t b;
84  uint8_t c;
85  uint8_t d;
86  const uint8_t *p;
87 
88  //Point to the first byte of the input data
89  p = (const uint8_t *) input;
90 
91  //Divide the input stream into blocks of 3 bytes
92  n = inputLen / 3;
93 
94  //A full encoding quantum is always completed at the end of a quantity
95  if(inputLen == (n * 3 + 1))
96  {
97  //The final quantum of encoding input is exactly 8 bits
98  if(input != NULL && output != NULL)
99  {
100  //Read input data
101  a = (p[n * 3] & 0xFC) >> 2;
102  b = (p[n * 3] & 0x03) << 4;
103 
104  //The final unit of encoded output will be two characters followed
105  //by two "=" padding characters
106  output[n * 4] = base64EncTable[a];
107  output[n * 4 + 1] = base64EncTable[b];
108  output[n * 4 + 2] = '=';
109  output[n * 4 + 3] = '=';
110  output[n * 4 + 4] = '\0';
111  }
112 
113  //Length of the encoded string (excluding the terminating NULL)
114  if(outputLen != NULL)
115  {
116  *outputLen = n * 4 + 4;
117  }
118  }
119  else if(inputLen == (n * 3 + 2))
120  {
121  //The final quantum of encoding input is exactly 16 bits
122  if(input != NULL && output != NULL)
123  {
124  //Read input data
125  a = (p[n * 3] & 0xFC) >> 2;
126  b = ((p[n * 3] & 0x03) << 4) | ((p[n * 3 + 1] & 0xF0) >> 4);
127  c = (p[n * 3 + 1] & 0x0F) << 2;
128 
129  //The final unit of encoded output will be three characters followed
130  //by one "=" padding character
131  output[n * 4] = base64EncTable[a];
132  output[n * 4 + 1] = base64EncTable[b];
133  output[n * 4 + 2] = base64EncTable[c];
134  output[n * 4 + 3] = '=';
135  output[n * 4 + 4] = '\0';
136  }
137 
138  //Length of the encoded string (excluding the terminating NULL)
139  if(outputLen != NULL)
140  {
141  *outputLen = n * 4 + 4;
142  }
143  }
144  else
145  {
146  //The final quantum of encoding input is an integral multiple of 24 bits
147  if(output != NULL)
148  {
149  //The final unit of encoded output will be an integral multiple of 4
150  //characters with no "=" padding
151  output[n * 4] = '\0';
152  }
153 
154  //Length of the encoded string (excluding the terminating NULL)
155  if(outputLen != NULL)
156  {
157  *outputLen = n * 4;
158  }
159  }
160 
161  //If the output parameter is NULL, then the function calculates the
162  //length of the resulting Base64 string without copying any data
163  if(input != NULL && output != NULL)
164  {
165  //The input data is processed block by block
166  while(n-- > 0)
167  {
168  //Read input data
169  a = (p[n * 3] & 0xFC) >> 2;
170  b = ((p[n * 3] & 0x03) << 4) | ((p[n * 3 + 1] & 0xF0) >> 4);
171  c = ((p[n * 3 + 1] & 0x0F) << 2) | ((p[n * 3 + 2] & 0xC0) >> 6);
172  d = p[n * 3 + 2] & 0x3F;
173 
174  //Map each 3-byte block to 4 printable characters using the Base64
175  //character set
176  output[n * 4] = base64EncTable[a];
177  output[n * 4 + 1] = base64EncTable[b];
178  output[n * 4 + 2] = base64EncTable[c];
179  output[n * 4 + 3] = base64EncTable[d];
180  }
181  }
182 }
183 
184 
185 /**
186  * @brief Base64 decoding algorithm
187  * @param[in] input Base64-encoded string
188  * @param[in] inputLen Length of the encoded string
189  * @param[out] output Resulting decoded data
190  * @param[out] outputLen Length of the decoded data
191  * @return Error code
192  **/
193 
194 error_t base64Decode(const char_t *input, size_t inputLen, void *output,
195  size_t *outputLen)
196 {
197  error_t error;
198  uint32_t value;
199  uint_t c;
200  size_t i;
201  size_t j;
202  size_t n;
203  size_t padLen;
204  uint8_t *p;
205 
206  //Check parameters
207  if(input == NULL && inputLen != 0)
209  if(outputLen == NULL)
211 
212  //Initialize status code
213  error = NO_ERROR;
214 
215  //Point to the buffer where to write the decoded data
216  p = (uint8_t *) output;
217 
218  //Initialize variables
219  j = 0;
220  n = 0;
221  value = 0;
222  padLen = 0;
223 
224  //Process the Base64-encoded string
225  for(i = 0; i < inputLen && !error; i++)
226  {
227  //Get current character
228  c = (uint_t) input[i];
229 
230  //Check the value of the current character
231  if(c == '\r' || c == '\n')
232  {
233  //CR and LF characters should be ignored
234  }
235  else if(c == '=')
236  {
237  //Increment the number of pad characters
238  padLen++;
239  }
240  else if(c < 128 && base64DecTable[c] < 64 && padLen == 0)
241  {
242  //Decode the current character
243  value = (value << 6) | base64DecTable[c];
244 
245  //Divide the input stream into blocks of 4 characters
246  if(++j == 4)
247  {
248  //Map each 4-character block to 3 bytes
249  if(p != NULL)
250  {
251  p[n] = (value >> 16) & 0xFF;
252  p[n + 1] = (value >> 8) & 0xFF;
253  p[n + 2] = value & 0xFF;
254  }
255 
256  //Adjust the length of the decoded data
257  n += 3;
258 
259  //Decode next block
260  j = 0;
261  value = 0;
262  }
263  }
264  else
265  {
266  //Implementations must reject the encoded data if it contains
267  //characters outside the base alphabet (refer to RFC 4648,
268  //section 3.3)
269  error = ERROR_INVALID_CHARACTER;
270  }
271  }
272 
273  //Check status code
274  if(!error)
275  {
276  //Check the number of pad characters
277  if(padLen == 0 && j == 0)
278  {
279  //No pad characters in this case
280  }
281  else if(padLen == 1 && j == 3)
282  {
283  //The "=" sequence indicates that the last block contains only 2 bytes
284  if(p != NULL)
285  {
286  //Decode the last two bytes
287  p[n] = (value >> 10) & 0xFF;
288  p[n + 1] = (value >> 2) & 0xFF;
289  }
290 
291  //Adjust the length of the decoded data
292  n += 2;
293  }
294  else if(padLen == 2 && j == 2)
295  {
296  //The "==" sequence indicates that the last block contains only 1 byte
297  if(p != NULL)
298  {
299  //Decode the last byte
300  p[n] = (value >> 4) & 0xFF;
301  }
302 
303  //Adjust the length of the decoded data
304  n++;
305  //Skip trailing pad characters
306  i++;
307  }
308  else
309  {
310  //The length of the input string must be a multiple of 4
311  error = ERROR_INVALID_LENGTH;
312  }
313  }
314 
315  //Total number of bytes that have been written
316  *outputLen = n;
317 
318  //Return status code
319  return error;
320 }
321 
322 #endif
uint8_t a
Definition: ndp.h:410
uint8_t p
Definition: ndp.h:298
void base64Encode(const void *input, size_t inputLen, char_t *output, size_t *outputLen)
Base64 encoding algorithm.
Definition: base64.c:78
error_t base64Decode(const char_t *input, size_t inputLen, void *output, size_t *outputLen)
Base64 decoding algorithm.
Definition: base64.c:194
Invalid parameter.
Definition: error.h:47
error_t
Error codes.
Definition: error.h:42
uint8_t value[]
Definition: tcp.h:332
General definitions for cryptographic algorithms.
Base64 encoding scheme.
uint8_t b[6]
Definition: ethernet.h:179
char char_t
Definition: compiler_port.h:43
uint8_t n
unsigned int uint_t
Definition: compiler_port.h:45
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:513