summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIru Cai <mytbk920423@gmail.com>2018-05-20 23:52:23 +0800
committerIru Cai <mytbk920423@gmail.com>2018-06-08 14:30:46 +0800
commitd029e2bbdffeeb7b35144802362926bc008620c7 (patch)
tree46d6d92ec12c4d38630466ef8b9721968a6c9659
parent08208e67707f7c626338ab163189e36a695e31c5 (diff)
downloadfqterm-d029e2bbdffeeb7b35144802362926bc008620c7.tar.xz
add ccan/base64
-rw-r--r--src/protocol/internal/ccan_base64.c253
-rw-r--r--src/protocol/internal/ccan_base64.h247
2 files changed, 500 insertions, 0 deletions
diff --git a/src/protocol/internal/ccan_base64.c b/src/protocol/internal/ccan_base64.c
new file mode 100644
index 0000000..7e3b711
--- /dev/null
+++ b/src/protocol/internal/ccan_base64.c
@@ -0,0 +1,253 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+#include "ccan_base64.h"
+
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+
+/**
+ * sixbit_to_b64 - maps a 6-bit value to the base64 alphabet
+ * @param map A base 64 map (see base64_init_map)
+ * @param sixbit Six-bit value to map
+ * @return a base 64 character
+ */
+static char sixbit_to_b64(const base64_maps_t *maps, const uint8_t sixbit)
+{
+ assert(sixbit <= 63);
+
+ return maps->encode_map[(unsigned char)sixbit];
+}
+
+/**
+ * sixbit_from_b64 - maps a base64-alphabet character to its 6-bit value
+ * @param maps A base 64 maps structure (see base64_init_maps)
+ * @param sixbit Six-bit value to map
+ * @return a six-bit value
+ */
+static int8_t sixbit_from_b64(const base64_maps_t *maps,
+ const unsigned char b64letter)
+{
+ int8_t ret;
+
+ ret = maps->decode_map[(unsigned char)b64letter];
+ if (ret == (char)0xff) {
+ errno = EDOM;
+ return -1;
+ }
+
+ return ret;
+}
+
+bool base64_char_in_alphabet(const base64_maps_t *maps, const char b64char)
+{
+ return (maps->decode_map[(const unsigned char)b64char] != (char)0xff);
+}
+
+void base64_init_maps(base64_maps_t *dest, const char src[64])
+{
+ unsigned char i;
+
+ memcpy(dest->encode_map,src,64);
+ memset(dest->decode_map,0xff,256);
+ for (i=0; i<64; i++) {
+ dest->decode_map[(unsigned char)src[i]] = i;
+ }
+}
+
+size_t base64_encoded_length(size_t srclen)
+{
+ return ((srclen + 2) / 3) * 4;
+}
+
+void base64_encode_triplet_using_maps(const base64_maps_t *maps,
+ char dest[4], const char src[3])
+{
+ char a = src[0];
+ char b = src[1];
+ char c = src[2];
+
+ dest[0] = sixbit_to_b64(maps, (a & 0xfc) >> 2);
+ dest[1] = sixbit_to_b64(maps, ((a & 0x3) << 4) | ((b & 0xf0) >> 4));
+ dest[2] = sixbit_to_b64(maps, ((c & 0xc0) >> 6) | ((b & 0xf) << 2));
+ dest[3] = sixbit_to_b64(maps, c & 0x3f);
+}
+
+void base64_encode_tail_using_maps(const base64_maps_t *maps, char dest[4],
+ const char *src, const size_t srclen)
+{
+ char longsrc[3] = { 0 };
+
+ assert(srclen <= 3);
+
+ memcpy(longsrc, src, srclen);
+ base64_encode_triplet_using_maps(maps, dest, longsrc);
+ memset(dest+1+srclen, '=', 3-srclen);
+}
+
+ssize_t base64_encode_using_maps(const base64_maps_t *maps,
+ char *dest, const size_t destlen,
+ const char *src, const size_t srclen)
+{
+ size_t src_offset = 0;
+ size_t dest_offset = 0;
+
+ if (destlen < base64_encoded_length(srclen)) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ while (srclen - src_offset >= 3) {
+ base64_encode_triplet_using_maps(maps, &dest[dest_offset], &src[src_offset]);
+ src_offset += 3;
+ dest_offset += 4;
+ }
+
+ if (src_offset < srclen) {
+ base64_encode_tail_using_maps(maps, &dest[dest_offset], &src[src_offset], srclen-src_offset);
+ dest_offset += 4;
+ }
+
+ memset(&dest[dest_offset], '\0', destlen-dest_offset);
+
+ return dest_offset;
+}
+
+size_t base64_decoded_length(size_t srclen)
+{
+ return ((srclen+3)/4*3);
+}
+
+int base64_decode_quartet_using_maps(const base64_maps_t *maps, char dest[3],
+ const char src[4])
+{
+ signed char a;
+ signed char b;
+ signed char c;
+ signed char d;
+
+ a = sixbit_from_b64(maps, src[0]);
+ b = sixbit_from_b64(maps, src[1]);
+ c = sixbit_from_b64(maps, src[2]);
+ d = sixbit_from_b64(maps, src[3]);
+
+ if ((a == -1) || (b == -1) || (c == -1) || (d == -1)) {
+ return -1;
+ }
+
+ dest[0] = (a << 2) | (b >> 4);
+ dest[1] = ((b & 0xf) << 4) | (c >> 2);
+ dest[2] = ((c & 0x3) << 6) | d;
+
+ return 0;
+}
+
+
+int base64_decode_tail_using_maps(const base64_maps_t *maps, char dest[3],
+ const char * src, const size_t srclen)
+{
+ char longsrc[4];
+ int quartet_result;
+ size_t insize = srclen;
+
+ while (insize != 0 &&
+ src[insize-1] == '=') { /* throw away padding symbols */
+ insize--;
+ }
+ if (insize == 0) {
+ return 0;
+ }
+ if (insize == 1) {
+ /* the input is malformed.... */
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy(longsrc, src, insize);
+ memset(longsrc+insize, 'A', 4-insize);
+ quartet_result = base64_decode_quartet_using_maps(maps, dest, longsrc);
+ if (quartet_result == -1) {
+ return -1;
+ }
+
+ return insize - 1;
+}
+
+ssize_t base64_decode_using_maps(const base64_maps_t *maps,
+ char *dest, const size_t destlen,
+ const char *src, const size_t srclen)
+{
+ ssize_t dest_offset = 0;
+ ssize_t i;
+ size_t more;
+
+ if (destlen < base64_decoded_length(srclen)) {
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ for(i=0; srclen - i > 4; i+=4) {
+ if (base64_decode_quartet_using_maps(maps, &dest[dest_offset], &src[i]) == -1) {
+ return -1;
+ }
+ dest_offset += 3;
+ }
+
+ more = base64_decode_tail_using_maps(maps, &dest[dest_offset], &src[i], srclen - i);
+ if (more == -1) {
+ return -1;
+ }
+ dest_offset += more;
+
+ memset(&dest[dest_offset], '\0', destlen-dest_offset);
+
+ return dest_offset;
+}
+
+
+
+
+/**
+ * base64_maps_rfc4648 - pregenerated maps struct for rfc4648
+ */
+const base64_maps_t base64_maps_rfc4648 = {
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
+
+ "\xff\xff\xff\xff\xff" /* 0 */ \
+ "\xff\xff\xff\xff\xff" /* 5 */ \
+ "\xff\xff\xff\xff\xff" /* 10 */ \
+ "\xff\xff\xff\xff\xff" /* 15 */ \
+ "\xff\xff\xff\xff\xff" /* 20 */ \
+ "\xff\xff\xff\xff\xff" /* 25 */ \
+ "\xff\xff\xff\xff\xff" /* 30 */ \
+ "\xff\xff\xff\xff\xff" /* 35 */ \
+ "\xff\xff\xff\x3e\xff" /* 40 */ \
+ "\xff\xff\x3f\x34\x35" /* 45 */ \
+ "\x36\x37\x38\x39\x3a" /* 50 */ \
+ "\x3b\x3c\x3d\xff\xff" /* 55 */ \
+ "\xff\xff\xff\xff\xff" /* 60 */ \
+ "\x00\x01\x02\x03\x04" /* 65 A */ \
+ "\x05\x06\x07\x08\x09" /* 70 */ \
+ "\x0a\x0b\x0c\x0d\x0e" /* 75 */ \
+ "\x0f\x10\x11\x12\x13" /* 80 */ \
+ "\x14\x15\x16\x17\x18" /* 85 */ \
+ "\x19\xff\xff\xff\xff" /* 90 */ \
+ "\xff\xff\x1a\x1b\x1c" /* 95 */ \
+ "\x1d\x1e\x1f\x20\x21" /* 100 */ \
+ "\x22\x23\x24\x25\x26" /* 105 */ \
+ "\x27\x28\x29\x2a\x2b" /* 110 */ \
+ "\x2c\x2d\x2e\x2f\x30" /* 115 */ \
+ "\x31\x32\x33\xff\xff" /* 120 */ \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 125 */ \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 155 */ \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 185 */ \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 215 */ \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" \
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" /* 245 */
+};
diff --git a/src/protocol/internal/ccan_base64.h b/src/protocol/internal/ccan_base64.h
new file mode 100644
index 0000000..3f1cd7c
--- /dev/null
+++ b/src/protocol/internal/ccan_base64.h
@@ -0,0 +1,247 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+#ifndef CCAN_BASE64_H
+#define CCAN_BASE64_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * base64_maps_t - structure to hold maps for encode/decode
+ */
+typedef struct {
+ char encode_map[64];
+ signed char decode_map[256];
+} base64_maps_t;
+
+/**
+ * base64_encoded_length - Calculate encode buffer length
+ * @param srclen the size of the data to be encoded
+ * @note add 1 to this to get null-termination
+ * @return Buffer length required for encode
+ */
+size_t base64_encoded_length(size_t srclen);
+
+/**
+ * base64_decoded_length - Calculate decode buffer length
+ * @param srclen Length of the data to be decoded
+ * @note This does not return the size of the decoded data! see base64_decode
+ * @return Minimum buffer length for safe decode
+ */
+size_t base64_decoded_length(size_t srclen);
+
+/**
+ * base64_init_maps - populate a base64_maps_t based on a supplied alphabet
+ * @param dest A base64 maps object
+ * @param src Alphabet to populate the maps from (e.g. base64_alphabet_rfc4648)
+ */
+void base64_init_maps(base64_maps_t *dest, const char src[64]);
+
+
+/**
+ * base64_encode_triplet_using_maps - encode 3 bytes into base64 using a specific alphabet
+ * @param maps Maps to use for encoding (see base64_init_maps)
+ * @param dest Buffer containing 3 bytes
+ * @param src Buffer containing 4 characters
+ */
+void base64_encode_triplet_using_maps(const base64_maps_t *maps,
+ char dest[4], const char src[3]);
+
+/**
+ * base64_encode_tail_using_maps - encode the final bytes of a source using a specific alphabet
+ * @param maps Maps to use for encoding (see base64_init_maps)
+ * @param dest Buffer containing 4 bytes
+ * @param src Buffer containing srclen bytes
+ * @param srclen Number of bytes (<= 3) to encode in src
+ */
+void base64_encode_tail_using_maps(const base64_maps_t *maps, char dest[4],
+ const char *src, size_t srclen);
+
+/**
+ * base64_encode_using_maps - encode a buffer into base64 using a specific alphabet
+ * @param maps Maps to use for encoding (see base64_init_maps)
+ * @param dest Buffer to encode into
+ * @param destlen Length of dest
+ * @param src Buffer to encode
+ * @param srclen Length of the data to encode
+ * @return Number of encoded bytes set in dest. -1 on error (and errno set)
+ * @note dest will be nul-padded to destlen (past any required padding)
+ * @note sets errno = EOVERFLOW if destlen is too small
+ */
+ssize_t base64_encode_using_maps(const base64_maps_t *maps,
+ char *dest, size_t destlen,
+ const char *src, size_t srclen);
+
+/*
+ * base64_char_in_alphabet - returns true if character can be part of an encoded string
+ * @param maps A base64 maps object (see base64_init_maps)
+ * @param b64char Character to check
+ */
+bool base64_char_in_alphabet(const base64_maps_t *maps, char b64char);
+
+/**
+ * base64_decode_using_maps - decode a base64-encoded string using a specific alphabet
+ * @param maps A base64 maps object (see base64_init_maps)
+ * @param dest Buffer to decode into
+ * @param destlen length of dest
+ * @param src the buffer to decode
+ * @param srclen the length of the data to decode
+ * @return Number of decoded bytes set in dest. -1 on error (and errno set)
+ * @note dest will be nul-padded to destlen
+ * @note sets errno = EOVERFLOW if destlen is too small
+ * @note sets errno = EDOM if src contains invalid characters
+ */
+ssize_t base64_decode_using_maps(const base64_maps_t *maps,
+ char *dest, size_t destlen,
+ const char *src, size_t srclen);
+
+/**
+ * base64_decode_quartet_using_maps - decode 4 bytes from base64 using a specific alphabet
+ * @param maps A base64 maps object (see base64_init_maps)
+ * @param dest Buffer containing 3 bytes
+ * @param src Buffer containing 4 bytes
+ * @return Number of decoded bytes set in dest. -1 on error (and errno set)
+ * @note sets errno = EDOM if src contains invalid characters
+ */
+int base64_decode_quartet_using_maps(const base64_maps_t *maps,
+ char dest[3], const char src[4]);
+
+/**
+ * base64_decode_tail_using_maps - decode the final bytes of a base64 string using a specific alphabet
+ * @param maps A base64 maps object (see base64_init_maps)
+ * @param dest Buffer containing 3 bytes
+ * @param src Buffer containing 4 bytes - padded with '=' as required
+ * @param srclen Number of bytes to decode in src
+ * @return Number of decoded bytes set in dest. -1 on error (and errno set)
+ * @note sets errno = EDOM if src contains invalid characters
+ * @note sets errno = EINVAL if src is an invalid base64 tail
+ */
+int base64_decode_tail_using_maps(const base64_maps_t *maps, char *dest,
+ const char *src, size_t srclen);
+
+
+/* the rfc4648 functions: */
+
+extern const base64_maps_t base64_maps_rfc4648;
+
+/**
+ * base64_encode - Encode a buffer into base64 according to rfc4648
+ * @param dest Buffer to encode into
+ * @param destlen Length of the destination buffer
+ * @param src Buffer to encode
+ * @param srclen Length of the data to encode
+ * @return Number of encoded bytes set in dest. -1 on error (and errno set)
+ * @note dest will be nul-padded to destlen (past any required padding)
+ * @note sets errno = EOVERFLOW if destlen is too small
+ *
+ * This function encodes src according to http://tools.ietf.org/html/rfc4648
+ *
+ * Example:
+ * size_t encoded_length;
+ * char dest[100];
+ * const char *src = "This string gets encoded";
+ * encoded_length = base64_encode(dest, sizeof(dest), src, strlen(src));
+ * printf("Returned data of length %zd @%p\n", encoded_length, &dest);
+ */
+static inline
+ssize_t base64_encode(char *dest, size_t destlen,
+ const char *src, size_t srclen)
+{
+ return base64_encode_using_maps(&base64_maps_rfc4648,
+ dest, destlen, src, srclen);
+}
+
+/**
+ * base64_encode_triplet - encode 3 bytes into base64 according to rfc4648
+ * @param dest Buffer containing 4 bytes
+ * @param src Buffer containing 3 bytes
+ */
+static inline
+void base64_encode_triplet(char dest[4], const char src[3])
+{
+ base64_encode_triplet_using_maps(&base64_maps_rfc4648, dest, src);
+}
+
+/**
+ * base64_encode_tail - encode the final bytes of a source according to rfc4648
+ * @param dest Buffer containing 4 bytes
+ * @param src Buffer containing srclen bytes
+ * @param srclen Number of bytes (<= 3) to encode in src
+ */
+static inline
+void base64_encode_tail(char dest[4], const char *src, size_t srclen)
+{
+ base64_encode_tail_using_maps(&base64_maps_rfc4648, dest, src, srclen);
+}
+
+
+/**
+ * base64_decode - decode An rfc4648 base64-encoded string
+ * @param dest Buffer to decode into
+ * @param destlen Length of the destination buffer
+ * @param src Buffer to decode
+ * @param srclen Length of the data to decode
+ * @return Number of decoded bytes set in dest. -1 on error (and errno set)
+ * @note dest will be nul-padded to destlen
+ * @note sets errno = EOVERFLOW if destlen is too small
+ * @note sets errno = EDOM if src contains invalid characters
+ *
+ * This function decodes the buffer according to
+ * http://tools.ietf.org/html/rfc4648
+ *
+ * Example:
+ * size_t decoded_length;
+ * char ret[100];
+ * const char *src = "Zm9vYmFyYmF6";
+ * decoded_length = base64_decode(ret, sizeof(ret), src, strlen(src));
+ * printf("Returned data of length %zd @%p\n", decoded_length, &ret);
+ */
+static inline
+ssize_t base64_decode(char *dest, size_t destlen,
+ const char *src, size_t srclen)
+{
+ return base64_decode_using_maps(&base64_maps_rfc4648,
+ dest, destlen, src, srclen);
+}
+
+/**
+ * base64_decode_quartet - decode the first 4 characters in src into dest
+ * @param dest Buffer containing 3 bytes
+ * @param src Buffer containing 4 characters
+ * @return Number of decoded bytes set in dest. -1 on error (and errno set)
+ * @note sets errno = EDOM if src contains invalid characters
+ */
+static inline
+int base64_decode_quartet(char dest[3], const char src[4])
+{
+ return base64_decode_quartet_using_maps(&base64_maps_rfc4648,
+ dest, src);
+}
+
+/**
+ * @brief decode the final bytes of a base64 string from src into dest
+ * @param dest Buffer containing 3 bytes
+ * @param src Buffer containing 4 bytes - padded with '=' as required
+ * @param srclen Number of bytes to decode in src
+ * @return Number of decoded bytes set in dest. -1 on error (and errno set)
+ * @note sets errno = EDOM if src contains invalid characters
+ * @note sets errno = EINVAL if src is an invalid base64 tail
+ */
+static inline
+ssize_t base64_decode_tail(char dest[3], const char *src, size_t srclen)
+{
+ return base64_decode_tail_using_maps(&base64_maps_rfc4648,
+ dest, src, srclen);
+}
+
+/* end rfc4648 functions */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CCAN_BASE64_H */