xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/crypto.c (revision c04135dc7741376aa3789fc5a329ff08acd5085e)
12232f800Sagc /*-
22232f800Sagc  * Copyright (c) 2009 The NetBSD Foundation, Inc.
32232f800Sagc  * All rights reserved.
42232f800Sagc  *
52232f800Sagc  * This code is derived from software contributed to The NetBSD Foundation
62232f800Sagc  * by Alistair Crooks (agc@NetBSD.org)
72232f800Sagc  *
82232f800Sagc  * Redistribution and use in source and binary forms, with or without
92232f800Sagc  * modification, are permitted provided that the following conditions
102232f800Sagc  * are met:
112232f800Sagc  * 1. Redistributions of source code must retain the above copyright
122232f800Sagc  *    notice, this list of conditions and the following disclaimer.
132232f800Sagc  * 2. Redistributions in binary form must reproduce the above copyright
142232f800Sagc  *    notice, this list of conditions and the following disclaimer in the
152232f800Sagc  *    documentation and/or other materials provided with the distribution.
162232f800Sagc  *
172232f800Sagc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
182232f800Sagc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
192232f800Sagc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
202232f800Sagc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
212232f800Sagc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
222232f800Sagc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
232232f800Sagc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
242232f800Sagc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
252232f800Sagc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
262232f800Sagc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
272232f800Sagc  * POSSIBILITY OF SUCH DAMAGE.
282232f800Sagc  */
2993bf6008Sagc /*
3093bf6008Sagc  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
3193bf6008Sagc  * All rights reserved.
3293bf6008Sagc  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
3393bf6008Sagc  * their moral rights under the UK Copyright Design and Patents Act 1988 to
3493bf6008Sagc  * be recorded as the authors of this copyright work.
3593bf6008Sagc  *
3693bf6008Sagc  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
3793bf6008Sagc  * use this file except in compliance with the License.
3893bf6008Sagc  *
3993bf6008Sagc  * You may obtain a copy of the License at
4093bf6008Sagc  *     http://www.apache.org/licenses/LICENSE-2.0
4193bf6008Sagc  *
4293bf6008Sagc  * Unless required by applicable law or agreed to in writing, software
4393bf6008Sagc  * distributed under the License is distributed on an "AS IS" BASIS,
4493bf6008Sagc  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4593bf6008Sagc  *
4693bf6008Sagc  * See the License for the specific language governing permissions and
4793bf6008Sagc  * limitations under the License.
4893bf6008Sagc  */
4993bf6008Sagc #include "config.h"
5093bf6008Sagc 
5157324b9fSagc #ifdef HAVE_SYS_CDEFS_H
5257324b9fSagc #include <sys/cdefs.h>
5357324b9fSagc #endif
5457324b9fSagc 
5557324b9fSagc #if defined(__NetBSD__)
5657324b9fSagc __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
57*c04135dcSagc __RCSID("$NetBSD: crypto.c,v 1.36 2014/02/17 07:39:19 agc Exp $");
5857324b9fSagc #endif
5957324b9fSagc 
6057324b9fSagc #include <sys/types.h>
6157324b9fSagc #include <sys/stat.h>
6257324b9fSagc 
63efdd9dbaSagc #ifdef HAVE_UNISTD_H
64efdd9dbaSagc #include <unistd.h>
65efdd9dbaSagc #endif
66efdd9dbaSagc 
6793bf6008Sagc #include <string.h>
68bcfd8565Sagc 
69d21b929eSagc #include "types.h"
70bcfd8565Sagc #include "crypto.h"
71bcfd8565Sagc #include "readerwriter.h"
72bcfd8565Sagc #include "memory.h"
73bcfd8565Sagc #include "netpgpdefs.h"
74bcfd8565Sagc #include "signature.h"
7593bf6008Sagc 
7693bf6008Sagc /**
7793bf6008Sagc \ingroup Core_MPI
7893bf6008Sagc \brief Decrypt and unencode MPI
7993bf6008Sagc \param buf Buffer in which to write decrypted unencoded MPI
8093bf6008Sagc \param buflen Length of buffer
8193bf6008Sagc \param encmpi
820c310959Sagc \param seckey
8393bf6008Sagc \return length of MPI
8493bf6008Sagc \note only RSA at present
8593bf6008Sagc */
8693bf6008Sagc int
87fc1f8641Sagc pgp_decrypt_decode_mpi(uint8_t *buf,
88bcfd8565Sagc 				unsigned buflen,
89c2430ca2Sagc 				const BIGNUM *g_to_k,
90bcfd8565Sagc 				const BIGNUM *encmpi,
91fc1f8641Sagc 				const pgp_seckey_t *seckey)
9293bf6008Sagc {
93520c968fSagc 	unsigned        mpisize;
94b15ec256Sagc 	uint8_t		encmpibuf[NETPGP_BUFSIZ];
95b15ec256Sagc 	uint8_t		mpibuf[NETPGP_BUFSIZ];
96c2430ca2Sagc 	uint8_t		gkbuf[NETPGP_BUFSIZ];
9793bf6008Sagc 	int             i;
98520c968fSagc 	int             n;
9993bf6008Sagc 
1005a83dba0Sagc 	mpisize = (unsigned)BN_num_bytes(encmpi);
10193bf6008Sagc 	/* MPI can't be more than 65,536 */
102bcfd8565Sagc 	if (mpisize > sizeof(encmpibuf)) {
103bcfd8565Sagc 		(void) fprintf(stderr, "mpisize too big %u\n", mpisize);
104bcfd8565Sagc 		return -1;
105bcfd8565Sagc 	}
106520c968fSagc 	switch (seckey->pubkey.alg) {
107fc1f8641Sagc 	case PGP_PKA_RSA:
108c2430ca2Sagc 		BN_bn2bin(encmpi, encmpibuf);
109fc1f8641Sagc 		if (pgp_get_debug_level(__FILE__)) {
11047561e26Sagc 			hexdump(stderr, "encrypted", encmpibuf, 16);
111bcfd8565Sagc 		}
112fc1f8641Sagc 		n = pgp_rsa_private_decrypt(mpibuf, encmpibuf,
113bcfd8565Sagc 					(unsigned)(BN_num_bits(encmpi) + 7) / 8,
1140c310959Sagc 					&seckey->key.rsa, &seckey->pubkey.key.rsa);
115bcfd8565Sagc 		if (n == -1) {
116bcfd8565Sagc 			(void) fprintf(stderr, "ops_rsa_private_decrypt failure\n");
117bcfd8565Sagc 			return -1;
118bcfd8565Sagc 		}
119fc1f8641Sagc 		if (pgp_get_debug_level(__FILE__)) {
12047561e26Sagc 			hexdump(stderr, "decrypted", mpibuf, 16);
121bcfd8565Sagc 		}
122bcfd8565Sagc 		if (n <= 0) {
123bcfd8565Sagc 			return -1;
124bcfd8565Sagc 		}
12593bf6008Sagc 		/* Decode EME-PKCS1_V1_5 (RFC 2437). */
126bcfd8565Sagc 		if (mpibuf[0] != 0 || mpibuf[1] != 2) {
127bcfd8565Sagc 			return -1;
128bcfd8565Sagc 		}
12993bf6008Sagc 		/* Skip the random bytes. */
130bcfd8565Sagc 		for (i = 2; i < n && mpibuf[i]; ++i) {
131bcfd8565Sagc 		}
132bcfd8565Sagc 		if (i == n || i < 10) {
133bcfd8565Sagc 			return -1;
134bcfd8565Sagc 		}
13593bf6008Sagc 		/* Skip the zero */
13657324b9fSagc 		i += 1;
13793bf6008Sagc 		/* this is the unencoded m buf */
138bcfd8565Sagc 		if ((unsigned) (n - i) <= buflen) {
1395a83dba0Sagc 			(void) memcpy(buf, mpibuf + i, (unsigned)(n - i)); /* XXX - Flexelint */
140bcfd8565Sagc 		}
141fc1f8641Sagc 		if (pgp_get_debug_level(__FILE__)) {
14247561e26Sagc 			hexdump(stderr, "decoded m", buf, (size_t)(n - i));
14393bf6008Sagc 		}
14493bf6008Sagc 		return n - i;
145fc1f8641Sagc 	case PGP_PKA_DSA:
146fc1f8641Sagc 	case PGP_PKA_ELGAMAL:
147c2430ca2Sagc 		(void) BN_bn2bin(g_to_k, gkbuf);
148c2430ca2Sagc 		(void) BN_bn2bin(encmpi, encmpibuf);
149fc1f8641Sagc 		if (pgp_get_debug_level(__FILE__)) {
15073f34b00Sagc 			hexdump(stderr, "encrypted", encmpibuf, 16);
15173f34b00Sagc 		}
152fc1f8641Sagc 		n = pgp_elgamal_private_decrypt(mpibuf, gkbuf, encmpibuf,
153c2430ca2Sagc 					(unsigned)BN_num_bytes(encmpi),
15473f34b00Sagc 					&seckey->key.elgamal, &seckey->pubkey.key.elgamal);
15573f34b00Sagc 		if (n == -1) {
15673f34b00Sagc 			(void) fprintf(stderr, "ops_elgamal_private_decrypt failure\n");
15773f34b00Sagc 			return -1;
15873f34b00Sagc 		}
159fc1f8641Sagc 		if (pgp_get_debug_level(__FILE__)) {
16073f34b00Sagc 			hexdump(stderr, "decrypted", mpibuf, 16);
16173f34b00Sagc 		}
16273f34b00Sagc 		if (n <= 0) {
16373f34b00Sagc 			return -1;
16473f34b00Sagc 		}
16573f34b00Sagc 		/* Decode EME-PKCS1_V1_5 (RFC 2437). */
166c2430ca2Sagc 		if (mpibuf[0] != 2) {
167c2430ca2Sagc 			fprintf(stderr, "mpibuf mismatch\n");
16873f34b00Sagc 			return -1;
16973f34b00Sagc 		}
17073f34b00Sagc 		/* Skip the random bytes. */
171c2430ca2Sagc 		for (i = 1; i < n && mpibuf[i]; ++i) {
17273f34b00Sagc 		}
17373f34b00Sagc 		if (i == n || i < 10) {
174c2430ca2Sagc 			fprintf(stderr, "175 n %d\n", n);
17573f34b00Sagc 			return -1;
17673f34b00Sagc 		}
17773f34b00Sagc 		/* Skip the zero */
17873f34b00Sagc 		i += 1;
17973f34b00Sagc 		/* this is the unencoded m buf */
18073f34b00Sagc 		if ((unsigned) (n - i) <= buflen) {
18173f34b00Sagc 			(void) memcpy(buf, mpibuf + i, (unsigned)(n - i)); /* XXX - Flexelint */
18273f34b00Sagc 		}
183fc1f8641Sagc 		if (pgp_get_debug_level(__FILE__)) {
18473f34b00Sagc 			hexdump(stderr, "decoded m", buf, (size_t)(n - i));
18573f34b00Sagc 		}
18673f34b00Sagc 		return n - i;
187520c968fSagc 	default:
188520c968fSagc 		(void) fprintf(stderr, "pubkey algorithm wrong\n");
189520c968fSagc 		return -1;
190520c968fSagc 	}
19193bf6008Sagc }
19293bf6008Sagc 
19393bf6008Sagc /**
19493bf6008Sagc \ingroup Core_MPI
19593bf6008Sagc \brief RSA-encrypt an MPI
19693bf6008Sagc */
1974b3a3e18Sagc unsigned
198fc1f8641Sagc pgp_rsa_encrypt_mpi(const uint8_t *encoded_m_buf,
19993bf6008Sagc 		    const size_t sz_encoded_m_buf,
200fc1f8641Sagc 		    const pgp_pubkey_t * pubkey,
201fc1f8641Sagc 		    pgp_pk_sesskey_params_t * skp)
20293bf6008Sagc {
20393bf6008Sagc 
204b15ec256Sagc 	uint8_t   encmpibuf[NETPGP_BUFSIZ];
2055a83dba0Sagc 	int             n;
20693bf6008Sagc 
2070c310959Sagc 	if (sz_encoded_m_buf != (size_t)BN_num_bytes(pubkey->key.rsa.n)) {
208bcfd8565Sagc 		(void) fprintf(stderr, "sz_encoded_m_buf wrong\n");
2094b3a3e18Sagc 		return 0;
210bcfd8565Sagc 	}
21193bf6008Sagc 
212fc1f8641Sagc 	n = pgp_rsa_public_encrypt(encmpibuf, encoded_m_buf,
2130c310959Sagc 				sz_encoded_m_buf, &pubkey->key.rsa);
214bcfd8565Sagc 	if (n == -1) {
215fc1f8641Sagc 		(void) fprintf(stderr, "pgp_rsa_public_encrypt failure\n");
2164b3a3e18Sagc 		return 0;
217bcfd8565Sagc 	}
21893bf6008Sagc 
21993bf6008Sagc 	if (n <= 0)
2204b3a3e18Sagc 		return 0;
22193bf6008Sagc 
22293bf6008Sagc 	skp->rsa.encrypted_m = BN_bin2bn(encmpibuf, n, NULL);
22393bf6008Sagc 
224fc1f8641Sagc 	if (pgp_get_debug_level(__FILE__)) {
22547561e26Sagc 		hexdump(stderr, "encrypted mpi", encmpibuf, 16);
22693bf6008Sagc 	}
2274b3a3e18Sagc 	return 1;
22893bf6008Sagc }
22993bf6008Sagc 
23037d8b79bSagc /**
23137d8b79bSagc \ingroup Core_MPI
23237d8b79bSagc \brief Elgamal-encrypt an MPI
23337d8b79bSagc */
23437d8b79bSagc unsigned
235fc1f8641Sagc pgp_elgamal_encrypt_mpi(const uint8_t *encoded_m_buf,
23637d8b79bSagc 		    const size_t sz_encoded_m_buf,
237fc1f8641Sagc 		    const pgp_pubkey_t * pubkey,
238fc1f8641Sagc 		    pgp_pk_sesskey_params_t * skp)
23937d8b79bSagc {
24037d8b79bSagc 
24137d8b79bSagc 	uint8_t   encmpibuf[NETPGP_BUFSIZ];
24237d8b79bSagc 	uint8_t   g_to_k[NETPGP_BUFSIZ];
24337d8b79bSagc 	int             n;
24437d8b79bSagc 
24537d8b79bSagc 	if (sz_encoded_m_buf != (size_t)BN_num_bytes(pubkey->key.elgamal.p)) {
24637d8b79bSagc 		(void) fprintf(stderr, "sz_encoded_m_buf wrong\n");
24737d8b79bSagc 		return 0;
24837d8b79bSagc 	}
24937d8b79bSagc 
250fc1f8641Sagc 	n = pgp_elgamal_public_encrypt(g_to_k, encmpibuf, encoded_m_buf,
25137d8b79bSagc 				sz_encoded_m_buf, &pubkey->key.elgamal);
25237d8b79bSagc 	if (n == -1) {
253fc1f8641Sagc 		(void) fprintf(stderr, "pgp_elgamal_public_encrypt failure\n");
25437d8b79bSagc 		return 0;
25537d8b79bSagc 	}
25637d8b79bSagc 
25737d8b79bSagc 	if (n <= 0)
25837d8b79bSagc 		return 0;
25937d8b79bSagc 
26037d8b79bSagc 	skp->elgamal.g_to_k = BN_bin2bn(g_to_k, n / 2, NULL);
26137d8b79bSagc 	skp->elgamal.encrypted_m = BN_bin2bn(encmpibuf, n / 2, NULL);
26237d8b79bSagc 
263fc1f8641Sagc 	if (pgp_get_debug_level(__FILE__)) {
26437d8b79bSagc 		hexdump(stderr, "encrypted mpi", encmpibuf, 16);
26537d8b79bSagc 	}
26637d8b79bSagc 	return 1;
26737d8b79bSagc }
26837d8b79bSagc 
269fc1f8641Sagc static pgp_cb_ret_t
270fc1f8641Sagc write_parsed_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
271d369874eSagc {
272fc1f8641Sagc 	const pgp_contents_t	*content = &pkt->u;
273d369874eSagc 
274fc1f8641Sagc 	if (pgp_get_debug_level(__FILE__)) {
275d369874eSagc 		printf("write_parsed_cb: ");
276fc1f8641Sagc 		pgp_print_packet(&cbinfo->printstate, pkt);
277d369874eSagc 	}
278fc1f8641Sagc 	if (pkt->tag != PGP_PTAG_CT_UNARMOURED_TEXT && cbinfo->printstate.skipping) {
279d369874eSagc 		puts("...end of skip");
2802b48e3a6Sagc 		cbinfo->printstate.skipping = 0;
281d369874eSagc 	}
282d369874eSagc 	switch (pkt->tag) {
283fc1f8641Sagc 	case PGP_PTAG_CT_UNARMOURED_TEXT:
284fc1f8641Sagc 		printf("PGP_PTAG_CT_UNARMOURED_TEXT\n");
2852b48e3a6Sagc 		if (!cbinfo->printstate.skipping) {
286d369874eSagc 			puts("Skipping...");
2872b48e3a6Sagc 			cbinfo->printstate.skipping = 1;
288d369874eSagc 		}
289*c04135dcSagc 		if (fwrite(content->unarmoured_text.data, 1,
290*c04135dcSagc 		       content->unarmoured_text.length, stdout) != content->unarmoured_text.length) {
291*c04135dcSagc 			fprintf(stderr, "unable to write unarmoured text data\n");
292*c04135dcSagc 			cbinfo->printstate.skipping = 1;
293*c04135dcSagc 		}
294d369874eSagc 		break;
295d369874eSagc 
296fc1f8641Sagc 	case PGP_PTAG_CT_PK_SESSION_KEY:
297fc1f8641Sagc 		return pgp_pk_sesskey_cb(pkt, cbinfo);
298d369874eSagc 
299fc1f8641Sagc 	case PGP_GET_SECKEY:
30073f34b00Sagc 		if (cbinfo->sshseckey) {
30173f34b00Sagc 			*content->get_seckey.seckey = cbinfo->sshseckey;
302fc1f8641Sagc 			return PGP_KEEP_MEMORY;
30373f34b00Sagc 		}
304fc1f8641Sagc 		return pgp_get_seckey_cb(pkt, cbinfo);
305d369874eSagc 
306fc1f8641Sagc 	case PGP_GET_PASSPHRASE:
307d369874eSagc 		return cbinfo->cryptinfo.getpassphrase(pkt, cbinfo);
308d369874eSagc 
309fc1f8641Sagc 	case PGP_PTAG_CT_LITDATA_BODY:
310fc1f8641Sagc 		return pgp_litdata_cb(pkt, cbinfo);
311d369874eSagc 
312fc1f8641Sagc 	case PGP_PTAG_CT_ARMOUR_HEADER:
313fc1f8641Sagc 	case PGP_PTAG_CT_ARMOUR_TRAILER:
314fc1f8641Sagc 	case PGP_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
315fc1f8641Sagc 	case PGP_PTAG_CT_COMPRESSED:
316fc1f8641Sagc 	case PGP_PTAG_CT_LITDATA_HEADER:
317fc1f8641Sagc 	case PGP_PTAG_CT_SE_IP_DATA_BODY:
318fc1f8641Sagc 	case PGP_PTAG_CT_SE_IP_DATA_HEADER:
319fc1f8641Sagc 	case PGP_PTAG_CT_SE_DATA_BODY:
320fc1f8641Sagc 	case PGP_PTAG_CT_SE_DATA_HEADER:
321d369874eSagc 		/* Ignore these packets  */
322e2c60ad1Sagc 		/* They're handled in parse_packet() */
323d369874eSagc 		/* and nothing else needs to be done */
324d369874eSagc 		break;
325d369874eSagc 
326d369874eSagc 	default:
327fc1f8641Sagc 		if (pgp_get_debug_level(__FILE__)) {
328d369874eSagc 			fprintf(stderr, "Unexpected packet tag=%d (0x%x)\n",
329d369874eSagc 				pkt->tag,
330d369874eSagc 				pkt->tag);
331d369874eSagc 		}
332d369874eSagc 		break;
333d369874eSagc 	}
334d369874eSagc 
335fc1f8641Sagc 	return PGP_RELEASE_MEMORY;
336d369874eSagc }
33793bf6008Sagc 
33893bf6008Sagc /**
33993bf6008Sagc \ingroup HighLevel_Crypto
34093bf6008Sagc Encrypt a file
341b1b58706Sagc \param infile Name of file to be encrypted
342b1b58706Sagc \param outfile Name of file to write to. If NULL, name is constructed from infile
34357324b9fSagc \param pubkey Public Key to encrypt file for
34493bf6008Sagc \param use_armour Write armoured text, if set
34593bf6008Sagc \param allow_overwrite Allow output file to be overwrwritten if it exists
3464b3a3e18Sagc \return 1 if OK; else 0
34793bf6008Sagc */
3484b3a3e18Sagc unsigned
349fc1f8641Sagc pgp_encrypt_file(pgp_io_t *io,
350d21b929eSagc 			const char *infile,
351b1b58706Sagc 			const char *outfile,
352fc1f8641Sagc 			const pgp_key_t *key,
3534b3a3e18Sagc 			const unsigned use_armour,
354f7745f84Sagc 			const unsigned allow_overwrite,
355f7745f84Sagc 			const char *cipher)
35693bf6008Sagc {
357fc1f8641Sagc 	pgp_output_t	*output;
358fc1f8641Sagc 	pgp_memory_t	*inmem;
3595a83dba0Sagc 	int		 fd_out;
36093bf6008Sagc 
361fc1f8641Sagc 	__PGP_USED(io);
362fc1f8641Sagc 	inmem = pgp_memory_new();
363fc1f8641Sagc 	if (!pgp_mem_readfile(inmem, infile)) {
3644b3a3e18Sagc 		return 0;
36593bf6008Sagc 	}
366fc1f8641Sagc 	fd_out = pgp_setup_file_write(&output, outfile, allow_overwrite);
367bcfd8565Sagc 	if (fd_out < 0) {
368fc1f8641Sagc 		pgp_memory_free(inmem);
3694b3a3e18Sagc 		return 0;
370bcfd8565Sagc 	}
37193bf6008Sagc 
37293bf6008Sagc 	/* set armoured/not armoured here */
373bcfd8565Sagc 	if (use_armour) {
374fc1f8641Sagc 		pgp_writer_push_armor_msg(output);
375bcfd8565Sagc 	}
37693bf6008Sagc 
37793bf6008Sagc 	/* Push the encrypted writer */
378fc1f8641Sagc 	if (!pgp_push_enc_se_ip(output, key, cipher)) {
379fc1f8641Sagc 		pgp_memory_free(inmem);
380520c968fSagc 		return 0;
381520c968fSagc 	}
38293bf6008Sagc 
38393bf6008Sagc 	/* This does the writing */
384fc1f8641Sagc 	pgp_write(output, pgp_mem_data(inmem), (unsigned)pgp_mem_len(inmem));
38593bf6008Sagc 
38693bf6008Sagc 	/* tidy up */
387fc1f8641Sagc 	pgp_memory_free(inmem);
388fc1f8641Sagc 	pgp_teardown_file_write(output, fd_out);
38993bf6008Sagc 
3904b3a3e18Sagc 	return 1;
39193bf6008Sagc }
39293bf6008Sagc 
393d369874eSagc /* encrypt the contents of the input buffer, and return the mem structure */
394fc1f8641Sagc pgp_memory_t *
395fc1f8641Sagc pgp_encrypt_buf(pgp_io_t *io,
396d369874eSagc 			const void *input,
397d369874eSagc 			const size_t insize,
398fc1f8641Sagc 			const pgp_key_t *pubkey,
399f7745f84Sagc 			const unsigned use_armour,
400f7745f84Sagc 			const char *cipher)
401d369874eSagc {
402fc1f8641Sagc 	pgp_output_t	*output;
403fc1f8641Sagc 	pgp_memory_t	*outmem;
404d369874eSagc 
405fc1f8641Sagc 	__PGP_USED(io);
406d369874eSagc 	if (input == NULL) {
407d369874eSagc 		(void) fprintf(io->errs,
408fc1f8641Sagc 			"pgp_encrypt_buf: null memory\n");
409d369874eSagc 		return 0;
410d369874eSagc 	}
411d369874eSagc 
412fc1f8641Sagc 	pgp_setup_memory_write(&output, &outmem, insize);
413d369874eSagc 
414d369874eSagc 	/* set armoured/not armoured here */
415d369874eSagc 	if (use_armour) {
416fc1f8641Sagc 		pgp_writer_push_armor_msg(output);
417d369874eSagc 	}
418d369874eSagc 
419d369874eSagc 	/* Push the encrypted writer */
420fc1f8641Sagc 	pgp_push_enc_se_ip(output, pubkey, cipher);
421d369874eSagc 
422d369874eSagc 	/* This does the writing */
423fc1f8641Sagc 	pgp_write(output, input, (unsigned)insize);
424d369874eSagc 
425d369874eSagc 	/* tidy up */
426fc1f8641Sagc 	pgp_writer_close(output);
427fc1f8641Sagc 	pgp_output_delete(output);
428d369874eSagc 
429d369874eSagc 	return outmem;
430d369874eSagc }
431d369874eSagc 
43293bf6008Sagc /**
43393bf6008Sagc    \ingroup HighLevel_Crypto
43493bf6008Sagc    \brief Decrypt a file.
435b1b58706Sagc    \param infile Name of file to be decrypted
436b1b58706Sagc    \param outfile Name of file to write to. If NULL, the filename is constructed from the input filename, following GPG conventions.
43793bf6008Sagc    \param keyring Keyring to use
43893bf6008Sagc    \param use_armour Expect armoured text, if set
43993bf6008Sagc    \param allow_overwrite Allow output file to overwritten, if set.
44041335e2dSagc    \param getpassfunc Callback to use to get passphrase
44193bf6008Sagc */
44293bf6008Sagc 
4434b3a3e18Sagc unsigned
444fc1f8641Sagc pgp_decrypt_file(pgp_io_t *io,
445d21b929eSagc 			const char *infile,
446b1b58706Sagc 			const char *outfile,
447fc1f8641Sagc 			pgp_keyring_t *secring,
448fc1f8641Sagc 			pgp_keyring_t *pubring,
4494b3a3e18Sagc 			const unsigned use_armour,
4504b3a3e18Sagc 			const unsigned allow_overwrite,
45173f34b00Sagc 			const unsigned sshkeys,
45241335e2dSagc 			void *passfp,
453ea162599Sagc 			int numtries,
454fc1f8641Sagc 			pgp_cbfunc_t *getpassfunc)
45593bf6008Sagc {
456fc1f8641Sagc 	pgp_stream_t	*parse = NULL;
457393ecd92Sagc 	const int	 printerrors = 1;
458b1b58706Sagc 	char		*filename = NULL;
4595a83dba0Sagc 	int		 fd_in;
4605a83dba0Sagc 	int		 fd_out;
46193bf6008Sagc 
46293bf6008Sagc 	/* setup for reading from given input file */
463fc1f8641Sagc 	fd_in = pgp_setup_file_read(io, &parse, infile,
46493bf6008Sagc 				    NULL,
465d369874eSagc 				    write_parsed_cb,
4664b3a3e18Sagc 				    0);
46793bf6008Sagc 	if (fd_in < 0) {
468b1b58706Sagc 		perror(infile);
4694b3a3e18Sagc 		return 0;
47093bf6008Sagc 	}
4712232f800Sagc 	/* setup output filename */
472b1b58706Sagc 	if (outfile) {
473fc1f8641Sagc 		fd_out = pgp_setup_file_write(&parse->cbinfo.output, outfile,
474b1b58706Sagc 				allow_overwrite);
47593bf6008Sagc 		if (fd_out < 0) {
476b1b58706Sagc 			perror(outfile);
477fc1f8641Sagc 			pgp_teardown_file_read(parse, fd_in);
4784b3a3e18Sagc 			return 0;
47993bf6008Sagc 		}
48093bf6008Sagc 	} else {
481d21b929eSagc 		const int	suffixlen = 4;
482b1b58706Sagc 		const char     *suffix = infile + strlen(infile) - suffixlen;
483d21b929eSagc 		unsigned	filenamelen;
484b1b58706Sagc 
48593bf6008Sagc 		if (strcmp(suffix, ".gpg") == 0 ||
48693bf6008Sagc 		    strcmp(suffix, ".asc") == 0) {
48769d4f30fSagc 			filenamelen = (unsigned)(strlen(infile) - strlen(suffix));
4885a83dba0Sagc 			if ((filename = calloc(1, filenamelen + 1)) == NULL) {
4895a83dba0Sagc 				(void) fprintf(stderr, "can't allocate %" PRIsize "d bytes\n",
4905a83dba0Sagc 					(size_t)(filenamelen + 1));
4915a83dba0Sagc 				return 0;
4925a83dba0Sagc 			}
493b1b58706Sagc 			(void) strncpy(filename, infile, filenamelen);
494b1b58706Sagc 			filename[filenamelen] = 0x0;
49593bf6008Sagc 		}
49693bf6008Sagc 
497fc1f8641Sagc 		fd_out = pgp_setup_file_write(&parse->cbinfo.output,
498b1b58706Sagc 					filename, allow_overwrite);
49993bf6008Sagc 		if (fd_out < 0) {
500b1b58706Sagc 			perror(filename);
5015a83dba0Sagc 			free(filename);
502fc1f8641Sagc 			pgp_teardown_file_read(parse, fd_in);
5034b3a3e18Sagc 			return 0;
50493bf6008Sagc 		}
50593bf6008Sagc 	}
50693bf6008Sagc 
50793bf6008Sagc 	/* \todo check for suffix matching armour param */
50893bf6008Sagc 
50993bf6008Sagc 	/* setup for writing decrypted contents to given output file */
51093bf6008Sagc 
51193bf6008Sagc 	/* setup keyring and passphrase callback */
5120aa60872Sagc 	parse->cbinfo.cryptinfo.secring = secring;
51341335e2dSagc 	parse->cbinfo.passfp = passfp;
51441335e2dSagc 	parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
5150aa60872Sagc 	parse->cbinfo.cryptinfo.pubring = pubring;
51673f34b00Sagc 	parse->cbinfo.sshseckey = (sshkeys) ? &secring->keys[0].key.seckey : NULL;
517ea162599Sagc 	parse->cbinfo.numtries = numtries;
51893bf6008Sagc 
51993bf6008Sagc 	/* Set up armour/passphrase options */
520b1b58706Sagc 	if (use_armour) {
521fc1f8641Sagc 		pgp_reader_push_dearmour(parse);
522b1b58706Sagc 	}
52393bf6008Sagc 
52493bf6008Sagc 	/* Do it */
525fc1f8641Sagc 	pgp_parse(parse, printerrors);
52693bf6008Sagc 
52793bf6008Sagc 	/* Unsetup */
528b1b58706Sagc 	if (use_armour) {
529fc1f8641Sagc 		pgp_reader_pop_dearmour(parse);
530b1b58706Sagc 	}
53193bf6008Sagc 
532ea162599Sagc 	/* if we didn't get the passphrase, unlink output file */
533ea162599Sagc 	if (!parse->cbinfo.gotpass) {
534ea162599Sagc 		(void) unlink((filename) ? filename : outfile);
535ea162599Sagc 	}
536ea162599Sagc 
537b1b58706Sagc 	if (filename) {
538fc1f8641Sagc 		pgp_teardown_file_write(parse->cbinfo.output, fd_out);
5395a83dba0Sagc 		free(filename);
540b1b58706Sagc 	}
541fc1f8641Sagc 	pgp_teardown_file_read(parse, fd_in);
54293bf6008Sagc 	/* \todo cleardown crypt */
54393bf6008Sagc 
5444b3a3e18Sagc 	return 1;
54593bf6008Sagc }
54693bf6008Sagc 
547d369874eSagc /* decrypt an area of memory */
548fc1f8641Sagc pgp_memory_t *
549fc1f8641Sagc pgp_decrypt_buf(pgp_io_t *io,
550d369874eSagc 			const void *input,
551d369874eSagc 			const size_t insize,
552fc1f8641Sagc 			pgp_keyring_t *secring,
553fc1f8641Sagc 			pgp_keyring_t *pubring,
554d369874eSagc 			const unsigned use_armour,
55573f34b00Sagc 			const unsigned sshkeys,
556d369874eSagc 			void *passfp,
557ea162599Sagc 			int numtries,
558fc1f8641Sagc 			pgp_cbfunc_t *getpassfunc)
55993bf6008Sagc {
560fc1f8641Sagc 	pgp_stream_t	*parse = NULL;
561fc1f8641Sagc 	pgp_memory_t	*outmem;
562fc1f8641Sagc 	pgp_memory_t	*inmem;
563d369874eSagc 	const int	 printerrors = 1;
56493bf6008Sagc 
565d369874eSagc 	if (input == NULL) {
566d369874eSagc 		(void) fprintf(io->errs,
567fc1f8641Sagc 			"pgp_encrypt_buf: null memory\n");
568d369874eSagc 		return 0;
56993bf6008Sagc 	}
57093bf6008Sagc 
571fc1f8641Sagc 	inmem = pgp_memory_new();
572fc1f8641Sagc 	pgp_memory_add(inmem, input, insize);
573d369874eSagc 
574d369874eSagc 	/* set up to read from memory */
575fc1f8641Sagc 	pgp_setup_memory_read(io, &parse, inmem,
576d369874eSagc 				    NULL,
577d369874eSagc 				    write_parsed_cb,
578d369874eSagc 				    0);
579d369874eSagc 
580d369874eSagc 	/* setup for writing decrypted contents to given output file */
581fc1f8641Sagc 	pgp_setup_memory_write(&parse->cbinfo.output, &outmem, insize);
582d369874eSagc 
583d369874eSagc 	/* setup keyring and passphrase callback */
5840aa60872Sagc 	parse->cbinfo.cryptinfo.secring = secring;
5850aa60872Sagc 	parse->cbinfo.cryptinfo.pubring = pubring;
586d369874eSagc 	parse->cbinfo.passfp = passfp;
587d369874eSagc 	parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
58873f34b00Sagc 	parse->cbinfo.sshseckey = (sshkeys) ? &secring->keys[0].key.seckey : NULL;
589ea162599Sagc 	parse->cbinfo.numtries = numtries;
590d369874eSagc 
591d369874eSagc 	/* Set up armour/passphrase options */
592d369874eSagc 	if (use_armour) {
593fc1f8641Sagc 		pgp_reader_push_dearmour(parse);
59493bf6008Sagc 	}
595d369874eSagc 
596d369874eSagc 	/* Do it */
597fc1f8641Sagc 	pgp_parse(parse, printerrors);
598d369874eSagc 
599d369874eSagc 	/* Unsetup */
600d369874eSagc 	if (use_armour) {
601fc1f8641Sagc 		pgp_reader_pop_dearmour(parse);
602d369874eSagc 	}
603d369874eSagc 
604d369874eSagc 	/* tidy up */
605fc1f8641Sagc 	pgp_teardown_memory_read(parse, inmem);
606d369874eSagc 
607fc1f8641Sagc 	pgp_writer_close(parse->cbinfo.output);
608fc1f8641Sagc 	pgp_output_delete(parse->cbinfo.output);
609d369874eSagc 
610ea162599Sagc 	/* if we didn't get the passphrase, return NULL */
611ea162599Sagc 	return (parse->cbinfo.gotpass) ? outmem : NULL;
612d369874eSagc }
613