Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions aws-esdk-cpp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "aws-esdk-cpp-stub"
version = "0.0.0"
edition = "2024"
publish = false

[lib]
path = "src/lib.rs"
19 changes: 19 additions & 0 deletions aws-esdk-cpp/aws-esdk-cpp/.duvet/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'$schema' = "https://awslabs.github.io/duvet/config/v0.4.0.json"

[[source]]
pattern = "./src/**/*.rs"

[[source]]
pattern = "./include/**/*.h"

[[source]]
pattern = "./*.cpp"

[[specification]]
source = "spec/shim/shim.md"

[[specification]]
source = "spec/shim/esdk-shim.md"

[report.snapshot]
enabled = true
23 changes: 23 additions & 0 deletions aws-esdk-cpp/aws-esdk-cpp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Cargo build output
/target/
Cargo.lock

# Compiled demo / test binaries (built via the Makefile)
/basic_hierarchical_keyring_example
/test_esdk

# Object files / archives
*.o
*.a

# Agent tooling scratch / transcripts
.agent-reports/

# CMake build output
/build/
/build-cmake/

# Duvet: generated requirement extraction, snapshot, and reports
.duvet/requirements/
.duvet/snapshot.txt
.duvet/reports/
63 changes: 63 additions & 0 deletions aws-esdk-cpp/aws-esdk-cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# CMake integration for the AWS Encryption SDK C++ bindings (aws-esdk-cpp).
#
# Consumers do:
# add_subdirectory(aws-esdk-cpp)
# target_link_libraries(my_app PRIVATE AWS::esdk)
# #include <aws/esdk/EncryptionSDK.h>
#
# This drives `cargo build` to produce the Rust staticlib and the cxx-generated
# C++ sources, then exposes them behind the AWS::esdk target.
cmake_minimum_required(VERSION 3.20)
project(aws_esdk_cpp LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(ESDK_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
set(ESDK_PROFILE debug)
set(ESDK_TARGET_DIR ${ESDK_ROOT}/target)

# Build the Rust staticlib + cxx-generated sources before we reference them.
execute_process(
COMMAND cargo build
WORKING_DIRECTORY ${ESDK_ROOT}
RESULT_VARIABLE _esdk_cargo_result
)
if(NOT _esdk_cargo_result EQUAL 0)
message(FATAL_ERROR "cargo build failed (exit ${_esdk_cargo_result})")
endif()

set(ESDK_STATICLIB ${ESDK_TARGET_DIR}/${ESDK_PROFILE}/libaws_esdk_cpp.a)
set(ESDK_BRIDGE_CC ${ESDK_TARGET_DIR}/cxxbridge/aws-esdk-cpp/src/lib.rs.cc)

# The cxx runtime archive lives in a hashed build dir; locate it post-build.
file(GLOB_RECURSE _esdk_cxxbridge_rt
${ESDK_TARGET_DIR}/${ESDK_PROFILE}/build/cxx-*/out/libcxxbridge1.a)
list(GET _esdk_cxxbridge_rt 0 ESDK_CXXBRIDGE_RT)

# The public target: compiles the generated C++ bridge and links the Rust lib.
add_library(aws_esdk_cpp STATIC ${ESDK_BRIDGE_CC})
target_include_directories(aws_esdk_cpp PUBLIC
${ESDK_ROOT}/include
${ESDK_TARGET_DIR}/cxxbridge
)
target_link_libraries(aws_esdk_cpp PUBLIC
${ESDK_STATICLIB}
${ESDK_CXXBRIDGE_RT}
pthread
${CMAKE_DL_LIBS}
)
if(APPLE)
target_link_libraries(aws_esdk_cpp PUBLIC
"-framework Security"
"-framework CoreFoundation"
"-framework SystemConfiguration"
)
endif()
add_library(AWS::esdk ALIAS aws_esdk_cpp)

# Build the integration test only when this is the top-level project.
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
add_executable(esdk_integration_test test_esdk.cpp)
target_link_libraries(esdk_integration_test PRIVATE AWS::esdk)
endif()
34 changes: 34 additions & 0 deletions aws-esdk-cpp/aws-esdk-cpp/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[package]
name = "aws-esdk-cpp"
version = "0.1.0"
edition = "2024"
keywords = ["crypto", "cryptography", "security", "encryption", "c++"]
categories = ["cryptography", "external-ffi-bindings"]
license = "ISC AND (Apache-2.0 OR ISC)"
description = "C++ shim exposing the Rust implementation of the AWS Encryption SDK to C++ callers."
repository = "https://github.com/aws/aws-encryption-sdk"
authors = ["AWS-CryptoTools"]
documentation = "https://docs.rs/crate/aws-esdk-cpp"
readme = "README.md"

[lib]
crate-type = ["staticlib", "cdylib"]

[dependencies]
aws-config = "1.8.12"
aws-mpl-legacy = { package = "aws-mpl-native", path = "../../mpl" }
aws-sdk-dynamodb = "1.103.0"
aws-sdk-kms = "1.98.0"
aws-smithy-types = "1.3.6"
cxx = "1.0.194"
tokio = {version = "1.49.0", features = ["full"] }
aws-esdk = { path = "../../esdk" }

[build-dependencies]
cxx-build = "1.0.194"
cc = "1.2.54"

# This nested package is not part of the root workspace (the root member is the
# sibling stub crate). Declare it as its own workspace root so `cargo` builds it
# standalone; `mpl`/`esdk` are consumed as path dependencies above.
[workspace]
43 changes: 43 additions & 0 deletions aws-esdk-cpp/aws-esdk-cpp/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Simple Makefile - all C++ bridge code is compiled into the Rust static library.

# Idiomatic example. Requires C++17 (the idiomatic header uses std::string_view).
# Needs live AWS resources / ESDK_TEST_* env vars to run; builds without them.
example: examples/basic_hierarchical_keyring_example.cpp include/aws/esdk/EncryptionSDK.h src/lib.rs target/debug/libaws_esdk_cpp.a
g++ examples/basic_hierarchical_keyring_example.cpp target/cxxbridge/aws-esdk-cpp/src/lib.rs.cc \
$$(find target/debug/build -path "*/cxx-*/out/libcxxbridge1.a" | head -n1) \
-Ltarget/debug -laws_esdk_cpp \
-Itarget/cxxbridge -Iinclude \
-lpthread -ldl \
-std=c++17 \
-o basic_hierarchical_keyring_example

# Idiomatic-facade integration tests. Requires C++17 (the idiomatic header uses
# std::string_view). Run ./test_esdk with ESDK_TEST_* env vars set (it skips
# cleanly if they are unset).
test_esdk: test_esdk.cpp include/aws/esdk/EncryptionSDK.h src/lib.rs target/debug/libaws_esdk_cpp.a
g++ test_esdk.cpp target/cxxbridge/aws-esdk-cpp/src/lib.rs.cc \
$$(find target/debug/build -path "*/cxx-*/out/libcxxbridge1.a" | head -n1) \
-Ltarget/debug -laws_esdk_cpp \
-Itarget/cxxbridge -Iinclude \
-lpthread -ldl \
-std=c++17 \
-o test_esdk

clean:
rm -f basic_hierarchical_keyring_example test_esdk

clippy:
cargo clippy --tests --examples

test:
cargo build
cargo build --release
make example
make test_esdk

duvet:
@test -e spec || ln -s ../../spec spec
rm -rf .duvet/reports .duvet/requirements
duvet report

.PHONY: all clean duvet test clippy
19 changes: 19 additions & 0 deletions aws-esdk-cpp/aws-esdk-cpp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# aws-esdk-cpp

A C++ shim over the Rust implementation of the AWS Encryption SDK.

This crate exposes the Rust AWS Encryption SDK (`aws-esdk`) to C++ callers through
an idiomatic, generator-agnostic C++ API. Consumers program against
`Aws::Esdk::` types and `#include <aws/esdk/EncryptionSDK.h>`; the underlying
Rust bindings (generated with `cxx`) are an implementation detail hidden behind
the facade.

The shim's own behavioral contract — type translation, resource lifetimes, error
propagation, delegation to the core library — is specified in
[`spec/shim/shim.md`](spec/shim/shim.md) (generic) and
[`spec/shim/esdk-shim.md`](spec/shim/esdk-shim.md) (ESDK-specific), and tracked
with Duvet annotations in the source.

## Status

Work in progress.
11 changes: 11 additions & 0 deletions aws-esdk-cpp/aws-esdk-cpp/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fn main() {
// Generate the cxx bridge code and compile it
cxx_build::bridge("src/lib.rs")
.flag_if_supported("-std=c++11")
.compile("cxxbridge-aws-mpl-cxx");

// Tell cargo to link the C++ standard library
println!("cargo:rustc-link-lib=c++");

println!("cargo:rerun-if-changed=src/lib.rs");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include <iostream>
#include <vector>
#include <aws/esdk/EncryptionSDK.h> // Idiomatic C++ wrapper layer

int main() {
try {
// Create AWS clients
auto client_config = Aws::Esdk::ClientConfig()
.with_max_retry_attempts(5);

auto kms = Aws::Esdk::KmsClient(client_config);
auto ddb = Aws::Esdk::DdbClient(client_config);

// Create keystore with constructor - all config in one place
auto keystore = Aws::Esdk::KeyStore(
"KeyStoreDdbTable", // table_name
"KeyStoreDdbTable", // logical_key_store_name
"arn:aws:kms:us-west-2:370957321024:key/9d989aa2-2f9c-438c-a745-cc57d3ad0126", // kms_arn
kms,
ddb
);

// Create hierarchical keyring with constructor
auto keyring = Aws::Esdk::HierarchicalKeyring(
keystore,
"3ce7656b-e166-40f3-8c9b-a920ce6596cd", // branch_key_id
4242, // ttl_seconds
42 // cache_capacity
);

// Create encryption SDK client
Aws::Esdk::EncryptionSDK sdk;

// Encrypt with std::vector - idiomatic C++
std::vector<uint8_t> plaintext = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'};
auto ciphertext = sdk.encrypt(plaintext, keyring);

// Decrypt
auto decrypted = sdk.decrypt(ciphertext, keyring);

// Validate results
if (plaintext != decrypted.plaintext) {
std::cerr << "Decryption failed: plaintext mismatch\n";
return 1;
}

std::cout << "Success! Encryption and decryption completed successfully.\n";

// Automatic cleanup via RAII - no manual delete calls needed!

} catch (const std::exception &e) {
std::cerr << "Error: " << e.what() << "\n";
return 1;
}

return 0;
}
Loading