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; }
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; }
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; }
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; }
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; }
/* 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; }