in source/session_encrypt.c [50:150]
int aws_cryptosdk_priv_try_gen_key(struct aws_cryptosdk_session *session) {
AWS_PRECONDITION(aws_cryptosdk_session_is_valid(session));
AWS_PRECONDITION(aws_cryptosdk_commitment_policy_is_valid(session->commitment_policy));
AWS_PRECONDITION(session->state == ST_GEN_KEY);
AWS_PRECONDITION(session->mode == AWS_CRYPTOSDK_ENCRYPT);
struct aws_cryptosdk_enc_request request;
struct aws_cryptosdk_enc_materials *materials = NULL;
struct data_key data_key;
int result = AWS_CRYPTOSDK_ERR_CRYPTO_UNKNOWN;
request.alloc = session->alloc;
request.enc_ctx = &session->header.enc_ctx;
// The default CMM will fill this in.
request.requested_alg = 0;
request.plaintext_size = session->precise_size_known ? session->precise_size : session->size_bound;
request.commitment_policy = session->commitment_policy;
if (aws_cryptosdk_cmm_generate_enc_materials(session->cmm, &materials, &request)) {
goto rethrow;
}
// Perform basic validation of the materials generated
session->alg_props = aws_cryptosdk_alg_props(materials->alg);
if (!session->alg_props) goto out;
if (materials->unencrypted_data_key.len != session->alg_props->data_key_len) goto out;
size_t num_encrypted_data_keys = aws_array_list_length(&materials->encrypted_data_keys);
if (!num_encrypted_data_keys) goto out;
if (session->max_encrypted_data_keys && num_encrypted_data_keys > session->max_encrypted_data_keys) {
result = AWS_CRYPTOSDK_ERR_LIMIT_EXCEEDED;
goto out;
}
// We should have a signature context iff this is a signed alg suite
if (!!session->alg_props->signature_len != !!materials->signctx) goto out;
if (!aws_cryptosdk_priv_algorithm_allowed_for_encrypt(materials->alg, session->commitment_policy)) {
result = AWS_CRYPTOSDK_ERR_COMMITMENT_POLICY_VIOLATION;
goto out;
}
// Move ownership of the signature context before we go any further.
session->signctx = materials->signctx;
materials->signctx = NULL;
// TODO - eliminate the data_key type
memcpy(&data_key, materials->unencrypted_data_key.buffer, materials->unencrypted_data_key.len);
aws_cryptosdk_transfer_list(&session->keyring_trace, &materials->keyring_trace);
session->cmm_success = true;
// Generate message ID and derive the content key from the data key.
size_t message_id_len = aws_cryptosdk_private_algorithm_message_id_len(session->alg_props);
if (aws_byte_buf_init(&session->header.message_id, session->alloc, message_id_len) != AWS_OP_SUCCESS) {
goto out;
}
if (aws_cryptosdk_genrandom(session->header.message_id.buffer, message_id_len)) {
goto out;
}
session->header.message_id.len = message_id_len;
if (aws_cryptosdk_commitment_policy_encrypt_must_include_commitment(session->commitment_policy)) {
assert(session->alg_props->commitment_len <= sizeof(session->key_commitment_arr));
session->header.alg_suite_data =
aws_byte_buf_from_array(session->key_commitment_arr, session->alg_props->commitment_len);
}
if (aws_cryptosdk_private_derive_key(
session->alg_props,
&session->content_key,
&data_key,
&session->header.alg_suite_data,
&session->header.message_id)) {
goto rethrow;
}
if (build_header(session, materials)) {
goto rethrow;
}
if (sign_header(session)) {
goto rethrow;
}
result = AWS_ERROR_SUCCESS;
out:
if (result) result = aws_raise_error(result);
goto cleanup;
rethrow:
result = AWS_OP_ERR;
cleanup:
if (materials) {
aws_byte_buf_secure_zero(&materials->unencrypted_data_key);
aws_cryptosdk_enc_materials_destroy(materials);
}
aws_secure_zero(&data_key, sizeof(data_key));
return result;
}