Пример #1
0
        /// <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>();
 }
Пример #3
0
        /// <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);
        }
Пример #4
0
 /// <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;
 }
Пример #5
0
        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));
        }
Пример #6
0
        /// <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);
     }
 }
Пример #8
0
        /// <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);
        }
Пример #9
0
        /// <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);
        }
Пример #10
0
 public MdeKeyWrapProvider(EncryptionKeyStoreProvider encryptionKeyStoreProvider)
 {
     this.EncryptionKeyStoreProvider = encryptionKeyStoreProvider ?? throw new ArgumentNullException(nameof(encryptionKeyStoreProvider));
 }