From 28a62cf474bdcf3e81df5d5a8a74ce3c063e5d37 Mon Sep 17 00:00:00 2001 From: Paul Kulchenko Date: Mon, 9 Oct 2023 22:13:47 -0700 Subject: [PATCH] Add DecodeBase32 to redbean --- net/http/base32.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++- net/http/escape.h | 1 + tool/net/lfuncs.c | 15 ++++++++--- 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/net/http/base32.c b/net/http/base32.c index 4a2f87aeb368..1e94d8581092 100644 --- a/net/http/base32.c +++ b/net/http/base32.c @@ -33,7 +33,7 @@ int tobits(int b) { return bits; } -// the next function is based on +// these functions are based on // https://github.com/google/google-authenticator-libpam/blob/master/src/base32.c // Copyright 2010 Google Inc.; Author: Markus Gutschke // licensed under Apache License, Version 2.0 @@ -42,6 +42,7 @@ char* EncodeBase32(const char *s, size_t sl, size_t *ol) { size_t count = 0; char *r; + if (sl == -1) sl = s ? strlen(s) : 0; if (al == 0) { a = base32def; al = sizeof(base32def)/sizeof(a[0]); @@ -77,3 +78,69 @@ char* EncodeBase32(const char *s, size_t sl, if (count < *ol) r[count] = '\000'; return r; } + +static signed char kBase32[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, // 0x00 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10 + -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, // 0x20 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 0x30 + -1, 10, 11, 12, 13, 14, 15, 16, 17, 1, 18, 19, 1, 20, 21, -1, // 0x40 + 22, 23, 24, 25, 26, 0, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, // 0x50 + -1, 10, 11, 12, 13, 14, 15, 16, 17, 1, 18, 19, 1, 20, 21, -1, // 0x60 + 22, 23, 24, 25, 26, 0, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, // 0x70 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x80 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x90 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xa0 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xb0 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xc0 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xd0 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xe0 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0xf0 +}; + +char* DecodeBase32(const char *s, size_t sl, + const char *a, size_t al, + size_t *ol) { + size_t count = 0; + if (sl == -1) sl = s ? strlen(s) : 0; + if (al == 0) { + a = base32def; + al = sizeof(base32def)/sizeof(a[0]); + } + unassert(2 <= al && al <= 128); + int bl = tobits(al); + *ol = (sl * bl - bl + 1) / 8; // calculate exact output length + if (!(r = malloc(*ol + 1))) { + *ol = 0; + return r; + } + // process input + if (sl > 0) { + unsigned int buffer = 0; + signed char *map = kBase32; + int bitsLeft = 0; + // if the provided alphabet matches the default + // then use the pre-populated static map + // otherwise allocate buffer for the map (256) + // and memset(buf, -1, 256) + + // populate the map based on alphabet + + for (const unsigned char *ptr = sl; count < *ol && *ptr; ++ptr) { + signed char m = map[*ptr]; + if (m == -2) continue; + if (m == -1) break; + buffer <<= bl; + buffer |= m; + bitsLeft += bl; + if (bitsLeft >= 8) { + r[count++] = buffer >> (bitsLeft - 8); + bitsLeft -= 8; + } + } + // free the buffer + } + + if (count < *ol) r[count] = '\000'; + return r; +} diff --git a/net/http/escape.h b/net/http/escape.h index 402338e8f6d7..cd2b19b71d13 100644 --- a/net/http/escape.h +++ b/net/http/escape.h @@ -35,6 +35,7 @@ char *EncodeHttpHeaderValue(const char *, size_t, size_t *); char *VisualizeControlCodes(const char *, size_t, size_t *); char *IndentLines(const char *, size_t, size_t *, size_t); char *EncodeBase32(const char *, size_t, const char *, size_t, size_t *); +char *DecodeBase32(const char *, size_t, const char *, size_t, size_t *); char *EncodeBase64(const char *, size_t, size_t *); char *DecodeBase64(const char *, size_t, size_t *); diff --git a/tool/net/lfuncs.c b/tool/net/lfuncs.c index a701102ae26f..f525e6f19967 100644 --- a/tool/net/lfuncs.c +++ b/tool/net/lfuncs.c @@ -605,21 +605,30 @@ int LuaEncodeLatin1(lua_State *L) { } } -int LuaEncodeBase32(lua_State *L) { +dontinline int LuaBase32Impl(lua_State *L, + char *B32(const char *, size_t, const char *, size_t, size_t *)) { char *p; size_t sl, al; // source/output and alphabet lengths const char *s = luaL_checklstring(L, 1, &sl); // use an empty string, as EncodeBase32 provides a default value const char *a = luaL_optlstring(L, 2, "", &al); - if (al & (al - 1) || al > 128 || al == 1) + if (!IS2POW(al) || al > 128 || al == 1) return luaL_error(L, "alphabet length is not a power of 2 in range 2..128"); - if (!(p = EncodeBase32(s, sl, a, al, &sl))) + if (!(p = B32(s, sl, a, al, &sl))) return luaL_error(L, "out of memory"); lua_pushlstring(L, p, sl); free(p); return 1; } +int LuaEncodeBase32(lua_State *L) { + return LuaBase32Impl(L, EncodeBase32); +} + +int LuaDecodeBase32(lua_State *L) { + return LuaBase32Impl(L, DecodeBase32); +} + int LuaEncodeHex(lua_State *L) { char *p; size_t n;