diff options
-rw-r--r-- | src/include/b64_decode.h | 35 | ||||
-rw-r--r-- | src/lib/Makefile.inc | 1 | ||||
-rw-r--r-- | src/lib/b64_decode.c | 146 |
3 files changed, 182 insertions, 0 deletions
diff --git a/src/include/b64_decode.h b/src/include/b64_decode.h new file mode 100644 index 0000000000..b52719671e --- /dev/null +++ b/src/include/b64_decode.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2015 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __INCLUDE_B64_DECODE_H__ +#define __INCLUDE_B64_DECODE_H__ + +#include <stddef.h> +#include <stdint.h> + +/* + * A function to convert a buffer of base64 format data into its source. + * + * The user provides output buffer of the size guaranteed to fit the result. + * + * Returns the size of the decoded data or zero if invalid charactes were + * encountered in the input buffer. + */ +size_t b64_decode(const uint8_t *input_data, + size_t input_length, + uint8_t *output_data); + +/* A macro to derive decoded size of a base64 encoded blob. */ +#define B64_DECODED_SIZE(encoded_size) (((encoded_size) * 3)/4) + +#endif diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index d4f0452b6f..19ff2b291a 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -97,6 +97,7 @@ ramstage-$(CONFIG_COOP_MULTITASKING) += thread.c ramstage-$(CONFIG_TIMER_QUEUE) += timer_queue.c ramstage-$(CONFIG_GENERIC_GPIO_LIB) += gpio.c ramstage-$(CONFIG_GENERIC_UDELAY) += timer.c +ramstage-y += b64_decode.c romstage-y += cbmem_common.c dynamic_cbmem.c ramstage-y += cbmem_common.c dynamic_cbmem.c diff --git a/src/lib/b64_decode.c b/src/lib/b64_decode.c new file mode 100644 index 0000000000..85f43c0747 --- /dev/null +++ b/src/lib/b64_decode.c @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2015 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <b64_decode.h> +#include <console/console.h> + +/* + * Translation Table to decode base64 ASCII stream into binary. Borrowed from + * + * http://base64.sourceforge.net/b64.c. + * + */ +static const char cd64[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMN" + "OPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; + +struct buffer_descriptor { + const uint8_t *input_buffer; + size_t data_size; + size_t input_index; +}; + +#define isalnum(c) ((((c) >= 'a') && ((c) <= 'z')) || \ + (((c) >= 'A') && ((c) <= 'Z')) || \ + (((c) >= '0') && ((c) <= '9'))) + +/* + * On each invocation this function returns the next valid base64 character + * from the encoded message, ignoring padding and line breaks. + * + * Once all input is consumed, 0 is returned on all following invocations. In + * case any other than expected characters is found in the encoded message, -1 + * is returned for error. + */ +static int get_next_char(struct buffer_descriptor *bd) +{ + uint8_t c; + + /* + * The canonical base64 encoded messages include the following + * characters: + * - '0..9A..Za..z+/' to represent 64 values + * - '=' for padding + * - '<CR><LF>' to split the message into lines. + */ + while (bd->input_index < bd->data_size) { + c = bd->input_buffer[bd->input_index++]; + + switch (c) { + case '=': + case 0xa: + case 0xd: + continue; + + default: + break; + } + + if (!isalnum(c) && (c != '+') && (c != '/')) + return -1; + + return c; + } + + return 0; +} + +/* +** decode +** +** decode a base64 encoded stream discarding padding and line breaks. +*/ +size_t b64_decode(const uint8_t *input_data, + size_t input_length, + uint8_t *output_data) +{ + struct buffer_descriptor bd; + unsigned interim = 0; + size_t output_size = 0; + /* count of processed input bits, modulo log2(64) */ + unsigned bit_count = 0; + + /* + * Keep the context on the stack to make things easier if this needs + * to run with CAR. + */ + bd.input_buffer = input_data; + bd.data_size = input_length; + bd.input_index = 0; + + while (1) { /* Until input is exausted. */ + int v = get_next_char(&bd); + + if (v < 0) { + printk(BIOS_ERR, + "Incompatible character at offset %zd.\n", + bd.input_index); + return 0; + } + + if (!v) + break; + + /* + * v is guaranteed to be in the proper range for cd64, the + * result is a 6 bit number. + */ + v = cd64[v - 43] - 62; + + if (bit_count >= 2) { + /* + * Once 6 more bits are added to the output, there is + * going to be at least a full byte. + * + * 'remaining_bits' is the exact number of bits which + * need to be added to the output to have another full + * byte ready. + */ + int remaining_bits = 8 - bit_count; + + interim <<= remaining_bits; + interim |= v >> (6 - remaining_bits); + + /* Pass the new full byte to the output. */ + output_data[output_size++] = interim & 0xff; + + interim = v; + bit_count -= 2; + } else { + interim <<= 6; + interim |= v; + bit_count += 6; + } + } + + return output_size; +} |