/// <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, EncryptionSettings encryptionSettings, EncryptionDiagnosticsContext operationDiagnostics, CancellationToken cancellationToken) { if (input == null) { return(input); } Debug.Assert(input.CanSeek, "DecryptAsync input.CanSeek false"); operationDiagnostics?.Begin(Constants.DiagnosticsDecryptOperation); JObject itemJObj = RetrieveItem(input); int propertiesDecryptedCount = await DecryptObjectAsync( itemJObj, encryptionSettings, cancellationToken); Stream result = EncryptionProcessor.BaseSerializer.ToStream(itemJObj); input.Dispose(); operationDiagnostics?.End(propertiesDecryptedCount); return(result); }
/// <remarks> /// If there isn't any PathsToEncrypt, 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> EncryptAsync( Stream input, EncryptionSettings encryptionSettings, EncryptionDiagnosticsContext operationDiagnostics, CancellationToken cancellationToken) { if (input == null) { throw new ArgumentNullException(nameof(input)); } operationDiagnostics?.Begin(Constants.DiagnosticsEncryptOperation); int propertiesEncryptedCount = 0; JObject itemJObj = EncryptionProcessor.BaseSerializer.FromStream <JObject>(input); foreach (string propertyName in encryptionSettings.PropertiesToEncrypt) { // possibly a wrong path configured in the Client Encryption Policy, ignore. JProperty propertyToEncrypt = itemJObj.Property(propertyName); if (propertyToEncrypt == null) { continue; } EncryptionSettingForProperty settingforProperty = encryptionSettings.GetEncryptionSettingForProperty(propertyName); if (settingforProperty == null) { throw new ArgumentException($"Invalid Encryption Setting for the Property:{propertyName}. "); } await EncryptJTokenAsync( propertyToEncrypt.Value, settingforProperty, propertyName == "id", cancellationToken); propertiesEncryptedCount++; } Stream result = EncryptionProcessor.BaseSerializer.ToStream(itemJObj); input.Dispose(); operationDiagnostics?.End(propertiesEncryptedCount); return(result); }
internal static async Task <Stream> DeserializeAndDecryptResponseAsync( Stream content, EncryptionSettings encryptionSettings, EncryptionDiagnosticsContext operationDiagnostics, CancellationToken cancellationToken) { if (!encryptionSettings.PropertiesToEncrypt.Any()) { return(content); } operationDiagnostics?.Begin(Constants.DiagnosticsDecryptOperation); 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. "); } int totalPropertiesDecryptedCount = 0; foreach (JToken value in documents) { if (value is not JObject document) { continue; } (_, int propertiesDecrypted) = await EncryptionProcessor.DecryptAsync( document, encryptionSettings, cancellationToken); totalPropertiesDecryptedCount += propertiesDecrypted; } operationDiagnostics?.End(totalPropertiesDecryptedCount); // the contents get decrypted in place by DecryptAsync. return(EncryptionProcessor.BaseSerializer.ToStream(contentJObj)); }