Renamed to GNUPG
[gnupg.git] / g10 / encode.c
1 /* encode.c - encode data
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
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.
10  *
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.
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 static int encode_simple( const char *filename, int mode );
40 static int write_pubkey_enc_from_list( PKC_LIST pkc_list, DEK *dek, IOBUF out );
41
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 = opt.def_cipher_algo;
92         if( (rc = make_dek_from_passphrase( cfx.dek , 2, NULL )) ) {
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, opt.armor? 1:0 )) ) {
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 GNUPG v" VERSION " ("
110                                             PRINTABLE_OS_NAME ")");
111
112     if( opt.compress )
113         iobuf_push_filter( out, compress_filter, &zfx );
114
115
116     /* setup the inner packet */
117     if( filename ) {
118         pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
119         pt->namelen = strlen(filename);
120         memcpy(pt->name, filename, pt->namelen );
121         if( !(filesize = iobuf_get_filelength(inp)) )
122             log_info("warning: '%s' is an empty file\n", filename );
123     }
124     else { /* no filename */
125         pt = m_alloc( sizeof *pt - 1 );
126         pt->namelen = 0;
127         filesize = 0; /* stdin */
128     }
129     pt->timestamp = make_timestamp();
130     pt->mode = 'b';
131     pt->len = filesize;
132     pt->buf = inp;
133     pkt.pkttype = PKT_PLAINTEXT;
134     pkt.pkt.plaintext = pt;
135     cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;
136
137     /* register the cipher filter */
138     if( mode )
139         iobuf_push_filter( out, cipher_filter, &cfx );
140
141     /* do the work */
142     if( (rc = build_packet( out, &pkt )) )
143         log_error("build_packet failed: %s\n", g10_errstr(rc) );
144
145     /* finish the stuff */
146     iobuf_close(inp);
147     iobuf_close(out); /* fixme: check returncode */
148     pt->buf = NULL;
149     free_packet(&pkt);
150     m_free(cfx.dek);
151     return rc;
152 }
153
154 /****************
155  * Encrypt the file with the given userids (or ask if none
156  * is supplied).
157  */
158 int
159 encode_crypt( const char *filename, STRLIST remusr )
160 {
161     IOBUF inp = NULL, out = NULL;
162     PACKET pkt;
163     PKT_plaintext *pt = NULL;
164     int rc = 0;
165     u32 filesize;
166     cipher_filter_context_t cfx;
167     armor_filter_context_t afx;
168     compress_filter_context_t zfx;
169     PKC_LIST pkc_list;
170
171     memset( &cfx, 0, sizeof cfx);
172     memset( &afx, 0, sizeof afx);
173     memset( &zfx, 0, sizeof zfx);
174
175     if( (rc=build_pkc_list( remusr, &pkc_list)) )
176         return rc;
177
178     /* prepare iobufs */
179     if( !(inp = iobuf_open(filename)) ) {
180         log_error("can't open %s: %s\n", filename? filename: "[stdin]",
181                                         strerror(errno) );
182         rc = G10ERR_OPEN_FILE;
183         goto leave;
184     }
185     else if( opt.verbose )
186         log_info("reading from '%s'\n", filename? filename: "[stdin]");
187
188     if( !(out = open_outfile( filename, opt.armor? 1:0 )) ) {
189         rc = G10ERR_CREATE_FILE;  /* or user said: do not overwrite */
190         goto leave;
191     }
192
193     if( opt.armor )
194         iobuf_push_filter( out, armor_filter, &afx );
195
196     write_comment( out, "#created by GNUPG v" VERSION " ("
197                                             PRINTABLE_OS_NAME ")");
198
199     if( opt.compress )
200         iobuf_push_filter( out, compress_filter, &zfx );
201
202     /* create a session key */
203     cfx.dek = m_alloc_secure( sizeof *cfx.dek );
204     cfx.dek->algo = opt.def_cipher_algo;
205     make_session_key( cfx.dek );
206     if( DBG_CIPHER )
207         log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
208
209     rc = write_pubkey_enc_from_list( pkc_list, cfx.dek, out );
210     if( rc  )
211         goto leave;
212
213     /* setup the inner packet */
214     if( filename ) {
215         pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
216         pt->namelen = strlen(filename);
217         memcpy(pt->name, filename, pt->namelen );
218         if( !(filesize = iobuf_get_filelength(inp)) )
219             log_info("warning: '%s' is an empty file\n", filename );
220     }
221     else { /* no filename */
222         pt = m_alloc( sizeof *pt - 1 );
223         pt->namelen = 0;
224         filesize = 0; /* stdin */
225     }
226     pt->timestamp = make_timestamp();
227     pt->mode = 'b';
228     pt->len = filesize;
229     pt->buf = inp;
230     init_packet(&pkt);
231     pkt.pkttype = PKT_PLAINTEXT;
232     pkt.pkt.plaintext = pt;
233     cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;
234
235     /* register the cipher filter */
236     iobuf_push_filter( out, cipher_filter, &cfx );
237
238     /* do the work */
239     if( (rc = build_packet( out, &pkt )) )
240         log_error("build_packet failed: %s\n", g10_errstr(rc) );
241
242     /* finish the stuff */
243   leave:
244     iobuf_close(inp);
245     if( rc )
246         iobuf_cancel(out);
247     else
248         iobuf_close(out); /* fixme: check returncode */
249     if( pt )
250         pt->buf = NULL;
251     free_packet(&pkt);
252     m_free(cfx.dek);
253     release_pkc_list( pkc_list );
254     return rc;
255 }
256
257
258 /****************
259  * Filter to do a complete public key encryption.
260  */
261 int
262 encrypt_filter( void *opaque, int control,
263                IOBUF a, byte *buf, size_t *ret_len)
264 {
265     size_t size = *ret_len;
266     encrypt_filter_context_t *efx = opaque;
267     int rc=0;
268
269     if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */
270         BUG(); /* not used */
271     }
272     else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
273         if( !efx->header_okay ) {
274             efx->cfx.dek = m_alloc_secure( sizeof *efx->cfx.dek );
275             efx->cfx.dek->algo = opt.def_cipher_algo;
276             make_session_key( efx->cfx.dek );
277             if( DBG_CIPHER )
278                 log_hexdump("DEK is: ",
279                              efx->cfx.dek->key, efx->cfx.dek->keylen );
280
281             rc = write_pubkey_enc_from_list( efx->pkc_list, efx->cfx.dek, a );
282             if( rc )
283                 return rc;
284
285             iobuf_push_filter( a, cipher_filter, &efx->cfx );
286
287             efx->header_okay = 1;
288         }
289         rc = iobuf_write( a, buf, size );
290
291     }
292     else if( control == IOBUFCTRL_FREE ) {
293     }
294     else if( control == IOBUFCTRL_DESC ) {
295         *(char**)buf = "encrypt_filter";
296     }
297     return rc;
298 }
299
300
301 /****************
302  * Write pubkey-enc packets from the list of PKCs to OUT.
303  */
304 static int
305 write_pubkey_enc_from_list( PKC_LIST pkc_list, DEK *dek, IOBUF out )
306 {
307     PACKET pkt;
308     PKT_public_cert *pkc;
309     PKT_pubkey_enc  *enc;
310     int rc;
311
312     for( ; pkc_list; pkc_list = pkc_list->next ) {
313
314         pkc = pkc_list->pkc;
315         enc = m_alloc_clear( sizeof *enc );
316         enc->pubkey_algo = pkc->pubkey_algo;
317         if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL )
318             g10_elg_encrypt( pkc, enc, dek );
319         else if( enc->pubkey_algo == PUBKEY_ALGO_RSA )
320             g10_rsa_encrypt( pkc, enc, dek );
321         else
322             BUG();
323         /* and write it */
324         init_packet(&pkt);
325         pkt.pkttype = PKT_PUBKEY_ENC;
326         pkt.pkt.pubkey_enc = enc;
327         rc = build_packet( out, &pkt );
328         free_pubkey_enc(enc);
329         if( rc ) {
330             log_error("build pubkey_enc packet failed: %s\n", g10_errstr(rc) );
331             return rc;
332         }
333     }
334     return 0;
335 }
336