有人使用过unidoc数字签名吗 | go | go 技术论坛-380玩彩网官网入口
公司要做上传合同电子签章,我的证书是用的阿里云买的ssl证书,下载下来的pfx文件,签名后打开一直显示文件签名后被修改或者已损坏,下面是我最后改来改去的最终版,如果不使用pfx证书,用generatekeys生成就不会显示被修改。
package main
import (
"bytes"
"crypto"
"crypto/rsa"
"crypto/x509"
"fmt"
"image"
"log"
"os"
"time"
"github.com/unidoc/unipdf/v3/annotator"
"github.com/unidoc/unipdf/v3/common/license"
"github.com/unidoc/unipdf/v3/core"
"github.com/unidoc/unipdf/v3/model"
"github.com/unidoc/unipdf/v3/model/sighandler"
"golang.org/x/crypto/pkcs12"
)
func init() {
// make sure to load your metered license api key prior to using the library.
// if you need a key, you can sign up and create a free one at https://cloud.unidoc.io
err := license.setmeteredkey(`8258c687d5bea0b89cb736d762de6937661d8f4562529b67b4ef478a2963d409`)
if err != nil {
panic(err)
}
}
var now = time.now()
func main() {
inputpath := `template_new.pdf`
imagefile := `image.png`
//watermarkimagefile := args[3]
outputpath := `template_new2.pdf`
// 读取pfx文件
pfxpath := "tanghuacomforthome.com.pfx"
pfxpassword := "0gfn69iu"
pfxdata, err := os.readfile(pfxpath)
if err != nil {
log.fatalf("无法读取pfx文件: %v", err)
}
// 解码pfx文件
priv, cert, err := decodepfx(pfxdata, pfxpassword)
if err != nil {
log.fatalf("fail: %v\n", err)
}
// create reader.
file, err := os.open(inputpath)
if err != nil {
log.fatalf("fail: %v\n", err)
}
defer file.close()
reader, err := model.newpdfreader(file)
if err != nil {
log.fatalf("fail: %v\n", err)
}
// create the image
imgfile, err := os.open(imagefile)
if err != nil {
log.fatalf("fail: %v\n", err)
}
defer imgfile.close()
signatureimage, _, err := image.decode(imgfile)
if err != nil {
log.fatalf("fail: %v\n", err)
}
// create appender.
appender, err := model.newpdfappender(reader)
if err != nil {
log.fatalf("fail: %v\n", err)
}
// create signature handler.
timestampserverurl := "https://freetsa.org/tsr"
handler, err := sighandler.newetsipadeslevellt(priv, cert, nil, timestampserverurl, appender)
if err != nil {
log.fatalf("fail: %v\n", err)
}
// create signature.
signature := model.newpdfsignature(handler)
signature.setname("tanghua")
signature.setreason("signature appearance reason")
signature.setdate(time.now(), "")
if err := signature.initialize(); err != nil {
log.fatalf("fail: %v\n", err)
}
// numpages, err := reader.getnumpages()
// if err != nil {
// log.fatal("fail: %v\n", err)
// }
opts := annotator.newsignaturefieldopts()
opts.fontsize = 10
opts.rect = []float64{10, 25, 110, 75}
opts.image = signatureimage
opts.imageposition = annotator.signatureimageright
field, err := annotator.newsignaturefield(
signature,
[]*annotator.signatureline{},
opts,
)
if err != nil {
log.fatalf("fail: %v\n", err)
}
field.t = core.makestring(fmt.sprintf("signature %d", 1))
if err = appender.sign(1, field); err != nil {
log.fatalf("fail: %v\n", err)
}
// write to buffer
buffer := bytes.newbuffer(nil)
err = appender.write(buffer)
if err != nil {
log.fatalf("error writing to buffer: %v\n", err)
}
// second pass to save dss/vri information
pdf2, err := model.newpdfreader(bytes.newreader(buffer.bytes()))
if err != nil {
log.fatalf("error creating pdf reader for second pass: %v\n", err)
}
appender2, err := model.newpdfappender(pdf2)
if err != nil {
log.fatalf("error creating pdf appender for second pass: %v\n", err)
}
appender2.setdss(appender.getdss())
buf2 := bytes.newbuffer(nil)
err = appender2.write(buf2)
if err != nil {
log.fatalf("error writing second pass buffer: %v\n", err)
}
// document timestamp for b-lta compatibility
pdf3, err := model.newpdfreader(bytes.newreader(buf2.bytes()))
if err != nil {
log.fatalf("error creating pdf reader for timestamp: %v\n", err)
}
appender3, err := model.newpdfappender(pdf3)
if err != nil {
log.fatalf("error creating pdf appender for timestamp: %v\n", err)
}
handler, err = sighandler.newdoctimestamp(timestampserverurl, crypto.sha512)
if err != nil {
log.fatalf("error creating timestamp handler: %v\n", err)
}
signature = model.newpdfsignature(handler)
signature.setname("test signature")
signature.setdate(time.now(), "")
err = signature.initialize()
if err != nil {
log.fatalf("error initializing timestamp signature: %v\n", err)
}
opts = annotator.newsignaturefieldopts()
opts.rect = []float64{10, 25, 110, 75}
opts.image = signatureimage
sigfield, err := annotator.newsignaturefield(
signature,
[]*annotator.signatureline{},
opts,
)
if err != nil {
log.fatalf("error creating timestamp signature field: %v\n", err)
}
err = appender3.sign(1, sigfield)
if err != nil {
log.fatalf("error signing with timestamp: %v\n", err)
}
err = appender3.writetofile(outputpath)
if err != nil {
log.fatalf("error writing final output file: %v\n", err)
}
log.printf("pdf file successfully signed. output path: %s\n", outputpath)
}
// func generatekeys() (*rsa.privatekey, *x509.certificate, error) {
// // generate private key.
// priv, err := rsa.generatekey(rand.reader, 2048)
// if err != nil {
// return nil, nil, err
// }
// // initialize x509 certificate template.
// template := x509.certificate{
// serialnumber: big.newint(1),
// subject: pkix.name{
// organization: []string{"tanghua"},
// },
// notbefore: now.add(-time.hour),
// notafter: now.add(time.hour * 24 * 365),
// keyusage: x509.keyusagedigitalsignature,
// extkeyusage: []x509.extkeyusage{x509.extkeyusageserverauth},
// basicconstraintsvalid: true,
// }
// // generate x509 certificate.
// certdata, err := x509.createcertificate(rand.reader, &template, &template, priv.public(), priv)
// if err != nil {
// return nil, nil, err
// }
// cert, err := x509.parsecertificate(certdata)
// if err != nil {
// return nil, nil, err
// }
// return priv, cert, nil
// }
// decodepfx 解码pfx文件并返回私钥和证书
func decodepfx(pfxdata []byte, password string) (*rsa.privatekey, *x509.certificate, error) {
// 使用pkcs12包解码pfx数据
blocks, err := pkcs12.topem(pfxdata, password)
if err != nil {
return nil, nil, err
}
var privatekey *rsa.privatekey
var certificate *x509.certificate
for _, block := range blocks {
switch block.type {
case "private key":
key, err := x509.parsepkcs1privatekey(block.bytes)
if err != nil {
return nil, nil, err
}
privatekey = key
case "certificate":
cert, err := x509.parsecertificate(block.bytes)
if err != nil {
return nil, nil, err
}
certificate = cert
}
}
if privatekey == nil || certificate == nil {
return nil, nil, fmt.errorf("未找到私钥或证书")
}
return privatekey, certificate, nil
}