2015-03-28 00:08:04 +01:00
|
|
|
/*
|
|
|
|
* 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;
|
2017-03-09 01:34:12 +01:00
|
|
|
unsigned int interim = 0;
|
2015-03-28 00:08:04 +01:00
|
|
|
size_t output_size = 0;
|
|
|
|
/* count of processed input bits, modulo log2(64) */
|
2017-03-09 01:34:12 +01:00
|
|
|
unsigned int bit_count = 0;
|
2015-03-28 00:08:04 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|