Fix a signal cleanup problem.
[gnupg.git] / common / b64enc.c
blob4722bd1e1afa0a42d6b33459ff8eac9a01a6e862
1 /* b64enc.c - Simple Base64 encoder.
2 * Copyright (C) 2001, 2003, 2004, 2008 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <assert.h>
27 #include "i18n.h"
28 #include "util.h"
30 #define B64ENC_DID_HEADER 1
31 #define B64ENC_DID_TRAILER 2
32 #define B64ENC_NO_LINEFEEDS 16
33 #define B64ENC_USE_PGPCRC 32
35 /* The base-64 character list */
36 static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
37 "abcdefghijklmnopqrstuvwxyz"
38 "0123456789+/";
40 /* Stuff required to create the OpenPGP CRC. This crc_table has been
41 created using this code:
43 #include <stdio.h>
44 #include <stdint.h>
46 #define CRCPOLY 0x864CFB
48 int
49 main (void)
51 int i, j;
52 uint32_t t;
53 uint32_t crc_table[256];
55 crc_table[0] = 0;
56 for (i=j=0; j < 128; j++ )
58 t = crc_table[j];
59 if ( (t & 0x00800000) )
61 t <<= 1;
62 crc_table[i++] = t ^ CRCPOLY;
63 crc_table[i++] = t;
65 else
67 t <<= 1;
68 crc_table[i++] = t;
69 crc_table[i++] = t ^ CRCPOLY;
73 puts ("static const u32 crc_table[256] = {");
74 for (i=j=0; i < 256; i++)
76 printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]);
77 if (i != 255)
79 putchar (',');
80 if ( ++j > 5)
82 j = 0;
83 putchar ('\n');
87 puts ("\n};");
88 return 0;
91 #define CRCINIT 0xB704CE
92 static const u32 crc_table[256] = {
93 0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a,
94 0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf,
95 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
96 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e,
97 0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa,
98 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f,
99 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b,
100 0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7,
101 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a,
102 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af,
103 0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29,
104 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5,
105 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1,
106 0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, 0x30563856, 0x30d074ad,
107 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099,
108 0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375,
109 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821,
110 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4,
111 0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049,
112 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5,
113 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791,
114 0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52,
115 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66,
116 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a,
117 0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337,
118 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2,
119 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6,
120 0x62b54340, 0x62330fbb, 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a,
121 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e,
122 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132,
123 0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506,
124 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea,
125 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c,
126 0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9,
127 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604,
128 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8,
129 0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc,
130 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69,
131 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d,
132 0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1,
133 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c,
134 0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9,
135 0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538
139 /* Prepare for base-64 writing to the stream FP. If TITLE is not NULL
140 and not an empty string, this string will be used as the title for
141 the armor lines, with TITLE being an empty string, we don't write
142 the header lines and furthermore even don't write any linefeeds.
143 If TITLE starts with "PGP " the OpenPGP CRC checksum will be
144 written as well. With TITLE beeing NULL, we merely don't write
145 header but make sure that lines are not too long. Note, that we
146 don't write any output unless at least one byte get written using
147 b64enc_write. */
148 gpg_error_t
149 b64enc_start (struct b64state *state, FILE *fp, const char *title)
151 memset (state, 0, sizeof *state);
152 state->fp = fp;
153 if (title && !*title)
154 state->flags |= B64ENC_NO_LINEFEEDS;
155 else if (title)
157 if (!strncmp (title, "PGP ", 4))
159 state->flags |= B64ENC_USE_PGPCRC;
160 state->crc = CRCINIT;
162 state->title = xtrystrdup (title);
163 if (!state->title)
164 return gpg_error_from_syserror ();
166 return 0;
170 /* Write NBYTES from BUFFER to the Base 64 stream identified by
171 STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
172 stream. */
173 gpg_error_t
174 b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
176 unsigned char radbuf[4];
177 int idx, quad_count;
178 const unsigned char *p;
179 FILE *fp = state->fp;
182 if (!nbytes)
184 if (buffer && fflush (fp))
185 goto write_error;
186 return 0;
189 if (!(state->flags & B64ENC_DID_HEADER))
191 if (state->title)
193 if ( fputs ("-----BEGIN ", fp) == EOF
194 || fputs (state->title, fp) == EOF
195 || fputs ("-----\n", fp) == EOF)
196 goto write_error;
197 if ( (state->flags & B64ENC_USE_PGPCRC)
198 && fputs ("\n", fp) == EOF)
199 goto write_error;
202 state->flags |= B64ENC_DID_HEADER;
205 idx = state->idx;
206 quad_count = state->quad_count;
207 assert (idx < 4);
208 memcpy (radbuf, state->radbuf, idx);
210 if ( (state->flags & B64ENC_USE_PGPCRC) )
212 size_t n;
213 u32 crc = state->crc;
215 for (p=buffer, n=nbytes; n; p++, n-- )
216 crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p];
217 state->crc = (crc & 0x00ffffff);
220 for (p=buffer; nbytes; p++, nbytes--)
222 radbuf[idx++] = *p;
223 if (idx > 2)
225 char tmp[4];
227 tmp[0] = bintoasc[(*radbuf >> 2) & 077];
228 tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
229 tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
230 tmp[3] = bintoasc[radbuf[2]&077];
231 for (idx=0; idx < 4; idx++)
232 putc (tmp[idx], fp);
233 idx = 0;
234 if (ferror (fp))
235 goto write_error;
236 if (++quad_count >= (64/4))
238 quad_count = 0;
239 if (!(state->flags & B64ENC_NO_LINEFEEDS)
240 && fputs ("\n", fp) == EOF)
241 goto write_error;
245 memcpy (state->radbuf, radbuf, idx);
246 state->idx = idx;
247 state->quad_count = quad_count;
248 return 0;
250 write_error:
251 return gpg_error_from_syserror ();
254 gpg_error_t
255 b64enc_finish (struct b64state *state)
257 gpg_error_t err = 0;
258 unsigned char radbuf[4];
259 int idx, quad_count;
260 FILE *fp;
261 char tmp[4];
263 if (!(state->flags & B64ENC_DID_HEADER))
264 goto cleanup;
266 /* Flush the base64 encoding */
267 fp = state->fp;
268 idx = state->idx;
269 quad_count = state->quad_count;
270 assert (idx < 4);
271 memcpy (radbuf, state->radbuf, idx);
273 if (idx)
275 tmp[0] = bintoasc[(*radbuf>>2)&077];
276 if (idx == 1)
278 tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
279 tmp[2] = '=';
280 tmp[3] = '=';
282 else
284 tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
285 tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
286 tmp[3] = '=';
288 for (idx=0; idx < 4; idx++)
289 putc (tmp[idx], fp);
290 idx = 0;
291 if (ferror (fp))
292 goto write_error;
294 if (++quad_count >= (64/4))
296 quad_count = 0;
297 if (!(state->flags & B64ENC_NO_LINEFEEDS)
298 && fputs ("\n", fp) == EOF)
299 goto write_error;
303 /* Finish the last line and write the trailer. */
304 if (quad_count
305 && !(state->flags & B64ENC_NO_LINEFEEDS)
306 && fputs ("\n", fp) == EOF)
307 goto write_error;
309 if ( (state->flags & B64ENC_USE_PGPCRC) )
311 /* Write the CRC. */
312 putc ('=', fp);
313 radbuf[0] = state->crc >>16;
314 radbuf[1] = state->crc >> 8;
315 radbuf[2] = state->crc;
316 tmp[0] = bintoasc[(*radbuf>>2)&077];
317 tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
318 tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
319 tmp[3] = bintoasc[radbuf[2]&077];
320 for (idx=0; idx < 4; idx++)
321 putc (tmp[idx], fp);
322 if (ferror (fp))
323 goto write_error;
324 if (!(state->flags & B64ENC_NO_LINEFEEDS)
325 && fputs ("\n", fp) == EOF)
326 goto write_error;
329 if (state->title)
331 if ( fputs ("-----END ", fp) == EOF
332 || fputs (state->title, fp) == EOF
333 || fputs ("-----\n", fp) == EOF)
334 goto write_error;
337 goto cleanup;
339 write_error:
340 err = gpg_error_from_syserror ();
342 cleanup:
343 if (state->title)
345 xfree (state->title);
346 state->title = NULL;
348 state->fp = NULL;
349 return err;