dsig

package module
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 13, 2026 License: MIT Imports: 15 Imported by: 6

README

github.com/lestrrat-go/dsig CI Go Reference codecov.io

Go module providing low-level digital signature operations.

While there are many standards for generating and verifying digital signatures, the core operations are virtually the same. This module implements the core functionality of digital signature generation / verifications in a framework agnostic way.

Features

  • RSA signatures (PKCS1v15 and PSS)
  • ECDSA signatures (P-256, P-384, P-521)
  • EdDSA signatures (Ed25519, Ed448)
  • HMAC signatures (SHA-256, SHA-384, SHA-512)
  • Support for crypto.Signer interface
  • Custom algorithm registration via Signer/Verifier interfaces

SYNOPSIS

package examples_test

import (
  "crypto/ecdsa"
  "crypto/ed25519"
  "crypto/elliptic"
  "crypto/rand"
  "crypto/rsa"
  "fmt"

  "github.com/lestrrat-go/dsig"
)

func Example() {
  payload := []byte("hello world")

  // RSA signing and verification
  {
    privKey, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
      fmt.Printf("failed to generate RSA key: %s\n", err)
      return
    }

    // Sign with RSA-PSS SHA256
    signature, err := dsig.Sign(privKey, dsig.RSAPSSWithSHA256, payload, nil)
    if err != nil {
      fmt.Printf("failed to sign with RSA: %s\n", err)
      return
    }

    // Verify with RSA-PSS SHA256
    err = dsig.Verify(&privKey.PublicKey, dsig.RSAPSSWithSHA256, payload, signature)
    if err != nil {
      fmt.Printf("failed to verify RSA signature: %s\n", err)
      return
    }
  }

  // ECDSA signing and verification
  {
    privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
    if err != nil {
      fmt.Printf("failed to generate ECDSA key: %s\n", err)
      return
    }

    // Sign with ECDSA P-256 SHA256
    signature, err := dsig.Sign(privKey, dsig.ECDSAWithP256AndSHA256, payload, nil)
    if err != nil {
      fmt.Printf("failed to sign with ECDSA: %s\n", err)
      return
    }

    // Verify with ECDSA P-256 SHA256
    err = dsig.Verify(&privKey.PublicKey, dsig.ECDSAWithP256AndSHA256, payload, signature)
    if err != nil {
      fmt.Printf("failed to verify ECDSA signature: %s\n", err)
      return
    }
  }

  // EdDSA signing and verification
  {
    pubKey, privKey, err := ed25519.GenerateKey(rand.Reader)
    if err != nil {
      fmt.Printf("failed to generate Ed25519 key: %s\n", err)
      return
    }

    // Sign with EdDSA
    signature, err := dsig.Sign(privKey, dsig.EdDSA, payload, nil)
    if err != nil {
      fmt.Printf("failed to sign with EdDSA: %s\n", err)
      return
    }

    // Verify with EdDSA
    err = dsig.Verify(pubKey, dsig.EdDSA, payload, signature)
    if err != nil {
      fmt.Printf("failed to verify EdDSA signature: %s\n", err)
      return
    }
  }

  // HMAC signing and verification
  {
    key := []byte("secret-key")

    // Sign with HMAC SHA256
    signature, err := dsig.Sign(key, dsig.HMACWithSHA256, payload, nil)
    if err != nil {
      fmt.Printf("failed to sign with HMAC: %s\n", err)
      return
    }

    // Verify with HMAC SHA256
    err = dsig.Verify(key, dsig.HMACWithSHA256, payload, signature)
    if err != nil {
      fmt.Printf("failed to verify HMAC signature: %s\n", err)
      return
    }
  }
  // OUTPUT:
}

source: examples/dsig_readme_example_test.go

Supported Algorithms

Constant Algorithm Key Type
HMACWithSHA256 HMAC using SHA-256 []byte
HMACWithSHA384 HMAC using SHA-384 []byte
HMACWithSHA512 HMAC using SHA-512 []byte
RSAPKCS1v15WithSHA256 RSA PKCS#1 v1.5 using SHA-256 *rsa.PrivateKey / *rsa.PublicKey
RSAPKCS1v15WithSHA384 RSA PKCS#1 v1.5 using SHA-384 *rsa.PrivateKey / *rsa.PublicKey
RSAPKCS1v15WithSHA512 RSA PKCS#1 v1.5 using SHA-512 *rsa.PrivateKey / *rsa.PublicKey
RSAPSSWithSHA256 RSA PSS using SHA-256 *rsa.PrivateKey / *rsa.PublicKey
RSAPSSWithSHA384 RSA PSS using SHA-384 *rsa.PrivateKey / *rsa.PublicKey
RSAPSSWithSHA512 RSA PSS using SHA-512 *rsa.PrivateKey / *rsa.PublicKey
ECDSAWithP256AndSHA256 ECDSA using P-256 and SHA-256 *ecdsa.PrivateKey / *ecdsa.PublicKey
ECDSAWithP384AndSHA384 ECDSA using P-384 and SHA-384 *ecdsa.PrivateKey / *ecdsa.PublicKey
ECDSAWithP521AndSHA512 ECDSA using P-521 and SHA-512 *ecdsa.PrivateKey / *ecdsa.PublicKey
EdDSA EdDSA using Ed25519 or Ed448 ed25519.PrivateKey / ed25519.PublicKey

Description

This library provides low-level digital signature operations. It does minimal parameter validation for performance, uses strongly typed APIs, and has minimal dependencies.

Contributions

Issues

For bug reports and feature requests, please include failing tests when possible.

Pull Requests

Please include tests that exercise your changes.

Documentation

Overview

Package dsig provides digital signature operations for Go. It contains low-level signature generation and verification tools that can be used by other signing libraries

The package follows these design principles: 1. Does minimal checking of input parameters (for performance); callers need to ensure that the parameters are valid. 2. All exported functions are strongly typed (i.e. they do not take `any` types unless they absolutely have to). 3. Does not rely on other high-level packages (standalone, except for internal packages).

Index

Constants

View Source
const (
	// HMAC signature algorithms
	// These use Hash-based Message Authentication Code with specified hash functions
	HMACWithSHA256 = "HMAC_WITH_SHA256"
	HMACWithSHA384 = "HMAC_WITH_SHA384"
	HMACWithSHA512 = "HMAC_WITH_SHA512"

	// RSA signature algorithms with PKCS#1 v1.5 padding
	// These use RSA signatures with PKCS#1 v1.5 padding and specified hash functions
	RSAPKCS1v15WithSHA256 = "RSA_PKCS1v15_WITH_SHA256"
	RSAPKCS1v15WithSHA384 = "RSA_PKCS1v15_WITH_SHA384"
	RSAPKCS1v15WithSHA512 = "RSA_PKCS1v15_WITH_SHA512"

	// RSA signature algorithms with PSS padding
	// These use RSA signatures with Probabilistic Signature Scheme (PSS) padding
	RSAPSSWithSHA256 = "RSA_PSS_WITH_SHA256"
	RSAPSSWithSHA384 = "RSA_PSS_WITH_SHA384"
	RSAPSSWithSHA512 = "RSA_PSS_WITH_SHA512"

	// ECDSA signature algorithms
	// These use Elliptic Curve Digital Signature Algorithm with specified curves and hash functions
	ECDSAWithP256AndSHA256 = "ECDSA_WITH_P256_AND_SHA256"
	ECDSAWithP384AndSHA384 = "ECDSA_WITH_P384_AND_SHA384"
	ECDSAWithP521AndSHA512 = "ECDSA_WITH_P521_AND_SHA512"

	// EdDSA signature algorithms
	// These use Edwards-curve Digital Signature Algorithm (supports Ed25519 and Ed448)
	EdDSA = "EDDSA"
)

Variables

This section is empty.

Functions

func IsVerificationError

func IsVerificationError(err error) bool

IsVerificationError checks if the given error is a verification error.

func NewVerificationError

func NewVerificationError(message string) error

NewVerificationError creates a new verification error with the given message.

func PackECDSASignature

func PackECDSASignature(r *big.Int, sbig *big.Int, curveBits int) ([]byte, error)

PackECDSASignature packs the r and s values from an ECDSA signature into a JWS-format byte slice. The output format follows RFC 7515: r||s as fixed-length byte arrays.

func RegisterAlgorithm

func RegisterAlgorithm(name string, info AlgorithmInfo) error

RegisterAlgorithm registers a new digital signature algorithm with the specified family and metadata.

info.Meta should contain extra metadata for some algorithms. HMAC, RSA, and ECDSA families need their respective metadata (HMACFamilyMeta, RSAFamilyMeta, and ECDSAFamilyMeta). Metadata for EdDSA is optional. For the Custom family, Meta must implement at least one of the Signer, SignerWithOpts, Verifier, or VerifierWithOpts interfaces.

Re-registration of an already-registered algorithm name is rejected. Use UnregisterAlgorithm to remove it first if you need to replace it.

func Sign

func Sign(key any, alg string, payload []byte, rr io.Reader) ([]byte, error)

Sign generates a digital signature using the specified key and algorithm.

rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader. Not all algorithms require this parameter, but it is included for consistency. 99% of the time, you can pass nil for rr, and it will work fine.

Deprecated in spirit: in the next major release of dsig (v2), the signature of Sign will change to match SignWithOpts, i.e. it will accept an additional crypto.SignerOpts parameter immediately before rr. Callers that need to pass per-call options today should use SignWithOpts; callers that do not can keep using Sign and migrate when v2 ships by threading a nil opts argument through at the call site.

func SignCryptoSigner

func SignCryptoSigner(signer crypto.Signer, raw []byte, h crypto.Hash, opts crypto.SignerOpts, rr io.Reader) ([]byte, error)

SignCryptoSigner generates a signature using a crypto.Signer interface. This function can be used for hardware security modules, smart cards, and other implementations of the crypto.Signer interface.

rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader.

Returns the signature bytes or an error if signing fails.

func SignDigest added in v1.2.1

func SignDigest(key any, alg string, digest []byte, rr io.Reader) ([]byte, error)

SignDigest generates a digital signature from a pre-computed digest.

For RSA/ECDSA, digest is the hash of the signing input and key is the private key used for signing.

For HMAC, the digest must be the pre-computed MAC (i.e. the output of hmac.New(hashFunc, key) after writing the signing input). The digest IS the signature, so it is returned as-is.

EdDSA and Custom families are not supported and return an error.

rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader.

Deprecated in spirit: in the next major release of dsig (v2), the signature of SignDigest will gain a crypto.SignerOpts parameter to align with Sign. No SignDigestWithOpts shim exists in v1 because Custom-family algorithms (the only ones that would benefit from per-call opts) are rejected outright today; once a DigestSigner interface for the Custom family is added, the opts parameter will appear at the same time.

func SignECDSA

func SignECDSA(key *ecdsa.PrivateKey, payload []byte, h crypto.Hash, rr io.Reader) ([]byte, error)

SignECDSA generates an ECDSA signature for the given payload using the specified private key and hash. The raw parameter should be the pre-computed signing input (typically header.payload).

rr is an io.Reader that provides randomness for signing. if rr is nil, it defaults to rand.Reader.

func SignECDSACryptoSigner

func SignECDSACryptoSigner(signer crypto.Signer, raw []byte, h crypto.Hash, rr io.Reader) ([]byte, error)

SignECDSACryptoSigner generates an ECDSA signature using a crypto.Signer interface. This function works with hardware security modules and other crypto.Signer implementations. The signature is converted from ASN.1 format to JWS format (r||s).

rr is an io.Reader that provides randomness for signing. If rr is nil, it defaults to rand.Reader.

func SignECDSADER added in v1.2.2

func SignECDSADER(key *ecdsa.PrivateKey, payload []byte, h crypto.Hash, rr io.Reader) ([]byte, error)

SignECDSADER generates an ECDSA signature in ASN.1 DER-encoded Ecdsa-Sig-Value format (RFC 3279 §2.2.3), as required by X.509/PKIX and composite signature schemes such as draft-ietf-lamps-pq-composite-sigs. For the fixed-length JWS r||s format (RFC 7515 §3.4), use SignECDSA instead.

The payload is hashed with h before signing. rr provides randomness; if nil, rand.Reader is used.

func SignEdDSA

func SignEdDSA(key ed25519.PrivateKey, payload []byte) ([]byte, error)

SignEdDSA generates an EdDSA (Ed25519) signature for the given payload. The raw parameter should be the pre-computed signing input (typically header.payload). EdDSA is deterministic and doesn't require additional hashing of the input.

func SignHMAC

func SignHMAC(key, payload []byte, hfunc func() hash.Hash) ([]byte, error)

SignHMAC generates an HMAC signature for the given payload using the specified hash function and key. The raw parameter should be the pre-computed signing input (typically header.payload).

func SignRSA

func SignRSA(key *rsa.PrivateKey, payload []byte, h crypto.Hash, pss bool, rr io.Reader) ([]byte, error)

SignRSA generates an RSA signature for the given payload using the specified private key and options. The raw parameter should be the pre-computed signing input (typically header.payload). If pss is true, RSA-PSS is used; otherwise, PKCS#1 v1.5 is used.

The rr parameter is an optional io.Reader that can be used to provide randomness for signing. If rr is nil, it defaults to rand.Reader.

func SignWithOpts added in v1.3.0

func SignWithOpts(key any, alg string, payload []byte, opts crypto.SignerOpts, rr io.Reader) ([]byte, error)

SignWithOpts is like Sign but threads an optional crypto.SignerOpts through to the underlying signer. For built-in families (HMAC, RSA, ECDSA, EdDSA) the opts argument is ignored — those algorithms have no per-call options the dsig layer understands. For Custom-family algorithms whose Meta implements SignerWithOpts, the opts are forwarded; otherwise the plain Signer.Sign method is called and opts are dropped.

This function exists as a transitional API. In the next major release of dsig (v2) it will be removed and its signature will become the canonical shape of Sign. Code that uses SignWithOpts today will need a mechanical rename to Sign (and nothing else) when v2 ships.

func UnpackASN1ECDSASignature

func UnpackASN1ECDSASignature(signed []byte, r, s *big.Int) error

UnpackASN1ECDSASignature unpacks an ASN.1 encoded ECDSA signature into r and s values. This is typically used when working with crypto.Signer interfaces that return ASN.1 encoded signatures.

func UnpackECDSASignature

func UnpackECDSASignature(signature []byte, pubkey *ecdsa.PublicKey, r, s *big.Int) error

UnpackECDSASignature unpacks a JWS-format ECDSA signature into r and s values. The signature should be in the format specified by RFC 7515 (r||s as fixed-length byte arrays).

func UnregisterAlgorithm added in v1.1.0

func UnregisterAlgorithm(name string) error

UnregisterAlgorithm removes a previously registered algorithm by name. Built-in algorithms cannot be unregistered. It is a no-op if the algorithm is not registered.

func Verify

func Verify(key any, alg string, payload, signature []byte) error

Verify verifies a digital signature using the specified key and algorithm.

Deprecated in spirit: in the next major release of dsig (v2), the signature of Verify will change to match VerifyWithOpts, i.e. it will accept an additional crypto.SignerOpts parameter at the end. Callers that need to pass per-call options today should use VerifyWithOpts; callers that do not can keep using Verify and migrate when v2 ships by threading a nil opts argument through at the call site.

func VerifyDigest added in v1.2.0

func VerifyDigest(key any, alg string, digest, signature []byte) error

VerifyDigest verifies a signature given a pre-computed digest.

For RSA/ECDSA, digest is the hash of the signing input and key is the public key used for verification.

For HMAC, digest must be the pre-computed MAC (i.e. the output of hmac.New(hashFunc, key) after writing the signing input). The key parameter is not used because it is already incorporated into the MAC.

EdDSA and Custom families are not supported and return an error.

Deprecated in spirit: in the next major release of dsig (v2), the signature of VerifyDigest will gain a crypto.SignerOpts parameter to align with Verify. No VerifyDigestWithOpts shim exists in v1 because Custom-family algorithms (the only ones that would benefit from per-call opts) are rejected outright today; once a DigestVerifier interface for the Custom family is added, the opts parameter will appear at the same time.

func VerifyECDSA

func VerifyECDSA(key *ecdsa.PublicKey, payload, signature []byte, h crypto.Hash) error

VerifyECDSA verifies an ECDSA signature for the given payload. This function verifies the signature using the specified public key and hash algorithm. The payload parameter should be the pre-computed signing input (typically header.payload).

func VerifyECDSACryptoSigner

func VerifyECDSACryptoSigner(signer crypto.Signer, payload, signature []byte, h crypto.Hash) error

VerifyECDSACryptoSigner verifies an ECDSA signature for crypto.Signer implementations. This function is useful for verifying signatures created by hardware security modules or other implementations of the crypto.Signer interface. The payload parameter should be the pre-computed signing input (typically header.payload).

func VerifyECDSADER added in v1.2.2

func VerifyECDSADER(key *ecdsa.PublicKey, payload, signature []byte, h crypto.Hash) error

VerifyECDSADER verifies an ECDSA signature in ASN.1 DER-encoded Ecdsa-Sig-Value format. See SignECDSADER for the format distinction. The payload is hashed with h before verification.

func VerifyECDSADigest added in v1.2.0

func VerifyECDSADigest(key *ecdsa.PublicKey, digest, signature []byte) error

VerifyECDSADigest verifies an ECDSA signature given a pre-computed digest. The caller is responsible for hashing the signing input with the correct hash function for the algorithm (e.g. SHA-256 for ES256). This function does not validate the digest length.

func VerifyEdDSA

func VerifyEdDSA(key ed25519.PublicKey, payload, signature []byte) error

VerifyEdDSA verifies an EdDSA (Ed25519) signature for the given payload. This function verifies the signature using Ed25519 verification algorithm. The payload parameter should be the pre-computed signing input (typically header.payload). EdDSA is deterministic and provides strong security guarantees without requiring hash function selection.

func VerifyHMAC

func VerifyHMAC(key, payload, signature []byte, hfunc func() hash.Hash) error

VerifyHMAC verifies an HMAC signature for the given payload. This function verifies the signature using the specified key and hash function. The payload parameter should be the pre-computed signing input (typically header.payload).

func VerifyHMACDigest added in v1.2.0

func VerifyHMACDigest(computedMAC, signature []byte) error

VerifyHMACDigest verifies an HMAC signature given a pre-computed MAC.

func VerifyRSA

func VerifyRSA(key *rsa.PublicKey, payload, signature []byte, h crypto.Hash, pss bool) error

VerifyRSA verifies an RSA signature for the given payload and header. This function constructs the signing input by encoding the header and payload according to JWS specification, then verifies the signature using the specified public key and hash algorithm. If pss is true, RSA-PSS verification is used; otherwise, PKCS#1 v1.5 verification is used.

func VerifyRSADigest added in v1.2.0

func VerifyRSADigest(key *rsa.PublicKey, digest, signature []byte, h crypto.Hash, pss bool) error

VerifyRSADigest verifies an RSA signature given a pre-computed digest. If pss is true, RSA-PSS verification is used; otherwise, PKCS#1 v1.5 is used.

func VerifyWithOpts added in v1.3.0

func VerifyWithOpts(key any, alg string, payload, signature []byte, opts crypto.SignerOpts) error

VerifyWithOpts is like Verify but threads an optional crypto.SignerOpts through to the underlying verifier. For built-in families (HMAC, RSA, ECDSA, EdDSA) the opts argument is ignored. For Custom-family algorithms whose Meta implements VerifierWithOpts, the opts are forwarded; otherwise the plain Verifier.Verify method is called and opts are dropped.

This function exists as a transitional API. In the next major release of dsig (v2) it will be removed and its signature will become the canonical shape of Verify. Code that uses VerifyWithOpts today will need a mechanical rename to Verify (and nothing else) when v2 ships.

Types

type AlgorithmInfo

type AlgorithmInfo struct {
	Family Family // The cryptographic family (HMAC, RSA, ECDSA, EdDSA)
	Meta   any    // Family-specific metadata
}

AlgorithmInfo contains metadata about a digital signature algorithm

func GetAlgorithmInfo

func GetAlgorithmInfo(name string) (AlgorithmInfo, bool)

GetAlgorithmInfo retrieves the algorithm information for a given algorithm name. Returns the info and true if found, zero value and false if not found.

type ECDSAFamilyMeta

type ECDSAFamilyMeta struct {
	Hash crypto.Hash // Hash algorithm
}

ECDSAFamilyMeta contains metadata specific to ECDSA algorithms

type EdDSAFamilyMeta

type EdDSAFamilyMeta struct {
}

EdDSAFamilyMeta contains metadata specific to EdDSA algorithms Currently EdDSA doesn't need specific metadata, but this provides extensibility

type Family

type Family int

Family represents the cryptographic algorithm family

const (
	InvalidFamily Family = iota
	HMAC
	RSA
	ECDSA
	EdDSAFamily
	Custom
)

func (Family) String

func (f Family) String() string

String returns the string representation of the Family

type HMACFamilyMeta

type HMACFamilyMeta struct {
	HashFunc func() hash.Hash // Hash function constructor
}

HMACFamilyMeta contains metadata specific to HMAC algorithms

type RSAFamilyMeta

type RSAFamilyMeta struct {
	Hash crypto.Hash // Hash algorithm
	PSS  bool        // Whether to use PSS padding (false = PKCS#1 v1.5)
}

RSAFamilyMeta contains metadata specific to RSA algorithms

type Signer added in v1.1.0

type Signer interface {
	Sign(key any, payload []byte, rand io.Reader) ([]byte, error)
}

Signer is an interface for custom signing implementations. For the Custom algorithm family, info.Meta must implement this interface to support signing. The implementation struct can carry any additional metadata it needs (hash functions, curves, etc.).

type SignerWithOpts added in v1.3.0

type SignerWithOpts interface {
	SignWithOpts(key any, payload []byte, opts crypto.SignerOpts, rand io.Reader) ([]byte, error)
}

SignerWithOpts is an optional interface that Custom-family signers can implement to receive a per-call crypto.SignerOpts. The canonical use case is ML-DSA, whose Sign method accepts an *mldsa.Options carrying a domain-separation context that the plain Signer interface cannot convey. Custom Meta values that do not implement this interface still work with SignWithOpts: the dispatcher falls back to the plain Signer.Sign method and the opts argument is dropped.

Implementing both Signer and SignerWithOpts is supported, but implementing only SignerWithOpts is sufficient because the dispatcher checks for it first.

type VerificationError

type VerificationError struct {
	// contains filtered or unexported fields
}

VerificationError represents an error that occurred during signature verification.

func (*VerificationError) Error

func (e *VerificationError) Error() string

type Verifier added in v1.1.0

type Verifier interface {
	Verify(key any, payload, signature []byte) error
}

Verifier is an interface for custom verification implementations. For the Custom algorithm family, info.Meta must implement this interface to support verification. The implementation struct can carry any additional metadata it needs (hash functions, curves, etc.).

type VerifierWithOpts added in v1.3.0

type VerifierWithOpts interface {
	VerifyWithOpts(key any, payload, signature []byte, opts crypto.SignerOpts) error
}

VerifierWithOpts is the verification counterpart of SignerWithOpts. See SignerWithOpts for usage notes.

Directories

Path Synopsis
internal
ecutil
Package ecutil defines tools that help with elliptic curve related computation
Package ecutil defines tools that help with elliptic curve related computation

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL