Skip to content

Commit

Permalink
feat: add support for .NET SDK V4
Browse files Browse the repository at this point in the history
  • Loading branch information
philasmar committed Sep 6, 2024
1 parent c4d499a commit f91117d
Show file tree
Hide file tree
Showing 31 changed files with 100 additions and 2,938 deletions.
42 changes: 13 additions & 29 deletions src/Amazon.Extensions.S3.Encryption.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net35;net45;netstandard2.0;netcoreapp3.1</TargetFrameworks>
<Version>2.1.2</Version>
<TargetFrameworks>net472;netstandard2.0;netcoreapp3.1;net8.0</TargetFrameworks>
<Version>3.0.0-preview.1</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageId>Amazon.Extensions.S3.Encryption</PackageId>
<Title>Amazon S3 Encryption Client for .NET</Title>
Expand All @@ -15,43 +15,27 @@
<PackageIcon>icon.png</PackageIcon>
<RepositoryUrl>https://github.com/aws/amazon-s3-encryption-client-dotnet/</RepositoryUrl>
<Company>Amazon Web Services</Company>
<AssemblyVersion>2.1.2</AssemblyVersion>
<FileVersion>2.1.2</FileVersion>

<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\public.snk</AssemblyOriginatorKeyFile>

<!-- workaround per https://github.com/Microsoft/msbuild/issues/1333 -->
<FrameworkPathOverride Condition="'$(TargetFramework)' == 'net35'">C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v3.5\Profile\Client</FrameworkPathOverride>

<!-- workaround per https://github.com/dotnet/msbuild/issues/5985 -->
<AutomaticallyUseReferenceAssemblyPackages Condition=" '$(TargetFramework)' == 'net35' ">false</AutomaticallyUseReferenceAssemblyPackages>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'net472'">
<AssemblyVersion>3.0.0</AssemblyVersion>
</PropertyGroup>

<ItemGroup>
<None Include="../LICENSE" Pack="true" PackagePath="" />
<None Include="../icon.png" Pack="true" PackagePath="" />
<None Include="../README.md" Pack="true" PackagePath="" />
</ItemGroup>

<PropertyGroup>
<DefineConstants Condition="'$(TargetFramework)' == 'net35'">$(DefineConstants);BCL;BCL35;AWS_APM_API</DefineConstants>
<DefineConstants Condition="'$(TargetFramework)' == 'net45'">$(DefineConstants);BCL;BCL45;AWS_ASYNC_API</DefineConstants>
<DefineConstants Condition="'$(TargetFramework)' == 'netstandard2.0'">$(DefineConstants);NETSTANDARD;AWS_ASYNC_API</DefineConstants>
<DefineConstants Condition="'$(TargetFramework)' == 'netcoreapp3.1'">$(DefineConstants);NETSTANDARD;AWS_ASYNC_API</DefineConstants>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AWSSDK.Core" Version="3.7.303.14" />
<PackageReference Include="AWSSDK.S3" Version="3.7.307.15" />
<PackageReference Include="AWSSDK.KeyManagementService" Version="3.7.301.15" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net35'">
<PackageReference Include="BouncyCastle" Version="1.8.9" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net45' Or '$(TargetFramework)' == 'netstandard2.0' Or '$(TargetFramework)' == 'netcoreapp3.1'">
<PackageReference Include="Portable.BouncyCastle" Version="1.8.10" />
<PackageReference Include="AWSSDK.Core" Version="4.0.0-preview.2" />
<PackageReference Include="AWSSDK.S3" Version="4.0.0-preview.2" />
<PackageReference Include="AWSSDK.KeyManagementService" Version="4.0.0-preview.2" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
</ItemGroup>

</Project>
16 changes: 1 addition & 15 deletions src/AmazonCryptoException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,13 @@ namespace Amazon.Extensions.S3.Encryption
/// <summary>
/// Exception thrown by the SDK for errors that occur within the SDK for crypto operations.
/// </summary>
#if !PCL && !NETSTANDARD
#if !PCL && NETFRAMEWORK
[Serializable]
#endif
public class AmazonCryptoException : Exception
{
public AmazonCryptoException(string message) : base(message) { }

public AmazonCryptoException(string message, Exception innerException) : base(message, innerException) { }

#if !PCL && !NETSTANDARD
/// <summary>
/// Constructs a new instance of the AmazonCryptoException class with serialized data.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext" /> that contains contextual information about the source or destination.</param>
/// <exception cref="T:System.ArgumentNullException">The <paramref name="info" /> parameter is null. </exception>
/// <exception cref="T:System.Runtime.Serialization.SerializationException">The class name is null or <see cref="P:System.Exception.HResult" /> is zero (0). </exception>
protected AmazonCryptoException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
: base(info, context)
{
}
#endif
}
}
11 changes: 0 additions & 11 deletions src/AmazonS3CryptoConfigurationV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,7 @@
* permissions and limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Amazon.Runtime.Internal.Util;
using Amazon.S3;
using System;
using System.Collections.Generic;
using Amazon.Runtime;
using Amazon.S3.Model;
using Amazon.Runtime.Internal;
using Amazon.S3;

namespace Amazon.Extensions.S3.Encryption
{
Expand Down
7 changes: 0 additions & 7 deletions src/AmazonS3EncryptionClientBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,10 @@ internal AmazonS3Client S3ClientForInstructionFile
}

internal AmazonS3CryptoConfigurationBase S3CryptoConfig { get; set; }
#if BCL35
internal readonly Amazon.Extensions.S3.Encryption.Utils.ConcurrentDictionary<string, UploadPartEncryptionContext> CurrentMultiPartUploadKeys =
new Amazon.Extensions.S3.Encryption.Utils.ConcurrentDictionary<string, UploadPartEncryptionContext>();
internal readonly Amazon.Extensions.S3.Encryption.Utils.ConcurrentDictionary<InitiateMultipartUploadRequest, UploadPartEncryptionContext> AllMultiPartUploadRequestContexts =
new Amazon.Extensions.S3.Encryption.Utils.ConcurrentDictionary<InitiateMultipartUploadRequest, UploadPartEncryptionContext>();
#else
internal readonly System.Collections.Concurrent.ConcurrentDictionary<string, UploadPartEncryptionContext> CurrentMultiPartUploadKeys =
new System.Collections.Concurrent.ConcurrentDictionary<string, UploadPartEncryptionContext>();
internal readonly System.Collections.Concurrent.ConcurrentDictionary<InitiateMultipartUploadRequest, UploadPartEncryptionContext> AllMultiPartUploadRequestContexts =
new System.Collections.Concurrent.ConcurrentDictionary<InitiateMultipartUploadRequest, UploadPartEncryptionContext>();
#endif
internal const string S3CryptoStream = "S3-Crypto-Stream";

#region Constructors
Expand Down
5 changes: 1 addition & 4 deletions src/AmazonS3EncryptionClientV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ protected override void CustomizeRuntimePipeline(RuntimePipeline pipeline)
pipeline.AddHandlerBefore<Amazon.S3.Internal.AmazonS3ResponseHandler>(new SetupDecryptionHandlerV2(this));
}

#if AWS_ASYNC_API

/// <summary>
/// Retrieves objects from Amazon S3. To use <c>GET</c>, you must have <c>READ</c>
/// access to the object. If you grant <c>READ</c> access to the anonymous user,
Expand Down Expand Up @@ -723,9 +721,8 @@ public override System.Threading.Tasks.Task<GetObjectResponse> GetObjectAsync(st
{
return base.GetObjectAsync(bucketName, key, versionId, cancellationToken);
}
#endif

#if BCL
#if NETFRAMEWORK
/// <summary>
/// Retrieves objects from Amazon S3. To use <c>GET</c>, you must have <c>READ</c>
/// access to the object. If you grant <c>READ</c> access to the anonymous user,
Expand Down
36 changes: 24 additions & 12 deletions src/EncryptionUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
using Amazon.KeyManagementService;
using Amazon.Runtime.SharedInterfaces;
using Amazon.Extensions.S3.Encryption.Util;
using Amazon.KeyManagementService.Model;

namespace Amazon.Extensions.S3.Encryption
{
Expand Down Expand Up @@ -86,7 +87,7 @@ internal static partial class EncryptionUtils

private static byte[] EncryptEnvelopeKeyUsingAsymmetricKeyPair(AsymmetricAlgorithm asymmetricAlgorithm, byte[] envelopeKey)
{
#if NETSTANDARD
#if !NETFRAMEWORK
RSA rsaCrypto = asymmetricAlgorithm as RSA;
if (rsaCrypto == null)
{
Expand Down Expand Up @@ -133,7 +134,7 @@ internal static byte[] DecryptNonKMSEnvelopeKey(byte[] encryptedEnvelopeKey, Enc

private static byte[] DecryptEnvelopeKeyUsingAsymmetricKeyPair(AsymmetricAlgorithm asymmetricAlgorithm, byte[] encryptedEnvelopeKey)
{
#if NETSTANDARD
#if !NETFRAMEWORK
RSA rsaCrypto = asymmetricAlgorithm as RSA;
if (rsaCrypto == null)
{
Expand Down Expand Up @@ -245,6 +246,7 @@ internal static void DecryptObjectUsingInstructionsGcm(GetObjectResponse respons

#region InstructionGeneration

#if NETFRAMEWORK
/// <summary>
/// Generates an instruction that will be used to encrypt an object
/// using materials with the KMSKeyID set.
Expand All @@ -269,14 +271,18 @@ internal static EncryptionInstructions GenerateInstructionsForKMSMaterials(IAmaz

// Generate IV, and get both the key and the encrypted key from KMS.
RandomNumberGenerator.Create().GetBytes(iv);
var generateDataKeyResult = kmsClient.GenerateDataKey(materials.KMSKeyID, materials.MaterialsDescription, KMSKeySpec);
var generateDataKeyResult = kmsClient.GenerateDataKey(new GenerateDataKeyRequest
{
KeyId = materials.KMSKeyID,
EncryptionContext = materials.MaterialsDescription,
KeySpec = KMSKeySpec
});

return new EncryptionInstructions(materials.MaterialsDescription, generateDataKeyResult.KeyPlaintext, generateDataKeyResult.KeyCiphertext, iv,
return new EncryptionInstructions(materials.MaterialsDescription, generateDataKeyResult.Plaintext.ToArray(), generateDataKeyResult.CiphertextBlob.ToArray(), iv,
XAmzWrapAlgKmsValue, XAmzAesCbcPaddingCekAlgValue);
}

#if AWS_ASYNC_API

#endif

/// <summary>
/// Generates an instruction that will be used to encrypt an object
/// using materials with the KMSKeyID set.
Expand All @@ -302,14 +308,17 @@ internal static async System.Threading.Tasks.Task<EncryptionInstructions> Genera

// Generate IV, and get both the key and the encrypted key from KMS.
RandomNumberGenerator.Create().GetBytes(iv);
var generateDataKeyResult = await kmsClient.GenerateDataKeyAsync(materials.KMSKeyID, materials.MaterialsDescription, KMSKeySpec).ConfigureAwait(false);
var generateDataKeyResult = await kmsClient.GenerateDataKeyAsync(new GenerateDataKeyRequest
{
KeyId = materials.KMSKeyID,
EncryptionContext = materials.MaterialsDescription,
KeySpec = KMSKeySpec
}).ConfigureAwait(false);

return new EncryptionInstructions(materials.MaterialsDescription, generateDataKeyResult.KeyPlaintext, generateDataKeyResult.KeyCiphertext, iv,
return new EncryptionInstructions(materials.MaterialsDescription, generateDataKeyResult.Plaintext.ToArray(), generateDataKeyResult.CiphertextBlob.ToArray(), iv,
XAmzWrapAlgKmsValue, XAmzAesCbcPaddingCekAlgValue);
}

#endif

/// <summary>
/// Generates an instruction that will be used to encrypt an object
/// using materials with the AsymmetricProvider or SymmetricProvider set.
Expand Down Expand Up @@ -354,15 +363,19 @@ internal static void EnsureSupportedAlgorithms(MetadataCollection metadata)
var xAmzWrapAlgMetadataValue = metadata[XAmzWrapAlg];
if (!SupportedWrapAlgorithms.Contains(xAmzWrapAlgMetadataValue))
{
#pragma warning disable 0618
throw new InvalidDataException($"Value '{xAmzWrapAlgMetadataValue}' for metadata key '{XAmzWrapAlg}' is invalid." +
$"{typeof(AmazonS3EncryptionClient).Name} only supports '{XAmzWrapAlgKmsValue}' as the key wrap algorithm. {ModeMessage}");
#pragma warning restore 0618
}

var xAmzCekAlgMetadataValue = metadata[XAmzCekAlg];
if (!(SupportedCekAlgorithms.Contains(xAmzCekAlgMetadataValue)))
#pragma warning disable 0618
throw new InvalidDataException(string.Format(CultureInfo.InvariantCulture,
"Value '{0}' for metadata key '{1}' is invalid. {2} only supports '{3}' as the content encryption algorithm. {4}",
xAmzCekAlgMetadataValue, XAmzCekAlg, typeof(AmazonS3EncryptionClient).Name, XAmzAesCbcPaddingCekAlgValue, ModeMessage));
#pragma warning restore 0618
}
}

Expand Down Expand Up @@ -399,7 +412,6 @@ internal static EncryptionInstructions BuildInstructionsFromObjectMetadata(
var cekAlgorithm = metadata[XAmzCekAlg];
var wrapAlgorithm = metadata[XAmzWrapAlg];

EncryptionInstructions instructions;
if (decryptedEnvelopeKeyKMS != null)
{
return new EncryptionInstructions(materialDescription, decryptedEnvelopeKeyKMS, encryptedEnvelopeKey, IV, wrapAlgorithm, cekAlgorithm);
Expand Down
29 changes: 20 additions & 9 deletions src/EncryptionUtilsV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using Amazon.Extensions.S3.Encryption.Primitives;
using Amazon.Extensions.S3.Encryption.Util;
using Amazon.KeyManagementService;
using Amazon.KeyManagementService.Model;
using Amazon.Runtime;
using Amazon.S3.Model;
using ThirdParty.Json.LitJson;
Expand Down Expand Up @@ -346,6 +347,7 @@ internal static Stream EncryptUploadPartRequestUsingInstructionsV2(Stream toBeEn
return aesGcmEncryptStream;
}

#if NETFRAMEWORK
/// <summary>
/// Generates an instruction that will be used to encrypt an object
/// using materials with the KMSKeyID set.
Expand Down Expand Up @@ -374,18 +376,23 @@ internal static EncryptionInstructions GenerateInstructionsForKMSMaterialsV2(IAm

// Generate nonce, and get both the key and the encrypted key from KMS.
RandomNumberGenerator.Create().GetBytes(nonce);
var result = kmsClient.GenerateDataKey(materials.KMSKeyID, materials.MaterialsDescription, KMSKeySpec);

var instructions = new EncryptionInstructions(materials.MaterialsDescription, result.KeyPlaintext, result.KeyCiphertext, nonce,
var result = kmsClient.GenerateDataKey(new GenerateDataKeyRequest
{
KeyId = materials.KMSKeyID,
EncryptionContext = materials.MaterialsDescription,
KeySpec = KMSKeySpec
});

var instructions = new EncryptionInstructions(materials.MaterialsDescription, result.Plaintext.ToArray(), result.CiphertextBlob.ToArray(), nonce,
XAmzWrapAlgKmsContextValue, XAmzAesGcmCekAlgValue);
return instructions;
}
default:
throw new NotSupportedException($"{materials.KmsType} is not supported for KMS Key Id {materials.KMSKeyID}");
}
}

#if AWS_ASYNC_API
#endif
/// <summary>
/// Generates an instruction that will be used to encrypt an object
/// using materials with the KMSKeyID set.
Expand Down Expand Up @@ -415,17 +422,21 @@ internal static async System.Threading.Tasks.Task<EncryptionInstructions> Genera

// Generate nonce, and get both the key and the encrypted key from KMS.
RandomNumberGenerator.Create().GetBytes(nonce);
var result = await kmsClient.GenerateDataKeyAsync(materials.KMSKeyID, materials.MaterialsDescription, KMSKeySpec).ConfigureAwait(false);

var instructions = new EncryptionInstructions(materials.MaterialsDescription, result.KeyPlaintext, result.KeyCiphertext, nonce,
var result = await kmsClient.GenerateDataKeyAsync(new GenerateDataKeyRequest
{
KeyId = materials.KMSKeyID,
EncryptionContext = materials.MaterialsDescription,
KeySpec = KMSKeySpec
}).ConfigureAwait(false);

var instructions = new EncryptionInstructions(materials.MaterialsDescription, result.Plaintext.ToArray(), result.CiphertextBlob.ToArray(), nonce,
XAmzWrapAlgKmsContextValue, XAmzAesGcmCekAlgValue);
return instructions;
}
default:
throw new NotSupportedException($"{materials.KmsType} is not supported for KMS Key Id {materials.KMSKeyID}");
}
}
#endif

/// <summary>
/// Converts x-amz-matdesc JSON string to dictionary
Expand Down
Loading

0 comments on commit f91117d

Please sign in to comment.