chiark / gitweb /
Import gnupg2_2.1.17.orig.tar.bz2
[gnupg2.git] / common / b64enc.c
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 g10 Code GmbH
6  *
7  * This file is part of GnuPG.
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  */
22
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <assert.h>
29
30 #include "i18n.h"
31 #include "util.h"
32
33 #define B64ENC_DID_HEADER   1
34 #define B64ENC_DID_TRAILER  2
35 #define B64ENC_NO_LINEFEEDS 16
36 #define B64ENC_USE_PGPCRC   32
37
38 /* The base-64 character list */
39 static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
40                                     "abcdefghijklmnopqrstuvwxyz"
41                                     "0123456789+/";
42
43 /* Stuff required to create the OpenPGP CRC.  This crc_table has been
44    created using this code:
45
46    #include <stdio.h>
47    #include <stdint.h>
48
49    #define CRCPOLY 0x864CFB
50
51    int
52    main (void)
53    {
54      int i, j;
55      uint32_t t;
56      uint32_t crc_table[256];
57
58      crc_table[0] = 0;
59      for (i=j=0; j < 128; j++ )
60        {
61          t = crc_table[j];
62          if ( (t & 0x00800000) )
63            {
64              t <<= 1;
65              crc_table[i++] = t ^ CRCPOLY;
66              crc_table[i++] = t;
67         }
68          else
69            {
70              t <<= 1;
71              crc_table[i++] = t;
72              crc_table[i++] = t ^ CRCPOLY;
73         }
74        }
75
76      puts ("static const u32 crc_table[256] = {");
77      for (i=j=0; i < 256; i++)
78        {
79          printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]);
80          if (i != 255)
81            {
82              putchar (',');
83              if ( ++j > 5)
84                {
85                  j = 0;
86                  putchar ('\n');
87                }
88            }
89        }
90      puts ("\n};");
91      return 0;
92    }
93 */
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
139 };
140
141
142 static gpg_error_t
143 enc_start (struct b64state *state, FILE *fp, estream_t stream,
144            const char *title)
145 {
146   memset (state, 0, sizeof *state);
147   state->fp = fp;
148   state->stream = stream;
149   state->lasterr = 0;
150   if (title && !*title)
151     state->flags |= B64ENC_NO_LINEFEEDS;
152   else if (title)
153     {
154       if (!strncmp (title, "PGP ", 4))
155         {
156           state->flags |= B64ENC_USE_PGPCRC;
157           state->crc = CRCINIT;
158         }
159       state->title = xtrystrdup (title);
160       if (!state->title)
161         state->lasterr = gpg_error_from_syserror ();
162     }
163   return state->lasterr;
164 }
165
166
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
175    b64enc_write. */
176 gpg_error_t
177 b64enc_start (struct b64state *state, FILE *fp, const char *title)
178 {
179   return enc_start (state, fp, NULL, title);
180 }
181
182 /* Same as b64enc_start but takes an estream.  */
183 gpg_error_t
184 b64enc_start_es (struct b64state *state, estream_t fp, const char *title)
185 {
186   return enc_start (state, NULL, fp, title);
187 }
188
189
190 static int
191 my_fputs (const char *string, struct b64state *state)
192 {
193   if (state->stream)
194     return es_fputs (string, state->stream);
195   else
196     return fputs (string, state->fp);
197 }
198
199
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
202    stream. */
203 gpg_error_t
204 b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
205 {
206   unsigned char radbuf[4];
207   int idx, quad_count;
208   const unsigned char *p;
209
210   if (state->lasterr)
211     return state->lasterr;
212
213   if (!nbytes)
214     {
215       if (buffer)
216         if (state->stream? es_fflush (state->stream) : fflush (state->fp))
217           goto write_error;
218       return 0;
219     }
220
221   if (!(state->flags & B64ENC_DID_HEADER))
222     {
223       if (state->title)
224         {
225           if ( my_fputs ("-----BEGIN ", state) == EOF
226                || my_fputs (state->title, state) == EOF
227                || my_fputs ("-----\n", state) == EOF)
228             goto write_error;
229           if ( (state->flags & B64ENC_USE_PGPCRC)
230                && my_fputs ("\n", state) == EOF)
231             goto write_error;
232         }
233
234       state->flags |= B64ENC_DID_HEADER;
235     }
236
237   idx = state->idx;
238   quad_count = state->quad_count;
239   assert (idx < 4);
240   memcpy (radbuf, state->radbuf, idx);
241
242   if ( (state->flags & B64ENC_USE_PGPCRC) )
243     {
244       size_t n;
245       u32 crc = state->crc;
246
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);
250     }
251
252   for (p=buffer; nbytes; p++, nbytes--)
253     {
254       radbuf[idx++] = *p;
255       if (idx > 2)
256         {
257           char tmp[4];
258
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];
263           if (state->stream)
264             {
265               for (idx=0; idx < 4; idx++)
266                 es_putc (tmp[idx], state->stream);
267               idx = 0;
268               if (es_ferror (state->stream))
269                 goto write_error;
270             }
271           else
272             {
273               for (idx=0; idx < 4; idx++)
274                 putc (tmp[idx], state->fp);
275               idx = 0;
276               if (ferror (state->fp))
277                 goto write_error;
278             }
279           if (++quad_count >= (64/4))
280             {
281               quad_count = 0;
282               if (!(state->flags & B64ENC_NO_LINEFEEDS)
283                   && my_fputs ("\n", state) == EOF)
284                 goto write_error;
285             }
286         }
287     }
288   memcpy (state->radbuf, radbuf, idx);
289   state->idx = idx;
290   state->quad_count = quad_count;
291   return 0;
292
293  write_error:
294   state->lasterr = gpg_error_from_syserror ();
295   if (state->title)
296     {
297       xfree (state->title);
298       state->title = NULL;
299     }
300   return state->lasterr;
301 }
302
303
304 gpg_error_t
305 b64enc_finish (struct b64state *state)
306 {
307   gpg_error_t err = 0;
308   unsigned char radbuf[4];
309   int idx, quad_count;
310   char tmp[4];
311
312   if (state->lasterr)
313     return state->lasterr;
314
315   if (!(state->flags & B64ENC_DID_HEADER))
316     goto cleanup;
317
318   /* Flush the base64 encoding */
319   idx = state->idx;
320   quad_count = state->quad_count;
321   assert (idx < 4);
322   memcpy (radbuf, state->radbuf, idx);
323
324   if (idx)
325     {
326       tmp[0] = bintoasc[(*radbuf>>2)&077];
327       if (idx == 1)
328         {
329           tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
330           tmp[2] = '=';
331           tmp[3] = '=';
332         }
333       else
334         {
335           tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
336           tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
337           tmp[3] = '=';
338         }
339       if (state->stream)
340         {
341           for (idx=0; idx < 4; idx++)
342             es_putc (tmp[idx], state->stream);
343           if (es_ferror (state->stream))
344             goto write_error;
345         }
346       else
347         {
348           for (idx=0; idx < 4; idx++)
349             putc (tmp[idx], state->fp);
350           if (ferror (state->fp))
351             goto write_error;
352         }
353
354       if (++quad_count >= (64/4))
355         {
356           quad_count = 0;
357           if (!(state->flags & B64ENC_NO_LINEFEEDS)
358               && my_fputs ("\n", state) == EOF)
359             goto write_error;
360         }
361     }
362
363   /* Finish the last line and write the trailer. */
364   if (quad_count
365       && !(state->flags & B64ENC_NO_LINEFEEDS)
366       && my_fputs ("\n", state) == EOF)
367     goto write_error;
368
369   if ( (state->flags & B64ENC_USE_PGPCRC) )
370     {
371       /* Write the CRC.  */
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];
380       if (state->stream)
381         {
382           for (idx=0; idx < 4; idx++)
383             es_putc (tmp[idx], state->stream);
384           if (es_ferror (state->stream))
385             goto write_error;
386         }
387       else
388         {
389           for (idx=0; idx < 4; idx++)
390             putc (tmp[idx], state->fp);
391           if (ferror (state->fp))
392             goto write_error;
393         }
394       if (!(state->flags & B64ENC_NO_LINEFEEDS)
395           && my_fputs ("\n", state) == EOF)
396         goto write_error;
397     }
398
399   if (state->title)
400     {
401       if ( my_fputs ("-----END ", state) == EOF
402            || my_fputs (state->title, state) == EOF
403            || my_fputs ("-----\n", state) == EOF)
404         goto write_error;
405     }
406
407   goto cleanup;
408
409  write_error:
410   err = gpg_error_from_syserror ();
411
412  cleanup:
413   if (state->title)
414     {
415       xfree (state->title);
416       state->title = NULL;
417     }
418   state->fp = NULL;
419   state->stream = NULL;
420   state->lasterr = err;
421   return err;
422 }