title: Bouncy Castle Sign and Verify SHA256 Certificate With C#
body: <p>I have been through a large number of examples of how people use Bouncy Castle to dynamically generate RSA Key Pairs and then sign and verify all within one block of code.  Those answers were great and really helped me ramp up quickly!</p>
  
  <p>That said, I need to create a client that can pass through WCF JSON calls a public key to be used later for signature verification and I cannot seem to get this to work.  First here is the code I use to generate the Certificate:</p>
  
  <pre><code>    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;
      }
  </code></pre>
  
  <p>With that completed, I then use the following code to sign a message:</p>
  
  <pre><code>    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 &gt; 0)
                  return UnicodeEncoding.ASCII.GetString(encodedBytes);
              else
                  return "";
          }
          catch (Exception exc)
          {
              Console.WriteLine("Signing Failed: " + exc.ToString());
              return "";
          }
      }
  </code></pre>
  
  <p>And, finally, my attempt to verify:</p>
  
  <pre><code>    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;
          } 
      }
  </code></pre>
  
  <p>Here is my test app:</p>
  
  <pre><code>        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!");
  
          }
  </code></pre>
  
  <p>When I attempt to run the test app, I am getting the error "Key not valid for use in specified state." on the line:</p>
  
  <pre><code>    string signature = SignData("Mary had a nuclear bomb", thisCert.PublicKey.Key.ToXmlString(true));
  </code></pre>
  
  <p>I tried replacing the "PublicKey.Key" with "PrivateKey" but that did not make a difference.  I also tried using the BounceyCastle X509Certificate but I could not figure out how to extract the keys.  Any ideas?</p>
  
  <p>Thank you!</p>
  
  <p>UPDATE:  I did figure out how to sign and verify with just .NET but that is not really useful to me as I need to be cross platform and, in fact, our main client app is written in Java.  Does anybody know the Bouncy Castle equivalent to the following code?</p>
  
  <pre><code>    public string SignDataAsXml(string Message, X509Certificate2 ThisCert)
      {
          XmlDocument doc = new XmlDocument();
          doc.PreserveWhitespace = false;
          doc.LoadXml("&lt;core&gt;" + Message + "&lt;/core&gt;");
  
          // 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);
      }
  </code></pre>