public static async Task <JObject> DecryptAsync( JObject document, Encryptor encryptor, CosmosDiagnosticsContext diagnosticsContext, IReadOnlyDictionary <List <string>, string> pathsToEncrypt, CancellationToken cancellationToken) { Debug.Assert(document != null); Debug.Assert(encryptor != null); Debug.Assert(diagnosticsContext != null); foreach (List <string> paths in pathsToEncrypt.Keys) { foreach (string path in paths) { if (document.TryGetValue(path.Substring(1), out JToken propertyValue)) { EncryptionProperties encryptionProperties = new EncryptionProperties( encryptionFormatVersion: 2, CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256, pathsToEncrypt[paths], propertyValue.ToObject <byte[]>(), path); JObject propPlainTextJObj = await PropertyEncryptionProcessor.DecryptContentAsync( encryptionProperties, encryptor, diagnosticsContext, cancellationToken); foreach (JProperty property in propPlainTextJObj.Properties()) { document[property.Name] = property.Value; } } } } if (document.TryGetValue(Constants.EncryptedInfo, out JToken encryptedInfo)) { EncryptionProperties encryptionProperties = JsonConvert.DeserializeObject <EncryptionProperties>(encryptedInfo.ToString()); JObject plainTextJObj = await PropertyEncryptionProcessor.DecryptContentAsync( encryptionProperties, encryptor, diagnosticsContext, cancellationToken); document.Remove(Constants.EncryptedInfo); foreach (JProperty property in plainTextJObj.Properties()) { document.Add(property.Name, property.Value); } } return(document); }
/// <remarks> /// If there isn't any data that needs to be decrypted, input stream will be returned without any modification. /// Else input stream will be disposed, and a new stream is returned. /// In case of an exception, input stream won't be disposed, but position will be end of stream. /// </remarks> public static async Task <Stream> DecryptAsync( Stream input, Encryptor encryptor, CosmosDiagnosticsContext diagnosticsContext, IReadOnlyDictionary <List <string>, string> pathsToEncrypt, CancellationToken cancellationToken) { Debug.Assert(input != null); Debug.Assert(input.CanSeek); Debug.Assert(encryptor != null); Debug.Assert(diagnosticsContext != null); JObject itemJObj; using (StreamReader sr = new StreamReader(input, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 1024, leaveOpen: true)) { using JsonTextReader jsonTextReader = new JsonTextReader(sr); itemJObj = JsonSerializer.Create().Deserialize <JObject>(jsonTextReader); } if (pathsToEncrypt != null) { foreach (List <string> paths in pathsToEncrypt.Keys) { foreach (string path in paths) { if (itemJObj.TryGetValue(path.Substring(1), out JToken propertyValue)) { EncryptionProperties encryptionProperties = new EncryptionProperties( encryptionFormatVersion: 2, CosmosEncryptionAlgorithm.AEAD_AES_256_CBC_HMAC_SHA256, pathsToEncrypt[paths], propertyValue.ToObject <byte[]>(), path); JObject propPlainTextJObj = await PropertyEncryptionProcessor.DecryptContentAsync( encryptionProperties, encryptor, diagnosticsContext, cancellationToken); foreach (JProperty property in propPlainTextJObj.Properties()) { itemJObj[property.Name] = property.Value; } } } input.Dispose(); } } JToken token = itemJObj[Constants.EncryptedInfo]; if (token != null) { JProperty encryptionPropertiesJProp = itemJObj.Property(Constants.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>(); JObject plainTextJObj = await PropertyEncryptionProcessor.DecryptContentAsync( encryptionProperties, encryptor, diagnosticsContext, cancellationToken); foreach (JProperty property in plainTextJObj.Properties()) { itemJObj.Add(property.Name, property.Value); } itemJObj.Remove(Constants.EncryptedInfo); input.Dispose(); } return(EncryptionProcessor.BaseSerializer.ToStream(itemJObj)); }