mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 01:43:36 +01:00
CCAN: add base64 module.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
9c254c8387
commit
81b2092cfc
1
Makefile
1
Makefile
@ -146,6 +146,7 @@ CCAN_HEADERS := \
|
||||
$(CCANDIR)/ccan/alignof/alignof.h \
|
||||
$(CCANDIR)/ccan/array_size/array_size.h \
|
||||
$(CCANDIR)/ccan/asort/asort.h \
|
||||
$(CCANDIR)/ccan/base64/base64.h \
|
||||
$(CCANDIR)/ccan/bitmap/bitmap.h \
|
||||
$(CCANDIR)/ccan/bitops/bitops.h \
|
||||
$(CCANDIR)/ccan/breakpoint/breakpoint.h \
|
||||
|
1
ccan/ccan/base64/LICENSE
Symbolic link
1
ccan/ccan/base64/LICENSE
Symbolic link
@ -0,0 +1 @@
|
||||
../../licenses/BSD-MIT
|
41
ccan/ccan/base64/_info
Normal file
41
ccan/ccan/base64/_info
Normal file
@ -0,0 +1,41 @@
|
||||
#include "config.h"
|
||||
|
||||
/**
|
||||
* base64 - base64 encoding and decoding (rfc4648).
|
||||
*
|
||||
* base64 encoding is used to encode data in a 7-bit clean manner.
|
||||
* Commonly used for escaping data before encapsulation or transfer
|
||||
*
|
||||
* Example:
|
||||
* #include <stdio.h>
|
||||
* #include <string.h>
|
||||
* #include <ccan/base64/base64.h>
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* char *base64_encoded_string;
|
||||
* int i;
|
||||
*
|
||||
* // print the base64-encoded form of the program arguments
|
||||
* for(i=1;i<argc;i++) {
|
||||
* size_t unencoded_length = strlen(argv[i]);
|
||||
* size_t encoded_length = base64_encoded_length(unencoded_length);
|
||||
* base64_encoded_string = malloc(encoded_length);
|
||||
* base64_encode(base64_encoded_string, encoded_length,
|
||||
* argv[i], unencoded_length);
|
||||
* printf("%s\n", base64_encoded_string);
|
||||
* free(base64_encoded_string);
|
||||
* }
|
||||
*
|
||||
* return 0;
|
||||
* }
|
||||
*
|
||||
* License: BSD-MIT
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
return 1;
|
||||
}
|
253
ccan/ccan/base64/base64.c
Normal file
253
ccan/ccan/base64/base64.c
Normal file
@ -0,0 +1,253 @@
|
||||
/* Licensed under BSD-MIT - see LICENSE file for details */
|
||||
#include "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 */
|
||||
};
|
241
ccan/ccan/base64/base64.h
Normal file
241
ccan/ccan/base64/base64.h
Normal file
@ -0,0 +1,241 @@
|
||||
/* 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>
|
||||
|
||||
/**
|
||||
* 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 */
|
||||
|
||||
|
||||
|
||||
#endif /* CCAN_BASE64_H */
|
96
ccan/ccan/base64/test/moretap.h
Normal file
96
ccan/ccan/base64/test/moretap.h
Normal file
@ -0,0 +1,96 @@
|
||||
#ifndef _BASE64_MORETAP_H
|
||||
#define _BASE64_MORETAP_H
|
||||
|
||||
#include <ccan/str/str.h>
|
||||
|
||||
/**
|
||||
* is_str - OK if strings are equal
|
||||
* @e1: expression for the variable string
|
||||
* @e2: expression for the expected string
|
||||
*
|
||||
* If the strings are equal, the test passes.
|
||||
*
|
||||
* Example:
|
||||
* is_str(give_me_a_fred(),"fred");
|
||||
*/
|
||||
static void _is_str(char *got,const char *expected, const char *got_string, const char *expected_string, const char *func, const char *file, int line) {
|
||||
if (streq(expected,got)) {
|
||||
_gen_result(1, func, file, line,"%s eq %s",
|
||||
got_string,expected_string);
|
||||
} else {
|
||||
_gen_result(0, func, file, line,"%s eq %s",
|
||||
got_string,expected_string);
|
||||
diag("Expected: %s",expected);
|
||||
diag(" Got: %s",got);
|
||||
}
|
||||
}
|
||||
# define is_str(got,expected) _is_str(got,expected,#got,#expected,__func__, __FILE__, __LINE__)
|
||||
|
||||
|
||||
/**
|
||||
* is_int - OK if arguments are equal when cast to integers
|
||||
* @e1: expression for the number
|
||||
* @e2: expression for the expected number
|
||||
*
|
||||
* If the numbers are equal, the test passes.
|
||||
*
|
||||
* Example:
|
||||
* is_int(give_me_17(),17);
|
||||
*/
|
||||
# define is_int(e1,e2 ...) \
|
||||
(((int)e1)==((int)e2) ? \
|
||||
_gen_result(1, __func__, __FILE__, __LINE__,"%s == %s",#e1,#e2) : \
|
||||
(_gen_result(0, __func__, __FILE__, __LINE__,"%s == %s",#e1,#e2)) || (diag("Expected: %d",e2),diag(" Got: %d",e1),0)) /* diag is void; note commas. */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* is_mem - OK if arguments are identical up to length @e3
|
||||
* @e1: expression for the buffer
|
||||
* @e2: expression for the expected buffer
|
||||
* @e2: length to compare in buffers
|
||||
*
|
||||
* If the buffers are equal up to @e2, the test passes.
|
||||
*
|
||||
* Example:
|
||||
* is_mem(give_me_foo(),"foo",3);
|
||||
*/
|
||||
static void _is_mem(const char *got, const char *expected, const size_t len,
|
||||
const char *got_string, const char *expected_string, const char *len_string,
|
||||
const char *func, const char *file, int line) {
|
||||
size_t offset = 0;
|
||||
|
||||
for (offset=0; offset<len; offset++) {
|
||||
if (got[offset] != expected[offset]) {
|
||||
_gen_result(0, func, file, line,"%s eq %s",got_string,expected_string);
|
||||
/* diag("Expected: %s",e2); */
|
||||
/* diag(" Got: %s",e1); */
|
||||
diag("Buffers differ at offset %zd (got=0x%02x expected=0x%02x)",
|
||||
offset,got[offset],expected[offset]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_gen_result(1, __func__, __FILE__, __LINE__,"%s eq %s",
|
||||
expected_string,got_string);
|
||||
}
|
||||
# define is_mem(got,expected,len) \
|
||||
_is_mem(got,expected,len,#got,#expected,#len,__func__, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* is_size_t - OK if arguments are equal when cast to size_t
|
||||
* @e1: expression for the number
|
||||
* @e2: expression for the expected number
|
||||
*
|
||||
* If the numbers are equal, the test passes.
|
||||
*
|
||||
* Example:
|
||||
* is_size_t(give_me_17(),17);
|
||||
*/
|
||||
# define is_size_t(e1,e2 ...) \
|
||||
((size_t)(e1)==((size_t)e2) ? \
|
||||
_gen_result(1, __func__, __FILE__, __LINE__,"%s == %s",#e1,#e2) : \
|
||||
(_gen_result(0, __func__, __FILE__, __LINE__, \
|
||||
"%s == %s",#e1,#e2)) || (diag("Expected: %zd",(size_t)e2),diag(" Got: %zd",(size_t)e1),0)) /* diag is void; note commas. */
|
||||
|
||||
#endif
|
359
ccan/ccan/base64/test/run.c
Normal file
359
ccan/ccan/base64/test/run.c
Normal file
@ -0,0 +1,359 @@
|
||||
/* Start of run.c test */
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <ccan/base64/base64.h>
|
||||
#include <ccan/tap/tap.h>
|
||||
|
||||
#include <ccan/base64/base64.c>
|
||||
#include "moretap.h"
|
||||
|
||||
static void * xmalloc(size_t size);
|
||||
|
||||
/* not defined in terms of test_encode_using_maps so we cross
|
||||
appropriate paths in library */
|
||||
#define test_encode(src,srclen,expected) \
|
||||
do { \
|
||||
size_t destlen; \
|
||||
char * dest; \
|
||||
destlen = base64_encoded_length(srclen); \
|
||||
destlen++; /* null termination */ \
|
||||
dest = xmalloc(destlen); \
|
||||
ok1(base64_encode(dest,destlen,src,srclen) != -1); \
|
||||
is_str(dest,expected); \
|
||||
free(dest); \
|
||||
} while (0)
|
||||
|
||||
#define test_encode_using_alphabet(alphastring,src,srclen,expected) \
|
||||
do { \
|
||||
size_t destlen; \
|
||||
char * dest; \
|
||||
base64_maps_t maps; \
|
||||
base64_init_maps(&maps,alphastring); \
|
||||
destlen = base64_encoded_length(srclen); \
|
||||
destlen++; /* null termination */ \
|
||||
dest = xmalloc(destlen); \
|
||||
ok1(base64_encode_using_maps(&maps,dest,destlen,src,srclen) != -1); \
|
||||
is_str(dest,expected); \
|
||||
free(dest); \
|
||||
} while (0)
|
||||
|
||||
/* not defined in terms of test_decode_using_alphabet so we cross
|
||||
appropriate paths in library */
|
||||
#define test_decode(src,srclen,expected,expectedlen) \
|
||||
do { \
|
||||
size_t destlen; \
|
||||
size_t bytes_used; \
|
||||
char * dest; \
|
||||
destlen = base64_decoded_length(srclen); \
|
||||
dest = xmalloc(destlen); \
|
||||
ok1((bytes_used = base64_decode(dest,destlen,src,srclen)) != -1); \
|
||||
is_size_t(bytes_used,expectedlen); \
|
||||
is_mem(dest,expected,bytes_used); \
|
||||
free(dest); \
|
||||
} while (0)
|
||||
|
||||
#define test_decode_using_alphabet(alphastring,src,srclen,expected,expectedlen) \
|
||||
do { \
|
||||
size_t destlen; \
|
||||
size_t bytes_used; \
|
||||
char * dest; \
|
||||
base64_maps_t maps; \
|
||||
\
|
||||
base64_init_maps(&maps,alphastring); \
|
||||
destlen = base64_decoded_length(srclen); \
|
||||
dest = xmalloc(destlen); \
|
||||
ok1((bytes_used = base64_decode_using_maps(&maps,dest,destlen,src,srclen)) != -1); \
|
||||
is_size_t(bytes_used,expectedlen); \
|
||||
is_mem(dest,expected,bytes_used); \
|
||||
free(dest); \
|
||||
} while (0)
|
||||
|
||||
#define check_bad_range_decode(stuff_to_test,stufflen) \
|
||||
do { \
|
||||
char dest[10]; \
|
||||
errno = 0; \
|
||||
is_size_t(base64_decode(dest,sizeof(dest),stuff_to_test,(size_t)stufflen), \
|
||||
(size_t)-1); \
|
||||
is_int(errno,EDOM); \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
plan_tests(131);
|
||||
|
||||
is_size_t(base64_encoded_length(0),(size_t)0);
|
||||
is_size_t(base64_encoded_length(1),(size_t)4);
|
||||
is_size_t(base64_encoded_length(2),(size_t)4);
|
||||
is_size_t(base64_encoded_length(3),(size_t)4);
|
||||
is_size_t(base64_encoded_length(512),(size_t)684);
|
||||
|
||||
/* straight from page 11 of http://tools.ietf.org/html/rfc4648 */
|
||||
test_encode("",0,"");
|
||||
test_encode("f",1,"Zg==");
|
||||
test_encode("fo",2,"Zm8=");
|
||||
|
||||
test_encode("foo",3,"Zm9v");
|
||||
test_encode("foob",4,"Zm9vYg==");
|
||||
test_encode("fooba",5,"Zm9vYmE=");
|
||||
test_encode("foobar",6,"Zm9vYmFy");
|
||||
|
||||
/* a few more */
|
||||
test_encode("foobarb",7,"Zm9vYmFyYg==");
|
||||
test_encode("foobarba",8,"Zm9vYmFyYmE=");
|
||||
test_encode("foobarbaz",9,"Zm9vYmFyYmF6");
|
||||
|
||||
test_encode("foobart",7,"Zm9vYmFydA==");
|
||||
|
||||
test_encode("abcdefghijklmnopqrstuvwxyz",26,"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=");
|
||||
test_encode("\x05\x05\x01\x00\x07",5,"BQUBAAc=");
|
||||
|
||||
test_encode("FOO",3,"Rk9P");
|
||||
test_encode("Z",1,"Wg==");
|
||||
|
||||
/* decode testing */
|
||||
|
||||
test_decode("",0,"",0);
|
||||
test_decode("Zg==",4,"f",1);
|
||||
test_decode("Zm8=",4,"fo",2);
|
||||
test_decode("Zm9v",4,"foo",3);
|
||||
test_decode("Zm9vYg==",8,"foob",4);
|
||||
test_decode("Zm9vYmE=",8,"fooba",5);
|
||||
test_decode("Zm9vYmFy",8,"foobar",6);
|
||||
test_decode("Zm9vYmFyYg==",12,"foobarb",7);
|
||||
test_decode("Zm9vYmFyYmE=",12,"foobarba",8);
|
||||
test_decode("Zm9vYmFyYmF6",12,"foobarbaz",9);
|
||||
|
||||
test_decode("Rk9P",4,"FOO",3);
|
||||
|
||||
test_decode("Wg==",4,"Z",1);
|
||||
test_decode("AA==",4,"\0",1);
|
||||
test_decode("AAA=",4,"\0\0",2);
|
||||
|
||||
{
|
||||
const char *binary = "\x01\x00\x03";
|
||||
const size_t binarylen = 3;
|
||||
|
||||
char * decoded;
|
||||
char * encoded;
|
||||
size_t encoded_len;
|
||||
size_t decoded_len;
|
||||
size_t decoded_space_required;
|
||||
|
||||
size_t encoded_space_required = base64_encoded_length(binarylen);
|
||||
encoded_space_required++; /* null termination */
|
||||
encoded = xmalloc(encoded_space_required);
|
||||
encoded_len = base64_encode(encoded,encoded_space_required,binary,binarylen);
|
||||
is_mem(encoded,"AQAD",encoded_len);
|
||||
|
||||
decoded_space_required = base64_decoded_length(encoded_len);
|
||||
decoded = xmalloc(decoded_space_required);
|
||||
decoded_len = base64_decode(decoded,decoded_space_required,encoded,encoded_len);
|
||||
is_size_t(decoded_len,binarylen);
|
||||
is_mem(binary,decoded,decoded_len);
|
||||
}
|
||||
|
||||
/* some expected encode failures: */
|
||||
{
|
||||
size_t destlen = 1;
|
||||
char dest[destlen];
|
||||
errno = 0;
|
||||
is_size_t(base64_encode(dest,destlen,"A",1),(size_t)-1);
|
||||
is_int(errno,EOVERFLOW);
|
||||
}
|
||||
|
||||
/* some expected decode failures: */
|
||||
{
|
||||
base64_maps_t maps;
|
||||
const char * src = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
base64_init_maps(&maps,src);
|
||||
|
||||
is_int(sixbit_from_b64(&maps,'\xfe'),(signed char)-1);
|
||||
is_int(errno,EDOM);
|
||||
}
|
||||
{
|
||||
size_t destlen = 10;
|
||||
char dest[destlen];
|
||||
errno = 0;
|
||||
is_size_t(base64_decode(dest,destlen,"A",1),(size_t)-1);
|
||||
is_int(errno,EINVAL);
|
||||
}
|
||||
{
|
||||
size_t destlen = 1;
|
||||
char dest[destlen];
|
||||
errno = 0;
|
||||
is_size_t(base64_decode(dest,destlen,"A",1),(size_t)-1);
|
||||
is_int(errno,EOVERFLOW);
|
||||
}
|
||||
{
|
||||
/* (char)1 is not a valid base64 character: */
|
||||
check_bad_range_decode("A\x01",2);
|
||||
/* (char)255 is not a valid base64 character: (char is signed on most platforms, so this is actually < 0 */
|
||||
check_bad_range_decode("\xff""A",2);
|
||||
check_bad_range_decode("A\xff",2);
|
||||
check_bad_range_decode("AA\xff",3);
|
||||
check_bad_range_decode("A\xff""A",3);
|
||||
check_bad_range_decode("\xff""AA",3);
|
||||
check_bad_range_decode("AAA\xff",4);
|
||||
check_bad_range_decode("\xff\x41\x41\x41\x41",5);
|
||||
check_bad_range_decode("A\xff\x41\x41\x41\x41",6);
|
||||
check_bad_range_decode("AA\xff\x41\x41\x41\x41",7);
|
||||
check_bad_range_decode("AAA\xff\x41\x41\x41\x41",8);
|
||||
}
|
||||
/* trigger some failures in the sixbit-to-b64 encoder: */
|
||||
/* this function now aborts rather than returning -1/setting errno */
|
||||
/* { */
|
||||
/* is_int(sixbit_to_b64(base64_maps_rfc4648,'\x70'),(char)-1); */
|
||||
/* is_int(sixbit_to_b64(base64_maps_rfc4648,'\xff'),(char)-1); */
|
||||
/* } */
|
||||
/* following tests all of the mapping from b64 chars to 6-bit values: */
|
||||
test_decode("//+FwHRSRIsFU2IhAEGD+AMPhOA=",28,"\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0",20);
|
||||
test_encode("\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0",20,"//+FwHRSRIsFU2IhAEGD+AMPhOA=");
|
||||
|
||||
|
||||
/* check the null-padding stuff */
|
||||
{
|
||||
size_t destlen = 8;
|
||||
char dest[destlen];
|
||||
memset(dest,'\1',sizeof(dest));
|
||||
is_size_t(base64_encode(dest,destlen,"A",1),(size_t)4);
|
||||
is_mem(&dest[4],"\0\0\0\0",4);
|
||||
}
|
||||
{
|
||||
size_t destlen = 3;
|
||||
char dest[destlen];
|
||||
memset(dest,'\1',sizeof(dest));
|
||||
is_size_t(base64_decode(dest,destlen,"Wg==",4), 1);
|
||||
is_mem(&dest[1],"\0",2);
|
||||
}
|
||||
|
||||
/* test encoding using different alphabets */
|
||||
{
|
||||
char alphabet_fs_safe[64];
|
||||
memcpy(alphabet_fs_safe,base64_maps_rfc4648.encode_map,sizeof(alphabet_fs_safe));
|
||||
alphabet_fs_safe[62] = '-';
|
||||
alphabet_fs_safe[63] = '_';
|
||||
test_encode_using_alphabet(alphabet_fs_safe,"\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0",20,"__-FwHRSRIsFU2IhAEGD-AMPhOA=");
|
||||
}
|
||||
|
||||
/* test decoding using different alphabets */
|
||||
{
|
||||
char alphabet_fs_safe[64];
|
||||
#define src "__-FwHRSRIsFU2IhAEGD-AMPhOA="
|
||||
#define expected "\xff\xff\x85\xc0\x74\x52\x44\x8b\x05\x53\x62\x21\x00\x41\x83\xf8\x03\x0f\x84\xe0"
|
||||
|
||||
memcpy(alphabet_fs_safe,base64_maps_rfc4648.encode_map,sizeof(alphabet_fs_safe));
|
||||
alphabet_fs_safe[62] = '-';
|
||||
alphabet_fs_safe[63] = '_';
|
||||
|
||||
test_decode_using_alphabet(alphabet_fs_safe,src,strlen(src),expected,20);
|
||||
#undef src
|
||||
#undef expected
|
||||
}
|
||||
|
||||
/* explicitly test the non-maps encode_triplet and
|
||||
encode_tail functions */
|
||||
{
|
||||
size_t destlen = 4;
|
||||
char dest[destlen];
|
||||
const char *src = "AB\04";
|
||||
memset(dest,'\1',sizeof(dest));
|
||||
base64_encode_triplet(dest,src);
|
||||
is_mem(dest,"QUIE",sizeof(dest));
|
||||
}
|
||||
{
|
||||
size_t destlen = 4;
|
||||
char dest[destlen];
|
||||
const char *src = "A";
|
||||
memset(dest,'\1',sizeof(dest));
|
||||
base64_encode_tail(dest,src,strlen(src));
|
||||
is_mem(dest,"QQ==",sizeof(dest));
|
||||
}
|
||||
|
||||
/* test the alphabet inversion */
|
||||
{
|
||||
base64_maps_t dest;
|
||||
const char expected_inverse[] =
|
||||
"\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 */
|
||||
;
|
||||
const char * src = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
base64_init_maps(&dest, src);
|
||||
is_mem((const char *)dest.decode_map, expected_inverse, 256);
|
||||
ok1(base64_char_in_alphabet(&dest,'A'));
|
||||
ok1(!base64_char_in_alphabet(&dest,'\n'));
|
||||
}
|
||||
|
||||
/* explicitly test the non-alpha decode_tail and decode_quartet */
|
||||
{
|
||||
char dest[4];
|
||||
const char *src = "QQ==";
|
||||
const char * expected = "A";
|
||||
memset(dest, '%', sizeof(dest));
|
||||
base64_decode_tail(dest,src,4);
|
||||
is_mem(dest, expected, 1);
|
||||
}
|
||||
{
|
||||
char dest[4];
|
||||
const char *src = "Zm9v";
|
||||
const char * expected = "foo";
|
||||
memset(dest, '%', sizeof(dest));
|
||||
base64_decode_quartet(dest,src);
|
||||
is_mem(dest, expected, 1);
|
||||
}
|
||||
|
||||
exit(exit_status());
|
||||
}
|
||||
|
||||
static void * xmalloc(size_t size)
|
||||
{
|
||||
char * ret;
|
||||
ret = malloc(size);
|
||||
if (ret == NULL) {
|
||||
perror("malloc");
|
||||
abort();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* End of run.c test */
|
Loading…
Reference in New Issue
Block a user