从证书导入公共RSA密钥

我们的客户将其公共RSA密钥存储在证书中。

我们需要在WinRT应用程序中对此密钥进行硬编码,因此我们可以加密客户端。 但是,我们在将密钥导入CryptographicKey类的实例时遇到问题。

我们在RSAProvider上使用ImportPublicKey:

rsaProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1); key = rsaProvider.ImportPublicKey(publicKeyBuffer); 

我们已经尝试将几个东西加载到publicKeyBuffer中:证书,从证书中以多种格式导出的公钥。

我们如何加载他们的公钥?

我在MSDN论坛上发现这篇文章非常有帮助。 Carlos Lopez发布了一些代码,用于从Base64编码证书中获取公钥。

http://social.msdn.microsoft.com/Forums/en-US/17e1467a-2de7-47d2-8d8c-130518eaac68/how-to-use-a-x509-certificate-not-a-pfx-to-verify-一个签名

这里的代码:

 public static CryptographicKey GetCryptographicPublicKeyFromCert(string strCert) { int length; CryptographicKey CryptKey = null; byte[] bCert = Convert.FromBase64String(strCert); // Assume Cert contains RSA public key // Find matching OID in the certificate and return public key byte[] rsaOID = EncodeOID("1.2.840.113549.1.1.1"); int index = FindX509PubKeyIndex(bCert, rsaOID, out length); // Found X509PublicKey in certificate so copy it. if (index > -1) { byte[] X509PublicKey = new byte[length]; Array.Copy(bCert, index, X509PublicKey, 0, length); AsymmetricKeyAlgorithmProvider AlgProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1); CryptKey = AlgProvider.ImportPublicKey(CryptographicBuffer.CreateFromByteArray(X509PublicKey)); } return CryptKey; } static int FindX509PubKeyIndex(byte[] Reference, byte[] value, out int length) { int index = -1; bool found; length = 0; for (int n = 0; n < Reference.Length; n++) { if ((Reference[n] == value[0]) && (n + value.Length < Reference.Length)) { index = n; found = true; for (int m = 1; m < value.Length; m++) { if (Reference[n + m] != value[m]) { found = false; break; } } if (found) break; else index = -1; } } if (index > -1) { // Find outer Sequence while (index > 0 && Reference[index] != 0x30) index--; index--; while (index > 0 && Reference[index] != 0x30) index--; } if (index > -1) { // Find the length of encoded Public Key if ((Reference[index + 1] & 0x80) == 0x80) { int numBytes = Reference[index + 1] & 0x7F; for (int m = 0; m < numBytes; m++) { length += (Reference[index + 2 + m] << ((numBytes - 1 - m) * 8)); } length += 4; } else { length = Reference[index + 1] + 2; } } return index; } static public byte[] EncodeOID(string szOID) { int[] OIDNums; byte[] pbEncodedTemp = new byte[64]; byte[] pbEncoded = null; int n, index, num, count; OIDNums = ParseOID(szOID); pbEncodedTemp[0] = 6; pbEncodedTemp[2] = Convert.ToByte(OIDNums[0] * 40 + OIDNums[1]); count = 1; for (n = 2, index = 3; n < OIDNums.Length; n++) { num = OIDNums[n]; if (num >= 16384) { pbEncodedTemp[index++] = Convert.ToByte(num / 16384 | 0x80); num = num % 16384; count++; } if (num >= 128) { pbEncodedTemp[index++] = Convert.ToByte(num / 128 | 0x80); num = num % 128; count++; } pbEncodedTemp[index++] = Convert.ToByte(num); count++; } pbEncodedTemp[1] = Convert.ToByte(count); pbEncoded = new byte[count + 2]; Array.Copy(pbEncodedTemp, 0, pbEncoded, 0, count + 2); return pbEncoded; } static public int[] ParseOID(string szOID) { int nlast, n = 0; bool fFinished = false; int count = 0; int[] dwNums = null; do { nlast = n; n = szOID.IndexOf(".", nlast); if (n == -1) fFinished = true; count++; n++; } while (fFinished == false); dwNums = new int[count]; count = 0; fFinished = false; do { nlast = n; n = szOID.IndexOf(".", nlast); if (n != -1) { dwNums[count] = Convert.ToInt32(szOID.Substring(nlast, n - nlast), 10); } else { fFinished = true; dwNums[count] = Convert.ToInt32(szOID.Substring(nlast, szOID.Length - nlast), 10); } n++; count++; } while (fFinished == false); return dwNums; } 

两件事情:

  1. ImportPublicKey键的参数是IBuffer。 最简单的方法是使用ToBuffer扩展方法获取byte []。
  2. 使用ImportPublicKey的覆盖,它接受IBuffer和CryptographicPublicKeyBlobType ,特别是CryptographicPublicKeyBlobType.X509SubjectPublicKeyInfo。 从证书中传入主题公钥信息字段。

对于那些如何使用存储在WinRT应用程序中的证书中的公钥的人来说,让我减轻你的痛苦:你不能,至少不能直接。

AsymmetricKeyAlgorithmProvider.ImportPublicKey函数采用IBuffer和CryptographicPublicKeyBlobType,keyBlob(IBuffer)参数是证书的公钥,而不是完整证书,只有公钥。

但是你无法获得证书的公钥而不首先解析它,这里是问题所在,没有办法在WinRT上解析证书,因为这个任务最常用的类X509Certificate不是可用,也不是它的名称空间,并且证书的工具仅用于Web服务连接。

解决此问题的唯一方法是实现证书解析器,或从开源项目(如Bouncy Castle)移植此类function。 所以,如果你知道一个,请留在评论中。

顺便说一下,要以可以在WinRT应用程序中使用的格式从证书(在.NET中)导出公钥,请使用:

 X509Certificate2 Certificate; .... byte[] CertificatePublicKey = Certificate.PublicKey.EncodedKeyValue.RawData; 

然后在WinRT应用程序中使用此:

 AsymmetricKeyAlgorithmProvider algorithm = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaSignPkcs1Sha1); IBuffer KeyBuffer = CryptographicBuffer.DecodeFromBase64String(CertificatePublicKeyContent); CryptographicKey key = algorithm.ImportPublicKey(KeyBuffer, CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey); 

请注意,我首先在base 64中编码公钥,但您可以使用原始二进制数据(CryptographicBuffer类有更多方法用于此目的)。