Digitalorus/pdfsign を使用して Go (Golang) で PDF ファイルに署名する

WBOY
リリース: 2024-02-09 10:00:11
転載
596 人が閲覧しました

使用 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/digitalorus/pdfsign

です。

私の完全なコードは次のとおりです:

リーリー

正確に言うと、これらは私の質問の Signer パラメーターと CertificateChains パラメーターです。 privateKey 変数とchainCerts 変数の正しい使用方法がわかりません。

メッセージ エラーは次のとおりです:

  • privateKey (interface{} 型の変数) を構造体リテラルの crypto.Signer 値として使用できません。interface{} は crypto.Signer を実装していません (Public メソッドがありません)
  • chainCertificates (タイプ []*x509.Certificate の変数) を構造リテラルの [][]*x509.Certificate 値として使用できません

私はこの言語を初めて使用するため、詳細な概念とデータ型をまだ理解していません。

他に何をすべきか、成功するためにどのような手順が欠けているかを教えてくれてありがとう。または、pkcs 証明書に基づいて PDF に署名する方法を知っている人がいたら。

回避策

デジタル署名を使用して PDF に署名するには、公開キー暗号化を使用してキーのペアを生成する必要があります。秘密鍵は署名に関連するデータを暗号化し、署名者のみがアクセスできるようにするために使用され、公開鍵は検証のために署名データを復号化するために使用されます。信頼できる認証局によって発行されたものでない場合、当該公開鍵は証明書を信頼するには、それを証明書ストアに追加する必要があります。 指定された例では、この署名データは、sign.SignData という構造内に保存されます。これは pdfsign ライブラリの一部であり、x509 証明書と、crypto.Signer インターフェイスを実装する署名者を必要とします。

最初のステップは、Go 標準ライブラリの crypto/ecdsa パッケージを使用してキーのペアを生成することです。 GenerateKey は、秘密鍵と公開鍵を privateKey 変数に保存します。この返された privateKey 変数は、現在直面している問題を解決するために必要な crypto.Signer インターフェイスを実装します。

これは、ecdsa.go コードの 142 行目を読むことで確認できます。

現在 gopkcs12.DecodeChain を使用して秘密キーを返していますが、crypto.Signer インターフェイスが実装されていないため、エラーが発生します。カスタムのものを実装する必要があるかもしれませんが、それは別の問題です。

###コンセプト:###

ECDSA

は、楕円曲線デジタル署名アルゴリズムを表します。デジタル署名に使用される公開鍵暗号化アルゴリズムです。詳細については、Go 標準ライブラリのドキュメントと NIST Web サイトを参照してください。

    https://pkg.go.dev/crypto/
  • [email protected]
  • https://www.php.cn/link/813b6a28cc4ac72d244266161e3e2eb4
  • NIST
P-384

: P-384 は、国立標準技術研究所 (NIST) が推奨する楕円曲線の 1 つで、鍵の長さは 384 ビットです。デジタル署名とその他の推奨される楕円曲線の詳細については、NIST の Web サイトを参照してください。私は実用的なソリューションとして 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 中国語 Web サイトの他の関連記事を参照してください。

ソース:stackoverflow.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!