Last active
June 4, 2022 18:45
-
-
Save richlander/52423b87b60d39d8b464 to your computer and use it in GitHub Desktop.
.NET Cryptography Updates for the .NET Framework 4.6
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Example 1: Signing a byte[] using PKCS#1 v1.5 padding and a SHA-256 hash | |
// 4.5: | |
public static byte[] SignDataPkcs1Sha256(X509Certificate2 cert, byte[] data) | |
{ | |
// X509Certificate2.PrivateKey returns the same object across multiple calls, | |
// so it shouldn't be Disposed independent of the X509Certificate2 object. | |
// | |
// The RSA base class doesn't expose any signature-based methods. | |
// The PrivateKey property returns AsymmetricAlgorithm, so really this call should be | |
// done via 'as', or another safe flow... but it's almost always seen as an explicit cast | |
RSACryptoServiceProvider rsaCsp = (RSACryptoServiceProvider)cert.PrivateKey; | |
// SignData's second parameter is of type object. This leads to bad discoverability, | |
// and debate about what the 'right' answer should be. | |
return rsaCsp.SignData(data, "SHA256"); | |
} | |
// 4.6: | |
public static byte[] SignDataPkcs1Sha256(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()) | |
{ | |
// RSA now exposes SignData, and the hash algorithm parameter takes a strong type, | |
// which allows for IntelliSense hints. | |
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); | |
} | |
} | |
// Example 2: Signing a byte[] using PSS padding and a SHA-256 hash. | |
// 4.5: Not possible | |
// 4.6: | |
public static byte[] SignDataPssSha256(X509Certificate2 cert, byte[] data) | |
{ | |
using (RSA rsa = cert.GetRSAPrivateKey()) | |
{ | |
// RSA's SignData method exposes the signature padding type. | |
// Pkcs1 was the only padding that .NET 4.5 could do. | |
// | |
// This value must match on both Sign and Verify, so application developers | |
// are cautioned to consider their support matrix before upgrading from | |
// Pkcs1 (PKCS#1 v1.5) to Pss (PKCS#1 v2.1, Probabilistic Signature Scheme) | |
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pss); | |
} | |
} | |
// Example 3: Encrypting a byte[] using OAEP(-SHA1) | |
// 4.5: | |
public static byte[] EncryptDataOaepSha1(X509Certificate2 cert, byte[] data) | |
{ | |
// X509Certificate2.PublicKey.Key returns the same object across multiple calls, | |
// so it shouldn't be Disposed independent of the X509Certificate2 object. | |
// | |
// The RSA base class has 'EncryptValue', but it just throws, so casting to | |
// RSACryptoServiceProvider is required. | |
// | |
// The PublicKey.Key property returns AsymmetricAlgorithm, so really this call should be | |
// done via 'as', or another safe flow... but it's almost always seen as an explicit cast | |
RSACryptoServiceProvider rsaCsp = (RSACryptoServiceProvider)cert.PublicKey.Key; | |
// RSACryptoServiceProvider.Encrypt's second parameter is a bool. While the documentation | |
// does say what it does, it doesn't tell someone familiar with the concepts (but not the | |
// particular implementation) what's going on. | |
return rsaCsp.Encrypt(data, true); | |
} | |
// 4.6: | |
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 formerly just "OAEP" is | |
// now OAEP-SHA1. | |
return rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA1); | |
} | |
} | |
// Example 4: Encrypting a byte[] using OAEP-SHA256 | |
// 4.5: Not possible | |
// 4.6: | |
public static byte[] EncryptDataOaepSha256(X509Certificate2 cert, byte[] data) | |
{ | |
using (RSA rsa = cert.GetRSAPublicKey()) | |
{ | |
return rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA256); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment