Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / crypto / external / bsd / netpgp / dist / src / lib / crypto.c
blob64ab1656ad1b8735abbdcccb0fe6470c73ab56f4
1 /*-
2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
3 * All rights reserved.
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Alistair Crooks (agc@NetBSD.org)
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
30 * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31 * All rights reserved.
32 * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33 * their moral rights under the UK Copyright Design and Patents Act 1988 to
34 * be recorded as the authors of this copyright work.
36 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37 * use this file except in compliance with the License.
39 * You may obtain a copy of the License at
40 * http://www.apache.org/licenses/LICENSE-2.0
42 * Unless required by applicable law or agreed to in writing, software
43 * distributed under the License is distributed on an "AS IS" BASIS,
44 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46 * See the License for the specific language governing permissions and
47 * limitations under the License.
49 #include "config.h"
51 #ifdef HAVE_SYS_CDEFS_H
52 #include <sys/cdefs.h>
53 #endif
55 #if defined(__NetBSD__)
56 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
57 __RCSID("$NetBSD: crypto.c,v 1.17 2009/10/06 02:26:05 agc Exp $");
58 #endif
60 #include <sys/types.h>
61 #include <sys/stat.h>
63 #ifdef HAVE_UNISTD_H
64 #include <unistd.h>
65 #endif
67 #include <string.h>
69 #include "types.h"
70 #include "crypto.h"
71 #include "readerwriter.h"
72 #include "memory.h"
73 #include "netpgpdefs.h"
74 #include "signature.h"
76 /**
77 \ingroup Core_MPI
78 \brief Decrypt and unencode MPI
79 \param buf Buffer in which to write decrypted unencoded MPI
80 \param buflen Length of buffer
81 \param encmpi
82 \param seckey
83 \return length of MPI
84 \note only RSA at present
86 int
87 __ops_decrypt_decode_mpi(unsigned char *buf,
88 unsigned buflen,
89 const BIGNUM *encmpi,
90 const __ops_seckey_t *seckey)
92 unsigned char encmpibuf[NETPGP_BUFSIZ];
93 unsigned char mpibuf[NETPGP_BUFSIZ];
94 unsigned mpisize;
95 int n;
96 int i;
98 mpisize = (unsigned)BN_num_bytes(encmpi);
99 /* MPI can't be more than 65,536 */
100 if (mpisize > sizeof(encmpibuf)) {
101 (void) fprintf(stderr, "mpisize too big %u\n", mpisize);
102 return -1;
104 BN_bn2bin(encmpi, encmpibuf);
106 if (seckey->pubkey.alg != OPS_PKA_RSA) {
107 (void) fprintf(stderr, "pubkey algorithm wrong\n");
108 return -1;
111 if (__ops_get_debug_level(__FILE__)) {
112 (void) fprintf(stderr, "\nDECRYPTING\n");
113 (void) fprintf(stderr, "encrypted data : ");
114 for (i = 0; i < 16; i++) {
115 (void) fprintf(stderr, "%2x ", encmpibuf[i]);
117 (void) fprintf(stderr, "\n");
119 n = __ops_rsa_private_decrypt(mpibuf, encmpibuf,
120 (unsigned)(BN_num_bits(encmpi) + 7) / 8,
121 &seckey->key.rsa, &seckey->pubkey.key.rsa);
122 if (n == -1) {
123 (void) fprintf(stderr, "ops_rsa_private_decrypt failure\n");
124 return -1;
127 if (__ops_get_debug_level(__FILE__)) {
128 (void) fprintf(stderr, "decrypted encoded m buf : ");
129 for (i = 0; i < 16; i++) {
130 (void) fprintf(stderr, "%2x ", mpibuf[i]);
132 (void) fprintf(stderr, "\n");
134 if (n <= 0) {
135 return -1;
138 if (__ops_get_debug_level(__FILE__)) {
139 printf(" decrypted=%d ", n);
140 hexdump(stdout, mpibuf, (unsigned)n, "");
141 printf("\n");
143 /* Decode EME-PKCS1_V1_5 (RFC 2437). */
145 if (mpibuf[0] != 0 || mpibuf[1] != 2) {
146 return -1;
149 /* Skip the random bytes. */
150 for (i = 2; i < n && mpibuf[i]; ++i) {
153 if (i == n || i < 10) {
154 return -1;
157 /* Skip the zero */
158 i += 1;
160 /* this is the unencoded m buf */
161 if ((unsigned) (n - i) <= buflen) {
162 (void) memcpy(buf, mpibuf + i, (unsigned)(n - i)); /* XXX - Flexelint */
165 if (__ops_get_debug_level(__FILE__)) {
166 int j;
168 printf("decoded m buf:\n");
169 for (j = 0; j < n - i; j++)
170 printf("%2x ", buf[j]);
171 printf("\n");
173 return n - i;
177 \ingroup Core_MPI
178 \brief RSA-encrypt an MPI
180 unsigned
181 __ops_rsa_encrypt_mpi(const unsigned char *encoded_m_buf,
182 const size_t sz_encoded_m_buf,
183 const __ops_pubkey_t * pubkey,
184 __ops_pk_sesskey_params_t * skp)
187 unsigned char encmpibuf[NETPGP_BUFSIZ];
188 int n;
190 if (sz_encoded_m_buf != (size_t)BN_num_bytes(pubkey->key.rsa.n)) {
191 (void) fprintf(stderr, "sz_encoded_m_buf wrong\n");
192 return 0;
195 n = __ops_rsa_public_encrypt(encmpibuf, encoded_m_buf,
196 sz_encoded_m_buf, &pubkey->key.rsa);
197 if (n == -1) {
198 (void) fprintf(stderr, "__ops_rsa_public_encrypt failure\n");
199 return 0;
202 if (n <= 0)
203 return 0;
205 skp->rsa.encrypted_m = BN_bin2bn(encmpibuf, n, NULL);
207 if (__ops_get_debug_level(__FILE__)) {
208 int i;
209 (void) fprintf(stderr, "encrypted mpi buf : ");
210 for (i = 0; i < 16; i++) {
211 (void) fprintf(stderr, "%2x ", encmpibuf[i]);
213 (void) fprintf(stderr, "\n");
215 return 1;
218 static __ops_cb_ret_t
219 write_parsed_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
221 const __ops_contents_t *content = &pkt->u;
222 static unsigned skipping; /* XXX - put skipping into pkt? */
224 if (__ops_get_debug_level(__FILE__)) {
225 printf("write_parsed_cb: ");
226 __ops_print_packet(pkt);
228 if (pkt->tag != OPS_PTAG_CT_UNARMOURED_TEXT && skipping) {
229 puts("...end of skip");
230 skipping = 0;
232 switch (pkt->tag) {
233 case OPS_PTAG_CT_UNARMOURED_TEXT:
234 printf("OPS_PTAG_CT_UNARMOURED_TEXT\n");
235 if (!skipping) {
236 puts("Skipping...");
237 skipping = 1;
239 fwrite(content->unarmoured_text.data, 1,
240 content->unarmoured_text.length, stdout);
241 break;
243 case OPS_PTAG_CT_PK_SESSION_KEY:
244 return pk_sesskey_cb(pkt, cbinfo);
246 case OPS_GET_SECKEY:
247 return get_seckey_cb(pkt, cbinfo);
249 case OPS_GET_PASSPHRASE:
250 return cbinfo->cryptinfo.getpassphrase(pkt, cbinfo);
252 case OPS_PTAG_CT_LITDATA_BODY:
253 return litdata_cb(pkt, cbinfo);
255 case OPS_PTAG_CT_ARMOUR_HEADER:
256 case OPS_PTAG_CT_ARMOUR_TRAILER:
257 case OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
258 case OPS_PTAG_CT_COMPRESSED:
259 case OPS_PTAG_CT_LITDATA_HEADER:
260 case OPS_PTAG_CT_SE_IP_DATA_BODY:
261 case OPS_PTAG_CT_SE_IP_DATA_HEADER:
262 case OPS_PTAG_CT_SE_DATA_BODY:
263 case OPS_PTAG_CT_SE_DATA_HEADER:
264 /* Ignore these packets */
265 /* They're handled in __ops_parse_packet() */
266 /* and nothing else needs to be done */
267 break;
269 default:
270 if (__ops_get_debug_level(__FILE__)) {
271 fprintf(stderr, "Unexpected packet tag=%d (0x%x)\n",
272 pkt->tag,
273 pkt->tag);
275 break;
278 return OPS_RELEASE_MEMORY;
282 \ingroup HighLevel_Crypto
283 Encrypt a file
284 \param infile Name of file to be encrypted
285 \param outfile Name of file to write to. If NULL, name is constructed from infile
286 \param pubkey Public Key to encrypt file for
287 \param use_armour Write armoured text, if set
288 \param allow_overwrite Allow output file to be overwrwritten if it exists
289 \return 1 if OK; else 0
291 unsigned
292 __ops_encrypt_file(__ops_io_t *io,
293 const char *infile,
294 const char *outfile,
295 const __ops_key_t *pubkey,
296 const unsigned use_armour,
297 const unsigned allow_overwrite)
299 __ops_output_t *output;
300 __ops_memory_t *inmem;
301 int fd_out;
303 __OPS_USED(io);
304 inmem = __ops_memory_new();
305 if (!__ops_mem_readfile(inmem, infile)) {
306 return 0;
308 fd_out = __ops_setup_file_write(&output, outfile, allow_overwrite);
309 if (fd_out < 0) {
310 __ops_memory_free(inmem);
311 return 0;
314 /* set armoured/not armoured here */
315 if (use_armour) {
316 __ops_writer_push_armor_msg(output);
319 /* Push the encrypted writer */
320 __ops_push_enc_se_ip(output, pubkey);
322 /* This does the writing */
323 __ops_write(output, __ops_mem_data(inmem), __ops_mem_len(inmem));
325 /* tidy up */
326 __ops_memory_free(inmem);
327 __ops_teardown_file_write(output, fd_out);
329 return 1;
332 /* encrypt the contents of the input buffer, and return the mem structure */
333 __ops_memory_t *
334 __ops_encrypt_buf(__ops_io_t *io,
335 const void *input,
336 const size_t insize,
337 const __ops_key_t *pubkey,
338 const unsigned use_armour)
340 __ops_output_t *output;
341 __ops_memory_t *outmem;
343 __OPS_USED(io);
344 if (input == NULL) {
345 (void) fprintf(io->errs,
346 "__ops_encrypt_buf: null memory\n");
347 return 0;
350 __ops_setup_memory_write(&output, &outmem, insize);
352 /* set armoured/not armoured here */
353 if (use_armour) {
354 __ops_writer_push_armor_msg(output);
357 /* Push the encrypted writer */
358 __ops_push_enc_se_ip(output, pubkey);
360 /* This does the writing */
361 __ops_write(output, input, insize);
363 /* tidy up */
364 __ops_writer_close(output);
365 __ops_output_delete(output);
367 return outmem;
371 \ingroup HighLevel_Crypto
372 \brief Decrypt a file.
373 \param infile Name of file to be decrypted
374 \param outfile Name of file to write to. If NULL, the filename is constructed from the input filename, following GPG conventions.
375 \param keyring Keyring to use
376 \param use_armour Expect armoured text, if set
377 \param allow_overwrite Allow output file to overwritten, if set.
378 \param getpassfunc Callback to use to get passphrase
381 unsigned
382 __ops_decrypt_file(__ops_io_t *io,
383 const char *infile,
384 const char *outfile,
385 __ops_keyring_t *keyring,
386 const unsigned use_armour,
387 const unsigned allow_overwrite,
388 void *passfp,
389 __ops_cbfunc_t *getpassfunc)
391 __ops_stream_t *parse = NULL;
392 const int printerrors = 1;
393 char *filename = NULL;
394 int fd_in;
395 int fd_out;
397 /* setup for reading from given input file */
398 fd_in = __ops_setup_file_read(io, &parse, infile,
399 NULL,
400 write_parsed_cb,
402 if (fd_in < 0) {
403 perror(infile);
404 return 0;
406 /* setup output filename */
407 if (outfile) {
408 fd_out = __ops_setup_file_write(&parse->cbinfo.output, outfile,
409 allow_overwrite);
410 if (fd_out < 0) {
411 perror(outfile);
412 __ops_teardown_file_read(parse, fd_in);
413 return 0;
415 } else {
416 const int suffixlen = 4;
417 const char *suffix = infile + strlen(infile) - suffixlen;
418 unsigned filenamelen;
420 if (strcmp(suffix, ".gpg") == 0 ||
421 strcmp(suffix, ".asc") == 0) {
422 filenamelen = strlen(infile) - strlen(suffix);
423 if ((filename = calloc(1, filenamelen + 1)) == NULL) {
424 (void) fprintf(stderr, "can't allocate %" PRIsize "d bytes\n",
425 (size_t)(filenamelen + 1));
426 return 0;
428 (void) strncpy(filename, infile, filenamelen);
429 filename[filenamelen] = 0x0;
432 fd_out = __ops_setup_file_write(&parse->cbinfo.output,
433 filename, allow_overwrite);
434 if (fd_out < 0) {
435 perror(filename);
436 free(filename);
437 __ops_teardown_file_read(parse, fd_in);
438 return 0;
442 /* \todo check for suffix matching armour param */
444 /* setup for writing decrypted contents to given output file */
446 /* setup keyring and passphrase callback */
447 parse->cbinfo.cryptinfo.keyring = keyring;
448 parse->cbinfo.passfp = passfp;
449 parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
451 /* Set up armour/passphrase options */
452 if (use_armour) {
453 __ops_reader_push_dearmour(parse);
456 /* Do it */
457 __ops_parse(parse, printerrors);
459 /* Unsetup */
460 if (use_armour) {
461 __ops_reader_pop_dearmour(parse);
464 if (filename) {
465 __ops_teardown_file_write(parse->cbinfo.output, fd_out);
466 free(filename);
468 __ops_teardown_file_read(parse, fd_in);
469 /* \todo cleardown crypt */
471 return 1;
474 /* decrypt an area of memory */
475 __ops_memory_t *
476 __ops_decrypt_buf(__ops_io_t *io,
477 const void *input,
478 const size_t insize,
479 __ops_keyring_t *keyring,
480 const unsigned use_armour,
481 void *passfp,
482 __ops_cbfunc_t *getpassfunc)
484 __ops_stream_t *parse = NULL;
485 __ops_memory_t *outmem;
486 __ops_memory_t *inmem;
487 const int printerrors = 1;
489 if (input == NULL) {
490 (void) fprintf(io->errs,
491 "__ops_encrypt_buf: null memory\n");
492 return 0;
495 inmem = __ops_memory_new();
496 __ops_memory_add(inmem, input, insize);
498 /* set up to read from memory */
499 __ops_setup_memory_read(io, &parse, inmem,
500 NULL,
501 write_parsed_cb,
504 /* setup for writing decrypted contents to given output file */
505 __ops_setup_memory_write(&parse->cbinfo.output, &outmem, insize);
507 /* setup keyring and passphrase callback */
508 parse->cbinfo.cryptinfo.keyring = keyring;
509 parse->cbinfo.passfp = passfp;
510 parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
512 /* Set up armour/passphrase options */
513 if (use_armour) {
514 __ops_reader_push_dearmour(parse);
517 /* Do it */
518 __ops_parse(parse, printerrors);
520 /* Unsetup */
521 if (use_armour) {
522 __ops_reader_pop_dearmour(parse);
525 /* tidy up */
526 __ops_teardown_memory_read(parse, inmem);
527 __ops_memory_release(inmem);
528 free(inmem);
530 __ops_writer_close(parse->cbinfo.output);
531 __ops_output_delete(parse->cbinfo.output);
533 return outmem;