用于 Metro 应用程序的 RSA 加密

4

我有公钥模数和公钥指数,需要在Metro样式应用程序中生成公钥并加密数据。 在C#中,我们有RSAParameters类,但我找不到任何适用于Metro样式应用程序的类似内容。

当我直接使用从证书接收的Base64编码的公钥,并尝试使用以下代码导入该密钥时,会抛出异常ASN1 bad tag value met,我认为这是由于数据格式无效造成的。

     //sample dummy key from certificate in base64encoded
     string key =   @"MIIB0zCCAX2gAwIBAgIJAMF/bHcA799IMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTIwMzI3MTEyNjQ5WhcNMTMwMzI3MTEyNjQ5WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMEPeWjP4sdqxvBlDId4BtRRTeWPwjlZLSOFvOVgmoSyoPva8psFUF6tH9/vPXIJrL80tdCoBt8YFH6pwDN9a1sCAwEAAaNQME4wHQYDVR0OBBYEFGARqQfUhX7atVU4sS+aQAPt/jFxMB8GA1UdIwQYMBaAFGARqQfUhX7atVU4sS+aQAPt/jFxMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADQQALqOyjovRbWUZvziVaE8QYy83WEln1l+HJU9D6tFncUZTlwSd8aUwyQsd3zOVNZ41oCAVv5R3h1jtBtPbM+c1K";
       symmetricKeyAlgorithmProvider asymmAlg = AsymmetricKeyAlgorithmProvider.OpenAlgorithm("RSA_OAEP_SHA1");
       CryptographicKey publicKey = asymmAlg.ImportPublicKey(CryptographicBuffer.DecodeFromBase64String(key));
        string input64string ="encrypt this";
        IBuffer dataToEncrypt = CryptographicBuffer.DecodeFromBase64String(input64string);
        IBuffer encryptedData = CryptographicEngine.Encrypt(publicKey, dataToEncrypt, null);

我也在尝试实现这个,但是还没有找到正确的结构替换方法。 - bl4kh4k
你可能想看一下我在这个问题上的回答:http://stackoverflow.com/questions/12459390/import-public-rsa-key-from-certificate - Rafael
2个回答

2

您的key是公钥的模数部分,长度为128。考虑从C#代码中导出的标准密钥:

using System.Runtime.InteropServices.WindowsRuntime;
CryptographicKey standardKeyPair = provider.CreateKeyPair(1024);
byte[] standardKey = standardKeyPair.ExportPublicKey(CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey).ToArray();

你可以看到 byte[] 标准密钥的长度为 140,其中有 7 位前缀和 5 位尾部。我不知道原因,但我将额外的 12 位复制到已知的密钥中,它可以正常工作。希望这可以帮助你:

public static IBuffer RsaEncrypt(this IBuffer dataToEncrypt, string publicKeyN)
{
    AsymmetricKeyAlgorithmProvider provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);

    CryptographicKey standardKeyPair = provider.CreateKeyPair(1024);
    byte[] standardKey = standardKeyPair.ExportPublicKey(CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey).ToArray();
    var data_n = CryptographicBuffer.DecodeFromBase64String(publicKeyN).ToArray();
    Array.Copy(data_n, 0, standardKey, 7, data_n.Length);
    var key = provider.ImportPublicKey(standardKey.AsBuffer(), CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);

    var result = CryptographicEngine.Encrypt(key, dataToEncrypt, null);
    return result;          
}

“额外的位”可能是密钥指数部分。 - Matt Johnson-Pint

0
这应该可以做到你所要求的:
public static IBuffer RsaEncrypt(byte[] modulus, byte[] exponent, IBuffer data)
{
  var rsa = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaOaepSha1);
  var keyBlob = modulus.Concat(exponent).ToArray().AsBuffer();
  var publicKey = rsa.ImportPublicKey(keyBlob, CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);
  return CryptographicEngine.Encrypt(publicKey, data, null);
}

当然,如果您愿意,仍然可以将base64字符串用作输入/输出,但是您已经知道如何做了。 :)
如果您深入到RFC3447的第61页,您会发现公钥格式结构只是模数后跟指数,这就是为什么我将它们连接在一起的原因。

1
公钥格式结构不仅仅是两个值的串联。它使用ASN.1格式,其中包括额外的头部信息。 - Anton
@anton 谢谢,但实际上这是什么意思呢?你能举个例子吗? - Matt Johnson-Pint
这意味着您需要一个ASN.1实现,可以将两个整数序列编码为字节数组:var publicKey = new X509RsaPublicKey(); publicKey.Modulus = new ASN1Integer(modulus); publicKey.Exponent = new ASN1Integer(exponent); rsa.ImportPublicKey(publicKey.GetBytes().AsBuffer(), CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey); - Anton
@Anton - 我在除了Java以外的地方都找不到这些类。你知道这个问题是关于Windows Store(WinRT)应用程序中的C#,还是你知道我不知道的一些命名空间? - Matt Johnson-Pint
那只是伪代码。如果名称恰好与Java中的某些内容匹配,那只是纯属巧合。.NET不包括ASN.1实现,因此您需要自己编写一个。这里有一个关于ASN.1格式的优秀概述:http://luca.ntop.org/Teaching/Appunti/asn1.html - Anton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接