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);
- }
- }
- }
-