roken: Add base32

This commit is contained in:
Nicolas Williams
2020-01-13 19:46:13 -06:00
parent 5ab1a2b7a6
commit 77619f245d
6 changed files with 497 additions and 1 deletions

View File

@@ -20,11 +20,12 @@ if HAVE_DBHEADER
AM_CPPFLAGS += -I$(DBHEADER)
endif
noinst_PROGRAMS = snprintf-test resolve-test rkpty test-detach test-auxval rkvis rkbase64
noinst_PROGRAMS = snprintf-test resolve-test rkpty test-detach test-auxval rkvis rkbase32 rkbase64
CHECK_LOCAL = snprintf-test resolve-test rkpty make-roken
check_PROGRAMS = \
base32-test \
base64-test \
getaddrinfo-test \
getifaddrs-test \
@@ -60,6 +61,9 @@ test_getuserinfo_LDADD = libtest.la $(LDADD)
rkvis_SOURCES = vis.c
rkvis_CPPFLAGS = -DTEST
rkbase32_SOURCES = base32.c
rkbase32_CPPFLAGS = -DTEST
rkbase64_SOURCES = base64.c
rkbase64_CPPFLAGS = -DTEST
@@ -82,6 +86,7 @@ tsearch_test_CFLAGS = -DTEST_TSEARCH
resolve_test_SOURCES = resolve-test.c
libroken_la_SOURCES = \
base32.c \
base64.c \
bswap.c \
concat.c \
@@ -191,6 +196,7 @@ XHEADERS = $(err_h) $(fnmatch_h) $(ifaddrs_h) $(search_h) $(vis_h)
CLEANFILES += err.h fnmatch.h ifaddrs.h search.h vis.h
dist_include_HEADERS = \
base32.h \
base64.h \
getarg.h \
hex.h \

View File

@@ -34,6 +34,7 @@ RELDIR=lib\roken
!include ../../windows/NTMakefile.w32
libroken_la_OBJS = \
$(OBJ)\base32.obj \
$(OBJ)\base64.obj \
$(OBJ)\bswap.obj \
$(OBJ)\concat.obj \
@@ -155,6 +156,7 @@ $(INCDIR)\roken.h: $(OBJ)\make-roken.exe
$(OBJ)\make-roken.exe > $@ || $(RM) $@
INCFILES = \
$(INCDIR)\base32.h \
$(INCDIR)\base64.h \
$(INCDIR)\dirent.h \
$(INCDIR)\dlfcn.h \
@@ -193,6 +195,7 @@ TMP_PROGS = $(OBJ)\snprintf-test.exe $(OBJ)\resolve-test.exe $(OBJ)\test-getuser
# Tests
TEST_PROGS = \
$(OBJ)\base32-test.exe \
$(OBJ)\base64-test.exe \
$(OBJ)\getaddrinfo-test.exe \
$(OBJ)\getifaddrs-test.exe \
@@ -250,6 +253,9 @@ $(OBJ)\snprintf-test.exe: $(OBJ)\snprintf-test.obj $(OBJ)\libtest.lib $(LIBROKEN
$(OBJ)\resolve-test.exe: $(OBJ)\resolve-test.obj $(LIBROKEN)
$(EXECONLINK) DnsAPI.lib
$(OBJ)\base32-test.exe: $(OBJ)\base32-test.obj $(OBJ)\base32.obj $(LIBROKEN)
$(EXECONLINK)
$(OBJ)\base64-test.exe: $(OBJ)\base64-test.obj $(OBJ)\base64.obj $(LIBROKEN)
$(EXECONLINK)
@@ -283,6 +289,7 @@ test-run:
cd $(OBJ)
-test-mini_inetd.exe
-dirent-test.exe
-base32-test.exe
-base64-test.exe
-getaddrinfo-test.exe www.h5l.org http
-getifaddrs-test.exe

105
lib/roken/base32-test.c Normal file
View File

@@ -0,0 +1,105 @@
/*
* Copyright (c) 1999 - 2001 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <config.h>
#include "roken.h"
#include <base32.h>
int
main(int argc, char **argv)
{
int numerr = 0;
int numtest = 1;
struct test {
int preserve_order;
void *data;
size_t len;
const char *result;
} *t, tests[] = {
{ 0, "", 0 , "" },
{ 0, "f", 1, "MY======" },
{ 0, "fo", 2, "MZXQ====" },
{ 0, "foo", 3, "MZXW6===" },
{ 0, "foob", 4, "MZXW6YQ=" },
{ 0, "fooba", 5, "MZXW6YTB" },
{ 0, "foobar", 6, "MZXW6YTBOI======" },
{ 1, "", 0 , "" },
{ 1, "f", 1, "CO======" },
{ 1, "fo", 2, "CPNG====" },
{ 1, "foo", 3, "CPNMU===" },
{ 1, "foob", 4, "CPNMUOG=" },
{ 1, "fooba", 5, "CPNMUOJ1" },
{ 1, "foobar", 6, "CPNMUOJ1E8======" },
{ 0, NULL, 0, NULL }
};
for(t = tests; t->data; t++) {
char *str;
int len;
len = rk_base32_encode(t->data, t->len, &str, t->preserve_order);
if (strcmp(str, t->result) != 0) {
fprintf(stderr, "failed test %d: %s != %s\n", numtest,
str, t->result);
numerr++;
}
free(str);
str = strdup(t->result);
len = rk_base32_decode(t->result, str, t->preserve_order);
if (len != t->len) {
fprintf(stderr, "failed test %d: len %lu != %lu\n", numtest,
(unsigned long)len, (unsigned long)t->len);
numerr++;
} else if(memcmp(str, t->data, t->len) != 0) {
fprintf(stderr, "failed test %d: data\n", numtest);
numerr++;
}
free(str);
numtest++;
}
{
char str[32];
if (rk_base32_decode("M=M=", str, 1) != -1) {
fprintf(stderr, "failed test %d: successful decode of `M=M='\n",
numtest++);
numerr++;
}
if (rk_base32_decode("MQ===", str, 1) != -1) {
fprintf(stderr, "failed test %d: successful decode of `MQ==='\n",
numtest++);
numerr++;
}
}
return numerr;
}

315
lib/roken/base32.c Normal file
View File

@@ -0,0 +1,315 @@
/*
* Copyright (c) 2020 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <config.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#ifdef TEST
#include <stdio.h>
#include <getarg.h>
#include <err.h>
#endif
#include "base32.h"
#include "roken.h"
static const unsigned char base32_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
static const unsigned char base32op_chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_base32_encode(const void *data, int size, char **str, enum rk_base32_flags flags)
{
const unsigned char *chars =
(flags & RK_BASE32_FLAG_PRESERVE_ORDER) ? base32op_chars :
base32_chars;
uint64_t c;
char *s, *p;
int i;
const unsigned char *q;
if (size > INT_MAX/8 || size < 0) {
*str = NULL;
errno = ERANGE;
return -1;
}
p = s = malloc(((size + 5 - 1) / 5) * 8 + 1);
if (p == NULL) {
*str = NULL;
return -1;
}
q = (const unsigned char *) data;
for (i = 0; i < size;) {
/* 5 bytes of input will give us 8 output bytes' worth of bits */
c = q[i++];
c <<= 8;
if (i < size)
c += q[i];
i++;
c <<= 8;
if (i < size)
c += q[i];
i++;
c <<= 8;
if (i < size)
c += q[i];
i++;
c <<= 8;
if (i < size)
c += q[i];
i++;
p[0] = chars[(c & 0x00000000f800000000ULL) >> 35];
p[1] = chars[(c & 0x0000000007c0000000ULL) >> 30];
p[2] = chars[(c & 0x00000000003e000000ULL) >> 25];
p[3] = chars[(c & 0x000000000001f00000ULL) >> 20];
p[4] = chars[(c & 0x0000000000000f8000ULL) >> 15];
p[5] = chars[(c & 0x000000000000007c00ULL) >> 10];
p[6] = chars[(c & 0x0000000000000003e0ULL) >> 5];
p[7] = chars[(c & 0x00000000000000001fULL) >> 0];
switch (i - size) {
case 4: p[2] = p[3] = '='; /*fallthrough*/
case 3: p[4] = '='; /*fallthrough*/
case 2: p[5] = p[6] = '='; /*fallthrough*/
case 1: p[7] = '='; /*fallthrough*/
default: break;
}
p += 8;
}
*p = 0;
*str = s;
return (int) strlen(s);
}
#define DECODE_ERROR ((uint64_t)-1)
static int
pos(char c, int preserve_order)
{
/* EBCDIC need not apply */
if (preserve_order) {
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'A' && c <= 'V')
return c - 'A' + ('9' - '0') + 1;
} else {
if (c >= 'A' && c <= 'Z')
return c - 'A';
if (c >= '2' && c <= '7')
return c - '2' + ('Z' - 'A') + 1;
}
return -1;
}
static uint64_t
token_decode(const char *token, enum rk_base32_flags flags)
{
uint64_t marker = 0;
uint64_t val = 0;
int preserve_order = !!(flags & RK_BASE32_FLAG_PRESERVE_ORDER);
int i, c;
if (strlen(token) < 8)
return DECODE_ERROR;
for (i = 0; i < 8; i++) {
val <<= 5;
if (token[i] == '=')
marker++;
else if (marker)
return DECODE_ERROR;
else if ((c = pos(token[i], preserve_order)) == -1 &&
(flags & RK_BASE32_FLAG_STOP_ON_GARBAGE))
break;
else if (c == -1)
return DECODE_ERROR;
else
val |= c;
}
if (marker > 6)
return DECODE_ERROR;
return (marker << 40) | val;
}
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_base32_decode(const char *str, void *data, enum rk_base32_flags flags)
{
const char *p;
unsigned char *q;
int preserve_order = !!(flags & RK_BASE32_FLAG_PRESERVE_ORDER);
q = data;
for (p = str; *p && (*p == '=' || pos(*p, preserve_order) != -1); p += 8) {
uint64_t val = token_decode(p, flags);
uint64_t marker = (val >> 40) & 0xffULL;
if (val == DECODE_ERROR) {
errno = EINVAL;
return -1;
}
*q++ = (val >> 32) & 0xffULL;
if (marker < 6)
*q++ = (val >> 24) & 0xffULL;
if (marker < 4)
*q++ = (val >> 16) & 0xffULL;
if (marker < 3)
*q++ = (val >> 8) & 0xffULL;
if (marker < 1)
*q++ = val & 0xffULL;
if (marker && !(flags & RK_BASE32_FLAG_INTERIOR_PADDING_OK))
break;
}
if (q - (unsigned char *) data > INT_MAX) {
errno = EOVERFLOW;
return -1;
}
return q - (unsigned char *) data;
}
#ifdef TEST
static int interior_padding_ok;
static int preserve_order_flag;
static int stop_on_garbage;
static int decode_flag;
static int help_flag;
/*
* The short options are compatible with a subset of the FreeBSD contrib
* vis(1). Heimdal additions have long option names only.
*/
static struct getargs args[] = {
{ "preserve-order", 'P', arg_flag, &preserve_order_flag,
"Use order-preserving alphabet", NULL },
{ "interior-padding-ok", 'O', arg_flag, &interior_padding_ok,
"Decode concatenated padded base32 strings as one", NULL },
{ "stop-on-garbage", 'G', arg_flag, &stop_on_garbage,
"Do not error on garbage", NULL },
{ "decode", 'd', arg_flag, &decode_flag, "Decode", NULL },
{ "help", 'h', arg_flag, &help_flag, "Print help message", NULL },
};
static size_t num_args = sizeof(args)/sizeof(args[0]);
int
main(int argc, char **argv)
{
enum rk_base32_flags flags = 0;
unsigned char *buf = NULL;
size_t buflen = 0;
size_t bufsz = 0;
int goptind = 0;
int ret;
setprogname("rkbase32");
if (getarg(args, num_args, argc, argv, &goptind) || help_flag) {
arg_printusage(args, num_args, NULL, "FILE | -");
return help_flag ? 0 : 1;
}
argc -= goptind;
argv += goptind;
flags |= preserve_order_flag ? RK_BASE32_FLAG_PRESERVE_ORDER : 0;
flags |= interior_padding_ok ? RK_BASE32_FLAG_INTERIOR_PADDING_OK : 0;
flags |= stop_on_garbage ? RK_BASE32_FLAG_STOP_ON_GARBAGE : 0;
if (help_flag)
return arg_printusage(args, num_args, NULL, "FILE | -- -"), 0;
if (argc != 1)
return arg_printusage(args, num_args, NULL, "FILE | -- -"), 1;
if (strcmp(argv[0], "-") == 0) {
unsigned char *tmp;
unsigned char d[4096];
size_t bytes;
while (!feof(stdin) && !ferror(stdin)) {
bytes = fread(d, 1, sizeof(d), stdin);
if (bytes == 0)
continue;
if (buflen + bytes > bufsz) {
if ((tmp = realloc(buf, bufsz + (bufsz >> 2) + sizeof(d))) == NULL)
err(1, "Could not read stdin");
buf = tmp;
bufsz = bufsz + (bufsz >> 2) + sizeof(d);
}
memcpy(buf + buflen, d, bytes);
buflen += bytes;
}
if (ferror(stdin))
err(1, "Could not read stdin");
} else {
void *d;
if ((ret = rk_undumpdata(argv[0], &d, &bufsz)))
err(1, "Could not read %s", argv[0]);
buflen = bufsz;
buf = d;
}
if (decode_flag) {
unsigned char *d;
if (buflen == bufsz) {
unsigned char *tmp;
if ((tmp = realloc(buf, bufsz + 1)) == NULL)
err(1, "Could not decode data");
buf = tmp;
bufsz++;
}
buf[buflen] = '\0';
if ((d = malloc(buflen * 5 / 8 + 4)) == NULL)
err(1, "Could not decode data");
if ((ret = rk_base32_decode((const char *)buf, d, flags)) < 0)
err(1, "Could not decode data");
if (fwrite(d, ret, 1, stdout) != 1)
err(1, "Could not write decoded data");
free(d);
} else {
char *e;
if ((ret = rk_base32_encode(buf, buflen, &e, flags)) < 0)
err(1, "Could not encode data");
if (fwrite(e, ret, 1, stdout) != 1)
err(1, "Could not write decoded data");
free(e);
if (fwrite("\n", 1, 1, stdout) != 1)
err(1, "Could not write decoded data");
}
free(buf);
return 0;
}
#endif

61
lib/roken/base32.h Normal file
View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* $Id$ */
#ifndef _BASE32_H_
#define _BASE32_H_
#ifndef ROKEN_LIB_FUNCTION
#ifdef _WIN32
#define ROKEN_LIB_FUNCTION
#define ROKEN_LIB_CALL __cdecl
#else
#define ROKEN_LIB_FUNCTION
#define ROKEN_LIB_CALL
#endif
#endif
enum rk_base32_flags {
RK_BASE32_FLAG_PRESERVE_ORDER = 1,
RK_BASE32_FLAG_STOP_ON_GARBAGE = 2,
RK_BASE32_FLAG_INTERIOR_PADDING_OK = 4,
};
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_base32_encode(const void *, int, char **, enum rk_base32_flags);
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_base32_decode(const char *, void *, enum rk_base32_flags);
#endif

View File

@@ -33,6 +33,8 @@ HEIMDAL_ROKEN_2.0 {
print_units_table;
rk_asnprintf;
rk_asprintf;
rk_base32_decode;
rk_base32_encode;
rk_base64_decode;
rk_base64_encode;
rk_bswap16;