2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
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
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.
51 #ifdef HAVE_SYS_CDEFS_H
52 #include <sys/cdefs.h>
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 $");
60 #include <sys/types.h>
71 #include "readerwriter.h"
73 #include "netpgpdefs.h"
74 #include "signature.h"
78 \brief Decrypt and unencode MPI
79 \param buf Buffer in which to write decrypted unencoded MPI
80 \param buflen Length of buffer
84 \note only RSA at present
87 __ops_decrypt_decode_mpi(unsigned char *buf
,
90 const __ops_seckey_t
*seckey
)
92 unsigned char encmpibuf
[NETPGP_BUFSIZ
];
93 unsigned char mpibuf
[NETPGP_BUFSIZ
];
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
);
104 BN_bn2bin(encmpi
, encmpibuf
);
106 if (seckey
->pubkey
.alg
!= OPS_PKA_RSA
) {
107 (void) fprintf(stderr
, "pubkey algorithm wrong\n");
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
);
123 (void) fprintf(stderr
, "ops_rsa_private_decrypt failure\n");
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");
138 if (__ops_get_debug_level(__FILE__
)) {
139 printf(" decrypted=%d ", n
);
140 hexdump(stdout
, mpibuf
, (unsigned)n
, "");
143 /* Decode EME-PKCS1_V1_5 (RFC 2437). */
145 if (mpibuf
[0] != 0 || mpibuf
[1] != 2) {
149 /* Skip the random bytes. */
150 for (i
= 2; i
< n
&& mpibuf
[i
]; ++i
) {
153 if (i
== n
|| i
< 10) {
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__
)) {
168 printf("decoded m buf:\n");
169 for (j
= 0; j
< n
- i
; j
++)
170 printf("%2x ", buf
[j
]);
178 \brief RSA-encrypt an MPI
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
];
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");
195 n
= __ops_rsa_public_encrypt(encmpibuf
, encoded_m_buf
,
196 sz_encoded_m_buf
, &pubkey
->key
.rsa
);
198 (void) fprintf(stderr
, "__ops_rsa_public_encrypt failure\n");
205 skp
->rsa
.encrypted_m
= BN_bin2bn(encmpibuf
, n
, NULL
);
207 if (__ops_get_debug_level(__FILE__
)) {
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");
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");
233 case OPS_PTAG_CT_UNARMOURED_TEXT
:
234 printf("OPS_PTAG_CT_UNARMOURED_TEXT\n");
239 fwrite(content
->unarmoured_text
.data
, 1,
240 content
->unarmoured_text
.length
, stdout
);
243 case OPS_PTAG_CT_PK_SESSION_KEY
:
244 return pk_sesskey_cb(pkt
, cbinfo
);
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 */
270 if (__ops_get_debug_level(__FILE__
)) {
271 fprintf(stderr
, "Unexpected packet tag=%d (0x%x)\n",
278 return OPS_RELEASE_MEMORY
;
282 \ingroup HighLevel_Crypto
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
292 __ops_encrypt_file(__ops_io_t
*io
,
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
;
304 inmem
= __ops_memory_new();
305 if (!__ops_mem_readfile(inmem
, infile
)) {
308 fd_out
= __ops_setup_file_write(&output
, outfile
, allow_overwrite
);
310 __ops_memory_free(inmem
);
314 /* set armoured/not armoured here */
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
));
326 __ops_memory_free(inmem
);
327 __ops_teardown_file_write(output
, fd_out
);
332 /* encrypt the contents of the input buffer, and return the mem structure */
334 __ops_encrypt_buf(__ops_io_t
*io
,
337 const __ops_key_t
*pubkey
,
338 const unsigned use_armour
)
340 __ops_output_t
*output
;
341 __ops_memory_t
*outmem
;
345 (void) fprintf(io
->errs
,
346 "__ops_encrypt_buf: null memory\n");
350 __ops_setup_memory_write(&output
, &outmem
, insize
);
352 /* set armoured/not armoured here */
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
);
364 __ops_writer_close(output
);
365 __ops_output_delete(output
);
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
382 __ops_decrypt_file(__ops_io_t
*io
,
385 __ops_keyring_t
*keyring
,
386 const unsigned use_armour
,
387 const unsigned allow_overwrite
,
389 __ops_cbfunc_t
*getpassfunc
)
391 __ops_stream_t
*parse
= NULL
;
392 const int printerrors
= 1;
393 char *filename
= NULL
;
397 /* setup for reading from given input file */
398 fd_in
= __ops_setup_file_read(io
, &parse
, infile
,
406 /* setup output filename */
408 fd_out
= __ops_setup_file_write(&parse
->cbinfo
.output
, outfile
,
412 __ops_teardown_file_read(parse
, fd_in
);
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));
428 (void) strncpy(filename
, infile
, filenamelen
);
429 filename
[filenamelen
] = 0x0;
432 fd_out
= __ops_setup_file_write(&parse
->cbinfo
.output
,
433 filename
, allow_overwrite
);
437 __ops_teardown_file_read(parse
, fd_in
);
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 */
453 __ops_reader_push_dearmour(parse
);
457 __ops_parse(parse
, printerrors
);
461 __ops_reader_pop_dearmour(parse
);
465 __ops_teardown_file_write(parse
->cbinfo
.output
, fd_out
);
468 __ops_teardown_file_read(parse
, fd_in
);
469 /* \todo cleardown crypt */
474 /* decrypt an area of memory */
476 __ops_decrypt_buf(__ops_io_t
*io
,
479 __ops_keyring_t
*keyring
,
480 const unsigned use_armour
,
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;
490 (void) fprintf(io
->errs
,
491 "__ops_encrypt_buf: null memory\n");
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
,
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 */
514 __ops_reader_push_dearmour(parse
);
518 __ops_parse(parse
, printerrors
);
522 __ops_reader_pop_dearmour(parse
);
526 __ops_teardown_memory_read(parse
, inmem
);
527 __ops_memory_release(inmem
);
530 __ops_writer_close(parse
->cbinfo
.output
);
531 __ops_output_delete(parse
->cbinfo
.output
);