Damian Gabino / picoGW_packet_forwarder
Committer:
dgabino
Date:
Wed Apr 11 14:47:16 2018 +0000
Revision:
0:9002b89157da
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dgabino 0:9002b89157da 1 /*
dgabino 0:9002b89157da 2 / _____) _ | |
dgabino 0:9002b89157da 3 ( (____ _____ ____ _| |_ _____ ____| |__
dgabino 0:9002b89157da 4 \____ \| ___ | (_ _) ___ |/ ___) _ \
dgabino 0:9002b89157da 5 _____) ) ____| | | || |_| ____( (___| | | |
dgabino 0:9002b89157da 6 (______/|_____)_|_|_| \__)_____)\____)_| |_|
dgabino 0:9002b89157da 7 (C)2013 Semtech-Cycleo
dgabino 0:9002b89157da 8
dgabino 0:9002b89157da 9 Description:
dgabino 0:9002b89157da 10 Base64 encoding & decoding library
dgabino 0:9002b89157da 11
dgabino 0:9002b89157da 12 License: Revised BSD License, see LICENSE.TXT file include in the project
dgabino 0:9002b89157da 13 Maintainer: Sylvain Miermont
dgabino 0:9002b89157da 14 */
dgabino 0:9002b89157da 15
dgabino 0:9002b89157da 16
dgabino 0:9002b89157da 17 /* -------------------------------------------------------------------------- */
dgabino 0:9002b89157da 18 /* --- DEPENDANCIES --------------------------------------------------------- */
dgabino 0:9002b89157da 19
dgabino 0:9002b89157da 20 #include <stdio.h>
dgabino 0:9002b89157da 21 #include <stdlib.h>
dgabino 0:9002b89157da 22 #include <stdint.h>
dgabino 0:9002b89157da 23
dgabino 0:9002b89157da 24 #include "base64.h"
dgabino 0:9002b89157da 25
dgabino 0:9002b89157da 26 /* -------------------------------------------------------------------------- */
dgabino 0:9002b89157da 27 /* --- PRIVATE MACROS ------------------------------------------------------- */
dgabino 0:9002b89157da 28
dgabino 0:9002b89157da 29 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
dgabino 0:9002b89157da 30 #define CRIT(a) fprintf(stderr, "\nCRITICAL file:%s line:%d msg:%s\n", __FILE__, __LINE__, a);exit(EXIT_FAILURE)
dgabino 0:9002b89157da 31
dgabino 0:9002b89157da 32 //#define DEBUG(args...) fprintf(stderr,"debug: " args) /* diagnostic message that is destined to the user */
dgabino 0:9002b89157da 33 #define DEBUG(args...)
dgabino 0:9002b89157da 34
dgabino 0:9002b89157da 35 /* -------------------------------------------------------------------------- */
dgabino 0:9002b89157da 36 /* --- PRIVATE CONSTANTS ---------------------------------------------------- */
dgabino 0:9002b89157da 37
dgabino 0:9002b89157da 38 /* -------------------------------------------------------------------------- */
dgabino 0:9002b89157da 39 /* --- PRIVATE MODULE-WIDE VARIABLES ---------------------------------------- */
dgabino 0:9002b89157da 40
dgabino 0:9002b89157da 41 static char code_62 = '+'; /* RFC 1421 standard character for code 62 */
dgabino 0:9002b89157da 42 static char code_63 = '/'; /* RFC 1421 standard character for code 63 */
dgabino 0:9002b89157da 43 static char code_pad = '='; /* RFC 1421 padding character if padding */
dgabino 0:9002b89157da 44
dgabino 0:9002b89157da 45 /* -------------------------------------------------------------------------- */
dgabino 0:9002b89157da 46 /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
dgabino 0:9002b89157da 47
dgabino 0:9002b89157da 48 /**
dgabino 0:9002b89157da 49 @brief Convert a code in the range 0-63 to an ASCII character
dgabino 0:9002b89157da 50 */
dgabino 0:9002b89157da 51 char code_to_char(uint8_t x);
dgabino 0:9002b89157da 52
dgabino 0:9002b89157da 53 /**
dgabino 0:9002b89157da 54 @brief Convert an ASCII character to a code in the range 0-63
dgabino 0:9002b89157da 55 */
dgabino 0:9002b89157da 56 uint8_t char_to_code(char x);
dgabino 0:9002b89157da 57
dgabino 0:9002b89157da 58 /* -------------------------------------------------------------------------- */
dgabino 0:9002b89157da 59 /* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */
dgabino 0:9002b89157da 60
dgabino 0:9002b89157da 61 char code_to_char(uint8_t x) {
dgabino 0:9002b89157da 62 if (x <= 25) {
dgabino 0:9002b89157da 63 return 'A' + x;
dgabino 0:9002b89157da 64 } else if ((x >= 26) && (x <= 51)) {
dgabino 0:9002b89157da 65 return 'a' + (x - 26);
dgabino 0:9002b89157da 66 } else if ((x >= 52) && (x <= 61)) {
dgabino 0:9002b89157da 67 return '0' + (x - 52);
dgabino 0:9002b89157da 68 } else if (x == 62) {
dgabino 0:9002b89157da 69 return code_62;
dgabino 0:9002b89157da 70 } else if (x == 63) {
dgabino 0:9002b89157da 71 return code_63;
dgabino 0:9002b89157da 72 } else {
dgabino 0:9002b89157da 73 DEBUG("ERROR: %i IS OUT OF RANGE 0-63 FOR BASE64 ENCODING\n", x);
dgabino 0:9002b89157da 74 exit(EXIT_FAILURE);
dgabino 0:9002b89157da 75 } //TODO: improve error management
dgabino 0:9002b89157da 76 }
dgabino 0:9002b89157da 77
dgabino 0:9002b89157da 78 uint8_t char_to_code(char x) {
dgabino 0:9002b89157da 79 if ((x >= 'A') && (x <= 'Z')) {
dgabino 0:9002b89157da 80 return (uint8_t)x - (uint8_t)'A';
dgabino 0:9002b89157da 81 } else if ((x >= 'a') && (x <= 'z')) {
dgabino 0:9002b89157da 82 return (uint8_t)x - (uint8_t)'a' + 26;
dgabino 0:9002b89157da 83 } else if ((x >= '0') && (x <= '9')) {
dgabino 0:9002b89157da 84 return (uint8_t)x - (uint8_t)'0' + 52;
dgabino 0:9002b89157da 85 } else if (x == code_62) {
dgabino 0:9002b89157da 86 return 62;
dgabino 0:9002b89157da 87 } else if (x == code_63) {
dgabino 0:9002b89157da 88 return 63;
dgabino 0:9002b89157da 89 } else {
dgabino 0:9002b89157da 90 DEBUG("ERROR: %c (0x%x) IS INVALID CHARACTER FOR BASE64 DECODING\n", x, x);
dgabino 0:9002b89157da 91 exit(EXIT_FAILURE);
dgabino 0:9002b89157da 92 } //TODO: improve error management
dgabino 0:9002b89157da 93 }
dgabino 0:9002b89157da 94
dgabino 0:9002b89157da 95 /* -------------------------------------------------------------------------- */
dgabino 0:9002b89157da 96 /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
dgabino 0:9002b89157da 97
dgabino 0:9002b89157da 98 int bin_to_b64_nopad(const uint8_t * in, int size, char * out, int max_len) {
dgabino 0:9002b89157da 99 int i;
dgabino 0:9002b89157da 100 int result_len; /* size of the result */
dgabino 0:9002b89157da 101 int full_blocks; /* number of 3 unsigned chars / 4 characters blocks */
dgabino 0:9002b89157da 102 int last_bytes; /* number of unsigned chars <3 in the last block */
dgabino 0:9002b89157da 103 int last_chars; /* number of characters <4 in the last block */
dgabino 0:9002b89157da 104 uint32_t b;
dgabino 0:9002b89157da 105
dgabino 0:9002b89157da 106 /* check input values */
dgabino 0:9002b89157da 107 if ((out == NULL) || (in == NULL)) {
dgabino 0:9002b89157da 108 DEBUG("ERROR: NULL POINTER AS OUTPUT IN BIN_TO_B64\n");
dgabino 0:9002b89157da 109 return -1;
dgabino 0:9002b89157da 110 }
dgabino 0:9002b89157da 111 if (size == 0) {
dgabino 0:9002b89157da 112 *out = 0; /* null string */
dgabino 0:9002b89157da 113 return 0;
dgabino 0:9002b89157da 114 }
dgabino 0:9002b89157da 115
dgabino 0:9002b89157da 116 /* calculate the number of base64 'blocks' */
dgabino 0:9002b89157da 117 full_blocks = size / 3;
dgabino 0:9002b89157da 118 last_bytes = size % 3;
dgabino 0:9002b89157da 119 switch (last_bytes) {
dgabino 0:9002b89157da 120 case 0: /* no byte left to encode */
dgabino 0:9002b89157da 121 last_chars = 0;
dgabino 0:9002b89157da 122 break;
dgabino 0:9002b89157da 123 case 1: /* 1 byte left to encode -> +2 chars */
dgabino 0:9002b89157da 124 last_chars = 2;
dgabino 0:9002b89157da 125 break;
dgabino 0:9002b89157da 126 case 2: /* 2 bytes left to encode -> +3 chars */
dgabino 0:9002b89157da 127 last_chars = 3;
dgabino 0:9002b89157da 128 break;
dgabino 0:9002b89157da 129 default:
dgabino 0:9002b89157da 130 CRIT("switch default that should not be possible");
dgabino 0:9002b89157da 131 }
dgabino 0:9002b89157da 132
dgabino 0:9002b89157da 133 /* check if output buffer is big enough */
dgabino 0:9002b89157da 134 result_len = (4 * full_blocks) + last_chars;
dgabino 0:9002b89157da 135 if (max_len < (result_len + 1)) { /* 1 char added for string terminator */
dgabino 0:9002b89157da 136 DEBUG("ERROR: OUTPUT BUFFER TOO SMALL IN BIN_TO_B64\n");
dgabino 0:9002b89157da 137 return -1;
dgabino 0:9002b89157da 138 }
dgabino 0:9002b89157da 139
dgabino 0:9002b89157da 140 /* process all the full blocks */
dgabino 0:9002b89157da 141 for (i = 0; i < full_blocks; ++i) {
dgabino 0:9002b89157da 142 b = (0xFF & in[3 * i] ) << 16;
dgabino 0:9002b89157da 143 b |= (0xFF & in[3 * i + 1]) << 8;
dgabino 0:9002b89157da 144 b |= 0xFF & in[3 * i + 2];
dgabino 0:9002b89157da 145 out[4 * i + 0] = code_to_char((b >> 18) & 0x3F);
dgabino 0:9002b89157da 146 out[4 * i + 1] = code_to_char((b >> 12) & 0x3F);
dgabino 0:9002b89157da 147 out[4 * i + 2] = code_to_char((b >> 6 ) & 0x3F);
dgabino 0:9002b89157da 148 out[4 * i + 3] = code_to_char( b & 0x3F);
dgabino 0:9002b89157da 149 }
dgabino 0:9002b89157da 150
dgabino 0:9002b89157da 151 /* process the last 'partial' block and terminate string */
dgabino 0:9002b89157da 152 i = full_blocks;
dgabino 0:9002b89157da 153 if (last_chars == 0) {
dgabino 0:9002b89157da 154 out[4 * i] = 0; /* null character to terminate string */
dgabino 0:9002b89157da 155 } else if (last_chars == 2) {
dgabino 0:9002b89157da 156 b = (0xFF & in[3 * i] ) << 16;
dgabino 0:9002b89157da 157 out[4 * i + 0] = code_to_char((b >> 18) & 0x3F);
dgabino 0:9002b89157da 158 out[4 * i + 1] = code_to_char((b >> 12) & 0x3F);
dgabino 0:9002b89157da 159 out[4 * i + 2] = 0; /* null character to terminate string */
dgabino 0:9002b89157da 160 } else if (last_chars == 3) {
dgabino 0:9002b89157da 161 b = (0xFF & in[3 * i] ) << 16;
dgabino 0:9002b89157da 162 b |= (0xFF & in[3 * i + 1]) << 8;
dgabino 0:9002b89157da 163 out[4 * i + 0] = code_to_char((b >> 18) & 0x3F);
dgabino 0:9002b89157da 164 out[4 * i + 1] = code_to_char((b >> 12) & 0x3F);
dgabino 0:9002b89157da 165 out[4 * i + 2] = code_to_char((b >> 6 ) & 0x3F);
dgabino 0:9002b89157da 166 out[4 * i + 3] = 0; /* null character to terminate string */
dgabino 0:9002b89157da 167 }
dgabino 0:9002b89157da 168
dgabino 0:9002b89157da 169 return result_len;
dgabino 0:9002b89157da 170 }
dgabino 0:9002b89157da 171
dgabino 0:9002b89157da 172 int b64_to_bin_nopad(const char * in, int size, uint8_t * out, int max_len) {
dgabino 0:9002b89157da 173 int i;
dgabino 0:9002b89157da 174 int result_len; /* size of the result */
dgabino 0:9002b89157da 175 int full_blocks; /* number of 3 unsigned chars / 4 characters blocks */
dgabino 0:9002b89157da 176 int last_chars; /* number of characters <4 in the last block */
dgabino 0:9002b89157da 177 int last_bytes; /* number of unsigned chars <3 in the last block */
dgabino 0:9002b89157da 178 uint32_t b;
dgabino 0:9002b89157da 179 ;
dgabino 0:9002b89157da 180
dgabino 0:9002b89157da 181 /* check input values */
dgabino 0:9002b89157da 182 if ((out == NULL) || (in == NULL)) {
dgabino 0:9002b89157da 183 DEBUG("ERROR: NULL POINTER AS OUTPUT OR INPUT IN B64_TO_BIN\n");
dgabino 0:9002b89157da 184 return -1;
dgabino 0:9002b89157da 185 }
dgabino 0:9002b89157da 186 if (size == 0) {
dgabino 0:9002b89157da 187 return 0;
dgabino 0:9002b89157da 188 }
dgabino 0:9002b89157da 189
dgabino 0:9002b89157da 190 /* calculate the number of base64 'blocks' */
dgabino 0:9002b89157da 191 full_blocks = size / 4;
dgabino 0:9002b89157da 192 last_chars = size % 4;
dgabino 0:9002b89157da 193 switch (last_chars) {
dgabino 0:9002b89157da 194 case 0: /* no char left to decode */
dgabino 0:9002b89157da 195 last_bytes = 0;
dgabino 0:9002b89157da 196 break;
dgabino 0:9002b89157da 197 case 1: /* only 1 char left is an error */
dgabino 0:9002b89157da 198 DEBUG("ERROR: ONLY ONE CHAR LEFT IN B64_TO_BIN\n");
dgabino 0:9002b89157da 199 return -1;
dgabino 0:9002b89157da 200 case 2: /* 2 chars left to decode -> +1 byte */
dgabino 0:9002b89157da 201 last_bytes = 1;
dgabino 0:9002b89157da 202 break;
dgabino 0:9002b89157da 203 case 3: /* 3 chars left to decode -> +2 bytes */
dgabino 0:9002b89157da 204 last_bytes = 2;
dgabino 0:9002b89157da 205 break;
dgabino 0:9002b89157da 206 default:
dgabino 0:9002b89157da 207 CRIT("switch default that should not be possible");
dgabino 0:9002b89157da 208 }
dgabino 0:9002b89157da 209
dgabino 0:9002b89157da 210 /* check if output buffer is big enough */
dgabino 0:9002b89157da 211 result_len = (3 * full_blocks) + last_bytes;
dgabino 0:9002b89157da 212 if (max_len < result_len) {
dgabino 0:9002b89157da 213 DEBUG("ERROR: OUTPUT BUFFER TOO SMALL IN B64_TO_BIN\n");
dgabino 0:9002b89157da 214 return -1;
dgabino 0:9002b89157da 215 }
dgabino 0:9002b89157da 216
dgabino 0:9002b89157da 217 /* process all the full blocks */
dgabino 0:9002b89157da 218 for (i = 0; i < full_blocks; ++i) {
dgabino 0:9002b89157da 219 b = (0x3F & char_to_code(in[4 * i] )) << 18;
dgabino 0:9002b89157da 220 b |= (0x3F & char_to_code(in[4 * i + 1])) << 12;
dgabino 0:9002b89157da 221 b |= (0x3F & char_to_code(in[4 * i + 2])) << 6;
dgabino 0:9002b89157da 222 b |= 0x3F & char_to_code(in[4 * i + 3]);
dgabino 0:9002b89157da 223 out[3 * i + 0] = (b >> 16) & 0xFF;
dgabino 0:9002b89157da 224 out[3 * i + 1] = (b >> 8 ) & 0xFF;
dgabino 0:9002b89157da 225 out[3 * i + 2] = b & 0xFF;
dgabino 0:9002b89157da 226 }
dgabino 0:9002b89157da 227
dgabino 0:9002b89157da 228 /* process the last 'partial' block */
dgabino 0:9002b89157da 229 i = full_blocks;
dgabino 0:9002b89157da 230 if (last_bytes == 1) {
dgabino 0:9002b89157da 231 b = (0x3F & char_to_code(in[4 * i] )) << 18;
dgabino 0:9002b89157da 232 b |= (0x3F & char_to_code(in[4 * i + 1])) << 12;
dgabino 0:9002b89157da 233 out[3 * i + 0] = (b >> 16) & 0xFF;
dgabino 0:9002b89157da 234 if (((b >> 12) & 0x0F) != 0) {
dgabino 0:9002b89157da 235 DEBUG("WARNING: last character contains unusable bits\n");
dgabino 0:9002b89157da 236 }
dgabino 0:9002b89157da 237 } else if (last_bytes == 2) {
dgabino 0:9002b89157da 238 b = (0x3F & char_to_code(in[4 * i] )) << 18;
dgabino 0:9002b89157da 239 b |= (0x3F & char_to_code(in[4 * i + 1])) << 12;
dgabino 0:9002b89157da 240 b |= (0x3F & char_to_code(in[4 * i + 2])) << 6;
dgabino 0:9002b89157da 241 out[3 * i + 0] = (b >> 16) & 0xFF;
dgabino 0:9002b89157da 242 out[3 * i + 1] = (b >> 8 ) & 0xFF;
dgabino 0:9002b89157da 243 if (((b >> 6) & 0x03) != 0) {
dgabino 0:9002b89157da 244 DEBUG("WARNING: last character contains unusable bits\n");
dgabino 0:9002b89157da 245 }
dgabino 0:9002b89157da 246 }
dgabino 0:9002b89157da 247
dgabino 0:9002b89157da 248 return result_len;
dgabino 0:9002b89157da 249 }
dgabino 0:9002b89157da 250
dgabino 0:9002b89157da 251 int bin_to_b64(const uint8_t * in, int size, char * out, int max_len) {
dgabino 0:9002b89157da 252 int ret;
dgabino 0:9002b89157da 253
dgabino 0:9002b89157da 254 ret = bin_to_b64_nopad(in, size, out, max_len);
dgabino 0:9002b89157da 255
dgabino 0:9002b89157da 256 if (ret == -1) {
dgabino 0:9002b89157da 257 return -1;
dgabino 0:9002b89157da 258 }
dgabino 0:9002b89157da 259 switch (ret % 4) {
dgabino 0:9002b89157da 260 case 0: /* nothing to do */
dgabino 0:9002b89157da 261 return ret;
dgabino 0:9002b89157da 262 case 1:
dgabino 0:9002b89157da 263 DEBUG("ERROR: INVALID UNPADDED BASE64 STRING\n");
dgabino 0:9002b89157da 264 return -1;
dgabino 0:9002b89157da 265 case 2: /* 2 chars in last block, must add 2 padding char */
dgabino 0:9002b89157da 266 if (max_len >= (ret + 2 + 1)) {
dgabino 0:9002b89157da 267 out[ret] = code_pad;
dgabino 0:9002b89157da 268 out[ret + 1] = code_pad;
dgabino 0:9002b89157da 269 out[ret + 2] = 0;
dgabino 0:9002b89157da 270 return ret + 2;
dgabino 0:9002b89157da 271 } else {
dgabino 0:9002b89157da 272 DEBUG("ERROR: not enough room to add padding in bin_to_b64\n");
dgabino 0:9002b89157da 273 return -1;
dgabino 0:9002b89157da 274 }
dgabino 0:9002b89157da 275 case 3: /* 3 chars in last block, must add 1 padding char */
dgabino 0:9002b89157da 276 if (max_len >= (ret + 1 + 1)) {
dgabino 0:9002b89157da 277 out[ret] = code_pad;
dgabino 0:9002b89157da 278 out[ret + 1] = 0;
dgabino 0:9002b89157da 279 return ret + 1;
dgabino 0:9002b89157da 280 } else {
dgabino 0:9002b89157da 281 DEBUG("ERROR: not enough room to add padding in bin_to_b64\n");
dgabino 0:9002b89157da 282 return -1;
dgabino 0:9002b89157da 283 }
dgabino 0:9002b89157da 284 default:
dgabino 0:9002b89157da 285 CRIT("switch default that should not be possible");
dgabino 0:9002b89157da 286 }
dgabino 0:9002b89157da 287 }
dgabino 0:9002b89157da 288
dgabino 0:9002b89157da 289 int b64_to_bin(const char * in, int size, uint8_t * out, int max_len) {
dgabino 0:9002b89157da 290 if (in == NULL) {
dgabino 0:9002b89157da 291 DEBUG("ERROR: NULL POINTER AS OUTPUT OR INPUT IN B64_TO_BIN\n");
dgabino 0:9002b89157da 292 return -1;
dgabino 0:9002b89157da 293 }
dgabino 0:9002b89157da 294 if ((size % 4 == 0) && (size >= 4)) { /* potentially padded Base64 */
dgabino 0:9002b89157da 295 if (in[size - 2] == code_pad) { /* 2 padding char to ignore */
dgabino 0:9002b89157da 296 return b64_to_bin_nopad(in, size - 2, out, max_len);
dgabino 0:9002b89157da 297 } else if (in[size - 1] == code_pad) { /* 1 padding char to ignore */
dgabino 0:9002b89157da 298 return b64_to_bin_nopad(in, size - 1, out, max_len);
dgabino 0:9002b89157da 299 } else { /* no padding to ignore */
dgabino 0:9002b89157da 300 return b64_to_bin_nopad(in, size, out, max_len);
dgabino 0:9002b89157da 301 }
dgabino 0:9002b89157da 302 } else { /* treat as unpadded Base64 */
dgabino 0:9002b89157da 303 return b64_to_bin_nopad(in, size, out, max_len);
dgabino 0:9002b89157da 304 }
dgabino 0:9002b89157da 305 }
dgabino 0:9002b89157da 306
dgabino 0:9002b89157da 307
dgabino 0:9002b89157da 308 /* --- EOF ------------------------------------------------------------------ */