diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionContainerExtensions.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionContainerExtensions.cs index b20758d1bc..c0852f9be5 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionContainerExtensions.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionContainerExtensions.cs @@ -29,7 +29,7 @@ public static class EncryptionContainerExtensions /// /// /// diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionCosmosClient.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionCosmosClient.cs index 8779f61a93..89dfc4b7bd 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionCosmosClient.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionCosmosClient.cs @@ -8,25 +8,26 @@ namespace Microsoft.Azure.Cosmos.Encryption using System.Net; using System.Threading; using System.Threading.Tasks; - using Microsoft.Data.Encryption.Cryptography; /// /// CosmosClient with Encryption support. /// internal sealed class EncryptionCosmosClient : CosmosClient { + internal static readonly SemaphoreSlim EncryptionKeyCacheSemaphore = new SemaphoreSlim(1, 1); + private readonly CosmosClient cosmosClient; private readonly AsyncCache clientEncryptionKeyPropertiesCacheByKeyId; - public EncryptionCosmosClient(CosmosClient cosmosClient, EncryptionKeyStoreProvider encryptionKeyStoreProvider) + public EncryptionCosmosClient(CosmosClient cosmosClient, EncryptionKeyWrapProvider encryptionKeyWrapProvider) { this.cosmosClient = cosmosClient ?? throw new ArgumentNullException(nameof(cosmosClient)); - this.EncryptionKeyStoreProvider = encryptionKeyStoreProvider ?? throw new ArgumentNullException(nameof(encryptionKeyStoreProvider)); + this.EncryptionKeyWrapProvider = encryptionKeyWrapProvider ?? throw new ArgumentNullException(nameof(encryptionKeyWrapProvider)); this.clientEncryptionKeyPropertiesCacheByKeyId = new AsyncCache(); } - public EncryptionKeyStoreProvider EncryptionKeyStoreProvider { get; } + public EncryptionKeyWrapProvider EncryptionKeyWrapProvider { get; } public override CosmosClientOptions ClientOptions => this.cosmosClient.ClientOptions; diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionCosmosClientExtensions.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionCosmosClientExtensions.cs index 2419e78676..ad2077f3dc 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionCosmosClientExtensions.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionCosmosClientExtensions.cs @@ -16,15 +16,15 @@ public static class EncryptionCosmosClientExtensions /// Get Cosmos Client with Encryption support for performing operations using client-side encryption. /// /// Regular Cosmos Client. - /// EncryptionKeyStoreProvider, provider that allows interaction with the master keys. + /// EncryptionKeyWrapProvider, provider that allows interaction with the master keys. /// CosmosClient to perform operations supporting client-side encryption / decryption. public static CosmosClient WithEncryption( this CosmosClient cosmosClient, - EncryptionKeyStoreProvider encryptionKeyStoreProvider) + EncryptionKeyWrapProvider encryptionKeyWrapProvider) { - if (encryptionKeyStoreProvider == null) + if (encryptionKeyWrapProvider == null) { - throw new ArgumentNullException(nameof(encryptionKeyStoreProvider)); + throw new ArgumentNullException(nameof(encryptionKeyWrapProvider)); } if (cosmosClient == null) @@ -32,19 +32,7 @@ public static CosmosClient WithEncryption( throw new ArgumentNullException(nameof(cosmosClient)); } - // set the TTL for ProtectedDataEncryption at the Encryption CosmosClient Init so that we have a uniform expiry of the KeyStoreProvider and ProtectedDataEncryption cache items. - if (encryptionKeyStoreProvider.DataEncryptionKeyCacheTimeToLive.HasValue) - { - ProtectedDataEncryptionKey.TimeToLive = encryptionKeyStoreProvider.DataEncryptionKeyCacheTimeToLive.Value; - } - else - { - // If null is passed to DataEncryptionKeyCacheTimeToLive it results in forever caching hence setting - // arbitrarily large caching period. ProtectedDataEncryptionKey does not seem to handle TimeSpan.MaxValue. - ProtectedDataEncryptionKey.TimeToLive = TimeSpan.FromDays(36500); - } - - return new EncryptionCosmosClient(cosmosClient, encryptionKeyStoreProvider); + return new EncryptionCosmosClient(cosmosClient, encryptionKeyWrapProvider); } } } diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabaseExtensions.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabaseExtensions.cs index 1a323f6d89..417c9f3856 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabaseExtensions.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionDatabaseExtensions.cs @@ -38,7 +38,7 @@ public static class EncryptionDatabaseExtensions public static async Task CreateClientEncryptionKeyAsync( this Database database, string clientEncryptionKeyId, - DataEncryptionKeyAlgorithm dataEncryptionKeyAlgorithm, + string dataEncryptionKeyAlgorithm, EncryptionKeyWrapMetadata encryptionKeyWrapMetadata, CancellationToken cancellationToken = default) { @@ -49,11 +49,9 @@ public static async Task CreateClientEncryptionKeyA throw new ArgumentNullException(nameof(clientEncryptionKeyId)); } - string encryptionAlgorithm = dataEncryptionKeyAlgorithm.ToString(); - - if (!string.Equals(encryptionAlgorithm, DataEncryptionKeyAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.ToString())) + if (!string.Equals(dataEncryptionKeyAlgorithm, DataEncryptionKeyAlgorithm.AeadAes256CbcHmacSha256)) { - throw new ArgumentException($"Invalid Encryption Algorithm '{encryptionAlgorithm}' passed. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); + throw new ArgumentException($"Invalid Encryption Algorithm '{dataEncryptionKeyAlgorithm}' passed. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } if (encryptionKeyWrapMetadata == null) @@ -65,17 +63,17 @@ public static async Task CreateClientEncryptionKeyA ? encryptionDatabase.EncryptionCosmosClient : throw new ArgumentException("Creating a ClientEncryptionKey resource requires the use of an encryption - enabled client. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); - EncryptionKeyStoreProvider encryptionKeyStoreProvider = encryptionCosmosClient.EncryptionKeyStoreProvider; + EncryptionKeyWrapProvider encryptionKeyWrapProvider = encryptionCosmosClient.EncryptionKeyWrapProvider; - if (!string.Equals(encryptionKeyWrapMetadata.Type, encryptionKeyStoreProvider.ProviderName)) + if (!string.Equals(encryptionKeyWrapMetadata.Type, encryptionKeyWrapProvider.ProviderName)) { - throw new ArgumentException("The EncryptionKeyWrapMetadata Type value does not match with the ProviderName of EncryptionKeyStoreProvider configured on the Client. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); + throw new ArgumentException("The EncryptionKeyWrapMetadata Type value does not match with the ProviderName of EncryptionKeyWrapProvider configured on the Client. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate( encryptionKeyWrapMetadata.Name, encryptionKeyWrapMetadata.Value, - encryptionKeyStoreProvider); + encryptionKeyWrapProvider.EncryptionKeyStoreProviderImpl); ProtectedDataEncryptionKey protectedDataEncryptionKey = new ProtectedDataEncryptionKey( clientEncryptionKeyId, @@ -91,7 +89,7 @@ public static async Task CreateClientEncryptionKeyA ClientEncryptionKeyProperties clientEncryptionKeyProperties = new ClientEncryptionKeyProperties( clientEncryptionKeyId, - encryptionAlgorithm, + dataEncryptionKeyAlgorithm, wrappedDataEncryptionKey, encryptionKeyWrapMetadata); @@ -145,11 +143,11 @@ public static async Task RewrapClientEncryptionKeyA ? encryptionDatabase.EncryptionCosmosClient : throw new ArgumentException("Rewraping a ClientEncryptionKey requires the use of an encryption - enabled client. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); - EncryptionKeyStoreProvider encryptionKeyStoreProvider = encryptionCosmosClient.EncryptionKeyStoreProvider; + EncryptionKeyWrapProvider encryptionKeyWrapProvider = encryptionCosmosClient.EncryptionKeyWrapProvider; - if (!string.Equals(newEncryptionKeyWrapMetadata.Type, encryptionKeyStoreProvider.ProviderName)) + if (!string.Equals(newEncryptionKeyWrapMetadata.Type, encryptionKeyWrapProvider.ProviderName)) { - throw new ArgumentException("The EncryptionKeyWrapMetadata Type value does not match with the ProviderName of EncryptionKeyStoreProvider configured on the Client. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); + throw new ArgumentException("The EncryptionKeyWrapMetadata Type value does not match with the ProviderName of EncryptionKeyWrapProvider configured on the Client. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } ClientEncryptionKeyProperties clientEncryptionKeyProperties = await clientEncryptionKey.ReadAsync(cancellationToken: cancellationToken); @@ -162,14 +160,14 @@ public static async Task RewrapClientEncryptionKeyA KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate( clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Name, clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Value, - encryptionKeyStoreProvider); + encryptionKeyWrapProvider.EncryptionKeyStoreProviderImpl); byte[] unwrappedKey = keyEncryptionKey.DecryptEncryptionKey(clientEncryptionKeyProperties.WrappedDataEncryptionKey); keyEncryptionKey = KeyEncryptionKey.GetOrCreate( newEncryptionKeyWrapMetadata.Name, newEncryptionKeyWrapMetadata.Value, - encryptionKeyStoreProvider); + encryptionKeyWrapProvider.EncryptionKeyStoreProviderImpl); byte[] rewrappedKey = keyEncryptionKey.EncryptEncryptionKey(unwrappedKey); diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionSettingForProperty.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionSettingForProperty.cs index 45b2a37c51..bf7103faa2 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionSettingForProperty.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionSettingForProperty.cs @@ -13,15 +13,13 @@ namespace Microsoft.Azure.Cosmos.Encryption internal sealed class EncryptionSettingForProperty { - private static readonly SemaphoreSlim EncryptionKeyCacheSemaphore = new SemaphoreSlim(1, 1); - private readonly string databaseRid; private readonly EncryptionContainer encryptionContainer; public EncryptionSettingForProperty( string clientEncryptionKeyId, - EncryptionType encryptionType, + Data.Encryption.Cryptography.EncryptionType encryptionType, EncryptionContainer encryptionContainer, string databaseRid) { @@ -33,7 +31,7 @@ public EncryptionSettingForProperty( public string ClientEncryptionKeyId { get; } - public EncryptionType EncryptionType { get; } + public Data.Encryption.Cryptography.EncryptionType EncryptionType { get; } public async Task BuildEncryptionAlgorithmForSettingAsync(CancellationToken cancellationToken) { @@ -52,7 +50,7 @@ public async Task BuildEncryptionAlgori // Here a request is sent out to unwrap using the Master Key configured via the Key Encryption Key. protectedDataEncryptionKey = await this.BuildProtectedDataEncryptionKeyAsync( clientEncryptionKeyProperties, - this.encryptionContainer.EncryptionCosmosClient.EncryptionKeyStoreProvider, + this.encryptionContainer.EncryptionCosmosClient.EncryptionKeyWrapProvider, this.ClientEncryptionKeyId, cancellationToken); } @@ -75,7 +73,7 @@ public async Task BuildEncryptionAlgori // try to build the ProtectedDataEncryptionKey. If it fails, try to force refresh the gateway cache and get the latest client encryption key. protectedDataEncryptionKey = await this.BuildProtectedDataEncryptionKeyAsync( clientEncryptionKeyProperties, - this.encryptionContainer.EncryptionCosmosClient.EncryptionKeyStoreProvider, + this.encryptionContainer.EncryptionCosmosClient.EncryptionKeyWrapProvider, this.ClientEncryptionKeyId, cancellationToken); } @@ -143,7 +141,7 @@ private async Task ForceRefreshGatewayCacheAndBuildP ProtectedDataEncryptionKey protectedDataEncryptionKey = await this.BuildProtectedDataEncryptionKeyAsync( clientEncryptionKeyProperties, - this.encryptionContainer.EncryptionCosmosClient.EncryptionKeyStoreProvider, + this.encryptionContainer.EncryptionCosmosClient.EncryptionKeyWrapProvider, this.ClientEncryptionKeyId, cancellationToken); @@ -152,18 +150,18 @@ private async Task ForceRefreshGatewayCacheAndBuildP private async Task BuildProtectedDataEncryptionKeyAsync( ClientEncryptionKeyProperties clientEncryptionKeyProperties, - EncryptionKeyStoreProvider encryptionKeyStoreProvider, + EncryptionKeyWrapProvider encryptionKeyWrapProvider, string keyId, CancellationToken cancellationToken) { - if (await EncryptionKeyCacheSemaphore.WaitAsync(-1, cancellationToken)) + if (await EncryptionCosmosClient.EncryptionKeyCacheSemaphore.WaitAsync(-1, cancellationToken)) { try { KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate( clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Name, clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Value, - encryptionKeyStoreProvider); + encryptionKeyWrapProvider.EncryptionKeyStoreProviderImpl); ProtectedDataEncryptionKey protectedDataEncryptionKey = ProtectedDataEncryptionKey.GetOrCreate( keyId, @@ -174,7 +172,7 @@ private async Task BuildProtectedDataEncryptionKeyAs } finally { - EncryptionKeyCacheSemaphore.Release(1); + EncryptionCosmosClient.EncryptionKeyCacheSemaphore.Release(1); } } diff --git a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionSettings.cs b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionSettings.cs index 5078fa3eb2..074d8a5c1f 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/EncryptionSettings.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/EncryptionSettings.cs @@ -49,12 +49,12 @@ public void SetRequestHeaders(RequestOptions requestOptions) }; } - private static EncryptionType GetEncryptionTypeForProperty(ClientEncryptionIncludedPath clientEncryptionIncludedPath) + private static Data.Encryption.Cryptography.EncryptionType GetEncryptionTypeForProperty(ClientEncryptionIncludedPath clientEncryptionIncludedPath) { return clientEncryptionIncludedPath.EncryptionType switch { - CosmosEncryptionType.Deterministic => EncryptionType.Deterministic, - CosmosEncryptionType.Randomized => EncryptionType.Randomized, + EncryptionType.Deterministic => Data.Encryption.Cryptography.EncryptionType.Deterministic, + EncryptionType.Randomized => Data.Encryption.Cryptography.EncryptionType.Randomized, _ => throw new ArgumentException($"Invalid encryption type {clientEncryptionIncludedPath.EncryptionType}. Please refer to https://aka.ms/CosmosClientEncryption for more details. "), }; } @@ -102,7 +102,7 @@ await encryptionContainer.EncryptionCosmosClient.GetClientEncryptionKeyPropertie // update the property level setting. foreach (ClientEncryptionIncludedPath propertyToEncrypt in clientEncryptionPolicy.IncludedPaths) { - EncryptionType encryptionType = GetEncryptionTypeForProperty(propertyToEncrypt); + Data.Encryption.Cryptography.EncryptionType encryptionType = GetEncryptionTypeForProperty(propertyToEncrypt); EncryptionSettingForProperty encryptionSettingsForProperty = new EncryptionSettingForProperty( propertyToEncrypt.ClientEncryptionKeyId, diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/AzureKeyVaultKeyWrapProvider.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/AzureKeyVaultKeyWrapProvider.cs new file mode 100644 index 0000000000..3945d380c1 --- /dev/null +++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/AzureKeyVaultKeyWrapProvider.cs @@ -0,0 +1,77 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Encryption +{ + using System; + using System.Threading.Tasks; + using global::Azure.Core; + using Microsoft.Data.Encryption.AzureKeyVaultProvider; + + /// + /// Implementation of key encryption key store provider that allows client applications to access data when a + /// key encryption key is stored in Microsoft Azure Key Vault. + /// + public sealed class AzureKeyVaultKeyWrapProvider : EncryptionKeyWrapProvider + { + private readonly AzureKeyVaultKeyStoreProvider azureKeyVaultKeyStoreProvider; + + /// + /// Initializes a new instance of the class. + /// Constructor that takes an implementation of Token Credential that is capable of providing an OAuth Token. + /// + /// returns token credentials. + public AzureKeyVaultKeyWrapProvider(TokenCredential tokenCredential) + { + // just rely on cache managed via EncryptionKeyWrapProvider. Setting DataEncryptionKeyCacheTimeToLive to zero results in not using azureKeyVaultKeyWrapProvider cache. + this.azureKeyVaultKeyStoreProvider = new AzureKeyVaultKeyStoreProvider(tokenCredential) + { + DataEncryptionKeyCacheTimeToLive = TimeSpan.Zero, + }; + } + + /// + /// Gets name of the Encryption Key Store Provider implementation. + /// + public override string ProviderName => this.azureKeyVaultKeyStoreProvider.ProviderName; + + /// + /// This function uses the asymmetric key specified by the key path + /// and decrypts an encrypted data dencryption key with RSA encryption algorithm. + /// . + /// Identifier of an asymmetric key in Azure Key Vault. + /// The key encryption algorithm. + /// The ciphertext key. + /// Plain text data encryption key. + public override Task UnwrapKeyAsync(string encryptionKeyId, string cosmosKeyEncryptionKeyAlgorithm, byte[] encryptedKey) + { + Data.Encryption.Cryptography.KeyEncryptionKeyAlgorithm keyEncryptionKeyAlgorithm = cosmosKeyEncryptionKeyAlgorithm switch + { + KeyEncryptionKeyAlgorithm.RsaOaep => Data.Encryption.Cryptography.KeyEncryptionKeyAlgorithm.RSA_OAEP, + _ => throw new NotSupportedException("The specified KeyEncryptionAlgorithm is not supported. Please refer to https://aka.ms/CosmosClientEncryption for more details. "), + }; + + return Task.FromResult(this.azureKeyVaultKeyStoreProvider.UnwrapKey(encryptionKeyId, keyEncryptionKeyAlgorithm, encryptedKey)); + } + + /// + /// This function uses the asymmetric key specified by the key path + /// and encrypts an unencrypted data encryption key with RSA encryption algorithm. + /// + /// Identifier of an asymmetric key in Azure Key Vault. + /// The key encryption algorithm. + /// The plaintext key. + /// Encrypted data encryption key. + public override Task WrapKeyAsync(string encryptionKeyId, string cosmosKeyEncryptionKeyAlgorithm, byte[] key) + { + Data.Encryption.Cryptography.KeyEncryptionKeyAlgorithm keyEncryptionKeyAlgorithm = cosmosKeyEncryptionKeyAlgorithm switch + { + KeyEncryptionKeyAlgorithm.RsaOaep => Data.Encryption.Cryptography.KeyEncryptionKeyAlgorithm.RSA_OAEP, + _ => throw new NotSupportedException("This specified KeyEncryptionAlgorithm is not supported. Please refer to https://aka.ms/CosmosClientEncryption for more details. "), + }; + + return Task.FromResult(this.azureKeyVaultKeyStoreProvider.WrapKey(encryptionKeyId, keyEncryptionKeyAlgorithm, key)); + } + } +} diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/DataEncryptionKeyAlgorithm.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/DataEncryptionKeyAlgorithm.cs new file mode 100644 index 0000000000..e5216c1eb9 --- /dev/null +++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/DataEncryptionKeyAlgorithm.cs @@ -0,0 +1,18 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Encryption +{ + /// + /// Represents the encryption algorithms supported for data encryption. + /// + public static class DataEncryptionKeyAlgorithm + { + /// + /// Represents the authenticated encryption algorithm with associated data as described in + /// http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05. + /// + public const string AeadAes256CbcHmacSha256 = "AEAD_AES_256_CBC_HMAC_SHA256"; + } +} diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/EncryptionKeyStoreProviderImpl.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/EncryptionKeyStoreProviderImpl.cs new file mode 100644 index 0000000000..45fc041933 --- /dev/null +++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/EncryptionKeyStoreProviderImpl.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Encryption +{ + using System; + using Microsoft.Data.Encryption.Cryptography; + + /// + /// The purpose/intention to introduce this class is to utilize the cache provide by the abstract class. This class basically + /// redirects all the corresponding calls to 's overridden methods and thus allowing us + /// to utilize the virtual method to access the cache. + /// + /// Note: Since and methods are not exposed, is not supported either. + /// + /// + /// The call hierarchy is as follows. Note, all core MDE API's used in internal cosmos encryption code are passed an EncryptionKeyStoreProviderImpl object. + /// ProtectedDataEncryptionKey -> KeyEncryptionKey(containing EncryptionKeyStoreProviderImpl object) -> EncryptionKeyStoreProviderImpl.WrapKey -> this.EncryptionKeyWrapProvider.WrapKeyAsync + /// ProtectedDataEncryptionKey -> KeyEncryptionKey(containing EncryptionKeyStoreProviderImpl object) -> EncryptionKeyStoreProviderImpl.UnWrapKey -> this.EncryptionKeyWrapProvider.UnwrapKeyAsync + /// + /// + internal class EncryptionKeyStoreProviderImpl : EncryptionKeyStoreProvider + { + private readonly EncryptionKeyWrapProvider encryptionKeyWrapProvider; + + public EncryptionKeyStoreProviderImpl(EncryptionKeyWrapProvider encryptionKeyWrapProvider) + { + this.encryptionKeyWrapProvider = encryptionKeyWrapProvider; + } + + public override string ProviderName => this.encryptionKeyWrapProvider.ProviderName; + + public override byte[] UnwrapKey(string encryptionKeyId, Data.Encryption.Cryptography.KeyEncryptionKeyAlgorithm algorithm, byte[] encryptedKey) + { + // since we do not expose GetOrCreateDataEncryptionKey we first look up the cache. + // Cache miss results in call to UnWrapCore which updates the cache after UnwrapKeyAsync is called. + return this.GetOrCreateDataEncryptionKey(encryptedKey.ToHexString(), UnWrapKeyCore); + + // delegate that is called by GetOrCreateDataEncryptionKey, which unwraps the key and updates the cache in case of cache miss. + byte[] UnWrapKeyCore() + { + return this.encryptionKeyWrapProvider.UnwrapKeyAsync(encryptionKeyId, algorithm.ToString(), encryptedKey) + .ConfigureAwait(false) + .GetAwaiter() + .GetResult(); + } + } + + public override byte[] WrapKey(string encryptionKeyId, Data.Encryption.Cryptography.KeyEncryptionKeyAlgorithm algorithm, byte[] key) + { + return this.encryptionKeyWrapProvider.WrapKeyAsync(encryptionKeyId, algorithm.ToString(), key) + .ConfigureAwait(false) + .GetAwaiter() + .GetResult(); + } + + /// + /// The public facing Cosmos Encryption library interface does not expose this method, hence not supported. + /// + public override byte[] Sign(string encryptionKeyId, bool allowEnclaveComputations) + { + throw new NotSupportedException("The Sign operation is not supported. "); + } + + /// + /// The public facing Cosmos Encryption library interface does not expose this method, hence not supported. + /// + public override bool Verify(string encryptionKeyId, bool allowEnclaveComputations, byte[] signature) + { + throw new NotSupportedException("The Verify operation is not supported. "); + } + } +} diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/EncryptionKeyWrapProvider.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/EncryptionKeyWrapProvider.cs new file mode 100644 index 0000000000..408f060a7c --- /dev/null +++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/EncryptionKeyWrapProvider.cs @@ -0,0 +1,92 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Encryption +{ + using System; + using System.Threading.Tasks; + using Microsoft.Data.Encryption.Cryptography; + + /// + /// Base class for all key store providers. A custom provider must derive from this + /// class and override its member functions. + /// + public abstract class EncryptionKeyWrapProvider + { + internal EncryptionKeyWrapProvider() + { + this.EncryptionKeyStoreProviderImpl = new EncryptionKeyStoreProviderImpl(this); + } + + /// + /// Gets or sets the lifespan of the decrypted data encryption key in the cache. + /// Once the timespan has elapsed, the decrypted data encryption key is discarded + /// and must be revalidated. + /// + /// + /// Internally, there is a cache of key encryption keys (once they are unwrapped). + /// This is useful for rapidly decrypting multiple data values. The default value is 2 hours. + /// Setting the to zero disables caching. + /// + public TimeSpan? DataEncryptionKeyCacheTimeToLive + { + get => this.EncryptionKeyStoreProviderImpl.DataEncryptionKeyCacheTimeToLive; + set + { + this.EncryptionKeyStoreProviderImpl.DataEncryptionKeyCacheTimeToLive = value; + + // set the TTL for ProtectedDataEncryption, so that we have a uniform expiry of the KeyStoreProvider and ProtectedDataEncryption cache items. + if (this.EncryptionKeyStoreProviderImpl.DataEncryptionKeyCacheTimeToLive.HasValue) + { + if (EncryptionCosmosClient.EncryptionKeyCacheSemaphore.Wait(-1)) + { + try + { + // pick the min of the new value being set and ProtectedDataEncryptionKey's current TTL. Note ProtectedDataEncryptionKey TimeToLive is static + // and results in various instances to share this value. Hence we pick up whatever is the min value. If a TimeSpan.Zero is across any one instance + // it should be fine, since we look up the KeyStoreProvider cache. ProtectedDataEncryptionKey's own cache supersedes KeyStoreProvider cache, since it stores + // the RootKey which is derived from unwrapped key(Data Encryption Key). + // Note: DataEncryptionKeyCacheTimeToLive is nullable. When set to null this results in AbsoluteExpirationRelativeToNow to be set to null which caches forever. + // whatever is the current set value for ProtectedDataEncryptionKey TimeToLive(is not nullable) would be min if null value is passed. + if (TimeSpan.Compare(this.EncryptionKeyStoreProviderImpl.DataEncryptionKeyCacheTimeToLive.Value, ProtectedDataEncryptionKey.TimeToLive) < 0) + { + ProtectedDataEncryptionKey.TimeToLive = this.EncryptionKeyStoreProviderImpl.DataEncryptionKeyCacheTimeToLive.Value; + } + } + finally + { + EncryptionCosmosClient.EncryptionKeyCacheSemaphore.Release(1); + } + } + } + } + } + + /// + /// Gets the unique name that identifies a particular implementation of the abstract . + /// + public abstract string ProviderName { get; } + + internal EncryptionKeyStoreProviderImpl EncryptionKeyStoreProviderImpl { get; } + + /// + /// Unwraps the specified of a data encryption key. The encrypted value is expected to be encrypted using + /// the key encryption key with the specified and using the specified . + /// + /// The key Id tells the provider where to find the key. + /// The key encryption algorithm. + /// The ciphertext key. + /// The unwrapped data encryption key. + public abstract Task UnwrapKeyAsync(string encryptionKeyId, string keyEncryptionKeyAlgorithm, byte[] encryptedKey); + + /// + /// Wraps a data encryption key using the key encryption key with the specified and using the specified . + /// + /// The key Id tells the provider where to find the key. + /// The key encryption algorithm. + /// The plaintext key. + /// The wrapped data encryption key. + public abstract Task WrapKeyAsync(string encryptionKeyId, string keyEncryptionKeyAlgorithm, byte[] key); + } +} diff --git a/Microsoft.Azure.Cosmos.Encryption/src/CosmosEncryptionType.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/EncryptionType.cs similarity index 58% rename from Microsoft.Azure.Cosmos.Encryption/src/CosmosEncryptionType.cs rename to Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/EncryptionType.cs index 111b54e3bf..f602f6e8b2 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/CosmosEncryptionType.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/EncryptionType.cs @@ -5,9 +5,17 @@ namespace Microsoft.Azure.Cosmos.Encryption { /// - /// Algorithms for use with client-side encryption support in Azure Cosmos DB. + /// Represents the encryption algorithms supported for data encryption. /// - internal static class CosmosEncryptionType + /// + /// The type of data encryption. + /// + /// + /// The two encryption types are Deterministic and Randomized. + /// Deterministic encryption always generates the same encrypted value for any given plain text value. + /// Randomized encryption uses a method that encrypts data in a less predictable manner. Randomized encryption is more secure. + /// + public static class EncryptionType { /// /// Deterministic encryption always generates the same encrypted value for any given plain text value. diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/KeyEncryptionKeyAlgorithm.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/KeyEncryptionKeyAlgorithm.cs new file mode 100644 index 0000000000..255000884f --- /dev/null +++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSupport/KeyEncryptionKeyAlgorithm.cs @@ -0,0 +1,17 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Encryption +{ + /// + /// Represents the encryption algorithms supported for key encryption. + /// + public static class KeyEncryptionKeyAlgorithm + { + /// + /// RSA public key cryptography algorithm with Optimal Asymmetric Encryption Padding (OAEP) padding. + /// + public const string RsaOaep = "RSA_OAEP"; + } +} diff --git a/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj b/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj index 85bf7c8b48..b0a6d4465a 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj +++ b/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj @@ -35,6 +35,7 @@ + diff --git a/Microsoft.Azure.Cosmos.Encryption/src/QueryDefinitionExtensions.cs b/Microsoft.Azure.Cosmos.Encryption/src/QueryDefinitionExtensions.cs index 808c8e8307..c9ee880032 100644 --- a/Microsoft.Azure.Cosmos.Encryption/src/QueryDefinitionExtensions.cs +++ b/Microsoft.Azure.Cosmos.Encryption/src/QueryDefinitionExtensions.cs @@ -88,7 +88,7 @@ public static async Task AddParameterAsync( return queryDefinitionwithEncryptedValues; } - if (settingsForProperty.EncryptionType == EncryptionType.Randomized) + if (settingsForProperty.EncryptionType == Data.Encryption.Cryptography.EncryptionType.Randomized) { throw new ArgumentException($"Unsupported argument with Path: {path} for query. For executing queries on encrypted path requires the use of deterministic encryption type. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } diff --git a/Microsoft.Azure.Cosmos.Encryption/tests/EmulatorTests/MdeEncryptionTests.cs b/Microsoft.Azure.Cosmos.Encryption/tests/EmulatorTests/MdeEncryptionTests.cs index b44fe889e4..5eccc58c7a 100644 --- a/Microsoft.Azure.Cosmos.Encryption/tests/EmulatorTests/MdeEncryptionTests.cs +++ b/Microsoft.Azure.Cosmos.Encryption/tests/EmulatorTests/MdeEncryptionTests.cs @@ -10,13 +10,13 @@ namespace Microsoft.Azure.Cosmos.Encryption.EmulatorTests using System.IO; using System.Linq; using System.Net; + using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using global::Azure; using Microsoft.Azure.Cosmos; using Microsoft.Azure.Cosmos.Encryption; - using Microsoft.Data.Encryption.Cryptography; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -33,22 +33,22 @@ public class MdeEncryptionTests private static Database database; private static Container encryptionContainer; private static Container encryptionContainerForChangeFeed; - private static TestEncryptionKeyStoreProvider testEncryptionKeyStoreProvider; + private static TestEncryptionKeyWrapProvider testEncryptionKeyWrapProvider; [ClassInitialize] [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "The ClassInitialize method takes a single parameter of type TestContext.")] public static async Task ClassInitialize(TestContext context) { MdeEncryptionTests.client = TestCommon.CreateCosmosClient(); - testEncryptionKeyStoreProvider = new TestEncryptionKeyStoreProvider + testEncryptionKeyWrapProvider = new TestEncryptionKeyWrapProvider { DataEncryptionKeyCacheTimeToLive = null }; - metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, "key1", "tempmetadata1"); - metadata2 = new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, "key2", "tempmetadata2"); + metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, "key1", "tempmetadata1"); + metadata2 = new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, "key2", "tempmetadata2"); - MdeEncryptionTests.encryptionCosmosClient = MdeEncryptionTests.client.WithEncryption(testEncryptionKeyStoreProvider); + MdeEncryptionTests.encryptionCosmosClient = MdeEncryptionTests.client.WithEncryption(testEncryptionKeyWrapProvider); MdeEncryptionTests.database = await MdeEncryptionTests.encryptionCosmosClient.CreateDatabaseAsync(Guid.NewGuid().ToString()); await MdeEncryptionTests.CreateClientEncryptionKeyAsync( @@ -60,10 +60,10 @@ await MdeEncryptionTests.CreateClientEncryptionKeyAsync( metadata2); - EncryptionKeyWrapMetadata revokedKekmetadata = new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, "revokedKek", "revokedKek-metadata"); + EncryptionKeyWrapMetadata revokedKekmetadata = new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, "revokedKek", "revokedKek-metadata"); await database.CreateClientEncryptionKeyAsync( "keywithRevokedKek", - DataEncryptionKeyAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256, + DataEncryptionKeyAlgorithm.AeadAes256CbcHmacSha256, revokedKekmetadata); Collection paths = new Collection() @@ -183,7 +183,7 @@ private static async Task CreateClientEncryptionKey { ClientEncryptionKeyResponse clientEncrytionKeyResponse = await database.CreateClientEncryptionKeyAsync( cekId, - DataEncryptionKeyAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256, + DataEncryptionKeyAlgorithm.AeadAes256CbcHmacSha256, encryptionKeyWrapMetadata); Assert.AreEqual(HttpStatusCode.Created, clientEncrytionKeyResponse.StatusCode); @@ -235,7 +235,7 @@ public async Task EncryptionBulkCrud() .WithBulkExecution(true) .Build()); - CosmosClient encryptionCosmosClientWithBulk = clientWithBulk.WithEncryption(new TestEncryptionKeyStoreProvider()); + CosmosClient encryptionCosmosClientWithBulk = clientWithBulk.WithEncryption(new TestEncryptionKeyWrapProvider()); Database databaseWithBulk = encryptionCosmosClientWithBulk.GetDatabase(MdeEncryptionTests.database.Id); Container encryptionContainerWithBulk = databaseWithBulk.GetContainer(MdeEncryptionTests.encryptionContainer.Id); @@ -257,18 +257,18 @@ public async Task EncryptionCreateClientEncryptionKey() { string cekId = "anotherCek"; - EncryptionKeyWrapMetadata metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, cekId, "testmetadata1"); + EncryptionKeyWrapMetadata metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, cekId, "testmetadata1"); ClientEncryptionKeyProperties clientEncryptionKeyProperties = await MdeEncryptionTests.CreateClientEncryptionKeyAsync( cekId, metadata1); Assert.AreEqual( - new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, name: cekId, value: metadata1.Value), + new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, name: cekId, value: metadata1.Value), clientEncryptionKeyProperties.EncryptionKeyWrapMetadata); // creating another key with same id should fail - metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, cekId, "testmetadata2"); + metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, cekId, "testmetadata2"); try { @@ -289,22 +289,22 @@ await MdeEncryptionTests.CreateClientEncryptionKeyAsync( public async Task EncryptionRewrapClientEncryptionKey() { string cekId = "rewrapkeytest"; - EncryptionKeyWrapMetadata metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, cekId, "testmetadata1"); + EncryptionKeyWrapMetadata metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, cekId, "testmetadata1"); ClientEncryptionKeyProperties clientEncryptionKeyProperties = await MdeEncryptionTests.CreateClientEncryptionKeyAsync( cekId, metadata1); Assert.AreEqual( - new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, name: cekId, value: metadata1.Value), + new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, name: cekId, value: metadata1.Value), clientEncryptionKeyProperties.EncryptionKeyWrapMetadata); - EncryptionKeyWrapMetadata updatedMetaData = new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, cekId, metadata1 + "updatedmetadata"); + EncryptionKeyWrapMetadata updatedMetaData = new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, cekId, metadata1 + "updatedmetadata"); clientEncryptionKeyProperties = await MdeEncryptionTests.RewarpClientEncryptionKeyAsync( cekId, updatedMetaData); Assert.AreEqual( - new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, name: cekId, value: updatedMetaData.Value), + new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, name: cekId, value: updatedMetaData.Value), clientEncryptionKeyProperties.EncryptionKeyWrapMetadata); } @@ -332,12 +332,12 @@ public async Task EncryptionCreateItemWithNullProperty() CosmosClient clientWithNoCaching = TestCommon.CreateCosmosClient(builder => builder .Build()); - TestEncryptionKeyStoreProvider testEncryptionKeyStoreProvider = new TestEncryptionKeyStoreProvider + TestEncryptionKeyWrapProvider testEncryptionKeyWrapProvider = new TestEncryptionKeyWrapProvider { DataEncryptionKeyCacheTimeToLive = TimeSpan.Zero }; - CosmosClient encryptionCosmosClient = clientWithNoCaching.WithEncryption(testEncryptionKeyStoreProvider); + CosmosClient encryptionCosmosClient = clientWithNoCaching.WithEncryption(testEncryptionKeyWrapProvider); Database database = encryptionCosmosClient.GetDatabase(MdeEncryptionTests.database.Id); Container encryptionContainer = database.GetContainer(MdeEncryptionTests.encryptionContainer.Id); @@ -395,7 +395,7 @@ await MdeEncryptionTests.ValidateQueryResultsAsync( expectedDoc: expectedDoc); // no access to key. - testEncryptionKeyStoreProvider.RevokeAccessSet = true; + testEncryptionKeyWrapProvider.RevokeAccessSet = true; testDoc = TestDoc.Create(); @@ -409,7 +409,7 @@ await MdeEncryptionTests.ValidateQueryResultsAsync( Assert.AreEqual(HttpStatusCode.Created, createResponse.StatusCode); VerifyExpectedDocResponse(testDoc, createResponse.Resource); - testEncryptionKeyStoreProvider.RevokeAccessSet = false; + testEncryptionKeyWrapProvider.RevokeAccessSet = false; } @@ -428,18 +428,18 @@ public async Task EncryptionResourceTokenAuthRestricted() restrictedUserPermission.Token); - CosmosClient encryptedclientForRestrictedUser = clientForRestrictedUser.WithEncryption(new TestEncryptionKeyStoreProvider()); + CosmosClient encryptedclientForRestrictedUser = clientForRestrictedUser.WithEncryption(new TestEncryptionKeyWrapProvider()); Database databaseForRestrictedUser = encryptedclientForRestrictedUser.GetDatabase(MdeEncryptionTests.database.Id); try { string cekId = "testingcekID"; - EncryptionKeyWrapMetadata metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, cekId, "testmetadata1"); + EncryptionKeyWrapMetadata metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, cekId, "testmetadata1"); ClientEncryptionKeyResponse clientEncrytionKeyResponse = await databaseForRestrictedUser.CreateClientEncryptionKeyAsync( cekId, - DataEncryptionKeyAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256, + DataEncryptionKeyAlgorithm.AeadAes256CbcHmacSha256, metadata1); Assert.Fail("CreateClientEncryptionKeyAsync should have failed due to restrictions"); } @@ -450,7 +450,7 @@ public async Task EncryptionResourceTokenAuthRestricted() try { string cekId = "testingcekID"; - EncryptionKeyWrapMetadata metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, cekId, "testmetadata1" + "updated"); + EncryptionKeyWrapMetadata metadata1 = new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, cekId, "testmetadata1" + "updated"); ClientEncryptionKeyResponse clientEncrytionKeyResponse = await databaseForRestrictedUser.RewrapClientEncryptionKeyAsync( cekId, @@ -1001,7 +1001,7 @@ public async Task EncryptionValidatePolicyRefreshPostContainerDeleteWithBulk() .WithBulkExecution(false) .Build()); - CosmosClient otherEncryptionClient = otherClient.WithEncryption(new TestEncryptionKeyStoreProvider()); + CosmosClient otherEncryptionClient = otherClient.WithEncryption(new TestEncryptionKeyWrapProvider()); Database otherDatabase = otherEncryptionClient.GetDatabase(MdeEncryptionTests.database.Id); Container otherEncryptionContainer = otherDatabase.GetContainer(encryptionContainerToDelete.Id); @@ -1150,7 +1150,7 @@ public async Task EncryptionValidatePolicyRefreshPostContainerDeleteTransactionB CosmosClient otherClient = TestCommon.CreateCosmosClient(builder => builder .Build()); - CosmosClient otherEncryptionClient = otherClient.WithEncryption(new TestEncryptionKeyStoreProvider()); + CosmosClient otherEncryptionClient = otherClient.WithEncryption(new TestEncryptionKeyWrapProvider()); Database otherDatabase = otherEncryptionClient.GetDatabase(MdeEncryptionTests.database.Id); Container otherEncryptionContainer = otherDatabase.GetContainer(encryptionContainerToDelete.Id); @@ -1282,7 +1282,7 @@ public async Task EncryptionValidatePolicyRefreshPostContainerDeleteQuery() CosmosClient otherClient = TestCommon.CreateCosmosClient(builder => builder .Build()); - CosmosClient otherEncryptionClient = otherClient.WithEncryption(new TestEncryptionKeyStoreProvider()); + CosmosClient otherEncryptionClient = otherClient.WithEncryption(new TestEncryptionKeyWrapProvider()); Database otherDatabase = otherEncryptionClient.GetDatabase(MdeEncryptionTests.database.Id); Container otherEncryptionContainer = otherDatabase.GetContainer(encryptionContainerToDelete.Id); @@ -1397,7 +1397,7 @@ public async Task EncryptionValidatePolicyRefreshPostContainerDeletePatch() CosmosClient otherClient = TestCommon.CreateCosmosClient(builder => builder .Build()); - CosmosClient otherEncryptionClient = otherClient.WithEncryption(new TestEncryptionKeyStoreProvider()); + CosmosClient otherEncryptionClient = otherClient.WithEncryption(new TestEncryptionKeyWrapProvider()); Database otherDatabase = otherEncryptionClient.GetDatabase(MdeEncryptionTests.database.Id); Container otherEncryptionContainer = otherDatabase.GetContainer(encryptionContainerToDelete.Id); @@ -1544,18 +1544,18 @@ public async Task EncryptionValidatePolicyRefreshPostDatabaseDelete() CosmosClient mainClient = TestCommon.CreateCosmosClient(builder => builder .Build()); - TestEncryptionKeyStoreProvider testEncryptionKeyStoreProvider = new TestEncryptionKeyStoreProvider + TestEncryptionKeyWrapProvider testEncryptionKeyWrapProvider = new TestEncryptionKeyWrapProvider { DataEncryptionKeyCacheTimeToLive = TimeSpan.FromMinutes(30), }; - EncryptionKeyWrapMetadata keyWrapMetadata = new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider.ProviderName, "myCek", "mymetadata1"); - CosmosClient encryptionCosmosClient = mainClient.WithEncryption(testEncryptionKeyStoreProvider); + EncryptionKeyWrapMetadata keyWrapMetadata = new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider.ProviderName, "myCek", "mymetadata1"); + CosmosClient encryptionCosmosClient = mainClient.WithEncryption(testEncryptionKeyWrapProvider); Database mainDatabase = await encryptionCosmosClient.CreateDatabaseAsync("databaseToBeDeleted"); ClientEncryptionKeyResponse clientEncrytionKeyResponse = await mainDatabase.CreateClientEncryptionKeyAsync( keyWrapMetadata.Name, - DataEncryptionKeyAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256, + DataEncryptionKeyAlgorithm.AeadAes256CbcHmacSha256, keyWrapMetadata); Collection originalPaths = new Collection() @@ -1597,12 +1597,12 @@ public async Task EncryptionValidatePolicyRefreshPostDatabaseDelete() CosmosClient otherClient1 = TestCommon.CreateCosmosClient(builder => builder .Build()); - TestEncryptionKeyStoreProvider testEncryptionKeyStoreProvider2 = new TestEncryptionKeyStoreProvider + TestEncryptionKeyWrapProvider testEncryptionKeyWrapProvider2 = new TestEncryptionKeyWrapProvider { DataEncryptionKeyCacheTimeToLive = TimeSpan.Zero, }; - CosmosClient otherEncryptionClient = otherClient1.WithEncryption(testEncryptionKeyStoreProvider2); + CosmosClient otherEncryptionClient = otherClient1.WithEncryption(testEncryptionKeyWrapProvider2); Database otherDatabase = otherEncryptionClient.GetDatabase(mainDatabase.Id); Container otherEncryptionContainer = otherDatabase.GetContainer(encryptionContainerToDelete.Id); @@ -1615,10 +1615,10 @@ public async Task EncryptionValidatePolicyRefreshPostDatabaseDelete() mainDatabase = await encryptionCosmosClient.CreateDatabaseAsync("databaseToBeDeleted"); - keyWrapMetadata = new EncryptionKeyWrapMetadata(testEncryptionKeyStoreProvider2.ProviderName, "myCek", "mymetadata2"); + keyWrapMetadata = new EncryptionKeyWrapMetadata(testEncryptionKeyWrapProvider2.ProviderName, "myCek", "mymetadata2"); clientEncrytionKeyResponse = await mainDatabase.CreateClientEncryptionKeyAsync( keyWrapMetadata.Name, - DataEncryptionKeyAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256, + DataEncryptionKeyAlgorithm.AeadAes256CbcHmacSha256, keyWrapMetadata); using (await mainDatabase.GetContainer(encryptionContainerToDelete.Id).DeleteContainerStreamAsync()) @@ -1723,12 +1723,12 @@ public async Task EncryptionValidatePolicyRefreshPostDatabaseDelete() .WithBulkExecution(true) .Build()); - TestEncryptionKeyStoreProvider testEncryptionKeyStoreProvider3 = new TestEncryptionKeyStoreProvider + TestEncryptionKeyWrapProvider testEncryptionKeyWrapProvider3 = new TestEncryptionKeyWrapProvider { DataEncryptionKeyCacheTimeToLive = TimeSpan.FromMinutes(30), }; - CosmosClient otherEncryptionClient2 = otherClient2.WithEncryption(testEncryptionKeyStoreProvider3); + CosmosClient otherEncryptionClient2 = otherClient2.WithEncryption(testEncryptionKeyWrapProvider3); Database otherDatabase2 = otherEncryptionClient2.GetDatabase(mainDatabase.Id); Container otherEncryptionContainer3 = otherDatabase2.GetContainer(otherEncryptionContainer2.Id); @@ -1774,18 +1774,102 @@ public async Task EncryptionValidatePolicyRefreshPostDatabaseDelete() await mainClient.GetDatabase("databaseToBeDeleted").DeleteStreamAsync(); } + [TestMethod] + public void MdeEncryptionTypesContractTest() + { + string[] cosmosSupportedEncryptionTypes = typeof(EncryptionType) + .GetMembers(BindingFlags.Static | BindingFlags.Public) + .Select(e => ((FieldInfo)e).GetValue(e).ToString()) + .ToArray(); + + string[] mdeSupportedEncryptionTypes = typeof(Data.Encryption.Cryptography.EncryptionType) + .GetMembers(BindingFlags.Static | BindingFlags.Public) + .Select(e => e.Name) + .ToArray(); + + if (mdeSupportedEncryptionTypes.Length > cosmosSupportedEncryptionTypes.Length) + { + HashSet missingEncryptionTypes = new HashSet(mdeSupportedEncryptionTypes); + foreach (string encryptionTypes in cosmosSupportedEncryptionTypes) + { + missingEncryptionTypes.Remove(encryptionTypes); + } + + // no Plaintext support. + missingEncryptionTypes.Remove("Plaintext"); + mdeSupportedEncryptionTypes = mdeSupportedEncryptionTypes.Where(value => value != "Plaintext").ToArray(); + + if (missingEncryptionTypes.Count != 0) + { + Assert.Fail($"Missing EncryptionType support from CosmosEncryptionType: {string.Join(";", missingEncryptionTypes)}"); + } + } + + CollectionAssert.AreEquivalent(mdeSupportedEncryptionTypes, cosmosSupportedEncryptionTypes); + } + + [TestMethod] + public void MdeEncryptionAlgorithmsTypesContractTest() + { + string[] cosmosKeyEncryptionAlgorithms = typeof(KeyEncryptionKeyAlgorithm) + .GetMembers(BindingFlags.Static | BindingFlags.Public) + .Select(e => ((FieldInfo)e).GetValue(e).ToString()) + .ToArray(); + + string[] mdeKeyEncryptionAlgorithms = typeof(Data.Encryption.Cryptography.KeyEncryptionKeyAlgorithm) + .GetMembers(BindingFlags.Static | BindingFlags.Public) + .Select(e => e.Name) + .ToArray(); + + if (mdeKeyEncryptionAlgorithms.Length > cosmosKeyEncryptionAlgorithms.Length) + { + HashSet missingKeyEncryptionAlgorithms = new HashSet(mdeKeyEncryptionAlgorithms); + foreach (string algorithm in cosmosKeyEncryptionAlgorithms) + { + missingKeyEncryptionAlgorithms.Remove(algorithm); + } + + Assert.Fail($"Missing key encryption algorithm support from CosmosKeyEncryptionKeyAlgorithm: {string.Join(";", missingKeyEncryptionAlgorithms)}"); + } + + CollectionAssert.AreEquivalent(mdeKeyEncryptionAlgorithms, cosmosKeyEncryptionAlgorithms); + + string[] cosmosDataEncryptionAlgorithms = typeof(DataEncryptionKeyAlgorithm) + .GetMembers(BindingFlags.Static | BindingFlags.Public) + .Select(e => ((FieldInfo)e).GetValue(e).ToString()) + .ToArray(); + + string[] mdeDataEncryptionAlgorithms = typeof(Data.Encryption.Cryptography.DataEncryptionKeyAlgorithm) + .GetMembers(BindingFlags.Static | BindingFlags.Public) + .Select(e => e.Name) + .ToArray(); + + if (mdeDataEncryptionAlgorithms.Length > cosmosDataEncryptionAlgorithms.Length) + { + HashSet missingDataEncryptionAlgorithms = new HashSet(mdeDataEncryptionAlgorithms); + foreach (string algorithm in cosmosDataEncryptionAlgorithms) + { + missingDataEncryptionAlgorithms.Remove(algorithm); + } + + Assert.Fail($"Missing data encryption algorithm support from CosmosDataEncryptionKeyAlgorithm: {string.Join(";", missingDataEncryptionAlgorithms)}"); + } + + CollectionAssert.AreEquivalent(mdeDataEncryptionAlgorithms, cosmosDataEncryptionAlgorithms); + } + [TestMethod] public async Task VerifyKekRevokeHandling() { CosmosClient clientWithNoCaching = TestCommon.CreateCosmosClient(builder => builder .Build()); - TestEncryptionKeyStoreProvider testEncryptionKeyStoreProvider = new TestEncryptionKeyStoreProvider + TestEncryptionKeyWrapProvider testEncryptionKeyWrapProvider = new TestEncryptionKeyWrapProvider { DataEncryptionKeyCacheTimeToLive = TimeSpan.Zero }; - CosmosClient encryptionCosmosClient = clientWithNoCaching.WithEncryption(testEncryptionKeyStoreProvider); + CosmosClient encryptionCosmosClient = clientWithNoCaching.WithEncryption(testEncryptionKeyWrapProvider); Database database = encryptionCosmosClient.GetDatabase(MdeEncryptionTests.database.Id); // Once a Dek gets cached and the Kek is revoked, calls to unwrap/wrap keys would fail since KEK is revoked. @@ -1809,7 +1893,7 @@ public async Task VerifyKekRevokeHandling() TestDoc testDoc1 = await MdeEncryptionTests.MdeCreateItemAsync(encryptionContainer); - testEncryptionKeyStoreProvider.RevokeAccessSet = true; + testEncryptionKeyWrapProvider.RevokeAccessSet = true; // try creating it and it should fail as it has been revoked. try @@ -1837,16 +1921,16 @@ await MdeEncryptionTests.ValidateQueryResultsAsync( } // for unwrap to succeed - testEncryptionKeyStoreProvider.RevokeAccessSet = false; + testEncryptionKeyWrapProvider.RevokeAccessSet = false; // lets rewrap it. await database.RewrapClientEncryptionKeyAsync("keywithRevokedKek", MdeEncryptionTests.metadata2); - testEncryptionKeyStoreProvider.RevokeAccessSet = true; + testEncryptionKeyWrapProvider.RevokeAccessSet = true; // Should fail but will try to fetch the lastest from the Backend and updates the cache. await MdeEncryptionTests.MdeCreateItemAsync(encryptionContainer); - testEncryptionKeyStoreProvider.RevokeAccessSet = false; - testEncryptionKeyStoreProvider.DataEncryptionKeyCacheTimeToLive = TimeSpan.FromMinutes(120); + testEncryptionKeyWrapProvider.RevokeAccessSet = false; + testEncryptionKeyWrapProvider.DataEncryptionKeyCacheTimeToLive = TimeSpan.FromMinutes(120); } [TestMethod] @@ -2126,7 +2210,7 @@ public async Task EncryptionTransactionalBatchWithCustomSerializer() .WithCustomSerializer(customSerializer) .Build()); - CosmosClient encryptionCosmosClientWithCustomSerializer = clientWithCustomSerializer.WithEncryption(new TestEncryptionKeyStoreProvider()); + CosmosClient encryptionCosmosClientWithCustomSerializer = clientWithCustomSerializer.WithEncryption(new TestEncryptionKeyWrapProvider()); Database databaseWithCustomSerializer = encryptionCosmosClientWithCustomSerializer.GetDatabase(MdeEncryptionTests.database.Id); Container encryptionContainerWithCustomSerializer = databaseWithCustomSerializer.GetContainer(MdeEncryptionTests.encryptionContainer.Id); @@ -2184,8 +2268,8 @@ await MdeEncryptionTests.ValidateQueryResultsAsync( public async Task ValidateCachingofProtectedDataEncryptionKey() { // Default cache TTL 2 hours. - TestEncryptionKeyStoreProvider newtestEncryptionKeyStoreProvider = new TestEncryptionKeyStoreProvider(); - CosmosClient newEncryptionClient = MdeEncryptionTests.client.WithEncryption(newtestEncryptionKeyStoreProvider); + TestEncryptionKeyWrapProvider newtestEncryptionKeyWrapProvider = new TestEncryptionKeyWrapProvider(); + CosmosClient newEncryptionClient = MdeEncryptionTests.client.WithEncryption(newtestEncryptionKeyWrapProvider); Database database = newEncryptionClient.GetDatabase(MdeEncryptionTests.database.Id); Container encryptionContainer = database.GetContainer(MdeEncryptionTests.encryptionContainer.Id); @@ -2195,17 +2279,13 @@ public async Task ValidateCachingofProtectedDataEncryptionKey() await MdeEncryptionTests.MdeCreateItemAsync(encryptionContainer); } - newtestEncryptionKeyStoreProvider.UnWrapKeyCallsCount.TryGetValue(metadata1.Value, out int unwrapcount); + newtestEncryptionKeyWrapProvider.UnWrapKeyCallsCount.TryGetValue(metadata1.Value, out int unwrapcount); // expecting just one unwrap. Assert.AreEqual(1, unwrapcount); // no caching. - newtestEncryptionKeyStoreProvider = new TestEncryptionKeyStoreProvider() - { - DataEncryptionKeyCacheTimeToLive = TimeSpan.Zero, - }; + newtestEncryptionKeyWrapProvider.DataEncryptionKeyCacheTimeToLive = TimeSpan.Zero; - newEncryptionClient = MdeEncryptionTests.client.WithEncryption(newtestEncryptionKeyStoreProvider); database = newEncryptionClient.GetDatabase(MdeEncryptionTests.database.Id); encryptionContainer = database.GetContainer(MdeEncryptionTests.encryptionContainer.Id); @@ -2215,7 +2295,7 @@ public async Task ValidateCachingofProtectedDataEncryptionKey() await MdeEncryptionTests.MdeCreateItemAsync(encryptionContainer); } - newtestEncryptionKeyStoreProvider.UnWrapKeyCallsCount.TryGetValue(metadata1.Value, out unwrapcount); + newtestEncryptionKeyWrapProvider.UnWrapKeyCallsCount.TryGetValue(metadata1.Value, out unwrapcount); Assert.IsTrue(unwrapcount > 1, "The actual unwrap count was not greater than 1"); } @@ -3214,7 +3294,7 @@ public Stream ToStream() } } - internal class TestEncryptionKeyStoreProvider : EncryptionKeyStoreProvider + internal class TestEncryptionKeyWrapProvider : EncryptionKeyWrapProvider { readonly Dictionary keyinfo = new Dictionary { @@ -3223,9 +3303,12 @@ internal class TestEncryptionKeyStoreProvider : EncryptionKeyStoreProvider }; public bool RevokeAccessSet { get; set; } + public Dictionary WrapKeyCallsCount { get; set; } + public Dictionary UnWrapKeyCallsCount { get; set; } - public TestEncryptionKeyStoreProvider() + + public TestEncryptionKeyWrapProvider() { this.WrapKeyCallsCount = new Dictionary(); this.UnWrapKeyCallsCount = new Dictionary(); @@ -3234,33 +3317,28 @@ public TestEncryptionKeyStoreProvider() public override string ProviderName => "TESTKEYSTORE_VAULT"; - public override byte[] UnwrapKey(string masterKeyPath, KeyEncryptionKeyAlgorithm encryptionAlgorithm, byte[] encryptedKey) + public override Task UnwrapKeyAsync(string masterKeyPath, string keyEncryptionKeyAlgorithm, byte[] encryptedKey) { if (masterKeyPath.Equals("revokedKek-metadata") && this.RevokeAccessSet) { throw new RequestFailedException((int)HttpStatusCode.Forbidden, "Forbidden"); } - return this.GetOrCreateDataEncryptionKey(encryptedKey.ToHexString(), DecryptEncryptionKey); - - byte[] DecryptEncryptionKey() + if (!this.UnWrapKeyCallsCount.ContainsKey(masterKeyPath)) { - if (!this.UnWrapKeyCallsCount.ContainsKey(masterKeyPath)) - { - this.UnWrapKeyCallsCount[masterKeyPath] = 1; - } - else - { - this.UnWrapKeyCallsCount[masterKeyPath]++; - } - - this.keyinfo.TryGetValue(masterKeyPath, out int moveBy); - byte[] plainkey = encryptedKey.Select(b => (byte)(b - moveBy)).ToArray(); - return plainkey; + this.UnWrapKeyCallsCount[masterKeyPath] = 1; } + else + { + this.UnWrapKeyCallsCount[masterKeyPath]++; + } + + this.keyinfo.TryGetValue(masterKeyPath, out int moveBy); + byte[] plainkey = encryptedKey.Select(b => (byte)(b - moveBy)).ToArray(); + return Task.FromResult(plainkey); } - public override byte[] WrapKey(string masterKeyPath, KeyEncryptionKeyAlgorithm encryptionAlgorithm, byte[] key) + public override Task WrapKeyAsync(string masterKeyPath, string keyEncryptionKeyAlgorithm, byte[] key) { if (!this.WrapKeyCallsCount.ContainsKey(masterKeyPath)) { @@ -3273,17 +3351,7 @@ public override byte[] WrapKey(string masterKeyPath, KeyEncryptionKeyAlgorithm e this.keyinfo.TryGetValue(masterKeyPath, out int moveBy); byte[] encryptedkey = key.Select(b => (byte)(b + moveBy)).ToArray(); - return encryptedkey; - } - - public override byte[] Sign(string masterKeyPath, bool allowEnclaveComputations) - { - return null; - } - - public override bool Verify(string masterKeyPath, bool allowEnclaveComputations, byte[] signature) - { - return true; + return Task.FromResult(encryptedkey); } } diff --git a/Microsoft.Azure.Cosmos.Encryption/tests/Microsoft.Azure.Cosmos.Encryption.Tests/Contracts/DotNetSDKEncryptionAPI.json b/Microsoft.Azure.Cosmos.Encryption/tests/Microsoft.Azure.Cosmos.Encryption.Tests/Contracts/DotNetSDKEncryptionAPI.json index 14887781c5..1f53d62344 100644 --- a/Microsoft.Azure.Cosmos.Encryption/tests/Microsoft.Azure.Cosmos.Encryption.Tests/Contracts/DotNetSDKEncryptionAPI.json +++ b/Microsoft.Azure.Cosmos.Encryption/tests/Microsoft.Azure.Cosmos.Encryption.Tests/Contracts/DotNetSDKEncryptionAPI.json @@ -1,5 +1,47 @@ { "Subclasses": { + "Microsoft.Azure.Cosmos.Encryption.AzureKeyVaultKeyWrapProvider;Microsoft.Azure.Cosmos.Encryption.EncryptionKeyWrapProvider;IsAbstract:False;IsSealed:True;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { + "Subclasses": {}, + "Members": { + "System.String get_ProviderName()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.String get_ProviderName();IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.String ProviderName": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.String ProviderName;CanRead:True;CanWrite:False;System.String get_ProviderName();IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.Threading.Tasks.Task`1[System.Byte[]] UnwrapKeyAsync(System.String, System.String, Byte[])": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.Threading.Tasks.Task`1[System.Byte[]] UnwrapKeyAsync(System.String, System.String, Byte[]);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.Threading.Tasks.Task`1[System.Byte[]] WrapKeyAsync(System.String, System.String, Byte[])": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.Threading.Tasks.Task`1[System.Byte[]] WrapKeyAsync(System.String, System.String, Byte[]);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Void .ctor(Azure.Core.TokenCredential)": { + "Type": "Constructor", + "Attributes": [], + "MethodInfo": "[Void .ctor(Azure.Core.TokenCredential), Void .ctor(Azure.Core.TokenCredential)]" + } + }, + "NestedTypes": {} + }, + "Microsoft.Azure.Cosmos.Encryption.DataEncryptionKeyAlgorithm;System.Object;IsAbstract:True;IsSealed:True;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { + "Subclasses": {}, + "Members": { + "System.String AeadAes256CbcHmacSha256": { + "Type": "Field", + "Attributes": [], + "MethodInfo": "System.String AeadAes256CbcHmacSha256;IsInitOnly:False;IsStatic:True;" + } + }, + "NestedTypes": {} + }, "Microsoft.Azure.Cosmos.Encryption.EncryptionContainerExtensions;System.Object;IsAbstract:True;IsSealed:True;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { "Subclasses": {}, "Members": { @@ -38,12 +80,12 @@ "Microsoft.Azure.Cosmos.Encryption.EncryptionCosmosClientExtensions;System.Object;IsAbstract:True;IsSealed:True;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { "Subclasses": {}, "Members": { - "Microsoft.Azure.Cosmos.CosmosClient WithEncryption(Microsoft.Azure.Cosmos.CosmosClient, Microsoft.Data.Encryption.Cryptography.EncryptionKeyStoreProvider)[System.Runtime.CompilerServices.ExtensionAttribute()]": { + "Microsoft.Azure.Cosmos.CosmosClient WithEncryption(Microsoft.Azure.Cosmos.CosmosClient, Microsoft.Azure.Cosmos.Encryption.EncryptionKeyWrapProvider)[System.Runtime.CompilerServices.ExtensionAttribute()]": { "Type": "Method", "Attributes": [ "ExtensionAttribute" ], - "MethodInfo": "Microsoft.Azure.Cosmos.CosmosClient WithEncryption(Microsoft.Azure.Cosmos.CosmosClient, Microsoft.Data.Encryption.Cryptography.EncryptionKeyStoreProvider);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + "MethodInfo": "Microsoft.Azure.Cosmos.CosmosClient WithEncryption(Microsoft.Azure.Cosmos.CosmosClient, Microsoft.Azure.Cosmos.Encryption.EncryptionKeyWrapProvider);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" } }, "NestedTypes": {} @@ -51,13 +93,13 @@ "Microsoft.Azure.Cosmos.Encryption.EncryptionDatabaseExtensions;System.Object;IsAbstract:True;IsSealed:True;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { "Subclasses": {}, "Members": { - "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ClientEncryptionKeyResponse] CreateClientEncryptionKeyAsync(Microsoft.Azure.Cosmos.Database, System.String, Microsoft.Data.Encryption.Cryptography.DataEncryptionKeyAlgorithm, Microsoft.Azure.Cosmos.EncryptionKeyWrapMetadata, System.Threading.CancellationToken)[System.Runtime.CompilerServices.AsyncStateMachineAttribute(typeof(Microsoft.Azure.Cosmos.Encryption.EncryptionDatabaseExtensions+))]-[System.Runtime.CompilerServices.ExtensionAttribute()]": { + "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ClientEncryptionKeyResponse] CreateClientEncryptionKeyAsync(Microsoft.Azure.Cosmos.Database, System.String, System.String, Microsoft.Azure.Cosmos.EncryptionKeyWrapMetadata, System.Threading.CancellationToken)[System.Runtime.CompilerServices.AsyncStateMachineAttribute(typeof(Microsoft.Azure.Cosmos.Encryption.EncryptionDatabaseExtensions+))]-[System.Runtime.CompilerServices.ExtensionAttribute()]": { "Type": "Method", "Attributes": [ "AsyncStateMachineAttribute", "ExtensionAttribute" ], - "MethodInfo": "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ClientEncryptionKeyResponse] CreateClientEncryptionKeyAsync(Microsoft.Azure.Cosmos.Database, System.String, Microsoft.Data.Encryption.Cryptography.DataEncryptionKeyAlgorithm, Microsoft.Azure.Cosmos.EncryptionKeyWrapMetadata, System.Threading.CancellationToken);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + "MethodInfo": "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ClientEncryptionKeyResponse] CreateClientEncryptionKeyAsync(Microsoft.Azure.Cosmos.Database, System.String, System.String, Microsoft.Azure.Cosmos.EncryptionKeyWrapMetadata, System.Threading.CancellationToken);IsAbstract:False;IsStatic:True;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" }, "System.Threading.Tasks.Task`1[Microsoft.Azure.Cosmos.ClientEncryptionKeyResponse] RewrapClientEncryptionKeyAsync(Microsoft.Azure.Cosmos.Database, System.String, Microsoft.Azure.Cosmos.EncryptionKeyWrapMetadata, System.Threading.CancellationToken)[System.Runtime.CompilerServices.AsyncStateMachineAttribute(typeof(Microsoft.Azure.Cosmos.Encryption.EncryptionDatabaseExtensions+))]-[System.Runtime.CompilerServices.ExtensionAttribute()]": { "Type": "Method", @@ -70,6 +112,106 @@ }, "NestedTypes": {} }, + "Microsoft.Azure.Cosmos.Encryption.EncryptionKeyWrapProvider;System.Object;IsAbstract:True;IsSealed:False;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { + "Subclasses": { + "Microsoft.Azure.Cosmos.Encryption.AzureKeyVaultKeyWrapProvider;Microsoft.Azure.Cosmos.Encryption.EncryptionKeyWrapProvider;IsAbstract:False;IsSealed:True;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { + "Subclasses": {}, + "Members": { + "System.String get_ProviderName()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.String get_ProviderName();IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.String ProviderName": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.String ProviderName;CanRead:True;CanWrite:False;System.String get_ProviderName();IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.Threading.Tasks.Task`1[System.Byte[]] UnwrapKeyAsync(System.String, System.String, Byte[])": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.Threading.Tasks.Task`1[System.Byte[]] UnwrapKeyAsync(System.String, System.String, Byte[]);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.Threading.Tasks.Task`1[System.Byte[]] WrapKeyAsync(System.String, System.String, Byte[])": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.Threading.Tasks.Task`1[System.Byte[]] WrapKeyAsync(System.String, System.String, Byte[]);IsAbstract:False;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Void .ctor(Azure.Core.TokenCredential)": { + "Type": "Constructor", + "Attributes": [], + "MethodInfo": "[Void .ctor(Azure.Core.TokenCredential), Void .ctor(Azure.Core.TokenCredential)]" + } + }, + "NestedTypes": {} + } + }, + "Members": { + "System.Nullable`1[System.TimeSpan] DataEncryptionKeyCacheTimeToLive": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.Nullable`1[System.TimeSpan] DataEncryptionKeyCacheTimeToLive;CanRead:True;CanWrite:True;System.Nullable`1[System.TimeSpan] get_DataEncryptionKeyCacheTimeToLive();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;Void set_DataEncryptionKeyCacheTimeToLive(System.Nullable`1[System.TimeSpan]);IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.Nullable`1[System.TimeSpan] get_DataEncryptionKeyCacheTimeToLive()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.Nullable`1[System.TimeSpan] get_DataEncryptionKeyCacheTimeToLive();IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.String get_ProviderName()": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.String get_ProviderName();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.String ProviderName": { + "Type": "Property", + "Attributes": [], + "MethodInfo": "System.String ProviderName;CanRead:True;CanWrite:False;System.String get_ProviderName();IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.Threading.Tasks.Task`1[System.Byte[]] UnwrapKeyAsync(System.String, System.String, Byte[])": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.Threading.Tasks.Task`1[System.Byte[]] UnwrapKeyAsync(System.String, System.String, Byte[]);IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "System.Threading.Tasks.Task`1[System.Byte[]] WrapKeyAsync(System.String, System.String, Byte[])": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "System.Threading.Tasks.Task`1[System.Byte[]] WrapKeyAsync(System.String, System.String, Byte[]);IsAbstract:True;IsStatic:False;IsVirtual:True;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + }, + "Void set_DataEncryptionKeyCacheTimeToLive(System.Nullable`1[System.TimeSpan])": { + "Type": "Method", + "Attributes": [], + "MethodInfo": "Void set_DataEncryptionKeyCacheTimeToLive(System.Nullable`1[System.TimeSpan]);IsAbstract:False;IsStatic:False;IsVirtual:False;IsGenericMethod:False;IsConstructor:False;IsFinal:False;" + } + }, + "NestedTypes": {} + }, + "Microsoft.Azure.Cosmos.Encryption.EncryptionType;System.Object;IsAbstract:True;IsSealed:True;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { + "Subclasses": {}, + "Members": { + "System.String Deterministic": { + "Type": "Field", + "Attributes": [], + "MethodInfo": "System.String Deterministic;IsInitOnly:False;IsStatic:True;" + }, + "System.String Randomized": { + "Type": "Field", + "Attributes": [], + "MethodInfo": "System.String Randomized;IsInitOnly:False;IsStatic:True;" + } + }, + "NestedTypes": {} + }, + "Microsoft.Azure.Cosmos.Encryption.KeyEncryptionKeyAlgorithm;System.Object;IsAbstract:True;IsSealed:True;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { + "Subclasses": {}, + "Members": { + "System.String RsaOaep": { + "Type": "Field", + "Attributes": [], + "MethodInfo": "System.String RsaOaep;IsInitOnly:False;IsStatic:True;" + } + }, + "NestedTypes": {} + }, "Microsoft.Azure.Cosmos.Encryption.QueryDefinitionExtensions;System.Object;IsAbstract:True;IsSealed:True;IsInterface:False;IsEnum:False;IsClass:True;IsValueType:False;IsNested:False;IsGenericType:False;IsSerializable:False": { "Subclasses": {}, "Members": {