ContentHasher
Hashes Storage content.
using Azure.Core;
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
namespace Azure.Storage
{
internal static class ContentHasher
{
internal class GetHashResult
{
public static GetHashResult Empty { get; } = new GetHashResult(1, default(ReadOnlyMemory<byte>));
public StorageChecksumAlgorithm Algorithm { get; }
public ReadOnlyMemory<byte> Checksum { get; }
public ReadOnlyMemory<byte> MD5 {
get {
if ((int)Algorithm != 2)
return default(ReadOnlyMemory<byte>);
return Checksum;
}
}
public ReadOnlyMemory<byte> StorageCrc64 {
get {
if ((int)Algorithm != 3)
return default(ReadOnlyMemory<byte>);
return Checksum;
}
}
public byte[] MD5AsArray {
get {
ReadOnlyMemory<byte> mD = MD5;
if (!mD.IsEmpty) {
mD = MD5;
return mD.ToArray();
}
return null;
}
}
public byte[] StorageCrc64AsArray {
get {
ReadOnlyMemory<byte> storageCrc = StorageCrc64;
if (!storageCrc.IsEmpty) {
storageCrc = StorageCrc64;
return storageCrc.ToArray();
}
return null;
}
}
private GetHashResult(StorageChecksumAlgorithm algorithm, ReadOnlyMemory<byte> checksum)
{
Algorithm = algorithm;
Checksum = checksum;
}
public static GetHashResult FromStorageCrc64(ReadOnlyMemory<byte> checksum)
{
return new GetHashResult(3, checksum);
}
public static GetHashResult FromMD5(ReadOnlyMemory<byte> checksum)
{
return new GetHashResult(2, checksum);
}
}
public delegate int GetFinalStreamHash (Span<byte> destination);
internal static int GetHashSizeInBytes(StorageChecksumAlgorithm algorithm)
{
StorageChecksumAlgorithm val = algorithm.ResolveAuto();
switch (val - 1) {
case 0:
return 0;
case 1:
return 16;
case 2:
return 8;
default:
throw Errors.InvalidArgument("algorithm");
}
}
internal static UploadTransferValidationOptions ToUploadTransferValidationOptions(this GetHashResult hashResult)
{
if (hashResult == null) {
UploadTransferValidationOptions val = new UploadTransferValidationOptions();
val.set_ChecksumAlgorithm(1);
return val;
}
UploadTransferValidationOptions val2 = new UploadTransferValidationOptions();
val2.set_ChecksumAlgorithm(hashResult.Algorithm);
val2.set_PrecalculatedChecksum(hashResult.Checksum);
return val2;
}
[AsyncStateMachine(typeof(<AssertResponseHashMatchInternal>d__3))]
public static Task AssertResponseHashMatchInternal(Stream content, StorageChecksumAlgorithm algorithm, Response response, bool async, CancellationToken cancellationToken)
{
<AssertResponseHashMatchInternal>d__3 stateMachine = default(<AssertResponseHashMatchInternal>d__3);
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.content = content;
stateMachine.algorithm = algorithm;
stateMachine.response = response;
stateMachine.async = async;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
public static void AssertResponseHashMatch(byte[] content, int offset, int count, StorageChecksumAlgorithm algorithm, Response response)
{
AssertResponseHashMatch(GetHash(BinaryData.FromBytes(new ReadOnlyMemory<byte>(content, offset, count)), algorithm), algorithm, response);
}
private static void AssertResponseHashMatch(GetHashResult computedHash, StorageChecksumAlgorithm algorithm, Response response)
{
if (computedHash == null)
throw Errors.ArgumentNull("computedHash");
if (response == null)
throw Errors.ArgumentNull("response");
StorageChecksumAlgorithm val = algorithm.ResolveAuto();
ReadOnlyMemory<byte> readOnlyMemory;
if ((int)val != 2) {
if ((int)val != 3)
throw Errors.InvalidArgument("algorithm");
readOnlyMemory = computedHash.StorageCrc64;
if (!readOnlyMemory.Span.SequenceEqual(response.get_Headers().TryGetValue("x-ms-content-crc64", out byte[] value) ? value : null))
throw Errors.HashMismatch("x-ms-content-crc64");
} else {
readOnlyMemory = computedHash.MD5;
if (!readOnlyMemory.Span.SequenceEqual(response.get_Headers().TryGetValue("Content-MD5", out byte[] value2) ? value2 : null))
throw Errors.HashMismatch("Content-MD5");
}
}
[AsyncStateMachine(typeof(<GetHashOrDefaultInternal>d__6))]
public static Task<GetHashResult> GetHashOrDefaultInternal(Stream content, UploadTransferValidationOptions options, bool async, CancellationToken cancellationToken)
{
<GetHashOrDefaultInternal>d__6 stateMachine = default(<GetHashOrDefaultInternal>d__6);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<GetHashResult>.Create();
stateMachine.content = content;
stateMachine.options = options;
stateMachine.async = async;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
public static GetHashResult GetHashOrDefault(BinaryData content, UploadTransferValidationOptions options)
{
if (GetHashOrDefaultTryFromOptions(options, out GetHashResult result))
return result;
return GetHash(content, options.get_ChecksumAlgorithm());
}
private static bool GetHashOrDefaultTryFromOptions(UploadTransferValidationOptions options, out GetHashResult result)
{
if (options == null || (int)options.get_ChecksumAlgorithm() == 1) {
result = null;
return true;
}
if (!options.get_PrecalculatedChecksum().IsEmpty) {
StorageChecksumAlgorithm val = options.get_ChecksumAlgorithm().ResolveAuto();
GetHashResult getHashResult;
if ((int)val != 2) {
if ((int)val != 3)
throw Errors.InvalidArgument("ChecksumAlgorithm");
getHashResult = GetHashResult.FromStorageCrc64(options.get_PrecalculatedChecksum());
} else
getHashResult = GetHashResult.FromMD5(options.get_PrecalculatedChecksum());
result = getHashResult;
return true;
}
result = null;
return false;
}
[AsyncStateMachine(typeof(<GetHashInternal>d__9))]
public static Task<GetHashResult> GetHashInternal(Stream content, StorageChecksumAlgorithm algorithmIdentifier, bool async, CancellationToken cancellationToken)
{
<GetHashInternal>d__9 stateMachine = default(<GetHashInternal>d__9);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<GetHashResult>.Create();
stateMachine.content = content;
stateMachine.algorithmIdentifier = algorithmIdentifier;
stateMachine.async = async;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
public static GetHashResult GetHash(BinaryData content, StorageChecksumAlgorithm algorithmIdentifier)
{
<>c__DisplayClass10_0 <>c__DisplayClass10_ = default(<>c__DisplayClass10_0);
<>c__DisplayClass10_.content = content;
StorageChecksumAlgorithm val = algorithmIdentifier.ResolveAuto();
if ((int)val == 2)
return GetHashResult.FromMD5(MD5.Create().ComputeHash(<>c__DisplayClass10_.content.ToArray()));
if ((int)val != 3)
throw Errors.InvalidArgument("algorithmIdentifier");
return GetHashResult.FromStorageCrc64(<GetHash>g__computeCrc|10_0(StorageCrc64HashAlgorithm.Create(), ref <>c__DisplayClass10_));
}
public static (Stream Stream, GetFinalStreamHash GetCurrentStreamHash, int HashSize, IDisposable Disposable) SetupChecksumCalculatingReadStream(Stream stream, StorageChecksumAlgorithm algorithmIdentifier)
{
IHasher hasher = GetHasher(algorithmIdentifier);
IHasher hasher2 = hasher;
Stream readStream = ChecksumCalculatingStream.GetReadStream(stream, hasher2.AppendHash);
IHasher hasher3 = hasher;
return (readStream, hasher3.GetFinalHash, hasher.HashSizeInBytes, hasher);
}
private static IHasher GetHasher(StorageChecksumAlgorithm algorithmIdentifier)
{
StorageChecksumAlgorithm val = algorithmIdentifier.ResolveAuto();
if ((int)val == 2)
return new HashAlgorithmHasher(MD5.Create());
if ((int)val != 3)
throw Errors.InvalidArgument("algorithmIdentifier");
return new NonCryptographicHashAlgorithmHasher(StorageCrc64HashAlgorithm.Create());
}
[AsyncStateMachine(typeof(<ComputeHashInternal>d__14))]
private static Task<byte[]> ComputeHashInternal(Stream content, IHasher hasher, bool async, CancellationToken cancellationToken)
{
<ComputeHashInternal>d__14 stateMachine = default(<ComputeHashInternal>d__14);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<byte[]>.Create();
stateMachine.content = content;
stateMachine.hasher = hasher;
stateMachine.async = async;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
public static IHasher GetHasherFromAlgorithmId(StorageChecksumAlgorithm algorithm)
{
StorageChecksumAlgorithm val = algorithm.ResolveAuto();
switch (val - 1) {
case 0:
return null;
case 1:
return new HashAlgorithmHasher(MD5.Create());
case 2:
return new NonCryptographicHashAlgorithmHasher(StorageCrc64HashAlgorithm.Create());
default:
throw Errors.InvalidArgument("algorithm");
}
}
public static (ReadOnlyMemory<byte> Checksum, StorageChecksumAlgorithm Algorithm) GetResponseChecksumOrDefault(Response response)
{
if (response.get_Headers().TryGetValue("x-ms-content-crc64", out byte[] value))
return (value, 3);
if (response.get_Headers().TryGetValue("Content-MD5", out byte[] value2))
return (value2, 2);
return (ReadOnlyMemory<byte>.Empty, 1);
}
}
}