in stuffer/s2n_stuffer_base64.c [75:146]
int s2n_stuffer_read_base64(struct s2n_stuffer *stuffer, struct s2n_stuffer *out)
{
POSIX_PRECONDITION(s2n_stuffer_validate(stuffer));
POSIX_PRECONDITION(s2n_stuffer_validate(out));
int bytes_this_round = 3;
s2n_stack_blob(o, 4, 4);
do {
if (s2n_stuffer_data_available(stuffer) < o.size) {
break;
}
POSIX_GUARD(s2n_stuffer_read(stuffer, &o));
uint8_t value1 = b64_inverse[o.data[0]];
uint8_t value2 = b64_inverse[o.data[1]];
uint8_t value3 = b64_inverse[o.data[2]];
uint8_t value4 = b64_inverse[o.data[3]];
/* We assume the entire thing is base64 data, thus, terminate cleanly if we encounter a non-base64 character */
if (value1 == 255) {
/* Undo the read */
stuffer->read_cursor -= o.size;
POSIX_BAIL(S2N_ERR_INVALID_BASE64);
}
/* The first two characters can never be '=' and in general
* everything has to be a valid character.
*/
POSIX_ENSURE(!(value1 == 64 || value2 == 64 || value2 == 255 || value3 == 255 || value4 == 255), S2N_ERR_INVALID_BASE64);
if (o.data[2] == '=') {
/* If there is only one output byte, then the second value
* should have none of its bottom four bits set.
*/
POSIX_ENSURE(!(o.data[3] != '=' || value2 & 0x0f), S2N_ERR_INVALID_BASE64);
bytes_this_round = 1;
value3 = 0;
value4 = 0;
} else if (o.data[3] == '=') {
/* The last two bits of the final value should be unset */
POSIX_ENSURE(!(value3 & 0x03), S2N_ERR_INVALID_BASE64);
bytes_this_round = 2;
value4 = 0;
}
/* Advance by bytes_this_round, and then fill in the data */
POSIX_GUARD(s2n_stuffer_skip_write(out, bytes_this_round));
uint8_t *ptr = out->blob.data + out->write_cursor - bytes_this_round;
/* value1 maps to the first 6 bits of the first data byte */
/* value2's top two bits are the rest */
*ptr = ((value1 << 2) & 0xfc) | ((value2 >> 4) & 0x03);
if (bytes_this_round > 1) {
/* Put the next four bits in the second data byte */
/* Put the next four bits in the third data byte */
ptr++;
*ptr = ((value2 << 4) & 0xf0) | ((value3 >> 2) & 0x0f);
}
if (bytes_this_round > 2) {
/* Put the next two bits in the third data byte */
/* Put the next six bits in the fourth data byte */
ptr++;
*ptr = ((value3 << 6) & 0xc0) | (value4 & 0x3f);
}
} while (bytes_this_round == 3);
return S2N_SUCCESS;
}