SignWithECDSA.cs
 // // This code is part of Document Solutions for PDF demos. // Copyright (c) MESCIUS inc. All rights reserved. // using System; using System.IO; using System.Drawing; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Security; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Crypto.Parameters; using GrapeCity.Documents.Pdf; using GrapeCity.Documents.Pdf.Security; using GrapeCity.Documents.Pdf.AcroForms; using GrapeCity.Documents.Text; namespace DsPdfWeb.Demos { // This sample shows how to sign an existing PDF file that contains // an empty signature field with an Elliptic Curve Digital Signature Algorithm // (ECDSA) certificate. // // The sample includes a ready to use class BCSignatureGenerator that implements // the GrapeCity.Documents.Pdf.IPkcs7SignatureGenerator interface using the // BouncyCastle.Cryptography package. Because unlike the current .NET system libraries, // BouncyCastle supports ECDSA, the BCSignatureGenerator class can be used in your // applications to handle ECDSA certificates. public class SignWithECDSA { public int CreatePDF(Stream stream) { var certPath = Path.Combine("Resources", "Misc", "DsPdfTest3_ECDSA.pfx"); var certPwd = "password"; var doc = new GcPdfDocument(); using var s = File.OpenRead(Path.Combine("Resources", "PDFs", "SignWithECDSA.pdf")); doc.Load(s); var sp = new SignatureProperties() { SignatureBuilder = new Pkcs7SignatureBuilder() { SignatureGenerator = new BCSignatureGenerator(certPath, certPwd, OID.HashAlgorithms.SHA256), CertificateChain = SecurityUtils.GetCertificateChain(certPath, certPwd), }, SignatureField = doc.AcroForm.Fields[0] }; sp.SignatureAppearance.Caption = "ECDSA"; doc.Sign(sp, stream); // Done. return doc.Pages.Count; } } /// <summary> /// Implements <see cref="IPkcs7SignatureGenerator"/>. /// This implementation uses BouncyCastle libraries which, /// unlike the current .NET system libraries, support ECDSA /// (Elliptic Curve Digital Signature Algorithm) keys. /// </summary> public class BCSignatureGenerator : IPkcs7SignatureGenerator { private OID _hashAlgorithm; private OID _encryptionAlgorithm; private string _encryptionAlgorithmName; private ICipherParameters _key; public BCSignatureGenerator(ICipherParameters key, OID hashAlgorithm) { _hashAlgorithm = hashAlgorithm; if (key is RsaKeyParameters) { _encryptionAlgorithm = OID.EncryptionAlgorithms.RSA; _encryptionAlgorithmName = "RSA"; } else if (key is DsaKeyParameters) { _encryptionAlgorithm = OID.EncryptionAlgorithms.DSA; _encryptionAlgorithmName = "DSA"; } else if (key is ECKeyParameters) { _encryptionAlgorithm = OID.EncryptionAlgorithms.ECDSA; _encryptionAlgorithmName = "ECDSA"; } else { throw new Exception($"Unknown algorithm used in the private key [{key}]"); } _key = key; } public BCSignatureGenerator(byte[] certificateData, string password, OID hashAlgorithm) : this(GetPrivateKey(certificateData, password), hashAlgorithm) { } public BCSignatureGenerator(Stream certificateStream, string password, OID hashAlgorithm) : this(GetPrivateKey(certificateStream, password), hashAlgorithm) { } public BCSignatureGenerator(string certificateFileName, string password, OID hashAlgorithm) : this(GetPrivateKey(certificateFileName, password), hashAlgorithm) { } public OID HashAlgorithm => _hashAlgorithm; public OID DigestEncryptionAlgorithm => _encryptionAlgorithm; public byte[] SignData(byte[] digest) { string han = DigestUtilities.GetAlgorithmName(new DerObjectIdentifier(_hashAlgorithm.ToString())); string algorithm = han + "with" + _encryptionAlgorithmName; ISigner sig = SignerUtilities.GetSigner(algorithm); sig.Init(true, _key); sig.BlockUpdate(digest, 0, digest.Length); return sig.GenerateSignature(); } public static ICipherParameters GetPrivateKey(Stream certificateStream, string password) { char[] p = new char[password.Length]; for (int i = 0; i < p.Length; i++) p[i] = password[i]; Pkcs12Store pk12 = new Pkcs12StoreBuilder().Build(); pk12.Load(certificateStream, p); foreach (var a in pk12.Aliases) { string alias = (string)a; if (pk12.IsKeyEntry(alias)) { var key = pk12.GetKey(alias); if (key.Key.IsPrivate) return key.Key; } } throw new Exception("Cannot get private key."); } public static ICipherParameters GetPrivateKey(string certificateFilePath, string password) { using var fs = new FileStream(certificateFilePath, FileMode.Open); return GetPrivateKey(fs, password); } public static ICipherParameters GetPrivateKey(byte[] certificateData, string password) { using var ms = new MemoryStream(certificateData); return GetPrivateKey(ms, password); } } }