예제 #1
0
static void add_subkey_binding_signature(pgp_subkeysig_t* p, pgp_key_t* primarykey, pgp_key_t* subkey, pgp_key_t* seckey)
{
	/*add "0x18: Subkey Binding Signature" packet, PGP_SIG_SUBKEY */
	pgp_create_sig_t* sig = NULL;
	pgp_output_t*     sigoutput = NULL;
	pgp_memory_t*     mem_sig = NULL;

	sig = pgp_create_sig_new();
	pgp_sig_start_key_sig(sig, &primarykey->key.pubkey, &subkey->key.pubkey, NULL, PGP_SIG_SUBKEY);

	pgp_add_creation_time(sig, time(NULL));
	pgp_add_key_expiration_time(sig, 0);
	pgp_add_key_flags(sig, PGP_KEYFLAG_ENC_STORAGE|PGP_KEYFLAG_ENC_COMM); /* NB: algo/hash/compression preferences are not added to subkeys */

	pgp_end_hashed_subpkts(sig);

	pgp_add_issuer_keyid(sig, seckey->pubkeyid); /* the issuer keyid is not hashed by definition */

	pgp_setup_memory_write(&sigoutput, &mem_sig, 128);
	pgp_write_sig(sigoutput, sig, &seckey->key.seckey.pubkey, &seckey->key.seckey);

	p->subkey         = primarykey->subkeyc-1; /* index of subkey in array */
	p->packet.length  = mem_sig->length;
	p->packet.raw     = mem_sig->buf; mem_sig->buf = NULL; /* move ownership to packet */
	copy_sig_info(&p->siginfo, &sig->sig.info); /* not sure, if this is okay, however, siginfo should be set up, otherwise we get "bad info-type" errors */

	pgp_create_sig_delete(sig);
	pgp_output_delete(sigoutput);
	free(mem_sig); /* do not use pgp_memory_free() as this would also free mem_sig->buf which is owned by the packet */
}
예제 #2
0
/**
\ingroup Core_Keys
\brief Add selfsigned User ID to key
\param keydata Key to which to add user ID
\param userid Self-signed User ID to add
\return 1 if OK; else 0
*/
unsigned 
pgp_add_selfsigned_userid(pgp_key_t *key, uint8_t *userid)
{
	pgp_create_sig_t	*sig;
	pgp_subpacket_t	 sigpacket;
	pgp_memory_t		*mem_userid = NULL;
	pgp_output_t		*useridoutput = NULL;
	pgp_memory_t		*mem_sig = NULL;
	pgp_output_t		*sigoutput = NULL;

	/*
         * create signature packet for this userid
         */

	/* create userid pkt */
	pgp_setup_memory_write(&useridoutput, &mem_userid, 128);
	pgp_write_struct_userid(useridoutput, userid);

	/* create sig for this pkt */
	sig = pgp_create_sig_new();
	pgp_sig_start_key_sig(sig, &key->key.seckey.pubkey, userid, PGP_CERT_POSITIVE);
	pgp_add_time(sig, (int64_t)time(NULL), "birth");
	pgp_add_issuer_keyid(sig, key->sigid);
	pgp_add_primary_userid(sig, 1);
	pgp_end_hashed_subpkts(sig);

	pgp_setup_memory_write(&sigoutput, &mem_sig, 128);
	pgp_write_sig(sigoutput, sig, &key->key.seckey.pubkey, &key->key.seckey);

	/* add this packet to key */
	sigpacket.length = pgp_mem_len(mem_sig);
	sigpacket.raw = pgp_mem_data(mem_sig);

	/* add userid to key */
	(void) pgp_add_userid(key, userid);
	(void) pgp_add_subpacket(key, &sigpacket);

	/* cleanup */
	pgp_create_sig_delete(sig);
	pgp_output_delete(useridoutput);
	pgp_output_delete(sigoutput);
	pgp_memory_free(mem_userid);
	pgp_memory_free(mem_sig);

	return 1;
}
예제 #3
0
/* this interface isn't right - hook into callback for getting passphrase */
char *
pgp_export_key(pgp_io_t *io, const pgp_key_t *keydata, uint8_t *passphrase)
{
	pgp_output_t	*output;
	pgp_memory_t	*mem;
	char		*cp;

	__PGP_USED(io);
	pgp_setup_memory_write(&output, &mem, 128);
	if (keydata->type == PGP_PTAG_CT_PUBLIC_KEY) {
		pgp_write_xfer_pubkey(output, keydata, 1);
	} else {
		pgp_write_xfer_seckey(output, keydata, passphrase,
					strlen((char *)passphrase), 1);
	}
	cp = netpgp_strdup(pgp_mem_data(mem));
	pgp_teardown_memory_write(output, mem);
	return cp;
}
예제 #4
0
static void add_selfsigned_userid(pgp_key_t *skey, pgp_key_t *pkey, const uint8_t *userid, time_t key_expiry)
{
	/* similar to pgp_add_selfsigned_userid() which, however, uses different key flags */
	pgp_create_sig_t* sig = NULL;
	pgp_subpacket_t	  sigpacket;
	pgp_memory_t*     mem_sig = NULL;
	pgp_output_t*     sigoutput = NULL;

	/* create sig for this pkt */
	sig = pgp_create_sig_new();
	pgp_sig_start_key_sig(sig, &skey->key.seckey.pubkey, NULL, userid, PGP_CERT_POSITIVE);

	pgp_add_creation_time(sig, time(NULL));
	pgp_add_key_expiration_time(sig, key_expiry);
	pgp_add_primary_userid(sig, 1);
	pgp_add_key_flags(sig, PGP_KEYFLAG_SIGN_DATA|PGP_KEYFLAG_CERT_KEYS);
	add_key_prefs(sig);
	pgp_add_key_features(sig); /* will add 0x01 - modification detection */

	pgp_end_hashed_subpkts(sig);

	pgp_add_issuer_keyid(sig, skey->pubkeyid); /* the issuer keyid is not hashed by definition */

	pgp_setup_memory_write(&sigoutput, &mem_sig, 128);
	pgp_write_sig(sigoutput, sig, &skey->key.seckey.pubkey, &skey->key.seckey);

	/* add this packet to key */
	sigpacket.length = pgp_mem_len(mem_sig);
	sigpacket.raw = pgp_mem_data(mem_sig);

	/* add user id and signature to key */
	pgp_update_userid(skey, userid, &sigpacket, &sig->sig.info);
	if(pkey) {
		pgp_update_userid(pkey, userid, &sigpacket, &sig->sig.info);
	}

	/* cleanup */
	pgp_create_sig_delete(sig);
	pgp_output_delete(sigoutput);
	pgp_memory_free(mem_sig);
}
예제 #5
0
파일: crypto.c 프로젝트: Henauxg/minix
/* encrypt the contents of the input buffer, and return the mem structure */
pgp_memory_t *
pgp_encrypt_buf(pgp_io_t *io,
			const void *input,
			const size_t insize,
			const pgp_key_t *pubkey,
			const unsigned use_armour,
			const char *cipher)
{
	pgp_output_t	*output;
	pgp_memory_t	*outmem;

	__PGP_USED(io);
	if (input == NULL) {
		(void) fprintf(io->errs,
			"pgp_encrypt_buf: null memory\n");
		return 0;
	}

	pgp_setup_memory_write(&output, &outmem, insize);

	/* set armoured/not armoured here */
	if (use_armour) {
		pgp_writer_push_armor_msg(output);
	}

	/* Push the encrypted writer */
	pgp_push_enc_se_ip(output, pubkey, cipher);

	/* This does the writing */
	pgp_write(output, input, (unsigned)insize);

	/* tidy up */
	pgp_writer_close(output);
	pgp_output_delete(output);

	return outmem;
}
예제 #6
0
파일: signature.c 프로젝트: Henauxg/minix
/**
\ingroup HighLevel_Sign
\brief Sign a file
\param inname Input filename
\param outname Output filename. If NULL, a name is constructed from the input filename.
\param seckey Secret Key to use for signing
\param armored Write armoured text, if set.
\param overwrite May overwrite existing file, if set.
\return 1 if OK; else 0;

*/
unsigned 
pgp_sign_file(pgp_io_t *io,
		const char *inname,
		const char *outname,
		const pgp_seckey_t *seckey,
		const char *hashname,
		const int64_t from,
		const uint64_t duration,
		const unsigned armored,
		const unsigned cleartext,
		const unsigned overwrite)
{
	pgp_create_sig_t	*sig;
	pgp_sig_type_t	 sig_type;
	pgp_hash_alg_t	 hash_alg;
	pgp_memory_t		*infile;
	pgp_output_t		*output;
	pgp_hash_t		*hash;
	unsigned		 ret;
	uint8_t			 keyid[PGP_KEY_ID_SIZE];
	int			 fd_out;

	sig = NULL;
	sig_type = PGP_SIG_BINARY;
	infile = NULL;
	output = NULL;
	hash = NULL;
	fd_out = 0;

	/* find the hash algorithm */
	hash_alg = pgp_str_to_hash_alg(hashname);
	if (hash_alg == PGP_HASH_UNKNOWN) {
		(void) fprintf(io->errs,
			"pgp_sign_file: unknown hash algorithm: \"%s\"\n",
			hashname);
		return 0;
	}

	/* read input file into buf */
	infile = pgp_memory_new();
	if (!pgp_mem_readfile(infile, inname)) {
		return 0;
	}

	/* setup output file */
	fd_out = open_output_file(&output, inname, outname,
				(armored) ? "asc" : "gpg", overwrite);
	if (fd_out < 0) {
		pgp_memory_free(infile);
		return 0;
	}

	/* set up signature */
	sig = pgp_create_sig_new();
	if (!sig) {
		pgp_memory_free(infile);
		pgp_teardown_file_write(output, fd_out);
		return 0;
	}

	pgp_start_sig(sig, seckey, hash_alg, sig_type);

	if (cleartext) {
		if (pgp_writer_push_clearsigned(output, sig) != 1) {
			return 0;
		}

		/* Do the signing */
		pgp_write(output, pgp_mem_data(infile), (unsigned)pgp_mem_len(infile));
		pgp_memory_free(infile);

		/* add signature with subpackets: */
		/* - creation time */
		/* - key id */
		ret = pgp_writer_use_armored_sig(output) &&
				pgp_add_time(sig, (int64_t)from, "birth") &&
				pgp_add_time(sig, (int64_t)duration, "expiration");
		if (ret == 0) {
			pgp_teardown_file_write(output, fd_out);
			return 0;
		}

		pgp_keyid(keyid, PGP_KEY_ID_SIZE, &seckey->pubkey, hash_alg);
		ret = pgp_add_issuer_keyid(sig, keyid) &&
			pgp_end_hashed_subpkts(sig) &&
			pgp_write_sig(output, sig, &seckey->pubkey, seckey);

		pgp_teardown_file_write(output, fd_out);

		if (ret == 0) {
			PGP_ERROR_1(&output->errors, PGP_E_W, "%s",
			    "Cannot sign file as cleartext");
		}
	} else {
		/* set armoured/not armoured here */
		if (armored) {
			pgp_writer_push_armor_msg(output);
		}

		/* write one_pass_sig */
		pgp_write_one_pass_sig(output, seckey, hash_alg, sig_type);

		/* hash file contents */
		hash = pgp_sig_get_hash(sig);
		hash->add(hash, pgp_mem_data(infile), (unsigned)pgp_mem_len(infile));

#if 1
		/* output file contents as Literal Data packet */
		pgp_write_litdata(output, pgp_mem_data(infile),
			(const int)pgp_mem_len(infile),
			PGP_LDT_BINARY);
#else
		/* XXX - agc - sync with writer.c 1094 for ops_writez */
		pgp_setup_memory_write(&litoutput, &litmem, bufsz);
		pgp_setup_memory_write(&zoutput, &zmem, bufsz);
		pgp_write_litdata(litoutput,
			pgp_mem_data(pgp_mem_data(infile),
			(const int)pgp_mem_len(infile), PGP_LDT_BINARY);
		pgp_writez(zoutput, pgp_mem_data(litmem), pgp_mem_len(litmem));
#endif

		/* add creation time to signature */
		pgp_add_time(sig, (int64_t)from, "birth");
		pgp_add_time(sig, (int64_t)duration, "expiration");
		/* add key id to signature */
		pgp_keyid(keyid, PGP_KEY_ID_SIZE, &seckey->pubkey, hash_alg);
		pgp_add_issuer_keyid(sig, keyid);
		pgp_end_hashed_subpkts(sig);
		pgp_write_sig(output, sig, &seckey->pubkey, seckey);

		/* tidy up */
		pgp_teardown_file_write(output, fd_out);

		pgp_create_sig_delete(sig);
		pgp_memory_free(infile);

		ret = 1;
	}

	return ret;
}
예제 #7
0
파일: signature.c 프로젝트: Henauxg/minix
/**
\ingroup HighLevel_Sign
\brief Signs a buffer
\param input Input text to be signed
\param input_len Length of input text
\param sig_type Signature type
\param seckey Secret Key
\param armored Write armoured text, if set
\return New pgp_memory_t struct containing signed text
\note It is the caller's responsibility to call pgp_memory_free(me)

*/
pgp_memory_t *
pgp_sign_buf(pgp_io_t *io,
		const void *input,
		const size_t insize,
		const pgp_seckey_t *seckey,
		const int64_t from,
		const uint64_t duration,
		const char *hashname,
		const unsigned armored,
		const unsigned cleartext)
{
	pgp_litdata_enum	 ld_type;
	pgp_create_sig_t	*sig;
	pgp_sig_type_t	 sig_type;
	pgp_hash_alg_t	 hash_alg;
	pgp_output_t		*output;
	pgp_memory_t		*mem;
	uint8_t			 keyid[PGP_KEY_ID_SIZE];
	pgp_hash_t		*hash;
	unsigned		 ret;

	sig = NULL;
	sig_type = PGP_SIG_BINARY;
	output = NULL;
	mem = pgp_memory_new();
	hash = NULL;
	ret = 0;

	hash_alg = pgp_str_to_hash_alg(hashname);
	if (hash_alg == PGP_HASH_UNKNOWN) {
		(void) fprintf(io->errs,
			"pgp_sign_buf: unknown hash algorithm: \"%s\"\n",
			hashname);
		return NULL;
	}

	/* setup literal data packet type */
	ld_type = (cleartext) ? PGP_LDT_TEXT : PGP_LDT_BINARY;

	if (input == NULL) {
		(void) fprintf(io->errs,
			"pgp_sign_buf: null input\n");
		return NULL;
	}

	/* set up signature */
	if ((sig = pgp_create_sig_new()) == NULL) {
		return NULL;
	}
	pgp_start_sig(sig, seckey, hash_alg, sig_type);

	/* setup writer */
	pgp_setup_memory_write(&output, &mem, insize);

	if (cleartext) {
		/* Do the signing */
		/* add signature with subpackets: */
		/* - creation time */
		/* - key id */
		ret = pgp_writer_push_clearsigned(output, sig) &&
			pgp_write(output, input, (unsigned)insize) &&
			pgp_writer_use_armored_sig(output) &&
			pgp_add_time(sig, from, "birth") &&
			pgp_add_time(sig, (int64_t)duration, "expiration");
		if (ret == 0) {
			return NULL;
		}
		pgp_output_delete(output);
	} else {
		/* set armoured/not armoured here */
		if (armored) {
			pgp_writer_push_armor_msg(output);
		}
		if (pgp_get_debug_level(__FILE__)) {
			fprintf(io->errs, "** Writing out one pass sig\n");
		}
		/* write one_pass_sig */
		pgp_write_one_pass_sig(output, seckey, hash_alg, sig_type);

		/* hash memory */
		hash = pgp_sig_get_hash(sig);
		hash->add(hash, input, (unsigned)insize);

		/* output file contents as Literal Data packet */
		if (pgp_get_debug_level(__FILE__)) {
			(void) fprintf(stderr, "** Writing out data now\n");
		}
		pgp_write_litdata(output, input, (const int)insize, ld_type);
		if (pgp_get_debug_level(__FILE__)) {
			fprintf(stderr, "** After Writing out data now\n");
		}

		/* add creation time to signature */
		pgp_add_time(sig, from, "birth");
		pgp_add_time(sig, (int64_t)duration, "expiration");
		/* add key id to signature */
		pgp_keyid(keyid, PGP_KEY_ID_SIZE, &seckey->pubkey, hash_alg);
		pgp_add_issuer_keyid(sig, keyid);
		pgp_end_hashed_subpkts(sig);

		/* write out sig */
		pgp_write_sig(output, sig, &seckey->pubkey, seckey);

		/* tidy up */
		pgp_writer_close(output);
		pgp_create_sig_delete(sig);
	}
	return mem;
}
예제 #8
0
int dc_pgp_symm_encrypt(dc_context_t* context,
                        const char* passphrase,
                        const void* plain, size_t plain_bytes,
                        char** ret_ctext_armored)
{
	int                    success = 0;
	uint8_t                salt[PGP_SALT_SIZE];
	pgp_crypt_t            crypt_info;
	uint8_t*               key = NULL;

	pgp_output_t*          payload_output = NULL;
	pgp_memory_t*          payload_mem = NULL;

	pgp_output_t*          encr_output = NULL;
	pgp_memory_t*          encr_mem = NULL;

	if (context==NULL || passphrase==NULL || plain==NULL || plain_bytes==0
	 || ret_ctext_armored==NULL ) {
		goto cleanup;
	}

	//printf("\n~~~~~~~~~~~~~~~~~~~~SETUP-PAYLOAD~~~~~~~~~~~~~~~~~~~~\n%s~~~~~~~~~~~~~~~~~~~~/SETUP-PAYLOAD~~~~~~~~~~~~~~~~~~~~\n",key_asc); // DEBUG OUTPUT

	/* put the payload into a literal data packet which will be encrypted then, see RFC 4880, 5.7 :
	"When it has been decrypted, it contains other packets (usually a literal data packet or compressed data
	packet, but in theory other Symmetrically Encrypted Data packets or sequences of packets that form whole OpenPGP messages)" */

	pgp_setup_memory_write(&payload_output, &payload_mem, 128);
	pgp_write_litdata(payload_output, (const uint8_t*)plain, plain_bytes, PGP_LDT_BINARY);

	/* create salt for the key */
	pgp_random(salt, PGP_SALT_SIZE);

	/* S2K */
	#define SYMM_ALGO PGP_SA_AES_128
	if (!pgp_crypt_any(&crypt_info, SYMM_ALGO)) {
		goto cleanup;
	}

	int s2k_spec = PGP_S2KS_ITERATED_AND_SALTED; // 0=simple, 1=salted, 3=salted+iterated
	int s2k_iter_id = 96; // 0=1024 iterations, 96=65536 iterations
	#define HASH_ALG  PGP_HASH_SHA256
	if ((key = pgp_s2k_do(passphrase, crypt_info.keysize, s2k_spec, HASH_ALG, salt, s2k_iter_id))==NULL) {
		goto cleanup;
	}

	/* encrypt the payload using the key using AES-128 and put it into
	OpenPGP's "Symmetric-Key Encrypted Session Key" (Tag 3, https://tools.ietf.org/html/rfc4880#section-5.3) followed by
	OpenPGP's "Symmetrically Encrypted Data Packet" (Tag 18, https://tools.ietf.org/html/rfc4880#section-5.13 , better than Tag 9) */

	pgp_setup_memory_write(&encr_output, &encr_mem, 128);
	pgp_writer_push_armor_msg(encr_output);

	/* Tag 3 - PGP_PTAG_CT_SK_SESSION_KEY */
	pgp_write_ptag     (encr_output, PGP_PTAG_CT_SK_SESSION_KEY);
	pgp_write_length   (encr_output, 1/*version*/
	                               + 1/*symm. algo*/
	                               + 1/*s2k_spec*/
	                               + 1/*S2 hash algo*/
	                               + ((s2k_spec==PGP_S2KS_SALTED || s2k_spec==PGP_S2KS_ITERATED_AND_SALTED)? PGP_SALT_SIZE : 0)/*the salt*/
	                               + ((s2k_spec==PGP_S2KS_ITERATED_AND_SALTED)? 1 : 0)/*number of iterations*/);

	pgp_write_scalar   (encr_output, 4, 1);                  // 1 octet: version
	pgp_write_scalar   (encr_output, SYMM_ALGO, 1);          // 1 octet: symm. algo

	pgp_write_scalar   (encr_output, s2k_spec, 1);           // 1 octet: s2k_spec
	pgp_write_scalar   (encr_output, HASH_ALG, 1);           // 1 octet: S2 hash algo
	if (s2k_spec==PGP_S2KS_SALTED || s2k_spec==PGP_S2KS_ITERATED_AND_SALTED) {
	  pgp_write        (encr_output, salt, PGP_SALT_SIZE);   // 8 octets: the salt
	}
	if (s2k_spec==PGP_S2KS_ITERATED_AND_SALTED) {
	  pgp_write_scalar (encr_output, s2k_iter_id, 1);        // 1 octet: number of iterations
	}

	// for(int j=0; j<AES_KEY_LENGTH; j++) { printf("%02x", key[j]); } printf("\n----------------\n");

	/* Tag 18 - PGP_PTAG_CT_SE_IP_DATA */
	//pgp_write_symm_enc_data((const uint8_t*)payload_mem->buf, payload_mem->length, PGP_SA_AES_128, key, encr_output); //-- would generate Tag 9
	{
		uint8_t* iv = calloc(1, crypt_info.blocksize); if (iv==NULL) { goto cleanup; }
		crypt_info.set_iv(&crypt_info, iv);
		free(iv);

		crypt_info.set_crypt_key(&crypt_info, &key[0]);
		pgp_encrypt_init(&crypt_info);

		pgp_write_se_ip_pktset(encr_output, payload_mem->buf, payload_mem->length, &crypt_info);

		crypt_info.decrypt_finish(&crypt_info);
	}

	/* done with symmetric key block */
	pgp_writer_close(encr_output);
	*ret_ctext_armored = dc_null_terminate((const char*)encr_mem->buf, encr_mem->length);

	//printf("\n~~~~~~~~~~~~~~~~~~~~SYMMETRICALLY ENCRYPTED~~~~~~~~~~~~~~~~~~~~\n%s~~~~~~~~~~~~~~~~~~~~/SYMMETRICALLY ENCRYPTED~~~~~~~~~~~~~~~~~~~~\n",encr_string); // DEBUG OUTPUT

	success = 1;

cleanup:
	if (payload_output) { pgp_output_delete(payload_output); }
	if (payload_mem) { pgp_memory_free(payload_mem); }
	if (encr_output) { pgp_output_delete(encr_output); }
	if (encr_mem) { pgp_memory_free(encr_mem); }
	free(key);
	return success;
}
예제 #9
0
파일: crypto.c 프로젝트: Henauxg/minix
/* decrypt an area of memory */
pgp_memory_t *
pgp_decrypt_buf(pgp_io_t *io,
			const void *input,
			const size_t insize,
			pgp_keyring_t *secring,
			pgp_keyring_t *pubring,
			const unsigned use_armour,
			const unsigned sshkeys,
			void *passfp,
			int numtries,
			pgp_cbfunc_t *getpassfunc)
{
	pgp_stream_t	*parse = NULL;
	pgp_memory_t	*outmem;
	pgp_memory_t	*inmem;
	const int	 printerrors = 1;

	if (input == NULL) {
		(void) fprintf(io->errs,
			"pgp_encrypt_buf: null memory\n");
		return 0;
	}

	inmem = pgp_memory_new();
	pgp_memory_add(inmem, input, insize);

	/* set up to read from memory */
	pgp_setup_memory_read(io, &parse, inmem,
				    NULL,
				    write_parsed_cb,
				    0);

	/* setup for writing decrypted contents to given output file */
	pgp_setup_memory_write(&parse->cbinfo.output, &outmem, insize);

	/* setup keyring and passphrase callback */
	parse->cbinfo.cryptinfo.secring = secring;
	parse->cbinfo.cryptinfo.pubring = pubring;
	parse->cbinfo.passfp = passfp;
	parse->cbinfo.cryptinfo.getpassphrase = getpassfunc;
	parse->cbinfo.sshseckey = (sshkeys) ? &secring->keys[0].key.seckey : NULL;
	parse->cbinfo.numtries = numtries;

	/* Set up armour/passphrase options */
	if (use_armour) {
		pgp_reader_push_dearmour(parse);
	}

	/* Do it */
	pgp_parse(parse, printerrors);

	/* Unsetup */
	if (use_armour) {
		pgp_reader_pop_dearmour(parse);
	}

	/* tidy up */
	pgp_teardown_memory_read(parse, inmem);

	pgp_writer_close(parse->cbinfo.output);
	pgp_output_delete(parse->cbinfo.output);

	/* if we didn't get the passphrase, return NULL */
	return (parse->cbinfo.gotpass) ? outmem : NULL;
}
예제 #10
0
/**
 \ingroup HighLevel_KeyGenerate
 \brief Generates an RSA keypair
 \param numbits Modulus size
 \param e Public Exponent
 \param keydata Pointer to keydata struct to hold new key
 \return 1 if key generated successfully; otherwise 0
 \note It is the caller's responsibility to call pgp_keydata_free(keydata)
*/
static unsigned 
rsa_generate_keypair(pgp_key_t *keydata,
			const int numbits,
			const unsigned long e,
			const char *hashalg,
			const char *cipher)
{
	pgp_seckey_t *seckey;
	RSA            *rsa;
	BN_CTX         *ctx;
	pgp_output_t *output;
	pgp_memory_t   *mem;

	ctx = BN_CTX_new();
	pgp_keydata_init(keydata, PGP_PTAG_CT_SECRET_KEY);
	seckey = pgp_get_writable_seckey(keydata);

	/* generate the key pair */

	rsa = RSA_generate_key(numbits, e, NULL, NULL);

	/* populate pgp key from ssl key */

	seckey->pubkey.version = PGP_V4;
	seckey->pubkey.birthtime = time(NULL);
	seckey->pubkey.days_valid = 0;
	seckey->pubkey.alg = PGP_PKA_RSA;

	seckey->pubkey.key.rsa.n = BN_dup(rsa->n);
	seckey->pubkey.key.rsa.e = BN_dup(rsa->e);

	seckey->s2k_usage = PGP_S2KU_ENCRYPTED_AND_HASHED;
	seckey->s2k_specifier = PGP_S2KS_SALTED;
	/* seckey->s2k_specifier=PGP_S2KS_SIMPLE; */
	if ((seckey->hash_alg = pgp_str_to_hash_alg(hashalg)) == PGP_HASH_UNKNOWN) {
		seckey->hash_alg = PGP_HASH_SHA1;
	}
	seckey->alg = pgp_str_to_cipher(cipher);
	seckey->octetc = 0;
	seckey->checksum = 0;

	seckey->key.rsa.d = BN_dup(rsa->d);
	seckey->key.rsa.p = BN_dup(rsa->p);
	seckey->key.rsa.q = BN_dup(rsa->q);
	seckey->key.rsa.u = BN_mod_inverse(NULL, rsa->p, rsa->q, ctx);
	if (seckey->key.rsa.u == NULL) {
		(void) fprintf(stderr, "seckey->key.rsa.u is NULL\n");
		return 0;
	}
	BN_CTX_free(ctx);

	RSA_free(rsa);

	pgp_keyid(keydata->sigid, PGP_KEY_ID_SIZE, &keydata->key.seckey.pubkey, seckey->hash_alg);
	pgp_fingerprint(&keydata->sigfingerprint, &keydata->key.seckey.pubkey, seckey->hash_alg);

	/* Generate checksum */

	output = NULL;
	mem = NULL;

	pgp_setup_memory_write(&output, &mem, 128);

	pgp_push_checksum_writer(output, seckey);

	switch (seckey->pubkey.alg) {
	case PGP_PKA_DSA:
		return pgp_write_mpi(output, seckey->key.dsa.x);
	case PGP_PKA_RSA:
	case PGP_PKA_RSA_ENCRYPT_ONLY:
	case PGP_PKA_RSA_SIGN_ONLY:
		if (!pgp_write_mpi(output, seckey->key.rsa.d) ||
		    !pgp_write_mpi(output, seckey->key.rsa.p) ||
		    !pgp_write_mpi(output, seckey->key.rsa.q) ||
		    !pgp_write_mpi(output, seckey->key.rsa.u)) {
			return 0;
		}
		break;
	case PGP_PKA_ELGAMAL:
		return pgp_write_mpi(output, seckey->key.elgamal.x);

	default:
		(void) fprintf(stderr, "Bad seckey->pubkey.alg\n");
		return 0;
	}

	/* close rather than pop, since its the only one on the stack */
	pgp_writer_close(output);
	pgp_teardown_memory_write(output, mem);

	/* should now have checksum in seckey struct */

	/* test */
	if (pgp_get_debug_level(__FILE__)) {
		test_seckey(seckey);
	}

	return 1;
}