Brief Introduction of Strong Name Signatures
Strong name signatures consist of the identities of an assembly. They are strengthened by both public keys and digital signatures (as generated from the assembly). The identities include the plain text name, version number and regional information of the assembly (if provided). An assembly with a strong name can only refer to other assemblies which also have strong names. Note, two assemblies with the same strong name should be identical. We can guarantee the name’s global uniqueness through the signing and issuing of the assembly with a strong name.
In particular, strong names satisfy the following requirements:
- Strong names guarantee name uniqueness by relying on unique key pairs. No one can generate the same assembly name as you. This is because an assembly generated with one private key has a different name than an assembly generated with another private key.
- Strong names protect the version lineage of an assembly. A strong name can ensure that no one can produce a subsequent version of your assembly. Users can be assured that a version of an assembly they load comes from the same publisher that created the original version of the application.
- Strong names provide a strong integrity check. Passing the .NET Framework security checks guarantees that the contents of the assembly have not been altered from the original build. Note, however, that strong names in and of themselves do not imply the same level of trust provided, for example, by a digital signature and supporting certificate.
Through the reflection mechanism, we can easily obtain a signature of .Net assembly. Thus, we can make a new assembly with exactly the same interfaces. However, you would not be able to prove whether or not the assembly was published by you and others will not be able to confirm whether or not the assembly is legal. To solve this problem, one way is to use the strong name signature for the publisher’s assembly. As we mentioned previously, an assembly with a strong name guarantees the name’s global uniqueness.
An assembly name contains four parts: Friendly Name, Culture, PublicKey (Token), and Version. Among these, friendly name and version are essential while, as set in the default situation, Culture=neutral and PublicKey(Token)=null. The assembly with PublicKey is called strong signature assembly. When a data type is being used, the common language runtime (CLR) will analyze and import the corresponding assembly. The assembly must have the same PublicKey(Token) as the one in the reference phase. If this assembly cannot be found, an exception would be thrown. When there is no PublicKey, this process will be skipped.
PublicKey and PublicKey Token
Public key has 32 bytes of header information, while the size of the public key is generally 128 bytes. The corresponding private key is owned by the developer, this is how it can mark its developer uniquely. For convenience, we use the SHA hash algorithm to generate a public key token of only 8 bytes; therefore, we can find the corresponding assembly according to the token.
How to Generate the Strong Name Signature for your Assembly
- Run the Visual Studio command line, generate a public or private key pair file by Sn.exe. Without specifying the file size, its default value is 596 bytes in total: 128 bytes public key, 32 bytes public key header and 436 private key.
- Sign the assembly. There are several methods for doing this:
1) Add content
[assembly: AssemblyKeyFile(@"StrongName.snk")] to the AssemblyInfo.cs file of your project.
2) Add the
/keyfile parameter when you compile the command line:
csc /target:library /keyfile:StrongName.snk /out:Something.dll *.cs.
3) Assign the snk file in the VS project->Property->Signning
- After completing all of the procedures above, your assembly now has a strong name signature. To check whether or not you signed it successfully, input: Sn -v Something.dll to your VS command line; if you got the result: Something.dll is valid, it means that you generated a program with a public key successfully. To get the assembly’s public key token, input command: Sn -T Something.dll.
Delayed Strong Name Signature
However, for some large scale programs, private key is protected whilst the corresponding public key is available, and the public key can be distributed freely. Here rises the problem: how can you make sure the developer uses the strong-name signed assembly (if they designed to put the assembly into GAC)? In other words, how can you obfuscate the code aimed at increasing the difficulty level for decompiling the source code?
This is the reason why Delayed Signature was born.
- Run the VS command line, generate a public/private key pair file. Without specifying the file size, its default value is 596 bytes in total: 128 byte public key, 32 byte public key header, and 436 private key. Use the command: Sn –k StrongName.snk
- Extract the public key: sn -p StrongName.snk public.snk
- Make the delayed signature for the assembly:
1) Add content
[assembly: AssemblyDelaySign(true)]to AssemblyInfo.cs; 2) Add
/delaysignparameters when you compile the command line:
csc /target:library /keyfile:StrongName.snk /delaysign /out:Something.dll *.cs3) Assign the snk file in VS project->Property->Signing, and tick the Delay Sign Only option.
- Make sure the CLR-trusted content of the assembly does not execute the Hash processing: sn -Vr Something.dll (Note: the above naming adds the corresponding items from the registry form, therefore you only need to execute it once for each assembly.
- Other programmers could refer to this assembly as any other assembly with a strong name signature. Meanwhile you can obfuscate the code.
- Make the final signature through the private key: sn -R Something.dll StrongName.snk (Note: we cannot extract the private key alone, since the private key and the public key are in the same file. However, public key can be extracted alone in order to distribute it.
- Open it to verify, the corresponding registry items mentioned in 4) would be removed: sn -Vu MyDll.dll