1 /* armor.c - Armor flter
2 * Copyright (C) 1998 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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 2 of the License, or
9 * (at your option) any later version.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
40 #define CRCINIT 0xB704CE
41 #define CRCPOLY 0X864CFB
42 #define CRCUPDATE(a,c) do { \
43 a = ((a) << 8) ^ crc_table[((a)&0xff >> 16) ^ (c)]; \
46 static u32 crc_table[256];
47 static byte bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
48 "abcdefghijklmnopqrstuvwxyz"
50 static byte asctobin[256]; /* runtime initialized */
51 static int is_initialized;
71 fhdrCHECKDashEscaped2,
72 fhdrCHECKDashEscaped3,
78 fhdrCLEARSIGSimpleNext,
87 /* if we encounter this armor string with this index, go
88 * into a mode which fakes packets and wait for the next armor */
89 #define BEGIN_SIGNED_MSG_IDX 3
90 static char *head_strings[] = {
92 "BEGIN PGP PUBLIC KEY BLOCK",
93 "BEGIN PGP SIGNATURE",
94 "BEGIN PGP SIGNED MESSAGE",
95 "BEGIN PGP ARMORED FILE", /* gnupg extension */
96 "BEGIN PGP PRIVATE KEY BLOCK",
97 "BEGIN PGP SECRET KEY BLOCK", /* only used by pgp2 */
100 static char *tail_strings[] = {
102 "END PGP PUBLIC KEY BLOCK",
105 "END PGP ARMORED FILE",
106 "END PGP PRIVATE KEY BLOCK",
107 "END PGP SECRET KEY BLOCK",
112 static fhdr_state_t find_header( fhdr_state_t state,
113 byte *buf, size_t *r_buflen,
115 unsigned *r_empty, int *r_hashes,
116 int only_keyblocks, int *not_dashed );
126 /* init the crc lookup table */
128 for(i=j=0; j < 128; j++ ) {
130 if( t & 0x00800000 ) {
132 crc_table[i++] = t ^ CRCPOLY;
138 crc_table[i++] = t ^ CRCPOLY;
141 /* build the helptable for radix64 to bin conversion */
142 for(i=0; i < 256; i++ )
143 asctobin[i] = 255; /* used to detect invalid characters */
144 for(s=bintoasc,i=0; *s; s++,i++ )
151 * Check whether this is an armored file or not
152 * See also parse-packet.c for details on this code
153 * Returns: True if it seems to be armored
156 is_armored( byte *buf )
162 return 1; /* invalid packet: assume it is armored */
163 pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
172 case PKT_OLD_COMMENT:
176 return 0; /* seems to be a regular packet: not armored */
184 * Try to check whether the iobuf is armored
185 * Returns true if this may be the case; the caller should use the
186 * filter to do further processing.
189 use_armor_filter( IOBUF a )
194 n = iobuf_peek(a, buf, 1 );
196 return 0; /* EOF, doesn't matter whether armored or not */
198 return 1; /* can't check it: try armored */
199 return is_armored(buf);
208 write_status(STATUS_BADARMOR);
209 g10_exit(1); /* stop here */
214 * check whether the armor header is valid on a signed message.
215 * this is for security reasons: the header lines are not included in the
216 * hash and by using some creative formatting rules, Mallory could fake
217 * any text at the beginning of a document; assuming it is read with
218 * a simple viewer. We only allow the Hash Header.
221 parse_hash_header( const char *line )
226 if( strlen(line) < 6 || strlen(line) > 60 )
227 return 0; /* too short or too long */
228 if( memcmp( line, "Hash:", 5 ) )
229 return 0; /* invalid header */
231 for(s=line+5;;s=s2) {
232 for(; *s && (*s==' ' || *s == '\t'); s++ )
236 for(s2=s+1; *s2 && *s2!=' ' && *s2 != '\t' && *s2 != ','; s2++ )
238 if( !strncmp( s, "RIPEMD160", s2-s ) )
240 else if( !strncmp( s, "SHA1", s2-s ) )
242 else if( !strncmp( s, "MD5", s2-s ) )
244 else if( !strncmp( s, "TIGER", s2-s ) )
248 for(; *s2 && (*s2==' ' || *s2 == '\t'); s2++ )
250 if( *s2 && *s2 != ',' )
260 * parse an ascii armor.
261 * Returns: the state,
262 * the remaining bytes in BUF are returned in RBUFLEN.
263 * r_empty return the # of empty lines before the buffer
266 find_header( fhdr_state_t state, byte *buf, size_t *r_buflen,
267 IOBUF a, size_t n, unsigned *r_empty, int *r_hashes,
268 int only_keyblocks, int *not_dashed )
280 assert(buflen >= 100 );
281 buflen -= 4; /* reserved room for CR,LF, and two extra */
286 /* read at least the first byte to check whether it is armored
289 for(n=0; n < 28 && (c=iobuf_get(a)) != -1 && c != '\n'; )
291 if( !n && c == '\n' )
292 state = fhdrCHECKBegin;
293 else if( !n || c == -1 )
294 state = fhdrNOArmor; /* too short */
295 else if( !is_armored( buf ) ) {
301 state = fhdrCHECKBegin;
303 state = fhdrINITCont;
306 case fhdrINIT: /* read some stuff into buffer */
308 case fhdrINITCont: /* read more stuff into buffer */
310 for(; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
312 state = c == '\n' ? fhdrCHECKBegin :
313 c == -1 ? fhdrEOF : fhdrINITSkip;
320 while( (c=iobuf_get(a)) != -1 && c != '\n' )
323 state = c == -1? fhdrEOF : fhdrINIT;
327 while( (c=iobuf_get(a)) != -1 && c != '\n' )
329 state = c == -1? fhdrEOF : fhdrWAITHeader;
332 case fhdrWAITHeader: /* wait for Header lines */
334 for(n=0; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
337 if( n < buflen || c == '\n' ) {
338 if( n && buf[0] != '\r') { /* maybe a header */
339 if( strchr( buf, ':') ) { /* yes */
341 if( buf[n-1] == '\r' )
344 log_info(_("armor header: "));
345 print_string( stderr, buf, n, 0 );
348 if( clearsig && !(hashes=parse_hash_header( buf )) ) {
350 && !memcmp( buf, "NotDashEscaped:", 15 ) ) {
352 state = fhdrWAITHeader;
355 log_error(_("invalid clearsig header\n"));
360 state = fhdrWAITHeader;
365 else if( clearsig && n > 15 && !memcmp(buf, "-----", 5 ) )
366 state = fhdrNullClearsig;
368 state = fhdrCHECKDashEscaped3;
370 else if( !n || (buf[0] == '\r' && !buf[1]) ) { /* empty line */
372 state = fhdrWAITClearsig;
374 /* this is not really correct: if we do not have
375 * a clearsig and no armor lines we are not allowed
376 * to have an empty line */
382 log_error(_("invalid armor header: "));
383 print_string( stderr, buf, n, 0 );
389 if( strchr( buf, ':') ) { /* buffer to short, but this is okay*/
391 log_info(_("armor header: "));
392 print_string( stderr, buf, n, 0 );
393 fputs("[...]\n", stderr); /* indicate it is truncated */
395 state = fhdrSKIPHeader; /* skip rest of line */
397 else /* line too long */
404 case fhdrWAITClearsig: /* skip the empty line (for clearsig) */
406 for(n=0; n < buflen && (c=iobuf_get(a)) != -1 && c != '\n'; )
409 if( n > 15 && !memcmp(buf, "-----", 5 ) )
410 state = fhdrNullClearsig;
412 state = fhdrREADClearsigNext;
414 state = fhdrCHECKDashEscaped3;
417 /* fixme: we should check whether this line continues
418 * it is possible that we have only read ws until here
419 * and more stuff is to come */
424 case fhdrNullClearsig: /* zero length cleartext */
425 state = fhdrENDClearsig;
428 case fhdrENDClearsig:
430 state = state == fhdrCHECKBegin ? fhdrINITSkip : fhdrERRORShow;
432 break; /* too short */
433 if( memcmp( buf, "-----", 5 ) )
436 p = strstr(buf+5, "-----");
444 break; /* garbage after dashes */
446 for(i=0; (s=head_strings[i]); i++ )
450 break; /* unknown begin line */
451 if( only_keyblocks && i != 1 && i != 5 && i != 6 )
452 break; /* not a keyblock armor */
454 /* found the begin line */
456 state = fhdrWAITHeader;
457 if( hdr_line == BEGIN_SIGNED_MSG_IDX )
459 if( opt.verbose > 1 )
460 log_info(_("armor: %s\n"), head_strings[hdr_line]);
463 case fhdrCLEARSIGSimple:
464 /* we are at the begin of a new line */
465 case fhdrCLEARSIGSimpleNext:
468 while( n < buflen && (c=iobuf_get(a)) != -1 ) {
476 else if( state == fhdrCLEARSIGSimple
477 && n > 15 && !memcmp(buf, "-----", 5 ) ) {
480 state = fhdrENDClearsig;
483 state = fhdrCLEARSIGSimple;
485 state = fhdrCLEARSIGSimpleNext;
489 case fhdrEMPTYClearsig:
490 case fhdrREADClearsig:
491 /* we are at the start of a line: read a clearsig into the buffer
492 * we have to look for a header line or dashed escaped text*/
495 while( n < buflen && (c=iobuf_get(a)) != -1 && c != '\n' )
500 else if( !n || ( buf[0]=='\r' && !buf[1] ) ) {
501 state = fhdrEMPTYClearsig;
505 state = fhdrCHECKClearsig2;
507 state = fhdrCHECKClearsig;
510 case fhdrCHECKDashEscaped3:
512 state = fhdrTEXTSimple;
515 if( !(n > 1 && buf[0] == '-' && buf[1] == ' ' ) ) {
520 case fhdrCHECKDashEscaped2:
521 case fhdrCHECKDashEscaped:
522 /* check dash escaped line */
523 if( buf[2] == '-' || ( n > 6 && !memcmp(buf+2, "From ", 5))) {
524 for(i=2; i < n; i++ )
527 buf[n] = 0; /* not really needed */
528 state = state == fhdrCHECKDashEscaped3 ? fhdrTEXT :
529 state == fhdrCHECKDashEscaped2 ?
530 fhdrREADClearsig : fhdrTESTSpaces;
533 log_error(_("invalid dash escaped line: "));
534 print_string( stderr, buf, n, 0 );
540 case fhdrCHECKClearsig:
541 /* check the clearsig line */
542 if( n > 15 && !memcmp(buf, "-----", 5 ) )
543 state = fhdrENDClearsig;
544 else if( buf[0] == '-' && buf[1] == ' ' && !*not_dashed )
545 state = fhdrCHECKDashEscaped;
547 state = fhdrTESTSpaces;
551 case fhdrCHECKClearsig2:
552 /* check the clearsig line */
553 if( n > 15 && !memcmp(buf, "-----", 5 ) )
554 state = fhdrENDClearsig;
555 else if( buf[0] == '-' && buf[1] == ' ' && !*not_dashed )
556 state = fhdrCHECKDashEscaped2;
558 state = fhdrREADClearsig;
562 case fhdrREADClearsigNext:
563 /* Read to the end of the line, do not care about checking
564 * for dashed escaped text of headers */
567 while( n < buflen && (c=iobuf_get(a)) != -1 && c != '\n' )
573 state = fhdrREADClearsig;
575 state = fhdrTESTSpaces;
578 case fhdrTESTSpaces: {
579 /* but must check whether the rest of the line
580 * only contains white spaces; this is problematic
581 * since we may have to restore the stuff. simply
582 * counting spaces is not enough, because it may be a
583 * mix of different white space characters */
584 IOBUF b = iobuf_temp();
585 while( (c=iobuf_get(a)) != -1 && c != '\n' ) {
587 if( c != ' ' && c != '\t' && c != '\r' )
591 /* okay we can skip the rest of the line */
593 state = fhdrREADClearsig;
596 iobuf_unget_and_close_temp(a,b);
597 state = fhdrREADClearsigNext;
602 log_error(_("invalid clear text header: "));
603 print_string( stderr, buf, n, 0 );
616 case fhdrWAITClearsig:
618 case fhdrEMPTYClearsig:
619 case fhdrCHECKClearsig:
620 case fhdrCHECKClearsig2:
621 case fhdrCHECKDashEscaped:
622 case fhdrCHECKDashEscaped2:
623 case fhdrCHECKDashEscaped3:
632 if( clearsig && state == fhdrTEXT )
633 state = fhdrCLEARSIG;
634 else if( clearsig && state == fhdrTEXTSimple ) {
635 state = fhdrCLEARSIGSimple;
640 if( state == fhdrCLEARSIG || state == fhdrREADClearsig ) {
641 /* append CR,LF after removing trailing wspaces */
642 for(p=buf+n-1; n; n--, p-- ) {
643 assert( *p != '\n' );
644 if( *p != ' ' && *p != '\t' && *p != '\r' ) {
664 /* figure out whether the data is armored or not */
666 check_input( armor_filter_context_t *afx, IOBUF a )
670 fhdr_state_t state = afx->parse_state;
673 if( state != fhdrENDClearsig )
674 state = fhdrHASArmor;
676 n = DIM(afx->helpbuf);
677 state = find_header( state, afx->helpbuf, &n, a,
678 afx->helplen, &emplines, &afx->hashes,
679 afx->only_keyblocks, &afx->not_dash_escaped );
682 afx->inp_checked = 1;
695 case fhdrNullClearsig:
696 case fhdrCLEARSIG: /* start fake package mode (for clear signatures) */
697 case fhdrREADClearsigNext:
698 case fhdrCLEARSIGSimple:
699 case fhdrCLEARSIGSimpleNext:
708 afx->inp_checked = 1;
717 afx->parse_state = state;
723 /* fake a literal data packet and wait for an armor line */
725 fake_packet( armor_filter_context_t *afx, IOBUF a,
726 size_t *retn, byte *buf, size_t size )
731 fhdr_state_t state = afx->parse_state;
732 unsigned emplines = afx->empty;
734 len = 2; /* reserve 2 bytes for the length header */
735 size -= 3; /* and 1 for empline handling and 2 for the term header */
736 while( !rc && len < size ) {
738 while( emplines && len < size ) {
745 if( state == fhdrENDClearsigHelp ) {
746 state = fhdrENDClearsig;
751 if( state != fhdrNullClearsig
752 && afx->helpidx < afx->helplen ) { /* flush the last buffer */
754 for(nn=afx->helpidx; len < size && nn < n ; nn++ )
755 buf[len++] = afx->helpbuf[nn];
759 if( state == fhdrEOF ) {
764 n = DIM(afx->helpbuf);
766 state = find_header( state, afx->helpbuf, &n, a,
767 state == fhdrNullClearsig? afx->helplen:0,
768 &emplines, &afx->hashes,
770 &afx->not_dash_escaped );
783 case fhdrREADClearsig:
784 case fhdrREADClearsigNext:
785 case fhdrCLEARSIGSimple:
786 case fhdrCLEARSIGSimpleNext:
790 case fhdrENDClearsig:
791 state = fhdrENDClearsigHelp;
798 buf[0] = (len-2) >> 8;
800 if( state == fhdrENDClearsig ) { /* write last (ending) length header */
801 if( buf[0] || buf[1] ) { /* write only if length of text is > 0 */
808 afx->parse_state = state;
809 afx->empty = emplines;
817 radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
818 byte *buf, size_t size )
830 val = afx->radbuf[0];
831 for( n=0; n < size; ) {
832 if( afx->helpidx < afx->helplen )
833 c = afx->helpbuf[afx->helpidx++];
834 else if( (c=iobuf_get(a)) == -1 )
836 if( c == '\n' || c == ' ' || c == '\r' || c == '\t' )
838 else if( c == '=' ) { /* pad character: stop */
844 else if( (c = asctobin[(c2=c)]) == 255 ) {
845 log_error(_("invalid radix64 character %02x skipped\n"), c2);
849 case 0: val = c << 2; break;
850 case 1: val |= (c>>4)&3; buf[n++]=val;val=(c<<4)&0xf0;break;
851 case 2: val |= (c>>2)&15; buf[n++]=val;val=(c<<6)&0xc0;break;
852 case 3: val |= c&0x3f; buf[n++] = val; break;
856 for(i=0; i < n; i++ )
857 crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
861 afx->radbuf[0] = val;
866 afx->parse_state = 0;
867 for(;;) { /* skip lf and pad characters */
868 if( afx->helpidx < afx->helplen )
869 c = afx->helpbuf[afx->helpidx++];
870 else if( (c=iobuf_get(a)) == -1 )
872 if( c == '\n' || c == ' ' || c == '\r'
873 || c == '\t' || c == '=' )
878 log_error(_("premature eof (no CRC)\n"));
883 if( (c = asctobin[c]) == 255 )
886 case 0: val = c << 2; break;
887 case 1: val |= (c>>4)&3; mycrc |= val << 16;val=(c<<4)&0xf0;break;
888 case 2: val |= (c>>2)&15; mycrc |= val << 8;val=(c<<6)&0xc0;break;
889 case 3: val |= c&0x3f; mycrc |= val; break;
891 if( afx->helpidx < afx->helplen )
892 c = afx->helpbuf[afx->helpidx++];
893 else if( (c=iobuf_get(a)) == -1 )
895 } while( ++idx < 4 );
897 log_error(_("premature eof (in CRC)\n"));
898 rc = G10ERR_INVALID_ARMOR;
900 else if( idx != 4 ) {
901 log_error(_("malformed CRC\n"));
902 rc = G10ERR_INVALID_ARMOR;
904 else if( mycrc != afx->crc ) {
905 log_error(_("CRC error; %06lx - %06lx\n"),
906 (ulong)afx->crc, (ulong)mycrc);
907 rc = G10ERR_INVALID_ARMOR;
913 rc = 0 /*check_trailer( &fhdr, c )*/;
915 if( afx->helpidx < afx->helplen )
916 c = afx->helpbuf[afx->helpidx++];
917 else if( (c=iobuf_get(a)) == -1 )
924 log_error(_("premature eof (in Trailer)\n"));
925 rc = G10ERR_INVALID_ARMOR;
928 log_error(_("error in trailer line\n"));
929 rc = G10ERR_INVALID_ARMOR;
944 * This filter is used to handle the armor stuff
947 armor_filter( void *opaque, int control,
948 IOBUF a, byte *buf, size_t *ret_len)
950 size_t size = *ret_len;
951 armor_filter_context_t *afx = opaque;
961 fp = fopen("armor.out", "w");
967 log_debug("armor-filter: control: %d\n", control );
968 if( control == IOBUFCTRL_UNDERFLOW && afx->inp_bypass ) {
969 for( n=0; n < size; n++ ) {
970 if( (c=iobuf_get(a)) == -1 )
978 else if( control == IOBUFCTRL_UNDERFLOW ) {
979 if( size < 15+(4*15) ) /* need space for up to 4 onepass_sigs */
980 BUG(); /* supplied buffer too short */
983 rc = fake_packet( afx, a, &n, buf, size );
984 else if( !afx->inp_checked ) {
985 rc = check_input( afx, a );
986 if( afx->inp_bypass ) {
987 for( n=0; n < size && n < afx->helplen; n++ )
988 buf[n] = afx->helpbuf[n];
991 assert( n == afx->helplen );
994 else if( afx->faked ) {
995 unsigned hashes = afx->hashes;
996 /* the buffer is at least 15+n*15 bytes long, so it
997 * is easy to construct the packets */
1001 hashes |= 4; /* default to MD 5 */
1004 /* first some onepass signature packets */
1005 buf[n++] = 0x90; /* old format, type 4, 1 length byte */
1006 buf[n++] = 13; /* length */
1007 buf[n++] = 3; /* version */
1008 buf[n++] = 0x01; /* sigclass 0x01 (canonical text mode)*/
1011 buf[n++] = DIGEST_ALGO_RMD160;
1013 else if( hashes & 2 ) {
1015 buf[n++] = DIGEST_ALGO_SHA1;
1017 else if( hashes & 4 ) {
1019 buf[n++] = DIGEST_ALGO_MD5;
1021 else if( hashes & 8 ) {
1023 buf[n++] = DIGEST_ALGO_TIGER;
1026 buf[n++] = 0; /* (don't know) */
1028 buf[n++] = 0; /* public key algo (don't know) */
1029 memset(buf+n, 0, 8); /* don't know the keyid */
1031 buf[n++] = !hashes; /* last one */
1034 /* followed by a plaintext packet */
1035 buf[n++] = 0xaf; /* old packet format, type 11, var length */
1036 buf[n++] = 0; /* set the length header */
1038 buf[n++] = 't'; /* canonical text mode */
1039 buf[n++] = 0; /* namelength */
1040 memset(buf+n, 0, 4); /* timestamp */
1044 rc = radix64_read( afx, a, &n, buf, size );
1047 rc = radix64_read( afx, a, &n, buf, size );
1050 if( fwrite(buf, n, 1, fp ) != 1 )
1055 else if( control == IOBUFCTRL_FLUSH ) {
1056 if( !afx->status ) { /* write the header line */
1057 if( afx->what >= DIM(head_strings) )
1058 log_bug("afx->what=%d", afx->what);
1059 iobuf_writestr(a, "-----");
1060 iobuf_writestr(a, head_strings[afx->what] );
1061 iobuf_writestr(a, "-----\n");
1062 iobuf_writestr(a, "Version: GnuPG v" VERSION " ("
1063 PRINTABLE_OS_NAME ")\n");
1065 if( opt.comment_string ) {
1066 const char *s = opt.comment_string;
1067 iobuf_writestr(a, "Comment: " );
1070 iobuf_writestr(a, "\\n" );
1071 else if( *s == '\r' )
1072 iobuf_writestr(a, "\\r" );
1073 else if( *s == '\v' )
1074 iobuf_writestr(a, "\\v" );
1078 iobuf_put(a, '\n' );
1082 "Comment: For info see www.gnupg.org");
1084 iobuf_writestr(a, afx->hdrlines);
1094 for(i=0; i < idx; i++ )
1095 radbuf[i] = afx->radbuf[i];
1097 for(i=0; i < size; i++ )
1098 crc = (crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ buf[i]];
1101 for( ; size; buf++, size-- ) {
1102 radbuf[idx++] = *buf;
1105 c = bintoasc[(*radbuf >> 2) & 077];
1107 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
1109 c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
1111 c = bintoasc[radbuf[2]&077];
1113 if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */
1119 for(i=0; i < idx; i++ )
1120 afx->radbuf[i] = radbuf[i];
1125 else if( control == IOBUFCTRL_INIT ) {
1126 if( !is_initialized )
1129 else if( control == IOBUFCTRL_FREE ) {
1130 if( afx->status ) { /* pad, write cecksum, and bottom line */
1134 for(i=0; i < idx; i++ )
1135 radbuf[i] = afx->radbuf[i];
1137 c = bintoasc[(*radbuf>>2)&077];
1140 c = bintoasc[((*radbuf << 4) & 060) & 077];
1146 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
1148 c = bintoasc[((radbuf[1] << 2) & 074) & 077];
1152 if( ++idx2 >= (64/4) ) { /* pgp doesn't like 72 here */
1157 /* may need a linefeed */
1162 radbuf[0] = crc >>16;
1163 radbuf[1] = crc >> 8;
1165 c = bintoasc[(*radbuf >> 2) & 077];
1167 c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
1169 c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
1171 c = bintoasc[radbuf[2]&077];
1174 /* and the the trailer */
1175 if( afx->what >= DIM(tail_strings) )
1176 log_bug("afx->what=%d", afx->what);
1177 iobuf_writestr(a, "-----");
1178 iobuf_writestr(a, tail_strings[afx->what] );
1179 iobuf_writestr(a, "-----\n");
1181 else if( !afx->any_data && !afx->inp_bypass )
1182 log_error(_("no valid OpenPGP data found.\n"));
1184 else if( control == IOBUFCTRL_DESC )
1185 *(char**)buf = "armor_filter";