What is a 'public key token' and how is it calculated in assembly strong names?
What is a public key token and how is it calculated in assembly strong names?
25.5k views Asked by Praveen Sharma AtThere are 7 answers
A public key token is used to identify the organization in a strongly named assembly. This information is added to the assembly metabase. I would assume Richard is correct about the technical way it is stored.
If you want to view the metabase of an assembly, use ILDASM. You can drill down into what is stored in the metabase in addition to seeing the IL.
From ECMA-335:
This declaration is used to store the low 8 bytes of the SHA-1 hash of the originator’s public key in the assembly reference, rather than the full public key.
An assembly reference can store either a full public key or an 8-byte “public key token.” Either can be used to validate that the same private key used to sign the assembly at compile time also signed the assembly used at runtime. Neither is required to be present, and while both can be stored, this is not useful.[Rationale: The public key or public key token stored in an assembly reference is used to ensure that the assembly being referenced and the assembly actually used at runtime were produced by an entity in possession of the same private key, and can therefore be assumed to have been intended for the same purpose. While the full public key is cryptographically safer, it requires more storage in the reference. The use of the public key token reduces the space required to store the reference while only weakening the validation process slightly. end rationale]
As for how the hash is calculated (I assume this may be what you're asking since the public key token is not "calculated"), from the same spec:
The CLI metadata allows the producer of an assembly to compute a cryptographic hash of that assembly (using the SHA-1 hash function) and then to encrypt it using the RSA algorithm (see Partition I) and a public/private key pair of the producer’s choosing. The results of this (an “SHA-1/RSA digital signature”) can then be stored in the metadata (§25.3.3) along with the public part of the key pair required by the RSA algorithm. The .publickey directive is used to specify the public key that was used to compute the signature. To calculate the hash, the signature is zeroed, the hash calculated, and then the result is stored into the signature.
The Strong Name (SN) signing process uses standard hash and cipher algorithms for Strong name signing. An SHA-1 hash over most of the PE file is generated. That hash value is RSA-signed with the SN private key. For verification purposes the public key is stored into the PE file as well as the signed hash value.
Except for the following, all portions of the PE File are hashed: • The Authenticode Signature entry: PE files can be authenticode signed. The authenticode signature is contained in the 8-byte entry at offset 128 of the PE Header Data Directory (“Certificate Table” in §25.2.3.3) and the contents of the PE File in the range specified by this directory entry. [Note: In a conforming PE File, this entry shall be zero. end note] • The Strong Name Blob: The 8-byte entry at offset 32 of the CLI Header (“StrongNameSignature” in §25.3.3) and the contents of the hash data contained at this RVA in the PE File. If the 8-byte entry is 0, there is no associated strong name signature. • The PE Header Checksum: The 4-byte entry at offset 64 of the PE Header Windows NT-Specific Fields (“File Checksum” in §25.2.3.2). [Note: In a conforming PE File, this entry shall be zero. end note]
You can download the spec here for free: http://www.ecma-international.org/publications/standards/Ecma-335.htm
If you need to generate a public key token based on a full public key, this little static method works:
private static byte[] GetKeyTokenFromFullKey(byte[] fullKey)
{
SHA1CryptoServiceProvider csp = new SHA1CryptoServiceProvider();
byte[] hash = csp.ComputeHash(fullKey);
byte[] token = new byte[8];
for (int i = 0; i < 8; i++ )
token[i] = hash[hash.Length - (i+1)];
return token;
}
Regarding your question, "How is it calculated", it's an SHA1 hash.
From dot net blog: