1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

sys/base64: Implement Base 64 Encoding with URL Safe Alphabet

RFC4648 specifies an alternate alphabet for base64 encoding / decoding
where '+' and '/' are exchanged for '-' and '-' to make the resulting
string safe to use in filenames and URLs.

This adds a base64url_encode() function that uses the alternate alphabet.

The base64_decode() function is extended to accept both alphabets.
This commit is contained in:
Benjamin Valentin 2020-03-30 15:09:02 +02:00 committed by Benjamin Valentin
parent e738508308
commit fc89531c61
4 changed files with 77 additions and 7 deletions

View File

@ -42,6 +42,10 @@ ifneq (,$(filter auto_init_saul,$(USEMODULE)))
USEMODULE += saul_init_devs
endif
ifneq (,$(filter base64url,$(USEMODULE)))
USEMODULE += base64
endif
ifneq (,$(filter csma_sender,$(USEMODULE)))
USEMODULE += random
USEMODULE += xtimer

View File

@ -1,5 +1,6 @@
PSEUDOMODULES += at_urc
PSEUDOMODULES += at24c%
PSEUDOMODULES += base64url
PSEUDOMODULES += can_mbox
PSEUDOMODULES += can_pm
PSEUDOMODULES += can_raw

View File

@ -18,26 +18,42 @@
*
*/
#include <stdbool.h>
#include "base64.h"
#include "kernel_defines.h"
#define BASE64_CAPITAL_UPPER_BOUND (25) /**< base64 'Z' */
#define BASE64_SMALL_UPPER_BOUND (51) /**< base64 'z' */
#define BASE64_NUMBER_UPPER_BOUND (61) /**< base64 '9' */
#define BASE64_PLUS (62) /**< base64 '+' */
#define BASE64_MINUS (62) /**< base64 '-' */
#define BASE64_SLASH (63) /**< base64 '/' */
#define BASE64_UNDERLINE (63) /**< base64 '_' */
#define BASE64_EQUALS (0xFE) /**< no base64 symbol '=' */
#define BASE64_NOT_DEFINED (0xFF) /**< no base64 symbol */
/*
* returns the corresponding ascii symbol value for the given base64 code
*/
static char getsymbol(unsigned char code)
static char getsymbol(unsigned char code, bool urlsafe)
{
if (code == BASE64_SLASH) {
if (!IS_ACTIVE(MODULE_BASE64URL)) {
urlsafe = false;
}
if (urlsafe && code == BASE64_UNDERLINE) {
return '_';
}
if (urlsafe && code == BASE64_MINUS) {
return '-';
}
if (!urlsafe && code == BASE64_SLASH) {
return '/';
}
if (code == BASE64_PLUS) {
if (!urlsafe && code == BASE64_PLUS) {
return '+';
}
@ -56,8 +72,9 @@ static char getsymbol(unsigned char code)
return (char)BASE64_NOT_DEFINED;
}
int base64_encode(const void *data_in, size_t data_in_size,
unsigned char *base64_out, size_t *base64_out_size)
static int base64_encode_base(const void *data_in, size_t data_in_size,
unsigned char *base64_out, size_t *base64_out_size,
bool urlsafe)
{
const unsigned char *in = data_in;
size_t required_size = base64_estimate_encode_size(data_in_size);
@ -103,14 +120,14 @@ int base64_encode(const void *data_in, size_t data_in_size,
nLst = tmpval & ((1 << njump * 2) - 1);
}
base64_out[iterate_base64_buffer++] = getsymbol(nNum);
base64_out[iterate_base64_buffer++] = getsymbol(nNum, urlsafe);
}
/* The last character is not finished yet */
njump++;
nNum = nLst << (8 - 2 * njump);
base64_out[iterate_base64_buffer++] = getsymbol(nNum);
base64_out[iterate_base64_buffer++] = getsymbol(nNum, urlsafe);
/* if required we append '=' for the required dividability */
while (iterate_base64_buffer % 4) {
@ -122,6 +139,20 @@ int base64_encode(const void *data_in, size_t data_in_size,
return BASE64_SUCCESS;
}
int base64_encode(const void *data_in, size_t data_in_size,
unsigned char *base64_out, size_t *base64_out_size)
{
return base64_encode_base(data_in, data_in_size, base64_out, base64_out_size, false);
}
#if IS_ACTIVE(MODULE_BASE64URL)
int base64url_encode(const void *data_in, size_t data_in_size,
unsigned char *base64_out, size_t *base64_out_size)
{
return base64_encode_base(data_in, data_in_size, base64_out, base64_out_size, true);
}
#endif
/*
* returns the corresponding base64 code for the given ascii symbol
*/
@ -131,10 +162,18 @@ static int getcode(char symbol)
return BASE64_SLASH;
}
if (symbol == '_') {
return BASE64_UNDERLINE;
}
if (symbol == '+') {
return BASE64_PLUS;
}
if (symbol == '-') {
return BASE64_MINUS;
}
if (symbol == '=') {
/* indicates a padded base64 end */
return BASE64_EQUALS;

View File

@ -76,6 +76,32 @@ static inline size_t base64_estimate_encode_size(size_t data_in_size)
int base64_encode(const void *data_in, size_t data_in_size,
unsigned char *base64_out, size_t *base64_out_size);
/**
* @brief Encodes a given datum to base64 with URL and Filename Safe Alphabet
* and save the result to the given destination.
*
* @see [RFC 4648, section 5](https://tools.ietf.org/html/rfc4648#section-5)
*
* @note Requires the use of the `base64url` module.
*
* @param[in] data_in pointer to the datum to encode
* @param[in] data_in_size the size of `data_in`
* @param[out] base64_out pointer to store the encoded base64 string
* @param[in,out] base64_out_size pointer to the variable containing the size of `base64_out.`
This value is overwritten with the estimated size used for
the encoded base64 string on BASE64_ERROR_BUFFER_OUT_SIZE.
This value is overwritten with the actual used size for the
encoded base64 string on BASE64_SUCCESS.
* @returns BASE64_SUCCESS on success,
BASE64_ERROR_BUFFER_OUT_SIZE on insufficient size for encoding to `base64_out`,
BASE64_ERROR_BUFFER_OUT if `base64_out` equals NULL
but the `base64_out_size` is sufficient,
BASE64_ERROR_DATA_IN if `data_in` equals NULL.
*/
int base64url_encode(const void *data_in, size_t data_in_size,
unsigned char *base64_out, size_t *base64_out_size);
/**
* @brief Decodes a given base64 string and save the result to the given destination.
* @param[out] base64_in pointer to store the encoded base64 string