Château gonflable Signer et Vérifier les Certificats SHA256 Avec C#

J'ai été par le biais d'un grand nombre d'exemples de la façon dont les gens utilisent Château Gonflable pour générer dynamiquement des Paires de Clés RSA et ensuite signer et vérifier tous dans un bloc de code. Ces réponses ont été super et m'a vraiment aidé à accélérer rapidement!

Cela dit, j'ai besoin de créer un client qui peut passer par la WCF JSON appelle une clé publique pour être utilisé plus tard pour la vérification de la signature et je n'arrive pas à obtenir que cela fonctionne. D'abord voici le code que j'utilise pour générer le Certificat:

    public System.Security.Cryptography.X509Certificates.X509Certificate2 LoadCertificate()
    {
        System.Security.Cryptography.X509Certificates.X509Certificate2 returnX509 = null;
        //X509Certificate returnCert = null;

        try
        {
            returnX509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(CertificateName, CertificatePassword);
            //returnCert = DotNetUtilities.FromX509Certificate(returnX509);
        }
        catch
        {
            Console.WriteLine("Failed to obtain cert - trying to make one now.");

            try
            {
                Guid nameGuid = Guid.NewGuid();
                AsymmetricCipherKeyPair kp;
                var x509 = GenerateCertificate("CN=Server-CertA-" + nameGuid.ToString(), out kp);
                SaveCertificateToFile(x509, kp, CertificateName, CertificateAlias, CertificatePassword);
                returnX509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(CertificateName, CertificatePassword);
                //returnCert = DotNetUtilities.FromX509Certificate(returnX509);
                Console.WriteLine("Successfully wrote and retrieved cert!");
            }
            catch (Exception exc)
            {
                Console.WriteLine("Failed to create cert - exception was: " + exc.ToString());
            }
        }

        return returnX509;
    }

Avec c'est terminé, je puis utiliser le code suivant pour signer un message:

    public string SignData(string Message, string PrivateKey)
    {
        try
        {
            byte[] orgBytes = UnicodeEncoding.ASCII.GetBytes(Message);
            byte[] privateKey = UnicodeEncoding.ASCII.GetBytes(PrivateKey);

            string curveName = "P-521";
            X9ECParameters ecP = NistNamedCurves.GetByName(curveName);
            ECDomainParameters ecSpec = new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed());

            ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA");
            BigInteger biPrivateKey = new BigInteger(privateKey);
            ECPrivateKeyParameters keyParameters = new ECPrivateKeyParameters(biPrivateKey, ecSpec);

            signer.Init(true, keyParameters);
            signer.BlockUpdate(orgBytes, 0, orgBytes.Length);

            byte[] data = signer.GenerateSignature();
            //Base64 Encode
            byte[] encodedBytes;
            using (MemoryStream encStream = new MemoryStream())
            {
                base64.Encode(orgBytes, 0, orgBytes.Length, encStream);
                encodedBytes = encStream.ToArray();
            }

            if (encodedBytes.Length > 0)
                return UnicodeEncoding.ASCII.GetString(encodedBytes);
            else
                return "";
        }
        catch (Exception exc)
        {
            Console.WriteLine("Signing Failed: " + exc.ToString());
            return "";
        }
    }

Et, enfin, une tentative de ma part pour vérifier:

    public bool VerifySignature(string PublicKey, string Signature, string Message)
    {
        try
        {
            AsymmetricKeyParameter pubKey = new AsymmetricKeyParameter(false);

            var publicKey = PublicKeyFactory.CreateKey(Convert.FromBase64String(PublicKey));
            ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA");
            byte[] orgBytes = UnicodeEncoding.ASCII.GetBytes(Message);

            signer.Init(false, publicKey);
            signer.BlockUpdate(orgBytes, 0, orgBytes.Length);

            //Base64 Decode
            byte[] encodeBytes = UnicodeEncoding.ASCII.GetBytes(Signature);
            byte[] decodeBytes;
            using (MemoryStream decStream = new MemoryStream())
            {
                base64.Decode(encodeBytes, 0, encodeBytes.Length, decStream);
                decodeBytes = decStream.ToArray();
            }

            return signer.VerifySignature(decodeBytes);
        }
        catch (Exception exc)
        {
            Console.WriteLine("Verification failed with the error: " + exc.ToString());
            return false;
        } 
    }

Voici mon test app:

        Console.WriteLine("Attempting to load cert...");
        System.Security.Cryptography.X509Certificates.X509Certificate2 thisCert = LoadCertificate();
        if (thisCert != null)
        {
            Console.WriteLine(thisCert.IssuerName.Name);
            Console.WriteLine("Signing the text - Mary had a nuclear bomb");
            string signature = SignData("Mary had a nuclear bomb", thisCert.PublicKey.Key.ToXmlString(true));

            Console.WriteLine("Signature: " + signature);

            Console.WriteLine("Verifying Signature");

            if (VerifySignature(thisCert.PublicKey.Key.ToXmlString(false), signature, "Mary had a nuclear bomb."))
                Console.WriteLine("Valid Signature!");
            else
                Console.WriteLine("Signature NOT valid!");

        }

Quand j'essaye d'exécuter l'application de test, j'obtiens l'erreur "Clé non valide pour l'utilisation dans l'état spécifié." sur la ligne:

    string signature = SignData("Mary had a nuclear bomb", thisCert.PublicKey.Key.ToXmlString(true));

J'ai essayé de remplacer le "PublicKey.La touche" avec "PrivateKey" mais qui n'a pas fait une différence. J'ai aussi essayé d'utiliser le BounceyCastle X509Certificate mais je ne pouvais pas comprendre comment extraire les clés. Des idées?

Merci!

Mise à JOUR: je n'ai trouver comment faire pour signer et vérifier avec juste .NET, mais qui n'est pas vraiment utile pour moi comme j'ai besoin de la croix-plate-forme et, en fait, notre principal client de l'app est écrit en Java. Quelqu'un sait le Château Gonflable équivalent au code suivant?

    public string SignDataAsXml(string Message, X509Certificate2 ThisCert)
{
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = false;
doc.LoadXml("<core>" + Message + "</core>");
//Create a SignedXml object.
SignedXml signedXml = new SignedXml(doc);
//Add the key to the SignedXml document. 
signedXml.SigningKey = ThisCert.PrivateKey;
//Create a reference to be signed.
Reference reference = new Reference();
reference.Uri = "";
//Add an enveloped transformation to the reference.
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
//Add the reference to the SignedXml object.
signedXml.AddReference(reference);
//Create a new KeyInfo object.
KeyInfo keyInfo = new KeyInfo();
//Load the certificate into a KeyInfoX509Data object 
//and add it to the KeyInfo object.
keyInfo.AddClause(new KeyInfoX509Data(ThisCert));
//Add the KeyInfo object to the SignedXml object.
signedXml.KeyInfo = keyInfo;
//Compute the signature.
signedXml.ComputeSignature();
//Get the XML representation of the signature and save 
//it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
//Append the element to the XML document.
doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, true));
if (doc.FirstChild is XmlDeclaration)
{
doc.RemoveChild(doc.FirstChild);
}
using (var stringWriter = new StringWriter())
{
using (var xmlTextWriter = XmlWriter.Create(stringWriter))
{
doc.WriteTo(xmlTextWriter);
xmlTextWriter.Flush();
return stringWriter.GetStringBuilder().ToString();
}
}
}
public bool VerifyXmlSignature(string XmlMessage, X509Certificate2 ThisCert)
{
//Create a new XML document.
XmlDocument xmlDocument = new XmlDocument();
//Load the passed XML file into the document. 
xmlDocument.LoadXml(XmlMessage);
//Create a new SignedXml object and pass it the XML document class.
SignedXml signedXml = new SignedXml(xmlDocument);
//Find the "Signature" node and create a new XmlNodeList object.
XmlNodeList nodeList = xmlDocument.GetElementsByTagName("Signature");
//Load the signature node.
signedXml.LoadXml((XmlElement)nodeList[0]);
//Check the signature and return the result. 
return signedXml.CheckSignature(ThisCert, true);
}
J'ai pensé ECDSA est qu'une variante de la normale DSA algorithme de signature et ne reflétait pas les clés sous-jacentes utilisées. J'étais sous l'impression que la signature et la vérification serait de travailler aussi longtemps que ils ont utilisé le même algorithme de signature. N'est-ce pas le cas?
J'ai fait la LoadCertificates() la méthode contient la génération de la clé de la partie. Je suis à l'aide de RSA356 pour générer les clés puis RSA356-ECDSA de signer des données.
Désolé, j'ai accidentellement mélangé deux choses ensemble. GenerateKeys est pour mon cryptage de traitement et n'a rien à voir avec ce problème. J'ai corrigé la question et a ajouté le code de test.

OriginalL'auteur SEMDeveloper | 2015-04-02