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,
7 * This file is part of GnuPG.
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.
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.
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/>.
33 #define B64ENC_DID_HEADER 1
34 #define B64ENC_DID_TRAILER 2
35 #define B64ENC_NO_LINEFEEDS 16
36 #define B64ENC_USE_PGPCRC 32
38 /* The base-64 character list */
39 static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
40 "abcdefghijklmnopqrstuvwxyz"
43 /* Stuff required to create the OpenPGP CRC. This crc_table has been
44 created using this code:
49 #define CRCPOLY 0x864CFB
56 uint32_t crc_table[256];
59 for (i=j=0; j < 128; j++ )
62 if ( (t & 0x00800000) )
65 crc_table[i++] = t ^ CRCPOLY;
72 crc_table[i++] = t ^ CRCPOLY;
76 puts ("static const u32 crc_table[256] = {");
77 for (i=j=0; i < 256; i++)
79 printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]);
94 #define CRCINIT 0xB704CE
95 static const u32 crc_table[256] = {
96 0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a,
97 0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf,
98 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
99 0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e,
100 0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa,
101 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f,
102 0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b,
103 0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7,
104 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a,
105 0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af,
106 0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29,
107 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5,
108 0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1,
109 0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, 0x30563856, 0x30d074ad,
110 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099,
111 0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375,
112 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821,
113 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4,
114 0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049,
115 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5,
116 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791,
117 0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52,
118 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66,
119 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a,
120 0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337,
121 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2,
122 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6,
123 0x62b54340, 0x62330fbb, 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a,
124 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e,
125 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132,
126 0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506,
127 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea,
128 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c,
129 0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9,
130 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604,
131 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8,
132 0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc,
133 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69,
134 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d,
135 0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1,
136 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c,
137 0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9,
138 0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538
143 enc_start (struct b64state *state, FILE *fp, estream_t stream,
146 memset (state, 0, sizeof *state);
148 state->stream = stream;
150 if (title && !*title)
151 state->flags |= B64ENC_NO_LINEFEEDS;
154 if (!strncmp (title, "PGP ", 4))
156 state->flags |= B64ENC_USE_PGPCRC;
157 state->crc = CRCINIT;
159 state->title = xtrystrdup (title);
161 state->lasterr = gpg_error_from_syserror ();
163 return state->lasterr;
167 /* Prepare for base-64 writing to the stream FP. If TITLE is not NULL
168 and not an empty string, this string will be used as the title for
169 the armor lines, with TITLE being an empty string, we don't write
170 the header lines and furthermore even don't write any linefeeds.
171 If TITLE starts with "PGP " the OpenPGP CRC checksum will be
172 written as well. With TITLE being NULL, we merely don't write
173 header but make sure that lines are not too long. Note, that we
174 don't write any output unless at least one byte get written using
177 b64enc_start (struct b64state *state, FILE *fp, const char *title)
179 return enc_start (state, fp, NULL, title);
182 /* Same as b64enc_start but takes an estream. */
184 b64enc_start_es (struct b64state *state, estream_t fp, const char *title)
186 return enc_start (state, NULL, fp, title);
191 my_fputs (const char *string, struct b64state *state)
194 return es_fputs (string, state->stream);
196 return fputs (string, state->fp);
200 /* Write NBYTES from BUFFER to the Base 64 stream identified by
201 STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
204 b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
206 unsigned char radbuf[4];
208 const unsigned char *p;
211 return state->lasterr;
216 if (state->stream? es_fflush (state->stream) : fflush (state->fp))
221 if (!(state->flags & B64ENC_DID_HEADER))
225 if ( my_fputs ("-----BEGIN ", state) == EOF
226 || my_fputs (state->title, state) == EOF
227 || my_fputs ("-----\n", state) == EOF)
229 if ( (state->flags & B64ENC_USE_PGPCRC)
230 && my_fputs ("\n", state) == EOF)
234 state->flags |= B64ENC_DID_HEADER;
238 quad_count = state->quad_count;
240 memcpy (radbuf, state->radbuf, idx);
242 if ( (state->flags & B64ENC_USE_PGPCRC) )
245 u32 crc = state->crc;
247 for (p=buffer, n=nbytes; n; p++, n-- )
248 crc = ((u32)crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p];
249 state->crc = (crc & 0x00ffffff);
252 for (p=buffer; nbytes; p++, nbytes--)
259 tmp[0] = bintoasc[(*radbuf >> 2) & 077];
260 tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
261 tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
262 tmp[3] = bintoasc[radbuf[2]&077];
265 for (idx=0; idx < 4; idx++)
266 es_putc (tmp[idx], state->stream);
268 if (es_ferror (state->stream))
273 for (idx=0; idx < 4; idx++)
274 putc (tmp[idx], state->fp);
276 if (ferror (state->fp))
279 if (++quad_count >= (64/4))
282 if (!(state->flags & B64ENC_NO_LINEFEEDS)
283 && my_fputs ("\n", state) == EOF)
288 memcpy (state->radbuf, radbuf, idx);
290 state->quad_count = quad_count;
294 state->lasterr = gpg_error_from_syserror ();
297 xfree (state->title);
300 return state->lasterr;
305 b64enc_finish (struct b64state *state)
308 unsigned char radbuf[4];
313 return state->lasterr;
315 if (!(state->flags & B64ENC_DID_HEADER))
318 /* Flush the base64 encoding */
320 quad_count = state->quad_count;
322 memcpy (radbuf, state->radbuf, idx);
326 tmp[0] = bintoasc[(*radbuf>>2)&077];
329 tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
335 tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
336 tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
341 for (idx=0; idx < 4; idx++)
342 es_putc (tmp[idx], state->stream);
343 if (es_ferror (state->stream))
348 for (idx=0; idx < 4; idx++)
349 putc (tmp[idx], state->fp);
350 if (ferror (state->fp))
354 if (++quad_count >= (64/4))
357 if (!(state->flags & B64ENC_NO_LINEFEEDS)
358 && my_fputs ("\n", state) == EOF)
363 /* Finish the last line and write the trailer. */
365 && !(state->flags & B64ENC_NO_LINEFEEDS)
366 && my_fputs ("\n", state) == EOF)
369 if ( (state->flags & B64ENC_USE_PGPCRC) )
372 my_fputs ("=", state);
373 radbuf[0] = state->crc >>16;
374 radbuf[1] = state->crc >> 8;
375 radbuf[2] = state->crc;
376 tmp[0] = bintoasc[(*radbuf>>2)&077];
377 tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
378 tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
379 tmp[3] = bintoasc[radbuf[2]&077];
382 for (idx=0; idx < 4; idx++)
383 es_putc (tmp[idx], state->stream);
384 if (es_ferror (state->stream))
389 for (idx=0; idx < 4; idx++)
390 putc (tmp[idx], state->fp);
391 if (ferror (state->fp))
394 if (!(state->flags & B64ENC_NO_LINEFEEDS)
395 && my_fputs ("\n", state) == EOF)
401 if ( my_fputs ("-----END ", state) == EOF
402 || my_fputs (state->title, state) == EOF
403 || my_fputs ("-----\n", state) == EOF)
410 err = gpg_error_from_syserror ();
415 xfree (state->title);
419 state->stream = NULL;
420 state->lasterr = err;