C# – How to create a snk from pfx / cer

cnetpfxsnkx509certificate

Microsoft seems to have created a certification jungle, that is hard to understand.

  • Microsoft X.509 certificate (.cer)
  • Personal Information Exchange (.pfx)
  • Assembly Signature Key Attribute (.snk)

    1. Would it be advisable to create an snk file based on pfx or cer?
      (Not sure if its even possible, and if its possible how is it done?)

    2. While an assembly can be signed with a password protected pfx, it
      doesn't seem to be strong named though, unless it is signed with snk
      instead. But the snk has no password protection. Which one is safer
      to use? As I am the only developer in my project, I don't have the
      multi-developer saftey environment issue, but still would like to
      know what is best approach.

Many Thanks,

Best Answer

A little clarification about your mentioned file types:

  • .cer-files are X.509 Certificates
  • .pfx-files are encrypted X.509 Certificates using a password-based symmetric key, also see PKCS #12 (Wikipedia)
  • .snk-files only contain the RSA key (public/private or public only)

It doesn't matter if you sign an assembly using .pfx-files or .snk-files, it will get strong named either way. Storing the RSA key as a encrypted certificate (.pfx) is of course more secure than storing just the unencrypted key (.snk).

You can easily extract the key from those files in code using class System.Security.Cryptography.X509Certificates.X509Certificate2.

To extract key from .pfx:

/// <summary>
/// Converts .pfx file to .snk file.
/// </summary>
/// <param name="pfxData">.pfx file data.</param>
/// <param name="pfxPassword">.pfx file password.</param>
/// <returns>.snk file data.</returns>
public static byte[] Pfx2Snk(byte[] pfxData, string pfxPassword)
{
    // load .pfx
    var cert = new X509Certificate2(pfxData, pfxPassword, X509KeyStorageFlags.Exportable);

    // create .snk
    var privateKey = (RSACryptoServiceProvider)cert.PrivateKey;
    return privateKey.ExportCspBlob(true);
}

Use privateKey.ExportCspBlob(false) to extract public key only! (e.g. for delay-signing of assemblies)