Skip to content

Commit 140ee61

Browse files
committed
feature: base32hex(Extended Hex Alphabet) support
1 parent 11c50ab commit 140ee61

7 files changed

Lines changed: 394 additions & 49 deletions

File tree

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ Table of Contents
2121
* [decode_base16](#decode_base16)
2222
* [encode_base32](#encode_base32)
2323
* [decode_base32](#decode_base32)
24+
* [encode_base32hex](#encode_base32hex)
25+
* [decode_base32hex](#decode_base32hex)
2426
* [encode_base64](#encode_base64)
2527
* [decode_base64](#decode_base64)
2628
* [encode_base64url](#encode_base64url)
@@ -95,6 +97,22 @@ Decode base32 format string into its raw value. If the given string is not valid
9597

9698
[Back to TOC](#table-of-contents)
9799

100+
### encode_base32hex
101+
`syntax: encoded = encode_base32hex(raw[, no_padding])`
102+
103+
Encode given string into base32hex format with/without padding '='. The default value of `no_padding` is false.
104+
For more info of base32hex format, see https://tools.ietf.org/html/rfc4648#section-7.
105+
106+
[Back to TOC](#table-of-contents)
107+
108+
### decode_base32hex
109+
`syntax: raw, err = decode_base32(encoded)`
110+
111+
Decode base32hex format string into its raw value. If the given string is not valid base32hex encoded, the `raw` will be `nil` and `err` will be `"invalid input"`.
112+
For more info of base32hex format, see https://tools.ietf.org/html/rfc4648#section-7.
113+
114+
[Back to TOC](#table-of-contents)
115+
98116
### encode_base64
99117
### decode_base64
100118
### encode_base64url

b32_data.h

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
#define CHARPAD '='
44
#define BADCHAR 0xff
55

6-
// rfc4648 version of base32
7-
static const char *e = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=";
6+
/* rfc4648 std version of base32 */
7+
static const char *std_encode_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=";
88

9-
static const char d[256] = {
9+
static const char std_decode_table[256] = {
1010
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
1111
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
1212
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
@@ -40,3 +40,44 @@ static const char d[256] = {
4040
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
4141
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
4242
};
43+
44+
45+
/* "Extended Hex Alphabet" version of base32,
46+
* https://tools.ietf.org/html/rfc4648#section-7
47+
*/
48+
static const char *hex_encode_table = "0123456789ABCDEFGHIJKLMNOPQRSTUV=";
49+
50+
static const char hex_decode_table[256] = {
51+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
52+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
53+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
54+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
55+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
56+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
57+
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
58+
0x8, 0x9, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
59+
BADCHAR, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
60+
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
61+
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, BADCHAR,
62+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
63+
BADCHAR, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10,
64+
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
65+
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, BADCHAR,
66+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
67+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
68+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
69+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
70+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
71+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
72+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
73+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
74+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
75+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
76+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
77+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
78+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
79+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
80+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
81+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
82+
BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR, BADCHAR,
83+
};

base32.c

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@
88
#define OUT_BLOCK_LEN 8
99

1010

11-
size_t b32_encode(char *dest, const char *src, size_t len, uint32_t no_padding)
11+
size_t b32_encode(char *dest, const char *src, size_t len, uint32_t no_padding,
12+
uint32_t hex)
1213
{
1314
unsigned char n1, n2, n3, n4, n5, n6, n7, n8;
1415
const uint8_t *s = (const uint8_t*)src;
1516
uint8_t *p = (uint8_t*)dest;
1617

18+
const char *encode_table = (hex == 0) ? std_encode_table : hex_encode_table;
19+
1720
while (likely(len >= IN_BLOCK_LEN)) {
1821
n8 = (s[4] & 0x1f);
1922
n7 = ((s[4] & 0xe0) >> 5) | ((s[3] & 0x03) << 3);
@@ -24,14 +27,14 @@ size_t b32_encode(char *dest, const char *src, size_t len, uint32_t no_padding)
2427
n2 = ((s[1] & 0xc0) >> 6) | ((s[0] & 0x07) << 2);
2528
n1 = ((s[0] & 0xf8) >> 3);
2629

27-
*p++ = e[n1];
28-
*p++ = e[n2];
29-
*p++ = e[n3];
30-
*p++ = e[n4];
31-
*p++ = e[n5];
32-
*p++ = e[n6];
33-
*p++ = e[n7];
34-
*p++ = e[n8];
30+
*p++ = encode_table[n1];
31+
*p++ = encode_table[n2];
32+
*p++ = encode_table[n3];
33+
*p++ = encode_table[n4];
34+
*p++ = encode_table[n5];
35+
*p++ = encode_table[n6];
36+
*p++ = encode_table[n7];
37+
*p++ = encode_table[n8];
3538

3639
s += IN_BLOCK_LEN;
3740
len -= IN_BLOCK_LEN;
@@ -46,29 +49,29 @@ size_t b32_encode(char *dest, const char *src, size_t len, uint32_t no_padding)
4649
n7 = ((s[3] & 0x03) << 3);
4750
n6 = ((s[3] & 0x7c) >> 2);
4851
n5 = ((s[3] & 0x80) >> 7);
49-
p[6] = e[n7];
50-
p[5] = e[n6];
52+
p[6] = encode_table[n7];
53+
p[5] = encode_table[n6];
5154
step += 2;
5255
/* fall through */
5356
case 3:
5457
n5 |= ((s[2] & 0x0f) << 1);
5558
n4 = ((s[2] & 0xf0) >> 4);
56-
p[4] = e[n5];
59+
p[4] = encode_table[n5];
5760
step += 1;
5861
/* fall through */
5962
case 2:
6063
n4 |= ((s[1] & 0x01) << 4);
6164
n3 = ((s[1] & 0x3e) >> 1);
6265
n2 = ((s[1] & 0xc0) >> 6);
63-
p[3] = e[n4];
64-
p[2] = e[n3];
66+
p[3] = encode_table[n4];
67+
p[2] = encode_table[n3];
6568
step += 2;
6669
/* fall through */
6770
case 1:
6871
n2 |= ((s[0] & 0x07) << 2);
6972
n1 = ((s[0] & 0xf8) >> 3);
70-
p[1] = e[n2];
71-
p[0] = e[n1];
73+
p[1] = encode_table[n2];
74+
p[0] = encode_table[n1];
7275
step += 2;
7376
break;
7477
case 0:
@@ -86,12 +89,14 @@ size_t b32_encode(char *dest, const char *src, size_t len, uint32_t no_padding)
8689
}
8790

8891

89-
size_t b32_decode(char *dest, const char *src, size_t len)
92+
size_t b32_decode(char *dest, const char *src, size_t len, uint32_t hex)
9093
{
9194
unsigned char in1, in2, in3, in4, in5, in6, in7, in8;
9295
const unsigned char *s = (const unsigned char*)src;
9396
unsigned char *p = (unsigned char*)dest;
9497

98+
const char *decode_table = (hex == 0) ? std_decode_table : hex_decode_table;
99+
95100
if (src[len - 1] == CHARPAD) {
96101
/*
97102
* if padding is used, then the message must be at least
@@ -113,14 +118,14 @@ size_t b32_decode(char *dest, const char *src, size_t len)
113118
}
114119

115120
while (likely(len >= OUT_BLOCK_LEN)) {
116-
in1 = d[*s++];
117-
in2 = d[*s++];
118-
in3 = d[*s++];
119-
in4 = d[*s++];
120-
in5 = d[*s++];
121-
in6 = d[*s++];
122-
in7 = d[*s++];
123-
in8 = d[*s++];
121+
in1 = decode_table[*s++];
122+
in2 = decode_table[*s++];
123+
in3 = decode_table[*s++];
124+
in4 = decode_table[*s++];
125+
in5 = decode_table[*s++];
126+
in6 = decode_table[*s++];
127+
in7 = decode_table[*s++];
128+
in8 = decode_table[*s++];
124129

125130
/* faster than memchr */
126131
if (unlikely(in1 == BADCHAR || in2 == BADCHAR || in3 == BADCHAR
@@ -142,35 +147,35 @@ size_t b32_decode(char *dest, const char *src, size_t len)
142147
int step = 0;
143148
unsigned int i;
144149
for (i = 0; i < len; i++) {
145-
if ((unsigned char)d[s[i]] == BADCHAR) {
150+
if ((unsigned char)decode_table[s[i]] == BADCHAR) {
146151
return -1;
147152
}
148153
}
149154

150155
switch(len) {
151156
case 7:
152-
in5 = d[s[4]];
153-
in6 = d[s[5]];
154-
in7 = d[s[6]];
157+
in5 = decode_table[s[4]];
158+
in6 = decode_table[s[5]];
159+
in7 = decode_table[s[6]];
155160
p[3] = ((in5 & 0x01) << 7) | ((in6 & 0x1f) << 2) | ((in7 & 0x18) >> 3);
156161
step++;
157162
/* fall through */
158163
case 5:
159-
in5 = d[s[4]];
160-
in4 = d[s[3]];
164+
in5 = decode_table[s[4]];
165+
in4 = decode_table[s[3]];
161166
p[2] = ((in4 & 0x0f) << 4) | ((in5 & 0x1e) >> 1);
162167
step++;
163168
/* fall through */
164169
case 4:
165-
in4 = d[s[3]];
166-
in3 = d[s[2]];
167-
in2 = d[s[1]];
170+
in4 = decode_table[s[3]];
171+
in3 = decode_table[s[2]];
172+
in2 = decode_table[s[1]];
168173
p[1] = ((in2 & 0x03) << 6) | ((in3 & 0x1f) << 1) | ((in4 & 0x10) >> 4);
169174
step++;
170175
/* fall through */
171176
case 2:
172-
in2 = d[s[1]];
173-
in1 = d[s[0]];
177+
in2 = decode_table[s[1]];
178+
in1 = decode_table[s[0]];
174179
p[0] = ((in1 & 0x1f) << 3) | ((in2 & 0x1c) >> 2);
175180
step++;
176181
case 0:

lib/resty/base_encoding.lua

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ size_t modp_b64_encode(char* dest, const char* str, size_t len,
4040
size_t modp_b64_decode(char* dest, const char* src, size_t len);
4141
size_t modp_b64w_encode(char* dest, const char* str, size_t len);
4242
size_t modp_b64w_decode(char* dest, const char* src, size_t len);
43-
size_t b32_encode(char* dest, const char* src, size_t len, uint32_t no_padding);
44-
size_t b32_decode(char* dest, const char* src, size_t len);
43+
size_t b32_encode(char* dest, const char* src, size_t len, uint32_t no_padding,
44+
uint32_t hex);
45+
size_t b32_decode(char* dest, const char* src, size_t len, uint32_t hex);
4546
size_t modp_b16_encode(char* dest, const char* str, size_t len,
4647
uint32_t out_in_lowercase);
4748
size_t modp_b16_decode(char* dest, const char* src, size_t len);
@@ -138,7 +139,7 @@ local function base32_encoded_length(len)
138139
end
139140

140141

141-
function _M.encode_base32(s, no_padding)
142+
local function encode_base32(s, no_padding, hex)
142143
if type(s) ~= 'string' then
143144
error("must provide a string")
144145
end
@@ -147,17 +148,25 @@ function _M.encode_base32(s, no_padding)
147148
local no_padding_int = no_padding and 1 or 0
148149
local dlen = base32_encoded_length(slen)
149150
local dst = get_string_buf(dlen)
150-
local r_dlen = encoding.b32_encode(dst, s, slen, no_padding_int)
151+
local r_dlen = encoding.b32_encode(dst, s, slen, no_padding_int, hex)
151152
return ffi_string(dst, r_dlen)
152153
end
153154

155+
function _M.encode_base32(s, no_padding)
156+
return encode_base32(s, no_padding, 0)
157+
end
158+
159+
function _M.encode_base32hex(s, no_padding)
160+
return encode_base32(s, no_padding, 1)
161+
end
162+
154163

155164
local function base32_decoded_length(len)
156165
return floor(len * 5 / 8)
157166
end
158167

159168

160-
function _M.decode_base32(s)
169+
local function decode_base32(s, hex)
161170
if type(s) ~= 'string' then
162171
error("must provide a string")
163172
end
@@ -169,13 +178,21 @@ function _M.decode_base32(s)
169178

170179
local dlen = base32_decoded_length(slen)
171180
local dst = get_string_buf(dlen)
172-
local r_dlen = encoding.b32_decode(dst, s, slen)
181+
local r_dlen = encoding.b32_decode(dst, s, slen, hex)
173182
if r_dlen == -1 then
174183
return nil, "invalid input"
175184
end
176185
return ffi_string(dst, r_dlen)
177186
end
178187

188+
function _M.decode_base32(s)
189+
return decode_base32(s, 0)
190+
end
191+
192+
function _M.decode_base32hex(s)
193+
return decode_base32(s, 1)
194+
end
195+
179196

180197
local function base16_encoded_length(len)
181198
return len * 2

t/base16.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ decode: aaaaaR: invalid input
151151
=== TEST 6: random tests
152152
--- lua
153153
local start = ngx.now()
154-
while ture do
154+
while true do
155155
for _ = 1, 1000 do
156156
local size = math.random(1, 20)
157157
local buf = table.new(size, 0)

0 commit comments

Comments
 (0)