[英]Import Public RSA Key From Certificate
我们的客户将其公共RSA密钥存储在证书中。
我们需要在WinRT应用程序中对此密钥进行硬编码,以便我们可以对客户端进行加密。 但是,将密钥导入CryptographicKey类的实例时遇到了问题。
我们在RSAProvider上使用ImportPublicKey:
rsaProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
key = rsaProvider.ImportPublicKey(publicKeyBuffer);
我们尝试将一些内容加载到publicKeyBuffer中:证书,即从证书导出的公钥,格式多种。
我们如何加载他们的公钥?
我在MSDN论坛中发现这篇文章非常有帮助。 卡洛斯·洛佩兹(Carlos Lopez)发布了一些代码,以从Base64编码的证书中获取公钥。
这里的代码:
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;
}
两件事情:
对于那些如何使用WinRT应用程序中存储在证书中的公共密钥的人,让我减轻痛苦:您不能,至少不能直接这样做。
AsymmetricKeyAlgorithmProvider.ImportPublicKey
函数采用IBuffer和CryptographicPublicKeyBlobType,keyBlob(IBuffer)参数是证书的公钥,而不是完整证书,仅是其公钥。
但是您不能不先解析就获得证书的公钥,这是问题所在,没有办法在WinRT上解析证书,因为该任务最常用的类X509Certificate不是可用,其名称空间也不可用,并且证书的功能仅在Web服务连接上使用。
解决此问题的唯一方法是实现证书解析器,或从诸如Bouncy Castle的开源项目中移植此类功能。 因此,如果您知道一个,请在评论中保留它。
顺便说一句,要以可在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类为此目的提供了更多方法)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.