internal StrongNameSignature StrongHash (Stream stream, StrongNameOptions options)
{
StrongNameSignature info = new StrongNameSignature ();
HashAlgorithm hash = HashAlgorithm.Create (TokenAlgorithm);
CryptoStream cs = new CryptoStream (Stream.Null, hash, CryptoStreamMode.Write);
// MS-DOS Header - always 128 bytes
// ref: Section 24.2.1, Partition II Metadata
byte[] mz = new byte [128];
stream.Read (mz, 0, 128);
if (BitConverterLE.ToUInt16 (mz, 0) != 0x5a4d)
return null;
UInt32 peHeader = BitConverterLE.ToUInt32 (mz, 60);
cs.Write (mz, 0, 128);
if (peHeader != 128) {
byte[] mzextra = new byte [peHeader - 128];
stream.Read (mzextra, 0, mzextra.Length);
cs.Write (mzextra, 0, mzextra.Length);
}
// PE File Header - always 248 bytes
// ref: Section 24.2.2, Partition II Metadata
byte[] pe = new byte [248];
stream.Read (pe, 0, 248);
if (BitConverterLE.ToUInt32 (pe, 0) != 0x4550)
return null;
if (BitConverterLE.ToUInt16 (pe, 4) != 0x14c)
return null;
// MUST zeroize both CheckSum and Security Directory
byte[] v = new byte [8];
Buffer.BlockCopy (v, 0, pe, 88, 4);
Buffer.BlockCopy (v, 0, pe, 152, 8);
cs.Write (pe, 0, 248);
UInt16 numSection = BitConverterLE.ToUInt16 (pe, 6);
int sectionLength = (numSection * 40);
byte[] sectionHeaders = new byte [sectionLength];
stream.Read (sectionHeaders, 0, sectionLength);
cs.Write (sectionHeaders, 0, sectionLength);
UInt32 cliHeaderRVA = BitConverterLE.ToUInt32 (pe, 232);
UInt32 cliHeaderPos = RVAtoPosition (cliHeaderRVA, numSection, sectionHeaders);
int cliHeaderSiz = (int) BitConverterLE.ToUInt32 (pe, 236);
// CLI Header
// ref: Section 24.3.3, Partition II Metadata
byte[] cli = new byte [cliHeaderSiz];
stream.Position = cliHeaderPos;
stream.Read (cli, 0, cliHeaderSiz);
UInt32 strongNameSignatureRVA = BitConverterLE.ToUInt32 (cli, 32);
info.SignaturePosition = RVAtoPosition (strongNameSignatureRVA, numSection, sectionHeaders);
info.SignatureLength = BitConverterLE.ToUInt32 (cli, 36);
UInt32 metadataRVA = BitConverterLE.ToUInt32 (cli, 8);
info.MetadataPosition = RVAtoPosition (metadataRVA, numSection, sectionHeaders);
info.MetadataLength = BitConverterLE.ToUInt32 (cli, 12);
if (options == StrongNameOptions.Metadata) {
cs.Close ();
hash.Initialize ();
byte[] metadata = new byte [info.MetadataLength];
stream.Position = info.MetadataPosition;
stream.Read (metadata, 0, metadata.Length);
info.Hash = hash.ComputeHash (metadata);
return info;
}
// now we hash every section EXCEPT the signature block
for (int i=0; i < numSection; i++) {
UInt32 start = BitConverterLE.ToUInt32 (sectionHeaders, i * 40 + 20);
int length = (int) BitConverterLE.ToUInt32 (sectionHeaders, i * 40 + 16);
byte[] section = new byte [length];
stream.Position = start;
stream.Read (section, 0, length);
if ((start <= info.SignaturePosition) && (info.SignaturePosition < start + length)) {
// hash before the signature
int before = (int)(info.SignaturePosition - start);
if (before > 0) {
cs.Write (section, 0, before);
}
// copy signature
info.Signature = new byte [info.SignatureLength];
Buffer.BlockCopy (section, before, info.Signature, 0, (int)info.SignatureLength);
Array.Reverse (info.Signature);
// hash after the signature
int s = (int)(before + info.SignatureLength);
int after = (int)(length - s);
if (after > 0) {
cs.Write (section, s, after);
}
}
else
cs.Write (section, 0, length);
}
cs.Close ();
info.Hash = hash.Hash;
return info;
}