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 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
Vous devez vous connecter pour publier un commentaire.
Château gonflable ne prend pas en charge les formats XML. À moins que votre cas d'utilisation strictement l'exige, vous constaterez qu'il est beaucoup plus facile de simplement utiliser Base64 encodages, avec les certificats X. 509) et les clés privées (PKCS#8) stockés au format PEM. Ce sont tous des formats de chaîne, de sorte que devrait être utilisable avec JSON directement.
Il y a d'autres problèmes dans les exemples de code: signature d'utiliser la clé privée, les signatures ne devraient pas être traitées comme des chaînes ASCII, éventuellement, vos messages sont effectivement UTF8. Je m'attends à l'intérieur de signer/vérifier des routines peut-être ressembler à ceci:
Un autre problème est que je pense .NET n'a pas l'obtenir ECDSA de soutien jusqu'à ce que .NET 3.5, en tout cas, il n'y a pas ECDsa classe .NET 1.1 (qui est en c.-cible pour la prochaine version 1.8, nous serons à la "modernisation" après que), donc DotNetUtilities n'a pas de support pour ECDSA. Cependant, nous pouvons exporter vers le fichier PKCS#12 et importation de la colombie-britannique. Un exemple de programme:
Je n'ai pas vraiment testé le code ci-dessus, mais il devrait vous donner quelque chose à faire. Note que la colombie-britannique a des clés et des certificats les générateurs de trop, alors vous pourriez choisir d'utiliser BC pour tout (sauf XML!), et les exportations et importations vers/depuis .NET des terres uniquement en cas de besoin.
J'ai essayé d'utiliser le code suivant (avec tous les dérivés que j'ai pu trouver pour exporter le cert dans un tableau d'octets Pkcs12Store pkcs12 = new Pkcs12StoreBuilder().Build(); pkcs12.Load(new MemoryStream(CurrentCert.CertificateStructure.GetEncoded(), false), CertificatePassword.ToCharArray()); Mais j'ai gardé l'obtention de l'erreur: Impossible de convertir l'objet de type 'Org.BouncyCastle.Asn1.DerSequence' de type 'Org.BouncyCastle.Asn1.DerInteger'
Si j'utilise cette ligne tout fonctionne, mais comment dois-je faire ceci en mémoire? pkcs12.Charge(Fichier.OpenRead("myCert.p12"), CertificatePassword.ToCharArray());
En colombie-britannique, un X509Certificate ne contient pas la clé privée correspondante. Lorsque vous avez créé le certificat, vous devez avoir généré une paire de clés, d'une certaine manière, de sorte que vous prendre la clé privée à partir de là. Vous pouvez ensuite stocker le certificat et la clé privée ensemble dans un fichier PKCS#12 magasin, ou vous pouvez les écrire dans des fichiers séparés, généralement codés en PEM. Recherche pour des exemples d'utilisation de Org.BouncyCastle.OpenSsl.PemWriter classe (et assurez-vous d'utiliser un mot de passe lors de l'écriture de la clé privée).
OriginalL'auteur Peter Dettman
Grâce à Petters réponse que je voulais ajouter du code pour vérifier la signature avec l'algorithme RSA.
OriginalL'auteur mGolzadh