static void test_load_v1_key(void) { test_begin("test_load_v1_key"); buffer_t *key_1 = buffer_create_dynamic(pool_datastack_create(), 128); struct dcrypt_private_key *pkey = NULL, *pkey2 = NULL; const char *error = NULL; test_assert(dcrypt_key_load_private(&pkey, DCRYPT_FORMAT_DOVECOT, "1\t716\t0\t048FD04FD3612B22D32790C592CF21CEF417EFD2EA34AE5F688FA5B51BED29E05A308B68DA78E16E90B47A11E133BD9A208A2894FD01B0BEE865CE339EA3FB17AC\td0cfaca5d335f9edc41c84bb47465184cb0e2ec3931bebfcea4dd433615e77a0", NULL, NULL, &error)); if (pkey != NULL) { buffer_set_used_size(key_1, 0); /* check that key_id matches */ struct dcrypt_public_key *pubkey = NULL; dcrypt_key_convert_private_to_public(pkey, &pubkey); test_assert(dcrypt_key_store_public(pubkey, DCRYPT_FORMAT_DOVECOT, key_1, NULL)); buffer_set_used_size(key_1, 0); dcrypt_key_id_public(pubkey, "sha256", key_1, &error); test_assert(strcmp("792caad4d38c9eb2134a0cbc844eae386116de096a0ccafc98479825fc99b6a1", binary_to_hex(key_1->data, key_1->used)) == 0); dcrypt_key_free_public(&pubkey); pkey2 = NULL; test_assert(dcrypt_key_load_private(&pkey2, DCRYPT_FORMAT_DOVECOT, "1\t716\t1\t0567e6bf9579813ae967314423b0fceb14bda24749303923de9a9bb9370e0026f995901a57e63113eeb2baf0c940e978d00686cbb52bd5014bc318563375876255\t0300E46DA2125427BE968EB3B649910CDC4C405E5FFDE18D433A97CABFEE28CEEFAE9EE356C792004FFB80981D67E741B8CC036A34235A8D2E1F98D1658CFC963D07EB\td0cfaca5d335f9edc41c84bb47465184cb0e2ec3931bebfcea4dd433615e77a0\t7c9a1039ea2e4fed73e81dd3ffc3fa22ea4a28352939adde7bf8ea858b00fa4f", NULL, pkey, &error)); if (pkey2 != NULL) { buffer_set_used_size(key_1, 0); /* check that key_id matches */ struct dcrypt_public_key *pubkey = NULL; dcrypt_key_convert_private_to_public(pkey2, &pubkey); test_assert(dcrypt_key_store_public(pubkey, DCRYPT_FORMAT_DOVECOT, key_1, NULL)); buffer_set_used_size(key_1, 0); test_assert(dcrypt_key_id_public_old(pubkey, key_1, &error)); test_assert(strcmp("7c9a1039ea2e4fed73e81dd3ffc3fa22ea4a28352939adde7bf8ea858b00fa4f", binary_to_hex(key_1->data, key_1->used)) == 0); dcrypt_key_free_public(&pubkey); dcrypt_key_free_private(&pkey2); } dcrypt_key_free_private(&pkey); } test_end(); }
static int o_stream_encrypt_key_for_pubkey_v2(struct encrypt_ostream *stream, const char *malg, const unsigned char *key, size_t key_len, struct dcrypt_public_key *pubkey, buffer_t *res) { enum dcrypt_key_type ktype; const char *error; buffer_t *encrypted_key, *ephemeral_key, *temp_key; ephemeral_key = buffer_create_dynamic(pool_datastack_create(), 256); encrypted_key = buffer_create_dynamic(pool_datastack_create(), 256); temp_key = buffer_create_dynamic(pool_datastack_create(), 48); ktype = dcrypt_key_type_public(pubkey); if (ktype == DCRYPT_KEY_RSA) { /* encrypt key as R (as we don't need DH with RSA)*/ if (!dcrypt_rsa_encrypt(pubkey, key, key_len, encrypted_key, &error)) { io_stream_set_error(&stream->ostream.iostream, "Cannot encrypt key data: %s", error); return -1; } } else if (ktype == DCRYPT_KEY_EC) { /* R = our ephemeral public key */ buffer_t *secret = buffer_create_dynamic(pool_datastack_create(), 256); /* derive ephemeral key and shared secret */ if (!dcrypt_ecdh_derive_secret_peer(pubkey, ephemeral_key, secret, &error)) { io_stream_set_error(&stream->ostream.iostream, "Cannot perform ECDH: %s", error); return -1; } /* use shared secret and ephemeral key to generate encryption key/iv */ if (!dcrypt_pbkdf2(secret->data, secret->used, ephemeral_key->data, ephemeral_key->used, malg, IO_STREAM_ENCRYPT_ROUNDS, temp_key, 48, &error)) { safe_memset(buffer_get_modifiable_data(secret, 0), 0, secret->used); io_stream_set_error(&stream->ostream.iostream, "Cannot perform key encryption: %s", error); } safe_memset(buffer_get_modifiable_data(secret, 0), 0, secret->used); /* encrypt key with shared secret */ struct dcrypt_context_symmetric *dctx; if (!dcrypt_ctx_sym_create("AES-256-CBC", DCRYPT_MODE_ENCRYPT, &dctx, &error)) { safe_memset(buffer_get_modifiable_data(temp_key, 0), 0, temp_key->used); io_stream_set_error(&stream->ostream.iostream, "Cannot perform key encryption: %s", error); return -1; } const unsigned char *ptr = temp_key->data; i_assert(temp_key->used == 48); dcrypt_ctx_sym_set_key(dctx, ptr, 32); dcrypt_ctx_sym_set_iv(dctx, ptr+32, 16); safe_memset(buffer_get_modifiable_data(temp_key, 0), 0, temp_key->used); int ec = 0; if (!dcrypt_ctx_sym_init(dctx, &error) || !dcrypt_ctx_sym_update(dctx, key, key_len, encrypted_key, &error) || !dcrypt_ctx_sym_final(dctx, encrypted_key, &error)) { io_stream_set_error(&stream->ostream.iostream, "Cannot perform key encryption: %s", error); ec = -1; } dcrypt_ctx_sym_destroy(&dctx); if (ec != 0) return ec; } else { io_stream_set_error(&stream->ostream.iostream, "Unsupported key type"); return -1; } /* store key type */ char kt = ktype; buffer_append(res, &kt, 1); /* store hash of public key as ID */ dcrypt_key_id_public(stream->pub, "sha256", res, NULL); /* store ephemeral key (if present) */ unsigned int val = htonl(ephemeral_key->used); buffer_append(res, &val, 4); buffer_append_buf(res, ephemeral_key, 0, (size_t)-1); /* store encrypted key */ val = htonl(encrypted_key->used); buffer_append(res, &val, 4); buffer_append_buf(res, encrypted_key, 0, (size_t)-1); return 0; }