Coverage Report

Created: 2024-11-21 07:03

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