Digital Signature
Install package
dotnet add package itext
dotnet add package itext.bouncy-castle-adapter
SignPdf
Create certificate
RSA rsa = RSA.Create();
CertificateRequest request = new CertificateRequest("CN=ceb.net.vn", rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
X509Certificate2 certificate2 = request.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(1));
byte[] bytes = certificate2.Export(X509ContentType.Pfx, "123456");
File.WriteAllBytes("certificate.pfx", bytes);
SignPdf
public static byte[] SignPdf(byte[] pdfBytes){
PdfFont font = PdfFontFactory.CreateFont(@"C:\Windows\Fonts\arial.ttf", PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);
string path = Path.Combine(Directory.GetCurrentDirectory(), "certificates", "certificate.pfx");
string password = "123456";
using MemoryStream inputMs = new MemoryStream(pdfBytes);
using MemoryStream outputMs = new MemoryStream();
Pkcs12Store pkcs12Store = new Pkcs12StoreBuilder().Build();
using(FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)){
pkcs12Store.Load(fs, password.ToArray());
}
string alias = null!;
foreach(string a in pkcs12Store.Aliases){
if (pkcs12Store.IsKeyEntry(a)){
alias = a;
break;
}
}
var bcPrivateKey = pkcs12Store.GetKey(alias).Key;
var privateKey = new PrivateKeyBC(bcPrivateKey);
var certificateChain = pkcs12Store.GetCertificateChain(alias).Select(p => new X509CertificateBC(p.Certificate)).ToArray();
var signerProperties = new SignerProperties()
.SetFieldName("cebnetvn")
.SetReason("Ký hóa đơn điện tử")
.SetLocation("Thành Phố Hồ Chí Minh")
.SetPageNumber(1)
.SetPageRect(new iText.Kernel.Geom.Rectangle(207, 70, 180, 70));
var appearance = new SignatureFieldAppearance("cebnetvn")
.SetContent($"Đã Đăng Ký Số\nNguyễn Văn Tèo\nNgày ký: {DateTime.Now:dd/MM/yyyy HH:mm}").SetFont(font).SetFontSize(12);
signerProperties.SetSignatureAppearance(appearance);
var reader = new PdfReader(new MemoryStream(pdfBytes));
var signer = new PdfSigner(reader, outputMs, new StampingProperties());
signer.SetSignerProperties(signerProperties);
IExternalSignature signature = new PrivateKeySignature(privateKey, DigestAlgorithms.SHA256);
signer.SignDetached(signature, certificateChain, null, null, null, 0, PdfSigner.CryptoStandard.CADES);
return outputMs.ToArray();
}
Signature Result
public class SignatureResult{
public string Name { get; set; } = null!;
public bool IsValid { get; set; }
public DateTime SigningDate { get; set; }
}
Verify Pdf
public static IEnumerable<SignatureResult> Verify(MemoryStream ms){
try{
ms.Position = 0;
using var reader = new PdfReader(ms);
using var pdf = new PdfDocument(reader);
var signatureUtil = new SignatureUtil(pdf);
var names = signatureUtil.GetSignatureNames();
if(names is null || names.Count == 0){
throw new Exception("PDf not found digital signature");
}
var results = new List<SignatureResult>();
foreach (var name in names){
var pkcs7 = signatureUtil.ReadSignatureData(name);
bool valid = pkcs7.VerifySignatureIntegrityAndAuthenticity();
results.Add(new SignatureResult{
Name = name,
IsValid = valid,
SigningDate = pkcs7.GetSignDate()
});
}
return results;
}
catch (Exception ex){
throw new Exception(ex.Message);
}
}
Export Pdf
public static byte[] ExportPdf(Invoice invoice, IEnumerable<Product> products){
PdfFont font = PdfFontFactory.CreateFont(@"C:\Windows\Fonts\arial.ttf", PdfEncodings.IDENTITY_H, PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);
MemoryStream pdfStream = new MemoryStream();
PdfWriter writer = new PdfWriter(pdfStream);
Document document = new Document(new PdfDocument(writer));
document.SetMargins(40, 40, 40, 40);
Paragraph title = new Paragraph("HÓA ĐƠN BÁN HÀNG")
.SetTextAlignment(TextAlignment.CENTER).SetFont(font).SetFontSize(20);
document.Add(title);
document.Add(new Paragraph($"Số hóa đơn: {invoice.Id}\nNgay2: {invoice.InvoiceDate:dd/MM/yyyy HH:mm}").SetFont(font).SetFontSize(12));
document.Add(new Paragraph($"Khách hàng: {invoice.CustomerName}\nĐịa chỉ: {invoice.CustomerAddress}").SetFont(font).SetFontSize(12));
document.Add(new Paragraph(" "));
var table = new Table(UnitValue.CreatePercentArray(new float[]{1, 4, 1, 2, 2}));
table.SetWidth(UnitValue.CreatePercentValue(100));
string[] columns = {"STT", "Sản phẩm", "SL", "Đơn giá", "Thành tiền"};
foreach (string col in columns){
table.AddHeaderCell(col).SetFont(font).SetFontSize(12);
}
int srNo = 1;
foreach (var product in products){
decimal amount = product.Quantity * product.Price;
table.AddCell(srNo.ToString());
table.AddCell(product.Name);
table.AddCell(product.Quantity.ToString());
table.AddCell(product.Price.ToString("#,##0", CultureInfo.InvariantCulture));
table.AddCell(amount.ToString("#,##0", CultureInfo.InvariantCulture));
srNo ++;
}
document.Add(table);
document.Add(new Paragraph(" "));
decimal total = products.Sum(p => p.Quantity * p.Price);
document.Add(new Paragraph($"Tổng cộng: {total:#,##0} VNĐ")).SetTextAlignment(TextAlignment.RIGHT).SetFont(font).SetFontSize(14);
document.Add(new Paragraph(" "));
document.Add(new Paragraph(" "));
var signTable = new Table(UnitValue.CreatePercentArray(new float[]{1, 1}));
signTable.SetWidth(UnitValue.CreatePercentValue(100));
var footer = new Paragraph("NGƯỜI MUA HÀNG\n\n\n\n(Ký, ghi rõ họ tên)").SetFont(font).SetTextAlignment(TextAlignment.CENTER);
signTable.AddCell(new Cell().SetBorder(Border.NO_BORDER).Add(footer));
Paragraph footCustomer = new Paragraph("NGƯỜI BÁN HÀNG\n\n\n\n(Đã ký số)").SetFont(font).SetTextAlignment(TextAlignment.CENTER);
signTable.AddCell(new Cell().SetBorder(Border.NO_BORDER).Add(footCustomer));
document.Add(signTable);
document.Close();
var signedPdf = Helper.SignPdf(pdfStream.ToArray());
return signedPdf.ToArray();
}
Subject
| Ký hiệu |
Tên |
Ví dụ |
| `CN` | Common Name | `ceb.net.vn` |
| `O` | Organization | `CEB Company` |
| `OU` | Organizational Unit | `IT Department` |
| `L` | Locality | `Ho Chi Minh City` |
| `ST` | State/Province | `Ho Chi Minh` |
| `C` | Country | `VN` |
| `STREET` | Địa chỉ đường | `123 Nguyen Hue` |
| `DC` | Domain Component | `net`, `vn` |
| `UID` | User ID | `user123` |
| `SERIALNUMBER` | Số định danh | `0123456789` |
| `E` / `emailAddress` | Email | `admin@ceb.net.vn` |
Create Subject
var builder = new X500DistinguishedNameBuilder();
builder.AddCommonName("CEB");
builder.AddOrganizationName("Tin Học Cho Mọi Người");
builder.AddLocalityName("Thành phố Hồ Chí Minh");
builder.AddStateOrProvinceName("Hồ Chí Minh");
builder.AddCountryOrRegion("VN");
var subject = builder.Build();