diff --git a/all-examples/README.md b/all-examples/README.md new file mode 100644 index 00000000..59bc2d6c --- /dev/null +++ b/all-examples/README.md @@ -0,0 +1,74 @@ +# S3 Encryption Client Examples + +This directory contains example projects for the Amazon S3 Encryption Client across different programming languages and major versions. + +## Directory Structure + +Each language has subdirectories for different major versions of the S3 Encryption Client: + +- `cpp/` - C++ examples + - `v2/` - S3EC C++ v2 example (transitional) + - `v3/` - S3EC C++ v3 example (improved) +- `dotnet/` - .NET examples + - `v3/` - S3EC .NET v3 example (transitional) + - `v4/` - S3EC .NET v4 example (improved) +- `go/` - Go examples + - `v3/` - S3EC Go v3 example (transitional) + - `v4/` - S3EC Go v4 example (improved) +- `java/` - Java examples + - `v3/` - S3EC Java v3 example (transitional) + - `v4/` - S3EC Java v4 example (improved) +- `php/` - PHP examples + - `v2/` - S3EC PHP v2 example (transitional) + - `v3/` - S3EC PHP v3 example (improved) +- `ruby/` - Ruby examples + - `v2/` - S3EC Ruby v2 example (transitional) + - `v3/` - S3EC Ruby v3 example (improved) + +## Setup Instructions + +### Prerequisites + +1. **Git Submodules**: Some examples depend on staging versions of the S3EC libraries that are included as git submodules. Initialize and update submodules: + + ```bash + git submodule update --init --recursive + ``` + +2. **AWS Credentials**: Configure your AWS credentials using one of the following methods: + - AWS CLI: `aws configure` + - Environment variables: `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` + - IAM roles (for EC2 instances) + +3. **KMS Key**: Use "arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01" by default, or create a KMS key in your AWS account and note the key ID for use in examples. + +### Language-Specific Setup + +Each language directory contains specific setup instructions in its README file. Generally: + +- **Java**: Requires JDK 11+ and Gradle +- **Go**: Requires Go 1.21+ +- **.NET**: Requires .NET 8.0+ +- **PHP**: Requires PHP 7.4+ and Composer +- **Ruby**: Requires Ruby 3.0+ and Bundler +- **C++**: Requires CMake 3.16+ and C++17 compiler + +## Usage + +Each example directory contains: + +- Build configuration files (e.g., `build.gradle.kts`, `go.mod`, `composer.json`) +- Source code demonstrating basic S3EC usage +- README with specific setup and run instructions + +## Dependencies + +Examples use different dependency sources based on version: + +- **Released versions**: Use public package repositories (Maven Central, npm, etc.) +- **Staging versions**: Use git submodules pointing to staging repositories +- **Local versions**: Reference locally built libraries + +## Support + +For issues with specific examples, refer to the individual README files in each language/version directory. diff --git a/all-examples/ruby/v2/Gemfile b/all-examples/ruby/v2/Gemfile new file mode 100644 index 00000000..5f51bf18 --- /dev/null +++ b/all-examples/ruby/v2/Gemfile @@ -0,0 +1,12 @@ +source 'https://rubygems.org' + +ruby '>= 2.7.0' + +gem 'aws-sdk-s3', path: 'local-ruby-sdk/gems/aws-sdk-s3' +gem 'aws-sdk-kms', path: 'local-ruby-sdk/gems/aws-sdk-kms' +gem 'json', '~> 2.0' +gem 'rexml', '~> 3.0' + +group :development do + gem 'rubocop', '~> 1.0' +end diff --git a/all-examples/ruby/v2/Gemfile.lock b/all-examples/ruby/v2/Gemfile.lock new file mode 100644 index 00000000..7c4a32c4 --- /dev/null +++ b/all-examples/ruby/v2/Gemfile.lock @@ -0,0 +1,82 @@ +PATH + remote: local-ruby-sdk/gems/aws-sdk-kms + specs: + aws-sdk-kms (1.115.0) + aws-sdk-core (~> 3, >= 3.234.0) + aws-sigv4 (~> 1.5) + +PATH + remote: local-ruby-sdk/gems/aws-sdk-s3 + specs: + aws-sdk-s3 (1.201.0) + aws-sdk-core (~> 3, >= 3.234.0) + aws-sdk-kms (~> 1) + aws-sigv4 (~> 1.5) + +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.3) + aws-eventstream (1.4.0) + aws-partitions (1.1177.0) + aws-sdk-core (3.235.0) + aws-eventstream (~> 1, >= 1.3.0) + aws-partitions (~> 1, >= 1.992.0) + aws-sigv4 (~> 1.9) + base64 + bigdecimal + jmespath (~> 1, >= 1.6.1) + logger + aws-sigv4 (1.12.1) + aws-eventstream (~> 1, >= 1.0.2) + base64 (0.3.0) + bigdecimal (3.3.1) + jmespath (1.6.2) + json (2.15.2) + language_server-protocol (3.17.0.5) + lint_roller (1.1.0) + logger (1.7.0) + parallel (1.27.0) + parser (3.3.10.0) + ast (~> 2.4.1) + racc + prism (1.6.0) + racc (1.8.1) + rainbow (3.1.1) + regexp_parser (2.11.3) + rexml (3.4.4) + rubocop (1.81.6) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.47.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.47.1) + parser (>= 3.3.7.2) + prism (~> 1.4) + ruby-progressbar (1.13.0) + unicode-display_width (3.2.0) + unicode-emoji (~> 4.1) + unicode-emoji (4.1.0) + +PLATFORMS + arm64-darwin-24 + ruby + +DEPENDENCIES + aws-sdk-kms! + aws-sdk-s3! + json (~> 2.0) + rexml (~> 3.0) + rubocop (~> 1.0) + +RUBY VERSION + ruby 3.4.7p58 + +BUNDLED WITH + 2.7.2 diff --git a/all-examples/ruby/v2/Makefile b/all-examples/ruby/v2/Makefile new file mode 100644 index 00000000..cfa1adef --- /dev/null +++ b/all-examples/ruby/v2/Makefile @@ -0,0 +1,70 @@ +# Makefile for S3 Encryption Client Ruby v2 Example + +# Default target +.PHONY: all install clean run help + +# Variables +SCRIPT = main.rb + +# Default arguments for running the example +# Override these when calling make run +BUCKET_NAME ?= avp-21638 +OBJECT_KEY ?= s3ec-ruby-v2 +KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 +AWS_REGION ?= us-east-2 + +all: install + +# Install dependencies using Bundler +install: + @echo "Installing Ruby dependencies..." + @bundle install + @echo "Dependencies installed successfully!" + +# Clean bundle artifacts +clean: + @echo "Cleaning bundle artifacts..." + @bundle clean --force + @echo "Clean completed!" + +# Run the example with default arguments +run: install + @echo "Running S3 Encryption Client v2 Ruby example..." + @echo "Bucket: $(BUCKET_NAME)" + @echo "Object Key: $(OBJECT_KEY)" + @echo "KMS Key ID: $(KMS_KEY_ID)" + @echo "Region: $(AWS_REGION)" + @echo "" + @bundle exec ruby $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) + +# Run with custom arguments +# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region +run-custom: install + @bundle exec ruby $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) + +# Show help +help: + @echo "S3 Encryption Client Ruby v2 Example Makefile" + @echo "" + @echo "Available targets:" + @echo " install - Install Ruby dependencies using Bundler" + @echo " run - Install dependencies and run the example with default parameters" + @echo " run-custom - Install dependencies and run with custom parameters" + @echo " clean - Remove bundle artifacts" + @echo " help - Show this help message" + @echo "" + @echo "Default parameters:" + @echo " BUCKET_NAME = $(BUCKET_NAME)" + @echo " OBJECT_KEY = $(OBJECT_KEY)" + @echo " KMS_KEY_ID = $(KMS_KEY_ID)" + @echo " AWS_REGION = $(AWS_REGION)" + @echo "" + @echo "To run with custom parameters:" + @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" + @echo "" + @echo "Prerequisites:" + @echo " - Ruby 3.0+ installed on the system" + @echo " - Bundler gem installed (gem install bundler)" + @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" + @echo " - Valid S3 bucket and KMS key with appropriate permissions" + @echo " - S3 Encryption Client v2 Ruby SDK (included in local-ruby-sdk)" diff --git a/all-examples/ruby/v2/local-ruby-sdk b/all-examples/ruby/v2/local-ruby-sdk new file mode 120000 index 00000000..7abd378c --- /dev/null +++ b/all-examples/ruby/v2/local-ruby-sdk @@ -0,0 +1 @@ +../../../test-server/ruby-v2-server/local-ruby-sdk \ No newline at end of file diff --git a/all-examples/ruby/v2/main.rb b/all-examples/ruby/v2/main.rb new file mode 100644 index 00000000..51d85cc9 --- /dev/null +++ b/all-examples/ruby/v2/main.rb @@ -0,0 +1,147 @@ +#!/usr/bin/env ruby + +require 'aws-sdk-s3' +require 'aws-sdk-kms' +require 'json' + +def main + # Check command line arguments + if ARGV.length != 4 + puts "Usage: #{$0} " + puts "Example: #{$0} avp-21638 s3ec-ruby-v2 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2" + exit 1 + end + + bucket_name = ARGV[0] + object_key = ARGV[1] + kms_key_id = ARGV[2] + region = ARGV[3] + + puts "=== S3 Encryption Client v2 Example (Ruby) ===" + puts "Bucket: #{bucket_name}" + puts "Object Key: #{object_key}" + puts "KMS Key ID: #{kms_key_id}" + puts "Region: #{region}" + puts + + begin + # Test data for encryption + test_data = "Hello, World! This is a test message for S3 encryption client v2 in Ruby." + puts "Original data: #{test_data}" + puts "Data length: #{test_data.length} bytes" + puts + + puts "--- Initialize S3 Encryption Client v2 ---" + + # Create regular S3 client + s3_client = Aws::S3::Client.new(region: region) + + # Create KMS client + kms_client = Aws::KMS::Client.new(region: region) + + # Create S3 Encryption Client v2 + encryption_client = Aws::S3::EncryptionV2::Client.new( + client: s3_client, + kms_key_id: kms_key_id, + kms_client: kms_client, + key_wrap_schema: :kms_context, + content_encryption_schema: :aes_gcm_no_padding, + security_profile: :v2 + ) + + puts "Successfully initialized S3 Encryption Client v2" + puts "--- Encrypt and Upload Object to S3 ---" + + # Add encryption context + encryption_context = { + 'purpose' => 'example', + 'version' => 'v2', + 'language' => 'ruby' + } + + # Upload encrypted object using S3 Encryption Client + put_response = encryption_client.put_object({ + bucket: bucket_name, + key: object_key, + body: test_data, + kms_encryption_context: encryption_context + }) + + puts "Successfully uploaded encrypted object to S3!" + puts " Bucket: #{bucket_name}" + puts " Key: #{object_key}" + puts " Encryption Context: #{encryption_context}" + puts + + puts "--- Download and Decrypt Object from S3 ---" + + # Download and decrypt object using S3 Encryption Client + get_response = encryption_client.get_object({ + bucket: bucket_name, + key: object_key, + kms_encryption_context: encryption_context + }) + + # Read the decrypted data + decrypted_data = get_response.body.read + + puts "Successfully downloaded and decrypted object from S3!" + puts " Object size: #{decrypted_data.length} bytes" + puts " Decrypted data: #{decrypted_data}" + puts + + puts "--- Verify Roundtrip Success ---" + + # Verify the roundtrip was successful + if decrypted_data == test_data + puts "SUCCESS: Roundtrip encryption/decryption completed successfully!" + puts " Original data matches decrypted data" + puts " Data integrity verified" + else + puts "ERROR: Roundtrip failed - data mismatch" + puts " Original: #{test_data}" + puts " Decrypted: #{decrypted_data}" + exit 1 + end + + # Optionally Delete the Object + #puts "--- Cleanup ---" + # Clean up the test object using regular S3 client + # s3_client.delete_object({ + # bucket: bucket_name, + # key: object_key + # }) + # puts "Test object deleted from S3" + + puts + puts "=== Example completed successfully! ===" + + rescue Aws::S3::Errors::NoSuchBucket => e + puts "Error: S3 bucket '#{bucket_name}' does not exist or is not accessible" + puts " #{e.message}" + exit 1 + rescue Aws::KMS::Errors::NotFoundException => e + puts "Error: KMS key '#{kms_key_id}' not found or not accessible" + puts " #{e.message}" + exit 1 + rescue Aws::S3::EncryptionV2::Errors::EncryptionError => e + puts "S3 Encryption Error: #{e.message}" + exit 1 + rescue Aws::S3::EncryptionV2::Errors::DecryptionError => e + puts "S3 Decryption Error: #{e.message}" + exit 1 + rescue Aws::Errors::ServiceError => e + puts "AWS Service Error: #{e.message}" + puts " Error Code: #{e.code}" if e.respond_to?(:code) + exit 1 + rescue StandardError => e + puts "Unexpected error: #{e.message}" + puts e.backtrace.first(5) + exit 1 + end +end + +# Run the main function if this script is executed directly +if __FILE__ == $0 + main +end diff --git a/all-examples/ruby/v3/Gemfile b/all-examples/ruby/v3/Gemfile new file mode 100644 index 00000000..5f51bf18 --- /dev/null +++ b/all-examples/ruby/v3/Gemfile @@ -0,0 +1,12 @@ +source 'https://rubygems.org' + +ruby '>= 2.7.0' + +gem 'aws-sdk-s3', path: 'local-ruby-sdk/gems/aws-sdk-s3' +gem 'aws-sdk-kms', path: 'local-ruby-sdk/gems/aws-sdk-kms' +gem 'json', '~> 2.0' +gem 'rexml', '~> 3.0' + +group :development do + gem 'rubocop', '~> 1.0' +end diff --git a/all-examples/ruby/v3/Makefile b/all-examples/ruby/v3/Makefile new file mode 100644 index 00000000..b27bf29f --- /dev/null +++ b/all-examples/ruby/v3/Makefile @@ -0,0 +1,70 @@ +# Makefile for S3 Encryption Client Ruby v3 Example + +# Default target +.PHONY: all install clean run help + +# Variables +SCRIPT = main.rb + +# Default arguments for running the example +# Override these when calling make run +BUCKET_NAME ?= avp-21638 +OBJECT_KEY ?= s3ec-ruby-v3 +KMS_KEY_ID ?= arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 +AWS_REGION ?= us-east-2 + +all: install + +# Install dependencies using Bundler +install: + @echo "Installing Ruby dependencies..." + @bundle install + @echo "Dependencies installed successfully!" + +# Clean bundle artifacts +clean: + @echo "Cleaning bundle artifacts..." + @bundle clean --force + @echo "Clean completed!" + +# Run the example with default arguments +run: install + @echo "Running S3 Encryption Client v3 Ruby example..." + @echo "Bucket: $(BUCKET_NAME)" + @echo "Object Key: $(OBJECT_KEY)" + @echo "KMS Key ID: $(KMS_KEY_ID)" + @echo "Region: $(AWS_REGION)" + @echo "" + @bundle exec ruby $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) + +# Run with custom arguments +# Usage: make run-custom BUCKET_NAME=my-bucket OBJECT_KEY=my-key KMS_KEY_ID=my-kms-key AWS_REGION=my-region +run-custom: install + @bundle exec ruby $(SCRIPT) $(BUCKET_NAME) $(OBJECT_KEY) $(KMS_KEY_ID) $(AWS_REGION) + +# Show help +help: + @echo "S3 Encryption Client Ruby v3 Example Makefile" + @echo "" + @echo "Available targets:" + @echo " install - Install Ruby dependencies using Bundler" + @echo " run - Install dependencies and run the example with default parameters" + @echo " run-custom - Install dependencies and run with custom parameters" + @echo " clean - Remove bundle artifacts" + @echo " help - Show this help message" + @echo "" + @echo "Default parameters:" + @echo " BUCKET_NAME = $(BUCKET_NAME)" + @echo " OBJECT_KEY = $(OBJECT_KEY)" + @echo " KMS_KEY_ID = $(KMS_KEY_ID)" + @echo " AWS_REGION = $(AWS_REGION)" + @echo "" + @echo "To run with custom parameters:" + @echo " make run BUCKET_NAME=your-bucket OBJECT_KEY=your-key KMS_KEY_ID=your-kms-key AWS_REGION=your-region" + @echo "" + @echo "Prerequisites:" + @echo " - Ruby 3.0+ installed on the system" + @echo " - Bundler gem installed (gem install bundler)" + @echo " - AWS credentials configured (AWS CLI, environment variables, or IAM role)" + @echo " - Valid S3 bucket and KMS key with appropriate permissions" + @echo " - S3 Encryption Client v3 Ruby SDK (included in local-ruby-sdk)" diff --git a/all-examples/ruby/v3/local-ruby-sdk b/all-examples/ruby/v3/local-ruby-sdk new file mode 120000 index 00000000..49be2657 --- /dev/null +++ b/all-examples/ruby/v3/local-ruby-sdk @@ -0,0 +1 @@ +../../../test-server/ruby-v3-server/local-ruby-sdk \ No newline at end of file diff --git a/all-examples/ruby/v3/main.rb b/all-examples/ruby/v3/main.rb new file mode 100644 index 00000000..fb15f317 --- /dev/null +++ b/all-examples/ruby/v3/main.rb @@ -0,0 +1,145 @@ +#!/usr/bin/env ruby + +require 'aws-sdk-s3' +require 'aws-sdk-kms' +require 'json' + +def main + # Check command line arguments + if ARGV.length != 4 + puts "Usage: #{$0} " + puts "Example: #{$0} avp-21638 s3ec-ruby-v3 arn:aws:kms:us-east-2:648638458147:key/a47079da-17e4-45a5-b82e-2bac101cad01 us-east-2" + exit 1 + end + + bucket_name = ARGV[0] + object_key = ARGV[1] + kms_key_id = ARGV[2] + region = ARGV[3] + + puts "=== S3 Encryption Client v3 Example (Ruby) ===" + puts "Bucket: #{bucket_name}" + puts "Object Key: #{object_key}" + puts "KMS Key ID: #{kms_key_id}" + puts "Region: #{region}" + puts + + begin + # Test data for encryption + test_data = "Hello, World! This is a test message for S3 encryption client v3 in Ruby." + puts "Original data: #{test_data}" + puts "Data length: #{test_data.length} bytes" + puts + + puts "--- Initialize S3 Encryption Client v3 ---" + + # Create regular S3 client + s3_client = Aws::S3::Client.new(region: region) + + # Create KMS client + kms_client = Aws::KMS::Client.new(region: region) + + # Create S3 Encryption Client v3 + encryption_client = Aws::S3::EncryptionV3::Client.new( + client: s3_client, + kms_key_id: kms_key_id, + kms_client: kms_client, + key_wrap_schema: :kms_context + ) + + puts "Successfully initialized S3 Encryption Client v3" + puts "--- Encrypt and Upload Object to S3 ---" + + # Add encryption context + encryption_context = { + 'purpose' => 'example', + 'version' => 'v3', + 'language' => 'ruby' + } + + # Upload encrypted object using S3 Encryption Client + put_response = encryption_client.put_object({ + bucket: bucket_name, + key: object_key, + body: test_data, + kms_encryption_context: encryption_context + }) + + puts "Successfully uploaded encrypted object to S3!" + puts " Bucket: #{bucket_name}" + puts " Key: #{object_key}" + puts " Encryption Context: #{encryption_context}" + puts + + puts "--- Download and Decrypt Object from S3 ---" + + # Download and decrypt object using S3 Encryption Client + get_response = encryption_client.get_object({ + bucket: bucket_name, + key: object_key, + kms_encryption_context: encryption_context + }) + + # Read the decrypted data + decrypted_data = get_response.body.read + + puts "Successfully downloaded and decrypted object from S3!" + puts " Object size: #{decrypted_data.length} bytes" + puts " Decrypted data: #{decrypted_data}" + puts + + puts "--- Verify Roundtrip Success ---" + + # Verify the roundtrip was successful + if decrypted_data == test_data + puts "SUCCESS: Roundtrip encryption/decryption completed successfully!" + puts " Original data matches decrypted data" + puts " Data integrity verified" + else + puts "ERROR: Roundtrip failed - data mismatch" + puts " Original: #{test_data}" + puts " Decrypted: #{decrypted_data}" + exit 1 + end + + # Optionally Delete the Object + #puts "--- Cleanup ---" + # Clean up the test object using regular S3 client + # s3_client.delete_object({ + # bucket: bucket_name, + # key: object_key + # }) + # puts "Test object deleted from S3" + + puts + puts "=== Example completed successfully! ===" + + rescue Aws::S3::Errors::NoSuchBucket => e + puts "Error: S3 bucket '#{bucket_name}' does not exist or is not accessible" + puts " #{e.message}" + exit 1 + rescue Aws::KMS::Errors::NotFoundException => e + puts "Error: KMS key '#{kms_key_id}' not found or not accessible" + puts " #{e.message}" + exit 1 + rescue Aws::S3::EncryptionV3::Errors::EncryptionError => e + puts "S3 Encryption Error: #{e.message}" + exit 1 + rescue Aws::S3::EncryptionV3::Errors::DecryptionError => e + puts "S3 Decryption Error: #{e.message}" + exit 1 + rescue Aws::Errors::ServiceError => e + puts "AWS Service Error: #{e.message}" + puts " Error Code: #{e.code}" if e.respond_to?(:code) + exit 1 + rescue StandardError => e + puts "Unexpected error: #{e.message}" + puts e.backtrace.first(5) + exit 1 + end +end + +# Run the main function if this script is executed directly +if __FILE__ == $0 + main +end