RSAProvider.ImportParameters()=>某些特殊rsa私钥的错误数据

时间:2014-10-24 15:25:18

标签: c# .net rsa

我们有一个C#/ .Net 4.0应用程序,它将RSA私钥从PEM文件导入RSACryptoServiceProvider。

此应用程序适用于从512到4096位的RSA-Keys,但没有使用特殊类型的rsa私钥。

您可以在此处找到两个示例键:test keys

OpenSSL-Command:openssl genrsa -out PRIVATE.KEY 2048

主要区别在于选择两个素数(p和q)。而不是两者都是用1024位生成的,它们在非工作密钥中是1023和1025位。 根据RSA规范,这应该没问题。

但是在ImportParameters()上,我们总是得到一个带有“错误数据”的加密 - 例外。任何想法如何获取更多信息,为什么私钥数据被拒绝或如何获得更多信息? 我们搜索了信息,如果微软对rsa密钥有要求,但找不到 任何有用的规格。

两个密钥都可以被OpenSSL以及使用这些私钥进行测试的各种智能卡使用。

以下是字节长度:

工作密钥:

  • 模数=> 256字节
  • 指数=> 3字节
  • D => 256字节
  • P => 128字节(1024位)
  • Q => 128字节(1024位)
  • DP => 128字节
  • DQ => 128字节
  • IQ => 128字节

不-工作密钥:

  • 模数=> 256字节
  • 指数=> 3字节
  • D => 256字节
  • P => 129字节(1025位)
  • Q => 128字节(1023位)
  • DP => 129字节
  • DQ => 128字节
  • IQ => 128字节

还试图用BouncyCastle解析PEM文件并从中导出RsaParameters, 但他们也被“糟糕的数据”拒绝了。 (而使用BouncyCastle不是一个选项btw。:()

提前致谢!

3 个答案:

答案 0 :(得分:1)

以防万一其他人遇到同样的问题。 MSDN-Mod给了我一个与微软认为RSA-Keys应该是什么样的信息的链接。

2.2.2.9.1 RSA Private Key BLOB

对于2048位RSA密钥,P和Q预计每个都是128字节...

答案 1 :(得分:0)

我有类似的问题。多亏了你,我注意到一些缓冲区有一个超出预期的额外字节。所有这些都具有0作为第一个字节,并且值> = 128作为第二个字节。在解析密钥时剥离0前缀解决了我的问题。

答案 2 :(得分:0)

如果你使用BouncyCastle做这项工作会更好。下面,一些代码使用Rsa传递publicKey加密和privateKey来解密。两个密钥也是使用BouncyCastle生成的,如您所见:

class Program
{
    private static string _csr;
    private static string _publicKey;
    private static string _privateKey;

    static void Main(string[] args)
    {
        GeneratePkcs10("braspag.com.br", "braspag", "BR", RootLenght.RootLength2048);
        CryptDecryptTest();

        Console.ReadKey();
    }

    private static void GeneratePkcs10
        (string domainName, string companyName, string countryIso2Characters, RootLenght rootLength)
    {
        try
        {
            var rsaKeyPairGenerator = new RsaKeyPairGenerator();
            var secureRandom = new SecureRandom();

            // Note: the numbers {3, 5, 17, 257 or 65537} as Fermat primes.
            // NIST doesn't allow a public exponent smaller than 65537, since smaller exponents are a problem if they aren't properly padded.
            // Note: the default in openssl is '65537', i.e. 0x10001.
            var genParam = new RsaKeyGenerationParameters
                (BigInteger.ValueOf(0x10001), secureRandom, (int)rootLength, 128);

            rsaKeyPairGenerator.Init(genParam);

            AsymmetricCipherKeyPair pair = rsaKeyPairGenerator.GenerateKeyPair();

            IDictionary attrs = new Hashtable();

            attrs.Add(X509Name.CN, domainName);
            attrs.Add(X509Name.O, companyName);
            attrs.Add(X509Name.C, countryIso2Characters);

            var subject = new X509Name(new ArrayList(attrs.Keys), attrs);

            var textWriter = new StringWriter(CultureInfo.InvariantCulture);
            var pemWriter = new PemWriter(textWriter);
            pemWriter.WriteObject(pair.Private);
            pemWriter.Writer.Flush();
            _privateKey = textWriter.ToString();
            textWriter.Close();

            textWriter = new StringWriter(CultureInfo.InvariantCulture);
            pemWriter = new PemWriter(textWriter);
            pemWriter.WriteObject(pair.Public);
            pemWriter.Writer.Flush();

            _publicKey = textWriter.ToString();
            textWriter.Close();

            ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHRSA", pair.Private, secureRandom);

            var pkcs10CertificationRequest = new Pkcs10CertificationRequest
                (signatureFactory, subject, pair.Public, null, pair.Private);
            _csr = Convert.ToBase64String(pkcs10CertificationRequest.GetEncoded());
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    private static void CryptDecryptTest()
    {
        const string originalText = "test";

        var encryptedText = RsaEncryptWithPublic(originalText, _publicKey);

        var decryptedText = RsaDecryptWithPrivate(encryptedText, _privateKey);

        Console.WriteLine(string.Format("Original Text: {0}", originalText));
        Console.WriteLine(string.Format("Encrypted Text: {0}", encryptedText));
        Console.WriteLine(string.Format("Decrypted Text: {0}", decryptedText));
    }

    public static string RsaEncryptWithPublic(string clearText, string publicKey)
    {
        var bytesToEncrypt = Encoding.UTF8.GetBytes(clearText);

        var encryptEngine = new Pkcs1Encoding(new RsaEngine());

        using (var txtreader = new StringReader(publicKey))
        {
            var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();

            encryptEngine.Init(true, keyParameter);
        }

        var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length));
        return encrypted;

    }

    public static string RsaDecryptWithPrivate(string base64Input, string privateKey)
    {
        var bytesToDecrypt = Convert.FromBase64String(base64Input);

        AsymmetricCipherKeyPair keyPair;
        var decryptEngine = new Pkcs1Encoding(new RsaEngine());

        using (var txtreader = new StringReader(privateKey))
        {
            keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();

            decryptEngine.Init(false, keyPair.Private);
        }

        var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
         return decrypted;
}


    private enum RootLenght
    {

        RootLength2048 = 2048,

        RootLength3072 = 3072,

        RootLength4096 = 4096,

    }
}