[coreboot-gerrit] New patch to review for coreboot: 4d8ab43 lib: add base64 decoder

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Tue Apr 21 10:45:26 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/9892

-gerrit

commit 4d8ab43bc59daa7c7b83225052deeec733c461d1
Author: Vadim Bendebury <vbendeb at chromium.org>
Date:   Fri Mar 27 16:08:04 2015 -0700

    lib: add base64 decoder
    
    It became necessary to decode base64 data retrieved from VPD and
    convert it into binary for inclusion in the device tree.
    
    The patch introduces the decoder function based on the description
    found in http://en.wikipedia.org/wiki/Base64.
    
    An open source implementation from http://base64.sourceforge.net was
    considered, in the end the only thing borrowed from it is the table to
    translate base64 ascii characters into numbers in 0..63 range.
    
    BRANCH=none
    BUG=chromium:450169
    
    TEST=created a test harness generating random contents of random size
         (in 8 to 32766 bytes range), then converting the contents into
         base64 using the Linux utility, and then converting it back to
         binary using this function and comparing the results.
    
         It succeeded 1700 iterations before it was stopped.
    
    Change-Id: I502f2c9494c99ba95ece37a7220c0c70c4755be2
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: 6609f76e1559d3cdd402276055c99e0de7da27c8
    Original-Change-Id: I5ed68af3a4daead50c44ae0f0c63d836f4b66851
    Original-Signed-off-by: Vadim Bendebury <vbendeb at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/262945
    Original-Reviewed-by: Aaron Durbin <adurbin at chromium.org>
---
 src/include/b64_decode.h |  35 ++++++++++++
 src/lib/Makefile.inc     |   1 +
 src/lib/b64_decode.c     | 146 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 182 insertions(+)

diff --git a/src/include/b64_decode.h b/src/include/b64_decode.h
new file mode 100644
index 0000000..b527196
--- /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 d4f0452..19ff2b2 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 0000000..85f43c0
--- /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;
+}



More information about the coreboot-gerrit mailing list