Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2e12a9e
breaking interface on Crypto EnvelopeEncrypt
chief-micco Aug 31, 2025
4bd9ca8
in-progress
chief-micco Sep 1, 2025
f044a21
main
chief-micco Sep 4, 2025
fb4ab20
Making the new IKeyMetastore
chief-micco Sep 6, 2025
33ba57f
Code quality fixes
chief-micco Sep 7, 2025
5f7cb78
Code quality fixes
chief-micco Sep 7, 2025
c749995
new envelopeencryption in progess
chief-micco Sep 7, 2025
89d8549
Implementing the Decrypt methods
chief-micco Sep 8, 2025
c9781d8
added new interface for kms
chief-micco Sep 8, 2025
ba14b08
Implemented new KeyManagement encrypt
chief-micco Sep 8, 2025
13bc190
implemented Decrypt
chief-micco Sep 8, 2025
c12db3f
tests for new KeyManagementService in aws extensions
chief-micco Sep 9, 2025
5d1371e
Fixes to stub to allow output streams to be publicly visible
chief-micco Sep 9, 2025
117cdd0
improved tests
chief-micco Sep 9, 2025
2950d15
finished implementation
chief-micco Sep 10, 2025
3a5b0c7
change stub to work based on old impl logic
chief-micco Sep 10, 2025
b4fbe21
main
chief-micco Sep 10, 2025
f6fa226
tests for the new EnvelopeEncryption in progress
chief-micco Sep 11, 2025
ce2441c
Added async tests for old kms implementation
chief-micco Sep 17, 2025
81029ca
added async envelope tests
chief-micco Sep 17, 2025
fdd1ecd
merged main
chief-micco Sep 17, 2025
771a301
changed Extensions library to PlugIns library
chief-micco Oct 1, 2025
e7803ff
main
chief-micco Nov 12, 2025
37c7853
main
chief-micco Nov 15, 2025
04491b9
updated nuget references and merged main
chief-micco Nov 15, 2025
d52e6c0
merged main
chief-micco Jan 8, 2026
9e153c8
Updated nuget references
chief-micco Jan 10, 2026
44fdb25
Add Builder pattern and KeySuffix option to DynamoDbMetastore
chief-micco Jan 11, 2026
40ef0f1
add placeholder for metastore compatibility tests
chief-micco Jan 11, 2026
7e1a4bd
compatibility tests already exist
chief-micco Jan 12, 2026
88b8e4b
moved test implemenation to a plugins.testing
chief-micco Jan 12, 2026
953c726
Add Core namespace with modernized session and partition abstractions
chief-micco Jan 20, 2026
40f5384
merged main
chief-micco Feb 4, 2026
5aa6d92
merged main and updated additional packages
chief-micco Feb 5, 2026
37cafc6
update nuget packages
chief-micco Mar 13, 2026
16b6ecf
C# AppEncryption: new metastore, Core session factory, Static KMS in …
chief-micco Mar 14, 2026
ea98a6a
Add Regression/Metastore integration tests: DynamoDbGlobalTableTest (…
chief-micco Mar 15, 2026
b50822a
docs: add SessionFactory upgrade guide and KeyMetastore section to pl…
chief-micco Mar 15, 2026
00fe5b1
merged main
chief-micco Mar 16, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
<WarningsNotAsErrors>NU1901;NU1902;NU1903;NU1904</WarningsNotAsErrors>
</PropertyGroup>
<ItemGroup Label="Package References">
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.5.10" />
<PackageReference Include="coverlet.msbuild" Version="6.0.4">
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.5.12" />
<PackageReference Include="coverlet.msbuild" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MySql.Data" Version="9.6.0" />
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.9.3" />
Expand All @@ -33,6 +33,8 @@
</ItemGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="../AppEncryption/AppEncryption.csproj" />
<ProjectReference Include="../AppEncryption.PlugIns.Aws/AppEncryption.PlugIns.Aws.csproj" />
<ProjectReference Include="../AppEncryption.PlugIns.Testing/AppEncryption.PlugIns.Testing.csproj" />
<ProjectReference Include="../AppEncryption.Tests/AppEncryption.Tests.csproj" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using GoDaddy.Asherah.AppEncryption.IntegrationTests.TestHelpers;
using GoDaddy.Asherah.AppEncryption.Kms;
using GoDaddy.Asherah.AppEncryption.Persistence;
using GoDaddy.Asherah.AppEncryption.PlugIns.Testing.Kms;
using GoDaddy.Asherah.Crypto.Exceptions;
using Microsoft.Extensions.Configuration;
using MySql.Data.MySqlClient;
Expand Down Expand Up @@ -48,7 +49,7 @@ public ConfigFixture()
Metastore = CreateMetastore();
}

public KeyManagementService KeyManagementService { get; }
public IKeyManagementService KeyManagementService { get; }

public IMetastore<JObject> Metastore { get; }

Expand Down Expand Up @@ -98,7 +99,7 @@ private IMetastore<JObject> CreateMetastore()
return new InMemoryMetastoreImpl<JObject>();
}

private KeyManagementService CreateKeyManagementService()
private IKeyManagementService CreateKeyManagementService()
{
if (KmsType.Equals(KeyManagementAws, StringComparison.OrdinalIgnoreCase))
{
Expand All @@ -124,7 +125,7 @@ private KeyManagementService CreateKeyManagementService()
.Build();
}

return new StaticKeyManagementServiceImpl(KeyManagementStaticMasterKey);
return new StaticKeyManagementService(KeyManagementStaticMasterKey);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ private object[] GenerateMocks(KeyState cacheIK, KeyState metaIK, KeyState cache
cacheSK + "CacheSK_" + metaSK + "MetaSK_" + DateTimeUtils.GetCurrentTimeAsUtcIsoDateTimeOffset() + "_" + Random.Next(),
DefaultProductId);

KeyManagementService kms = configFixture.KeyManagementService;
IKeyManagementService kms = configFixture.KeyManagementService;

CryptoKeyHolder cryptoKeyHolder = CryptoKeyHolder.GenerateIKSK();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System;
using System.Threading.Tasks;
using GoDaddy.Asherah.AppEncryption.Core;
using GoDaddy.Asherah.AppEncryption.IntegrationTests.Utils;
using Xunit;

using static GoDaddy.Asherah.AppEncryption.IntegrationTests.TestHelpers.Constants;

namespace GoDaddy.Asherah.AppEncryption.IntegrationTests.Regression.Core
{
[Collection("Configuration collection")]
public class EncryptionSessionTest : IDisposable
{
private readonly byte[] payload;
private readonly GoDaddy.Asherah.AppEncryption.Core.SessionFactory sessionFactory;
private readonly string partitionId;
private readonly IEncryptionSession encryptionSession;

public EncryptionSessionTest(ConfigFixture configFixture)
{
payload = PayloadGenerator.CreateDefaultRandomBytePayload();
sessionFactory = CoreSessionFactoryGenerator.CreateDefaultSessionFactory(
configFixture.KeyManagementService);
partitionId = DefaultPartitionId + "_" + DateTimeUtils.GetCurrentTimeAsUtcIsoDateTimeOffset();
encryptionSession = sessionFactory.GetSession(partitionId);
}

public void Dispose()
{
encryptionSession?.Dispose();
sessionFactory?.Dispose();
}

[Fact]
private void EncryptDecrypt()
{
byte[] dataRowRecord = encryptionSession.Encrypt(payload);
byte[] decryptedPayload = encryptionSession.Decrypt(dataRowRecord);

Assert.Equal(payload, decryptedPayload);
}

[Fact]
private void EncryptDecryptSameSessionMultipleRounds()
{
int iterations = 40;
for (int i = 0; i < iterations; i++)
{
byte[] dataRowRecord = encryptionSession.Encrypt(payload);
byte[] decryptedPayload = encryptionSession.Decrypt(dataRowRecord);

Assert.Equal(payload, decryptedPayload);
}
}

[Fact]
private void EncryptDecryptWithDifferentSession()
{
byte[] dataRowRecord = encryptionSession.Encrypt(payload);

using (IEncryptionSession otherSession = sessionFactory.GetSession(partitionId))
{
byte[] decryptedPayload = otherSession.Decrypt(dataRowRecord);
Assert.Equal(payload, decryptedPayload);
}
}

[Fact]
private void EncryptDecryptWithDifferentPayloads()
{
byte[] otherPayload = PayloadGenerator.CreateDefaultRandomBytePayload();
byte[] dataRowRecord1 = encryptionSession.Encrypt(payload);
byte[] dataRowRecord2 = encryptionSession.Encrypt(otherPayload);

byte[] decryptedPayload1 = encryptionSession.Decrypt(dataRowRecord1);
byte[] decryptedPayload2 = encryptionSession.Decrypt(dataRowRecord2);

Assert.Equal(payload, decryptedPayload1);
Assert.Equal(otherPayload, decryptedPayload2);
}

[Fact]
private async Task EncryptAsyncDecryptAsync()
{
byte[] dataRowRecord = await encryptionSession.EncryptAsync(payload);
byte[] decryptedPayload = await encryptionSession.DecryptAsync(dataRowRecord);

Assert.Equal(payload, decryptedPayload);
}

[Fact]
private async Task EncryptAsyncDecryptWithDifferentSession()
{
byte[] dataRowRecord = await encryptionSession.EncryptAsync(payload);

using (IEncryptionSession otherSession = sessionFactory.GetSession(partitionId))
{
byte[] decryptedPayload = await otherSession.DecryptAsync(dataRowRecord);
Assert.Equal(payload, decryptedPayload);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
using GoDaddy.Asherah.AppEncryption.IntegrationTests.Utils;
using GoDaddy.Asherah.AppEncryption.Persistence;
using GoDaddy.Asherah.AppEncryption.Tests;
using GoDaddy.Asherah.AppEncryption.Tests.AppEncryption.Persistence;
using GoDaddy.Asherah.AppEncryption.Tests.Fixtures;
using Xunit;

namespace GoDaddy.Asherah.AppEncryption.IntegrationTests.Regression
{
[Collection("Configuration collection")]
public class DynamoDbGlobalTableTest : IClassFixture<DynamoDBContainerFixture>, IClassFixture<MetricsFixture>, IDisposable
public class DynamoDbGlobalTableTest : IClassFixture<DynamoDbContainerFixture>, IClassFixture<MetricsFixture>, IDisposable
{
private const string PartitionKey = "Id";
private const string SortKey = "Created";
Expand All @@ -23,7 +23,7 @@ public class DynamoDbGlobalTableTest : IClassFixture<DynamoDBContainerFixture>,

private AmazonDynamoDBClient tempDynamoDbClient;

public DynamoDbGlobalTableTest(DynamoDBContainerFixture dynamoDbContainerFixture, ConfigFixture configFixture)
public DynamoDbGlobalTableTest(DynamoDbContainerFixture dynamoDbContainerFixture, ConfigFixture configFixture)
{
serviceUrl = dynamoDbContainerFixture.GetServiceUrl();
this.configFixture = configFixture;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
using System;
using System.Collections.Generic;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using GoDaddy.Asherah.AppEncryption.Core;
using GoDaddy.Asherah.AppEncryption.IntegrationTests.Utils;
using GoDaddy.Asherah.AppEncryption.PlugIns.Aws.Metastore;
using GoDaddy.Asherah.AppEncryption.Tests.Fixtures;
using Xunit;

namespace GoDaddy.Asherah.AppEncryption.IntegrationTests.Regression.Metastore
{
[Collection("Configuration collection")]
public class DynamoDbGlobalTableTest : IClassFixture<DynamoDbContainerFixture>, IDisposable
{
private const string PartitionKey = "Id";
private const string SortKey = "Created";
private const string DefaultTableName = "EncryptionKey";
private const string DefaultRegion = "us-west-2";

private readonly ConfigFixture _configFixture;
private readonly string _serviceUrl;
private readonly AmazonDynamoDBClient _tempDynamoDbClient;

public DynamoDbGlobalTableTest(DynamoDbContainerFixture dynamoDbContainerFixture, ConfigFixture configFixture)
{
_serviceUrl = dynamoDbContainerFixture.GetServiceUrl();
_configFixture = configFixture;

var amazonDynamoDbConfig = new AmazonDynamoDBConfig
{
ServiceURL = _serviceUrl,
AuthenticationRegion = DefaultRegion,
};
_tempDynamoDbClient = new AmazonDynamoDBClient(amazonDynamoDbConfig);
var request = new CreateTableRequest
{
TableName = DefaultTableName,
AttributeDefinitions = new List<AttributeDefinition>
{
new AttributeDefinition(PartitionKey, ScalarAttributeType.S),
new AttributeDefinition(SortKey, ScalarAttributeType.N),
},
KeySchema = new List<KeySchemaElement>
{
new KeySchemaElement(PartitionKey, KeyType.HASH),
new KeySchemaElement(SortKey, KeyType.RANGE),
},
ProvisionedThroughput = new ProvisionedThroughput(1L, 1L),
};
_tempDynamoDbClient.CreateTableAsync(request).Wait();
}

public void Dispose()
{
try
{
_tempDynamoDbClient?.DeleteTableAsync(DefaultTableName).Wait();
}
catch (AggregateException)
{
// Table may not exist.
}
}

private GoDaddy.Asherah.AppEncryption.Core.SessionFactory GetSessionFactory(bool withKeySuffix, string region)
{
var options = new DynamoDbMetastoreOptions
{
KeyRecordTableName = DefaultTableName,
KeySuffix = withKeySuffix ? region : string.Empty,
};

// Reuse the same client so both "regions" hit the same table (global table simulation).
var metastore = DynamoDbMetastore.NewBuilder()
.WithDynamoDbClient(_tempDynamoDbClient)
.WithOptions(options)
.Build();

return CoreSessionFactoryGenerator.CreateDefaultSessionFactory(
_configFixture.KeyManagementService,
metastore);
}

[Fact]
private void TestRegionSuffix()
{
byte[] originalPayload = PayloadGenerator.CreateDefaultRandomBytePayload();
byte[] dataRowRecordBytes;
byte[] decryptedBytes;

using (var sessionFactory = GetSessionFactory(true, DefaultRegion))
{
using (IEncryptionSession session = sessionFactory.GetSession("shopper123"))
{
dataRowRecordBytes = session.Encrypt(originalPayload);
}
}

using (var sessionFactory = GetSessionFactory(true, DefaultRegion))
{
using (IEncryptionSession session = sessionFactory.GetSession("shopper123"))
{
decryptedBytes = session.Decrypt(dataRowRecordBytes);
}
}

Assert.Equal(originalPayload, decryptedBytes);
}

[Fact]
private void TestRegionSuffixBackwardCompatibility()
{
byte[] originalPayload = PayloadGenerator.CreateDefaultRandomBytePayload();
byte[] dataRowRecordBytes;
byte[] decryptedBytes;

using (var sessionFactory = GetSessionFactory(false, DefaultRegion))
{
using (IEncryptionSession session = sessionFactory.GetSession("shopper123"))
{
dataRowRecordBytes = session.Encrypt(originalPayload);
}
}

using (var sessionFactory = GetSessionFactory(true, DefaultRegion))
{
using (IEncryptionSession session = sessionFactory.GetSession("shopper123"))
{
decryptedBytes = session.Decrypt(dataRowRecordBytes);
}
}

Assert.Equal(originalPayload, decryptedBytes);
}

[Fact]
private void TestCrossRegionDecryption()
{
byte[] originalPayload = PayloadGenerator.CreateDefaultRandomBytePayload();
byte[] dataRowRecordBytes;
byte[] decryptedBytes;

using (var sessionFactory = GetSessionFactory(true, DefaultRegion))
{
using (IEncryptionSession session = sessionFactory.GetSession("shopper123"))
{
dataRowRecordBytes = session.Encrypt(originalPayload);
}
}

using (var sessionFactory = GetSessionFactory(true, "us-east-1"))
{
using (IEncryptionSession session = sessionFactory.GetSession("shopper123"))
{
decryptedBytes = session.Decrypt(dataRowRecordBytes);
}
}

Assert.Equal(originalPayload, decryptedBytes);
}
}
}
Loading
Loading