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