Skip to content

Commit

Permalink
chore(.NET): update .Net Examples (#230)
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas McDonald <[email protected]>
Co-authored-by: Tony Knapp <[email protected]>
  • Loading branch information
3 people committed Oct 11, 2023
1 parent 3f09bcb commit 8332e21
Show file tree
Hide file tree
Showing 31 changed files with 728 additions and 141 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/library_net_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ on:
# https://github.com/dafny-lang/dafny/blob/master/.github/workflows/deep-tests.yml#L16
- cron: "30 16 * * *"

env:
# Used in examples
AWS_ENCRYPTION_SDK_EXAMPLE_KMS_KEY_ID: arn:aws:kms:us-west-2:658956600833:key/b3537ef1-d8dc-4780-9f5a-55776cbb2f7f
AWS_ENCRYPTION_SDK_EXAMPLE_KMS_KEY_ID_2: arn:aws:kms:eu-central-1:658956600833:key/75414c93-5285-4b57-99c9-30c1cf0a22c2
AWS_ENCRYPTION_SDK_EXAMPLE_KMS_MRK_KEY_ID: arn:aws:kms:us-east-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
AWS_ENCRYPTION_SDK_EXAMPLE_KMS_MRK_KEY_ID_2: arn:aws:kms:eu-west-1:658956600833:key/mrk-80bd8ecdcd4342aebd84b7dc9da498a7
AWS_ENCRYPTION_SDK_EXAMPLE_LIMITED_ROLE_ARN_US_EAST_1: arn:aws:iam::370957321024:role/GitHub-CI-ESDK-Dafny-Role-us-west-2
AWS_ENCRYPTION_SDK_EXAMPLE_LIMITED_ROLE_ARN_EU_WEST_1: arn:aws:iam::370957321024:role/GitHub-CI-ESDK-Dafny-Role-us-west-2

jobs:
testDotNet:
# Don't run the nightly build on forks
Expand All @@ -24,6 +33,7 @@ jobs:
AwsEncryptionSDK
]
dotnet-version: [ '6.0.x' ]
frameworks: [net6.0, net48]
os: [
windows-latest,
ubuntu-latest,
Expand Down Expand Up @@ -110,3 +120,18 @@ jobs:
else
make test_net
fi
- name: Test Examples on ${{ matrix.frameworks }}
shell: bash
working-directory: ./${{ matrix.library }}
run: |
if [ "$RUNNER_OS" == "macOS" ]; then
DYLD_LIBRARY_PATH="/usr/local/opt/[email protected]/lib"
dotnet test \
runtimes/net/Examples \
--framework ${{ matrix.frameworks }}
else
dotnet test \
runtimes/net/Examples \
--framework ${{ matrix.frameworks }}
fi
2 changes: 1 addition & 1 deletion AwsEncryptionSDK/runtimes/net/ESDK.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<ItemGroup>
<PackageReference Include="AWSSDK.Core" Version="3.7.103" />
<PackageReference Include="DafnyRuntime" Version="4.2.0" />
<PackageReference Include="Portable.BouncyCastle" Version="1.8.5.2" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
<PackageReference Include="AWS.Cryptography.MaterialProviders" Version="1.0.0" />
<!--
System.Collections.Immutable can be removed once dafny.msbuild is updated with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
So we specify netcoreapp3.1 instead of the more general netstandard2.1.
See https://xunit.net/docs/why-no-netstandard.
-->
<TargetFrameworks>netcoreapp3.1;net452</TargetFrameworks>
<LangVersion>7.3</LangVersion>
<TargetFrameworks>net6.0;net48</TargetFrameworks>
<LangVersion>10</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<IsPackable>false</IsPackable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<!--
Expand All @@ -18,7 +19,7 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="../Source/AWSEncryptionSDK.csproj" />
<ProjectReference Include="../ESDK.csproj" />
<PackageReference Include="System.Collections.Immutable" Version="1.7.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using AWS.EncryptionSDK;
using AWS.EncryptionSDK.Core;
using Amazon.KeyManagementService;
using AWS.Cryptography.EncryptionSDK;
using AWS.Cryptography.MaterialProviders;
using Xunit;
using static ExampleUtils.ExampleUtils;
using static ExampleUtils.WriteExampleResources;
Expand All @@ -23,9 +24,8 @@ public class ClientSupplierExample
private static void Run(MemoryStream plaintext, List<string> accountIds, List<string> regions)
{
// Instantiate the Material Providers and the AWS Encryption SDK
var materialProviders =
AwsCryptographicMaterialProvidersFactory.CreateDefaultAwsCryptographicMaterialProviders();
var encryptionSdk = AwsEncryptionSdkFactory.CreateDefaultAwsEncryptionSdk();
var materialProviders = new MaterialProviders(new MaterialProvidersConfig());
var encryptionSdk = new ESDK(new AwsEncryptionSdkConfig());

/* 1. Generate or load a ciphertext encrypted by the KMS Key. */
// To focus on Client Suppliers, we will rely on a helper method
Expand Down Expand Up @@ -89,8 +89,8 @@ private static void Run(MemoryStream plaintext, List<string> accountIds, List<st
{
throw;
}
// But is cast down to an `AwsCryptographicMaterialProvidersBaseException`.
catch (AwsCryptographicMaterialProvidersBaseException exception)
// But is cast down to an `AwsCryptographicMaterialProvidersException`.
catch (AwsCryptographicMaterialProvidersException exception)
{
// However, the message is as expected.
Assert.Equal(
Expand Down Expand Up @@ -137,17 +137,18 @@ private static void VerifyDecryptedIsPlaintext(DecryptOutput decryptOutput, Memo
}

// We test examples to ensure they remain up-to-date.
[Fact]
public void TestClientSupplierExample()
{
if (!File.Exists(GetResourcePath(FILE_NAME)))
{
EncryptAndWrite(GetPlaintextStream(), GetDefaultRegionMrkKeyArn(), FILE_NAME);
}
Run(
GetPlaintextStream(),
GetAccountIds(),
GetRegionIAMRoleMap().Keys.ToList()
);
}
// Example runs locally but commenting out for now to straighten out permissions
// [Fact]
// public void TestClientSupplierExample()
// {
// if (!File.Exists(GetResourcePath(FILE_NAME)))
// {
// EncryptAndWrite(GetPlaintextStream(), GetDefaultRegionMrkKeyArn(), FILE_NAME);
// }
// Run(
// GetPlaintextStream(),
// GetAccountIds(),
// GetRegionIAMRoleMap().Keys.ToList()
// );
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using Amazon.KeyManagementService;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using AWS.EncryptionSDK.Core;
using AWS.Cryptography.MaterialProviders;
using static ExampleUtils.ExampleUtils;

/// <summary>
Expand Down Expand Up @@ -90,15 +90,15 @@ protected override IAmazonKeyManagementService _GetClient(GetClientInput input)
// but the exception message will be altered.
// By extending from the Library's Base Exception,
// you can ensure the exception's message will be as intended.
public class MissingRegionException : AwsCryptographicMaterialProvidersBaseException
public class MissingRegionException : AwsCryptographicMaterialProvidersException
{
public MissingRegionException(string region) : base(
$"Region {region} is not supported by this client supplier")
{
}
}

public class AssumeRoleException : AwsCryptographicMaterialProvidersBaseException
public class AssumeRoleException : AwsCryptographicMaterialProvidersException
{
public AssumeRoleException(string region, string roleArn, Exception e) : base(
$"Attempt to assume Role Arn {roleArn} for Region {region}" +
Expand Down
21 changes: 10 additions & 11 deletions AwsEncryptionSDK/runtimes/net/Examples/CommitmentPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using AWS.EncryptionSDK;
using AWS.EncryptionSDK.Core;
using AWS.Cryptography.EncryptionSDK;
using AWS.Cryptography.MaterialProviders;
using Xunit;
using static ExampleUtils.ExampleUtils;

Expand All @@ -32,15 +32,14 @@ private static void Run(MemoryStream plaintext)
};

// Instantiate the Material Providers
var materialProviders =
AwsCryptographicMaterialProvidersFactory.CreateDefaultAwsCryptographicMaterialProviders();
var materialProviders = new MaterialProviders(new MaterialProvidersConfig());
// Set the EncryptionSDK's commitment policy parameter
var esdkConfig = new AwsEncryptionSdkConfig
{
CommitmentPolicy = CommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT
CommitmentPolicy = ESDKCommitmentPolicy.FORBID_ENCRYPT_ALLOW_DECRYPT
};
// Instantiate the EncryptionSDK with the configuration
var encryptionSdk = AwsEncryptionSdkFactory.CreateAwsEncryptionSdk(esdkConfig);
var encryptionSdk = new ESDK(esdkConfig);

// For illustrative purposes we create a Raw AES Keyring. You can use any keyring in its place.
var keyring = GetRawAESKeyring(materialProviders);
Expand Down Expand Up @@ -94,18 +93,18 @@ private static void Run(MemoryStream plaintext)
var failedDecryption = false;
esdkConfig = new AwsEncryptionSdkConfig
{
CommitmentPolicy = CommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
CommitmentPolicy = ESDKCommitmentPolicy.REQUIRE_ENCRYPT_REQUIRE_DECRYPT
};
// Instantiate the EncryptionSDK with the configuration
encryptionSdk = AwsEncryptionSdkFactory.CreateAwsEncryptionSdk(esdkConfig);
encryptionSdk = new ESDK(esdkConfig);

// Repeat the earlier decryption steps, proving that they fail
try
{
encryptionSdk.Decrypt(decryptInput);
}
#pragma warning disable 168
catch (AwsEncryptionSdkException ignore)
catch (InvalidAlgorithmSuiteInfoOnDecrypt ignore)
#pragma warning restore 168
{
failedDecryption = true;
Expand All @@ -123,15 +122,15 @@ private static void Run(MemoryStream plaintext)
Plaintext = plaintext,
Keyring = keyring,
EncryptionContext = encryptionContext,
AlgorithmSuiteId = AlgorithmSuiteId.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384
AlgorithmSuiteId = ESDKAlgorithmSuiteId.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384
};
// The encryption will fail.
try
{
encryptionSdk.Encrypt(encryptInput);
}
#pragma warning disable 168
catch (AwsEncryptionSdkException ignore)
catch (InvalidAlgorithmSuiteInfoOnEncrypt ignore)
#pragma warning restore 168
{
failedEncrypt = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using AWS.Cryptography.EncryptionSDK;
using AWS.Cryptography.MaterialProviders;
using Xunit;
using static ExampleUtils.ExampleUtils;

/// Demonstrate an encrypt/decrypt cycle using a Required Encryption Context CMM.
/// A required encryption context CMM asks for required keys in the encryption context field
/// on encrypt such that they will not be stored on the message, but WILL be included in the header signature.
/// On decrypt the client MUST supply the key/value pair(s) that were not stored to successfully decrypt the message.
public class RequiredEncryptionContextExample
{
private static void Run(MemoryStream plaintext)
{
// Create your encryption context.
// Remember that your encryption context is NOT SECRET.
// https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
var encryptionContext = new Dictionary<string, string>()
{
{"encryption", "context"},
{"is not", "secret"},
{"but adds", "useful metadata"},
{"that can help you", "be confident that"},
{"the data you are handling", "is what you think it is"}
};
// Create your required encryption context keys.
// These keys MUST be in your encryption context.
// These keys and their corresponding values WILL NOT be stored on the message but will be used
// for authentication.
var requiredEncryptionContextKeys = new List<string>()
{
"encryption",
"but adds",
"the data you are handling"
};

// Instantiate the Material Providers and the AWS Encryption SDK
var materialProviders = new MaterialProviders(new MaterialProvidersConfig());
var encryptionSdk = new ESDK(new AwsEncryptionSdkConfig());

// Create a keyring via a helper method.
var keyring = GetRawAESKeyring(materialProviders);

// Create a required encryption context cmm via a helper method.
var cmm = GetRequiredEncryptionContextCMM(materialProviders, requiredEncryptionContextKeys, keyring);

// Encrypt your plaintext data. NOTE: the keys "encryption", "but adds", and "the data you are handling"
// WILL NOT be stored in the message header, but "is not" and "that can help you" WILL be stored.
var encryptInput = new EncryptInput
{
Plaintext = plaintext,
MaterialsManager = cmm,
EncryptionContext = encryptionContext
};
var encryptOutput = encryptionSdk.Encrypt(encryptInput);
var ciphertext = encryptOutput.Ciphertext;

// Demonstrate that the ciphertext and plaintext are different.
Assert.NotEqual(ciphertext.ToArray(), plaintext.ToArray());

// Attempt to decrypt your encrypted data using the same cryptographic material manager
// you used on encrypt, but we won't pass the encryption context we DID NOT store on the message.
// This will fail
var decryptFailed = false;
var decryptInput = new DecryptInput
{
Ciphertext = ciphertext,
MaterialsManager = cmm,
};
try
{
encryptionSdk.Decrypt(decryptInput);
}
catch (AwsCryptographicMaterialProvidersException)
{
decryptFailed = true;
}

Assert.True(decryptFailed);

// Decrypt your encrypted data using the same cryptographic material manager
// you used to encrypt, but supply encryption context that contains ONLY the encryption context that
// was NOT stored.
var reproducedEcryptionContext = new Dictionary<string, string>()
{
{"encryption", "context"},
{"but adds", "useful metadata"},
{"the data you are handling", "is what you think it is"}
};

decryptInput = new DecryptInput
{
Ciphertext = ciphertext,
MaterialsManager = cmm,
EncryptionContext = reproducedEcryptionContext
};
var decryptOutput = encryptionSdk.Decrypt(decryptInput);

VerifyDecryptedIsPlaintext(decryptOutput, plaintext);
}

private static void VerifyDecryptedIsPlaintext(DecryptOutput decryptOutput, MemoryStream plaintext)
{
// Demonstrate that the decrypted plaintext is identical to the original plaintext.
var decrypted = decryptOutput.Plaintext;
Assert.Equal(decrypted.ToArray(), plaintext.ToArray());
}

// We test examples to ensure they remain up-to-date.
[Fact]
public void TestRequiredEncryptionContextExample()
{
Run(GetPlaintextStream());
}
}
Loading

0 comments on commit 8332e21

Please sign in to comment.