mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-18 22:54:25 +01:00
ccan: import base32 module.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
4
Makefile
4
Makefile
@@ -79,6 +79,7 @@ CCAN_OBJS := \
|
|||||||
ccan-ptr_valid.o \
|
ccan-ptr_valid.o \
|
||||||
ccan-rbuf.o \
|
ccan-rbuf.o \
|
||||||
ccan-read_write_all.o \
|
ccan-read_write_all.o \
|
||||||
|
ccan-str-base32.o \
|
||||||
ccan-str-hex.o \
|
ccan-str-hex.o \
|
||||||
ccan-str.o \
|
ccan-str.o \
|
||||||
ccan-take.o \
|
ccan-take.o \
|
||||||
@@ -138,6 +139,7 @@ CCAN_HEADERS := \
|
|||||||
$(CCANDIR)/ccan/rbuf/rbuf.h \
|
$(CCANDIR)/ccan/rbuf/rbuf.h \
|
||||||
$(CCANDIR)/ccan/read_write_all/read_write_all.h \
|
$(CCANDIR)/ccan/read_write_all/read_write_all.h \
|
||||||
$(CCANDIR)/ccan/short_types/short_types.h \
|
$(CCANDIR)/ccan/short_types/short_types.h \
|
||||||
|
$(CCANDIR)/ccan/str/base32/base32.h \
|
||||||
$(CCANDIR)/ccan/str/hex/hex.h \
|
$(CCANDIR)/ccan/str/hex/hex.h \
|
||||||
$(CCANDIR)/ccan/str/str.h \
|
$(CCANDIR)/ccan/str/str.h \
|
||||||
$(CCANDIR)/ccan/str/str_debug.h \
|
$(CCANDIR)/ccan/str/str_debug.h \
|
||||||
@@ -549,3 +551,5 @@ ccan-bitops.o: $(CCANDIR)/ccan/bitops/bitops.c
|
|||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
ccan-rbuf.o: $(CCANDIR)/ccan/rbuf/rbuf.c
|
ccan-rbuf.o: $(CCANDIR)/ccan/rbuf/rbuf.c
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
ccan-str-base32.o: $(CCANDIR)/ccan/str/base32/base32.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|||||||
1
ccan/ccan/str/base32/LICENSE
Symbolic link
1
ccan/ccan/str/base32/LICENSE
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../../licenses/CC0
|
||||||
26
ccan/ccan/str/base32/_info
Normal file
26
ccan/ccan/str/base32/_info
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#include "config.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* str/base32 - RFC4648 base32 encoder/decoder.
|
||||||
|
*
|
||||||
|
* This code implements RFC4638 encoding, but you should use bech32 for most
|
||||||
|
* things anyway.
|
||||||
|
*
|
||||||
|
* License: CC0 (Public domain)
|
||||||
|
* Author: Rusty Russell <rusty@rustcorp.com.au>
|
||||||
|
*/
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
/* Expect exactly one argument */
|
||||||
|
if (argc != 2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "depends") == 0) {
|
||||||
|
printf("ccan/endian\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
159
ccan/ccan/str/base32/base32.c
Normal file
159
ccan/ccan/str/base32/base32.c
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/* CC0 license (public domain) - see LICENSE file for details */
|
||||||
|
#include "base32.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ccan/endian/endian.h>
|
||||||
|
#include <string.h> /* for memcpy, memset */
|
||||||
|
|
||||||
|
const char *base32_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=";
|
||||||
|
|
||||||
|
/* RFC 4648:
|
||||||
|
*
|
||||||
|
* (1) The final quantum of encoding input is an integral multiple of 40
|
||||||
|
* bits; here, the final unit of encoded output will be an integral
|
||||||
|
* multiple of 8 characters with no "=" padding.
|
||||||
|
*
|
||||||
|
* (2) The final quantum of encoding input is exactly 8 bits; here, the
|
||||||
|
* final unit of encoded output will be two characters followed by
|
||||||
|
* six "=" padding characters.
|
||||||
|
*
|
||||||
|
* (3) The final quantum of encoding input is exactly 16 bits; here, the
|
||||||
|
* final unit of encoded output will be four characters followed by
|
||||||
|
* four "=" padding characters.
|
||||||
|
*
|
||||||
|
* (4) The final quantum of encoding input is exactly 24 bits; here, the
|
||||||
|
* final unit of encoded output will be five characters followed by
|
||||||
|
* three "=" padding characters.
|
||||||
|
*
|
||||||
|
* (5) The final quantum of encoding input is exactly 32 bits; here, the
|
||||||
|
* final unit of encoded output will be seven characters followed by
|
||||||
|
* one "=" padding character.
|
||||||
|
*/
|
||||||
|
static size_t padlen(size_t remainder)
|
||||||
|
{
|
||||||
|
switch (remainder) {
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
|
case 1:
|
||||||
|
return 6;
|
||||||
|
case 2:
|
||||||
|
return 4;
|
||||||
|
case 3:
|
||||||
|
return 3;
|
||||||
|
case 4:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t base32_str_size(size_t bytes)
|
||||||
|
{
|
||||||
|
return (bytes + 4) / 5 * 8 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t base32_data_size(const char *str, size_t strlen)
|
||||||
|
{
|
||||||
|
/* 8 chars == 5 bytes, round up to avoid overflow even though
|
||||||
|
* not required for well-formed strings. */
|
||||||
|
size_t max = (strlen + 7) / 8 * 5, padding = 0;
|
||||||
|
|
||||||
|
/* Count trailing padding bytes. */
|
||||||
|
while (strlen && str[strlen-1] == base32_chars[32] && padding < 6) {
|
||||||
|
strlen--;
|
||||||
|
padding++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return max - (padding * 5 + 7) / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool decode_8_chars(const char c[8], beint64_t *res, int *bytes)
|
||||||
|
{
|
||||||
|
uint64_t acc = 0;
|
||||||
|
size_t num_pad = 0;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
const char *p;
|
||||||
|
|
||||||
|
acc <<= 5;
|
||||||
|
p = memchr(base32_chars, c[i], 32);
|
||||||
|
if (!p) {
|
||||||
|
if (c[i] == base32_chars[32]) {
|
||||||
|
num_pad++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Can't have padding then non-pad */
|
||||||
|
if (num_pad)
|
||||||
|
return false;
|
||||||
|
acc |= (p - base32_chars);
|
||||||
|
}
|
||||||
|
*res = cpu_to_be64(acc);
|
||||||
|
|
||||||
|
/* Can't have 2 or 5 padding bytes */
|
||||||
|
if (num_pad == 5 || num_pad == 2)
|
||||||
|
return false;
|
||||||
|
*bytes = (40 - num_pad * 5) / 8;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool base32_decode(const char *str, size_t slen, void *buf, size_t bufsize)
|
||||||
|
{
|
||||||
|
while (slen >= 8) {
|
||||||
|
beint64_t val;
|
||||||
|
int bytes;
|
||||||
|
if (!decode_8_chars(str, &val, &bytes))
|
||||||
|
return false;
|
||||||
|
str += 8;
|
||||||
|
slen -= 8;
|
||||||
|
/* Copy bytes into dst. */
|
||||||
|
if (bufsize < bytes)
|
||||||
|
return false;
|
||||||
|
memcpy(buf, (char *)&val + 3, bytes);
|
||||||
|
buf = (char *)buf + bytes;
|
||||||
|
bufsize -= bytes;
|
||||||
|
}
|
||||||
|
return slen == 0 && bufsize == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void encode_8_chars(char *dest, const uint8_t *buf, int bytes)
|
||||||
|
{
|
||||||
|
beint64_t val = 0;
|
||||||
|
uint64_t res;
|
||||||
|
int bits = bytes * 8;
|
||||||
|
|
||||||
|
assert(bytes > 0 && bytes <= 5);
|
||||||
|
memcpy((char *)&val + 3, buf, bytes);
|
||||||
|
res = be64_to_cpu(val);
|
||||||
|
|
||||||
|
while (bits > 0) {
|
||||||
|
*dest = base32_chars[(res >> 35) & 0x1F];
|
||||||
|
dest++;
|
||||||
|
res <<= 5;
|
||||||
|
bits -= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes != 5)
|
||||||
|
memset(dest, base32_chars[32], padlen(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool base32_encode(const void *buf, size_t bufsize, char *dest, size_t destsize)
|
||||||
|
{
|
||||||
|
while (bufsize) {
|
||||||
|
int bytes = 5;
|
||||||
|
|
||||||
|
if (bytes > bufsize)
|
||||||
|
bytes = bufsize;
|
||||||
|
|
||||||
|
if (destsize < 8)
|
||||||
|
return false;
|
||||||
|
encode_8_chars(dest, buf, bytes);
|
||||||
|
buf = (const char *)buf + bytes;
|
||||||
|
bufsize -= bytes;
|
||||||
|
destsize -= 8;
|
||||||
|
dest += 8;
|
||||||
|
}
|
||||||
|
if (destsize != 1)
|
||||||
|
return false;
|
||||||
|
*dest = '\0';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
77
ccan/ccan/str/base32/base32.h
Normal file
77
ccan/ccan/str/base32/base32.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/* CC0 (Public domain) - see LICENSE file for details */
|
||||||
|
#ifndef CCAN_STR_BASE32_H
|
||||||
|
#define CCAN_STR_BASE32_H
|
||||||
|
#include "config.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* base32_decode - Unpack a base32 string.
|
||||||
|
* @str: the base32 string
|
||||||
|
* @slen: the length of @str
|
||||||
|
* @buf: the buffer to write the data into
|
||||||
|
* @bufsize: the length of @buf
|
||||||
|
*
|
||||||
|
* Returns false if there are any characters which aren't valid encodings
|
||||||
|
* or the string wasn't the right length for @bufsize.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* unsigned char data[20];
|
||||||
|
*
|
||||||
|
* if (!base32_decode(argv[1], strlen(argv[1]), data, 20))
|
||||||
|
* printf("String is malformed!\n");
|
||||||
|
*/
|
||||||
|
bool base32_decode(const char *str, size_t slen, void *buf, size_t bufsize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* base32_encode - Create a nul-terminated base32 string
|
||||||
|
* @buf: the buffer to read the data from
|
||||||
|
* @bufsize: the length of @buf
|
||||||
|
* @dest: the string to fill
|
||||||
|
* @destsize: the max size of the string
|
||||||
|
*
|
||||||
|
* Returns true if the string, including terminator, fits in @destsize;
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* unsigned char buf[] = { 'f', 'o' };
|
||||||
|
* char str[9];
|
||||||
|
*
|
||||||
|
* if (!base32_encode(buf, sizeof(buf), str, sizeof(str)))
|
||||||
|
* abort();
|
||||||
|
*/
|
||||||
|
bool base32_encode(const void *buf, size_t bufsize, char *dest, size_t destsize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* base32_str_size - Calculate how big a nul-terminated base32 string is
|
||||||
|
* @bytes: bytes of data to represent
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* unsigned char buf[] = { 'f', 'o' };
|
||||||
|
* char str[base32_str_size(sizeof(buf))];
|
||||||
|
*
|
||||||
|
* base32_encode(buf, sizeof(buf), str, sizeof(str));
|
||||||
|
*/
|
||||||
|
size_t base32_str_size(size_t bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* base32_data_size - Calculate how many bytes of data in a base32 string
|
||||||
|
* @str: the string
|
||||||
|
* @strlen: the length of str to examine.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* const char str[] = "MZXQ====";
|
||||||
|
* unsigned char buf[base32_data_size(str, strlen(str))];
|
||||||
|
*
|
||||||
|
* base32_decode(str, strlen(str), buf, sizeof(buf));
|
||||||
|
*/
|
||||||
|
size_t base32_data_size(const char *str, size_t strlen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* base32_chars - the encoding/decoding array to use.
|
||||||
|
*
|
||||||
|
* It must be at least 33 characters long, representing 32 values and
|
||||||
|
* the pad value. The default array is "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=".
|
||||||
|
*/
|
||||||
|
extern const char *base32_chars;
|
||||||
|
|
||||||
|
#endif /* CCAN_STR_BASE32_H */
|
||||||
38
ccan/ccan/str/base32/test/run-lower.c
Normal file
38
ccan/ccan/str/base32/test/run-lower.c
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include <ccan/str/base32/base32.h>
|
||||||
|
/* Include the C files directly. */
|
||||||
|
#include <ccan/str/base32/base32.c>
|
||||||
|
#include <ccan/tap/tap.h>
|
||||||
|
|
||||||
|
static void test(const char *data, const char *b32)
|
||||||
|
{
|
||||||
|
char test[1000];
|
||||||
|
|
||||||
|
ok1(base32_str_size(strlen(data)) == strlen(b32) + 1);
|
||||||
|
ok1(base32_data_size(b32, strlen(b32)) == strlen(data));
|
||||||
|
ok1(base32_encode(data, strlen(data), test, strlen(b32)+1));
|
||||||
|
ok1(strcmp(test, b32) == 0);
|
||||||
|
test[strlen(data)] = '\0';
|
||||||
|
ok1(base32_decode(b32, strlen(b32), test, strlen(data)));
|
||||||
|
ok1(strcmp(test, data) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
/* This is how many tests you plan to run */
|
||||||
|
plan_tests(8 * 6);
|
||||||
|
|
||||||
|
base32_chars = "abcdefghijklmnopqrstuvwxyz234567=";
|
||||||
|
|
||||||
|
/* Test vectors from RFC, but lower-case */
|
||||||
|
test("", "");
|
||||||
|
test("f", "my======");
|
||||||
|
test("fo", "mzxq====");
|
||||||
|
test("foo", "mzxw6===");
|
||||||
|
test("foob", "mzxw6yq=");
|
||||||
|
test("fooba", "mzxw6ytb");
|
||||||
|
test("r", "oi======");
|
||||||
|
test("foobar", "mzxw6ytboi======");
|
||||||
|
|
||||||
|
/* This exits depending on whether all tests passed */
|
||||||
|
return exit_status();
|
||||||
|
}
|
||||||
36
ccan/ccan/str/base32/test/run.c
Normal file
36
ccan/ccan/str/base32/test/run.c
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#include <ccan/str/base32/base32.h>
|
||||||
|
/* Include the C files directly. */
|
||||||
|
#include <ccan/str/base32/base32.c>
|
||||||
|
#include <ccan/tap/tap.h>
|
||||||
|
|
||||||
|
static void test(const char *data, const char *b32)
|
||||||
|
{
|
||||||
|
char test[1000];
|
||||||
|
|
||||||
|
ok1(base32_str_size(strlen(data)) == strlen(b32) + 1);
|
||||||
|
ok1(base32_data_size(b32, strlen(b32)) == strlen(data));
|
||||||
|
ok1(base32_encode(data, strlen(data), test, strlen(b32)+1));
|
||||||
|
ok1(strcmp(test, b32) == 0);
|
||||||
|
test[strlen(data)] = '\0';
|
||||||
|
ok1(base32_decode(b32, strlen(b32), test, strlen(data)));
|
||||||
|
ok1(strcmp(test, data) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
/* This is how many tests you plan to run */
|
||||||
|
plan_tests(8 * 6);
|
||||||
|
|
||||||
|
/* Test vectors from RFC */
|
||||||
|
test("", "");
|
||||||
|
test("f", "MY======");
|
||||||
|
test("fo", "MZXQ====");
|
||||||
|
test("foo", "MZXW6===");
|
||||||
|
test("foob", "MZXW6YQ=");
|
||||||
|
test("fooba", "MZXW6YTB");
|
||||||
|
test("r", "OI======");
|
||||||
|
test("foobar", "MZXW6YTBOI======");
|
||||||
|
|
||||||
|
/* This exits depending on whether all tests passed */
|
||||||
|
return exit_status();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user