>  기사  >  백엔드 개발  >  digitalorus/pdfsign을 사용하여 Go(Golang)에서 PDF 파일에 서명

digitalorus/pdfsign을 사용하여 Go(Golang)에서 PDF 파일에 서명

WBOY
WBOY앞으로
2024-02-09 10:00:11597검색

使用 digitalorus/pdfsign 在 Go (Golang) 中签署 pdf 文件

Go 언어로 PDF 파일에 서명하는 것은 일반적인 요구 사항이며 이 기능은 digitalorus/pdfsign 라이브러리를 사용하여 쉽게 구현할 수 있습니다. PHP 편집자 Youzi가 이 라이브러리를 사용하는 방법을 소개합니다. 비즈니스 응용 프로그램이든 개인 프로젝트이든 PDF 파일에 서명하는 것은 일반적인 작업입니다. digitalorus/pdfsign 라이브러리는 간단하고 사용하기 쉬운 인터페이스를 제공하여 Go 언어로 PDF 파일에 간단하고 빠르게 서명할 수 있도록 해줍니다. 이 기사를 통해 Go 언어로 digitalorus/pdfsign 라이브러리를 사용하여 PDF 파일의 서명 작업을 완료하는 방법을 배우게 됩니다. 함께 탐험해 보세요!

질문 내용

go(golang)에서는 PDF 문서에 서명을 해야 하는데 다른 언어와는 달리 작업을 쉽게 해주는 라이브러리가 없습니다. 유료 제품을 몇 개 찾았지만 옵션이 아니었습니다.

먼저 다음 패키지를 사용하여 개인 키와 x509 인증서를 추출한 PKCS 인증서(.p12)가 있습니다. https://pkg.go.dev/software.sslmate.com/src/go -pkcs12

그런데 PDF 문서에 서명하려고 할 때 이러한 작업을 수행하는 함수에 매개변수를 올바르게 전달하는 방법을 모르기 때문에 막히게 됩니다. 사용된 패키지는 https://pkg.go.dev/github.com/digitorus/pdfsign

내 전체 코드는 다음과 같습니다:

으아악

정확히 말하면 제 질문의 Signer 및 CertificateChains 매개변수입니다. privateKey 및 chainCerts 변수를 올바르게 사용하는 방법을 모르겠습니다.

메시지 오류:

  • privateKey(인터페이스 유형 변수{})를 구조체 리터럴의 crypto.Signer 값으로 사용할 수 없습니다. 인터페이스{}는 crypto.Signer를 구현하지 않습니다(공용 메서드 누락)
  • chainCertificates([]*x509.Certificate 유형의 변수)를 구조 리터럴의 [][]*x509.Certificate 값으로 사용할 수 없습니다

저는 이 언어를 처음 접해서 아직 심층적인 개념과 데이터 유형을 이해하지 못합니다.

성공하기 위해 무엇을 더 해야 하는지, 어떤 단계를 놓치고 있는지 알려주셔서 감사합니다. 또는 pkcs 인증서를 기반으로 PDF에 서명하는 방법을 아는 사람이 있다면.

해결 방법

디지털 서명을 사용하여 PDF에 서명하려면 공개 키 암호화를 사용하여 키 쌍을 생성해야 합니다. 개인 키는 서명과 관련된 데이터를 암호화하는 데 사용되며 서명자만 액세스할 수 있으며, 공개 키는 검증을 위해 서명 데이터를 해독하는 데 사용됩니다. 인증서를 신뢰할 수 있도록 하려면 인증서를 인증서 저장소에 추가해야 합니다. 주어진 예에서 이 서명 데이터는 pdfsign 라이브러리의 일부인 sign.SignData라는 구조 내에 저장되며 x509 인증서와 crypto.Signer 인터페이스를 구현하는 서명자가 필요합니다.

첫 번째 단계는 Go 표준 라이브러리의 crypto/ecdsa 패키지를 사용하여 키 쌍을 생성하는 것입니다. GenerateKey는 개인 키와 공개 키를 privateKey 변수에 저장합니다. 이 반환된 privateKey 변수는 현재 직면한 문제를 해결하는 데 필요한 crypto.Signer 인터페이스를 구현합니다.

ecdsa.go 코드의 142번째 줄을 읽어보면 이를 확인할 수 있습니다.

현재 gopkcs12.DecodeChain을 사용하여 개인 키를 반환하고 있지만 crypto.Signer 인터페이스를 구현하지 않아 오류가 발생합니다. 사용자 정의 구현이 필요할 수도 있지만 이는 또 다른 질문입니다.

콘셉트:

ECDSA는 타원 곡선 디지털 서명 알고리즘을 나타냅니다. 디지털 서명에 사용되는 공개 키 암호화 알고리즘입니다. 자세한 내용은 Go 표준 라이브러리 문서와 NIST 웹사이트를 참조하세요.

NIST P-384: P-384는 NIST(미국 국립표준기술원)에서 권장하는 키 길이가 384비트인 타원 곡선 중 하나입니다. 디지털 서명 및 권장되는 타원 곡선에 대한 자세한 내용은 NIST 웹 사이트를 참조하세요. 저는 P-384를 작업 솔루션으로 사용합니다.

第二步是使用Go标准库中的crypto/x509包通过其链生成器生成x509证书和证书链。这些是您在问题中寻求帮助的特定变量,但不属于您在错误消息中可以清楚看到的预期类型。只需遵循 lib 指令并使用 x509.Certificate.Verify() 就像我在工作解决方案中所做的那样,这将返回正确的类型 [][]*x509.Certificate。

请参阅 Go 标准库文档以获取更多信息。

第三步是打开输入 pdf 文件并使用 Go 标准库中的 os 包创建输出 pdf 文件。

第四步实际上是使用 digitalorus/pdfsign 库对 pdf 文件进行签名。

这是我今天编码和测试的一个有效解决方案,旨在让您回到正轨,进行一些研究并根据您的需求进行修改:

package main

import (
    "crypto"
    "crypto/ecdsa"
    "crypto/elliptic"
    "crypto/rand"
    "crypto/x509"
    "crypto/x509/pkix"
    "fmt"
    "github.com/digitorus/pdf"
    "github.com/digitorus/pdfsign/revocation"
    "github.com/digitorus/pdfsign/sign"
    "log"
    "math/big"
    "os"
    "time"
)

func main() {
    // First step

    privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)

    if err != nil {
        panic(err)
    }

    // Second step

    x509RootCertificate := &x509.Certificate{
        SerialNumber: big.NewInt(2023),
        Subject: pkix.Name{
            Organization:  []string{"Your Organization"},
            Country:       []string{"Your Country"},
            Province:      []string{"Your Province"},
            Locality:      []string{"Your Locality"},
            StreetAddress: []string{"Your Street Address"},
            PostalCode:    []string{"Your Postal Code"},
        },
        NotBefore:             time.Now(),
        NotAfter:              time.Now().AddDate(10, 0, 0),
        IsCA:                  true,
        ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
        KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
        BasicConstraintsValid: true,
    }

    rootCertificateBytes, err := x509.CreateCertificate(rand.Reader, x509RootCertificate, x509RootCertificate, &privateKey.PublicKey, privateKey)

    if err != nil {
        panic(err)
    }

    rootCertificate, err := x509.ParseCertificate(rootCertificateBytes)

    if err != nil {
        panic(err)
    }

    roots := x509.NewCertPool()

    roots.AddCert(rootCertificate)

    certificateChain, err := rootCertificate.Verify(x509.VerifyOptions{
        Roots: roots,
    })

    if err != nil {
        panic(err)
    }

    // Third step

    outputFile, err := os.Create("output.pdf")

    if err != nil {
        panic(err)
    }

    defer func(outputFile *os.File) {
        err = outputFile.Close()

        if err != nil {
            log.Println(err)
        }

        fmt.Println("output file closed")
    }(outputFile)

    inputFile, err := os.Open("input.pdf")

    if err != nil {
        panic(err)
    }

    defer func(inputFile *os.File) {
        err = inputFile.Close()

        if err != nil {
            log.Println(err)
        }

        fmt.Println("input file closed")
    }(inputFile)

    fileInfo, err := inputFile.Stat()

    if err != nil {
        panic(err)
    }

    size := fileInfo.Size()

    pdfReader, err := pdf.NewReader(inputFile, size)

    if err != nil {
        panic(err)
    }

    // Fourth step

    err = sign.Sign(inputFile, outputFile, pdfReader, size, sign.SignData{
        Signature: sign.SignDataSignature{
            Info: sign.SignDataSignatureInfo{
                Name:        "Your name",
                Location:    "Your location",
                Reason:      "Your reason",
                ContactInfo: "Your contact info",
                Date:        time.Now().Local(),
            },
            CertType:   sign.CertificationSignature,
            DocMDPPerm: sign.AllowFillingExistingFormFieldsAndSignaturesPerms,
        },
        Signer:            privateKey,       // crypto.Signer
        DigestAlgorithm:   crypto.SHA256,    // hash algorithm for the digest creation
        Certificate:       rootCertificate,  // x509.Certificate
        CertificateChains: certificateChain, // x509.Certificate.Verify()
        TSA: sign.TSA{
            URL:      "",
            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 {
        log.Println(err)
    } else {
        log.Println("pdf signed")
    }
}

结果:

go run main.go

2023/12/01 21:53:37 pdf signed
input file closed
output file closed

위 내용은 digitalorus/pdfsign을 사용하여 Go(Golang)에서 PDF 파일에 서명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 stackoverflow.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제