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