示例#1
0
        internal async Task <InMemoryRawDek> UnwrapAsync(
            DataEncryptionKeyProperties dekProperties,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            EncryptionKeyUnwrapResult unwrapResult;

            if (this.DekProvider.EncryptionKeyWrapProvider == null)
            {
                throw new InvalidOperationException($"For use of '{CosmosEncryptionAlgorithm.AEAes256CbcHmacSha256Randomized}' algorithm, " +
                                                    "Encryptor or CosmosDataEncryptionKeyProvider needs to be initialized with EncryptionKeyWrapProvider.");
            }

            using (diagnosticsContext.CreateScope("UnwrapDataEncryptionKey"))
            {
                unwrapResult = await this.DekProvider.EncryptionKeyWrapProvider.UnwrapKeyAsync(
                    dekProperties.WrappedDataEncryptionKey,
                    dekProperties.EncryptionKeyWrapMetadata,
                    cancellationToken);
            }

            DataEncryptionKey dek = DataEncryptionKey.Create(
                unwrapResult.DataEncryptionKey,
                dekProperties.EncryptionAlgorithm);

            return(new InMemoryRawDek(dek, unwrapResult.ClientCacheTimeToLive));
        }
示例#2
0
        internal async Task <DataEncryptionKey> FetchUnWrappedLegacySupportedMdeDekAsync(
            DataEncryptionKeyProperties dekProperties,
            string encryptionAlgorithm,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            EncryptionKeyUnwrapResult unwrapResult;

            if (this.DekProvider.EncryptionKeyStoreProvider == null)
            {
                throw new InvalidOperationException($"For use of '{CosmosEncryptionAlgorithm.MdeAeadAes256CbcHmac256Randomized}' algorithm based DEK, " +
                                                    "Encryptor or CosmosDataEncryptionKeyProvider needs to be initialized with EncryptionKeyStoreProvider.");
            }

            try
            {
                using (diagnosticsContext.CreateScope("UnwrapDataEncryptionKey"))
                {
                    unwrapResult = await this.UnWrapDekMdeEncAlgoAsync(
                        dekProperties,
                        diagnosticsContext,
                        cancellationToken);
                }

                return(DataEncryptionKey.Create(
                           unwrapResult.DataEncryptionKey,
                           encryptionAlgorithm));
            }
            catch (Exception exception)
            {
                throw EncryptionExceptionFactory.EncryptionKeyNotFoundException(
                          $"Failed to unwrap Data Encryption Key with id: '{dekProperties.Id}'.",
                          exception);
            }
        }
示例#3
0
        public override TransactionalBatch CreateItemStream(
            Stream streamPayload,
            TransactionalBatchItemRequestOptions requestOptions = null)
        {
            if (requestOptions is EncryptionTransactionalBatchItemRequestOptions encryptionItemRequestOptions &&
                encryptionItemRequestOptions.EncryptionOptions != null)
            {
                CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(requestOptions);
                using (diagnosticsContext.CreateScope("EncryptItemStream"))
                {
                    streamPayload = EncryptionProcessor.EncryptAsync(
                        streamPayload,
                        this.encryptor,
                        encryptionItemRequestOptions.EncryptionOptions,
                        diagnosticsContext,
                        cancellationToken: default).Result;
                }
            }

            this.transactionalBatch = this.transactionalBatch.CreateItemStream(
                streamPayload,
                requestOptions);

            return(this);
        }
        public override async Task <ResponseMessage> ReplaceItemStreamAsync(
            Stream streamPayload,
            string id,
            PartitionKey partitionKey,
            ItemRequestOptions requestOptions   = null,
            CancellationToken cancellationToken = default)
        {
            if (id == null)
            {
                throw new ArgumentNullException(nameof(id));
            }

            if (streamPayload == null)
            {
                throw new ArgumentNullException(nameof(streamPayload));
            }

            CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(requestOptions);

            using (diagnosticsContext.CreateScope("ReplaceItemStream"))
            {
                return(await this.ReplaceItemHelperAsync(
                           streamPayload,
                           id,
                           partitionKey,
                           requestOptions,
                           decryptResponse : true,
                           diagnosticsContext,
                           cancellationToken));
            }
        }
示例#5
0
        internal static async Task <Stream> DeserializeAndDecryptResponseAsync(
            Stream content,
            Encryptor encryptor,
            CancellationToken cancellationToken)
        {
            JObject contentJObj = EncryptionProcessor.BaseSerializer.FromStream <JObject>(content);

            if (!(contentJObj.SelectToken(Constants.DocumentsResourcePropertyName) is JArray documents))
            {
                throw new InvalidOperationException("Feed Response body contract was violated. Feed response did not have an array of Documents");
            }

            foreach (JToken value in documents)
            {
                if (!(value is JObject document))
                {
                    continue;
                }

                CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(null);
                using (diagnosticsContext.CreateScope("EncryptionProcessor.DeserializeAndDecryptResponseAsync"))
                {
                    await EncryptionProcessor.DecryptAsync(
                        document,
                        encryptor,
                        diagnosticsContext,
                        cancellationToken);
                }
            }

            // the contents of contentJObj get decrypted in place for MDE algorithm model, and for legacy model _ei property is removed
            // and corresponding decrypted properties are added back in the documents.
            return(EncryptionProcessor.BaseSerializer.ToStream(contentJObj));
        }
示例#6
0
        internal async Task <(byte[], EncryptionKeyWrapMetadata, InMemoryRawDek)> WrapAsync(
            string id,
            byte[] key,
            string encryptionAlgorithm,
            EncryptionKeyWrapMetadata metadata,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            EncryptionKeyWrapResult keyWrapResponse = null;

            using (diagnosticsContext.CreateScope("WrapDataEncryptionKey"))
            {
                keyWrapResponse = string.Equals(encryptionAlgorithm, CosmosEncryptionAlgorithm.AEAes256CbcHmacSha256Randomized) && this.DekProvider.EncryptionKeyWrapProvider != null
                    ? await this.DekProvider.EncryptionKeyWrapProvider.WrapKeyAsync(key, metadata, cancellationToken)
                    : string.Equals(encryptionAlgorithm, CosmosEncryptionAlgorithm.MdeAeadAes256CbcHmac256Randomized) && this.DekProvider.MdeKeyWrapProvider != null
                        ? await this.DekProvider.MdeKeyWrapProvider.WrapKeyAsync(key, metadata, cancellationToken)
                        : throw new ArgumentException(string.Format(
                                                          "Unsupported encryption algorithm {0}." +
                                                          " Please initialize the Encryptor or CosmosDataEncryptionKeyProvider with an implementation of the EncryptionKeyStoreProvider / EncryptionKeyWrapProvider.",
                                                          encryptionAlgorithm));
            }

            // Verify
            DataEncryptionKeyProperties tempDekProperties = new DataEncryptionKeyProperties(
                id,
                encryptionAlgorithm,
                keyWrapResponse.WrappedDataEncryptionKey,
                keyWrapResponse.EncryptionKeyWrapMetadata,
                DateTime.UtcNow);

            byte[]         rawKey            = null;
            InMemoryRawDek roundTripResponse = null;

            if (string.Equals(encryptionAlgorithm, CosmosEncryptionAlgorithm.AEAes256CbcHmacSha256Randomized))
            {
                roundTripResponse = await this.UnwrapAsync(tempDekProperties, diagnosticsContext, cancellationToken);

                rawKey = roundTripResponse.DataEncryptionKey.RawKey;
            }
            else if (string.Equals(encryptionAlgorithm, CosmosEncryptionAlgorithm.MdeAeadAes256CbcHmac256Randomized))
            {
                EncryptionKeyUnwrapResult unwrapResult = await this.UnWrapDekMdeEncAlgoAsync(
                    tempDekProperties,
                    diagnosticsContext,
                    cancellationToken);

                rawKey = unwrapResult.DataEncryptionKey;
            }

            if (!rawKey.SequenceEqual(key))
            {
                throw new InvalidOperationException("The key wrapping provider configured was unable to unwrap the wrapped key correctly.");
            }

            return(keyWrapResponse.WrappedDataEncryptionKey, keyWrapResponse.EncryptionKeyWrapMetadata, roundTripResponse);
        }
示例#7
0
 private async Task <DataEncryptionKeyProperties> ReadResourceAsync(
     string id,
     CosmosDiagnosticsContext diagnosticsContext,
     CancellationToken cancellationToken)
 {
     using (diagnosticsContext.CreateScope("ReadDataEncryptionKey"))
     {
         return(await this.ReadInternalAsync(
                    id : id,
                    requestOptions : null,
                    diagnosticsContext : diagnosticsContext,
                    cancellationToken : cancellationToken));
     }
 }
        internal static async Task <Stream> DeserializeAndDecryptResponseAsync(
            Stream content,
            Encryptor encryptor,
            CancellationToken cancellationToken)
        {
            JObject contentJObj = EncryptionProcessor.BaseSerializer.FromStream <JObject>(content);
            JArray  result      = new JArray();

            if (!(contentJObj.SelectToken(Constants.DocumentsResourcePropertyName) is JArray documents))
            {
                throw new InvalidOperationException("Feed Response body contract was violated. Feed response did not have an array of Documents");
            }

            foreach (JToken value in documents)
            {
                if (!(value is JObject document))
                {
                    result.Add(value);
                    continue;
                }

                CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(null);
                using (diagnosticsContext.CreateScope("EncryptionProcessor.DeserializeAndDecryptResponseAsync"))
                {
                    (JObject decryptedDocument, DecryptionContext _) = await EncryptionProcessor.DecryptAsync(
                        document,
                        encryptor,
                        diagnosticsContext,
                        cancellationToken);

                    result.Add(decryptedDocument);
                }
            }

            JObject decryptedResponse = new JObject();

            foreach (JProperty property in contentJObj.Properties())
            {
                if (property.Name.Equals(Constants.DocumentsResourcePropertyName))
                {
                    decryptedResponse.Add(property.Name, (JToken)result);
                }
                else
                {
                    decryptedResponse.Add(property.Name, property.Value);
                }
            }

            return(EncryptionProcessor.BaseSerializer.ToStream(decryptedResponse));
        }
示例#9
0
 private async Task <ItemResponse <DataEncryptionKeyProperties> > ReadInternalAsync(
     string id,
     ItemRequestOptions requestOptions,
     CosmosDiagnosticsContext diagnosticsContext,
     CancellationToken cancellationToken)
 {
     using (diagnosticsContext.CreateScope("ReadInternalAsync"))
     {
         return(await this.DekProvider.Container.ReadItemAsync <DataEncryptionKeyProperties>(
                    id,
                    new PartitionKey(id),
                    requestOptions,
                    cancellationToken));
     }
 }
示例#10
0
        public override async Task <TransactionalBatchResponse> ExecuteAsync(
            CancellationToken cancellationToken = default)
        {
            CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(options: null);

            using (diagnosticsContext.CreateScope("TransactionalBatch.ExecuteAsync"))
            {
                TransactionalBatchResponse response = await this.transactionalBatch.ExecuteAsync(cancellationToken);

                return(await this.DecryptTransactionalBatchResponseAsync(
                           response,
                           diagnosticsContext,
                           cancellationToken));
            }
        }
        public override ChangeFeedProcessorBuilder GetChangeFeedProcessorBuilder <T>(
            string processorName,
            ChangesHandler <T> onChangesDelegate)
        {
            CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(null);

            using (diagnosticsContext.CreateScope("GetChangeFeedProcessorBuilder"))
            {
                return(this.container.GetChangeFeedProcessorBuilder(
                           processorName,
                           async(IReadOnlyCollection <JObject> documents, CancellationToken cancellationToken) =>
                {
                    List <T> decryptItems = new List <T>(documents.Count);
                    if (typeof(T) == typeof(DecryptableItem))
                    {
                        foreach (JToken value in documents)
                        {
                            DecryptableItemCore item = new DecryptableItemCore(
                                value,
                                this.Encryptor,
                                this.CosmosSerializer);

                            decryptItems.Add((T)(object)item);
                        }
                    }
                    else
                    {
                        foreach (JObject document in documents)
                        {
                            (JObject decryptedDocument, DecryptionContext _) = await EncryptionProcessor.DecryptAsync(
                                document,
                                this.Encryptor,
                                diagnosticsContext,
                                cancellationToken);

                            decryptItems.Add(decryptedDocument.ToObject <T>());
                        }
                    }

                    // Call the original passed in delegate
                    await onChangesDelegate(decryptItems, cancellationToken);
                }));
            }
        }
        public override async Task <ResponseMessage> ReadItemStreamAsync(
            string id,
            PartitionKey partitionKey,
            ItemRequestOptions requestOptions   = null,
            CancellationToken cancellationToken = default)
        {
            CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(requestOptions);

            using (diagnosticsContext.CreateScope("ReadItemStream"))
            {
                return(await this.ReadItemHelperAsync(
                           id,
                           partitionKey,
                           requestOptions,
                           decryptResponse : true,
                           diagnosticsContext,
                           cancellationToken));
            }
        }
        public override async Task <ItemResponse <T> > ReadItemAsync <T>(
            string id,
            PartitionKey partitionKey,
            ItemRequestOptions requestOptions   = null,
            CancellationToken cancellationToken = default)
        {
            CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(requestOptions);

            using (diagnosticsContext.CreateScope("ReadItem"))
            {
                ResponseMessage responseMessage;

                if (typeof(T) == typeof(DecryptableItem))
                {
                    responseMessage = await this.ReadItemHelperAsync(
                        id,
                        partitionKey,
                        requestOptions,
                        decryptResponse : false,
                        diagnosticsContext,
                        cancellationToken);

                    DecryptableItemCore decryptableItem = new DecryptableItemCore(
                        EncryptionProcessor.BaseSerializer.FromStream <JObject>(responseMessage.Content),
                        this.Encryptor,
                        this.CosmosSerializer);

                    return(new EncryptionItemResponse <T>(
                               responseMessage,
                               (T)(object)decryptableItem));
                }

                responseMessage = await this.ReadItemHelperAsync(
                    id,
                    partitionKey,
                    requestOptions,
                    decryptResponse : true,
                    diagnosticsContext,
                    cancellationToken);

                return(this.ResponseFactory.CreateItemResponse <T>(responseMessage));
            }
        }
        public override async Task <ResponseMessage> ReadNextAsync(CancellationToken cancellationToken = default)
        {
            CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(options: null);

            using (diagnosticsContext.CreateScope("FeedIterator.ReadNext"))
            {
                ResponseMessage responseMessage = await this.feedIterator.ReadNextAsync(cancellationToken);

                if (responseMessage.IsSuccessStatusCode && responseMessage.Content != null)
                {
                    Stream decryptedContent = await EncryptionProcessor.DeserializeAndDecryptResponseAsync(
                        responseMessage.Content,
                        this.encryptor,
                        cancellationToken);

                    return(new DecryptedResponseMessage(responseMessage, decryptedContent));
                }

                return(responseMessage);
            }
        }
示例#15
0
        private async Task <EncryptionKeyUnwrapResult> UnWrapDekMdeEncAlgoAsync(
            DataEncryptionKeyProperties dekProperties,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            EncryptionKeyUnwrapResult unwrapResult;

            if (this.DekProvider.MdeKeyWrapProvider == null)
            {
                throw new InvalidOperationException($"For use of '{CosmosEncryptionAlgorithm.MdeAeadAes256CbcHmac256Randomized}' algorithm, " +
                                                    "Encryptor or CosmosDataEncryptionKeyProvider needs to be initialized with EncryptionKeyStoreProvider.");
            }

            using (diagnosticsContext.CreateScope("UnwrapDataEncryptionKey"))
            {
                unwrapResult = await this.DekProvider.MdeKeyWrapProvider.UnwrapKeyAsync(
                    dekProperties.WrappedDataEncryptionKey,
                    dekProperties.EncryptionKeyWrapMetadata,
                    cancellationToken);
            }

            return(unwrapResult);
        }
        public override async Task <ItemResponse <T> > CreateItemAsync <T>(
            T item,
            PartitionKey?partitionKey           = null,
            ItemRequestOptions requestOptions   = null,
            CancellationToken cancellationToken = default)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (!(requestOptions is EncryptionItemRequestOptions encryptionItemRequestOptions) ||
                encryptionItemRequestOptions.EncryptionOptions == null)
            {
                return(await this.container.CreateItemAsync <T>(
                           item,
                           partitionKey,
                           requestOptions,
                           cancellationToken));
            }

            if (partitionKey == null)
            {
                throw new NotSupportedException($"{nameof(partitionKey)} cannot be null for operations using {nameof(EncryptionContainer)}.");
            }

            CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(requestOptions);

            using (diagnosticsContext.CreateScope("CreateItem"))
            {
                ResponseMessage responseMessage;

                if (item is EncryptableItem encryptableItem)
                {
                    using (Stream streamPayload = encryptableItem.ToStream(this.CosmosSerializer))
                    {
                        responseMessage = await this.CreateItemHelperAsync(
                            streamPayload,
                            partitionKey.Value,
                            requestOptions,
                            decryptResponse : false,
                            diagnosticsContext,
                            cancellationToken);
                    }

                    encryptableItem.SetDecryptableItem(
                        EncryptionProcessor.BaseSerializer.FromStream <JObject>(responseMessage.Content),
                        this.Encryptor,
                        this.CosmosSerializer);

                    return(new EncryptionItemResponse <T>(
                               responseMessage,
                               item));
                }
                else
                {
                    using (Stream itemStream = this.CosmosSerializer.ToStream <T>(item))
                    {
                        responseMessage = await this.CreateItemHelperAsync(
                            itemStream,
                            partitionKey.Value,
                            requestOptions,
                            decryptResponse : true,
                            diagnosticsContext,
                            cancellationToken);
                    }

                    return(this.ResponseFactory.CreateItemResponse <T>(responseMessage));
                }
            }
        }