efa9fd230e3ded33969dca3fa0d985d38cd23c99
[gnupg.git] / g10 / encode.c
1 /* encode.c - encode/sign data
2  *      Copyright (c) 1997 by Werner Koch (dd9jn)
3  *
4  * This file is part of G10.
5  *
6  * G10 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.
10  *
11  * G10 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include "options.h"
29 #include "packet.h"
30 #include "errors.h"
31 #include "iobuf.h"
32 #include "keydb.h"
33 #include "memory.h"
34 #include "util.h"
35 #include "main.h"
36 #include "filter.h"
37
38
39
40
41 static int encode_simple( const char *filename, int mode );
42 static IOBUF open_outfile( const char *iname );
43 static int compress_filter( void *opaque, int control,
44                             IOBUF chain, byte *buf, size_t *ret_len);
45 static int cipher_filter( void *opaque, int control,
46                           IOBUF chain, byte *buf, size_t *ret_len);
47
48
49
50 typedef struct {
51     DEK *dek;
52     PKT_encr_data ed;
53     BLOWFISH_context *bf_ctx;
54     int header;
55 } cipher_filter_context_t;
56
57
58
59
60 /****************
61  * Encode FILENAME only with the symmetric cipher. Take input from
62  * stdin if FILENAME is NULL.
63  */
64 int
65 encode_symmetric( const char *filename )
66 {
67     return encode_simple( filename, 1 );
68 }
69
70 /****************
71  * Encode FILENAME as literal data packet only. Take input from
72  * stdin if FILENAME is NULL.
73  */
74 int
75 encode_store( const char *filename )
76 {
77     return encode_simple( filename, 0 );
78 }
79
80 static void
81 write_comment( IOBUF out, const char *s )
82 {
83     PACKET pkt;
84     size_t n = strlen(s);
85     int rc;
86
87     pkt.pkttype = PKT_COMMENT;
88     pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n - 1 );
89     pkt.pkt.comment->len = n;
90     strcpy(pkt.pkt.comment->data, s);
91     if( (rc = build_packet( out, &pkt )) )
92         log_error("build_packet(comment) failed: %s\n", g10_errstr(rc) );
93     free_packet( &pkt );
94 }
95
96
97 static int
98 encode_simple( const char *filename, int mode )
99 {
100     IOBUF inp, out;
101     PACKET pkt;
102     PKT_plaintext *pt;
103     int rc = 0;
104     u32 filesize;
105     cipher_filter_context_t cfx;
106     armor_filter_context_t afx;
107
108     memset( &cfx, 0, sizeof cfx);
109     memset( &afx, 0, sizeof afx);
110
111     /* prepare iobufs */
112     if( !(inp = iobuf_open(filename)) ) {
113         log_error("can't open %s: %s\n", filename? filename: "[stdin]",
114                                         strerror(errno) );
115         return G10ERR_OPEN_FILE;
116     }
117
118     cfx.dek = NULL;
119     if( mode ) {
120         cfx.dek = m_alloc_secure( sizeof *cfx.dek );
121         cfx.dek->algo = DEFAULT_CIPHER_ALGO;
122         if( (rc = make_dek_from_passphrase( cfx.dek , 2 )) ) {
123             m_free(cfx.dek);
124             iobuf_close(inp);
125             log_error("error creating passphrase: %s\n", g10_errstr(rc) );
126             return rc;
127         }
128     }
129
130     if( !(out = open_outfile( filename )) ) {
131         iobuf_close(inp);
132         m_free(cfx.dek);
133         return G10ERR_CREATE_FILE;  /* or user said: do not overwrite */
134     }
135
136     if( opt.armor )
137         iobuf_push_filter( out, armor_filter, &afx );
138
139     write_comment( out, "#Created by G10 pre-release " VERSION );
140
141     if( opt.compress )
142         iobuf_push_filter( out, compress_filter, NULL );
143
144
145     /* setup the inner packet */
146     if( filename ) {
147         pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
148         pt->namelen = strlen(filename);
149         memcpy(pt->name, filename, pt->namelen );
150         if( !(filesize = iobuf_get_filelength(inp)) )
151             log_info("warning: '%s' is an empty file\n", filename );
152     }
153     else { /* no filename */
154         pt = m_alloc( sizeof *pt - 1 );
155         pt->namelen = 0;
156         filesize = 0; /* stdin */
157     }
158     pt->timestamp = make_timestamp();
159     pt->mode = 'b';
160     pt->len = filesize;
161     pt->buf = inp;
162     pkt.pkttype = PKT_PLAINTEXT;
163     pkt.pkt.plaintext = pt;
164     cfx.ed.len = filesize? calc_packet_length( &pkt ) : 0;
165     cfx.ed.buf = NULL; /* not used! */
166
167     /* register the cipher filter */
168     if( mode )
169         iobuf_push_filter( out, cipher_filter, &cfx );
170
171     /* do the work */
172     if( (rc = build_packet( out, &pkt )) )
173         log_error("build_packet failed: %s\n", g10_errstr(rc) );
174
175     /* finish the stuff */
176     iobuf_close(inp);
177     iobuf_close(out); /* fixme: check returncode */
178     pt->buf = NULL;
179     free_packet(&pkt);
180     m_free(cfx.dek);
181     return rc;
182 }
183
184 /****************
185  * Encrypt the file with the given userids (or ask if none
186  * is supplied).
187  */
188 int
189 encode_crypt( const char *filename, STRLIST remusr )
190 {
191     IOBUF inp, out;
192     PACKET pkt;
193     PKT_plaintext *pt;
194     PKT_pubkey_cert *pkc = NULL;
195     PKT_pubkey_enc  *enc = NULL;
196     int last_rc, rc = 0;
197     u32 filesize;
198     cipher_filter_context_t cfx;
199     armor_filter_context_t afx;
200     int any_names = 0;
201     STRLIST local_remusr = NULL;
202     char *ustr;
203
204     memset( &cfx, 0, sizeof cfx);
205     memset( &afx, 0, sizeof afx);
206
207     if( !remusr ) {
208         remusr = NULL; /* fixme: ask */
209         local_remusr = remusr;
210     }
211
212     /* prepare iobufs */
213     if( !(inp = iobuf_open(filename)) ) {
214         log_error("can't open %s: %s\n", filename? filename: "[stdin]",
215                                         strerror(errno) );
216         free_strlist(local_remusr);
217         return G10ERR_OPEN_FILE;
218     }
219     else if( opt.verbose )
220         log_error("reding from '%s'\n", filename? filename: "[stdin]");
221
222     if( !(out = open_outfile( filename )) ) {
223         iobuf_close(inp);
224         free_strlist(local_remusr);
225         return G10ERR_CREATE_FILE;  /* or user said: do not overwrite */
226     }
227
228     if( opt.armor )
229         iobuf_push_filter( out, armor_filter, &afx );
230
231     write_comment( out, "#Created by G10 pre-release " VERSION );
232
233     if( opt.compress )
234         iobuf_push_filter( out, compress_filter, NULL );
235
236     /* create a session key */
237     cfx.dek = m_alloc_secure( sizeof *cfx.dek );
238     cfx.dek->algo = DEFAULT_CIPHER_ALGO;
239     make_session_key( cfx.dek );
240     if( DBG_CIPHER )
241         log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
242
243     /* loop over all user ids and build public key packets for each */
244     for(last_rc=0 ; remusr; remusr = remusr->next ) {
245         if( pkc )
246             free_pubkey_cert( pkc );
247         pkc = m_alloc_clear( sizeof *pkc );
248         pkc->pubkey_algo = DEFAULT_PUBKEY_ALGO;
249
250         if( (rc = get_pubkey_by_name( pkc, remusr->d )) ) {
251             last_rc = rc;
252             log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
253             continue;
254         }
255         /* build the pubkey packet */
256         enc = m_alloc_clear( sizeof *enc );
257         enc->pubkey_algo = pkc->pubkey_algo;
258         if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) {
259             RSA_public_key pkey;
260
261             mpi_get_keyid( pkc->d.rsa.rsa_n, enc->keyid );
262             enc->d.rsa.rsa_integer = encode_session_key( cfx.dek,
263                                         mpi_get_nbits(pkc->d.rsa.rsa_n) );
264             pkey.n = pkc->d.rsa.rsa_n;
265             pkey.e = pkc->d.rsa.rsa_e;
266             if( DBG_CIPHER )
267                 log_mpidump("Plain DEK frame: ", enc->d.rsa.rsa_integer);
268             rsa_public( enc->d.rsa.rsa_integer, enc->d.rsa.rsa_integer, &pkey);
269             if( DBG_CIPHER )
270                 log_mpidump("Encry DEK frame: ", enc->d.rsa.rsa_integer);
271             if( opt.verbose ) {
272                 ustr = get_user_id_string( enc->keyid );
273                 log_info("RSA enciphered for: %s\n", ustr );
274                 m_free(ustr);
275             }
276         }
277         else {
278             last_rc = rc = G10ERR_PUBKEY_ALGO;
279             log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
280             free_pubkey_enc(enc);
281             continue;
282         }
283         /* and write it */
284         init_packet(&pkt);
285         pkt.pkttype = PKT_PUBKEY_ENC;
286         pkt.pkt.pubkey_enc = enc;
287         if( (rc = build_packet( out, &pkt )) ) {
288             last_rc = rc;
289             log_error("build pubkey_enc packet failed: %s\n", g10_errstr(rc) );
290             free_pubkey_enc(enc);
291             continue;
292         }
293         /* okay: a pubkey packet has been written */
294         free_pubkey_enc(enc);
295         any_names = 1;
296     }
297     if( pkc ) {
298         free_pubkey_cert( pkc );
299         pkc = NULL;
300     }
301     if( !any_names ) {
302         log_error("no valid keys - aborting further processing\n");
303         iobuf_close(inp);
304         iobuf_cancel(out);
305         m_free(cfx.dek); /* free and burn the session key */
306         free_strlist(local_remusr);
307         return last_rc;
308     }
309
310     /* setup the inner packet */
311     if( filename ) {
312         pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
313         pt->namelen = strlen(filename);
314         memcpy(pt->name, filename, pt->namelen );
315         if( !(filesize = iobuf_get_filelength(inp)) )
316             log_info("warning: '%s' is an empty file\n", filename );
317     }
318     else { /* no filename */
319         pt = m_alloc( sizeof *pt - 1 );
320         pt->namelen = 0;
321         filesize = 0; /* stdin */
322     }
323     pt->timestamp = make_timestamp();
324     pt->mode = 'b';
325     pt->len = filesize;
326     pt->buf = inp;
327     init_packet(&pkt);
328     pkt.pkttype = PKT_PLAINTEXT;
329     pkt.pkt.plaintext = pt;
330     cfx.ed.len = filesize? calc_packet_length( &pkt ) : 0;
331     cfx.ed.buf = NULL; /* not used! */
332
333     /* register the cipher filter */
334     iobuf_push_filter( out, cipher_filter, &cfx );
335
336     /* do the work */
337     if( (rc = build_packet( out, &pkt )) )
338         log_error("build_packet failed: %s\n", g10_errstr(rc) );
339
340     /* finish the stuff */
341     iobuf_close(inp);
342     iobuf_close(out); /* fixme: check returncode */
343     pt->buf = NULL;
344     free_packet(&pkt);
345     m_free(cfx.dek);
346     free_strlist(local_remusr);
347     return rc;
348 }
349
350
351 /****************
352  * Make an output filename for the inputfile INAME.
353  * Returns an
354  */
355 static IOBUF
356 open_outfile( const char *iname )
357 {
358     IOBUF a = NULL;
359     int rc;
360
361     if( (!iname && !opt.outfile) || opt.outfile_is_stdout ) {
362         if( !(a = iobuf_create(NULL)) )
363             log_error("can't open [stdout]: %s\n", strerror(errno) );
364         else if( opt.verbose )
365             log_info("writing to stdout\n");
366     }
367     else {
368         char *buf=NULL;
369         const char *name;
370
371         if( opt.outfile )
372             name = opt.outfile;
373         else {
374             buf = m_alloc(strlen(iname)+4+1);
375             strcpy(stpcpy(buf,iname), ".g10");
376             name = buf;
377         }
378         if( !(rc=overwrite_filep( name )) ) {
379             if( !(a = iobuf_create( name )) )
380                 log_error("can't create %s: %s\n", name, strerror(errno) );
381             else if( opt.verbose )
382                 log_info("writing to '%s'\n", name );
383         }
384         else if( rc != -1 )
385             log_error("oops: overwrite_filep(%s): %s\n", name, g10_errstr(rc) );
386         m_free(buf);
387     }
388     return a;
389 }
390
391
392 static int
393 compress_filter( void *opaque, int control,
394                  IOBUF a, byte *buf, size_t *ret_len)
395 {
396     size_t size = *ret_len;
397     int rc=0;
398
399     if( control == IOBUFCTRL_FLUSH ) {
400         assert(a);
401         if( iobuf_write( a, buf, size ) )
402             rc = G10ERR_WRITE_FILE;
403     }
404     else if( control == IOBUFCTRL_DESC ) {
405         *(char**)buf = "compress_filter";
406     }
407     return rc;
408 }
409
410
411 /****************
412  * The filter is used to encipher data.
413  */
414 static int
415 cipher_filter( void *opaque, int control,
416                IOBUF a, byte *buf, size_t *ret_len)
417 {
418     size_t size = *ret_len;
419     cipher_filter_context_t *cfx = opaque;
420     int rc=0;
421
422     if( control == IOBUFCTRL_FLUSH ) {
423         assert(a);
424         if( !cfx->header ) {
425             PACKET pkt;
426             byte temp[10];
427
428             pkt.pkttype = PKT_ENCR_DATA;
429             pkt.pkt.encr_data = &cfx->ed;
430             if( build_packet( a, &pkt ))
431                 log_bug("build_packet(ENCR_DATA) failed\n");
432             randomize_buffer( temp, 8, 1 );
433             temp[8] = temp[6];
434             temp[9] = temp[7];
435             if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH ) {
436                 cfx->bf_ctx = m_alloc_secure( sizeof *cfx->bf_ctx );
437                 blowfish_setkey( cfx->bf_ctx, cfx->dek->key, cfx->dek->keylen );
438                 blowfish_setiv( cfx->bf_ctx, NULL );
439                 blowfish_encode_cfb( cfx->bf_ctx, temp, temp, 10);
440             }
441             else
442                 log_bug("no cipher algo %d\n", cfx->dek->algo);
443
444             iobuf_write(a, temp, 10);
445             cfx->header=1;
446         }
447
448         if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH )
449             blowfish_encode_cfb( cfx->bf_ctx, buf, buf, size);
450         if( iobuf_write( a, buf, size ) )
451             rc = G10ERR_WRITE_FILE;
452     }
453     else if( control == IOBUFCTRL_FREE ) {
454         if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH )
455             m_free(cfx->bf_ctx);
456     }
457     else if( control == IOBUFCTRL_DESC ) {
458         *(char**)buf = "cipher_filter";
459     }
460     return rc;
461 }
462