Beispiel #1
0
int dc_pgp_is_valid_key(dc_context_t* context, const dc_key_t* raw_key)
{
	int             key_is_valid = 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 (context==NULL || raw_key==NULL
	 || 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); /* function returns 0 on any error in any packet - this does not mean, we cannot use the key. We check the details below therefore. */

	if (raw_key->type==DC_KEY_PUBLIC && public_keys->keyc >= 1) {
		key_is_valid = 1;
	}
	else if (raw_key->type==DC_KEY_PRIVATE && private_keys->keyc >= 1) {
		key_is_valid = 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 key_is_valid;
}
Beispiel #2
0
int dc_pgp_split_key(dc_context_t* context, const dc_key_t* private_in, dc_key_t* ret_public_key)
{
	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();
	pgp_memory_t*   pubmem = pgp_memory_new();
	pgp_output_t*   pubout = pgp_output_new();

	if (context==NULL || private_in==NULL || ret_public_key==NULL
	 || public_keys==NULL || private_keys==NULL || keysmem==NULL || pubmem==NULL || pubout==NULL) {
		goto cleanup;
	}

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

	if (private_in->type!=DC_KEY_PRIVATE || private_keys->keyc <= 0) {
		dc_log_warning(context, 0, "Split key: Given key is no private key.");
		goto cleanup;
	}

	if (public_keys->keyc <= 0) {
		dc_log_warning(context, 0, "Split key: Given key does not contain a public key.");
		goto cleanup;
	}

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

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

	success = 1;

cleanup:
	if (pubout)       { pgp_output_delete(pubout); }
	if (pubmem)       { pgp_memory_free(pubmem); }
	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 #3
0
static void 
hash_add_key(pgp_hash_t *hash, const pgp_pubkey_t *key)
{
	pgp_memory_t	*mem = pgp_memory_new();
	const unsigned 	 dontmakepacket = 0;
	size_t		 len;

	pgp_build_pubkey(mem, key, dontmakepacket);
	len = pgp_mem_len(mem);
	pgp_hash_add_int(hash, 0x99, 1);
	pgp_hash_add_int(hash, (unsigned)len, 2);
	hash->add(hash, pgp_mem_data(mem), (unsigned)len);
	pgp_memory_free(mem);
}
Beispiel #4
0
/**
\ingroup HighLevel_Crypto
Encrypt a file
\param infile Name of file to be encrypted
\param outfile Name of file to write to. If NULL, name is constructed from infile
\param pubkey Public Key to encrypt file for
\param use_armour Write armoured text, if set
\param allow_overwrite Allow output file to be overwrwritten if it exists
\return 1 if OK; else 0
*/
unsigned 
pgp_encrypt_file(pgp_io_t *io,
			const char *infile,
			const char *outfile,
			const pgp_key_t *key,
			const unsigned use_armour,
			const unsigned allow_overwrite,
			const char *cipher)
{
	pgp_output_t	*output;
	pgp_memory_t	*inmem;
	int		 fd_out;

	__PGP_USED(io);
	inmem = pgp_memory_new();
	if (!pgp_mem_readfile(inmem, infile)) {
		return 0;
	}
	fd_out = pgp_setup_file_write(&output, outfile, allow_overwrite);
	if (fd_out < 0) {
		pgp_memory_free(inmem);
		return 0;
	}

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

	/* Push the encrypted writer */
	if (!pgp_push_enc_se_ip(output, key, cipher)) {
		pgp_memory_free(inmem);
		return 0;
	}

	/* This does the writing */
	pgp_write(output, pgp_mem_data(inmem), (unsigned)pgp_mem_len(inmem));

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

	return 1;
}
Beispiel #5
0
static void 
start_sig_in_mem(pgp_create_sig_t *sig)
{
	/* since this has subpackets and stuff, we have to buffer the whole */
	/* thing to get counts before writing. */
	sig->mem = pgp_memory_new();
	pgp_memory_init(sig->mem, 100);
	pgp_writer_set_memory(sig->output, sig->mem);

	/* write nearly up to the first subpacket */
	pgp_write_scalar(sig->output, (unsigned)sig->sig.info.version, 1);
	pgp_write_scalar(sig->output, (unsigned)sig->sig.info.type, 1);
	pgp_write_scalar(sig->output, (unsigned)sig->sig.info.key_alg, 1);
	pgp_write_scalar(sig->output, (unsigned)sig->sig.info.hash_alg, 1);

	/* dummy hashed subpacket count */
	sig->hashoff = (unsigned)pgp_mem_len(sig->mem);
	pgp_write_scalar(sig->output, 0, 2);
}
Beispiel #6
0
unsigned 
pgp_fileread_litdata(const char *filename,
				 const pgp_litdata_enum type,
				 pgp_output_t *output)
{
	pgp_memory_t	*mem;
	unsigned   	 ret;
	int		 len;

	mem = pgp_memory_new();
	if (!pgp_mem_readfile(mem, filename)) {
		(void) fprintf(stderr, "pgp_mem_readfile of '%s' failed\n", filename);
		return 0;
	}
	len = (int)pgp_mem_len(mem);
	ret = pgp_write_litdata(output, pgp_mem_data(mem), len, type);
	pgp_memory_free(mem);
	return ret;
}
Beispiel #7
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 #8
0
/**
\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;
}
Beispiel #9
0
/* sign a file, and put the signature in a separate file */
int
pgp_sign_detached(pgp_io_t *io,
			const char *f,
			char *sigfile,
			pgp_seckey_t *seckey,
			const char *hash,
			const int64_t from,
			const uint64_t duration,
			const unsigned armored, const unsigned overwrite)
{
	pgp_create_sig_t	*sig;
	pgp_hash_alg_t	 hash_alg;
	pgp_output_t		*output;
	pgp_memory_t		*mem;
	uint8_t	 	 	 keyid[PGP_KEY_ID_SIZE];
	int			 fd;

	/* find out which hash algorithm to use */
	hash_alg = pgp_str_to_hash_alg(hash);
	if (hash_alg == PGP_HASH_UNKNOWN) {
		(void) fprintf(io->errs,"Unknown hash algorithm: %s\n", hash);
		return 0;
	}

	/* setup output file */
	fd = open_output_file(&output, f, sigfile,
				(armored) ? "asc" : "sig", overwrite);
	if (fd < 0) {
		(void) fprintf(io->errs,"Can't open output file: %s\n", f);
		return 0;
	}

	/* create a new signature */
	sig = pgp_create_sig_new();
	pgp_start_sig(sig, seckey, hash_alg, PGP_SIG_BINARY);

	/* read the contents of 'f', and add that to the signature */
	mem = pgp_memory_new();
	if (!pgp_mem_readfile(mem, f)) {
		pgp_teardown_file_write(output, fd);
		return 0;
	}
	/* set armoured/not armoured here */
	if (armored) {
		pgp_writer_push_armor_msg(output);
	}
	pgp_sig_add_data(sig, pgp_mem_data(mem), pgp_mem_len(mem));
	pgp_memory_free(mem);

	/* calculate the signature */
	pgp_add_time(sig, from, "birth");
	pgp_add_time(sig, (int64_t)duration, "expiration");
	pgp_keyid(keyid, sizeof(keyid), &seckey->pubkey, hash_alg);
	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);
	pgp_seckey_free(seckey);

	return 1;
}
Beispiel #10
0
/**
\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;
}
Beispiel #11
0
int dc_pgp_pk_encrypt( dc_context_t*       context,
                       const void*         plain_text,
                       size_t              plain_bytes,
                       const dc_keyring_t* raw_public_keys_for_encryption,
                       const dc_key_t*     raw_private_key_for_signing,
                       int                 use_armor,
                       void**              ret_ctext,
                       size_t*             ret_ctext_bytes)
{
	pgp_keyring_t*  public_keys = calloc(1, sizeof(pgp_keyring_t));
	pgp_keyring_t*  private_keys = calloc(1, sizeof(pgp_keyring_t));
	pgp_keyring_t*  dummy_keys = calloc(1, sizeof(pgp_keyring_t));
	pgp_memory_t*   keysmem = pgp_memory_new();
	pgp_memory_t*   signedmem = NULL;
	int             i = 0;
	int             success = 0;

	if (context==NULL || plain_text==NULL || plain_bytes==0 || ret_ctext==NULL || ret_ctext_bytes==NULL
	 || raw_public_keys_for_encryption==NULL || raw_public_keys_for_encryption->count<=0
	 || keysmem==NULL || public_keys==NULL || private_keys==NULL || dummy_keys==NULL) {
		goto cleanup;
	}

	*ret_ctext       = NULL;
	*ret_ctext_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_public_keys_for_encryption->count; i++) {
		pgp_memory_clear(keysmem);
		pgp_memory_add(keysmem, raw_public_keys_for_encryption->keys[i]->binary, raw_public_keys_for_encryption->keys[i]->bytes);
		pgp_filter_keys_from_mem(&s_io, public_keys, private_keys/*should stay empty*/, NULL, 0, keysmem);
	}

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

	/* encrypt */
	{
		const void* signed_text = NULL;
		size_t      signed_bytes = 0;
		int         encrypt_raw_packet = 0;
		clock_t     sign_clocks = 0;
		clock_t     encrypt_clocks = 0;

		if (raw_private_key_for_signing) {
			pgp_memory_clear(keysmem);
			pgp_memory_add(keysmem, raw_private_key_for_signing->binary, raw_private_key_for_signing->bytes);
			pgp_filter_keys_from_mem(&s_io, dummy_keys, private_keys, NULL, 0, keysmem);
			if (private_keys->keyc <= 0) {
				dc_log_warning(context, 0, "No key for signing found.");
				goto cleanup;
			}

			clock_t start = clock();

			pgp_key_t* sk0 = &private_keys->keys[0];
			signedmem = pgp_sign_buf(&s_io, plain_text, plain_bytes, &sk0->key.seckey, time(NULL)/*birthtime*/, 0/*duration*/,
				NULL/*hash, defaults to sha256*/, 0/*armored*/, 0/*cleartext*/);

			sign_clocks = clock()-start;

			if (signedmem==NULL) {
				dc_log_warning(context, 0, "Signing failed.");
				goto cleanup;
			}
			signed_text        = signedmem->buf;
			signed_bytes       = signedmem->length;
			encrypt_raw_packet = 1;
		}
		else {
			signed_text        = plain_text;
			signed_bytes       = plain_bytes;
			encrypt_raw_packet = 0;
		}

		clock_t start = clock();

		pgp_memory_t* outmem = pgp_encrypt_buf(&s_io, signed_text, signed_bytes, public_keys, use_armor, NULL/*cipher*/, encrypt_raw_packet);

		encrypt_clocks = clock()-start;

		dc_log_info(context, 0, "Message signed in %.3f ms and encrypted in %.3f ms.", (double)(sign_clocks)*1000.0/CLOCKS_PER_SEC, (double)(encrypt_clocks)*1000.0/CLOCKS_PER_SEC);

		if (outmem==NULL) {
			dc_log_warning(context, 0, "Encryption failed.");
			goto cleanup;
		}
		*ret_ctext       = outmem->buf;
		*ret_ctext_bytes = outmem->length;
		free(outmem); /* do not use pgp_memory_free() as we took ownership of the buffer */
	}

	success = 1;

cleanup:
	if (keysmem)      { pgp_memory_free(keysmem); }
	if (signedmem)    { pgp_memory_free(signedmem); }
	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); }
	return success;
}
Beispiel #12
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 #13
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 #14
0
/* 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;
}