Smartcard related updates
[gnupg.git] / common / b64enc.c
1 /* b64enc.c - Simple Base64 encoder.
2  * Copyright (C) 2001, 2003, 2004, 2008, 2010 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <assert.h>
26
27 #include "i18n.h"
28 #include "util.h"
29
30 #define B64ENC_DID_HEADER   1
31 #define B64ENC_DID_TRAILER  2
32 #define B64ENC_NO_LINEFEEDS 16
33 #define B64ENC_USE_PGPCRC   32
34
35 /* The base-64 character list */
36 static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
37                                     "abcdefghijklmnopqrstuvwxyz" 
38                                     "0123456789+/"; 
39
40 /* Stuff required to create the OpenPGP CRC.  This crc_table has been
41    created using this code:
42
43    #include <stdio.h>
44    #include <stdint.h>
45    
46    #define CRCPOLY 0x864CFB
47    
48    int
49    main (void)
50    {
51      int i, j;
52      uint32_t t;
53      uint32_t crc_table[256];
54    
55      crc_table[0] = 0;
56      for (i=j=0; j < 128; j++ )
57        {
58          t = crc_table[j];
59          if ( (t & 0x00800000) )
60            {
61              t <<= 1;
62              crc_table[i++] = t ^ CRCPOLY;
63              crc_table[i++] = t;
64         }
65          else
66            {
67              t <<= 1;
68              crc_table[i++] = t;
69              crc_table[i++] = t ^ CRCPOLY;
70         }
71        }
72    
73      puts ("static const u32 crc_table[256] = {");
74      for (i=j=0; i < 256; i++)
75        {
76          printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]);
77          if (i != 255)
78            {
79              putchar (',');
80              if ( ++j > 5)
81                {
82                  j = 0;
83                  putchar ('\n');
84                }
85            }
86        }
87      puts ("\n};");
88      return 0;
89    }
90 */
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
136 };
137
138
139 static gpg_error_t
140 enc_start (struct b64state *state, FILE *fp, estream_t stream,
141            const char *title)
142 {
143   memset (state, 0, sizeof *state);
144   state->fp = fp;
145   state->stream = stream;
146   if (title && !*title)
147     state->flags |= B64ENC_NO_LINEFEEDS;
148   else if (title)
149     {
150       if (!strncmp (title, "PGP ", 4))
151         {
152           state->flags |= B64ENC_USE_PGPCRC;
153           state->crc = CRCINIT;
154         }
155       state->title = xtrystrdup (title);
156       if (!state->title)
157         return gpg_error_from_syserror ();
158     }
159   return 0;
160 }
161
162
163 /* Prepare for base-64 writing to the stream FP.  If TITLE is not NULL
164    and not an empty string, this string will be used as the title for
165    the armor lines, with TITLE being an empty string, we don't write
166    the header lines and furthermore even don't write any linefeeds.
167    If TITLE starts with "PGP " the OpenPGP CRC checksum will be
168    written as well.  With TITLE beeing NULL, we merely don't write
169    header but make sure that lines are not too long. Note, that we
170    don't write any output unless at least one byte get written using
171    b64enc_write. */
172 gpg_error_t
173 b64enc_start (struct b64state *state, FILE *fp, const char *title)
174 {
175   return enc_start (state, fp, NULL, title);
176 }
177
178 /* Same as b64enc_start but takes an estream.  */
179 gpg_error_t
180 b64enc_start_es (struct b64state *state, estream_t fp, const char *title)
181 {
182   return enc_start (state, NULL, fp, title);
183 }
184
185
186 static int
187 my_fputs (const char *string, struct b64state *state)
188 {
189   if (state->stream)
190     return es_fputs (string, state->stream);
191   else
192     return fputs (string, state->fp);
193 }
194
195
196 /* Write NBYTES from BUFFER to the Base 64 stream identified by
197    STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
198    stream. */
199 gpg_error_t
200 b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
201 {
202   unsigned char radbuf[4];
203   int idx, quad_count;
204   const unsigned char *p;
205
206
207   if (!nbytes)
208     {
209       if (buffer)
210         if (state->stream? es_fflush (state->stream) : fflush (state->fp))
211           goto write_error;
212       return 0;
213     }
214
215   if (!(state->flags & B64ENC_DID_HEADER))
216     {
217       if (state->title)
218         {
219           if ( my_fputs ("-----BEGIN ", state) == EOF
220                || my_fputs (state->title, state) == EOF
221                || my_fputs ("-----\n", state) == EOF)
222             goto write_error;
223           if ( (state->flags & B64ENC_USE_PGPCRC) 
224                && my_fputs ("\n", state) == EOF)
225             goto write_error;
226         }
227         
228       state->flags |= B64ENC_DID_HEADER;
229     }
230
231   idx = state->idx;
232   quad_count = state->quad_count;
233   assert (idx < 4);
234   memcpy (radbuf, state->radbuf, idx);
235
236   if ( (state->flags & B64ENC_USE_PGPCRC) )
237     {
238       size_t n;
239       u32 crc = state->crc;
240
241       for (p=buffer, n=nbytes; n; p++, n-- )
242         crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p];
243       state->crc = (crc & 0x00ffffff);
244     }
245
246   for (p=buffer; nbytes; p++, nbytes--)
247     {
248       radbuf[idx++] = *p;
249       if (idx > 2)
250         {
251           char tmp[4];
252
253           tmp[0] = bintoasc[(*radbuf >> 2) & 077];
254           tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
255           tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
256           tmp[3] = bintoasc[radbuf[2]&077];
257           if (state->stream)
258             {
259               for (idx=0; idx < 4; idx++)
260                 es_putc (tmp[idx], state->stream);
261               idx = 0;
262               if (es_ferror (state->stream))
263                 goto write_error;
264             }
265           else
266             {
267               for (idx=0; idx < 4; idx++)
268                 putc (tmp[idx], state->fp);
269               idx = 0;
270               if (ferror (state->fp))
271                 goto write_error;
272             }
273           if (++quad_count >= (64/4)) 
274             {
275               quad_count = 0;
276               if (!(state->flags & B64ENC_NO_LINEFEEDS)
277                   && my_fputs ("\n", state) == EOF)
278                 goto write_error;
279             }
280         }
281     }
282   memcpy (state->radbuf, radbuf, idx);
283   state->idx = idx;
284   state->quad_count = quad_count;
285   return 0;
286
287  write_error:
288   return gpg_error_from_syserror ();
289 }
290
291
292 gpg_error_t
293 b64enc_finish (struct b64state *state)
294 {
295   gpg_error_t err = 0;
296   unsigned char radbuf[4];
297   int idx, quad_count;
298   char tmp[4];
299
300   if (!(state->flags & B64ENC_DID_HEADER))
301     goto cleanup;
302
303   /* Flush the base64 encoding */
304   idx = state->idx;
305   quad_count = state->quad_count;
306   assert (idx < 4);
307   memcpy (radbuf, state->radbuf, idx);
308
309   if (idx)
310     {
311       tmp[0] = bintoasc[(*radbuf>>2)&077];
312       if (idx == 1)
313         {
314           tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
315           tmp[2] = '=';
316           tmp[3] = '=';
317         }
318       else 
319         { 
320           tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
321           tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
322           tmp[3] = '=';
323         }
324       if (state->stream)
325         {
326           for (idx=0; idx < 4; idx++)
327             es_putc (tmp[idx], state->stream);
328           idx = 0;
329           if (es_ferror (state->stream))
330             goto write_error;
331         }
332       else
333         {
334           for (idx=0; idx < 4; idx++)
335             putc (tmp[idx], state->fp);
336           idx = 0;
337           if (ferror (state->fp))
338             goto write_error;
339         }
340
341       if (++quad_count >= (64/4)) 
342         {
343           quad_count = 0;
344           if (!(state->flags & B64ENC_NO_LINEFEEDS)
345               && my_fputs ("\n", state) == EOF)
346             goto write_error;
347         }
348     }
349
350   /* Finish the last line and write the trailer. */
351   if (quad_count
352       && !(state->flags & B64ENC_NO_LINEFEEDS)
353       && my_fputs ("\n", state) == EOF)
354     goto write_error;
355   
356   if ( (state->flags & B64ENC_USE_PGPCRC) )
357     {
358       /* Write the CRC.  */
359       my_fputs ("=", state);
360       radbuf[0] = state->crc >>16;
361       radbuf[1] = state->crc >> 8;
362       radbuf[2] = state->crc;
363       tmp[0] = bintoasc[(*radbuf>>2)&077];
364       tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
365       tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
366       tmp[3] = bintoasc[radbuf[2]&077];
367       if (state->stream)
368         {
369           for (idx=0; idx < 4; idx++)
370             es_putc (tmp[idx], state->stream);
371           if (es_ferror (state->stream))
372             goto write_error;
373         }
374       else
375         {
376           for (idx=0; idx < 4; idx++)
377             putc (tmp[idx], state->fp);
378           if (ferror (state->fp))
379             goto write_error;
380         }
381       if (!(state->flags & B64ENC_NO_LINEFEEDS)
382           && my_fputs ("\n", state) == EOF)
383         goto write_error;
384     }
385
386   if (state->title)
387     {
388       if ( my_fputs ("-----END ", state) == EOF
389            || my_fputs (state->title, state) == EOF
390            || my_fputs ("-----\n", state) == EOF)
391         goto write_error;
392     }
393
394   goto cleanup;
395
396  write_error:
397   err = gpg_error_from_syserror ();
398
399  cleanup:
400   if (state->title)
401     {
402       xfree (state->title);
403       state->title = NULL;
404     }
405   state->fp = NULL;
406   state->stream = NULL;
407   return err;
408 }
409