/src/fluent-bit/src/flb_base64.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* Fluent Bit |
4 | | * ========== |
5 | | * Copyright (C) 2019-2021 The Fluent Bit Authors |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | /* This code is based on base64.c from the mbedtls-2.25.0 Library distribution, |
21 | | * as originally written by Paul Bakker, et al., and forked by the Fluent Bit |
22 | | * project to provide performant base64 encoding and decoding routines. |
23 | | * The 2.25.0 implementation is included rather than 2.26.0+ implementation due |
24 | | * to performance degradation introduced in 2.26.0. |
25 | | * |
26 | | * Method and variable names are changed by the Fluent Bit authors to maintain |
27 | | * consistency with the Fluent Bit project. |
28 | | * The self test section of the code was removed by the Fluent Bit authors. |
29 | | * Other minor changes are made by the Fluent Bit authors. |
30 | | * |
31 | | * The original source file base64.c is copyright and licensed as follows; |
32 | | * |
33 | | * RFC 1521 base64 encoding/decoding |
34 | | * |
35 | | * Copyright The Mbed TLS Contributors |
36 | | * SPDX-License-Identifier: Apache-2.0 |
37 | | * |
38 | | * Licensed under the Apache License, Version 2.0 (the "License"); you may |
39 | | * not use this file except in compliance with the License. |
40 | | * You may obtain a copy of the License at |
41 | | * |
42 | | * http://www.apache.org/licenses/LICENSE-2.0 |
43 | | * |
44 | | * Unless required by applicable law or agreed to in writing, software |
45 | | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
46 | | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
47 | | * See the License for the specific language governing permissions and |
48 | | * limitations under the License. |
49 | | */ |
50 | | |
51 | | #include <fluent-bit/flb_base64.h> |
52 | | |
53 | | #include <stdint.h> |
54 | | |
55 | | static const unsigned char base64_enc_map[64] = |
56 | | { |
57 | | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', |
58 | | 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', |
59 | | 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', |
60 | | 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', |
61 | | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', |
62 | | 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', |
63 | | '8', '9', '+', '/' |
64 | | }; |
65 | | |
66 | | static const unsigned char base64_dec_map[128] = |
67 | | { |
68 | | 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, |
69 | | 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, |
70 | | 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, |
71 | | 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, |
72 | | 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, |
73 | | 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, |
74 | | 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, |
75 | | 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
76 | | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, |
77 | | 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, |
78 | | 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, |
79 | | 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, |
80 | | 49, 50, 51, 127, 127, 127, 127, 127 |
81 | | }; |
82 | | |
83 | 692 | #define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ |
84 | | |
85 | | /* |
86 | | * Encode a buffer into base64 format |
87 | | */ |
88 | | int flb_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, |
89 | | const unsigned char *src, size_t slen ) |
90 | 692 | { |
91 | 692 | size_t i, n; |
92 | 692 | int C1, C2, C3; |
93 | 692 | unsigned char *p; |
94 | | |
95 | 692 | if( slen == 0 ) |
96 | 0 | { |
97 | 0 | *olen = 0; |
98 | 0 | return( 0 ); |
99 | 0 | } |
100 | | |
101 | 692 | n = slen / 3 + ( slen % 3 != 0 ); |
102 | | |
103 | 692 | if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 ) |
104 | 0 | { |
105 | 0 | *olen = BASE64_SIZE_T_MAX; |
106 | 0 | return( FLB_BASE64_ERR_BUFFER_TOO_SMALL ); |
107 | 0 | } |
108 | | |
109 | 692 | n *= 4; |
110 | | |
111 | 692 | if( ( dlen < n + 1 ) || ( NULL == dst ) ) |
112 | 155 | { |
113 | 155 | *olen = n + 1; |
114 | 155 | return( FLB_BASE64_ERR_BUFFER_TOO_SMALL ); |
115 | 155 | } |
116 | | |
117 | 537 | n = ( slen / 3 ) * 3; |
118 | | |
119 | 4.42k | for( i = 0, p = dst; i < n; i += 3 ) |
120 | 3.88k | { |
121 | 3.88k | C1 = *src++; |
122 | 3.88k | C2 = *src++; |
123 | 3.88k | C3 = *src++; |
124 | | |
125 | 3.88k | *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; |
126 | 3.88k | *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; |
127 | 3.88k | *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; |
128 | 3.88k | *p++ = base64_enc_map[C3 & 0x3F]; |
129 | 3.88k | } |
130 | | |
131 | 537 | if( i < slen ) |
132 | 433 | { |
133 | 433 | C1 = *src++; |
134 | 433 | C2 = ( ( i + 1 ) < slen ) ? *src++ : 0; |
135 | | |
136 | 433 | *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; |
137 | 433 | *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; |
138 | | |
139 | 433 | if( ( i + 1 ) < slen ) |
140 | 113 | *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; |
141 | 320 | else *p++ = '='; |
142 | | |
143 | 433 | *p++ = '='; |
144 | 433 | } |
145 | | |
146 | 537 | *olen = p - dst; |
147 | 537 | *p = 0; |
148 | | |
149 | 537 | return( 0 ); |
150 | 692 | } |
151 | | |
152 | | /* |
153 | | * Decode a base64-formatted buffer |
154 | | */ |
155 | | int flb_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, |
156 | | const unsigned char *src, size_t slen ) |
157 | 293 | { |
158 | 293 | size_t i, n; |
159 | 293 | uint32_t j, x; |
160 | 293 | unsigned char *p; |
161 | | |
162 | | /* First pass: check for validity and get output length */ |
163 | 7.18M | for( i = n = j = 0; i < slen; i++ ) |
164 | 7.18M | { |
165 | | /* Skip spaces before checking for EOL */ |
166 | 7.18M | x = 0; |
167 | 11.5M | while( i < slen && src[i] == ' ' ) |
168 | 4.39M | { |
169 | 4.39M | ++i; |
170 | 4.39M | ++x; |
171 | 4.39M | } |
172 | | |
173 | | /* Spaces at end of buffer are OK */ |
174 | 7.18M | if( i == slen ) |
175 | 31 | break; |
176 | | |
177 | 7.18M | if( ( slen - i ) >= 2 && |
178 | 7.18M | src[i] == '\r' && src[i + 1] == '\n' ) |
179 | 5.10k | continue; |
180 | | |
181 | 7.18M | if( src[i] == '\n' ) |
182 | 14.9k | continue; |
183 | | |
184 | | /* Space inside a line is an error */ |
185 | 7.16M | if( x != 0 ) |
186 | 33 | return( FLB_BASE64_ERR_INVALID_CHARACTER ); |
187 | | |
188 | 7.16M | if( src[i] == '=' && ++j > 2 ) |
189 | 1 | return( FLB_BASE64_ERR_INVALID_CHARACTER ); |
190 | | |
191 | 7.16M | if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) |
192 | 85 | return( FLB_BASE64_ERR_INVALID_CHARACTER ); |
193 | | |
194 | 7.16M | if( base64_dec_map[src[i]] < 64 && j != 0 ) |
195 | 1 | return( FLB_BASE64_ERR_INVALID_CHARACTER ); |
196 | | |
197 | 7.16M | n++; |
198 | 7.16M | } |
199 | | |
200 | 173 | if( n == 0 ) |
201 | 25 | { |
202 | 25 | *olen = 0; |
203 | 25 | return( 0 ); |
204 | 25 | } |
205 | | |
206 | | /* The following expression is to calculate the following formula without |
207 | | * risk of integer overflow in n: |
208 | | * n = ( ( n * 6 ) + 7 ) >> 3; |
209 | | */ |
210 | 148 | n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 ); |
211 | 148 | n -= j; |
212 | | |
213 | 148 | if( dst == NULL || dlen < n ) |
214 | 56 | { |
215 | 56 | *olen = n; |
216 | 56 | return( FLB_BASE64_ERR_BUFFER_TOO_SMALL ); |
217 | 56 | } |
218 | | |
219 | 2.11M | for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) |
220 | 2.11M | { |
221 | 2.11M | if( *src == '\r' || *src == '\n' || *src == ' ' ) |
222 | 2.11M | continue; |
223 | | |
224 | 1.52k | j -= ( base64_dec_map[*src] == 64 ); |
225 | 1.52k | x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F ); |
226 | | |
227 | 1.52k | if( ++n == 4 ) |
228 | 350 | { |
229 | 350 | n = 0; |
230 | 350 | if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); |
231 | 350 | if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); |
232 | 350 | if( j > 2 ) *p++ = (unsigned char)( x ); |
233 | 350 | } |
234 | 1.52k | } |
235 | | |
236 | 92 | *olen = p - dst; |
237 | | |
238 | 92 | return( 0 ); |
239 | 148 | } |