/* * Copyright (C) 2007, 2008, 2009 David Shaw <dshaw@jabberwocky.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ static const char RCSID[]="$Id: output.c 580 2009-02-10 15:15:47Z dshaw $"; #include <config.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <assert.h> #include "packets.h" #include "output.h" extern unsigned int output_width; extern char *comment; static enum data_type output_type; static FILE *output; static unsigned int line_items; static unsigned long all_crc=CRC24_INIT; #define CRC24_POLY 0x864CFBL void do_crc24(unsigned long *crc,const unsigned char *buf,size_t len) { size_t i; for(i=0;i<len;i++) { int j; *crc^=buf[i]<<16; for(j=0;j<8;j++) { *crc<<=1; if(*crc&0x1000000) *crc^=CRC24_POLY; } } } static void print_base16(const unsigned char *buf,size_t length) { static unsigned long line_crc=CRC24_INIT; static unsigned int line=0; if(buf) { size_t i; static unsigned int offset=0; for(i=0;i<length;i++,offset++) { if(offset%line_items==0) { if(line) { fprintf(output,"%06lX\n",line_crc&0xFFFFFFL); line_crc=CRC24_INIT; } fprintf(output,"%3u: ",++line); } fprintf(output,"%02X ",buf[i]); do_crc24(&line_crc,&buf[i],1); } } else { fprintf(output,"%06lX\n",line_crc&0xFFFFFFL); fprintf(output,"%3u: %06lX\n",line+1,all_crc&0xFFFFFFL); } } void print_bytes(FILE *stream,const unsigned char *buf,size_t length) { size_t i; for(i=0;i<length;i++) fprintf(stream,"%02X",buf[i]); } void output_file_format(FILE *stream,const char *prefix) { fprintf(stream,"%sFile format:\n",prefix); fprintf(stream,"%sa) 1 octet: Version of the paperkey format (currently 0).\n",prefix); fprintf(stream,"%sb) 1 octet: OpenPGP key or subkey version (currently 4)\n",prefix); fprintf(stream,"%sc) n octets: Key fingerprint (20 octets for a version 4 key or subkey)\n",prefix); fprintf(stream,"%sd) 2 octets: 16-bit big endian length of the following secret data\n",prefix); fprintf(stream,"%se) n octets: Secret data: a partial OpenPGP secret key or subkey packet as\n",prefix); fprintf(stream,"%s specified in RFC 4880, starting with the string-to-key usage\n",prefix); fprintf(stream,"%s octet and continuing until the end of the packet.\n",prefix); fprintf(stream,"%sRepeat fields b through e as needed to cover all subkeys.\n",prefix); fprintf(stream,"%s\n",prefix); fprintf(stream,"%sTo recover a secret key without using the paperkey program, use the\n",prefix); fprintf(stream,"%skey fingerprint to match an existing public key packet with the\n",prefix); fprintf(stream,"%scorresponding secret data from the paper key. Next, append this secret\n",prefix); fprintf(stream,"%sdata to the public key packet. Finally, switch the public key packet tag\n",prefix); fprintf(stream,"%sfrom 6 to 5 (14 to 7 for subkeys). This will recreate the original secret\n",prefix); fprintf(stream,"%skey or secret subkey packet. Repeat as needed for all public key or subkey\n",prefix); fprintf(stream,"%spackets in the public key. All other packets (user IDs, signatures, etc.)\n",prefix); fprintf(stream,"%smay simply be copied from the public key.\n",prefix); } int output_start(const char *name,enum data_type type, unsigned char fingerprint[20]) { if(name) { if(type==RAW) output=fopen(name,"wb"); else output=fopen(name,"w"); if(!output) return -1; } else output=stdout; output_type=type; switch(type) { case RAW: break; case AUTO: case BASE16: { time_t now=time(NULL); line_items=(output_width-5-6)/3; fprintf(output,"# Secret portions of key "); print_bytes(output,fingerprint,20); fprintf(output,"\n"); fprintf(output,"# Base16 data extracted %.24s\n",ctime(&now)); fprintf(output,"# Created with " PACKAGE_STRING " by David Shaw\n#\n"); output_file_format(output,"# "); fprintf(output,"#\n# Each base16 line ends with a CRC-24 of that line.\n"); fprintf(output,"# The entire block of data ends with a CRC-24 of the entire block of data.\n\n"); if(comment) fprintf(output,"# %s\n\n",comment); } break; } return 0; } ssize_t output_bytes(const unsigned char *buf,size_t length) { ssize_t ret=-1; do_crc24(&all_crc,buf,length); switch(output_type) { case RAW: if(buf==NULL) { unsigned char crc[3]; crc[0]=(all_crc&0xFFFFFFL)>>16; crc[1]=(all_crc&0xFFFFFFL)>>8; crc[2]=(all_crc&0xFFFFFFL); ret=fwrite(crc,1,3,output); } else ret=fwrite(buf,1,length,output); break; case AUTO: case BASE16: print_base16(buf,length); ret=length; break; } return ret; } ssize_t output_length16(size_t length) { unsigned char encoded[2]; assert(length<=65535); encoded[0]=length>>8; encoded[1]=length; return output_bytes(encoded,2); } ssize_t output_openpgp_length(size_t length) { unsigned char encoded[5]; if(length>8383) { encoded[0]=0xFF; encoded[1]=length>>24; encoded[2]=length>>16; encoded[3]=length>>8; encoded[4]=length; return output_bytes(encoded,5); } else if(length>191) { encoded[0]=192+((length-192)>>8); encoded[1]=(length-192); return output_bytes(encoded,2); } else { encoded[0]=length; return output_bytes(encoded,1); } } void output_finish(void) { output_bytes(NULL,0); }