/// <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()); } }