private async Task <BinaryData> ClientSideDecryptInternal(BinaryData downloadedMessage, bool async, CancellationToken cancellationToken) { if (!EncryptedMessageSerializer.TryDeserialize(downloadedMessage, out var encryptedMessage)) { return(downloadedMessage); // not recognized as client-side encrypted message } var encryptedMessageStream = new MemoryStream(Convert.FromBase64String(encryptedMessage.EncryptedMessageText)); var decryptedMessageStream = await _decryptor.DecryptReadInternal( encryptedMessageStream, encryptedMessage.EncryptionData, ivInStream : false, noPadding : false, async : async, cancellationToken).ConfigureAwait(false); // if we got back the stream we put in, then we couldn't decrypt and are supposed to return the original // message to the user if (encryptedMessageStream == decryptedMessageStream) { return(downloadedMessage); } return(async ? await BinaryData.FromStreamAsync(decryptedMessageStream, cancellationToken).ConfigureAwait(false) : BinaryData.FromStream(decryptedMessageStream)); }
public async Task <Stream> DecryptInternal( Stream content, Metadata metadata, HttpRange originalRange, string receivedContentRange, bool async, CancellationToken cancellationToken) { ContentRange?contentRange = string.IsNullOrWhiteSpace(receivedContentRange) ? default : ContentRange.Parse(receivedContentRange); EncryptionData encryptionData = GetAndValidateEncryptionDataOrDefault(metadata); if (encryptionData == default) { return(await TrimStreamInternal(content, originalRange, contentRange, alreadyTrimmedOffsetAmount : 0, async, cancellationToken).ConfigureAwait(false)); } bool ivInStream = originalRange.Offset >= Constants.ClientSideEncryption.EncryptionBlockSize; // this method throws when key cannot be resolved. Blobs is intended to throw on this failure. var plaintext = await _decryptor.DecryptReadInternal( content, encryptionData, ivInStream, CanIgnorePadding(contentRange), async, cancellationToken).ConfigureAwait(false); int v2StartRegion0Indexed = (int)((contentRange?.Start / encryptionData.EncryptedRegionInfo?.GetTotalRegionLength()) ?? 0); int alreadyTrimmedOffset = encryptionData.EncryptionAgent.EncryptionVersion switch { ClientSideEncryptionVersion.V1_0 => ivInStream ? Constants.ClientSideEncryption.EncryptionBlockSize : 0, // first block is special case where we don't want to communicate a trim. Otherwise communicate nonce length * 1-indexed start region + tag length * 0-indexed region ClientSideEncryptionVersion.V2_0 => contentRange?.Start > 0 ? (-encryptionData.EncryptedRegionInfo.NonceLength * (v2StartRegion0Indexed)) - (Constants.ClientSideEncryption.V2.TagSize * v2StartRegion0Indexed) : 0, _ => throw Errors.ClientSideEncryption.ClientSideEncryptionVersionNotSupported() }; return(await TrimStreamInternal(plaintext, originalRange, contentRange, alreadyTrimmedOffset, async, cancellationToken).ConfigureAwait(false)); }