/src/libgpg-error-1.49/src/b64enc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* b64enc.c - Simple Base64 encoder. |
2 | | * Copyright (C) 2001, 2003, 2004, 2008, 2010, |
3 | | * 2011 Free Software Foundation, Inc. |
4 | | * Copyright (C) 2001, 2003, 2004, 2008, 2010, |
5 | | * 2011, 2018 g10 Code GmbH |
6 | | * |
7 | | * This file is part of Libgpg-error. |
8 | | * |
9 | | * This file is free software; you can redistribute it and/or modify |
10 | | * it under the terms of the GNU Lesser General Public License as |
11 | | * published by the Free Software Foundation; either version 2.1 of |
12 | | * the License, or (at your option) any later version. |
13 | | * |
14 | | * This file is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | * GNU General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public License |
20 | | * along with this program; if not, see <https://www.gnu.org/licenses/>. |
21 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
22 | | * |
23 | | * This file was originally a part of GnuPG. |
24 | | */ |
25 | | |
26 | | #include <config.h> |
27 | | #include <stdio.h> |
28 | | #include <stdint.h> |
29 | | #include <stdlib.h> |
30 | | #include <string.h> |
31 | | #include <errno.h> |
32 | | |
33 | | #include "gpgrt-int.h" |
34 | | |
35 | | |
36 | 0 | #define B64ENC_DID_HEADER 1 |
37 | | #define B64ENC_DID_TRAILER 2 |
38 | 0 | #define B64ENC_NO_LINEFEEDS 16 |
39 | 0 | #define B64ENC_USE_PGPCRC 32 |
40 | | |
41 | | /* The base-64 character list */ |
42 | | static unsigned char const bintoasc[64] = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
43 | | "abcdefghijklmnopqrstuvwxyz" |
44 | | "0123456789+/"); |
45 | | |
46 | | /* Stuff required to create the OpenPGP CRC. This crc_table has been |
47 | | created using this code: |
48 | | |
49 | | #include <stdio.h> |
50 | | #include <stdint.h> |
51 | | |
52 | | #define CRCPOLY 0x864CFB |
53 | | |
54 | | int |
55 | | main (void) |
56 | | { |
57 | | int i, j; |
58 | | uint32_t t; |
59 | | uint32_t crc_table[256]; |
60 | | |
61 | | crc_table[0] = 0; |
62 | | for (i=j=0; j < 128; j++ ) |
63 | | { |
64 | | t = crc_table[j]; |
65 | | if ( (t & 0x00800000) ) |
66 | | { |
67 | | t <<= 1; |
68 | | crc_table[i++] = t ^ CRCPOLY; |
69 | | crc_table[i++] = t; |
70 | | } |
71 | | else |
72 | | { |
73 | | t <<= 1; |
74 | | crc_table[i++] = t; |
75 | | crc_table[i++] = t ^ CRCPOLY; |
76 | | } |
77 | | } |
78 | | |
79 | | puts ("static const u32 crc_table[256] = {"); |
80 | | for (i=j=0; i < 256; i++) |
81 | | { |
82 | | printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]); |
83 | | if (i != 255) |
84 | | { |
85 | | putchar (','); |
86 | | if ( ++j > 5) |
87 | | { |
88 | | j = 0; |
89 | | putchar ('\n'); |
90 | | } |
91 | | } |
92 | | } |
93 | | puts ("\n};"); |
94 | | return 0; |
95 | | } |
96 | | */ |
97 | 0 | #define CRCINIT 0xB704CE |
98 | | static const uint32_t crc_table[256] = { |
99 | | 0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, |
100 | | 0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf, |
101 | | 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272, |
102 | | 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e, |
103 | | 0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa, |
104 | | 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f, |
105 | | 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b, |
106 | | 0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7, |
107 | | 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a, |
108 | | 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af, |
109 | | 0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29, |
110 | | 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5, |
111 | | 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1, |
112 | | 0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, 0x30563856, 0x30d074ad, |
113 | | 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099, |
114 | | 0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375, |
115 | | 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821, |
116 | | 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4, |
117 | | 0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049, |
118 | | 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5, |
119 | | 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791, |
120 | | 0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52, |
121 | | 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66, |
122 | | 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a, |
123 | | 0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337, |
124 | | 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2, |
125 | | 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6, |
126 | | 0x62b54340, 0x62330fbb, 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a, |
127 | | 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e, |
128 | | 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132, |
129 | | 0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506, |
130 | | 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea, |
131 | | 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c, |
132 | | 0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9, |
133 | | 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604, |
134 | | 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8, |
135 | | 0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc, |
136 | | 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69, |
137 | | 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d, |
138 | | 0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1, |
139 | | 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c, |
140 | | 0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9, |
141 | | 0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538 |
142 | | }; |
143 | | |
144 | | |
145 | | /* Prepare for Base-64 writing to STREAM. If TITLE is not NULL and |
146 | | * not an empty string, that string will be used as the title for the |
147 | | * armor lines, with TITLE being an empty string, we don't write the |
148 | | * header lines and furthermore even don't write any linefeeds. If |
149 | | * TITLE starts with "PGP " the OpenPGP CRC checksum will be written |
150 | | * as well. With TITLE being NULL, we merely don't write header but |
151 | | * make sure that lines are not too long. Note, that we don't write |
152 | | * anything unless at least one byte is written using b64enc_write. |
153 | | * On success an enoder object is returned which needs to be released |
154 | | * using _gpgrt_b64dec_finish. On error NULL is returned an ERRNO is |
155 | | * set. |
156 | | */ |
157 | | gpgrt_b64state_t |
158 | | _gpgrt_b64enc_start (estream_t stream, const char *title) |
159 | 0 | { |
160 | 0 | gpgrt_b64state_t state; |
161 | |
|
162 | 0 | state = xtrycalloc (1, sizeof *state); |
163 | 0 | if (!state) |
164 | 0 | return NULL; |
165 | | |
166 | 0 | state->stream = stream; |
167 | 0 | if (title && !*title) |
168 | 0 | state->flags |= B64ENC_NO_LINEFEEDS; |
169 | 0 | else if (title) |
170 | 0 | { |
171 | 0 | if (!strncmp (title, "PGP ", 4)) |
172 | 0 | { |
173 | 0 | state->flags |= B64ENC_USE_PGPCRC; |
174 | 0 | state->crc = CRCINIT; |
175 | 0 | } |
176 | 0 | state->title = xtrystrdup (title); |
177 | 0 | if (!state->title) |
178 | 0 | { |
179 | 0 | xfree (state); |
180 | 0 | return NULL; |
181 | 0 | } |
182 | 0 | } |
183 | | |
184 | 0 | return state; |
185 | 0 | } |
186 | | |
187 | | |
188 | | /* Write NBYTES from BUFFER to the Base 64 stream identified by STATE. |
189 | | * With BUFFER and NBYTES being 0, merely do a fflush on the stream. |
190 | | */ |
191 | | gpg_err_code_t |
192 | | _gpgrt_b64enc_write (gpgrt_b64state_t state, const void *buffer, size_t nbytes) |
193 | 0 | { |
194 | 0 | unsigned char radbuf[4]; |
195 | 0 | int idx, quad_count; |
196 | 0 | const unsigned char *p; |
197 | |
|
198 | 0 | if (state->lasterr) |
199 | 0 | return state->lasterr; |
200 | | |
201 | 0 | if (!nbytes) |
202 | 0 | { |
203 | 0 | if (buffer) |
204 | 0 | if (_gpgrt_fflush (state->stream)) |
205 | 0 | goto write_error; |
206 | 0 | return 0; |
207 | 0 | } |
208 | | |
209 | 0 | if (!(state->flags & B64ENC_DID_HEADER)) |
210 | 0 | { |
211 | 0 | if (state->title) |
212 | 0 | { |
213 | 0 | if ( _gpgrt_fputs ("-----BEGIN ", state->stream) == EOF |
214 | 0 | || _gpgrt_fputs (state->title, state->stream) == EOF |
215 | 0 | || _gpgrt_fputs ("-----\n", state->stream) == EOF) |
216 | 0 | goto write_error; |
217 | 0 | if ( (state->flags & B64ENC_USE_PGPCRC) |
218 | 0 | && _gpgrt_fputs ("\n", state->stream) == EOF) |
219 | 0 | goto write_error; |
220 | 0 | } |
221 | | |
222 | 0 | state->flags |= B64ENC_DID_HEADER; |
223 | 0 | } |
224 | | |
225 | 0 | idx = state->idx; |
226 | 0 | quad_count = state->quad_count; |
227 | 0 | gpgrt_assert (idx < 4); |
228 | 0 | memcpy (radbuf, state->radbuf, idx); |
229 | |
|
230 | 0 | if ( (state->flags & B64ENC_USE_PGPCRC) ) |
231 | 0 | { |
232 | 0 | size_t n; |
233 | 0 | uint32_t crc = state->crc; |
234 | |
|
235 | 0 | for (p=buffer, n=nbytes; n; p++, n-- ) |
236 | 0 | crc = ((uint32_t)crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p]; |
237 | 0 | state->crc = (crc & 0x00ffffff); |
238 | 0 | } |
239 | |
|
240 | 0 | for (p=buffer; nbytes; p++, nbytes--) |
241 | 0 | { |
242 | 0 | radbuf[idx++] = *p; |
243 | 0 | if (idx > 2) |
244 | 0 | { |
245 | 0 | char tmp[4]; |
246 | |
|
247 | 0 | tmp[0] = bintoasc[(*radbuf >> 2) & 077]; |
248 | 0 | tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077]; |
249 | 0 | tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077]; |
250 | 0 | tmp[3] = bintoasc[radbuf[2]&077]; |
251 | 0 | for (idx=0; idx < 4; idx++) |
252 | 0 | _gpgrt_fputc (tmp[idx], state->stream); |
253 | 0 | idx = 0; |
254 | 0 | if (_gpgrt_ferror (state->stream)) |
255 | 0 | goto write_error; |
256 | | |
257 | 0 | if (++quad_count >= (64/4)) |
258 | 0 | { |
259 | 0 | quad_count = 0; |
260 | 0 | if (!(state->flags & B64ENC_NO_LINEFEEDS) |
261 | 0 | && _gpgrt_fputs ("\n", state->stream) == EOF) |
262 | 0 | goto write_error; |
263 | 0 | } |
264 | 0 | } |
265 | 0 | } |
266 | 0 | memcpy (state->radbuf, radbuf, idx); |
267 | 0 | state->idx = idx; |
268 | 0 | state->quad_count = quad_count; |
269 | 0 | return 0; |
270 | | |
271 | 0 | write_error: |
272 | 0 | state->lasterr = _gpg_err_code_from_syserror (); |
273 | 0 | if (state->title) |
274 | 0 | { |
275 | 0 | xfree (state->title); |
276 | 0 | state->title = NULL; |
277 | 0 | } |
278 | 0 | return state->lasterr; |
279 | 0 | } |
280 | | |
281 | | |
282 | | gpg_err_code_t |
283 | | _gpgrt_b64enc_finish (gpgrt_b64state_t state) |
284 | 0 | { |
285 | 0 | gpg_err_code_t err = 0; |
286 | 0 | unsigned char radbuf[4]; |
287 | 0 | int idx, quad_count; |
288 | 0 | char tmp[4]; |
289 | |
|
290 | 0 | if (!state) |
291 | 0 | return 0; /* Already released. */ |
292 | | |
293 | 0 | if (state->using_decoder) |
294 | 0 | { |
295 | 0 | err = GPG_ERR_CONFLICT; /* State was created for the decoder. */ |
296 | 0 | goto cleanup; |
297 | 0 | } |
298 | | |
299 | 0 | if (state->lasterr) |
300 | 0 | { |
301 | 0 | err = state->lasterr; |
302 | 0 | goto cleanup; |
303 | 0 | } |
304 | | |
305 | 0 | if (!(state->flags & B64ENC_DID_HEADER)) |
306 | 0 | goto cleanup; |
307 | | |
308 | | /* Flush the base64 encoding */ |
309 | 0 | idx = state->idx; |
310 | 0 | quad_count = state->quad_count; |
311 | 0 | gpgrt_assert (idx < 4); |
312 | 0 | memcpy (radbuf, state->radbuf, idx); |
313 | |
|
314 | 0 | if (idx) |
315 | 0 | { |
316 | 0 | tmp[0] = bintoasc[(*radbuf>>2)&077]; |
317 | 0 | if (idx == 1) |
318 | 0 | { |
319 | 0 | tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077]; |
320 | 0 | tmp[2] = '='; |
321 | 0 | tmp[3] = '='; |
322 | 0 | } |
323 | 0 | else |
324 | 0 | { |
325 | 0 | tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077]; |
326 | 0 | tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077]; |
327 | 0 | tmp[3] = '='; |
328 | 0 | } |
329 | 0 | for (idx=0; idx < 4; idx++) |
330 | 0 | _gpgrt_fputc (tmp[idx], state->stream); |
331 | 0 | if (_gpgrt_ferror (state->stream)) |
332 | 0 | goto write_error; |
333 | | |
334 | 0 | if (++quad_count >= (64/4)) |
335 | 0 | { |
336 | 0 | quad_count = 0; |
337 | 0 | if (!(state->flags & B64ENC_NO_LINEFEEDS) |
338 | 0 | && _gpgrt_fputs ("\n", state->stream) == EOF) |
339 | 0 | goto write_error; |
340 | 0 | } |
341 | 0 | } |
342 | | |
343 | | /* Finish the last line and write the trailer. */ |
344 | 0 | if (quad_count |
345 | 0 | && !(state->flags & B64ENC_NO_LINEFEEDS) |
346 | 0 | && _gpgrt_fputs ("\n", state->stream) == EOF) |
347 | 0 | goto write_error; |
348 | | |
349 | 0 | if ( (state->flags & B64ENC_USE_PGPCRC) ) |
350 | 0 | { |
351 | | /* Write the CRC. */ |
352 | 0 | _gpgrt_fputs ("=", state->stream); |
353 | 0 | radbuf[0] = state->crc >>16; |
354 | 0 | radbuf[1] = state->crc >> 8; |
355 | 0 | radbuf[2] = state->crc; |
356 | 0 | tmp[0] = bintoasc[(*radbuf>>2)&077]; |
357 | 0 | tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077]; |
358 | 0 | tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077]; |
359 | 0 | tmp[3] = bintoasc[radbuf[2]&077]; |
360 | 0 | for (idx=0; idx < 4; idx++) |
361 | 0 | _gpgrt_fputc (tmp[idx], state->stream); |
362 | 0 | if (_gpgrt_ferror (state->stream)) |
363 | 0 | goto write_error; |
364 | | |
365 | 0 | if (!(state->flags & B64ENC_NO_LINEFEEDS) |
366 | 0 | && _gpgrt_fputs ("\n", state->stream) == EOF) |
367 | 0 | goto write_error; |
368 | 0 | } |
369 | | |
370 | 0 | if (state->title) |
371 | 0 | { |
372 | 0 | if ( _gpgrt_fputs ("-----END ", state->stream) == EOF |
373 | 0 | || _gpgrt_fputs (state->title, state->stream) == EOF |
374 | 0 | || _gpgrt_fputs ("-----\n", state->stream) == EOF) |
375 | 0 | goto write_error; |
376 | 0 | } |
377 | | |
378 | 0 | cleanup: |
379 | 0 | xfree (state->title); |
380 | 0 | xfree (state); |
381 | 0 | return err; |
382 | | |
383 | 0 | write_error: |
384 | 0 | err = gpg_error_from_syserror (); |
385 | 0 | goto cleanup; |
386 | 0 | } |