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); }
public async Task EncryptionUTRewrapDekWithoutEncryptionSerializer() { string dekId = "mydek"; EncryptionTestHandler testHandler = new EncryptionTestHandler(); // Create a DEK using a properly setup client first Container container = this.GetContainerWithMockSetup(testHandler); DatabaseCore databaseWithSerializer = (DatabaseCore)((ContainerCore)(ContainerInlineCore)container).Database; DataEncryptionKeyResponse dekResponse = await databaseWithSerializer.CreateDataEncryptionKeyAsync(dekId, EncryptionUnitTests.Algo, this.metadata1); Assert.AreEqual(HttpStatusCode.Created, dekResponse.StatusCode); // Clear the handler pipeline that would have got setup testHandler.InnerHandler = null; // Ensure rewrap for this key fails on improperly configured client try { DatabaseCore database = (DatabaseCore)((ContainerCore)(ContainerInlineCore)this.GetContainer(testHandler)).Database; DataEncryptionKey dek = database.GetDataEncryptionKey(dekId); await dek.RewrapAsync(this.metadata2); Assert.Fail(); } catch (ArgumentException ex) { Assert.AreEqual(ClientResources.EncryptionKeyWrapProviderNotConfigured, ex.Message); } }
public async Task EncryptionUTCreateItemWithUnknownDek() { Container container = this.GetContainerWithMockSetup(); DatabaseCore database = (DatabaseCore)((ContainerCore)(ContainerInlineCore)container).Database; MyItem item = EncryptionUnitTests.GetNewItem(); try { await container.CreateItemAsync( item, new PartitionKey(item.PK), new ItemRequestOptions { EncryptionOptions = new EncryptionOptions { DataEncryptionKey = database.GetDataEncryptionKey("random"), PathsToEncrypt = MyItem.PathsToEncrypt } }); Assert.Fail(); } catch (CosmosException ex) { Assert.IsTrue(ex.Message.Contains(ClientResources.DataEncryptionKeyNotFound)); } }
public async Task EncryptionUTRewrapDek() { Container container = this.GetContainerWithMockSetup(); DatabaseCore database = (DatabaseCore)((ContainerCore)(ContainerInlineCore)container).Database; string dekId = "mydek"; DataEncryptionKeyResponse createResponse = await database.CreateDataEncryptionKeyAsync(dekId, EncryptionUnitTests.Algo, this.metadata1); DataEncryptionKeyProperties createdProperties = createResponse.Resource; Assert.AreEqual(HttpStatusCode.Created, createResponse.StatusCode); this.VerifyWrap(this.dek, this.metadata1); DataEncryptionKey dek = database.GetDataEncryptionKey(dekId); DataEncryptionKeyResponse rewrapResponse = await dek.RewrapAsync(this.metadata2); DataEncryptionKeyProperties rewrappedProperties = rewrapResponse.Resource; Assert.IsNotNull(rewrappedProperties); Assert.AreEqual(dekId, rewrappedProperties.Id); Assert.AreEqual(createdProperties.CreatedTime, rewrappedProperties.CreatedTime); Assert.IsNotNull(rewrappedProperties.LastModified); Assert.AreEqual(createdProperties.ResourceId, rewrappedProperties.ResourceId); Assert.AreEqual(createdProperties.SelfLink, rewrappedProperties.SelfLink); IEnumerable <byte> expectedRewrappedKey = this.dek.Select(b => (byte)(b + 2)); Assert.IsTrue(expectedRewrappedKey.SequenceEqual(rewrappedProperties.WrappedDataEncryptionKey)); Assert.AreEqual(new EncryptionKeyWrapMetadata(this.metadata2.Value + this.metadataUpdateSuffix), rewrappedProperties.EncryptionKeyWrapMetadata); Assert.AreEqual(2, this.testHandler.Received.Count); RequestMessage rewrapRequestMessage = this.testHandler.Received[1]; Assert.AreEqual(ResourceType.ClientEncryptionKey, rewrapRequestMessage.ResourceType); Assert.AreEqual(OperationType.Replace, rewrapRequestMessage.OperationType); Assert.AreEqual(createResponse.ETag, rewrapRequestMessage.Headers[HttpConstants.HttpHeaders.IfMatch]); Assert.IsTrue(this.testHandler.Deks.ContainsKey(dekId)); DataEncryptionKeyProperties serverDekProperties = this.testHandler.Deks[dekId]; Assert.IsTrue(serverDekProperties.Equals(rewrappedProperties)); this.VerifyWrap(this.dek, this.metadata2); this.mockKeyWrapProvider.VerifyNoOtherCalls(); }
private static async Task <MyItem> CreateItemAsync(Container container, string dekId, List <string> pathsToEncrypt) { DatabaseCore database = (DatabaseCore)((ContainerCore)(ContainerInlineCore)container).Database; MyItem item = EncryptionUnitTests.GetNewItem(); ItemResponse <MyItem> response = await container.CreateItemAsync <MyItem>( item, requestOptions : new ItemRequestOptions { EncryptionOptions = new EncryptionOptions { DataEncryptionKey = database.GetDataEncryptionKey(dekId), PathsToEncrypt = pathsToEncrypt } }); Assert.AreEqual(HttpStatusCode.Created, response.StatusCode); Assert.AreEqual(item, response.Resource); return(item); }
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)); }