FeedIterator <DataEncryptionKeyProperties> GetDataEncryptionKeyIterator(
            string startId                     = null,
            string endId                       = null,
            bool isDescending                  = false,
            string continuationToken           = null,
            QueryRequestOptions requestOptions = null)
        {
            if (!(this.GetDataEncryptionKeyStreamIterator(
                      startId,
                      endId,
                      isDescending,
                      continuationToken,
                      requestOptions) is FeedIteratorInternal dekStreamIterator))
            {
                throw new InvalidOperationException($"Expected FeedIteratorInternal.");
            }

            return(new FeedIteratorCore <DataEncryptionKeyProperties>(
                       dekStreamIterator,
                       (responseMessage) =>
            {
                FeedResponse <DataEncryptionKeyProperties> results = this.ClientContext.ResponseFactory.CreateQueryFeedResponse <DataEncryptionKeyProperties>(responseMessage, ResourceType.ClientEncryptionKey);
                foreach (DataEncryptionKeyProperties result in results)
                {
                    Uri dekUri = DataEncryptionKeyCore.CreateLinkUri(this.ClientContext, this, result.Id);
                    this.ClientContext.DekCache.Set(this.Id, dekUri, result);
                }

                return results;
            }));
        }
Example #2
0
        private async Task <JObject> DecryptContentAsync(
            EncryptionProperties encryptionProperties,
            DatabaseCore database,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            if (encryptionProperties.EncryptionFormatVersion != 1)
            {
                throw CosmosExceptionFactory.CreateInternalServerErrorException($"Unknown encryption format version: {encryptionProperties.EncryptionFormatVersion}. Please upgrade your SDK to the latest version.");
            }

            DataEncryptionKeyCore tempDek = (DataEncryptionKeyInlineCore)database.GetDataEncryptionKey(id: "unknown");

            (DataEncryptionKeyProperties _, InMemoryRawDek inMemoryRawDek) = await tempDek.FetchUnwrappedByRidAsync(
                encryptionProperties.DataEncryptionKeyRid,
                diagnosticsContext,
                cancellationToken);

            byte[] plainText = inMemoryRawDek.AlgorithmUsingRawDek.DecryptData(encryptionProperties.EncryptedData);

            JObject plainTextJObj = null;

            using (MemoryStream memoryStream = new MemoryStream(plainText))
                using (StreamReader streamReader = new StreamReader(memoryStream))
                    using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader))
                    {
                        plainTextJObj = JObject.Load(jsonTextReader);
                    }

            return(plainTextJObj);
        }
        internal DataEncryptionKeyInlineCore(DataEncryptionKeyCore dataEncryptionKey)
        {
            if (dataEncryptionKey == null)
            {
                throw new ArgumentException(nameof(dataEncryptionKey));
            }

            this.dataEncryptionKey = dataEncryptionKey;
        }
Example #4
0
        internal DataEncryptionKeyCore(
            CosmosClientContext clientContext,
            DatabaseCore database,
            string keyId)
        {
            this.Id            = keyId;
            this.ClientContext = clientContext;
            this.LinkUri       = DataEncryptionKeyCore.CreateLinkUri(clientContext, database, keyId);

            this.Database = database;
        }
        async Task <DataEncryptionKeyResponse> CreateDataEncryptionKeyAsync(
            string id,
            CosmosEncryptionAlgorithm encryptionAlgorithmId,
            EncryptionKeyWrapMetadata encryptionKeyWrapMetadata,
            RequestOptions requestOptions       = null,
            CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrEmpty(id))
            {
                throw new ArgumentNullException(nameof(id));
            }

            if (encryptionAlgorithmId != CosmosEncryptionAlgorithm.AE_AES_256_CBC_HMAC_SHA_256_RANDOMIZED)
            {
                throw new ArgumentException(string.Format("Unsupported Encryption Algorithm {0}", encryptionAlgorithmId), nameof(encryptionAlgorithmId));
            }

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

            this.ClientContext.ValidateResource(id);

            DataEncryptionKeyCore newDek = (DataEncryptionKeyInlineCore)this.GetDataEncryptionKey(id);

            CosmosDiagnosticsContext diagnosticsContext = CosmosDiagnosticsContext.Create(requestOptions);

            byte[] rawDek = newDek.GenerateKey(encryptionAlgorithmId);

            (byte[] wrappedDek, EncryptionKeyWrapMetadata updatedMetadata, InMemoryRawDek inMemoryRawDek) = await newDek.WrapAsync(
                rawDek,
                encryptionAlgorithmId,
                encryptionKeyWrapMetadata,
                diagnosticsContext,
                cancellationToken);

            DataEncryptionKeyProperties dekProperties = new DataEncryptionKeyProperties(id, encryptionAlgorithmId, wrappedDek, updatedMetadata);
            Stream streamPayload = this.ClientContext.SerializerCore.ToStream(dekProperties);
            Task <ResponseMessage> responseMessage = this.CreateDataEncryptionKeyStreamAsync(
                streamPayload,
                requestOptions,
                cancellationToken);

            DataEncryptionKeyResponse dekResponse = await this.ClientContext.ResponseFactory.CreateDataEncryptionKeyResponseAsync(newDek, responseMessage);

            Debug.Assert(dekResponse.Resource != null);

            this.ClientContext.DekCache.Set(this.Id, newDek.LinkUri, dekResponse.Resource);
            this.ClientContext.DekCache.SetRawDek(dekResponse.Resource.SelfLink, inMemoryRawDek);
            return(dekResponse);
        }
        public async Task <Stream> EncryptAsync(
            Stream input,
            EncryptionOptions encryptionOptions,
            DatabaseCore database,
            EncryptionKeyWrapProvider encryptionKeyWrapProvider,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            Debug.Assert(input != null);
            Debug.Assert(encryptionOptions != null);
            Debug.Assert(database != null);
            Debug.Assert(diagnosticsContext != null);

            if (encryptionOptions.PathsToEncrypt == null)
            {
                throw new ArgumentNullException(nameof(encryptionOptions.PathsToEncrypt));
            }

            if (encryptionOptions.PathsToEncrypt.Count == 0)
            {
                return(input);
            }

            foreach (string path in encryptionOptions.PathsToEncrypt)
            {
                if (string.IsNullOrEmpty(path) || path[0] != '/' || path.LastIndexOf('/') != 0)
                {
                    throw new ArgumentException($"Invalid path {path ?? string.Empty}", nameof(encryptionOptions.PathsToEncrypt));
                }
            }

            if (encryptionOptions.DataEncryptionKey == null)
            {
                throw new ArgumentException("Invalid encryption options", nameof(encryptionOptions.DataEncryptionKey));
            }

            if (encryptionKeyWrapProvider == null)
            {
                throw new ArgumentException(ClientResources.EncryptionKeyWrapProviderNotConfigured);
            }

            DataEncryptionKey dek = database.GetDataEncryptionKey(encryptionOptions.DataEncryptionKey.Id);

            DataEncryptionKeyCore dekCore = (DataEncryptionKeyInlineCore)dek;

            (DataEncryptionKeyProperties dekProperties, InMemoryRawDek inMemoryRawDek) = await dekCore.FetchUnwrappedAsync(
                diagnosticsContext,
                cancellationToken);

            JObject itemJObj = EncryptionProcessor.baseSerializer.FromStream <JObject>(input);

            JObject toEncryptJObj = new JObject();

            foreach (string pathToEncrypt in encryptionOptions.PathsToEncrypt)
            {
                string propertyName        = pathToEncrypt.Substring(1);
                JToken propertyValueHolder = itemJObj.Property(propertyName).Value;

                // Even null in the JSON is a JToken with Type Null, this null check is just a sanity check
                if (propertyValueHolder != null)
                {
                    toEncryptJObj.Add(propertyName, itemJObj.Property(propertyName).Value.Value <JToken>());
                    itemJObj.Remove(propertyName);
                }
            }

            MemoryStream memoryStream = EncryptionProcessor.baseSerializer.ToStream <JObject>(toEncryptJObj) as MemoryStream;

            Debug.Assert(memoryStream != null);
            Debug.Assert(memoryStream.TryGetBuffer(out _));

            byte[] plainText = memoryStream.GetBuffer();

            EncryptionProperties encryptionProperties = new EncryptionProperties(
                dataEncryptionKeyRid: dekProperties.ResourceId,
                encryptionFormatVersion: 1,
                encryptedData: inMemoryRawDek.AlgorithmUsingRawDek.EncryptData(plainText));

            itemJObj.Add(Constants.Properties.EncryptedInfo, JObject.FromObject(encryptionProperties));
            return(EncryptionProcessor.baseSerializer.ToStream(itemJObj));
        }
        public async Task <Stream> DecryptAsync(
            Stream input,
            DatabaseCore database,
            EncryptionKeyWrapProvider encryptionKeyWrapProvider,
            CosmosDiagnosticsContext diagnosticsContext,
            CancellationToken cancellationToken)
        {
            Debug.Assert(input != null);
            Debug.Assert(database != null);
            Debug.Assert(input.CanSeek);
            Debug.Assert(diagnosticsContext != null);

            if (encryptionKeyWrapProvider == null)
            {
                return(input);
            }

            JObject itemJObj = EncryptionProcessor.baseSerializer.FromStream <JObject>(input);

            JProperty encryptionPropertiesJProp = itemJObj.Property(Constants.Properties.EncryptedInfo);
            JObject   encryptionPropertiesJObj  = null;

            if (encryptionPropertiesJProp != null && encryptionPropertiesJProp.Value != null && encryptionPropertiesJProp.Value.Type == JTokenType.Object)
            {
                encryptionPropertiesJObj = (JObject)encryptionPropertiesJProp.Value;
            }

            if (encryptionPropertiesJObj == null)
            {
                input.Position = 0;
                return(input);
            }

            EncryptionProperties encryptionProperties = encryptionPropertiesJObj.ToObject <EncryptionProperties>();

            if (encryptionProperties.EncryptionFormatVersion != 1)
            {
                throw CosmosExceptionFactory.CreateInternalServerErrorException($"Unknown encryption format version: {encryptionProperties.EncryptionFormatVersion}. Please upgrade your SDK to the latest version.");
            }

            DataEncryptionKeyCore tempDek = (DataEncryptionKeyInlineCore)database.GetDataEncryptionKey(id: "unknown");

            (DataEncryptionKeyProperties _, InMemoryRawDek inMemoryRawDek) = await tempDek.FetchUnwrappedByRidAsync(
                encryptionProperties.DataEncryptionKeyRid,
                diagnosticsContext,
                cancellationToken);

            byte[] plainText = inMemoryRawDek.AlgorithmUsingRawDek.DecryptData(encryptionProperties.EncryptedData);

            JObject plainTextJObj = null;

            using (MemoryStream memoryStream = new MemoryStream(plainText))
                using (StreamReader streamReader = new StreamReader(memoryStream))
                    using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader))
                    {
                        plainTextJObj = JObject.Load(jsonTextReader);
                    }

            foreach (JProperty property in plainTextJObj.Properties())
            {
                itemJObj.Add(property.Name, property.Value);
            }

            itemJObj.Remove(Constants.Properties.EncryptedInfo);
            return(EncryptionProcessor.baseSerializer.ToStream(itemJObj));
        }