diff --git a/Makefile.dep b/Makefile.dep index dea76221bc..a850147b09 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -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 diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 42638e67fe..0abd042378 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -1,5 +1,6 @@ PSEUDOMODULES += at_urc PSEUDOMODULES += at24c% +PSEUDOMODULES += base64url PSEUDOMODULES += can_mbox PSEUDOMODULES += can_pm PSEUDOMODULES += can_raw diff --git a/sys/base64/base64.c b/sys/base64/base64.c index 0749bf9f3d..0f1b90075a 100644 --- a/sys/base64/base64.c +++ b/sys/base64/base64.c @@ -18,26 +18,42 @@ * */ +#include #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; diff --git a/sys/include/base64.h b/sys/include/base64.h index af2bf6894b..c34534059f 100644 --- a/sys/include/base64.h +++ b/sys/include/base64.h @@ -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