lib: Add base64 library

Since base64 is such a simple and commonly used feature it makes no
sense to build the whole of mbedTLS for it. Instead take the
implementation that comes with mbedTLS and import it as a native library
outside of ext/ for all to use directly.

Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
This commit is contained in:
Carles Cufi 2018-03-22 20:05:26 +01:00 committed by Anas Nashif
commit fb50e81dfd
5 changed files with 303 additions and 0 deletions

79
include/base64.h Normal file
View file

@ -0,0 +1,79 @@
/**
*
* RFC 1521 base64 encoding/decoding
*
* Copyright (C) 2018, Nordic Semiconductor ASA
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef __BASE64_H__
#define __BASE64_H__
#include <stddef.h>
#include <zephyr/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Encode a buffer into base64 format
*
* @param dst destination buffer
* @param dlen size of the destination buffer
* @param olen number of bytes written
* @param src source buffer
* @param slen amount of data to be encoded
*
* @return 0 if successful, or -ENOMEM if the buffer is too small.
* *olen is always updated to reflect the amount
* of data that has (or would have) been written.
* If that length cannot be represented, then no data is
* written to the buffer and *olen is set to the maximum
* length representable as a size_t.
*
* @note Call this function with dlen = 0 to obtain the
* required buffer size in *olen
*/
int base64_encode(u8_t *dst, size_t dlen, size_t *olen, const u8_t *src,
size_t slen);
/**
* @brief Decode a base64-formatted buffer
*
* @param dst destination buffer (can be NULL for checking size)
* @param dlen size of the destination buffer
* @param olen number of bytes written
* @param src source buffer
* @param slen amount of data to be decoded
*
* @return 0 if successful, -ENOMEM, or -EINVAL if the input data is
* not correct. *olen is always updated to reflect the amount
* of data that has (or would have) been written.
*
* @note Call this function with *dst = NULL or dlen = 0 to obtain
* the required buffer size in *olen
*/
int base64_decode(u8_t *dst, size_t dlen, size_t *olen, const u8_t *src,
size_t slen);
#ifdef __cplusplus
}
#endif
#endif /* __BASE64_H__ */

View file

@ -4,3 +4,4 @@ if(NOT CONFIG_NATIVE_APPLICATION)
add_subdirectory(libc)
endif()
add_subdirectory_if_kconfig(ring_buffer)
add_subdirectory_if_kconfig(base64)

View file

@ -24,4 +24,11 @@ config RING_BUFFER
Enable usage of ring buffers. This is similar to kernel FIFOs but ring
buffers manage their own buffer memory and can store arbitrary data.
For optimal performance, use buffer sizes that are a power of 2.
config BASE64
bool
prompt "Enable base64 encoding and decoding"
default n
help
Enable base64 encoding and decoding functionality
endmenu

View file

@ -0,0 +1 @@
zephyr_sources(base64.c)

215
lib/base64/base64.c Normal file
View file

@ -0,0 +1,215 @@
/*
* RFC 1521 base64 encoding/decoding
*
* Copyright (C) 2018, Nordic Semiconductor ASA
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#include <stdint.h>
#include <errno.h>
#include <base64.h>
static const u8_t base64_enc_map[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', '/'
};
static const u8_t base64_dec_map[128] = {
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 127, 127, 127, 127, 127
};
#define BASE64_SIZE_T_MAX ((size_t) -1) /* SIZE_T_MAX is not standard */
/*
* Encode a buffer into base64 format
*/
int base64_encode(u8_t *dst, size_t dlen, size_t *olen, const u8_t *src,
size_t slen)
{
size_t i, n;
int C1, C2, C3;
u8_t *p;
if (slen == 0) {
*olen = 0;
return 0;
}
n = slen / 3 + (slen % 3 != 0);
if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
*olen = BASE64_SIZE_T_MAX;
return -ENOMEM;
}
n *= 4;
if ((dlen < n + 1) || (!dst)) {
*olen = n + 1;
return -ENOMEM;
}
n = (slen / 3) * 3;
for (i = 0, p = dst; i < n; i += 3) {
C1 = *src++;
C2 = *src++;
C3 = *src++;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
*p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
*p++ = base64_enc_map[C3 & 0x3F];
}
if (i < slen) {
C1 = *src++;
C2 = ((i + 1) < slen) ? *src++ : 0;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
if ((i + 1) < slen) {
*p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
} else {
*p++ = '=';
}
*p++ = '=';
}
*olen = p - dst;
*p = 0;
return 0;
}
/*
* Decode a base64-formatted buffer
*/
int base64_decode(u8_t *dst, size_t dlen, size_t *olen, const u8_t *src,
size_t slen)
{
size_t i, n;
u32_t j, x;
u8_t *p;
/* First pass: check for validity and get output length */
for (i = n = j = 0; i < slen; i++) {
/* Skip spaces before checking for EOL */
x = 0;
while (i < slen && src[i] == ' ') {
++i;
++x;
}
/* Spaces at end of buffer are OK */
if (i == slen) {
break;
}
if ((slen - i) >= 2 && src[i] == '\r' && src[i + 1] == '\n') {
continue;
}
if (src[i] == '\n') {
continue;
}
/* Space inside a line is an error */
if (x != 0) {
return -EINVAL;
}
if (src[i] == '=' && ++j > 2) {
return -EINVAL;
}
if (src[i] > 127 || base64_dec_map[src[i]] == 127) {
return -EINVAL;
}
if (base64_dec_map[src[i]] < 64 && j != 0) {
return -EINVAL;
}
n++;
}
if (n == 0) {
*olen = 0;
return 0;
}
/* The following expression is to calculate the following formula
* without risk of integer overflow in n:
* n = ( ( n * 6 ) + 7 ) >> 3;
*/
n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
n -= j;
if (dst == NULL || dlen < n) {
*olen = n;
return -ENOMEM;
}
for (j = 3, n = x = 0, p = dst; i > 0; i--, src++) {
if (*src == '\r' || *src == '\n' || *src == ' ') {
continue;
}
j -= (base64_dec_map[*src] == 64);
x = (x << 6) | (base64_dec_map[*src] & 0x3F);
if (++n == 4) {
n = 0;
if (j > 0) {
*p++ = (unsigned char)(x >> 16);
}
if (j > 1) {
*p++ = (unsigned char)(x >> 8);
}
if (j > 2) {
*p++ = (unsigned char)(x);
}
}
}
*olen = p - dst;
return 0;
}