关于C#:XML签名与随机RSA密钥一起使用,但不与证书中的密钥一起使用

XML Signature works with random RSA Key but not with key from certificate

我正在尝试使用C中的以下算法签署XML文档:

http://www.w3.org/2001/04/xmldsig-more#rsa-sha256

当我尝试用随机RSA密钥签名时,它工作得很好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.PreserveWhitespace = false;
        xmlDoc.Load("hpbtest.xml");
        RSA Key = new RSACryptoServiceProvider(2048);
        // Create a SignedXml object.
        PrefixedSignedXML signedXml = new PrefixedSignedXML(xmlDoc);
        // Add the key to the SignedXml document.
        signedXml.SigningKey = Key;
        signedXml.SignedInfo.SignatureMethod ="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
        // Create a reference to be signed.
        Reference reference = new Reference();
        reference.Uri ="#xpointer(//*[@authenticate='true'])";
        reference.DigestMethod ="http://www.w3.org/2001/04/xmlenc#sha256";
        // Add an enveloped transformation to the reference.
        XmlDsigExcC14NTransform env = new XmlDsigExcC14NTransform();
        env.Algorithm ="http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
        reference.AddTransform(env);
        // Add the reference to the SignedXml object.
        signedXml.AddReference(reference);
        // Compute the signature.
        signedXml.ComputeSignature("ds");
        // Get the XML representation of the signature and save
        // it to an XmlElement object.
        XmlElement xmlDigitalSignature = signedXml.GetXml("ds");
        // Append the element to the XML document.
        xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
        xmlDoc.Save("hpbtest.xml");

但是,如果我想使用OpenSSL生成的证书中的RSA密钥:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.PreserveWhitespace = false;
        xmlDoc.Load("hpbtest.xml");
        RSA Key = new GestionCertificat("CN=Bruno").getClePrivee();//Get the private key
        // Create a SignedXml object.
        PrefixedSignedXML signedXml = new PrefixedSignedXML(xmlDoc);
        // Add the key to the SignedXml document.
        signedXml.SigningKey = Key;
        signedXml.SignedInfo.SignatureMethod ="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
        // Create a reference to be signed.
        Reference reference = new Reference();
        reference.Uri ="#xpointer(//*[@authenticate='true'])";
        reference.DigestMethod ="http://www.w3.org/2001/04/xmlenc#sha256";
        // Add an enveloped transformation to the reference.
        XmlDsigExcC14NTransform env = new XmlDsigExcC14NTransform();
        env.Algorithm ="http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
        reference.AddTransform(env);
        // Add the reference to the SignedXml object.
        signedXml.AddReference(reference);
        // Compute the signature.
        signedXml.ComputeSignature("ds");
        // Get the XML representation of the signature and save
        // it to an XmlElement object.
        XmlElement xmlDigitalSignature = signedXml.GetXml("ds");
        // Append the element to the XML document.
        xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
        xmlDoc.Save("hpbtest.xml");

我得到这个错误:

Invalid specified algorithm

在这两个示例中,我的RSA密钥具有相同的长度(2048),我不知道为什么会出现此错误。

谢谢您!

托马斯


我终于找到了解决问题的办法。如果它能帮助某人:

以前我尝试通过以下方式从证书中获取私钥:

1
RSA Key = new GestionCertificat("CN=EbicsAuth").getClePrivee();//Get the private key

这是我班手势证书的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
String CertificatEncoded;
    String ModulusEncoded;
    String ExponentEncoded;
    RSA Cle;
    RSA ClePrivee;
    X509Certificate2 Certificat;
    public GestionCertificat(String NomCertificat)
    {
        X509Store store = new X509Store(StoreLocation.CurrentUser);
        store.Open(OpenFlags.ReadOnly);
        X509Certificate2Collection certCollection = store.Certificates;
        X509Certificate2 cert = null;
        foreach (X509Certificate2 c in certCollection)
        {
            if (c.Subject == NomCertificat)
            {
                cert = c;
                break;
            }
        }
        store.Close();
        Certificat = cert;
        CertificatEncoded = Convert.ToBase64String(cert.RawData); //Conversion du certificat en base64
        RSACryptoServiceProvider rsaprovider = (RSACryptoServiceProvider)cert.PublicKey.Key;//Récupération de la clé RSA du certificat
        RSAParameters newparams = rsaprovider.ExportParameters(false);//Extractions des paramètres de la clé
        ModulusEncoded = Convert.ToBase64String(newparams.Modulus);//Conversion du Modulus en base64
        ExponentEncoded = Convert.ToBase64String(newparams.Exponent);//Conversion de l'Exponent en base64
        Cle = (RSA)cert.PublicKey.Key;
        ClePrivee = (RSA)cert.PrivateKey;
    }

    public String getCertificatEncoded()
    {
        return this.CertificatEncoded;
    }

    public String getModulusEncoded()
    {
        return this.ModulusEncoded;
    }

    public String getExponentEncoded()
    {
        return this.ExponentEncoded;
    }

    public RSA getClePublique()
    {
        return this.Cle;
    }

    public RSA getClePrivee()
    {
        return this.ClePrivee;
    }

    public X509Certificate2 getCertificat()
    {
        return this.Certificat;
    }

但现在,为了让RSA密钥签署我的XML,我做了以下操作:

1
2
3
4
RSACryptoServiceProvider Key = new RSACryptoServiceProvider();
var gestionCertif = new GestionCertificat("CN=EbicsAuth");
X509Certificate2 Cert = gestionCertif.getCertificat();
Key.FromXmlString(Cert.PrivateKey.ToXmlString(true));

现在签名生效了!