+8  A: 

Authenticode is a issued by a certificate authority. Strong naming works like a self-signed certificate and can be treated as such. It's a standard digital signature algorithm but the problem is, how you can verify the public key of assembly author? If you get it from a trusted channel from the author and you trust the author in that channel, then yes, you can verify it just like a self-signed certificate.

So, to summarize, answer is:

  1. As long as you are sure strong name private key is kept safe by the author and you know author's public key, you can make sure it's not tampered (to the extent you can make sure a digitally signed email is not tampered). By the way, don't get me wrong. The quote is completely true and an attacker can easily resign the assembly or remove the existing signature. However the resulting assembly will have a different digital signature that can be checked against the original (if you have the original public key).
  2. In this case, it's similar to a self-signed certificate, if you can somehow be sure of author's public key, you can verify the authority, however unlike Authenticode which relies on a certificate authority, there is no straightforward (system-defined) way to distribute the public key.
Mehrdad Afshari
But the verification that checks whether the public key is the one you know is valid, has to be made mannualy. Isn't it?
Pablo Marambio
Yeah, we're talking theoretically about this fact. In practice, it's not suggested to use strong name for these purposes. It's a strong *name* after all, not strong *signature*. But theoretically, it's possible and pretty safe way to accomplish what I said, just like GPG signature or so..
Mehrdad Afshari
+1  A: 
Hamish Smith
> Strong naming your assembly does not make it tamper-proof. < I think that is not true when you know (and check) the public key of the original author, because the tampered assembly will have a *different* signature. Trusted MS-Office add-ins written in .NET rely on that fact, btw.
0xA3
Hamish, you *can* use the strong name to verify that an assembly was created by a specific author, because although an attacker can tamper with the assembly, it's impossible for him to re-use the original assembly's strong name.
RoadWarrior
+7  A: 

When you sign an assembly with a strong name based on a private key that you create, this has the following benefits:

  • A strong name guarantees the uniqueness of an assembly's identity by adding a public key token and a digital signature to the assembly.
  • A strong name can be matched to a public key to prove that the assembly comes from the publisher with that public key, and only that publisher.
  • A strong name provides a strong integrity check. Passing the .NET Framework security checks guarantees that the contents of the assembly haven't been changed since it was last built.

Is it possible to use strong-naming to verify an assembly author?

Yes, as discussed above strong-naming can verify the assembly's latest author. But it doesn't verify the original author. If an attacker replaces your assembly's strong name, then all that can be verified is that you weren't the latest author of the assembly. If he removes the strong name, then no author verification can be done at all.

To which extent can a strong-named assembly be verified to avoid tampering?

The following C# code verifies that an attacker hasn't tampered with the public key token that was written to your assembly when you applied the strong name. It doesn't avoid tampering, but it can detect some types of tampering. The method below accepts a byte array containing your public key token, and compares it with the actual token of the assembly. Note that for this technique to be effective, your obfuscator of choice should encrypt the string containing your public key token, and only decrypt it on the fly as it's used. And also be aware that you need to have FullTrust permission for this code to work because it uses reflection underneath the hood.

// Check that public key token matches what's expected.
private static bool IsPublicTokenOkay_Check(byte [] tokenExpected)
{
    // Retrieve token from current assembly
    byte [] tokenCurrent = Assembly.GetExecutingAssembly().GetName().GetPublicKeyToken();

    // Check that lengths match
    if (tokenExpected.Length == tokenCurrent.Length)
    {
        // Check that token contents match
        for (int i = 0; i < tokenCurrent.Length; i++)
            if (tokenExpected[i] != tokenCurrent[i]) 
                return false;
    }
    else
    {
        return false;
    }
    return true;
}

You can also force verification of the strong name signature in case the strong name was removed by an attacker or the strong name check was disabled in the registry. The following code demonstrates a call into a static method of another class called NativeMethods. This is where the verification will be enforced.

// Check that this assembly has a strong name.
private bool IsStrongNameValid_Check()
{
    byte wasVerified = Convert.ToByte(false); 
     byte forceVerification = Convert.ToByte(true);
    string assemblyName = AppDomain.CurrentDomain.BaseDirectory + 
                          AppDomain.CurrentDomain.FriendlyName; 
    return NativeMethods.CheckSignature(assemblyName, 
                                        forceVerification, 
                                        ref wasVerified);
}

The actual signature verification is done using P/Invoke as shown below. The usage of the StrongNameSignatureVerificationEx API is quite convoluted - for a decent explanation, see this blog entry.

// P/Invoke to check various security settings
// Using byte for arguments rather than bool, 
// because bool won't work on 64-bit Windows!
[DllImport("mscoree.dll", CharSet=CharSet.Unicode)]
private static extern bool StrongNameSignatureVerificationEx(string wszFilePath, 
                                                             byte fForceVerification, 
                                                             ref byte pfWasVerified);

// Private constructor because this type has no non-static members
private NativeMethods()
{
}

public static bool CheckSignature(string assemblyName, 
                                  byte forceVerification, 
                                  ref byte wasVerified)
{
    return StrongNameSignatureVerificationEx(assemblyName, 
                                             forceVerification, 
                                             ref wasVerified );
}
RoadWarrior
Thanks! Excelent example. Which kinds of tampering would be overlooked /bypassed by this check?
Pablo Marambio
This code won't detect a situation where the attacker has changed your copy of the public key token to match his own public key. And of course it can't detect tampering where the code itself is prevented from running.
RoadWarrior
@RoadWarrior: Great stuff. I'm going to have to think about this again.
Hamish Smith