/// <summary> /// Get Cosmos Client with Encryption support for performing operations using client-side encryption. /// </summary> /// <param name="cosmosClient">Regular Cosmos Client.</param> /// <param name="encryptionKeyStoreProvider">EncryptionKeyStoreProvider, provider that allows interaction with the master keys.</param> /// <returns> CosmosClient to perform operations supporting client-side encryption / decryption.</returns> public static CosmosClient WithEncryption( this CosmosClient cosmosClient, EncryptionKeyStoreProvider encryptionKeyStoreProvider) { if (encryptionKeyStoreProvider == null) { throw new ArgumentNullException(nameof(encryptionKeyStoreProvider)); } if (cosmosClient == null) { 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)); }
public EncryptionCosmosClient(CosmosClient cosmosClient, EncryptionKeyStoreProvider encryptionKeyStoreProvider) { this.cosmosClient = cosmosClient ?? throw new ArgumentNullException(nameof(cosmosClient)); this.EncryptionKeyStoreProvider = encryptionKeyStoreProvider ?? throw new ArgumentNullException(nameof(encryptionKeyStoreProvider)); this.clientEncryptionPolicyCacheByContainerId = new AsyncCache <string, ClientEncryptionPolicy>(); this.clientEncryptionKeyPropertiesCacheByKeyId = new AsyncCache <string, ClientEncryptionKeyProperties>(); }
/// <summary> /// Initializes a new instance of MdeEncryptionAlgorithm. /// Uses <see cref="AeadAes256CbcHmac256EncryptionAlgorithm"/> which implements authenticated encryption algorithm with associated data as described /// <see href="http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05">here</see> . /// More specifically this implements AEAD_AES_256_CBC_HMAC_SHA256 algorithm. /// </summary> /// <param name="dekProperties"> Data Encryption Key properties</param> /// <param name="encryptionType"> Encryption type </param> /// <param name="encryptionKeyStoreProvider"> EncryptionKeyStoreProvider for wrapping and unwrapping </param> public MdeEncryptionAlgorithm( DataEncryptionKeyProperties dekProperties, Data.Encryption.Cryptography.EncryptionType encryptionType, EncryptionKeyStoreProvider encryptionKeyStoreProvider, TimeSpan?cacheTimeToLive) { if (dekProperties == null) { throw new ArgumentNullException(nameof(dekProperties)); } if (encryptionKeyStoreProvider == null) { throw new ArgumentNullException(nameof(encryptionKeyStoreProvider)); } KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate( dekProperties.EncryptionKeyWrapMetadata.Name, dekProperties.EncryptionKeyWrapMetadata.Value, encryptionKeyStoreProvider); ProtectedDataEncryptionKey protectedDataEncryptionKey; if (cacheTimeToLive.HasValue) { // no caching if (cacheTimeToLive.Value == TimeSpan.Zero) { protectedDataEncryptionKey = new ProtectedDataEncryptionKey( dekProperties.Id, keyEncryptionKey, dekProperties.WrappedDataEncryptionKey); } else { protectedDataEncryptionKey = ProtectedDataEncryptionKey.GetOrCreate( dekProperties.Id, keyEncryptionKey, dekProperties.WrappedDataEncryptionKey); protectedDataEncryptionKey.TimeToLive = cacheTimeToLive.Value; } } else { protectedDataEncryptionKey = ProtectedDataEncryptionKey.GetOrCreate( dekProperties.Id, keyEncryptionKey, dekProperties.WrappedDataEncryptionKey); } this.mdeAeadAes256CbcHmac256EncryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate( protectedDataEncryptionKey, encryptionType); }
/// <summary> /// Initializes a new instance of the <see cref="CosmosDataEncryptionKeyProvider"/> class. /// </summary> /// <param name="encryptionKeyStoreProvider"> MDE EncryptionKeyStoreProvider for Wrapping/UnWrapping services. </param> /// <param name="cacheTimeToLive">Time to live for EncryptionKeyStoreProvider's ProtectedDataEncryptionKey before having to refresh. 0 results in no Caching.</param> /// <param name="dekPropertiesTimeToLive">Time to live for DEK properties before having to refresh.</param> public CosmosDataEncryptionKeyProvider( EncryptionKeyStoreProvider encryptionKeyStoreProvider, TimeSpan?cacheTimeToLive = null, TimeSpan?dekPropertiesTimeToLive = null) { this.EncryptionKeyStoreProvider = encryptionKeyStoreProvider ?? throw new ArgumentNullException(nameof(encryptionKeyStoreProvider)); this.MdeKeyWrapProvider = new MdeKeyWrapProvider(encryptionKeyStoreProvider); this.dataEncryptionKeyContainerCore = new DataEncryptionKeyContainerCore(this); this.DekCache = new DekCache(dekPropertiesTimeToLive); this.PdekCacheTimeToLive = cacheTimeToLive; }
internal ProtectedDataEncryptionKey BuildProtectedDataEncryptionKey( ClientEncryptionKeyProperties clientEncryptionKeyProperties, EncryptionKeyStoreProvider encryptionKeyStoreProvider, string keyId) { KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate( clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Name, clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Value, encryptionKeyStoreProvider); return(new ProtectedDataEncryptionKey( keyId, keyEncryptionKey, clientEncryptionKeyProperties.WrappedDataEncryptionKey)); }
/// <summary> /// Get Cosmos Client with Encryption support for performing operations using client-side encryption. /// </summary> /// <param name="cosmosClient">Regular Cosmos Client.</param> /// <param name="encryptionKeyStoreProvider">EncryptionKeyStoreProvider, provider that allows interaction with the master keys.</param> /// <returns> CosmosClient to perform operations supporting client-side encryption / decryption.</returns> public static CosmosClient WithEncryption( this CosmosClient cosmosClient, EncryptionKeyStoreProvider encryptionKeyStoreProvider) { if (encryptionKeyStoreProvider == null) { throw new ArgumentNullException(nameof(encryptionKeyStoreProvider)); } if (cosmosClient == null) { throw new ArgumentNullException(nameof(cosmosClient)); } return(new EncryptionCosmosClient(cosmosClient, encryptionKeyStoreProvider)); }
/// <summary> /// Initializes a new instance of the <see cref="CosmosDataEncryptionKeyProvider"/> class. /// </summary> /// <param name="encryptionKeyStoreProvider"> MDE EncryptionKeyStoreProvider for Wrapping/UnWrapping services. </param> /// <param name="dekPropertiesTimeToLive">Time to live for DEK properties before having to refresh.</param> public CosmosDataEncryptionKeyProvider( EncryptionKeyStoreProvider encryptionKeyStoreProvider, TimeSpan?dekPropertiesTimeToLive = null) { this.EncryptionKeyStoreProvider = encryptionKeyStoreProvider ?? throw new ArgumentNullException(nameof(encryptionKeyStoreProvider)); this.MdeKeyWrapProvider = new MdeKeyWrapProvider(encryptionKeyStoreProvider); this.dataEncryptionKeyContainerCore = new DataEncryptionKeyContainerCore(this); this.DekCache = new DekCache(dekPropertiesTimeToLive); this.PdekCacheTimeToLive = this.EncryptionKeyStoreProvider.DataEncryptionKeyCacheTimeToLive; if (this.PdekCacheTimeToLive.HasValue) { // set the TTL for Protected Data Encryption. ProtectedDataEncryptionKey.TimeToLive = this.PdekCacheTimeToLive.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); } }
/// <summary> /// Create a Client Encryption Key used to Encrypt data. /// </summary> /// <param name="database">Regular cosmos database.</param> /// <param name="clientEncryptionKeyId"> Client Encryption Key id.</param> /// <param name="dataEncryptionKeyAlgorithm"> Encryption Algorthm. </param> /// <param name="encryptionKeyWrapMetadata"> EncryptionKeyWrapMetadata.</param> /// <param name="cancellationToken"> cancellation token </param> /// <returns>Container to perform operations supporting client-side encryption / decryption.</returns> /// <example> /// This example shows how to create a new Client Encryption Key. /// /// <code language="c#"> /// <![CDATA[ /// ClientEncryptionKeyResponse response = await this.cosmosDatabase.CreateClientEncryptionKeyAsync( /// "testKey", /// DataEncryptionKeyAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256, /// new EncryptionKeyWrapMetadata("metadataName", "MetadataValue")); /// ]]> /// </code> /// </example> public static async Task <ClientEncryptionKeyResponse> CreateClientEncryptionKeyAsync( this Database database, string clientEncryptionKeyId, DataEncryptionKeyAlgorithm dataEncryptionKeyAlgorithm, EncryptionKeyWrapMetadata encryptionKeyWrapMetadata, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); if (string.IsNullOrWhiteSpace(clientEncryptionKeyId)) { throw new ArgumentNullException(nameof(clientEncryptionKeyId)); } string encryptionAlgorithm = dataEncryptionKeyAlgorithm.ToString(); if (!string.Equals(encryptionAlgorithm, DataEncryptionKeyAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256.ToString())) { throw new ArgumentException($"Invalid Encryption Algorithm '{encryptionAlgorithm}' passed. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } if (encryptionKeyWrapMetadata == null) { throw new ArgumentNullException(nameof(encryptionKeyWrapMetadata)); } EncryptionCosmosClient encryptionCosmosClient; if (database is EncryptionDatabase encryptionDatabase) { encryptionCosmosClient = encryptionDatabase.EncryptionCosmosClient; } else { 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; KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate( encryptionKeyWrapMetadata.Name, encryptionKeyWrapMetadata.Value, encryptionKeyStoreProvider); ProtectedDataEncryptionKey protectedDataEncryptionKey = new ProtectedDataEncryptionKey( clientEncryptionKeyId, keyEncryptionKey); byte[] wrappedDataEncryptionKey = protectedDataEncryptionKey.EncryptedValue; ClientEncryptionKeyProperties clientEncryptionKeyProperties = new ClientEncryptionKeyProperties( clientEncryptionKeyId, encryptionAlgorithm, wrappedDataEncryptionKey, encryptionKeyWrapMetadata); ClientEncryptionKeyResponse clientEncryptionKeyResponse = await database.CreateClientEncryptionKeyAsync( clientEncryptionKeyProperties, cancellationToken : cancellationToken); return(clientEncryptionKeyResponse); }
/// <summary> /// Rewrap an existing Client Encryption Key. /// </summary> /// <param name="database">Regular cosmos database.</param> /// <param name="clientEncryptionKeyId"> Client Encryption Key id.</param> /// <param name="newEncryptionKeyWrapMetadata"> EncryptionKeyWrapMetadata.</param> /// <param name="cancellationToken"> cancellation token </param> /// <returns>Container to perform operations supporting client-side encryption / decryption.</returns> /// <example> /// This example shows how to rewrap a Client Encryption Key. /// /// <code language="c#"> /// <![CDATA[ /// ClientEncryptionKeyResponse response = await this.cosmosDatabase.RewrapClientEncryptionKeyAsync( /// "keyToRewrap", /// new EncryptionKeyWrapMetadata("metadataName", "UpdatedMetadataValue"))); /// ]]> /// </code> /// </example> public static async Task <ClientEncryptionKeyResponse> RewrapClientEncryptionKeyAsync( this Database database, string clientEncryptionKeyId, EncryptionKeyWrapMetadata newEncryptionKeyWrapMetadata, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); if (string.IsNullOrWhiteSpace(clientEncryptionKeyId)) { throw new ArgumentNullException(nameof(clientEncryptionKeyId)); } if (newEncryptionKeyWrapMetadata == null) { throw new ArgumentNullException(nameof(newEncryptionKeyWrapMetadata)); } ClientEncryptionKey clientEncryptionKey = database.GetClientEncryptionKey(clientEncryptionKeyId); EncryptionCosmosClient encryptionCosmosClient; if (database is EncryptionDatabase encryptionDatabase) { encryptionCosmosClient = encryptionDatabase.EncryptionCosmosClient; } else { 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; ClientEncryptionKeyProperties clientEncryptionKeyProperties = await clientEncryptionKey.ReadAsync(cancellationToken : cancellationToken); RequestOptions requestOptions = new RequestOptions { IfMatchEtag = clientEncryptionKeyProperties.ETag, }; KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate( clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Name, clientEncryptionKeyProperties.EncryptionKeyWrapMetadata.Value, encryptionKeyStoreProvider); byte[] unwrappedKey = keyEncryptionKey.DecryptEncryptionKey(clientEncryptionKeyProperties.WrappedDataEncryptionKey); keyEncryptionKey = KeyEncryptionKey.GetOrCreate( newEncryptionKeyWrapMetadata.Name, newEncryptionKeyWrapMetadata.Value, encryptionKeyStoreProvider); byte[] rewrappedKey = keyEncryptionKey.EncryptEncryptionKey(unwrappedKey); clientEncryptionKeyProperties = new ClientEncryptionKeyProperties( clientEncryptionKeyId, clientEncryptionKeyProperties.EncryptionAlgorithm, rewrappedKey, newEncryptionKeyWrapMetadata); ClientEncryptionKeyResponse clientEncryptionKeyResponse = await clientEncryptionKey.ReplaceAsync( clientEncryptionKeyProperties, requestOptions, cancellationToken : cancellationToken); return(clientEncryptionKeyResponse); }
public MdeKeyWrapProvider(EncryptionKeyStoreProvider encryptionKeyStoreProvider) { this.EncryptionKeyStoreProvider = encryptionKeyStoreProvider ?? throw new ArgumentNullException(nameof(encryptionKeyStoreProvider)); }