/// <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 == null) return null; using (var asmHash = new AssemblyHash(hashAlgo)) { asmHash.Hash(data); return asmHash.ComputeHash(); } }
/// <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 == null) { return(null); } using (var asmHash = new AssemblyHash(hashAlgo)) { asmHash.Hash(data); return(asmHash.ComputeHash()); } }
/// <summary> /// Creates a counter signature, just like /// <c>sn -a IdentityPubKey.snk IdentityKey.snk SignaturePubKey.snk</c> can do. /// The public key <c>sn</c> prints is <paramref name="signaturePubKey"/>'s value. /// </summary> /// <param name="identityPubKey">Identity public key</param> /// <param name="identityKey">Identity strong name key pair</param> /// <param name="signaturePubKey">Signature public key</param> /// <returns>The counter signature</returns> public static byte[] CreateCounterSignature(StrongNamePublicKey identityPubKey, StrongNameKey identityKey, StrongNamePublicKey signaturePubKey) { var hash = AssemblyHash.Hash(signaturePubKey.CreatePublicKey(), identityPubKey.HashAlgorithm); using (var rsa = identityKey.CreateRSA()) { var rsaFmt = new RSAPKCS1SignatureFormatter(rsa); string hashName = identityPubKey.HashAlgorithm.GetName(); rsaFmt.SetHashAlgorithm(hashName); var snSig = rsaFmt.CreateSignature(hash); Array.Reverse(snSig); return(snSig); } }
/// <summary> /// Strong name hashes the .NET file /// </summary> /// <param name="hashAlg">Hash algorithm</param> /// <param name="snSigOffset">Strong name sig offset (relative to start of .NET PE file)</param> /// <param name="snSigSize">Size of strong name signature</param> /// <returns>The strong name hash of the .NET file</returns> byte[] StrongNameHashData(AssemblyHashAlgorithm hashAlg, long snSigOffset, uint snSigSize) { var reader = new BinaryReader(stream); snSigOffset += baseOffset; long snSigOffsetEnd = snSigOffset + snSigSize; using var hasher = new AssemblyHash(hashAlg); var buffer = new byte[0x8000]; // Hash the DOS header. It's defined to be all data from the start of // the file up to the NT headers. stream.Position = baseOffset + 0x3C; uint ntHeadersOffs = reader.ReadUInt32(); stream.Position = baseOffset; hasher.Hash(stream, ntHeadersOffs, buffer); // Hash NT headers, but hash authenticode + checksum as 0s stream.Position += 6; int numSections = reader.ReadUInt16(); stream.Position -= 8; hasher.Hash(stream, 0x18, buffer); // magic + FileHeader bool is32bit = reader.ReadUInt16() == 0x010B; stream.Position -= 2; int optHeaderSize = is32bit ? 0x60 : 0x70; if (stream.Read(buffer, 0, optHeaderSize) != optHeaderSize) { throw new IOException("Could not read data"); } // Clear checksum for (int i = 0; i < 4; i++) { buffer[0x40 + i] = 0; } hasher.Hash(buffer, 0, optHeaderSize); const int imageDirsSize = 16 * 8; if (stream.Read(buffer, 0, imageDirsSize) != imageDirsSize) { throw new IOException("Could not read data"); } // Clear authenticode data dir for (int i = 0; i < 8; i++) { buffer[(4 * 8) + i] = 0; } hasher.Hash(buffer, 0, imageDirsSize); // Hash section headers long sectHeadersOffs = stream.Position; hasher.Hash(stream, (uint)numSections * 0x28, buffer); // Hash all raw section data but make sure we don't hash the location // where the strong name signature will be stored. for (int i = 0; i < numSections; i++) { stream.Position = sectHeadersOffs + (i * 0x28) + 0x10; uint sizeOfRawData = reader.ReadUInt32(); uint pointerToRawData = reader.ReadUInt32(); stream.Position = baseOffset + pointerToRawData; while (sizeOfRawData > 0) { var pos = stream.Position; if (snSigOffset <= pos && pos < snSigOffsetEnd) { uint skipSize = (uint)(snSigOffsetEnd - pos); if (skipSize >= sizeOfRawData) { break; } sizeOfRawData -= skipSize; stream.Position += skipSize; continue; } if (pos >= snSigOffsetEnd) { hasher.Hash(stream, sizeOfRawData, buffer); break; } uint maxLen = (uint)Math.Min(snSigOffset - pos, sizeOfRawData); hasher.Hash(stream, maxLen, buffer); sizeOfRawData -= maxLen; } } return(hasher.ComputeHash()); }
/// <summary> /// Strong name hashes the .NET file /// </summary> /// <param name="hashAlg">Hash algorithm</param> /// <param name="snSigOffset">Strong name sig offset (relative to start of .NET PE file)</param> /// <param name="snSigSize">Size of strong name signature</param> /// <returns>The strong name hash of the .NET file</returns> byte[] StrongNameHashData(AssemblyHashAlgorithm hashAlg, long snSigOffset, uint snSigSize) { var reader = new BinaryReader(stream); snSigOffset += baseOffset; long snSigOffsetEnd = snSigOffset + snSigSize; using (var hasher = new AssemblyHash(hashAlg)) { byte[] buffer = new byte[0x8000]; // Hash the DOS header. It's defined to be all data from the start of // the file up to the NT headers. stream.Position = baseOffset + 0x3C; uint ntHeadersOffs = reader.ReadUInt32(); stream.Position = baseOffset; hasher.Hash(stream, ntHeadersOffs, buffer); // Hash NT headers, but hash authenticode + checksum as 0s stream.Position += 6; int numSections = reader.ReadUInt16(); stream.Position -= 8; hasher.Hash(stream, 0x18, buffer); // magic + FileHeader bool is32bit = reader.ReadUInt16() == 0x010B; stream.Position -= 2; int optHeaderSize = is32bit ? 0x60 : 0x70; if (stream.Read(buffer, 0, optHeaderSize) != optHeaderSize) throw new IOException("Could not read data"); // Clear checksum for (int i = 0; i < 4; i++) buffer[0x40 + i] = 0; hasher.Hash(buffer, 0, optHeaderSize); const int imageDirsSize = 16 * 8; if (stream.Read(buffer, 0, imageDirsSize) != imageDirsSize) throw new IOException("Could not read data"); // Clear authenticode data dir for (int i = 0; i < 8; i++) buffer[4 * 8 + i] = 0; hasher.Hash(buffer, 0, imageDirsSize); // Hash section headers long sectHeadersOffs = stream.Position; hasher.Hash(stream, (uint)numSections * 0x28, buffer); // Hash all raw section data but make sure we don't hash the location // where the strong name signature will be stored. for (int i = 0; i < numSections; i++) { stream.Position = sectHeadersOffs + i * 0x28 + 0x10; uint sizeOfRawData = reader.ReadUInt32(); uint pointerToRawData = reader.ReadUInt32(); stream.Position = baseOffset + pointerToRawData; while (sizeOfRawData > 0) { var pos = stream.Position; if (snSigOffset <= pos && pos < snSigOffsetEnd) { uint skipSize = (uint)(snSigOffsetEnd - pos); if (skipSize >= sizeOfRawData) break; sizeOfRawData -= skipSize; stream.Position += skipSize; continue; } if (pos >= snSigOffsetEnd) { hasher.Hash(stream, sizeOfRawData, buffer); break; } uint maxLen = (uint)Math.Min(snSigOffset - pos, sizeOfRawData); hasher.Hash(stream, maxLen, buffer); sizeOfRawData -= maxLen; } } return hasher.ComputeHash(); } }