/* * Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). You may not use * this file except in compliance with the License. A copy of the License is * located at * * http://aws.amazon.com/apache2.0/ * * or in the "license" file accompanying this file. This file is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing permissions and * limitations under the License. */ #include #include struct aws_cryptosdk_enc_materials *aws_cryptosdk_enc_materials_new( struct aws_allocator *alloc, enum aws_cryptosdk_alg_id alg) { AWS_PRECONDITION(aws_allocator_is_valid(alloc)); struct aws_cryptosdk_enc_materials *enc_mat; enc_mat = aws_mem_acquire(alloc, sizeof(struct aws_cryptosdk_enc_materials)); if (!enc_mat) return NULL; enc_mat->alloc = alloc; enc_mat->alg = alg; memset(&enc_mat->unencrypted_data_key, 0, sizeof(struct aws_byte_buf)); enc_mat->signctx = NULL; if (aws_cryptosdk_edk_list_init(alloc, &enc_mat->encrypted_data_keys)) { aws_mem_release(alloc, enc_mat); return NULL; } if (aws_cryptosdk_keyring_trace_init(alloc, &enc_mat->keyring_trace)) { aws_cryptosdk_edk_list_clean_up(&enc_mat->encrypted_data_keys); aws_mem_release(alloc, enc_mat); return NULL; } return enc_mat; } void aws_cryptosdk_enc_materials_destroy(struct aws_cryptosdk_enc_materials *enc_mat) { AWS_PRECONDITION(enc_mat == NULL || aws_cryptosdk_enc_materials_is_valid(enc_mat)); if (enc_mat) { aws_cryptosdk_sig_abort(enc_mat->signctx); aws_byte_buf_clean_up_secure(&enc_mat->unencrypted_data_key); aws_cryptosdk_edk_list_clean_up(&enc_mat->encrypted_data_keys); aws_cryptosdk_keyring_trace_clean_up(&enc_mat->keyring_trace); aws_mem_release(enc_mat->alloc, enc_mat); } } // TODO: initialization for trailing signature key, if necessary struct aws_cryptosdk_dec_materials *aws_cryptosdk_dec_materials_new( struct aws_allocator *alloc, enum aws_cryptosdk_alg_id alg) { AWS_PRECONDITION(aws_allocator_is_valid(alloc)); struct aws_cryptosdk_dec_materials *dec_mat = aws_mem_acquire(alloc, sizeof(struct aws_cryptosdk_dec_materials)); if (!dec_mat) return NULL; dec_mat->alloc = alloc; dec_mat->unencrypted_data_key.buffer = NULL; dec_mat->unencrypted_data_key.len = 0; dec_mat->unencrypted_data_key.capacity = 0; dec_mat->unencrypted_data_key.allocator = NULL; dec_mat->alg = alg; dec_mat->signctx = NULL; if (aws_cryptosdk_keyring_trace_init(alloc, &dec_mat->keyring_trace)) { aws_mem_release(alloc, dec_mat); return NULL; } return dec_mat; } void aws_cryptosdk_dec_materials_destroy(struct aws_cryptosdk_dec_materials *dec_mat) { AWS_PRECONDITION(dec_mat == NULL || aws_cryptosdk_dec_materials_is_valid(dec_mat)); if (dec_mat) { aws_cryptosdk_sig_abort(dec_mat->signctx); aws_byte_buf_clean_up_secure(&dec_mat->unencrypted_data_key); aws_cryptosdk_keyring_trace_clean_up(&dec_mat->keyring_trace); aws_mem_release(dec_mat->alloc, dec_mat); } } int aws_cryptosdk_keyring_on_encrypt( struct aws_cryptosdk_keyring *keyring, struct aws_allocator *request_alloc, struct aws_byte_buf *unencrypted_data_key, struct aws_array_list *keyring_trace, struct aws_array_list *edks, const struct aws_hash_table *enc_ctx, enum aws_cryptosdk_alg_id alg) { AWS_PRECONDITION(aws_allocator_is_valid(request_alloc)); AWS_PRECONDITION(aws_cryptosdk_keyring_is_valid(keyring) && (keyring->vtable != NULL)); AWS_PRECONDITION(aws_byte_buf_is_valid(unencrypted_data_key)); AWS_PRECONDITION(aws_cryptosdk_keyring_trace_is_valid(keyring_trace)); AWS_PRECONDITION(aws_cryptosdk_edk_list_is_valid(edks) && aws_cryptosdk_edk_list_elements_are_valid(edks)); AWS_PRECONDITION(enc_ctx == NULL || aws_hash_table_is_valid(enc_ctx)); /* Shallow copy of byte buffer: does NOT duplicate key bytes */ const struct aws_byte_buf precall_data_key_buf = *unencrypted_data_key; /* Precondition: If a data key has not already been generated, there must be no EDKs. * Generating a new one and then pushing new EDKs on the list would cause the list of * EDKs to be inconsistent. (i.e., they would decrypt to different data keys.) */ if (!precall_data_key_buf.buffer && aws_array_list_length(edks)) return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_STATE); AWS_CRYPTOSDK_PRIVATE_VF_CALL( on_encrypt, keyring, request_alloc, unencrypted_data_key, keyring_trace, edks, enc_ctx, alg); /* Postcondition: If this keyring generated data key, it must be the right length. */ if (!precall_data_key_buf.buffer && unencrypted_data_key->buffer) { const struct aws_cryptosdk_alg_properties *props = aws_cryptosdk_alg_props(alg); if (props == NULL || (unencrypted_data_key->len != props->data_key_len)) { return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_STATE); } } /* Postcondition: If data key was generated before call, byte buffer must not have been * modified. * * Note that this only checks the metadata in the byte buffer and not the key * bytes themselves. Verifying the key bytes were unchanged would require making an extra * copy of the key bytes, a case of the cure being worse than the disease. */ if (precall_data_key_buf.buffer) { if (memcmp(&precall_data_key_buf, unencrypted_data_key, sizeof(precall_data_key_buf))) return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_STATE); } return ret; } int aws_cryptosdk_keyring_on_decrypt( struct aws_cryptosdk_keyring *keyring, struct aws_allocator *request_alloc, struct aws_byte_buf *unencrypted_data_key, struct aws_array_list *keyring_trace, const struct aws_array_list *edks, const struct aws_hash_table *enc_ctx, enum aws_cryptosdk_alg_id alg) { AWS_PRECONDITION(aws_allocator_is_valid(request_alloc)); AWS_PRECONDITION(aws_cryptosdk_keyring_is_valid(keyring) && (keyring->vtable != NULL)); AWS_PRECONDITION(aws_byte_buf_is_valid(unencrypted_data_key)); AWS_PRECONDITION(aws_cryptosdk_keyring_trace_is_valid(keyring_trace)); AWS_PRECONDITION(aws_cryptosdk_edk_list_is_valid(edks)); AWS_PRECONDITION(enc_ctx == NULL || aws_hash_table_is_valid(enc_ctx)); /* Precondition: data key buffer must be unset. */ if (unencrypted_data_key->buffer) return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_STATE); AWS_CRYPTOSDK_PRIVATE_VF_CALL( on_decrypt, keyring, request_alloc, unencrypted_data_key, keyring_trace, edks, enc_ctx, alg); /* Postcondition: if data key was decrypted, its length must agree with algorithm * specification. If this is not the case, it either means ciphertext was tampered * with or the keyring implementation is not setting the length properly. */ if (unencrypted_data_key->buffer) { const struct aws_cryptosdk_alg_properties *props = aws_cryptosdk_alg_props(alg); if (props == NULL || unencrypted_data_key->len != props->data_key_len) return aws_raise_error(AWS_CRYPTOSDK_ERR_BAD_CIPHERTEXT); } return ret; }