SignWithECDSA.cs
//// This code is part of Document Solutions for PDF .NET demos.// Copyright (c) MESCIUS inc. All rights reserved.//using System;using System.IO;
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;
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); } }}