Beispiel #1
0
/* add a key to a secret keyring */
int
pgp_add_to_secring(pgp_keyring_t *keyring, const pgp_seckey_t *seckey)
{
	const pgp_pubkey_t	*pubkey;
	pgp_key_t		*key;

	if (pgp_get_debug_level(__FILE__)) {
		fprintf(stderr, "pgp_add_to_secring\n");
	}
	if (keyring->keyc > 0) {
		key = &keyring->keys[keyring->keyc - 1];
		if (pgp_get_debug_level(__FILE__) &&
		    key->key.pubkey.alg == PGP_PKA_DSA &&
		    seckey->pubkey.alg == PGP_PKA_ELGAMAL) {
			fprintf(stderr, "pgp_add_to_secring: found elgamal seckey\n");
		}
	}
	EXPAND_ARRAY(keyring, key);
	key = &keyring->keys[keyring->keyc++];
	(void) memset(key, 0x0, sizeof(*key));
	pubkey = &seckey->pubkey;
	pgp_keyid(key->sigid, PGP_KEY_ID_SIZE, pubkey, keyring->hashtype);
	pgp_fingerprint(&key->sigfingerprint, pubkey, keyring->hashtype);
	key->type = PGP_PTAG_CT_SECRET_KEY;
	key->key.seckey = *seckey;
	if (pgp_get_debug_level(__FILE__)) {
		fprintf(stderr, "pgp_add_to_secring: keyc %u\n", keyring->keyc);
	}
	return 1;
}
Beispiel #2
0
/* add a key to a public keyring */
int
pgp_add_to_pubring(pgp_keyring_t *keyring, const pgp_pubkey_t *pubkey, pgp_content_enum tag)
{
	pgp_key_t	*key;
	time_t		 duration;

	if (pgp_get_debug_level(__FILE__)) {
		fprintf(stderr, "pgp_add_to_pubring (type %u)\n", tag);
	}
	switch(tag) {
	case PGP_PTAG_CT_PUBLIC_KEY:
		EXPAND_ARRAY(keyring, key);
		key = &keyring->keys[keyring->keyc++];
		duration = key->key.pubkey.duration;
		(void) memset(key, 0x0, sizeof(*key));
		key->type = tag;
		pgp_keyid(key->sigid, PGP_KEY_ID_SIZE, pubkey, keyring->hashtype);
		pgp_fingerprint(&key->sigfingerprint, pubkey, keyring->hashtype);
		key->key.pubkey = *pubkey;
		key->key.pubkey.duration = duration;
		return 1;
	case PGP_PTAG_CT_PUBLIC_SUBKEY:
		/* subkey is not the first */
		key = &keyring->keys[keyring->keyc - 1];
		pgp_keyid(key->encid, PGP_KEY_ID_SIZE, pubkey, keyring->hashtype);
		duration = key->key.pubkey.duration;
		(void) memcpy(&key->enckey, pubkey, sizeof(key->enckey));
		key->enckey.duration = duration;
		return 1;
	default:
		return 0;
	}
}
Beispiel #3
0
int dc_pgp_calc_fingerprint(const dc_key_t* raw_key, uint8_t** ret_fingerprint, size_t* ret_fingerprint_bytes)
{
	int             success = 0;
	pgp_keyring_t*  public_keys = calloc(1, sizeof(pgp_keyring_t));
	pgp_keyring_t*  private_keys = calloc(1, sizeof(pgp_keyring_t));
	pgp_memory_t*   keysmem = pgp_memory_new();

	if (raw_key==NULL || ret_fingerprint==NULL || *ret_fingerprint!=NULL || ret_fingerprint_bytes==NULL || *ret_fingerprint_bytes!=0
	 || raw_key->binary==NULL || raw_key->bytes <= 0
	 || public_keys==NULL || private_keys==NULL || keysmem==NULL) {
		goto cleanup;
	}

	pgp_memory_add(keysmem, raw_key->binary, raw_key->bytes);
	pgp_filter_keys_from_mem(&s_io, public_keys, private_keys, NULL, 0, keysmem);

	if (raw_key->type != DC_KEY_PUBLIC || public_keys->keyc <= 0) {
		goto cleanup;
	}

	pgp_key_t* key0 = &public_keys->keys[0];
	pgp_pubkey_t* pubkey0 = &key0->key.pubkey;
	if (!pgp_fingerprint(&key0->pubkeyfpr, pubkey0, 0)) {
		goto cleanup;
	}

	*ret_fingerprint_bytes = key0->pubkeyfpr.length;
    *ret_fingerprint = malloc(*ret_fingerprint_bytes);
	memcpy(*ret_fingerprint, key0->pubkeyfpr.fingerprint, *ret_fingerprint_bytes);

	success = 1;

cleanup:
	if (keysmem)      { pgp_memory_free(keysmem); }
	if (public_keys)  { pgp_keyring_purge(public_keys); free(public_keys); } /*pgp_keyring_free() frees the content, not the pointer itself*/
	if (private_keys) { pgp_keyring_purge(private_keys); free(private_keys); }
	return success;
}
Beispiel #4
0
int dc_pgp_create_keypair(dc_context_t* context, const char* addr, dc_key_t* ret_public_key, dc_key_t* ret_private_key)
{
	int              success = 0;
	pgp_key_t        seckey;
	pgp_key_t        pubkey;
	pgp_key_t        subkey;
	uint8_t          subkeyid[PGP_KEY_ID_SIZE];
	uint8_t*         user_id = NULL;
	pgp_memory_t*    pubmem = pgp_memory_new();
	pgp_memory_t*    secmem = pgp_memory_new();
	pgp_output_t*    pubout = pgp_output_new();
	pgp_output_t*    secout = pgp_output_new();

	memset(&seckey, 0, sizeof(pgp_key_t));
	memset(&pubkey, 0, sizeof(pgp_key_t));
	memset(&subkey, 0, sizeof(pgp_key_t));

	if (context==NULL || addr==NULL || ret_public_key==NULL || ret_private_key==NULL
	 || pubmem==NULL || secmem==NULL || pubout==NULL || secout==NULL) {
		goto cleanup;
	}

	/* Generate User ID.
	By convention, this is the e-mail-address in angle brackets.

	As the user-id is only decorative in Autocrypt and not needed for Delta Chat,
	so we _could_ just use sth. that looks like an e-mail-address.
	This would protect the user's privacy if someone else uploads the keys to keyservers.

	However, as eg. Enigmail displayes the user-id in "Good signature from <user-id>,
	for now, we decided to leave the address in the user-id */
	#if 0
		user_id = (uint8_t*)dc_mprintf("<%08X@%08X.org>", (int)random(), (int)random());
	#else
		user_id = (uint8_t*)dc_mprintf("<%s>", addr);
	#endif


	/* generate two keypairs */
	if (!pgp_rsa_generate_keypair(&seckey, DC_KEYGEN_BITS, DC_KEYGEN_E, NULL, NULL, NULL, 0)
	 || !pgp_rsa_generate_keypair(&subkey, DC_KEYGEN_BITS, DC_KEYGEN_E, NULL, NULL, NULL, 0)) {
		goto cleanup;
	}


	/* Create public key, bind public subkey to public key
	------------------------------------------------------------------------ */

	pubkey.type = PGP_PTAG_CT_PUBLIC_KEY;
	pgp_pubkey_dup(&pubkey.key.pubkey, &seckey.key.pubkey);
	memcpy(pubkey.pubkeyid, seckey.pubkeyid, PGP_KEY_ID_SIZE);
	pgp_fingerprint(&pubkey.pubkeyfpr, &seckey.key.pubkey, 0);
	add_selfsigned_userid(&seckey, &pubkey, (const uint8_t*)user_id, 0/*never expire*/);

	EXPAND_ARRAY((&pubkey), subkey);
	{
		pgp_subkey_t* p = &pubkey.subkeys[pubkey.subkeyc++];
		pgp_pubkey_dup(&p->key.pubkey, &subkey.key.pubkey);
		pgp_keyid(subkeyid, PGP_KEY_ID_SIZE, &pubkey.key.pubkey, PGP_HASH_SHA1);
		memcpy(p->id, subkeyid, PGP_KEY_ID_SIZE);
	}

	EXPAND_ARRAY((&pubkey), subkeysig);
	add_subkey_binding_signature(&pubkey.subkeysigs[pubkey.subkeysigc++], &pubkey, &subkey, &seckey);


	/* Create secret key, bind secret subkey to secret key
	------------------------------------------------------------------------ */

	EXPAND_ARRAY((&seckey), subkey);
	{
		pgp_subkey_t* p = &seckey.subkeys[seckey.subkeyc++];
		pgp_seckey_dup(&p->key.seckey, &subkey.key.seckey);
		pgp_keyid(subkeyid, PGP_KEY_ID_SIZE, &seckey.key.pubkey, PGP_HASH_SHA1);
		memcpy(p->id, subkeyid, PGP_KEY_ID_SIZE);
	}

	EXPAND_ARRAY((&seckey), subkeysig);
	add_subkey_binding_signature(&seckey.subkeysigs[seckey.subkeysigc++], &seckey, &subkey, &seckey);


	/* Done with key generation, write binary keys to memory
	------------------------------------------------------------------------ */

	pgp_writer_set_memory(pubout, pubmem);
	if (!pgp_write_xfer_key(pubout, &pubkey, 0/*armored*/)
	 || pubmem->buf==NULL || pubmem->length <= 0) {
		goto cleanup;
	}

	pgp_writer_set_memory(secout, secmem);
	if (!pgp_write_xfer_key(secout, &seckey, 0/*armored*/)
	 || secmem->buf==NULL || secmem->length <= 0) {
		goto cleanup;
	}

	dc_key_set_from_binary(ret_public_key, pubmem->buf, pubmem->length, DC_KEY_PUBLIC);
	dc_key_set_from_binary(ret_private_key, secmem->buf, secmem->length, DC_KEY_PRIVATE);

	success = 1;

cleanup:
	if (pubout) { pgp_output_delete(pubout); }
	if (secout) { pgp_output_delete(secout); }
	if (pubmem) { pgp_memory_free(pubmem); }
	if (secmem) { pgp_memory_free(secmem); }
	pgp_key_free(&seckey); /* not: pgp_keydata_free() which will also free the pointer itself (we created it on the stack) */
	pgp_key_free(&pubkey);
	pgp_key_free(&subkey);
	free(user_id);
	return success;
}
Beispiel #5
0
int dc_pgp_pk_decrypt( dc_context_t*       context,
                       const void*         ctext,
                       size_t              ctext_bytes,
                       const dc_keyring_t* raw_private_keys_for_decryption,
                       const dc_keyring_t* raw_public_keys_for_validation,
                       int                 use_armor,
                       void**              ret_plain,
                       size_t*             ret_plain_bytes,
                       dc_hash_t*          ret_signature_fingerprints)
{
	pgp_keyring_t*    public_keys = calloc(1, sizeof(pgp_keyring_t)); /*should be 0 after parsing*/
	pgp_keyring_t*    private_keys = calloc(1, sizeof(pgp_keyring_t));
	pgp_keyring_t*    dummy_keys = calloc(1, sizeof(pgp_keyring_t));
	pgp_validation_t* vresult = calloc(1, sizeof(pgp_validation_t));
	key_id_t*         recipients_key_ids = NULL;
	unsigned          recipients_cnt = 0;
	pgp_memory_t*     keysmem = pgp_memory_new();
	int               i = 0;
	int               success = 0;

	if (context==NULL || ctext==NULL || ctext_bytes==0 || ret_plain==NULL || ret_plain_bytes==NULL
	 || raw_private_keys_for_decryption==NULL || raw_private_keys_for_decryption->count<=0
	 || vresult==NULL || keysmem==NULL || public_keys==NULL || private_keys==NULL) {
		goto cleanup;
	}

	*ret_plain             = NULL;
	*ret_plain_bytes       = 0;

	/* setup keys (the keys may come from pgp_filter_keys_fileread(), see also pgp_keyring_add(rcpts, key)) */
	for (i = 0; i < raw_private_keys_for_decryption->count; i++) {
		pgp_memory_clear(keysmem); /* a simple concatenate of private binary keys fails (works for public keys, however, we don't do it there either) */
		pgp_memory_add(keysmem, raw_private_keys_for_decryption->keys[i]->binary, raw_private_keys_for_decryption->keys[i]->bytes);
		pgp_filter_keys_from_mem(&s_io, dummy_keys/*should stay empty*/, private_keys, NULL, 0, keysmem);
	}

	if (private_keys->keyc<=0) {
		dc_log_warning(context, 0, "Decryption-keyring contains unexpected data (%i/%i)", public_keys->keyc, private_keys->keyc);
		goto cleanup;
	}

	if (raw_public_keys_for_validation) {
		for (i = 0; i < raw_public_keys_for_validation->count; i++) {
			pgp_memory_clear(keysmem);
			pgp_memory_add(keysmem, raw_public_keys_for_validation->keys[i]->binary, raw_public_keys_for_validation->keys[i]->bytes);
			pgp_filter_keys_from_mem(&s_io, public_keys, dummy_keys/*should stay empty*/, NULL, 0, keysmem);
		}
	}

	/* decrypt */
	{
		pgp_memory_t* outmem = pgp_decrypt_and_validate_buf(&s_io, vresult, ctext, ctext_bytes, private_keys, public_keys,
			use_armor, &recipients_key_ids, &recipients_cnt);
		if (outmem==NULL) {
			dc_log_warning(context, 0, "Decryption failed.");
			goto cleanup;
		}
		*ret_plain       = outmem->buf;
		*ret_plain_bytes = outmem->length;
		free(outmem); /* do not use pgp_memory_free() as we took ownership of the buffer */

		// collect the keys of the valid signatures
		if (ret_signature_fingerprints)
		{
			for (i = 0; i < vresult->validc; i++)
			{
				unsigned from = 0;
				pgp_key_t* key0 = pgp_getkeybyid(&s_io, public_keys, vresult->valid_sigs[i].signer_id, &from, NULL, NULL, 0, 0);
				if (key0) {
					pgp_pubkey_t* pubkey0 = &key0->key.pubkey;
					if (!pgp_fingerprint(&key0->pubkeyfpr, pubkey0, 0)) {
						goto cleanup;
					}

					char* fingerprint_hex = dc_binary_to_uc_hex(key0->pubkeyfpr.fingerprint, key0->pubkeyfpr.length);
					if (fingerprint_hex) {
						dc_hash_insert(ret_signature_fingerprints, fingerprint_hex, strlen(fingerprint_hex), (void*)1);
					}
					free(fingerprint_hex);
				}
			}
		}
	}

	success = 1;

cleanup:
	if (keysmem)            { pgp_memory_free(keysmem); }
	if (public_keys)        { pgp_keyring_purge(public_keys); free(public_keys); } /*pgp_keyring_free() frees the content, not the pointer itself*/
	if (private_keys)       { pgp_keyring_purge(private_keys); free(private_keys); }
	if (dummy_keys)         { pgp_keyring_purge(dummy_keys); free(dummy_keys); }
	if (vresult)            { pgp_validate_result_free(vresult); }
	free(recipients_key_ids);
	return success;
}
Beispiel #6
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;
}