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-rbuf.o \
|
||||
ccan-read_write_all.o \
|
||||
ccan-str-base32.o \
|
||||
ccan-str-hex.o \
|
||||
ccan-str.o \
|
||||
ccan-take.o \
|
||||
@@ -138,6 +139,7 @@ CCAN_HEADERS := \
|
||||
$(CCANDIR)/ccan/rbuf/rbuf.h \
|
||||
$(CCANDIR)/ccan/read_write_all/read_write_all.h \
|
||||
$(CCANDIR)/ccan/short_types/short_types.h \
|
||||
$(CCANDIR)/ccan/str/base32/base32.h \
|
||||
$(CCANDIR)/ccan/str/hex/hex.h \
|
||||
$(CCANDIR)/ccan/str/str.h \
|
||||
$(CCANDIR)/ccan/str/str_debug.h \
|
||||
@@ -549,3 +551,5 @@ ccan-bitops.o: $(CCANDIR)/ccan/bitops/bitops.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
ccan-rbuf.o: $(CCANDIR)/ccan/rbuf/rbuf.c
|
||||
$(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