private async Task <ClientEncryptionKeyProperties> FetchClientEncryptionKeyPropertiesAsync( EncryptionContainer encryptionContainer, string clientEncryptionKeyId, RequestOptions requestOptions, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ClientEncryptionKey clientEncryptionKey = encryptionContainer.Database.GetClientEncryptionKey(clientEncryptionKeyId); try { return(await clientEncryptionKey.ReadAsync(requestOptions : requestOptions, cancellationToken : cancellationToken)); } catch (CosmosException ex) { if (ex.StatusCode == HttpStatusCode.NotFound) { throw new InvalidOperationException($"Encryption Based Container without Client Encryption Keys. Please make sure you have created the Client Encryption Keys:{ex.Message}. Please refer to https://aka.ms/CosmosClientEncryption for more details."); } else { throw; } } }
public EncryptionContainerResponse( ContainerResponse containerResponse, EncryptionContainer encryptionContainer) { this.containerResponse = containerResponse ?? throw new ArgumentNullException(nameof(containerResponse)); this.encryptionContainer = encryptionContainer ?? throw new ArgumentNullException(nameof(encryptionContainer)); }
public async Task <ClientEncryptionKeyProperties> GetClientEncryptionKeyPropertiesAsync( string clientEncryptionKeyId, EncryptionContainer encryptionContainer, string databaseRid, CancellationToken cancellationToken = default, bool shouldForceRefresh = false) { if (encryptionContainer == null) { throw new ArgumentNullException(nameof(encryptionContainer)); } if (string.IsNullOrEmpty(databaseRid)) { throw new ArgumentNullException(nameof(databaseRid)); } if (string.IsNullOrEmpty(clientEncryptionKeyId)) { throw new ArgumentNullException(nameof(clientEncryptionKeyId)); } // Client Encryption key Id is unique within a Database. string cacheKey = databaseRid + "|" + clientEncryptionKeyId; return(await this.clientEncryptionKeyPropertiesCacheByKeyId.GetAsync( cacheKey, obsoleteValue : null, async() => await this.FetchClientEncryptionKeyPropertiesAsync(encryptionContainer, clientEncryptionKeyId, cancellationToken), cancellationToken, forceRefresh : shouldForceRefresh)); }
public EncryptionFeedIterator( FeedIterator feedIterator, EncryptionContainer encryptionContainer, RequestOptions requestOptions) { this.feedIterator = feedIterator ?? throw new ArgumentNullException(nameof(feedIterator)); this.encryptionContainer = encryptionContainer ?? throw new ArgumentNullException(nameof(encryptionContainer)); this.requestOptions = requestOptions ?? throw new ArgumentNullException(nameof(requestOptions)); }
public EncryptionTransactionalBatch( TransactionalBatch transactionalBatch, EncryptionContainer encryptionContainer, CosmosSerializer cosmosSerializer) { this.transactionalBatch = transactionalBatch ?? throw new ArgumentNullException(nameof(transactionalBatch)); this.encryptionContainer = encryptionContainer ?? throw new ArgumentNullException(nameof(encryptionContainer)); this.cosmosSerializer = cosmosSerializer ?? throw new ArgumentNullException(nameof(cosmosSerializer)); }
public EncryptionSettingForProperty( string clientEncryptionKeyId, Data.Encryption.Cryptography.EncryptionType encryptionType, EncryptionContainer encryptionContainer, string databaseRid) { this.ClientEncryptionKeyId = string.IsNullOrEmpty(clientEncryptionKeyId) ? throw new ArgumentNullException(nameof(clientEncryptionKeyId)) : clientEncryptionKeyId; this.EncryptionType = encryptionType; this.encryptionContainer = encryptionContainer ?? throw new ArgumentNullException(nameof(encryptionContainer)); this.databaseRid = string.IsNullOrEmpty(databaseRid) ? throw new ArgumentNullException(nameof(databaseRid)) : databaseRid; }
public EncryptionTransactionalBatch( TransactionalBatch transactionalBatch, EncryptionContainer encryptionContainer, CosmosSerializer cosmosSerializer) { this.transactionalBatch = transactionalBatch ?? throw new ArgumentNullException(nameof(transactionalBatch)); this.encryptionContainer = encryptionContainer ?? throw new ArgumentNullException(nameof(encryptionContainer)); this.cosmosSerializer = cosmosSerializer ?? throw new ArgumentNullException(nameof(cosmosSerializer)); this.encryptionDiagnosticsContext = new EncryptionDiagnosticsContext(); this.encryptionDiagnosticsContext.Begin(Constants.DiagnosticsEncryptOperation); }
public EncryptionFeedIterator( EncryptionContainer encryptionContainer, ChangeFeedStartFrom changeFeedStartFrom, ChangeFeedMode changeFeedMode, ChangeFeedRequestOptions changeFeedRequestOptions = null) { this.encryptionContainer = encryptionContainer ?? throw new ArgumentNullException(nameof(encryptionContainer)); this.requestOptions = changeFeedRequestOptions; this.FeedIterator = encryptionContainer.Container.GetChangeFeedStreamIterator( changeFeedStartFrom, changeFeedMode, changeFeedRequestOptions); }
public async Task <ClientEncryptionKeyProperties> GetClientEncryptionKeyPropertiesAsync( string clientEncryptionKeyId, EncryptionContainer encryptionContainer, string databaseRid, string ifNoneMatchEtag, bool shouldForceRefresh, CancellationToken cancellationToken) { if (encryptionContainer == null) { throw new ArgumentNullException(nameof(encryptionContainer)); } if (string.IsNullOrEmpty(databaseRid)) { throw new ArgumentNullException(nameof(databaseRid)); } if (string.IsNullOrEmpty(clientEncryptionKeyId)) { throw new ArgumentNullException(nameof(clientEncryptionKeyId)); } // Client Encryption key Id is unique within a Database. string cacheKey = databaseRid + "|" + clientEncryptionKeyId; // this allows us to read from the Gateway Cache. If an IfNoneMatchEtag is passed the logic around the gateway cache allows us to fetch the latest ClientEncryptionKeyProperties // from the servers if the gateway cache has a stale value. This can happen if a client connected via different Gateway has rewrapped the key. RequestOptions requestOptions = new RequestOptions { AddRequestHeaders = (headers) => { headers.Add(Constants.AllowCachedReadsHeader, bool.TrueString); headers.Add(Constants.DatabaseRidHeader, databaseRid); }, }; if (!string.IsNullOrEmpty(ifNoneMatchEtag)) { requestOptions.IfNoneMatchEtag = ifNoneMatchEtag; } return(await this.clientEncryptionKeyPropertiesCacheByKeyId.GetAsync( cacheKey, obsoleteValue : null, async() => await this.FetchClientEncryptionKeyPropertiesAsync(encryptionContainer, clientEncryptionKeyId, requestOptions, cancellationToken), cancellationToken, forceRefresh : shouldForceRefresh)); }
public EncryptionFeedIterator( EncryptionContainer encryptionContainer, string queryText = null, string continuationToken = null, QueryRequestOptions requestOptions = null) { this.encryptionContainer = encryptionContainer ?? throw new ArgumentNullException(nameof(encryptionContainer)); this.queryText = queryText; this.continuationToken = continuationToken; this.requestOptions = requestOptions; this.FeedIterator = encryptionContainer.Container.GetItemQueryStreamIterator( queryText, continuationToken, requestOptions); this.queryType = QueryType.QueryTextType; }
public EncryptionFeedIterator( EncryptionContainer encryptionContainer, FeedRange feedRange, QueryDefinition queryDefinition, string continuationToken, QueryRequestOptions requestOptions = null) { this.encryptionContainer = encryptionContainer ?? throw new ArgumentNullException(nameof(encryptionContainer)); this.feedRange = feedRange; this.queryDefinition = queryDefinition; this.continuationToken = continuationToken; this.requestOptions = requestOptions; this.FeedIterator = encryptionContainer.Container.GetItemQueryStreamIterator( feedRange, queryDefinition, continuationToken, requestOptions); this.queryType = QueryType.QueryDefinitionWithFeedRangeType; }
/// <summary> /// Gets a QueryDefinition with Encrypted Parameters. /// </summary> /// <param name="queryDefinition"> Query Definition to be replaced with Encrypted Values.</param> /// <param name="name"> Query Paramerter Name. </param> /// <param name="value"> Query Paramerter Value.</param> /// <param name="path"> Encrypted Property Path. </param> /// <param name="cancellationToken"> cancellation token </param> /// <returns> QueryDefinition with encrypted parameters. </returns> /// <example> /// This example shows how to pass in a QueryDefinition with Encryption support to AddParameterAsync /// to encrypt the required Property for running Query on encrypted data. /// /// <code language="c#"> /// <![CDATA[ /// containerWithEncryption = await this.cosmosDatabase.GetContainer("id").InitializeEncryptionAsync(); /// QueryDefinition withEncryptedParameter = containerWithEncryption.CreateQueryDefinition( /// "SELECT * FROM c where c.PropertyName = @PropertyValue"); /// await withEncryptedParameter.AddParameterAsync( /// "@PropertyName", /// PropertyValue, /// "/PropertyName"); /// ]]> /// </code> /// </example> public static async Task <QueryDefinition> AddParameterAsync( this QueryDefinition queryDefinition, string name, object value, string path, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); if (queryDefinition == null) { throw new ArgumentNullException(nameof(queryDefinition)); } if (string.IsNullOrWhiteSpace(path) || path[0] != '/' || path.LastIndexOf('/') != 0) { throw new InvalidOperationException($"Invalid path {path ?? string.Empty}, {nameof(path)}. "); } if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentNullException(nameof(name)); } if (value == null) { throw new ArgumentNullException(nameof(value)); } QueryDefinition queryDefinitionwithEncryptedValues = queryDefinition; if (queryDefinition is EncryptionQueryDefinition encryptionQueryDefinition) { EncryptionContainer encryptionContainer = (EncryptionContainer)encryptionQueryDefinition.Container; // get the path's encryption setting. EncryptionSettings encryptionSettings = await encryptionContainer.GetOrUpdateEncryptionSettingsFromCacheAsync(obsoleteEncryptionSettings : null, cancellationToken : cancellationToken); EncryptionSettingForProperty settingsForProperty = encryptionSettings.GetEncryptionSettingForProperty(path.Substring(1)); if (settingsForProperty == null) { // property not encrypted. queryDefinitionwithEncryptedValues.WithParameter(name, value); return(queryDefinitionwithEncryptedValues); } if (settingsForProperty.EncryptionType == 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. "); } Stream valueStream = encryptionContainer.CosmosSerializer.ToStream(value); Stream encryptedValueStream = await EncryptionProcessor.EncryptValueStreamAsync(valueStream, settingsForProperty, cancellationToken); queryDefinitionwithEncryptedValues.WithParameterStream(name, encryptedValueStream); return(queryDefinitionwithEncryptedValues); } else { throw new ArgumentException("Executing queries on encrypted path requires the use of an encryption - enabled client. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } }
public static Task <EncryptionSettings> CreateAsync(EncryptionContainer encryptionContainer, CancellationToken cancellationToken) { return(InitializeEncryptionSettingsAsync(encryptionContainer, cancellationToken)); }
/// <summary> /// Gets a QueryDefinition with Encrypted Parameters. /// </summary> /// <param name="queryDefinition"> Query Definition to be replaced with Encrypted Values.</param> /// <param name="name"> Query Paramerter Name. </param> /// <param name="value"> Query Paramerter Value.</param> /// <param name="path"> Encrypted Property Path. </param> /// <param name="cancellationToken"> cancellation token </param> /// <returns> QueryDefinition with encrypted parameters. </returns> /// <example> /// This example shows how to pass in a QueryDefinition with Encryption support to AddParameterAsync /// to encrypt the required Property for running Query on encrypted data. /// /// <code language="c#"> /// <![CDATA[ /// containerWithEncryption = await this.cosmosDatabase.GetContainer("id").InitializeEncryptionAsync(); /// QueryDefinition withEncryptedParameter = containerWithEncryption.CreateQueryDefinition( /// "SELECT * FROM c where c.PropertyName = @PropertyValue"); /// await withEncryptedParameter.AddParameterAsync( /// "@PropertyName", /// PropertyValue, /// "/PropertyName"); /// ]]> /// </code> /// </example> public static async Task <QueryDefinition> AddParameterAsync( this QueryDefinition queryDefinition, string name, object value, string path, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); if (queryDefinition == null) { throw new ArgumentNullException(nameof(queryDefinition)); } if (string.IsNullOrWhiteSpace(path) || path[0] != '/' || path.LastIndexOf('/') != 0) { throw new InvalidOperationException($"Invalid path {path ?? string.Empty}, {nameof(path)}. "); } if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentNullException(nameof(name)); } if (value == null) { throw new ArgumentNullException(nameof(value)); } QueryDefinition queryDefinitionwithEncryptedValues = queryDefinition; if (queryDefinition is EncryptionQueryDefinition encryptionQueryDefinition) { EncryptionContainer encryptionContainer = (EncryptionContainer)encryptionQueryDefinition.Container; Stream valueStream = encryptionContainer.CosmosSerializer.ToStream(value); // not really required, but will have things setup for subsequent queries or operations on this Container if the Container was never init // or if this was the first operation carried out on this container. await encryptionContainer.EncryptionProcessor.InitEncryptionSettingsIfNotInitializedAsync(cancellationToken); // get the path's encryption setting. EncryptionSettingForProperty settingsForProperty = await encryptionContainer.EncryptionProcessor.EncryptionSettings.GetEncryptionSettingForPropertyAsync( path.Substring(1), cancellationToken); if (settingsForProperty == null) { // property not encrypted. queryDefinitionwithEncryptedValues.WithParameter(name, value); return(queryDefinitionwithEncryptedValues); } if (settingsForProperty.EncryptionType == 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. "); } AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = await settingsForProperty.BuildEncryptionAlgorithmForSettingAsync(cancellationToken : cancellationToken); JToken propertyValueToEncrypt = EncryptionProcessor.BaseSerializer.FromStream <JToken>(valueStream); (EncryptionProcessor.TypeMarker typeMarker, byte[] serializedData) = EncryptionProcessor.Serialize(propertyValueToEncrypt); byte[] cipherText = aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt(serializedData); if (cipherText == null) { throw new InvalidOperationException($"{nameof(AddParameterAsync)} returned null cipherText from {nameof(aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt)}. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } byte[] cipherTextWithTypeMarker = new byte[cipherText.Length + 1]; cipherTextWithTypeMarker[0] = (byte)typeMarker; Buffer.BlockCopy(cipherText, 0, cipherTextWithTypeMarker, 1, cipherText.Length); queryDefinitionwithEncryptedValues.WithParameter(name, cipherTextWithTypeMarker); return(queryDefinitionwithEncryptedValues); } else { throw new ArgumentException("Executing queries on encrypted path requires the use of an encryption - enabled client. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } }