有人使用过unidoc数字签名吗

公司要做上传合同电子签章,我的证书是用的阿里云买的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
}
讨论数量: 2

那估计就是证书有些问题吧,确认下pfx读取的证书这些跟自己生成的有哪些区别

1个月前 评论
ldwangaqr (楼主) 1个月前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!