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