private static async Task <DecryptionContext> MdeEncAlgoDecryptObjectAsync( JObject document, Encryptor encryptor, EncryptionProperties encryptionProperties, CosmosDiagnosticsContext diagnosticsContext, CancellationToken cancellationToken) { JObject plainTextJObj = new JObject(); foreach (string path in encryptionProperties.EncryptedPaths) { string propertyName = path.Substring(1); if (!document.TryGetValue(propertyName, out JToken propertyValue)) { throw new InvalidOperationException($"{nameof(encryptionProperties.EncryptedPaths)} includes a path: '{path}' which was not found."); } byte[] cipherTextWithTypeMarker = propertyValue.ToObject <byte[]>(); if (cipherTextWithTypeMarker == null) { continue; } byte[] cipherText = new byte[cipherTextWithTypeMarker.Length - 1]; Buffer.BlockCopy(cipherTextWithTypeMarker, 1, cipherText, 0, cipherTextWithTypeMarker.Length - 1); byte[] plainText = await EncryptionProcessor.MdeEncAlgoDecryptPropertyAsync( encryptionProperties, cipherText, encryptor, diagnosticsContext, cancellationToken); EncryptionProcessor.DeserializeAndAddProperty( (TypeMarker)cipherTextWithTypeMarker[0], plainText, plainTextJObj, propertyName); } List <string> pathsDecrypted = new List <string>(); foreach (JProperty property in plainTextJObj.Properties()) { document[property.Name] = property.Value; pathsDecrypted.Add("/" + property.Name); } DecryptionContext decryptionContext = EncryptionProcessor.CreateDecryptionContext( pathsDecrypted, encryptionProperties.DataEncryptionKeyId); document.Remove(Constants.EncryptedInfo); return(decryptionContext); }
private static async Task <DecryptionContext> LegacyEncAlgoDecryptContentAsync( JObject document, EncryptionProperties encryptionProperties, Encryptor encryptor, CosmosDiagnosticsContext diagnosticsContext, CancellationToken cancellationToken) { if (encryptionProperties.EncryptionFormatVersion != 2) { throw new NotSupportedException($"Unknown encryption format version: {encryptionProperties.EncryptionFormatVersion}. Please upgrade your SDK to the latest version."); } byte[] plainText = await encryptor.DecryptAsync( encryptionProperties.EncryptedData, encryptionProperties.DataEncryptionKeyId, encryptionProperties.EncryptionAlgorithm, cancellationToken); if (plainText == null) { throw new InvalidOperationException($"{nameof(Encryptor)} returned null plainText from {nameof(DecryptAsync)}."); } JObject plainTextJObj; using (MemoryStream memoryStream = new MemoryStream(plainText)) using (StreamReader streamReader = new StreamReader(memoryStream)) using (JsonTextReader jsonTextReader = new JsonTextReader(streamReader)) { plainTextJObj = JObject.Load(jsonTextReader); } List <string> pathsDecrypted = new List <string>(); foreach (JProperty property in plainTextJObj.Properties()) { document.Add(property.Name, property.Value); pathsDecrypted.Add("/" + property.Name); } DecryptionContext decryptionContext = EncryptionProcessor.CreateDecryptionContext( pathsDecrypted, encryptionProperties.DataEncryptionKeyId); document.Remove(Constants.EncryptedInfo); return(decryptionContext); }
private static DecryptionContext CreateDecryptionContext( List <string> pathsDecrypted, string dataEncryptionKeyId) { DecryptionInfo decryptionInfo = new DecryptionInfo( pathsDecrypted, dataEncryptionKeyId); DecryptionContext decryptionContext = new DecryptionContext( new List <DecryptionInfo>() { decryptionInfo }); return(decryptionContext); }
/// <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, DecryptionContext)> DecryptAsync( Stream input, Encryptor encryptor, CosmosDiagnosticsContext diagnosticsContext, CancellationToken cancellationToken) { if (input == null) { return(input, null); } Debug.Assert(input.CanSeek); Debug.Assert(encryptor != null); Debug.Assert(diagnosticsContext != null); JObject itemJObj = EncryptionProcessor.RetrieveItem(input); JObject encryptionPropertiesJObj = EncryptionProcessor.RetrieveEncryptionProperties(itemJObj); if (encryptionPropertiesJObj == null) { input.Position = 0; return(input, null); } EncryptionProperties encryptionProperties = encryptionPropertiesJObj.ToObject <EncryptionProperties>(); DecryptionContext decryptionContext = encryptionProperties.EncryptionAlgorithm switch { CosmosEncryptionAlgorithm.MdeAeadAes256CbcHmac256Randomized => await EncryptionProcessor.MdeEncAlgoDecryptObjectAsync( itemJObj, encryptor, encryptionProperties, diagnosticsContext, cancellationToken), CosmosEncryptionAlgorithm.AEAes256CbcHmacSha256Randomized => await EncryptionProcessor.LegacyEncAlgoDecryptContentAsync( itemJObj, encryptionProperties, encryptor, diagnosticsContext, cancellationToken), _ => throw new NotSupportedException($"Encryption Algorithm : {encryptionProperties.EncryptionAlgorithm} is not supported."), }; input.Dispose(); return(EncryptionProcessor.BaseSerializer.ToStream(itemJObj), decryptionContext); }
public static async Task <(JObject, DecryptionContext)> DecryptAsync( JObject document, Encryptor encryptor, CosmosDiagnosticsContext diagnosticsContext, CancellationToken cancellationToken) { Debug.Assert(document != null); Debug.Assert(encryptor != null); JObject encryptionPropertiesJObj = EncryptionProcessor.RetrieveEncryptionProperties(document); if (encryptionPropertiesJObj == null) { return(document, null); } EncryptionProperties encryptionProperties = encryptionPropertiesJObj.ToObject <EncryptionProperties>(); DecryptionContext decryptionContext = encryptionProperties.EncryptionAlgorithm switch { CosmosEncryptionAlgorithm.MdeAeadAes256CbcHmac256Randomized => await EncryptionProcessor.MdeEncAlgoDecryptObjectAsync( document, encryptor, encryptionProperties, diagnosticsContext, cancellationToken), CosmosEncryptionAlgorithm.AEAes256CbcHmacSha256Randomized => await EncryptionProcessor.LegacyEncAlgoDecryptContentAsync( document, encryptionProperties, encryptor, diagnosticsContext, cancellationToken), _ => throw new NotSupportedException($"Encryption Algorithm : {encryptionProperties.EncryptionAlgorithm} is not supported."), }; return(document, decryptionContext); }