updated doc
[gnutls.git] / lib / opencdk / armor.c
blob8491aa993c1661aa4e4a46b7c3950f2b1d8f0622
1 /* armor.c - Armor filters
2 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2007, 2008, 2010
3 * Free Software Foundation, Inc.
5 * Author: Timo Schulz
7 * This file is part of OpenCDK.
9 * The OpenCDK library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 * USA
24 * ChangeLog for basic BASE64 code (base64_encode, base64_decode):
25 * Original author: Eric S. Raymond (Fetchmail)
26 * Heavily modified by Brendan Cully <brendan@kublai.com> (Mutt)
27 * Modify the code for generic use by Timo Schulz <twoaday@freakmail.de>
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/stat.h>
37 #include "opencdk.h"
38 #include "main.h"
39 #include "filters.h"
41 #ifdef __MINGW32__
42 #define LF "\r\n"
43 #define ALTLF "\n"
44 #else
45 #define LF "\n"
46 #define ALTLF "\r\n"
47 #endif
49 #define CRCINIT 0xB704CE
51 #define BAD -1
52 #define b64val(c) index64[(unsigned int)(c)]
54 static u32 crc_table[] = {
55 0x000000, 0x864CFB, 0x8AD50D, 0x0C99F6, 0x93E6E1, 0x15AA1A, 0x1933EC,
56 0x9F7F17,
57 0xA18139, 0x27CDC2, 0x2B5434, 0xAD18CF, 0x3267D8, 0xB42B23, 0xB8B2D5,
58 0x3EFE2E,
59 0xC54E89, 0x430272, 0x4F9B84, 0xC9D77F, 0x56A868, 0xD0E493, 0xDC7D65,
60 0x5A319E,
61 0x64CFB0, 0xE2834B, 0xEE1ABD, 0x685646, 0xF72951, 0x7165AA, 0x7DFC5C,
62 0xFBB0A7,
63 0x0CD1E9, 0x8A9D12, 0x8604E4, 0x00481F, 0x9F3708, 0x197BF3, 0x15E205,
64 0x93AEFE,
65 0xAD50D0, 0x2B1C2B, 0x2785DD, 0xA1C926, 0x3EB631, 0xB8FACA, 0xB4633C,
66 0x322FC7,
67 0xC99F60, 0x4FD39B, 0x434A6D, 0xC50696, 0x5A7981, 0xDC357A, 0xD0AC8C,
68 0x56E077,
69 0x681E59, 0xEE52A2, 0xE2CB54, 0x6487AF, 0xFBF8B8, 0x7DB443, 0x712DB5,
70 0xF7614E,
71 0x19A3D2, 0x9FEF29, 0x9376DF, 0x153A24, 0x8A4533, 0x0C09C8, 0x00903E,
72 0x86DCC5,
73 0xB822EB, 0x3E6E10, 0x32F7E6, 0xB4BB1D, 0x2BC40A, 0xAD88F1, 0xA11107,
74 0x275DFC,
75 0xDCED5B, 0x5AA1A0, 0x563856, 0xD074AD, 0x4F0BBA, 0xC94741, 0xC5DEB7,
76 0x43924C,
77 0x7D6C62, 0xFB2099, 0xF7B96F, 0x71F594, 0xEE8A83, 0x68C678, 0x645F8E,
78 0xE21375,
79 0x15723B, 0x933EC0, 0x9FA736, 0x19EBCD, 0x8694DA, 0x00D821, 0x0C41D7,
80 0x8A0D2C,
81 0xB4F302, 0x32BFF9, 0x3E260F, 0xB86AF4, 0x2715E3, 0xA15918, 0xADC0EE,
82 0x2B8C15,
83 0xD03CB2, 0x567049, 0x5AE9BF, 0xDCA544, 0x43DA53, 0xC596A8, 0xC90F5E,
84 0x4F43A5,
85 0x71BD8B, 0xF7F170, 0xFB6886, 0x7D247D, 0xE25B6A, 0x641791, 0x688E67,
86 0xEEC29C,
87 0x3347A4, 0xB50B5F, 0xB992A9, 0x3FDE52, 0xA0A145, 0x26EDBE, 0x2A7448,
88 0xAC38B3,
89 0x92C69D, 0x148A66, 0x181390, 0x9E5F6B, 0x01207C, 0x876C87, 0x8BF571,
90 0x0DB98A,
91 0xF6092D, 0x7045D6, 0x7CDC20, 0xFA90DB, 0x65EFCC, 0xE3A337, 0xEF3AC1,
92 0x69763A,
93 0x578814, 0xD1C4EF, 0xDD5D19, 0x5B11E2, 0xC46EF5, 0x42220E, 0x4EBBF8,
94 0xC8F703,
95 0x3F964D, 0xB9DAB6, 0xB54340, 0x330FBB, 0xAC70AC, 0x2A3C57, 0x26A5A1,
96 0xA0E95A,
97 0x9E1774, 0x185B8F, 0x14C279, 0x928E82, 0x0DF195, 0x8BBD6E, 0x872498,
98 0x016863,
99 0xFAD8C4, 0x7C943F, 0x700DC9, 0xF64132, 0x693E25, 0xEF72DE, 0xE3EB28,
100 0x65A7D3,
101 0x5B59FD, 0xDD1506, 0xD18CF0, 0x57C00B, 0xC8BF1C, 0x4EF3E7, 0x426A11,
102 0xC426EA,
103 0x2AE476, 0xACA88D, 0xA0317B, 0x267D80, 0xB90297, 0x3F4E6C, 0x33D79A,
104 0xB59B61,
105 0x8B654F, 0x0D29B4, 0x01B042, 0x87FCB9, 0x1883AE, 0x9ECF55, 0x9256A3,
106 0x141A58,
107 0xEFAAFF, 0x69E604, 0x657FF2, 0xE33309, 0x7C4C1E, 0xFA00E5, 0xF69913,
108 0x70D5E8,
109 0x4E2BC6, 0xC8673D, 0xC4FECB, 0x42B230, 0xDDCD27, 0x5B81DC, 0x57182A,
110 0xD154D1,
111 0x26359F, 0xA07964, 0xACE092, 0x2AAC69, 0xB5D37E, 0x339F85, 0x3F0673,
112 0xB94A88,
113 0x87B4A6, 0x01F85D, 0x0D61AB, 0x8B2D50, 0x145247, 0x921EBC, 0x9E874A,
114 0x18CBB1,
115 0xE37B16, 0x6537ED, 0x69AE1B, 0xEFE2E0, 0x709DF7, 0xF6D10C, 0xFA48FA,
116 0x7C0401,
117 0x42FA2F, 0xC4B6D4, 0xC82F22, 0x4E63D9, 0xD11CCE, 0x575035, 0x5BC9C3,
118 0xDD8538
121 static const char *armor_begin[] = {
122 "BEGIN PGP MESSAGE",
123 "BEGIN PGP PUBLIC KEY BLOCK",
124 "BEGIN PGP PRIVATE KEY BLOCK",
125 "BEGIN PGP SIGNATURE",
126 NULL
129 static const char *armor_end[] = {
130 "END PGP MESSAGE",
131 "END PGP PUBLIC KEY BLOCK",
132 "END PGP PRIVATE KEY BLOCK",
133 "END PGP SIGNATURE",
134 NULL
137 static const char *valid_headers[] = {
138 "Comment",
139 "Version",
140 "MessageID",
141 "Hash",
142 "Charset",
143 NULL
146 static char b64chars[] =
147 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
149 static int index64[128] = {
150 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
151 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
152 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
153 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
154 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
155 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
156 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
157 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
161 /* encode a raw binary buffer to a null-terminated base64 strings */
162 static int
163 base64_encode (char *out, const byte * in, size_t len, size_t olen)
165 if (!out || !in)
167 gnutls_assert ();
168 return CDK_Inv_Value;
171 while (len >= 3 && olen > 10)
173 *out++ = b64chars[in[0] >> 2];
174 *out++ = b64chars[((in[0] << 4) & 0x30) | (in[1] >> 4)];
175 *out++ = b64chars[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
176 *out++ = b64chars[in[2] & 0x3f];
177 olen -= 4;
178 len -= 3;
179 in += 3;
182 /* clean up remainder */
183 if (len > 0 && olen > 4)
185 byte fragment = 0;
186 *out++ = b64chars[in[0] >> 2];
187 fragment = (in[0] << 4) & 0x30;
188 if (len > 1)
189 fragment |= in[1] >> 4;
190 *out++ = b64chars[fragment];
191 *out++ = (len < 2) ? '=' : b64chars[(in[1] << 2) & 0x3c];
192 *out++ = '=';
194 *out = '\0';
195 return 0;
199 /* Convert '\0'-terminated base64 string to raw byte buffer.
200 Returns length of returned buffer, or -1 on error. */
201 static int
202 base64_decode (byte * out, const char *in)
204 size_t len;
205 byte digit1, digit2, digit3, digit4;
207 if (!out || !in)
209 gnutls_assert ();
210 return -1;
213 len = 0;
216 digit1 = in[0];
217 if (digit1 > 127 || b64val (digit1) == BAD)
219 gnutls_assert ();
220 return -1;
222 digit2 = in[1];
223 if (digit2 > 127 || b64val (digit2) == BAD)
225 gnutls_assert ();
226 return -1;
228 digit3 = in[2];
229 if (digit3 > 127 || ((digit3 != '=') && (b64val (digit3) == BAD)))
231 gnutls_assert ();
232 return -1;
234 digit4 = in[3];
235 if (digit4 > 127 || ((digit4 != '=') && (b64val (digit4) == BAD)))
237 gnutls_assert ();
238 return -1;
240 in += 4;
242 /* digits are already sanity-checked */
243 *out++ = (b64val (digit1) << 2) | (b64val (digit2) >> 4);
244 len++;
245 if (digit3 != '=')
247 *out++ = ((b64val (digit2) << 4) & 0xf0) | (b64val (digit3) >> 2);
248 len++;
249 if (digit4 != '=')
251 *out++ = ((b64val (digit3) << 6) & 0xc0) | b64val (digit4);
252 len++;
256 while (*in && digit4 != '=');
258 return len;
262 /* Return the compression algorithm in @r_zipalgo.
263 If the parameter is not set after execution,
264 the stream is not compressed. */
265 static int
266 compress_get_algo (cdk_stream_t inp, int *r_zipalgo)
268 byte plain[512];
269 char buf[128];
270 int nread, pkttype;
272 *r_zipalgo = 0;
273 cdk_stream_seek (inp, 0);
274 while (!cdk_stream_eof (inp))
276 nread = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
277 if (!nread || nread == -1)
278 break;
279 if (nread == 1 && !cdk_stream_eof (inp)
280 && (nread = _cdk_stream_gets (inp, buf, DIM (buf) - 1)) > 0)
282 base64_decode (plain, buf);
283 if (!(*plain & 0x80))
284 break;
285 pkttype = *plain & 0x40 ? (*plain & 0x3f) : ((*plain >> 2) & 0xf);
286 if (pkttype == CDK_PKT_COMPRESSED && r_zipalgo)
288 _gnutls_buffers_log ("armor compressed (algo=%d)\n",
289 *(plain + 1));
290 *r_zipalgo = *(plain + 1);
292 break;
295 return 0;
299 static int
300 check_armor (cdk_stream_t inp, int *r_zipalgo)
302 char buf[4096];
303 size_t nread;
304 int check;
306 check = 0;
307 nread = cdk_stream_read (inp, buf, DIM (buf) - 1);
308 if (nread > 0)
310 buf[nread] = '\0';
311 if (strstr (buf, "-----BEGIN PGP"))
313 compress_get_algo (inp, r_zipalgo);
314 check = 1;
316 cdk_stream_seek (inp, 0);
318 return check;
322 static int
323 is_armored (int ctb)
325 int pkttype = 0;
327 if (!(ctb & 0x80))
329 gnutls_assert ();
330 return 1; /* invalid packet: assume it is armored */
332 pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb >> 2) & 0xf);
333 switch (pkttype)
335 case CDK_PKT_MARKER:
336 case CDK_PKT_ONEPASS_SIG:
337 case CDK_PKT_PUBLIC_KEY:
338 case CDK_PKT_SECRET_KEY:
339 case CDK_PKT_PUBKEY_ENC:
340 case CDK_PKT_SIGNATURE:
341 case CDK_PKT_LITERAL:
342 case CDK_PKT_COMPRESSED:
343 return 0; /* seems to be a regular packet: not armored */
345 return 1;
349 static u32
350 update_crc (u32 crc, const byte * buf, size_t buflen)
352 unsigned int j;
354 if (!crc)
355 crc = CRCINIT;
357 for (j = 0; j < buflen; j++)
358 crc = (crc << 8) ^ crc_table[0xff & ((crc >> 16) ^ buf[j])];
359 crc &= 0xffffff;
360 return crc;
364 static cdk_error_t
365 armor_encode (void *data, FILE * in, FILE * out)
367 armor_filter_t *afx = data;
368 struct stat statbuf;
369 char crcbuf[5], buf[128], raw[49];
370 byte crcbuf2[3];
371 size_t nread = 0;
372 const char *lf;
374 if (!afx)
376 gnutls_assert ();
377 return CDK_Inv_Value;
379 if (afx->idx < 0 || afx->idx > (int) DIM (armor_begin) ||
380 afx->idx2 < 0 || afx->idx2 > (int) DIM (armor_end))
382 gnutls_assert ();
383 return CDK_Inv_Value;
386 _gnutls_buffers_log ("armor filter: encode\n");
388 memset (crcbuf, 0, sizeof (crcbuf));
390 lf = afx->le ? afx->le : LF;
391 fprintf (out, "-----%s-----%s", armor_begin[afx->idx], lf);
392 fprintf (out, "Version: OpenPrivacy " PACKAGE_VERSION "%s", lf);
393 if (afx->hdrlines)
394 fwrite (afx->hdrlines, 1, strlen (afx->hdrlines), out);
395 fprintf (out, "%s", lf);
397 if (fstat (fileno (in), &statbuf))
399 gnutls_assert ();
400 return CDK_General_Error;
403 while (!feof (in))
405 nread = fread (raw, 1, DIM (raw) - 1, in);
406 if (!nread)
407 break;
408 if (ferror (in))
410 gnutls_assert ();
411 return CDK_File_Error;
413 afx->crc = update_crc (afx->crc, (byte *) raw, nread);
414 base64_encode (buf, (byte *) raw, nread, DIM (buf) - 1);
415 fprintf (out, "%s%s", buf, lf);
418 crcbuf2[0] = afx->crc >> 16;
419 crcbuf2[1] = afx->crc >> 8;
420 crcbuf2[2] = afx->crc;
421 crcbuf[0] = b64chars[crcbuf2[0] >> 2];
422 crcbuf[1] = b64chars[((crcbuf2[0] << 4) & 0x30) | (crcbuf2[1] >> 4)];
423 crcbuf[2] = b64chars[((crcbuf2[1] << 2) & 0x3c) | (crcbuf2[2] >> 6)];
424 crcbuf[3] = b64chars[crcbuf2[2] & 0x3f];
425 fprintf (out, "=%s%s", crcbuf, lf);
426 fprintf (out, "-----%s-----%s", armor_end[afx->idx2], lf);
428 return 0;
433 * cdk_armor_filter_use:
434 * @inp: the stream to check
436 * Check if the stream contains armored data.
439 cdk_armor_filter_use (cdk_stream_t inp)
441 int c, check;
442 int zipalgo;
444 zipalgo = 0;
445 c = cdk_stream_getc (inp);
446 if (c == EOF)
447 return 0; /* EOF, doesn't matter whether armored or not */
448 cdk_stream_seek (inp, 0);
449 check = is_armored (c);
450 if (check)
452 check = check_armor (inp, &zipalgo);
453 if (zipalgo)
454 _cdk_stream_set_compress_algo (inp, zipalgo);
456 return check;
460 static int
461 search_header (const char *buf, const char **array)
463 const char *s;
464 int i;
466 if (strlen (buf) < 5 || strncmp (buf, "-----", 5))
468 gnutls_assert ();
469 return -1;
471 for (i = 0; (s = array[i]); i++)
473 if (!strncmp (s, buf + 5, strlen (s)))
474 return i;
476 return -1;
480 const char *
481 _cdk_armor_get_lineend (void)
483 return LF;
487 static cdk_error_t
488 armor_decode (void *data, FILE * in, FILE * out)
490 armor_filter_t *afx = data;
491 const char *s;
492 char buf[127];
493 byte raw[128], crcbuf[4];
494 u32 crc2 = 0;
495 ssize_t nread = 0;
496 int i, pgp_data = 0;
497 cdk_error_t rc = 0;
498 int len;
500 if (!afx)
502 gnutls_assert ();
503 return CDK_Inv_Value;
506 _gnutls_buffers_log ("armor filter: decode\n");
508 fseek (in, 0, SEEK_SET);
509 /* Search the begin of the message */
510 while (!feof (in) && !pgp_data)
512 s = fgets (buf, DIM (buf) - 1, in);
513 if (!s)
514 break;
515 afx->idx = search_header (buf, armor_begin);
516 if (afx->idx >= 0)
517 pgp_data = 1;
520 if (feof (in) || !pgp_data)
522 gnutls_assert ();
523 return CDK_Armor_Error; /* no data found */
526 /* Parse header until the empty line is reached */
527 while (!feof (in))
529 s = fgets (buf, DIM (buf) - 1, in);
530 if (!s)
531 return CDK_EOF;
532 if (strcmp (s, LF) == 0 || strcmp (s, ALTLF) == 0)
534 rc = 0;
535 break; /* empty line */
537 /* From RFC2440: OpenPGP should consider improperly formatted Armor
538 Headers to be corruption of the ASCII Armor. A colon and a single
539 space separate the key and value. */
540 if (!strstr (buf, ": "))
542 gnutls_assert ();
543 return CDK_Armor_Error;
545 rc = CDK_General_Error;
546 for (i = 0; (s = valid_headers[i]); i++)
548 if (!strncmp (s, buf, strlen (s)))
549 rc = 0;
551 if (rc)
553 /* From RFC2440: Unknown keys should be reported to the user,
554 but OpenPGP should continue to process the message. */
555 _cdk_log_info ("unknown header: `%s'\n", buf);
556 rc = 0;
560 /* Read the data body */
561 while (!feof (in))
563 s = fgets (buf, DIM (buf) - 1, in);
564 if (!s)
565 break;
567 len = strlen(buf);
569 if (buf[len - 1] == '\n')
570 buf[len - 1] = '\0';
571 if (buf[len - 1] == '\r')
572 buf[len - 1] = '\0';
573 if (buf[0] == '=' && strlen (s) == 5)
574 { /* CRC */
575 memset (crcbuf, 0, sizeof (crcbuf));
576 base64_decode (crcbuf, buf + 1);
577 crc2 = (crcbuf[0] << 16) | (crcbuf[1] << 8) | crcbuf[2];
578 break; /* stop here */
580 else
582 nread = base64_decode (raw, buf);
583 if (nread == -1 || nread == 0)
584 break;
585 afx->crc = update_crc (afx->crc, raw, nread);
586 fwrite (raw, 1, nread, out);
590 /* Search the tail of the message */
591 s = fgets (buf, DIM (buf) - 1, in);
592 if (s)
594 int len = strlen(buf);
595 if (buf[len - 1] == '\n')
596 buf[len - 1] = '\0';
597 if (buf[len - 1] == '\r')
598 buf[len - 1] = '\0';
599 rc = CDK_General_Error;
600 afx->idx2 = search_header (buf, armor_end);
601 if (afx->idx2 >= 0)
602 rc = 0;
605 /* This catches error when no tail was found or the header is
606 different then the tail line. */
607 if (rc || afx->idx != afx->idx2)
608 rc = CDK_Armor_Error;
610 afx->crc_okay = (afx->crc == crc2) ? 1 : 0;
611 if (!afx->crc_okay && !rc)
613 _gnutls_buffers_log ("file crc=%08X afx_crc=%08X\n",
614 (unsigned int) crc2, (unsigned int) afx->crc);
615 rc = CDK_Armor_CRC_Error;
618 return rc;
623 * cdk_file_armor:
624 * @hd: Handle
625 * @file: Name of the file to protect.
626 * @output: Output filename.
628 * Protect a file with ASCII armor.
630 cdk_error_t
631 cdk_file_armor (cdk_ctx_t hd, const char *file, const char *output)
633 cdk_stream_t inp, out;
634 cdk_error_t rc;
636 rc = _cdk_check_args (hd->opt.overwrite, file, output);
637 if (rc)
638 return rc;
640 rc = cdk_stream_open (file, &inp);
641 if (rc)
643 gnutls_assert ();
644 return rc;
647 rc = cdk_stream_new (output, &out);
648 if (rc)
650 cdk_stream_close (inp);
651 gnutls_assert ();
652 return rc;
655 cdk_stream_set_armor_flag (out, CDK_ARMOR_MESSAGE);
656 if (hd->opt.compress)
657 rc = cdk_stream_set_compress_flag (out, hd->compress.algo,
658 hd->compress.level);
659 if (!rc)
660 rc = cdk_stream_set_literal_flag (out, 0, file);
661 if (!rc)
662 rc = cdk_stream_kick_off (inp, out);
663 if (!rc)
664 rc = _cdk_stream_get_errno (out);
666 cdk_stream_close (out);
667 cdk_stream_close (inp);
668 return rc;
673 * cdk_file_dearmor:
674 * @file: Name of the file to unprotect.
675 * @output: Output filename.
677 * Remove ASCII armor from a file.
679 cdk_error_t
680 cdk_file_dearmor (const char *file, const char *output)
682 cdk_stream_t inp, out;
683 cdk_error_t rc;
684 int zipalgo;
686 rc = _cdk_check_args (1, file, output);
687 if (rc)
689 gnutls_assert ();
690 return rc;
693 rc = cdk_stream_open (file, &inp);
694 if (rc)
696 gnutls_assert ();
697 return rc;
700 rc = cdk_stream_create (output, &out);
701 if (rc)
703 cdk_stream_close (inp);
704 gnutls_assert ();
705 return rc;
708 if (cdk_armor_filter_use (inp))
710 rc = cdk_stream_set_literal_flag (inp, 0, NULL);
711 zipalgo = cdk_stream_is_compressed (inp);
712 if (zipalgo)
713 rc = cdk_stream_set_compress_flag (inp, zipalgo, 0);
714 if (!rc)
715 rc = cdk_stream_set_armor_flag (inp, 0);
716 if (!rc)
717 rc = cdk_stream_kick_off (inp, out);
718 if (!rc)
719 rc = _cdk_stream_get_errno (inp);
722 cdk_stream_close (inp);
723 cdk_stream_close (out);
724 gnutls_assert ();
725 return rc;
730 _cdk_filter_armor (void *data, int ctl, FILE * in, FILE * out)
732 if (ctl == STREAMCTL_READ)
733 return armor_decode (data, in, out);
734 else if (ctl == STREAMCTL_WRITE)
735 return armor_encode (data, in, out);
736 else if (ctl == STREAMCTL_FREE)
738 armor_filter_t *afx = data;
739 if (afx)
741 _gnutls_buffers_log ("free armor filter\n");
742 afx->idx = afx->idx2 = 0;
743 afx->crc = afx->crc_okay = 0;
744 return 0;
748 gnutls_assert ();
749 return CDK_Inv_Mode;
754 * cdk_armor_encode_buffer:
755 * @inbuf: the raw input buffer
756 * @inlen: raw buffer len
757 * @outbuf: the destination buffer for the base64 output
758 * @outlen: destination buffer len
759 * @nwritten: actual length of the base64 data
760 * @type: the base64 file type.
762 * Encode the given buffer into base64 format. The base64
763 * string will be null terminated but the null will
764 * not be contained in the size.
766 cdk_error_t
767 cdk_armor_encode_buffer (const byte * inbuf, size_t inlen,
768 char *outbuf, size_t outlen,
769 size_t * nwritten, int type)
771 const char *head, *tail, *le;
772 byte tempbuf[48];
773 char tempout[128];
774 size_t pos, off, len, rest;
776 if (!inbuf || !nwritten)
778 gnutls_assert ();
779 return CDK_Inv_Value;
781 if (type > CDK_ARMOR_SIGNATURE)
783 gnutls_assert ();
784 return CDK_Inv_Mode;
787 head = armor_begin[type];
788 tail = armor_end[type];
789 le = _cdk_armor_get_lineend ();
790 pos = strlen (head) + 10 + 2 + 2 + strlen (tail) + 10 + 2 + 5 + 2 + 1;
791 /* The output data is 4/3 times larger, plus a line end for each line. */
792 pos += (4 * inlen / 3) + 2 * (4 * inlen / 3 / 64) + 1;
794 if (outbuf && outlen < pos)
796 gnutls_assert ();
797 *nwritten = pos;
798 return CDK_Too_Short;
801 /* Only return the size of the output. */
802 if (!outbuf)
804 *nwritten = pos;
805 return 0;
808 pos = 0;
809 memset (outbuf, 0, outlen);
810 memcpy (outbuf + pos, "-----", 5);
811 pos += 5;
812 memcpy (outbuf + pos, head, strlen (head));
813 pos += strlen (head);
814 memcpy (outbuf + pos, "-----", 5);
815 pos += 5;
816 memcpy (outbuf + pos, le, strlen (le));
817 pos += strlen (le);
818 memcpy (outbuf + pos, le, strlen (le));
819 pos += strlen (le);
820 rest = inlen;
821 for (off = 0; off < inlen;)
823 if (rest > 48)
825 memcpy (tempbuf, inbuf + off, 48);
826 off += 48;
827 len = 48;
829 else
831 memcpy (tempbuf, inbuf + off, rest);
832 off += rest;
833 len = rest;
835 rest -= len;
836 base64_encode (tempout, tempbuf, len, DIM (tempout) - 1);
837 memcpy (outbuf + pos, tempout, strlen (tempout));
838 pos += strlen (tempout);
839 memcpy (outbuf + pos, le, strlen (le));
840 pos += strlen (le);
843 memcpy (outbuf + pos, "-----", 5);
844 pos += 5;
845 memcpy (outbuf + pos, tail, strlen (tail));
846 pos += strlen (tail);
847 memcpy (outbuf + pos, "-----", 5);
848 pos += 5;
849 memcpy (outbuf + pos, le, strlen (le));
850 pos += strlen (le);
851 outbuf[pos] = 0;
852 *nwritten = pos - 1;
853 return 0;