本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
AWS Encryption SDK for C 示例
以下示例说明了如何使用AWS Encryption SDK for C加密和解密数据。
本节中的示例说明了如何使用版本 2.0.x 及更高版本的 AWS Encryption SDK for C。有关使用早期版本的示例,请在 GitHub 上 aws-encryption-sdk-c 存储库
在安装和构建AWS Encryption SDK for C时,将在 examples
子目录中包含以下示例和其他示例的源代码,并编译和构建这些代码以保存到 build
目录中。您也可以在 GitHub 上 aws-encryption-sdk-c
主题
加密和解密字符串
以下示例说明了如何使用AWS Encryption SDK for C加密和解密字符串。
该示例包含 AWS KMS 密钥环,这是一种在 AWS Key Management Service(AWS KMS)中使用 AWS KMS key 生成数据密钥并对其进行加密的密钥环。该示例包括用 C++ 编写的代码。使用 AWS KMS 密钥环时,AWS Encryption SDK for C 需要 AWS SDK for C++ 来调用 AWS KMS。如果您使用的是不与 AWS KMS 交互的密钥环,例如原始的 AES 密钥环、原始的 RSA 密钥环或不包含 AWS KMS 密钥环的多密钥环,则不需要 AWS SDK for C++。
有关创建 AWS KMS key 的帮助,请参阅《AWS Key Management Service 开发人员指南》中的创建密钥。有关标识 AWS KMS 密钥环中的 AWS KMS keys 的帮助,请参阅 在 AWS KMS 钥匙圈 AWS KMS keys 中识别。
请参阅完整的代码示例:string.cpp
加密字符串
该示例的第一部分使用具有一个 AWS KMS key 的 AWS KMS 密钥环以加密明文字符串。
- 第 1 步。加载错误字符串。
在 C 或 C++ 代码中调用
aws_cryptosdk_load_error_strings()
方法。该方法加载对调试非常有用的错误信息。您只需要调用一次,例如在
main
方法中调用。/* Load error strings for debugging */ aws_cryptosdk_load_error_strings();
- 步骤 2:构造密钥环。
-
创建一个用于加密的 AWS KMS 密钥环。该示例中的密钥环配置了一个 AWS KMS key,但您可以为 AWS KMS 密钥环配置多个 AWS KMS keys,包括不同 AWS 区域 和不同账户中的 AWS KMS keys。
要在 AWS Encryption SDK for C 的加密密钥环中标识 AWS KMS key,请指定密钥 ARN 或别名 ARN。在解密密钥环中,您必须使用密钥 ARN。有关详细信息,请参阅 在 AWS KMS 钥匙圈 AWS KMS keys 中识别。
在 AWS KMS 钥匙圈 AWS KMS keys 中识别
在创建具有多个 AWS KMS keys 的密钥环时,您可以指定用于生成和加密明文数据密钥的 AWS KMS key,以及一组加密相同明文数据密钥的可选附加 AWS KMS keys。在该示例中,您仅指定生成器 AWS KMS key。
在运行该代码之前,请将示例密钥 ARN 替换为有效 ARN。
const char * key_arn = "
arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab
"; struct aws_cryptosdk_keyring *kms_keyring = Aws::Cryptosdk::KmsKeyring::Builder().Build(key_arn); - 步骤 3:创建会话。
-
使用分配器、模式枚举器和密钥环创建一个会话。
每个会话都需要一种模式:用于加密的
AWS_CRYPTOSDK_ENCRYPT
或用于解密的AWS_CRYPTOSDK_DECRYPT
。要更改现有会话的模式,请使用aws_cryptosdk_session_reset
方法。在使用密钥环创建一个会话后,您可以使用该开发工具包提供的方法释放对密钥环的引用。该会话在生命周期内保留对密钥环对象的引用。在销毁该会话时,将释放对密钥环和会话对象的引用。这种引用计数方法有助于防止内存泄漏,并防止在使用对象时将其释放。
struct aws_cryptosdk_session *session = aws_cryptosdk_session_new_from_keyring_2(alloc, AWS_CRYPTOSDK_ENCRYPT, kms_keyring); /* When you add the keyring to the session, release the keyring object */ aws_cryptosdk_keyring_release(kms_keyring);
- 步骤 4:设置加密上下文。
-
加密上下文是任意的非机密其他经过身份验证的数据。如果您在加密时提供了加密上下文,AWS Encryption SDK将以加密方式将加密上下文绑定到密文,因此需要相同的加密上下文才能解密数据。使用加密上下文是可选的,但作为一项最佳实践,建议您提供加密上下文。
首先,创建一个包含加密上下文字符串的哈希表。
/* Allocate a hash table for the encryption context */ int set_up_enc_ctx(struct aws_allocator *alloc, struct aws_hash_table *my_enc_ctx) // Create encryption context strings AWS_STATIC_STRING_FROM_LITERAL(enc_ctx_key1, "Example"); AWS_STATIC_STRING_FROM_LITERAL(enc_ctx_value1, "String"); AWS_STATIC_STRING_FROM_LITERAL(enc_ctx_key2, "Company"); AWS_STATIC_STRING_FROM_LITERAL(enc_ctx_value2, "MyCryptoCorp"); // Put the key-value pairs in the hash table aws_hash_table_put(my_enc_ctx, enc_ctx_key1, (void *)enc_ctx_value1, &was_created) aws_hash_table_put(my_enc_ctx, enc_ctx_key2, (void *)enc_ctx_value2, &was_created)
获取会话中加密上下文的可变指针。然后,使用
aws_cryptosdk_enc_ctx_clone
函数将加密上下文复制到会话中。请将副本保留在my_enc_ctx
中,以便在解密数据后验证该值。加密上下文是会话的一部分,而不是传递给会话进程函数的参数。这可保证对消息的每个分段使用相同的加密上下文,即使多次调用会话进程函数来加密整个消息也是如此。
struct aws_hash_table *session_enc_ctx = aws_cryptosdk_session_get_enc_ctx_ptr_mut(session); aws_cryptosdk_enc_ctx_clone(alloc, session_enc_ctx, my_enc_ctx)
- 步骤 5:加密字符串。
-
要加密明文字符串,请使用
aws_cryptosdk_session_process_full
方法和使用加密模式的会话。此方法在 AWS Encryption SDK 版本 1.9.x 和 2.2.x 中引入,专为非串流加密和解密而设计。要处理串流数据,请在循环中调用aws_cryptosdk_session_process
。加密时,明文字段为输入字段;密文字段为输出字段。处理完成后,
ciphertext_output
字段包含加密的消息,其中包括实际密文、加密的数据密钥和加密上下文。您可以通过适用于任何支持的编程语言的 AWS Encryption SDK以解密该加密消息。/* Gets the length of the plaintext that the session processed */ size_t ciphertext_len_output; if (AWS_OP_SUCCESS != aws_cryptosdk_session_process_full(session, ciphertext_output, ciphertext_buf_sz_output, &ciphertext_len_output, plaintext_input, plaintext_len_input)) { aws_cryptosdk_session_destroy(session); return 8; }
- 步骤6:清理会话。
-
最后一步将销毁会话,包括对 CMM 和密钥环的引用。
您也可以根据需要重复使用具有相同密钥环和 CMM 的会话来解密字符串,或加密/解密其他消息,而不是销毁会话。要使用会话进行解密,请使用
aws_cryptosdk_session_reset
方法将模式更改为AWS_CRYPTOSDK_DECRYPT
。
解密字符串
本示例的第二部分将对包含原始字符串密文的加密消息进行解密。
- 步骤 1:加载错误字符串。
-
在 C 或 C++ 代码中调用
aws_cryptosdk_load_error_strings()
方法。该方法加载对调试非常有用的错误信息。您只需要调用一次,例如在
main
方法中调用。/* Load error strings for debugging */ aws_cryptosdk_load_error_strings();
- 步骤 2:构造密钥环。
-
解密 AWS KMS 中的数据时,您需要传入加密 API 返回的加密消息。Decrypt API 不会将 AWS KMS key 作为输入。相反,AWS KMS 通过在加密时使用的 AWS KMS key 对密文进行解密。不过,AWS Encryption SDK 允许您在加密和解密时指定具有 AWS KMS keys 的 AWS KMS 密钥环。
在解密时,您可以配置一个仅具有要用于解密加密消息的 AWS KMS keys 的密钥环。例如,您可能希望创建一个密钥环,它仅具有您的组织中的特定角色使用的 AWS KMS key。除非出现在解密密钥环中,否则,AWS Encryption SDK 绝不会使用 AWS KMS key。如果该开发工具包无法使用您提供的密钥环中的 AWS KMS keys 解密加密的数据密钥(由于未使用密钥环中的任何 AWS KMS keys 加密任何数据密钥,或者调用方无权使用密钥环中的 AWS KMS keys 进行解密),解密调用将会失败。
为解密密钥环指定 AWS KMS key 时,您必须使用其密钥 ARN。别名 ARN 仅允许在加密密钥环中使用。有关标识 AWS KMS 密钥环中的 AWS KMS keys 的帮助,请参阅 在 AWS KMS 钥匙圈 AWS KMS keys 中识别。
在该示例中,我们指定一个密钥环,该密钥环配置了用于加密字符串的相同 AWS KMS key。在运行该代码之前,请将示例密钥 ARN 替换为有效 ARN。
const char * key_arn = "
arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab
" struct aws_cryptosdk_keyring *kms_keyring = Aws::Cryptosdk::KmsKeyring::Builder().Build(key_arn); - 步骤 3:创建会话。
-
使用分配器和密钥环创建一个会话。要配置解密会话,请使用
AWS_CRYPTOSDK_DECRYPT
模式配置会话。在使用密钥环创建一个会话后,您可以使用该开发工具包提供的方法释放对密钥环的引用。该会话在生命周期内保留对密钥环对象的引用,在销毁该会话时,将会释放会话和密钥环。这种引用计数方法有助于防止内存泄漏,并防止在使用对象时将其释放。
struct aws_cryptosdk_session *session = aws_cryptosdk_session_new_from_keyring_2(alloc, AWS_CRYPTOSDK_DECRYPT, kms_keyring); /* When you add the keyring to the session, release the keyring object */ aws_cryptosdk_keyring_release(kms_keyring);
- 步骤 4:解密字符串。
-
要解密字符串,请使用
aws_cryptosdk_session_process_full
方法和配置用于解密的会话。此方法在 AWS Encryption SDK 版本 1.9.x 和 2.2.x 中引入,专为非串流加密和解密而设计。要处理串流数据,请在循环中调用aws_cryptosdk_session_process
。解密时,密文字段为输入字段,明文字段是输出字段。
ciphertext_input
字段包含加密方法返回的加密消息。处理完成后,plaintext_output
字段包含明文(解密后的)字符串。size_t plaintext_len_output; if (AWS_OP_SUCCESS != aws_cryptosdk_session_process_full(session, plaintext_output, plaintext_buf_sz_output, &plaintext_len_output, ciphertext_input, ciphertext_len_input)) { aws_cryptosdk_session_destroy(session); return 13; }
- 步骤 5:验证加密上下文。
-
请确保实际的加密上下文(用于解密消息的上下文)包含您在加密消息时提供的加密上下文。实际加密上下文可能包含额外的键值对,因为加密材料管理器 (CMM) 可以在加密消息前向提供的加密上下文添加键值对。
在AWS Encryption SDK for C中,您不需要在解密时提供加密上下文,因为在该开发工具包返回的加密消息中包含加密上下文。但是,在其返回明文消息前,您的解密函数应验证用于解密消息的加密上下文中包含所提供的加密上下文中的所有键值对。
首先,获取会话中哈希表的只读指针。该哈希表包含用于解密消息的加密上下文。
const struct aws_hash_table *session_enc_ctx = aws_cryptosdk_session_get_enc_ctx_ptr(session);
然后,遍历加密时复制的
my_enc_ctx
哈希表中的加密上下文。验证用于解密的session_enc_ctx
哈希表包含用于加密的my_enc_ctx
哈希表中的所有键值对。如果缺少任何密钥,或密钥具有不同的值,则停止处理并输出错误消息。for (struct aws_hash_iter iter = aws_hash_iter_begin(my_enc_ctx); !aws_hash_iter_done(&iter); aws_hash_iter_next(&iter)) { struct aws_hash_element *session_enc_ctx_kv_pair; aws_hash_table_find(session_enc_ctx, iter.element.key, &session_enc_ctx_kv_pair) if (!session_enc_ctx_kv_pair || !aws_string_eq( (struct aws_string *)iter.element.value, (struct aws_string *)session_enc_ctx_kv_pair->value)) { fprintf(stderr, "Wrong encryption context!\n"); abort(); } }
- 步骤6:清理会话。
-
验证加密上下文后,可以销毁会话,或重用会话。如果需要重新配置会话,请使用
aws_cryptosdk_session_reset
方法。aws_cryptosdk_session_destroy(session);