
目前有业务需要给 pdf 合同进行电子签名,目前使用的是 https://github.com/digitorus/pdfsign 这个库,但是碰到一个问题,首先是能够正常签名,但是校验时出现了一些问题。
当对已经签名过的 pdf 文件在末尾添加几个随机字节,此时使用 pdfsign 去检测,是没有办法检测到该文件已经被篡改了,在 adobe reader 中是能够检测到该文件有问题。
这里不讨论公司是否拥有这个资质的问题
有几个需要帮助的地方:
代码:
package main import ( "crypto" "crypto/rsa" "crypto/x509" "encoding/json" "encoding/pem" "errors" "github.com/digitorus/pdf" "github.com/digitorus/pdfsign/revocation" "github.com/digitorus/pdfsign/sign" "github.com/digitorus/pdfsign/verify" "log" "os" "time" ) func main() { err := run("a.pdf", "b.pdf") if err != nil { panic(err) } data, err := os.ReadFile("b.pdf") if err != nil { panic(err) } data = append(data, []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}...) err = os.WriteFile("c.pdf", data, 0644) if err != nil { panic(err) } verifyPdf("c.pdf") } func verifyPdf(pdfName string) { input_file, err := os.Open(pdfName) if err != nil { panic(err) } defer input_file.Close() resp, err := verify.File(input_file) if err != nil { panic(err) } jsonData, err := json.MarshalIndent(resp, "", "\t") if err != nil { panic(err) } // 将 jsonData 的数据写入文件 err = os.WriteFile("verify.json", jsonData, 0644) return } func run(input, output string) error { input_file, err := os.Open(input) if err != nil { panic(err) } defer input_file.Close() output_file, err := os.Create(output) if err != nil { panic(err) } defer output_file.Close() finfo, err := input_file.Stat() if err != nil { panic(err) } size := finfo.Size() rdr, err := pdf.NewReader(input_file, size) if err != nil { panic(err) } certificate_data, err := os.ReadFile("certificate.crt") if err != nil { panic(err) } certificate_data_block, _ := pem.Decode(certificate_data) if certificate_data_block == nil { //log.Fatal(errors.New("failed to parse PEM block containing the certificate")) panic(err) } cert, err := x509.ParseCertificate(certificate_data_block.Bytes) if err != nil { panic(err) } privateKeyFs, err := os.ReadFile("private_key.pem") if err != nil { panic(err) } key_data_block, _ := pem.Decode(privateKeyFs) if key_data_block == nil { panic(errors.New("failed to parse PEM block containing the private key")) } // 尝试解析 PKCS#1 格式的私钥 pkey, err := x509.ParsePKCS1PrivateKey(key_data_block.Bytes) if err != nil { var t any t, err = x509.ParsePKCS8PrivateKey(key_data_block.Bytes) pkey = t.(*rsa.PrivateKey) if err != nil { panic(err) } } certificate_chains := make([][]*x509.Certificate, 0) err = sign.Sign(input_file, output_file, rdr, size, sign.SignData{ Signature: sign.SignDataSignature{ Info: sign.SignDataSignatureInfo{ Name: "xx", Location: "xx", Reason: "xx", ContactInfo: "xxx", Date: time.Now().Local(), }, CertType: sign.CertificationSignature, DocMDPPerm: sign.AllowFillingExistingFormFieldsAndSignaturesPerms, }, Signer: pkey, // crypto.Signer DigestAlgorithm: crypto.SHA256, // hash algorithm for the digest creation Certificate: cert, // x509.Certificate CertificateChains: certificate_chains, // x509.Certificate.Verify() TSA: sign.TSA{ URL: "https://freetsa.org/tsr", Username: "", Password: "", }, // The follow options are likely to change in a future release // // cache revocation data when bulk signing RevocationData: revocation.InfoArchival{}, // custom revocation lookup RevocationFunction: sign.DefaultEmbedRevocationStatusFunction, }) if err != nil { panic(err) } else { log.Println("Signed PDF written to " + output) } return nil } /* 自签私钥与证书生成 1. 生成私钥 openssl genpkey -algorithm RSA -out private_key.pem 2. 创建证书签名请求 (CSR) openssl req -new -key private_key.pem -out csr.pem 3. 签发自签证书 openssl x509 -req -days 365 -in csr.pem -signkey private_key.pem -out certificate.crt */ 1 tool2dx 2024 年 9 月 24 日 "当对已经签名过的 pdf 文件在末尾添加几个随机字节" 写点代码去掉就可以了。pdf 可以用软件遍历出文件结尾地址。后面如果是随机字节,并不会影响到签名本体,这部分内容本来就是多余的,又不会去读。 |
2 DefoliationM 2024 年 9 月 24 日 via Android 试试随机改几个字节,而不是添加到末尾? |
3 cdx OP |
4 xxmaqzas 2024 年 9 月 24 日 不能把签过的 md5 存数据库么,直接校验文件的 md5 值 |