问题
I am trying to load the Private and Public keys from a PEM file using .Net Core. My code looks like this:
var localPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
var path = Path.Combine(localPath, this._configManager.JwtPem);
var rsaCryptoServiceProvider = new RSACryptoServiceProvider();
var linesList = File.ReadAllLines(path).ToList();
var line = string.Concat(linesList.GetRange(1, linesList.Count - 2));
rsaCryptoServiceProvider.ImportCspBlob(Convert.FromBase64String(line));
The exception I am getting is:
Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException : Bad Version of provider
at Internal.NativeCrypto.CapiHelper.ImportKeyBlob(SafeProvHandle saveProvHandle, CspProviderFlags flags, Boolean addNoSaltFlag, Byte[] keyBlob, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.ImportCspBlob(Byte[] keyBlob)
at StepNexusCA.ServiceLayer.Authorization.TokenService.GenerateToken(List`1 claims)
The PEM file containing the PKCS1 format of my development Private/Public keys is here:
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAwgs8kmIwk+4geRO7dGZjzYpgD2OiaUrnOOIk+ObXt/CcjhwX
lSst+jBmfMF1Wp/mF4aUQsePxN59MYV2BsqPLEkzVdq/fb/7V2wbZcooJAQKkJwT
emtYHrBN00KBBeu9uQZlFOw365ij4GrbP7mcr4tNFZ3TPnRFUUFqhvB6mEG1aZsb
lOn1lgL34tAycQHNxttXz/aGfPyTefQ+yISvSY2n8288OVlyfu6wKDONQYS+/stC
tCV+a+/dDUSUjaZsXM1+BMSflsINqIcCTCMvPa6fb5Z+USfPDcDNwzUyX20LBzH5
wFwPLIvuoqJeeczcaHaT+dS2ZZREj6kgUsdC+QIBAwKCAQEAgVzTDEF1t/QVpg0n
ou7tM7GVX5fBm4dE0JbDUJnlJUsTCWgPuMdz/CBEUyujkb/uulm4LIUKgz7+IQOk
BIcKHYYiOTx/qSqnj51nmTFwGAKxtb1iUZzlacrejNcArp0pJgRDY0glR7sX6vHn
f9ETH7IzY76M1E2Di4Dxr0r8ZX/3ozsrSXp+GMJLeN9sCjKSyxoE5Y71eDBTCX2N
tShJJjhqUDz61bhKlX9j5c3jWvTXx46dE8wjoJ/BW1XJo5J1gzHQ/OLYeOXIdxlj
jVSlEuU69UT588B7UEEK9N9xK5K/c0Yw5gd02RUv/o7qdpYQICeGtQMMaFkm75xy
nUOxwwKBgQD/orUvgNJfFKyvGY8XJTuek5q8IcFD8AFO3b7pNnPynw8llyEpACAv
Onf9aJSPZvtrabSqrpO8k8Ijyhe2Ino39GuRV8RURl46GmFN31RoYV1wHI4K7Emh
68cdKbCEBudog+kImImldBAfo+QmBtqhS+u4B5qQwwnFa8DriQoiYwKBgQDCUg0r
Jd/ZXDLXk/H5PHpTApmUVd7SWLLIDfkBAlRO8Sni4/Ka+KTTZDec5uoo0hoP6cCs
Z9+MZz4XOiwv9dCEI5czMawGmwsm23+fGM/PP/lW4yD8dz10KZggKjWElymDVl+n
zsc6ctwHAOfYwREi7E+R4rWTBgTEvH2I3deV8wKBgQCqbHjKVeGUuHMfZl9kw30U
YmcoFoDX9VY0k9SbeaKhv19uZMDGABV00aVTmw2071JHm83HHw0oYoFtMWUkFvwl
TZ0Lj9g4Lul8EZYz6jhFlj5KvbQHSDEWnS9oxnWtWe+bAptbEFvDorVqbULEBJHA
3UfQBRG111vY8oCdBgbBlwKBgQCBjAjHbpU7ksyPt/amKFGMrGZi4+nhkHcwCVCr
VuLfS3FB7UxnUG3iQs+970bF4Wa1RoBy7+pdmilk0XLKo+BYF7oiIR1ZvLIZ56pq
EIqKKqY57MCoT35NcRAVcXkDD3ECOZUaidom9z1aAJqQgLYXSDUL7HkMrq3YfakF
6Tpj9wKBgEPCSW7EMFjK2NzmB+4b+skxXcfCZ0ldNtwoUDijuAMFg8ueC3j2qFUX
bAXSApi3mQMow1/JwQxiZ+b+GDLdTcE/PrBVBRkL/5RkmnVagbjBrdZhVjpC+dUo
eEkCChClGGpRyPJ+DYYRyX1Fk9Und8Xbd49Vv+/6RL76ys3gGQl8
-----END RSA PRIVATE KEY-----
Why can't I import the key using ImportCspBlob(...)? I have not found much info online regarding the exception but where is my code wrong? I am aware of BouncyCastle but I am trying to do this natively using .Net Core.
回答1:
The format for ImportCspBlob is the format from ExportCspBlob, which is the PRIVATEKEY blob format required by CryptImportKey. Since .NET just transparently passes that on to Windows CAPI, the ImportCspBlob method throws on non-Windows platforms.
Another answer that I've given in the past for importing private keys (including PKCS#1 RSAPrivateKey) is a bit of a meta-answer, which includes links to just get things working: Digital signature in c# without using BouncyCastle.
.NET Core 3.0's daily builds have the functionality built-in. Mostly. The PEM format is easy in practice, but somewhat annoying in the spec, so the methods leave it up to the caller to "un-PEM" the data... for the default formatting on a single-value payload with no attributes (like you have in your example) you can do it with daily builds via
private static RSA ReadKeyFromFile(string filename)
{
string pemContents = System.IO.File.ReadAllText(filename);
const string RsaPrivateKeyHeader = "-----BEGIN RSA PRIVATE KEY-----";
const string RsaPrivateKeyFooter = "-----END RSA PRIVATE KEY-----";
if (pemContents.StartsWith(RsaPrivateKeyHeader))
{
int endIdx = pemContents.IndexOf(
RsaPrivateKeyFooter,
RsaPrivateKeyHeader.Length,
StringComparison.Ordinal);
string base64 = pemContents.Substring(
RsaPrivateKeyHeader.Length,
endIdx - RsaPrivateKeyHeader.Length);
byte[] der = Convert.FromBase64String(base64);
RSA rsa = RSA.Create();
rsa.ImportRSAPrivateKey(der, out _);
return rsa;
}
// "BEGIN PRIVATE KEY" (ImportPkcs8PrivateKey),
// "BEGIN ENCRYPTED PRIVATE KEY" (ImportEncryptedPkcs8PrivateKey),
// "BEGIN PUBLIC KEY" (ImportSubjectPublicKeyInfo),
// "BEGIN RSA PUBLIC KEY" (ImportRSAPublicKey)
// could any/all be handled here.
throw new InvalidOperationException();
}
Daily builds of the .NET Core SDK can be obtained from https://github.com/dotnet/core-sdk/#installers-and-binaries
回答2:
If you don't need to convert from PEM to DER in the code, you can use openssl to get the DER encoded private key file:
openssl rsa -in key.pem -out key.der -outform der
回答3:
The .Net Cryptographic API does not support the industry widely used PEM files so we need to convert it to the XML format, introduced by Microsoft. Basically, the solution was found in another similar question here C# Extract public key from RSA PEM private key.
回答4:
There are a lot of Convert PEM to XML online tools, just convert your pem to xml, then
RSA.FromXmlString(string xmlString)
来源:https://stackoverflow.com/questions/53434030/how-to-import-pkcs1-keys-from-a-pem-file-containing-private-public-keys-in-ne