Encrypt / Decrypt in C# using Certificate

Ilya picture Ilya · Jan 11, 2017 · Viewed 34k times · Source

I'm having trouble finding a good example in encrypting / decrypting strings in C# using a certificate. I was able to find and implement an example of signing and validating a signature, as shown below. Could someone point me to an easy, similar example for encryption?

private static string Sign(RSACryptoServiceProvider privateKey, string content)
{
    SHA1Managed sha1 = new SHA1Managed();
    UnicodeEncoding  encoding = new UnicodeEncoding ();
    byte[] data = encoding.GetBytes(content);
    byte[] hash = sha1.ComputeHash(data);

    // Sign the hash
    var signature = privateKey.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
    return Convert.ToBase64String(signature);
}

public static bool Verify(RSACryptoServiceProvider publicKey, string content, string hashString)
{
    SHA1Managed sha1 = new SHA1Managed();
    UnicodeEncoding  encoding = new UnicodeEncoding ();
    byte[] data = encoding.GetBytes(content);
    byte[] hash = sha1.ComputeHash(data);
    return publicKey.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), Convert.FromBase64String(hashString));
}

Answer

bartonjs picture bartonjs · Jan 11, 2017

Per the .NET Framework team's guidance (have to search for "Cryptography Updates", there doesn't seem to be an anchor nearby -- or, just look at the code samples).

public static byte[] EncryptDataOaepSha1(X509Certificate2 cert, byte[] data)
{
    // GetRSAPublicKey returns an object with an independent lifetime, so it should be
    // handled via a using statement.
    using (RSA rsa = cert.GetRSAPublicKey())
    {
        // OAEP allows for multiple hashing algorithms, what was formermly just "OAEP" is
        // now OAEP-SHA1.
        return rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA1);
    }
}

Decrypt would thus be

public static byte[] DecryptDataOaepSha1(X509Certificate2 cert, byte[] data)
{
    // GetRSAPrivateKey returns an object with an independent lifetime, so it should be
    // handled via a using statement.
    using (RSA rsa = cert.GetRSAPrivateKey())
    {
        return rsa.Decrypt(data, RSAEncryptionPadding.OaepSHA1);
    }
}

Caveats:

  • RSA.Encrypt(byte[], RSAEncryptionPadding) was added in .NET Framework 4.6 (and .NET Core 1.0 / .NET Standard 1.3), so make sure you are building a project with a high enough target version.
  • RSA encryption is mainly used to encrypt symmetric keys, not actual data payloads, because it is expensive and has a size limit (always lower than the keysize (in bytes), the different padding modes consume different amounts of available space).
  • While the RSA base class talks about OaepSHA256 (etc) only Pkcs1 and OaepSHA1 are supported by all providers in .NET Core. (OaepSHA256+ is limited to RSACng)