From 2a02a3a7dfda2679ebda86fa830023fe996a06c9 Mon Sep 17 00:00:00 2001 From: Harsh Sharma <92harshsharma@gmail.com> Date: Wed, 13 Jun 2018 13:26:38 -0500 Subject: Initial commit --- lora_pkt_fwd/src/base64.c | 308 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 308 insertions(+) create mode 100644 lora_pkt_fwd/src/base64.c (limited to 'lora_pkt_fwd/src/base64.c') diff --git a/lora_pkt_fwd/src/base64.c b/lora_pkt_fwd/src/base64.c new file mode 100644 index 0000000..8ba908e --- /dev/null +++ b/lora_pkt_fwd/src/base64.c @@ -0,0 +1,308 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech-Cycleo + +Description: + Base64 encoding & decoding library + +License: Revised BSD License, see LICENSE.TXT file include in the project +Maintainer: Sylvain Miermont +*/ + + +/* -------------------------------------------------------------------------- */ +/* --- DEPENDANCIES --------------------------------------------------------- */ + +#include +#include +#include + +#include "base64.h" + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE MACROS ------------------------------------------------------- */ + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define CRIT(a) fprintf(stderr, "\nCRITICAL file:%s line:%u msg:%s\n", __FILE__, __LINE__,a);exit(EXIT_FAILURE) + +//#define DEBUG(args...) fprintf(stderr,"debug: " args) /* diagnostic message that is destined to the user */ +#define DEBUG(args...) + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE MODULE-WIDE VARIABLES ---------------------------------------- */ + +static char code_62 = '+'; /* RFC 1421 standard character for code 62 */ +static char code_63 = '/'; /* RFC 1421 standard character for code 63 */ +static char code_pad = '='; /* RFC 1421 padding character if padding */ + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ + +/** +@brief Convert a code in the range 0-63 to an ASCII character +*/ +char code_to_char(uint8_t x); + +/** +@brief Convert an ASCII character to a code in the range 0-63 +*/ +uint8_t char_to_code(char x); + +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ + +char code_to_char(uint8_t x) { + if (x <= 25) { + return 'A' + x; + } else if ((x >= 26) && (x <= 51)) { + return 'a' + (x-26); + } else if ((x >= 52) && (x <= 61)) { + return '0' + (x-52); + } else if (x == 62) { + return code_62; + } else if (x == 63) { + return code_63; + } else { + DEBUG("ERROR: %i IS OUT OF RANGE 0-63 FOR BASE64 ENCODING\n", x); + exit(EXIT_FAILURE); + } //TODO: improve error management +} + +uint8_t char_to_code(char x) { + if ((x >= 'A') && (x <= 'Z')) { + return (uint8_t)x - (uint8_t)'A'; + } else if ((x >= 'a') && (x <= 'z')) { + return (uint8_t)x - (uint8_t)'a' + 26; + } else if ((x >= '0') && (x <= '9')) { + return (uint8_t)x - (uint8_t)'0' + 52; + } else if (x == code_62) { + return 62; + } else if (x == code_63) { + return 63; + } else { + DEBUG("ERROR: %c (0x%x) IS INVALID CHARACTER FOR BASE64 DECODING\n", x, x); + exit(EXIT_FAILURE); + } //TODO: improve error management +} + +/* -------------------------------------------------------------------------- */ +/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ + +int bin_to_b64_nopad(const uint8_t * in, int size, char * out, int max_len) { + int i; + int result_len; /* size of the result */ + int full_blocks; /* number of 3 unsigned chars / 4 characters blocks */ + int last_bytes; /* number of unsigned chars <3 in the last block */ + int last_chars; /* number of characters <4 in the last block */ + uint32_t b; + + /* check input values */ + if ((out == NULL) || (in == NULL)) { + DEBUG("ERROR: NULL POINTER AS OUTPUT IN BIN_TO_B64\n"); + return -1; + } + if (size == 0) { + *out = 0; /* null string */ + return 0; + } + + /* calculate the number of base64 'blocks' */ + full_blocks = size / 3; + last_bytes = size % 3; + switch (last_bytes) { + case 0: /* no byte left to encode */ + last_chars = 0; + break; + case 1: /* 1 byte left to encode -> +2 chars */ + last_chars = 2; + break; + case 2: /* 2 bytes left to encode -> +3 chars */ + last_chars = 3; + break; + default: + CRIT("switch default that should not be possible"); + } + + /* check if output buffer is big enough */ + result_len = (4*full_blocks) + last_chars; + if (max_len < (result_len + 1)) { /* 1 char added for string terminator */ + DEBUG("ERROR: OUTPUT BUFFER TOO SMALL IN BIN_TO_B64\n"); + return -1; + } + + /* process all the full blocks */ + for (i=0; i < full_blocks; ++i) { + b = (0xFF & in[3*i] ) << 16; + b |= (0xFF & in[3*i + 1]) << 8; + b |= 0xFF & in[3*i + 2]; + out[4*i + 0] = code_to_char((b >> 18) & 0x3F); + out[4*i + 1] = code_to_char((b >> 12) & 0x3F); + out[4*i + 2] = code_to_char((b >> 6 ) & 0x3F); + out[4*i + 3] = code_to_char( b & 0x3F); + } + + /* process the last 'partial' block and terminate string */ + i = full_blocks; + if (last_chars == 0) { + out[4*i] = 0; /* null character to terminate string */ + } else if (last_chars == 2) { + b = (0xFF & in[3*i] ) << 16; + out[4*i + 0] = code_to_char((b >> 18) & 0x3F); + out[4*i + 1] = code_to_char((b >> 12) & 0x3F); + out[4*i + 2] = 0; /* null character to terminate string */ + } else if (last_chars == 3) { + b = (0xFF & in[3*i] ) << 16; + b |= (0xFF & in[3*i + 1]) << 8; + out[4*i + 0] = code_to_char((b >> 18) & 0x3F); + out[4*i + 1] = code_to_char((b >> 12) & 0x3F); + out[4*i + 2] = code_to_char((b >> 6 ) & 0x3F); + out[4*i + 3] = 0; /* null character to terminate string */ + } + + return result_len; +} + +int b64_to_bin_nopad(const char * in, int size, uint8_t * out, int max_len) { + int i; + int result_len; /* size of the result */ + int full_blocks; /* number of 3 unsigned chars / 4 characters blocks */ + int last_chars; /* number of characters <4 in the last block */ + int last_bytes; /* number of unsigned chars <3 in the last block */ + uint32_t b; + ; + + /* check input values */ + if ((out == NULL) || (in == NULL)) { + DEBUG("ERROR: NULL POINTER AS OUTPUT OR INPUT IN B64_TO_BIN\n"); + return -1; + } + if (size == 0) { + return 0; + } + + /* calculate the number of base64 'blocks' */ + full_blocks = size / 4; + last_chars = size % 4; + switch (last_chars) { + case 0: /* no char left to decode */ + last_bytes = 0; + break; + case 1: /* only 1 char left is an error */ + DEBUG("ERROR: ONLY ONE CHAR LEFT IN B64_TO_BIN\n"); + return -1; + case 2: /* 2 chars left to decode -> +1 byte */ + last_bytes = 1; + break; + case 3: /* 3 chars left to decode -> +2 bytes */ + last_bytes = 2; + break; + default: + CRIT("switch default that should not be possible"); + } + + /* check if output buffer is big enough */ + result_len = (3*full_blocks) + last_bytes; + if (max_len < result_len) { + DEBUG("ERROR: OUTPUT BUFFER TOO SMALL IN B64_TO_BIN\n"); + return -1; + } + + /* process all the full blocks */ + for (i=0; i < full_blocks; ++i) { + b = (0x3F & char_to_code(in[4*i] )) << 18; + b |= (0x3F & char_to_code(in[4*i + 1])) << 12; + b |= (0x3F & char_to_code(in[4*i + 2])) << 6; + b |= 0x3F & char_to_code(in[4*i + 3]); + out[3*i + 0] = (b >> 16) & 0xFF; + out[3*i + 1] = (b >> 8 ) & 0xFF; + out[3*i + 2] = b & 0xFF; + } + + /* process the last 'partial' block */ + i = full_blocks; + if (last_bytes == 1) { + b = (0x3F & char_to_code(in[4*i] )) << 18; + b |= (0x3F & char_to_code(in[4*i + 1])) << 12; + out[3*i + 0] = (b >> 16) & 0xFF; + if (((b >> 12) & 0x0F) != 0) { + DEBUG("WARNING: last character contains unusable bits\n"); + } + } else if (last_bytes == 2) { + b = (0x3F & char_to_code(in[4*i] )) << 18; + b |= (0x3F & char_to_code(in[4*i + 1])) << 12; + b |= (0x3F & char_to_code(in[4*i + 2])) << 6; + out[3*i + 0] = (b >> 16) & 0xFF; + out[3*i + 1] = (b >> 8 ) & 0xFF; + if (((b >> 6) & 0x03) != 0) { + DEBUG("WARNING: last character contains unusable bits\n"); + } + } + + return result_len; +} + +int bin_to_b64(const uint8_t * in, int size, char * out, int max_len) { + int ret; + + ret = bin_to_b64_nopad(in, size, out, max_len); + + if (ret == -1) { + return -1; + } + switch (ret%4) { + case 0: /* nothing to do */ + return ret; + case 1: + DEBUG("ERROR: INVALID UNPADDED BASE64 STRING\n"); + return -1; + case 2: /* 2 chars in last block, must add 2 padding char */ + if (max_len >= (ret + 2 + 1)) { + out[ret] = code_pad; + out[ret+1] = code_pad; + out[ret+2] = 0; + return ret+2; + } else { + DEBUG("ERROR: not enough room to add padding in bin_to_b64\n"); + return -1; + } + case 3: /* 3 chars in last block, must add 1 padding char */ + if (max_len >= (ret + 1 + 1)) { + out[ret] = code_pad; + out[ret+1] = 0; + return ret+1; + } else { + DEBUG("ERROR: not enough room to add padding in bin_to_b64\n"); + return -1; + } + default: + CRIT("switch default that should not be possible"); + } +} + +int b64_to_bin(const char * in, int size, uint8_t * out, int max_len) { + if (in == NULL) { + DEBUG("ERROR: NULL POINTER AS OUTPUT OR INPUT IN B64_TO_BIN\n"); + return -1; + } + if ((size%4 == 0) && (size >= 4)) { /* potentially padded Base64 */ + if (in[size-2] == code_pad) { /* 2 padding char to ignore */ + return b64_to_bin_nopad(in, size-2, out, max_len); + } else if (in[size-1] == code_pad) { /* 1 padding char to ignore */ + return b64_to_bin_nopad(in, size-1, out, max_len); + } else { /* no padding to ignore */ + return b64_to_bin_nopad(in, size, out, max_len); + } + } else { /* treat as unpadded Base64 */ + return b64_to_bin_nopad(in, size, out, max_len); + } +} + + +/* --- EOF ------------------------------------------------------------------ */ -- cgit v1.2.3