Time for another visit to the managed strong name API; this time lets take a look at public key tokens. If we want to calculate a token, the strong name API provides two functions that we can use. We've already covered the first, StrongNameTokenFromAssemblyEx, which allows you to extract the token from an assembly. The second API, StrongNameTokenFromPublicKey allows you to generate the token from a public key blob. Together these functions are what sn -T and sn -t rely on to do their work.
If you want to see this calculation yourself, its instructive to look at the implementation of StrongNameTokenFromPublicKey, which can be found in the strongname.cpp file in the clr\src\dlls\mscorsn directory. The interesting portion of the function is between lines 858 and 911. You can see we keep a cache of the token of the ECMA key. If we're not trying to get that token, then we simply take the SHA-1 hash of the key. On lines 910 and 911, we grab the low 8 bytes of that hash, reversing them in order to put them in host byte order.
Lets take a closer look at StrongNameTokenFromPublicKey from a client perspective:
As I mentioned above, this function is used to create the strong name token of a public key blob. Notice that it does not work over a key pair, which is why sn -t does not work on a .snk file. If you want to use the -t parameter to sn, you'll need to first use -p to extract the public key out of the key pair, and then run -t on only the public key. The parameters are:
|pbPublicKeyBlob||buffer containing the public key blob|
|cbPublicKeyBlob||number of bytes in pbPublicKeyBlob|
|ppbStrongNameToken||[out] pointer to a buffer where the token will be stored|
|pcbStrongNameToken||[out] size, in bytes, of the token|
Using this method is very easy. Sin ply pass in the public key blob, and it will create and pass back out the token. Once you've finished using the buffer containing the token, you should call StrongNameFreeBuffer to release that memory. As with most of the other strong name APIs, StrongNameTokenFromPublicKey returns true on success and false on error.
Since we'd already wrapped StrongNameTokenFromAssemblyEx, updating the managed StrongName API to be able to implement -T and -t ourselves was rather easy. Most of the work is in the new functions CreateTokenFromAssembly and CreateTokenFromPublicKey in MS.StrongName\Keys.cs. CreateTokenFromAssembly is very similar to ExtractPublicKeyFromAssembly, except that instead of returning the public key blob and throwing away the token, we do the opposite. CreateTokenFromPublicKey simply calls into StrongNameTokenFromPublicKey, and if it succeeds, we copy the token out of the memory allocated by the native StrongName API and into a managed byte array. Then we can free the native buffer and return the managed array.
After implementing those two methods, adding four methods to msn\Commands.cs to implement each of -T, -Tp, -t, and -tp was easy. These methods simply call either CreateTokenFromAssembly or CreateTokenFromPublicKey, and print the results as a hex string. If the extra p was provided, its easy work to simply display the public key at the same time.
- Added DisplayPublicKeyTokenFromAssembly, DisplayPublicKeyTokenWithKeyFromAssembly, DisplayPublicKeyTokenFromFile, and DisplayPublicKeyTokenWithKeyFromFile to implement new commands.
- Added the -t, -tp, -T, and -Tp commands
- added extra resources to support displaying of tokens
- added CreateTokenFromAssembly and CreateTokenFromPublicKey
- added P/Invoke declaration for StrongNameTokenFromPublicKey