Lesson 35 - Get Compute Auth Token Working

This commit is contained in:
Norman Lansing
2026-02-28 12:32:28 -05:00
parent 1d477ee42a
commit 4fde462bce
7743 changed files with 1397833 additions and 18 deletions

View File

@@ -0,0 +1,60 @@
#ifndef AWS_CAL_CAL_H
#define AWS_CAL_CAL_H
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/common.h>
#include <aws/common/logging.h>
#include <aws/cal/exports.h>
AWS_PUSH_SANE_WARNING_LEVEL
struct aws_allocator;
#define AWS_C_CAL_PACKAGE_ID 7
enum aws_cal_errors {
AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED = AWS_ERROR_ENUM_BEGIN_RANGE(AWS_C_CAL_PACKAGE_ID),
AWS_ERROR_CAL_MISSING_REQUIRED_KEY_COMPONENT,
AWS_ERROR_CAL_INVALID_KEY_LENGTH_FOR_ALGORITHM,
AWS_ERROR_CAL_UNKNOWN_OBJECT_IDENTIFIER,
AWS_ERROR_CAL_MALFORMED_ASN1_ENCOUNTERED,
AWS_ERROR_CAL_MISMATCHED_DER_TYPE,
AWS_ERROR_CAL_UNSUPPORTED_ALGORITHM,
AWS_ERROR_CAL_BUFFER_TOO_LARGE_FOR_ALGORITHM,
AWS_ERROR_CAL_INVALID_CIPHER_MATERIAL_SIZE_FOR_ALGORITHM,
AWS_ERROR_CAL_DER_UNSUPPORTED_NEGATIVE_INT,
AWS_ERROR_CAL_UNSUPPORTED_KEY_FORMAT,
AWS_ERROR_CAL_CRYPTO_OPERATION_FAILED,
AWS_ERROR_CAL_END_RANGE = AWS_ERROR_ENUM_END_RANGE(AWS_C_CAL_PACKAGE_ID)
};
enum aws_cal_log_subject {
AWS_LS_CAL_GENERAL = AWS_LOG_SUBJECT_BEGIN_RANGE(AWS_C_CAL_PACKAGE_ID),
AWS_LS_CAL_ECC,
AWS_LS_CAL_HASH,
AWS_LS_CAL_HMAC,
AWS_LS_CAL_DER,
AWS_LS_CAL_LIBCRYPTO_RESOLVE,
AWS_LS_CAL_RSA,
AWS_LS_CAL_LAST = AWS_LOG_SUBJECT_END_RANGE(AWS_C_CAL_PACKAGE_ID)
};
AWS_EXTERN_C_BEGIN
AWS_CAL_API void aws_cal_library_init(struct aws_allocator *allocator);
AWS_CAL_API void aws_cal_library_clean_up(void);
/*
* Every CRT thread that might invoke aws-lc functionality should call this as part of the thread at_exit process
*/
AWS_CAL_API void aws_cal_thread_clean_up(void);
AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL
#endif /* AWS_CAL_CAL_H */

View File

@@ -0,0 +1,185 @@
#ifndef AWS_CAL_ECC_H
#define AWS_CAL_ECC_H
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/cal/exports.h>
#include <aws/common/atomics.h>
#include <aws/common/byte_buf.h>
#include <aws/common/common.h>
AWS_PUSH_SANE_WARNING_LEVEL
enum aws_ecc_curve_name {
AWS_CAL_ECDSA_P256,
AWS_CAL_ECDSA_P384,
};
struct aws_ecc_key_pair;
typedef void aws_ecc_key_pair_destroy_fn(struct aws_ecc_key_pair *key_pair);
typedef int aws_ecc_key_pair_sign_message_fn(
const struct aws_ecc_key_pair *key_pair,
const struct aws_byte_cursor *message,
struct aws_byte_buf *signature_output);
typedef int aws_ecc_key_pair_derive_public_key_fn(struct aws_ecc_key_pair *key_pair);
typedef int aws_ecc_key_pair_verify_signature_fn(
const struct aws_ecc_key_pair *signer,
const struct aws_byte_cursor *message,
const struct aws_byte_cursor *signature);
typedef size_t aws_ecc_key_pair_signature_length_fn(const struct aws_ecc_key_pair *signer);
struct aws_ecc_key_pair_vtable {
aws_ecc_key_pair_destroy_fn *destroy;
aws_ecc_key_pair_derive_public_key_fn *derive_pub_key;
aws_ecc_key_pair_sign_message_fn *sign_message;
aws_ecc_key_pair_verify_signature_fn *verify_signature;
aws_ecc_key_pair_signature_length_fn *signature_length;
};
struct aws_ecc_key_pair {
struct aws_allocator *allocator;
struct aws_atomic_var ref_count;
enum aws_ecc_curve_name curve_name;
struct aws_byte_buf key_buf;
struct aws_byte_buf pub_x;
struct aws_byte_buf pub_y;
struct aws_byte_buf priv_d;
struct aws_ecc_key_pair_vtable *vtable;
void *impl;
};
AWS_EXTERN_C_BEGIN
/**
* Adds one to an ecc key pair's ref count.
*/
AWS_CAL_API void aws_ecc_key_pair_acquire(struct aws_ecc_key_pair *key_pair);
/**
* Subtracts one from an ecc key pair's ref count. If ref count reaches zero, the key pair is destroyed.
*/
AWS_CAL_API void aws_ecc_key_pair_release(struct aws_ecc_key_pair *key_pair);
/**
* Creates an Elliptic Curve private key that can be used for signing.
* Returns a new instance of aws_ecc_key_pair if the key was successfully built.
* Otherwise returns NULL. Note: priv_key::len must match the appropriate length
* for the selected curve_name.
*/
AWS_CAL_API struct aws_ecc_key_pair *aws_ecc_key_pair_new_from_private_key(
struct aws_allocator *allocator,
enum aws_ecc_curve_name curve_name,
const struct aws_byte_cursor *priv_key);
#if !defined(AWS_OS_IOS)
/**
* Creates an Elliptic Curve public/private key pair that can be used for signing and verifying.
* Returns a new instance of aws_ecc_key_pair if the key was successfully built.
* Otherwise returns NULL.
* Note: On Apple platforms this function is only supported on MacOS. This is
* due to usage of SecItemExport, which is only available on MacOS 10.7+
* (yes, MacOS only and no other Apple platforms). There are alternatives for
* ios and other platforms, but they are ugly to use. Hence for now it only
* supports this call on MacOS.
*/
AWS_CAL_API struct aws_ecc_key_pair *aws_ecc_key_pair_new_generate_random(
struct aws_allocator *allocator,
enum aws_ecc_curve_name curve_name);
#endif /* !AWS_OS_IOS */
/**
* Creates an Elliptic Curve public key that can be used for verifying.
* Returns a new instance of aws_ecc_key_pair if the key was successfully built.
* Otherwise returns NULL. Note: public_key_x::len and public_key_y::len must
* match the appropriate length for the selected curve_name.
*/
AWS_CAL_API struct aws_ecc_key_pair *aws_ecc_key_pair_new_from_public_key(
struct aws_allocator *allocator,
enum aws_ecc_curve_name curve_name,
const struct aws_byte_cursor *public_key_x,
const struct aws_byte_cursor *public_key_y);
/**
* Creates an Elliptic Curve public/private key pair from a DER encoded key pair.
* Returns a new instance of aws_ecc_key_pair if the key was successfully built.
* Otherwise returns NULL. Whether or not signing or verification can be perform depends
* on if encoded_keys is a public/private pair or a public key.
*/
AWS_CAL_API struct aws_ecc_key_pair *aws_ecc_key_pair_new_from_asn1(
struct aws_allocator *allocator,
const struct aws_byte_cursor *encoded_keys);
/**
* Creates an Elliptic curve public key from x and y coordinates encoded as hex strings
* Returns a new instance of aws_ecc_key_pair if the key was successfully built.
* Otherwise returns NULL.
*/
AWS_CAL_API struct aws_ecc_key_pair *aws_ecc_key_new_from_hex_coordinates(
struct aws_allocator *allocator,
enum aws_ecc_curve_name curve_name,
struct aws_byte_cursor pub_x_hex_cursor,
struct aws_byte_cursor pub_y_hex_cursor);
/**
* Derives a public key from the private key if supported by this operating system (not supported on OSX).
* key_pair::pub_x and key_pair::pub_y will be set with the raw key buffers.
*/
AWS_CAL_API int aws_ecc_key_pair_derive_public_key(struct aws_ecc_key_pair *key_pair);
/**
* Get the curve name from the oid. OID here is the payload of the DER encoded ASN.1 part (doesn't include
* type specifier or length. On success, the value of curve_name will be set.
*/
AWS_CAL_API int aws_ecc_curve_name_from_oid(struct aws_byte_cursor *oid, enum aws_ecc_curve_name *curve_name);
/**
* Get the DER encoded OID from the curve_name. The OID in this case will not contain the type or the length specifier.
*/
AWS_CAL_API int aws_ecc_oid_from_curve_name(enum aws_ecc_curve_name curve_name, struct aws_byte_cursor *oid);
/**
* Uses the key_pair's private key to sign message. The output will be in signature. Signature must be large enough
* to hold the signature. Check aws_ecc_key_pair_signature_length() for the appropriate size. Signature will be DER
* encoded.
*
* It is the callers job to make sure message is the appropriate cryptographic digest for this operation. It's usually
* something like a SHA256.
*/
AWS_CAL_API int aws_ecc_key_pair_sign_message(
const struct aws_ecc_key_pair *key_pair,
const struct aws_byte_cursor *message,
struct aws_byte_buf *signature);
/**
* Uses the key_pair's public key to verify signature of message. Signature should be DER
* encoded.
*
* It is the callers job to make sure message is the appropriate cryptographic digest for this operation. It's usually
* something like a SHA256.
*
* returns AWS_OP_SUCCESS if the signature is valid.
*/
AWS_CAL_API int aws_ecc_key_pair_verify_signature(
const struct aws_ecc_key_pair *key_pair,
const struct aws_byte_cursor *message,
const struct aws_byte_cursor *signature);
AWS_CAL_API size_t aws_ecc_key_pair_signature_length(const struct aws_ecc_key_pair *key_pair);
AWS_CAL_API void aws_ecc_key_pair_get_public_key(
const struct aws_ecc_key_pair *key_pair,
struct aws_byte_cursor *pub_x,
struct aws_byte_cursor *pub_y);
AWS_CAL_API void aws_ecc_key_pair_get_private_key(
const struct aws_ecc_key_pair *key_pair,
struct aws_byte_cursor *private_d);
AWS_CAL_API size_t aws_ecc_key_coordinate_byte_size_from_curve_name(enum aws_ecc_curve_name curve_name);
AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL
#endif /* AWS_CAL_ECC_H */

View File

@@ -0,0 +1,28 @@
#ifndef AWS_CAL_EXPORTS_H
#define AWS_CAL_EXPORTS_H
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#if defined(AWS_C_RT_USE_WINDOWS_DLL_SEMANTICS) || defined(WIN32)
# ifdef AWS_CAL_USE_IMPORT_EXPORT
# ifdef AWS_CAL_EXPORTS
# define AWS_CAL_API __declspec(dllexport)
# else
# define AWS_CAL_API __declspec(dllimport)
# endif /* AWS_CAL_EXPORTS */
# else
# define AWS_CAL_API
# endif /* AWS_CAL_USE_IMPORT_EXPORT */
#else /* defined (AWS_C_RT_USE_WINDOWS_DLL_SEMANTICS) || defined (WIN32) */
# if ((__GNUC__ >= 4) || defined(__clang__)) && defined(AWS_CAL_USE_IMPORT_EXPORT) && defined(AWS_CAL_EXPORTS)
# define AWS_CAL_API __attribute__((visibility("default")))
# else
# define AWS_CAL_API
# endif /* __GNUC__ >= 4 || defined(__clang__) */
#endif /* defined (AWS_C_RT_USE_WINDOWS_DLL_SEMANTICS) || defined (WIN32) */
#endif /* AWS_CAL_EXPORTS_H */

View File

@@ -0,0 +1,139 @@
#ifndef AWS_CAL_HASH_H_
#define AWS_CAL_HASH_H_
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/cal/exports.h>
#include <aws/common/byte_buf.h>
#include <aws/common/common.h>
AWS_PUSH_SANE_WARNING_LEVEL
#define AWS_SHA256_LEN 32
#define AWS_SHA1_LEN 20
#define AWS_MD5_LEN 16
struct aws_hash;
struct aws_hash_vtable {
const char *alg_name;
const char *provider;
void (*destroy)(struct aws_hash *hash);
int (*update)(struct aws_hash *hash, const struct aws_byte_cursor *buf);
int (*finalize)(struct aws_hash *hash, struct aws_byte_buf *out);
};
struct aws_hash {
struct aws_allocator *allocator;
struct aws_hash_vtable *vtable;
size_t digest_size;
bool good;
void *impl;
};
typedef struct aws_hash *(aws_hash_new_fn)(struct aws_allocator *allocator);
AWS_EXTERN_C_BEGIN
/**
* Allocates and initializes a sha256 hash instance.
*/
AWS_CAL_API struct aws_hash *aws_sha256_new(struct aws_allocator *allocator);
/**
* Allocates and initializes a sha1 hash instance.
*/
AWS_CAL_API struct aws_hash *aws_sha1_new(struct aws_allocator *allocator);
/**
* Allocates and initializes an md5 hash instance.
*/
AWS_CAL_API struct aws_hash *aws_md5_new(struct aws_allocator *allocator);
/**
* Cleans up and deallocates hash.
*/
AWS_CAL_API void aws_hash_destroy(struct aws_hash *hash);
/**
* Updates the running hash with to_hash. this can be called multiple times.
*/
AWS_CAL_API int aws_hash_update(struct aws_hash *hash, const struct aws_byte_cursor *to_hash);
/**
* Completes the hash computation and writes the final digest to output.
* Allocation of output is the caller's responsibility. If you specify
* truncate_to to something other than 0, the output will be truncated to that
* number of bytes. For example, if you want a SHA256 digest as the first 16
* bytes, set truncate_to to 16. If you want the full digest size, just set this
* to 0.
*/
AWS_CAL_API int aws_hash_finalize(struct aws_hash *hash, struct aws_byte_buf *output, size_t truncate_to);
/**
* Computes the md5 hash over input and writes the digest output to 'output'.
* Use this if you don't need to stream the data you're hashing and you can load
* the entire input to hash into memory.
*/
AWS_CAL_API int aws_md5_compute(
struct aws_allocator *allocator,
const struct aws_byte_cursor *input,
struct aws_byte_buf *output,
size_t truncate_to);
/**
* Computes the sha256 hash over input and writes the digest output to 'output'.
* Use this if you don't need to stream the data you're hashing and you can load
* the entire input to hash into memory. If you specify truncate_to to something
* other than 0, the output will be truncated to that number of bytes. For
* example, if you want a SHA256 digest as the first 16 bytes, set truncate_to
* to 16. If you want the full digest size, just set this to 0.
*/
AWS_CAL_API int aws_sha256_compute(
struct aws_allocator *allocator,
const struct aws_byte_cursor *input,
struct aws_byte_buf *output,
size_t truncate_to);
/**
* Computes the sha1 hash over input and writes the digest output to 'output'.
* Use this if you don't need to stream the data you're hashing and you can load
* the entire input to hash into memory. If you specify truncate_to to something
* other than 0, the output will be truncated to that number of bytes. For
* example, if you want a SHA1 digest as the first 16 bytes, set truncate_to
* to 16. If you want the full digest size, just set this to 0.
*/
AWS_CAL_API int aws_sha1_compute(
struct aws_allocator *allocator,
const struct aws_byte_cursor *input,
struct aws_byte_buf *output,
size_t truncate_to);
/**
* Set the implementation of md5 to use. If you compiled without BYO_CRYPTO,
* you do not need to call this. However, if use this, we will honor it,
* regardless of compile options. This may be useful for testing purposes. If
* you did set BYO_CRYPTO, and you do not call this function you will
* segfault.
*/
AWS_CAL_API void aws_set_md5_new_fn(aws_hash_new_fn *fn);
/**
* Set the implementation of sha256 to use. If you compiled without
* BYO_CRYPTO, you do not need to call this. However, if use this, we will
* honor it, regardless of compile options. This may be useful for testing
* purposes. If you did set BYO_CRYPTO, and you do not call this function
* you will segfault.
*/
AWS_CAL_API void aws_set_sha256_new_fn(aws_hash_new_fn *fn);
/**
* Set the implementation of sha1 to use. If you compiled without
* BYO_CRYPTO, you do not need to call this. However, if use this, we will
* honor it, regardless of compile options. This may be useful for testing
* purposes. If you did set BYO_CRYPTO, and you do not call this function
* you will segfault.
*/
AWS_CAL_API void aws_set_sha1_new_fn(aws_hash_new_fn *fn);
AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL
#endif /* AWS_CAL_HASH_H_ */

View File

@@ -0,0 +1,87 @@
#ifndef AWS_CAL_HMAC_H_
#define AWS_CAL_HMAC_H_
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/cal/exports.h>
#include <aws/common/byte_buf.h>
#include <aws/common/common.h>
AWS_PUSH_SANE_WARNING_LEVEL
#define AWS_SHA256_HMAC_LEN 32
struct aws_hmac;
struct aws_hmac_vtable {
const char *alg_name;
const char *provider;
void (*destroy)(struct aws_hmac *hmac);
int (*update)(struct aws_hmac *hmac, const struct aws_byte_cursor *buf);
int (*finalize)(struct aws_hmac *hmac, struct aws_byte_buf *out);
};
struct aws_hmac {
struct aws_allocator *allocator;
struct aws_hmac_vtable *vtable;
size_t digest_size;
bool good;
void *impl;
};
typedef struct aws_hmac *(aws_hmac_new_fn)(struct aws_allocator *allocator, const struct aws_byte_cursor *secret);
AWS_EXTERN_C_BEGIN
/**
* Allocates and initializes a sha256 hmac instance. Secret is the key to be
* used for the hmac process.
*/
AWS_CAL_API struct aws_hmac *aws_sha256_hmac_new(struct aws_allocator *allocator, const struct aws_byte_cursor *secret);
/**
* Cleans up and deallocates hmac.
*/
AWS_CAL_API void aws_hmac_destroy(struct aws_hmac *hmac);
/**
* Updates the running hmac with to_hash. this can be called multiple times.
*/
AWS_CAL_API int aws_hmac_update(struct aws_hmac *hmac, const struct aws_byte_cursor *to_hmac);
/**
* Completes the hmac computation and writes the final digest to output.
* Allocation of output is the caller's responsibility. If you specify
* truncate_to to something other than 0, the output will be truncated to that
* number of bytes. For example if you want a SHA256 digest as the first 16
* bytes, set truncate_to to 16. If you want the full digest size, just set this
* to 0.
*/
AWS_CAL_API int aws_hmac_finalize(struct aws_hmac *hmac, struct aws_byte_buf *output, size_t truncate_to);
/**
* Computes the sha256 hmac over input and writes the digest output to 'output'.
* Use this if you don't need to stream the data you're hashing and you can load
* the entire input to hash into memory. If you specify truncate_to to something
* other than 0, the output will be truncated to that number of bytes. For
* example if you want a SHA256 HMAC digest as the first 16 bytes, set
* truncate_to to 16. If you want the full digest size, just set this to 0.
*/
AWS_CAL_API int aws_sha256_hmac_compute(
struct aws_allocator *allocator,
const struct aws_byte_cursor *secret,
const struct aws_byte_cursor *to_hmac,
struct aws_byte_buf *output,
size_t truncate_to);
/**
* Set the implementation of sha256 hmac to use. If you compiled without
* BYO_CRYPTO, you do not need to call this. However, if use this, we will
* honor it, regardless of compile options. This may be useful for testing
* purposes. If you did set BYO_CRYPTO, and you do not call this function
* you will segfault.
*/
AWS_CAL_API void aws_set_sha256_hmac_new_fn(aws_hmac_new_fn *fn);
AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL
#endif /* AWS_CAL_HASH_H_ */

View File

@@ -0,0 +1,165 @@
#ifndef AWS_CAL_RSA_H
#define AWS_CAL_RSA_H
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/cal/cal.h>
#include <aws/common/byte_buf.h>
AWS_PUSH_SANE_WARNING_LEVEL
struct aws_rsa_key_pair;
enum aws_rsa_encryption_algorithm {
AWS_CAL_RSA_ENCRYPTION_PKCS1_5,
AWS_CAL_RSA_ENCRYPTION_OAEP_SHA256,
AWS_CAL_RSA_ENCRYPTION_OAEP_SHA512,
};
enum aws_rsa_signature_algorithm {
AWS_CAL_RSA_SIGNATURE_PKCS1_5_SHA256,
AWS_CAL_RSA_SIGNATURE_PSS_SHA256,
};
/*
* Note: prefer using standard key sizes - 1024, 2048, 4096.
* Other key sizes will work, but which key sizes are supported may vary by
* platform. Typically, multiples of 64 should work on all platforms.
*/
enum {
AWS_CAL_RSA_MIN_SUPPORTED_KEY_SIZE_IN_BITS = 1024,
AWS_CAL_RSA_MAX_SUPPORTED_KEY_SIZE_IN_BITS = 4096,
};
AWS_EXTERN_C_BEGIN
/**
* Creates an RSA public key from RSAPublicKey as defined in rfc 8017 (aka PKCS1).
* Returns a new instance of aws_rsa_key_pair if the key was successfully built.
* Otherwise returns NULL.
*/
AWS_CAL_API struct aws_rsa_key_pair *aws_rsa_key_pair_new_from_public_key_pkcs1(
struct aws_allocator *allocator,
struct aws_byte_cursor key);
/**
* Creates an RSA private key from RSAPrivateKey as defined in rfc 8017 (aka PKCS1).
* Returns a new instance of aws_rsa_key_pair if the key was successfully built.
* Otherwise returns NULL.
*/
AWS_CAL_API struct aws_rsa_key_pair *aws_rsa_key_pair_new_from_private_key_pkcs1(
struct aws_allocator *allocator,
struct aws_byte_cursor key);
/**
* Adds one to an RSA key pair's ref count.
* Returns key_pair pointer.
*/
AWS_CAL_API struct aws_rsa_key_pair *aws_rsa_key_pair_acquire(struct aws_rsa_key_pair *key_pair);
/**
* Subtracts one from an RSA key pair's ref count. If ref count reaches zero, the key pair is destroyed.
* Always returns NULL.
*/
AWS_CAL_API struct aws_rsa_key_pair *aws_rsa_key_pair_release(struct aws_rsa_key_pair *key_pair);
/**
* Max plaintext size that can be encrypted by the key (i.e. max data size
* supported by the key - bytes needed for padding).
*/
AWS_CAL_API size_t aws_rsa_key_pair_max_encrypt_plaintext_size(
const struct aws_rsa_key_pair *key_pair,
enum aws_rsa_encryption_algorithm algorithm);
/*
* Uses the key_pair's private key to encrypt the plaintext. The output will be
* in out. out must be large enough to to hold the ciphertext. Check
* aws_rsa_key_pair_block_length() for output upper bound.
*/
AWS_CAL_API int aws_rsa_key_pair_encrypt(
const struct aws_rsa_key_pair *key_pair,
enum aws_rsa_encryption_algorithm algorithm,
struct aws_byte_cursor plaintext,
struct aws_byte_buf *out);
/*
* Uses the key_pair's private key to decrypt the ciphertext. The output will be
* in out. out must be large enough to to hold the ciphertext. Check
* aws_rsa_key_pair_block_length() for output upper bound.
*/
AWS_CAL_API int aws_rsa_key_pair_decrypt(
const struct aws_rsa_key_pair *key_pair,
enum aws_rsa_encryption_algorithm algorithm,
struct aws_byte_cursor ciphertext,
struct aws_byte_buf *out);
/*
* Max size for a block supported by a given key pair.
*/
AWS_CAL_API size_t aws_rsa_key_pair_block_length(const struct aws_rsa_key_pair *key_pair);
/**
* Uses the key_pair's private key to sign message. The output will be in out. out must be large enough
* to hold the signature. Check aws_rsa_key_pair_signature_length() for the appropriate size.
*
* It is the callers job to make sure message is the appropriate cryptographic digest for this operation. It's usually
* something like a SHA256.
*/
AWS_CAL_API int aws_rsa_key_pair_sign_message(
const struct aws_rsa_key_pair *key_pair,
enum aws_rsa_signature_algorithm algorithm,
struct aws_byte_cursor digest,
struct aws_byte_buf *out);
/**
* Uses the key_pair's public key to verify signature of message.
*
* It is the callers job to make sure message is the appropriate cryptographic digest for this operation. It's usually
* something like a SHA256.
*
* returns AWS_OP_SUCCESS if the signature is valid.
* raises AWS_ERROR_CAL_SIGNATURE_VALIDATION_FAILED if signature validation failed
*/
AWS_CAL_API int aws_rsa_key_pair_verify_signature(
const struct aws_rsa_key_pair *key_pair,
enum aws_rsa_signature_algorithm algorithm,
struct aws_byte_cursor digest,
struct aws_byte_cursor signature);
/*
* Max size for a signature supported by a given key pair.
*/
AWS_CAL_API size_t aws_rsa_key_pair_signature_length(const struct aws_rsa_key_pair *key_pair);
enum aws_rsa_key_export_format {
AWS_CAL_RSA_KEY_EXPORT_PKCS1,
};
/*
* Get public key for the key pair.
* Inits out to a copy of key.
* Any encoding on top of that (ex. b64) is left up to user.
* Note: this function is currently not supported on windows for generated keys.
*/
AWS_CAL_API int aws_rsa_key_pair_get_public_key(
const struct aws_rsa_key_pair *key_pair,
enum aws_rsa_key_export_format format,
struct aws_byte_buf *out);
/*
* Get private key for the key pair.
* Inits out to a copy of key.
* Any encoding on top of that (ex. b64) is left up to user.
* Note: this function is currently not supported on Windows for generated keys.
*/
AWS_CAL_API int aws_rsa_key_pair_get_private_key(
const struct aws_rsa_key_pair *key_pair,
enum aws_rsa_key_export_format format,
struct aws_byte_buf *out);
AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL
#endif /* AWS_CAL_RSA_H */

View File

@@ -0,0 +1,259 @@
#ifndef AWS_CAL_SYMMETRIC_CIPHER_H
#define AWS_CAL_SYMMETRIC_CIPHER_H
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/cal/cal.h>
#include <aws/common/byte_buf.h>
AWS_PUSH_SANE_WARNING_LEVEL
#define AWS_AES_256_CIPHER_BLOCK_SIZE 16
#define AWS_AES_256_KEY_BIT_LEN 256
#define AWS_AES_256_KEY_BYTE_LEN (AWS_AES_256_KEY_BIT_LEN / 8)
struct aws_symmetric_cipher;
typedef struct aws_symmetric_cipher *(aws_aes_cbc_256_new_fn)(struct aws_allocator *allocator,
const struct aws_byte_cursor *key,
const struct aws_byte_cursor *iv);
typedef struct aws_symmetric_cipher *(aws_aes_ctr_256_new_fn)(struct aws_allocator *allocator,
const struct aws_byte_cursor *key,
const struct aws_byte_cursor *iv);
typedef struct aws_symmetric_cipher *(aws_aes_gcm_256_new_fn)(struct aws_allocator *allocator,
const struct aws_byte_cursor *key,
const struct aws_byte_cursor *iv,
const struct aws_byte_cursor *aad);
typedef struct aws_symmetric_cipher *(aws_aes_keywrap_256_new_fn)(struct aws_allocator *allocator,
const struct aws_byte_cursor *key);
enum aws_symmetric_cipher_state {
AWS_SYMMETRIC_CIPHER_READY,
AWS_SYMMETRIC_CIPHER_FINALIZED,
AWS_SYMMETRIC_CIPHER_ERROR,
};
AWS_EXTERN_C_BEGIN
/**
* Creates an instance of AES CBC with 256-bit key.
* If key and iv are NULL, they will be generated internally.
* You can get the generated key and iv back by calling:
*
* aws_symmetric_cipher_get_key() and
* aws_symmetric_cipher_get_initialization_vector()
*
* respectively.
*
* If they are set, that key and iv will be copied internally and used by the cipher.
*
* Returns NULL on failure. You can check aws_last_error() to get the error code indicating the failure cause.
*/
AWS_CAL_API struct aws_symmetric_cipher *aws_aes_cbc_256_new(
struct aws_allocator *allocator,
const struct aws_byte_cursor *key,
const struct aws_byte_cursor *iv);
/**
* Creates an instance of AES CTR with 256-bit key.
* If key and iv are NULL, they will be generated internally.
* You can get the generated key and iv back by calling:
*
* aws_symmetric_cipher_get_key() and
* aws_symmetric_cipher_get_initialization_vector()
*
* respectively.
*
* If they are set, that key and iv will be copied internally and used by the cipher.
*
* Returns NULL on failure. You can check aws_last_error() to get the error code indicating the failure cause.
*/
AWS_CAL_API struct aws_symmetric_cipher *aws_aes_ctr_256_new(
struct aws_allocator *allocator,
const struct aws_byte_cursor *key,
const struct aws_byte_cursor *iv);
/**
* Creates an instance of AES GCM with 256-bit key.
* If key, iv are NULL, they will be generated internally.
* You can get the generated key and iv back by calling:
*
* aws_symmetric_cipher_get_key() and
* aws_symmetric_cipher_get_initialization_vector()
*
* respectively.
*
* If aad is set it will be copied and applied to the cipher.
*
* If they are set, that key and iv will be copied internally and used by the cipher.
*
* For decryption purposes tag can be provided via aws_symmetric_cipher_set_tag method.
* Note: for decrypt operations, tag must be provided before first decrypt is called.
* (this is a windows bcrypt limitations, but for consistency sake same limitation is extended to other platforms)
* Tag generated during encryption can be retrieved using aws_symmetric_cipher_get_tag method
* after finalize is called.
*
* Returns NULL on failure. You can check aws_last_error() to get the error code indicating the failure cause.
*/
AWS_CAL_API struct aws_symmetric_cipher *aws_aes_gcm_256_new(
struct aws_allocator *allocator,
const struct aws_byte_cursor *key,
const struct aws_byte_cursor *iv,
const struct aws_byte_cursor *aad);
/**
* Creates an instance of AES Keywrap with 256-bit key.
* If key is NULL, it will be generated internally.
* You can get the generated key back by calling:
*
* aws_symmetric_cipher_get_key()
*
* If key is set, that key will be copied internally and used by the cipher.
*
* Returns NULL on failure. You can check aws_last_error() to get the error code indicating the failure cause.
*/
AWS_CAL_API struct aws_symmetric_cipher *aws_aes_keywrap_256_new(
struct aws_allocator *allocator,
const struct aws_byte_cursor *key);
/**
* Cleans up internal resources and state for cipher and then deallocates it.
*/
AWS_CAL_API void aws_symmetric_cipher_destroy(struct aws_symmetric_cipher *cipher);
/**
* Encrypts the value in to_encrypt and writes the encrypted data into out.
* If out is dynamic it will be expanded. If it is not, and out is not large enough to handle
* the encrypted output, the call will fail. If you're trying to optimize to use a stack based array
* or something, make sure it's at least as large as the size of to_encrypt + an extra BLOCK to account for
* padding etc...
*
* returns AWS_OP_SUCCESS on success. Call aws_last_error() to determine the failure cause if it returns
* AWS_OP_ERR;
*/
AWS_CAL_API int aws_symmetric_cipher_encrypt(
struct aws_symmetric_cipher *cipher,
struct aws_byte_cursor to_encrypt,
struct aws_byte_buf *out);
/**
* Decrypts the value in to_decrypt and writes the decrypted data into out.
* If out is dynamic it will be expanded. If it is not, and out is not large enough to handle
* the decrypted output, the call will fail. If you're trying to optimize to use a stack based array
* or something, make sure it's at least as large as the size of to_decrypt + an extra BLOCK to account for
* padding etc...
*
* returns AWS_OP_SUCCESS on success. Call aws_last_error() to determine the failure cause if it returns
* AWS_OP_ERR;
*/
AWS_CAL_API int aws_symmetric_cipher_decrypt(
struct aws_symmetric_cipher *cipher,
struct aws_byte_cursor to_decrypt,
struct aws_byte_buf *out);
/**
* Encrypts any remaining data that was reserved for final padding, loads GMACs etc... and if there is any
* writes any remaining encrypted data to out. If out is dynamic it will be expanded. If it is not, and
* out is not large enough to handle the decrypted output, the call will fail. If you're trying to optimize
* to use a stack based array or something, make sure it's at least as large as the size of 2 BLOCKs to account for
* padding etc...
*
* After invoking this function, you MUST call aws_symmetric_cipher_reset() before invoking any encrypt/decrypt
* operations on this cipher again.
*
* returns AWS_OP_SUCCESS on success. Call aws_last_error() to determine the failure cause if it returns
* AWS_OP_ERR;
*/
AWS_CAL_API int aws_symmetric_cipher_finalize_encryption(struct aws_symmetric_cipher *cipher, struct aws_byte_buf *out);
/**
* Decrypts any remaining data that was reserved for final padding, loads GMACs etc... and if there is any
* writes any remaining decrypted data to out. If out is dynamic it will be expanded. If it is not, and
* out is not large enough to handle the decrypted output, the call will fail. If you're trying to optimize
* to use a stack based array or something, make sure it's at least as large as the size of 2 BLOCKs to account for
* padding etc...
*
* After invoking this function, you MUST call aws_symmetric_cipher_reset() before invoking any encrypt/decrypt
* operations on this cipher again.
*
* returns AWS_OP_SUCCESS on success. Call aws_last_error() to determine the failure cause if it returns
* AWS_OP_ERR;
*/
AWS_CAL_API int aws_symmetric_cipher_finalize_decryption(struct aws_symmetric_cipher *cipher, struct aws_byte_buf *out);
/**
* Resets the cipher state for starting a new encrypt or decrypt operation. Note encrypt/decrypt cannot be mixed on the
* same cipher without a call to reset in between them. However, this leaves the key, iv etc... materials setup for
* immediate reuse.
* Note: GCM tag is not preserved between operations. If you intend to do encrypt followed directly by decrypt, make
* sure to make a copy of tag before reseting the cipher and pass that copy for decryption.
*
* Warning: In most cases it's a really bad idea to reset a cipher and perform another operation using that cipher.
* Key and IV should not be reused for different operations. Instead of reseting the cipher, destroy the cipher
* and create new one with a new key/iv pair. Use reset at your own risk, and only after careful consideration.
*
* returns AWS_OP_SUCCESS on success. Call aws_last_error() to determine the failure cause if it returns
* AWS_OP_ERR;
*/
AWS_CAL_API int aws_symmetric_cipher_reset(struct aws_symmetric_cipher *cipher);
/**
* Gets the current GMAC tag. If not AES GCM, this function will just return an empty cursor.
* The memory in this cursor is unsafe as it refers to the internal buffer.
* This was done because the use case doesn't require fetching these during an
* encryption or decryption operation and it dramatically simplifies the API.
* Only use this function between other calls to this API as any function call can alter the value of this tag.
*
* If you need to access it in a different pattern, copy the values to your own buffer first.
*/
AWS_CAL_API struct aws_byte_cursor aws_symmetric_cipher_get_tag(const struct aws_symmetric_cipher *cipher);
/**
* Sets the GMAC tag on the cipher. Does nothing for ciphers that do not support tag.
*/
AWS_CAL_API void aws_symmetric_cipher_set_tag(struct aws_symmetric_cipher *cipher, struct aws_byte_cursor tag);
/**
* Gets the original initialization vector as a cursor.
* The memory in this cursor is unsafe as it refers to the internal buffer.
* This was done because the use case doesn't require fetching these during an
* encryption or decryption operation and it dramatically simplifies the API.
*
* Unlike some other fields, this value does not change after the inital construction of the cipher.
*
* For some algorithms, such as AES Keywrap, this will return an empty cursor.
*/
AWS_CAL_API struct aws_byte_cursor aws_symmetric_cipher_get_initialization_vector(
const struct aws_symmetric_cipher *cipher);
/**
* Gets the original key.
*
* The memory in this cursor is unsafe as it refers to the internal buffer.
* This was done because the use case doesn't require fetching these during an
* encryption or decryption operation and it dramatically simplifies the API.
*
* Unlike some other fields, this value does not change after the inital construction of the cipher.
*/
AWS_CAL_API struct aws_byte_cursor aws_symmetric_cipher_get_key(const struct aws_symmetric_cipher *cipher);
/**
* Returns true if the state of the cipher is good, and otherwise returns false.
* Most operations, other than aws_symmetric_cipher_reset() will fail if this function is returning false.
* aws_symmetric_cipher_reset() will reset the state to a good state if possible.
*/
AWS_CAL_API bool aws_symmetric_cipher_is_good(const struct aws_symmetric_cipher *cipher);
/**
* Retuns the current state of the cipher. Ther state of the cipher can be ready for use, finalized, or has encountered
* an error. if the cipher is in a finished or error state, it must be reset before further use.
*/
AWS_CAL_API enum aws_symmetric_cipher_state aws_symmetric_cipher_get_state(const struct aws_symmetric_cipher *cipher);
AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL
#endif /* AWS_CAL_SYMMETRIC_CIPHER_H */