Skip to content

Commit 4cfd3d0

Browse files
committed
更新base64实现
1 parent 6f60cee commit 4cfd3d0

File tree

1 file changed

+96
-135
lines changed

1 file changed

+96
-135
lines changed

luaclib/src/lcrypt/b64.c

Lines changed: 96 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,170 +1,131 @@
11
#include "lcrypt.h"
22

3-
#define BASE64_CHUNK (65535)
3+
#define BASE64_CHUNK (16)
4+
5+
static inline int b64_calc_padding(const uint8_t *buffer, size_t len) {
6+
size_t n = 0;
7+
for (size_t i = 1; i <= 2; i++)
8+
if (buffer[len - i] == '=')
9+
n++;
10+
return n;
11+
}
412

5-
#define BASE64_ENC_LENGTH(len) (((len) + 2) / 3 * 4)
13+
static inline void b64_trans_char(uint8_t *buf, size_t blen, char a1, char a2, char b1, char b2) {
14+
for (size_t i = 0; i < blen; i++)
15+
{
16+
if (buf[i] == a1)
17+
buf[i] = a2;
18+
else if (buf[i] == b1)
19+
buf[i] = b2;
20+
}
21+
}
622

7-
#define BASE64_DEC_LENGTH(len) ((len + 3) / 4 * 3)
23+
static inline void b64enc_trans_urlsafe(uint8_t *buf, size_t blen) {
24+
return b64_trans_char(buf, blen, '/', '_', '+', '-');
25+
}
826

9-
#define BASE64_URLSAFE(safe, ch, a, b, c, d) \
10-
if (urlsafe) { \
11-
if (ch == a) \
12-
ch = b; \
13-
else if (ch == c) \
14-
ch = d; \
27+
static inline const uint8_t* b64dec_trans_urlsafe(const uint8_t * __restrict buffer, uint8_t* __restrict rep, size_t len) {
28+
int urlsafe = 1; size_t pos = 0;
29+
for (size_t i = 0; i < len; i++)
30+
{
31+
if (buffer[i] == '_' || buffer[i] == '-')
32+
{
33+
pos = i;
34+
urlsafe = 0;
35+
break;
36+
}
1537
}
38+
if (urlsafe)
39+
return buffer;
1640

17-
static inline void encoder(uint8_t *buffer, uint32_t idx, uint8_t code, int32_t urlsafe) {
18-
static const char b64code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
19-
uint8_t ch = b64code[code];
20-
BASE64_URLSAFE(urlsafe, ch, '+', '-', '/', '_');
21-
/* check encoder */
22-
buffer[idx] = ch;
41+
memcpy(rep, buffer, len);
42+
b64_trans_char(rep + pos, len - pos, '_', '/', '-', '+');
43+
return rep;
2344
}
2445

25-
int lb64encode(lua_State *L) {
26-
46+
int lb64decode(lua_State *L) {
2747
size_t tsize = 0;
2848
const uint8_t* text = (const uint8_t *)luaL_checklstring(L, 1, &tsize);
2949
if (!text || tsize == 0)
3050
return 0;
3151

32-
int32_t urlsafe = 0;
33-
if (lua_isboolean(L, 2) && lua_toboolean(L, 2))
34-
urlsafe = 1;
52+
int urlsafe = lua_toboolean(L, 2);
3553

36-
int32_t nopadding = 0;
37-
if (lua_isboolean(L, 3) && lua_toboolean(L, 3))
38-
nopadding = 1;
54+
int padding = tsize % 4;
3955

40-
int esize = BASE64_ENC_LENGTH(tsize);
56+
EVP_ENCODE_CTX* ctx = EVP_ENCODE_CTX_new();
57+
EVP_DecodeInit(ctx);
4158

42-
char *buffer;
43-
if (tsize <= BASE64_CHUNK)
44-
buffer = alloca(esize);
45-
else
46-
buffer = lua_newuserdata(L, esize);
47-
48-
int64_t nsize = tsize;
49-
size_t idx, set, index = 0;
50-
51-
/* normal encoder */
52-
for (idx = 0; idx < nsize - 2; idx += 3) {
53-
set = (text[idx] << 16) | (text[idx + 1] << 8) | (text[idx + 2]);
54-
encoder((uint8_t*)buffer, index++, set >> 18 & 0x3f, urlsafe);
55-
encoder((uint8_t*)buffer, index++, set >> 12 & 0x3f, urlsafe);
56-
encoder((uint8_t*)buffer, index++, set >> 6 & 0x3f, urlsafe);
57-
encoder((uint8_t*)buffer, index++, set & 0x3f, urlsafe);
58-
}
59+
ssize_t nsize = BASE64_CHUNK;
60+
ssize_t bsize = BASE64_CHUNK;
61+
uint8_t buffer[bsize];
62+
uint8_t rep[bsize];
5963

60-
// int padding = tsize - idx;
61-
/* checked padding. */
62-
switch (tsize - idx) {
63-
case 1: /* only 1 char */
64-
set = text[idx];
65-
encoder((uint8_t*)buffer, index++, set >> 2, urlsafe);
66-
encoder((uint8_t*)buffer, index++, (set << 4) & 0x3f, urlsafe);
67-
if (!nopadding) {
68-
buffer[index++] = '=';
69-
buffer[index++] = '=';
64+
luaL_Buffer B; luaL_buffinit(L, &B);
65+
while (tsize)
66+
{
67+
if (tsize < BASE64_CHUNK)
68+
bsize = tsize;
69+
70+
int ret = EVP_DecodeUpdate(ctx, buffer, (int *)&nsize, urlsafe ? b64dec_trans_urlsafe(text, rep, bsize) : text, bsize);
71+
if(ret == -1)
72+
goto failed;
73+
74+
luaL_addlstring(&B, (char *)buffer, nsize);
75+
76+
if ((size_t)bsize == tsize)
77+
{
78+
if (padding)
79+
{
80+
EVP_DecodeUpdate(ctx, buffer, (int *)&nsize, (const uint8_t *)"===", 4 - padding);
81+
luaL_addlstring(&B, (char *)buffer, nsize);
7082
}
7183
break;
72-
case 2: /* having 2 char */
73-
set = text[idx] << 8 | text[idx + 1];
74-
encoder((uint8_t*)buffer, index++, (set >> 10) & 0x3f, urlsafe);
75-
encoder((uint8_t*)buffer, index++, (set >> 4) & 0x3f, urlsafe);
76-
encoder((uint8_t*)buffer, index++, (set << 2) & 0x3f, urlsafe);
77-
if (!nopadding)
78-
buffer[index++] = '=';
79-
break;
84+
}
85+
text += BASE64_CHUNK; tsize -= BASE64_CHUNK; nsize = bsize = BASE64_CHUNK;
8086
}
81-
lua_pushlstring(L, buffer, index);
87+
88+
bsize = BASE64_CHUNK;
89+
int ret = EVP_DecodeFinal(ctx, buffer, (int *)&bsize);
90+
if (ret == -1)
91+
goto failed;
92+
93+
luaL_addlstring(&B, (char *)buffer, bsize);
94+
95+
luaL_pushresult(&B);
96+
EVP_ENCODE_CTX_free(ctx);
8297
return 1;
83-
}
8498

85-
static inline uint8_t decoder(lua_State* L, uint8_t ch, int32_t urlsafe) {
86-
static const int8_t b64code_idx[] = {
87-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
88-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
89-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
90-
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
91-
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
92-
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
93-
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
94-
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
95-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
96-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
97-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
98-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
99-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
100-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
101-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
102-
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
103-
};
104-
BASE64_URLSAFE(urlsafe, ch, '-', '+', '_', '/');
105-
int8_t code = b64code_idx[ch];
106-
if (code == -1)
107-
return luaL_error(L, "Invalid base64 decode byte. %d", ch);
108-
return (uint8_t)code;
99+
failed:
100+
EVP_ENCODE_CTX_free(ctx);
101+
return 0;
109102
}
110103

111-
int lb64decode(lua_State *L) {
104+
int lb64encode(lua_State *L) {
112105
size_t tsize = 0;
113106
const uint8_t* text = (const uint8_t *)luaL_checklstring(L, 1, &tsize);
114107
if (!text || tsize == 0)
115108
return 0;
116109

117-
int32_t urlsafe = 0;
118-
if (lua_isboolean(L, 2) && lua_toboolean(L, 2))
119-
urlsafe = 1;
110+
size_t blen = EVP_ENCODE_LENGTH(tsize);
111+
unsigned char* buf;
112+
if (blen < 65535)
113+
buf = alloca(blen);
114+
else
115+
buf = lua_newuserdata(L, blen);
120116

121-
int dsize = BASE64_DEC_LENGTH(tsize);
117+
int len = EVP_EncodeBlock(buf, text, tsize);
118+
if (len < 1)
119+
return 0;
122120

123-
char *buffer;
124-
if (tsize <= BASE64_CHUNK)
125-
buffer = alloca(dsize);
126-
else
127-
buffer = lua_newuserdata(L, dsize);
121+
/* 是否URL安全 */
122+
if (lua_toboolean(L, 2))
123+
b64enc_trans_urlsafe(buf, len);
128124

129-
size_t index = 0, idx = 0;
130-
uint32_t offsets, i, pos;
131-
for (idx = 0; idx < tsize;)
132-
{
133-
i = 0, pos = 0;
134-
uint8_t set[] = {0, 0, 0, 0};
135-
while (idx + pos < tsize && i < 4) {
136-
uint8_t ch = text[idx + (pos++)];
137-
if (ch == '=') {
138-
if (idx + pos < tsize - 2)
139-
return luaL_error(L, "Invalid base64 decode text.");
140-
break;
141-
}
142-
if (ch == '\n')
143-
continue;
144-
set[i++] = decoder(L, ch, urlsafe);
145-
}
146-
// printf("pos = %d, set = { %d, %d, %d, %d }\n", idx, set[0], set[1], set[2], set[3]);
147-
offsets = (set[0] << 18) | (set[1] << 12) | (set[2] << 6) | set[3];
148-
switch (4 - i){
149-
case 0:
150-
/* decode normal character. */
151-
buffer[index++] = (offsets >> 16);
152-
buffer[index++] = (offsets >> 8) & 0xFF;;
153-
buffer[index++] = offsets & 0xFF;
154-
break;
155-
case 1:
156-
/* padding 1 character. */
157-
buffer[index++] = (offsets >> 16);
158-
buffer[index++] = (offsets >> 8) & 0xFF;;
159-
break;
160-
case 2:
161-
/* padding 2 character. */
162-
buffer[index++] = offsets >> 16;
163-
break;
164-
}
165-
idx += pos;
166-
}
167-
// printf("ret = %d\n", index);
168-
lua_pushlstring(L, buffer, index);
125+
/* 是否去掉padding */
126+
if (lua_toboolean(L, 3))
127+
len -= b64_calc_padding(buf, len);
128+
129+
lua_pushlstring(L, (char*)buf, len);
169130
return 1;
170131
}

0 commit comments

Comments
 (0)