/********************************************************************************* Copyright 2006-2008 MakingThings 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. *********************************************************************************/ /* Written by Simon Josefsson. Partially adapted from GNU MailUtils (mailbox/filter_trans.c, as of 2004-11-28). Improved by review from Paul Eggert, Bruno Haible, and Stepan Kasal */ #include "base64.h" bool isbase64 (char ch); /* C89 compliant way to cast 'char' to 'unsigned char'. */ static inline unsigned char to_uchar (char ch) { return ch; } /** \defgroup base64 Base 64 The Make Controller Base 64 library provides a way to decode and encode base 64 data. This is often handy when you need to send raw/binary data (as opposed to text) through a text based format, like XML or JSON. Most code lifted from gnulib - http://savannah.gnu.org/projects/gnulib - and written by Simon Josefsson. \par \ingroup Libraries @{ */ /** Base 64 encode a block of data. Provide a buffer to write into and to read from. As Base64 encoding results in 4 bytes for every 3 source bytes, ensure your destination buffer is large enough. @param dest The buffer that the encoded string will be written into. @param dest_size The maximum number of bytes to write into the destination buffer. @param src A block of data to encode. @param src_size The number of bytes from src to encode. @return The length of the generated string (not including null termination). \par Example \code #define BUFF_SIZE 256 char encode_buf[BUFF_SIZE]; int len = Base64_Encode(encode_buf, BUFF_SIZE, "test", 4); // we now have "dGVzdA==" in encode_buf, and len is 8 \endcode */ int Base64_Encode(char* dest, int dest_size, const char* src, int src_size) { // our library of valid b64 chars static const unsigned char b64str[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int orig_size = dest_size; while(dest_size && src_size) { *dest++ = b64str[(to_uchar (src[0]) >> 2) & 0x3f]; if(!--dest_size) break; *dest++ = b64str[((to_uchar (src[0]) << 4) + (--src_size ? to_uchar (src[1]) >> 4 : 0)) & 0x3f]; if(!--dest_size) break; *dest++ = (src_size ? b64str[((to_uchar (src[1]) << 2) + (--src_size ? to_uchar (src[2]) >> 6 : 0)) & 0x3f] : '='); if(!--dest_size) break; *dest++ = src_size ? b64str[to_uchar (src[2]) & 0x3f] : '='; if(!--dest_size) break; if(src_size) src_size--; if(src_size) src += 3; } if(dest_size) *dest = '\0'; return orig_size - dest_size; } /* With this approach this file works independent of the charset used (think EBCDIC). However, it does assume that the characters in the Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX 1003.1-2001 require that char and unsigned char are 8-bit quantities, though, taking care of that problem. But this may be a potential problem on non-POSIX C99 platforms. IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_" as the formal parameter rather than "x". */ #define B64(_) \ ((_) == 'A' ? 0 \ : (_) == 'B' ? 1 \ : (_) == 'C' ? 2 \ : (_) == 'D' ? 3 \ : (_) == 'E' ? 4 \ : (_) == 'F' ? 5 \ : (_) == 'G' ? 6 \ : (_) == 'H' ? 7 \ : (_) == 'I' ? 8 \ : (_) == 'J' ? 9 \ : (_) == 'K' ? 10 \ : (_) == 'L' ? 11 \ : (_) == 'M' ? 12 \ : (_) == 'N' ? 13 \ : (_) == 'O' ? 14 \ : (_) == 'P' ? 15 \ : (_) == 'Q' ? 16 \ : (_) == 'R' ? 17 \ : (_) == 'S' ? 18 \ : (_) == 'T' ? 19 \ : (_) == 'U' ? 20 \ : (_) == 'V' ? 21 \ : (_) == 'W' ? 22 \ : (_) == 'X' ? 23 \ : (_) == 'Y' ? 24 \ : (_) == 'Z' ? 25 \ : (_) == 'a' ? 26 \ : (_) == 'b' ? 27 \ : (_) == 'c' ? 28 \ : (_) == 'd' ? 29 \ : (_) == 'e' ? 30 \ : (_) == 'f' ? 31 \ : (_) == 'g' ? 32 \ : (_) == 'h' ? 33 \ : (_) == 'i' ? 34 \ : (_) == 'j' ? 35 \ : (_) == 'k' ? 36 \ : (_) == 'l' ? 37 \ : (_) == 'm' ? 38 \ : (_) == 'n' ? 39 \ : (_) == 'o' ? 40 \ : (_) == 'p' ? 41 \ : (_) == 'q' ? 42 \ : (_) == 'r' ? 43 \ : (_) == 's' ? 44 \ : (_) == 't' ? 45 \ : (_) == 'u' ? 46 \ : (_) == 'v' ? 47 \ : (_) == 'w' ? 48 \ : (_) == 'x' ? 49 \ : (_) == 'y' ? 50 \ : (_) == 'z' ? 51 \ : (_) == '0' ? 52 \ : (_) == '1' ? 53 \ : (_) == '2' ? 54 \ : (_) == '3' ? 55 \ : (_) == '4' ? 56 \ : (_) == '5' ? 57 \ : (_) == '6' ? 58 \ : (_) == '7' ? 59 \ : (_) == '8' ? 60 \ : (_) == '9' ? 61 \ : (_) == '+' ? 62 \ : (_) == '/' ? 63 \ : -1) static const signed char b64[0x100] = { B64 (0), B64 (1), B64 (2), B64 (3), B64 (4), B64 (5), B64 (6), B64 (7), B64 (8), B64 (9), B64 (10), B64 (11), B64 (12), B64 (13), B64 (14), B64 (15), B64 (16), B64 (17), B64 (18), B64 (19), B64 (20), B64 (21), B64 (22), B64 (23), B64 (24), B64 (25), B64 (26), B64 (27), B64 (28), B64 (29), B64 (30), B64 (31), B64 (32), B64 (33), B64 (34), B64 (35), B64 (36), B64 (37), B64 (38), B64 (39), B64 (40), B64 (41), B64 (42), B64 (43), B64 (44), B64 (45), B64 (46), B64 (47), B64 (48), B64 (49), B64 (50), B64 (51), B64 (52), B64 (53), B64 (54), B64 (55), B64 (56), B64 (57), B64 (58), B64 (59), B64 (60), B64 (61), B64 (62), B64 (63), B64 (64), B64 (65), B64 (66), B64 (67), B64 (68), B64 (69), B64 (70), B64 (71), B64 (72), B64 (73), B64 (74), B64 (75), B64 (76), B64 (77), B64 (78), B64 (79), B64 (80), B64 (81), B64 (82), B64 (83), B64 (84), B64 (85), B64 (86), B64 (87), B64 (88), B64 (89), B64 (90), B64 (91), B64 (92), B64 (93), B64 (94), B64 (95), B64 (96), B64 (97), B64 (98), B64 (99), B64 (100), B64 (101), B64 (102), B64 (103), B64 (104), B64 (105), B64 (106), B64 (107), B64 (108), B64 (109), B64 (110), B64 (111), B64 (112), B64 (113), B64 (114), B64 (115), B64 (116), B64 (117), B64 (118), B64 (119), B64 (120), B64 (121), B64 (122), B64 (123), B64 (124), B64 (125), B64 (126), B64 (127), B64 (128), B64 (129), B64 (130), B64 (131), B64 (132), B64 (133), B64 (134), B64 (135), B64 (136), B64 (137), B64 (138), B64 (139), B64 (140), B64 (141), B64 (142), B64 (143), B64 (144), B64 (145), B64 (146), B64 (147), B64 (148), B64 (149), B64 (150), B64 (151), B64 (152), B64 (153), B64 (154), B64 (155), B64 (156), B64 (157), B64 (158), B64 (159), B64 (160), B64 (161), B64 (162), B64 (163), B64 (164), B64 (165), B64 (166), B64 (167), B64 (168), B64 (169), B64 (170), B64 (171), B64 (172), B64 (173), B64 (174), B64 (175), B64 (176), B64 (177), B64 (178), B64 (179), B64 (180), B64 (181), B64 (182), B64 (183), B64 (184), B64 (185), B64 (186), B64 (187), B64 (188), B64 (189), B64 (190), B64 (191), B64 (192), B64 (193), B64 (194), B64 (195), B64 (196), B64 (197), B64 (198), B64 (199), B64 (200), B64 (201), B64 (202), B64 (203), B64 (204), B64 (205), B64 (206), B64 (207), B64 (208), B64 (209), B64 (210), B64 (211), B64 (212), B64 (213), B64 (214), B64 (215), B64 (216), B64 (217), B64 (218), B64 (219), B64 (220), B64 (221), B64 (222), B64 (223), B64 (224), B64 (225), B64 (226), B64 (227), B64 (228), B64 (229), B64 (230), B64 (231), B64 (232), B64 (233), B64 (234), B64 (235), B64 (236), B64 (237), B64 (238), B64 (239), B64 (240), B64 (241), B64 (242), B64 (243), B64 (244), B64 (245), B64 (246), B64 (247), B64 (248), B64 (249), B64 (250), B64 (251), B64 (252), B64 (253), B64 (254), B64 (255) }; /* Return true if CH is a character from the Base64 alphabet, and false otherwise. Note that '=' is padding and not considered to be part of the alphabet. */ bool isbase64 (char ch) { //return uchar_in_range(to_uchar (ch)); && (0 <= b64[to_uchar(ch)]); -- uchar_in_range is always true for a uchar return (0 <= b64[to_uchar(ch)]); } /** Decode a Base64 string into a block of data. @param dest A pointer to the block of data to write in. @param dest_size A pointer to the maximum number of bytes to write into dest. The number of bytes successfully written will be stored in this value upon return. @param src The base 64 string to decode. @param src_size The size of the base 64 string. @return True on successful decode, false on failure. \par Example \code #define BUFF_SIZE 256 char decode_buf[BUFF_SIZE]; int decode_size = BUFF_SIZE; bool result = Base64_Decode(decode_buf, &decode_size, "dGVzdA==", 8); // we now have "test" in decode_buf, and decode_size is set to 6 \endcode */ bool Base64_Decode(char* dest, int* dest_size, const char* src, int src_size) { int out_remaining = *dest_size; while(src_size >= 2) { if(!isbase64 (src[0]) || !isbase64 (src[1])) break; if(out_remaining) { *dest++ = ((b64[to_uchar (src[0])] << 2) | (b64[to_uchar (src[1])] >> 4)); out_remaining--; } if(src_size == 2) break; if(src[2] == '=') { if(src_size != 4) break; if(src[3] != '=') break; } else { if(!isbase64 (src[2])) break; if(out_remaining) { *dest++ = (((b64[to_uchar (src[1])] << 4) & 0xf0) | (b64[to_uchar (src[2])] >> 2)); out_remaining--; } if(src_size == 3) break; if(src[3] == '=') { if(src_size != 4) break; } else { if(!isbase64 (src[3])) break; if(out_remaining) { *dest++ = (((b64[to_uchar (src[2])] << 6) & 0xc0) | b64[to_uchar (src[3])]); out_remaining--; } } } src += 4; src_size -= 4; } *dest_size -= out_remaining; if(src_size != 0) return false; return true; } /** @} */