fingerprints and self signatures added
[gnupg.git] / g10 / encode.c
1 /* encode.c - encode 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
43
44 /****************
45  * Encode FILENAME only with the symmetric cipher. Take input from
46  * stdin if FILENAME is NULL.
47  */
48 int
49 encode_symmetric( const char *filename )
50 {
51     return encode_simple( filename, 1 );
52 }
53
54 /****************
55  * Encode FILENAME as literal data packet only. Take input from
56  * stdin if FILENAME is NULL.
57  */
58 int
59 encode_store( const char *filename )
60 {
61     return encode_simple( filename, 0 );
62 }
63
64
65 static int
66 encode_simple( const char *filename, int mode )
67 {
68     IOBUF inp, out;
69     PACKET pkt;
70     PKT_plaintext *pt;
71     int rc = 0;
72     u32 filesize;
73     cipher_filter_context_t cfx;
74     armor_filter_context_t afx;
75     compress_filter_context_t zfx;
76
77     memset( &cfx, 0, sizeof cfx);
78     memset( &afx, 0, sizeof afx);
79     memset( &zfx, 0, sizeof zfx);
80
81     /* prepare iobufs */
82     if( !(inp = iobuf_open(filename)) ) {
83         log_error("can't open %s: %s\n", filename? filename: "[stdin]",
84                                         strerror(errno) );
85         return G10ERR_OPEN_FILE;
86     }
87
88     cfx.dek = NULL;
89     if( mode ) {
90         cfx.dek = m_alloc_secure( sizeof *cfx.dek );
91         cfx.dek->algo = DEFAULT_CIPHER_ALGO;
92         if( (rc = make_dek_from_passphrase( cfx.dek , 2 )) ) {
93             m_free(cfx.dek);
94             iobuf_close(inp);
95             log_error("error creating passphrase: %s\n", g10_errstr(rc) );
96             return rc;
97         }
98     }
99
100     if( !(out = open_outfile( filename )) ) {
101         iobuf_close(inp);
102         m_free(cfx.dek);
103         return G10ERR_CREATE_FILE;  /* or user said: do not overwrite */
104     }
105
106     if( opt.armor )
107         iobuf_push_filter( out, armor_filter, &afx );
108
109     write_comment( out, "#Created by G10 pre-release " VERSION );
110
111     if( opt.compress )
112         iobuf_push_filter( out, compress_filter, &zfx );
113
114
115     /* setup the inner packet */
116     if( filename ) {
117         pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
118         pt->namelen = strlen(filename);
119         memcpy(pt->name, filename, pt->namelen );
120         if( !(filesize = iobuf_get_filelength(inp)) )
121             log_info("warning: '%s' is an empty file\n", filename );
122     }
123     else { /* no filename */
124         pt = m_alloc( sizeof *pt - 1 );
125         pt->namelen = 0;
126         filesize = 0; /* stdin */
127     }
128     pt->timestamp = make_timestamp();
129     pt->mode = 'b';
130     pt->len = filesize;
131     pt->buf = inp;
132     pkt.pkttype = PKT_PLAINTEXT;
133     pkt.pkt.plaintext = pt;
134     cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;
135
136     /* register the cipher filter */
137     if( mode )
138         iobuf_push_filter( out, cipher_filter, &cfx );
139
140     /* do the work */
141     if( (rc = build_packet( out, &pkt )) )
142         log_error("build_packet failed: %s\n", g10_errstr(rc) );
143
144     /* finish the stuff */
145     iobuf_close(inp);
146     iobuf_close(out); /* fixme: check returncode */
147     pt->buf = NULL;
148     free_packet(&pkt);
149     m_free(cfx.dek);
150     return rc;
151 }
152
153 /****************
154  * Encrypt the file with the given userids (or ask if none
155  * is supplied).
156  */
157 int
158 encode_crypt( const char *filename, STRLIST remusr )
159 {
160     IOBUF inp, out;
161     PACKET pkt;
162     PKT_plaintext *pt;
163     PKT_public_cert *pkc = NULL;
164     PKT_pubkey_enc  *enc = NULL;
165     int last_rc, rc = 0;
166     u32 filesize;
167     cipher_filter_context_t cfx;
168     armor_filter_context_t afx;
169     compress_filter_context_t zfx;
170     int any_names = 0;
171     STRLIST local_remusr = NULL;
172     char *ustr;
173
174     memset( &cfx, 0, sizeof cfx);
175     memset( &afx, 0, sizeof afx);
176     memset( &zfx, 0, sizeof zfx);
177
178     if( !remusr ) {
179         remusr = NULL; /* fixme: ask */
180         local_remusr = remusr;
181     }
182
183     /* prepare iobufs */
184     if( !(inp = iobuf_open(filename)) ) {
185         log_error("can't open %s: %s\n", filename? filename: "[stdin]",
186                                         strerror(errno) );
187         free_strlist(local_remusr);
188         return G10ERR_OPEN_FILE;
189     }
190     else if( opt.verbose )
191         log_error("reding from '%s'\n", filename? filename: "[stdin]");
192
193     if( !(out = open_outfile( filename )) ) {
194         iobuf_close(inp);
195         free_strlist(local_remusr);
196         return G10ERR_CREATE_FILE;  /* or user said: do not overwrite */
197     }
198
199     if( opt.armor )
200         iobuf_push_filter( out, armor_filter, &afx );
201
202     write_comment( out, "#Created by G10 pre-release " VERSION );
203
204     if( opt.compress )
205         iobuf_push_filter( out, compress_filter, &zfx );
206
207     /* create a session key */
208     cfx.dek = m_alloc_secure( sizeof *cfx.dek );
209     cfx.dek->algo = DEFAULT_CIPHER_ALGO;
210     make_session_key( cfx.dek );
211     if( DBG_CIPHER )
212         log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
213
214     /* loop over all user ids and build public key packets for each */
215     for(last_rc=0 ; remusr; remusr = remusr->next ) {
216         if( pkc )
217             free_public_cert( pkc );
218         pkc = m_alloc_clear( sizeof *pkc );
219         pkc->pubkey_algo = DEFAULT_PUBKEY_ALGO;
220
221         if( (rc = get_pubkey_by_name( pkc, remusr->d )) ) {
222             last_rc = rc;
223             log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
224             continue;
225         }
226         /* build the pubkey packet */
227         enc = m_alloc_clear( sizeof *enc );
228         enc->pubkey_algo = pkc->pubkey_algo;
229         if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
230             ELG_public_key pkey;
231             MPI frame;
232
233             enc->d.elg.a = mpi_alloc( mpi_get_nlimbs(pkc->d.elg.p) );
234             enc->d.elg.b = mpi_alloc( mpi_get_nlimbs(pkc->d.elg.p) );
235             keyid_from_pkc( pkc, enc->keyid );
236             frame = encode_session_key( cfx.dek, mpi_get_nbits(pkc->d.elg.p) );
237             pkey.p = pkc->d.elg.p;
238             pkey.g = pkc->d.elg.g;
239             pkey.y = pkc->d.elg.y;
240             if( DBG_CIPHER )
241                 log_mpidump("Plain DEK frame: ", frame);
242             elg_encrypted( enc->d.elg.a, enc->d.elg.b, frame, &pkey);
243             mpi_free( frame );
244             if( DBG_CIPHER ) {
245                 log_mpidump("Encry DEK a: ", enc->d.elg.a );
246                 log_mpidump("      DEK b: ", enc->d.elg.b );
247             }
248             if( opt.verbose ) {
249                 ustr = get_user_id_string( enc->keyid );
250                 log_info("ElGamal encrypteded for: %s\n", ustr );
251                 m_free(ustr);
252             }
253         }
254       #ifdef HAVE_RSA_CIPHER
255         else if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) {
256             RSA_public_key pkey;
257
258             keyid_from_pkc( pkc, enc->keyid );
259             enc->d.rsa.rsa_integer = encode_session_key( cfx.dek,
260                                         mpi_get_nbits(pkc->d.rsa.rsa_n) );
261             pkey.n = pkc->d.rsa.rsa_n;
262             pkey.e = pkc->d.rsa.rsa_e;
263             if( DBG_CIPHER )
264                 log_mpidump("Plain DEK frame: ", enc->d.rsa.rsa_integer);
265             rsa_public( enc->d.rsa.rsa_integer, enc->d.rsa.rsa_integer, &pkey);
266             if( DBG_CIPHER )
267                 log_mpidump("Encry DEK frame: ", enc->d.rsa.rsa_integer);
268             if( opt.verbose ) {
269                 ustr = get_user_id_string( enc->keyid );
270                 log_info("RSA encrypteded for: %s\n", ustr );
271                 m_free(ustr);
272             }
273         }
274       #endif/*HAVE_RSA_CIPHER*/
275         else {
276             last_rc = rc = G10ERR_PUBKEY_ALGO;
277             log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
278             free_pubkey_enc(enc);
279             continue;
280         }
281         /* and write it */
282         init_packet(&pkt);
283         pkt.pkttype = PKT_PUBKEY_ENC;
284         pkt.pkt.pubkey_enc = enc;
285         if( (rc = build_packet( out, &pkt )) ) {
286             last_rc = rc;
287             log_error("build pubkey_enc packet failed: %s\n", g10_errstr(rc) );
288             free_pubkey_enc(enc);
289             continue;
290         }
291         /* okay: a pubkey packet has been written */
292         free_pubkey_enc(enc);
293         any_names = 1;
294     }
295     if( pkc ) {
296         free_public_cert( pkc );
297         pkc = NULL;
298     }
299     if( !any_names ) {
300         log_error("no valid keys - aborting further processing\n");
301         iobuf_close(inp);
302         iobuf_cancel(out);
303         m_free(cfx.dek); /* free and burn the session key */
304         free_strlist(local_remusr);
305         return last_rc;
306     }
307
308     /* setup the inner packet */
309     if( filename ) {
310         pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
311         pt->namelen = strlen(filename);
312         memcpy(pt->name, filename, pt->namelen );
313         if( !(filesize = iobuf_get_filelength(inp)) )
314             log_info("warning: '%s' is an empty file\n", filename );
315     }
316     else { /* no filename */
317         pt = m_alloc( sizeof *pt - 1 );
318         pt->namelen = 0;
319         filesize = 0; /* stdin */
320     }
321     pt->timestamp = make_timestamp();
322     pt->mode = 'b';
323     pt->len = filesize;
324     pt->buf = inp;
325     init_packet(&pkt);
326     pkt.pkttype = PKT_PLAINTEXT;
327     pkt.pkt.plaintext = pt;
328     cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;
329
330     /* register the cipher filter */
331     iobuf_push_filter( out, cipher_filter, &cfx );
332
333     /* do the work */
334     if( (rc = build_packet( out, &pkt )) )
335         log_error("build_packet failed: %s\n", g10_errstr(rc) );
336
337     /* finish the stuff */
338     iobuf_close(inp);
339     iobuf_close(out); /* fixme: check returncode */
340     pt->buf = NULL;
341     free_packet(&pkt);
342     m_free(cfx.dek);
343     free_strlist(local_remusr);
344     return rc;
345 }
346
347
348