112 lines
3.6 KiB
C#
112 lines
3.6 KiB
C#
// dnlib: See LICENSE.txt for more info
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Security.Cryptography;
|
|
|
|
namespace dnlib.DotNet {
|
|
/// <summary>
|
|
/// Hashes some data according to a <see cref="AssemblyHashAlgorithm"/>
|
|
/// </summary>
|
|
readonly struct AssemblyHash : IDisposable {
|
|
readonly HashAlgorithm hasher;
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
/// <remarks>If <paramref name="hashAlgo"/> is an unsupported hash algorithm, then
|
|
/// <see cref="AssemblyHashAlgorithm.SHA1"/> will be used as the hash algorithm.</remarks>
|
|
/// <param name="hashAlgo">The algorithm to use</param>
|
|
public AssemblyHash(AssemblyHashAlgorithm hashAlgo) =>
|
|
hasher = hashAlgo switch {
|
|
AssemblyHashAlgorithm.MD5 => MD5.Create(),
|
|
AssemblyHashAlgorithm.SHA_256 => SHA256.Create(),
|
|
AssemblyHashAlgorithm.SHA_384 => SHA384.Create(),
|
|
AssemblyHashAlgorithm.SHA_512 => SHA512.Create(),
|
|
_ => SHA1.Create(),
|
|
};
|
|
|
|
/// <inheritdoc/>
|
|
public void Dispose() {
|
|
if (hasher is not null)
|
|
((IDisposable)hasher).Dispose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hash data
|
|
/// </summary>
|
|
/// <remarks>If <paramref name="hashAlgo"/> is an unsupported hash algorithm, then
|
|
/// <see cref="AssemblyHashAlgorithm.SHA1"/> will be used as the hash algorithm.</remarks>
|
|
/// <param name="data">The data</param>
|
|
/// <param name="hashAlgo">The algorithm to use</param>
|
|
/// <returns>Hashed data or null if <paramref name="data"/> was <c>null</c></returns>
|
|
public static byte[] Hash(byte[] data, AssemblyHashAlgorithm hashAlgo) {
|
|
if (data is null)
|
|
return null;
|
|
|
|
using (var asmHash = new AssemblyHash(hashAlgo)) {
|
|
asmHash.Hash(data);
|
|
return asmHash.ComputeHash();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hash data
|
|
/// </summary>
|
|
/// <param name="data">Data</param>
|
|
public void Hash(byte[] data) => Hash(data, 0, data.Length);
|
|
|
|
/// <summary>
|
|
/// Hash data
|
|
/// </summary>
|
|
/// <param name="data">Data</param>
|
|
/// <param name="offset">Offset</param>
|
|
/// <param name="length">Length</param>
|
|
public void Hash(byte[] data, int offset, int length) {
|
|
if (hasher.TransformBlock(data, offset, length, data, offset) != length)
|
|
throw new IOException("Could not calculate hash");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hash stream data
|
|
/// </summary>
|
|
/// <param name="stream">Stream</param>
|
|
/// <param name="length">Number of bytes to hash</param>
|
|
/// <param name="buffer">Temp buffer</param>
|
|
public void Hash(Stream stream, uint length, byte[] buffer) {
|
|
while (length > 0) {
|
|
int len = length > (uint)buffer.Length ? buffer.Length : (int)length;
|
|
if (stream.Read(buffer, 0, len) != len)
|
|
throw new IOException("Could not read data");
|
|
Hash(buffer, 0, len);
|
|
length -= (uint)len;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the hash
|
|
/// </summary>
|
|
public byte[] ComputeHash() {
|
|
hasher.TransformFinalBlock(Array2.Empty<byte>(), 0, 0);
|
|
return hasher.Hash;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a public key token from the hash of some <paramref name="publicKeyData"/>
|
|
/// </summary>
|
|
/// <remarks>A public key is hashed, and the last 8 bytes of the hash, in reverse
|
|
/// order, is used as the public key token</remarks>
|
|
/// <param name="publicKeyData">The data</param>
|
|
/// <returns>A new <see cref="PublicKeyToken"/> instance</returns>
|
|
public static PublicKeyToken CreatePublicKeyToken(byte[] publicKeyData) {
|
|
if (publicKeyData is null)
|
|
return new PublicKeyToken();
|
|
var hash = Hash(publicKeyData, AssemblyHashAlgorithm.SHA1);
|
|
var pkt = new byte[8];
|
|
for (int i = 0; i < pkt.Length && i < hash.Length; i++)
|
|
pkt[i] = hash[hash.Length - i - 1];
|
|
return new PublicKeyToken(pkt);
|
|
}
|
|
}
|
|
}
|