Documentation
¶
Overview ¶
Package crypto provides cryptographic primitives for DIDComm v2.1 messaging.
This package implements the cryptographic algorithms required by the DIDComm Messaging specification (https://identity.foundation/didcomm-messaging/spec/v2.1/).
Supported Algorithms ¶
Key Agreement (for encryption):
- ECDH-ES+A256KW: Ephemeral-Static ECDH with AES-256 Key Wrap (anoncrypt)
- ECDH-1PU+A256KW: ECDH-1PU with AES-256 Key Wrap (authcrypt)
Content Encryption:
- A256GCM: AES-256-GCM
- A256CBC-HS512: AES-256-CBC with HMAC-SHA-512
- XC20P: XChaCha20-Poly1305 (DIDComm anoncrypt default)
Signing:
- EdDSA: Ed25519
- ES256: ECDSA with P-256 and SHA-256
- ES256K: ECDSA with secp256k1 and SHA-256
Interoperability ¶
The implementation targets interoperability with the sicpa-dlab/didcomm-rust reference implementation. See the test/didcomm_interop directory for interoperability tests.
Package crypto provides cryptographic operations for DIDComm v2.1.
This package implements:
- JWE encryption (anoncrypt with ECDH-ES, authcrypt with ECDH-1PU)
- JWS signing for signed messages
- Key derivation for ECDH key agreement
Encryption Modes ¶
DIDComm supports two encryption modes:
Anoncrypt (Anonymous Encryption): Uses ECDH-ES for key agreement. The sender is anonymous and cannot be authenticated from the ciphertext.
encrypted, err := crypto.Anoncrypt(message, recipientKeys)
Authcrypt (Authenticated Encryption): Uses ECDH-1PU for key agreement. The sender is authenticated and the recipient can verify who sent the message.
encrypted, err := crypto.Authcrypt(message, senderKey, recipientKeys)
Content Encryption ¶
Supported content encryption algorithms:
- A256GCM (recommended for anoncrypt)
- A256CBC-HS512 (required for authcrypt)
Key Agreement Curves ¶
Supported curves for key agreement:
- X25519 (required)
- P-256 (required)
- P-384 (required)
Signing ¶
Supported signing algorithms:
- EdDSA with Ed25519 (required)
- ES256 with P-256 (required)
- ES256K with secp256k1 (required)
Index ¶
- Constants
- Variables
- func DIDCommAnoncryptDefaults() (keyAlg string, contentAlg string)
- func DIDCommAuthcryptDefaults() (keyAlg string, contentAlg string)
- func Decrypt(ctx context.Context, encrypted []byte, privateKey jwk.Key) ([]byte, error)
- func DecryptECDH1PU(ctx context.Context, encrypted []byte, ...) ([]byte, error)
- func DecryptWithKeyStore(ctx context.Context, encrypted []byte, keyStore KeyStore) ([]byte, error)
- func Encrypt(ctx context.Context, plaintext []byte, recipientKeys []jwk.Key, ...) ([]byte, error)
- func GenerateContentEncryptionKey(enc string) ([]byte, error)
- func GenerateSecp256k1Key() (jwk.Key, error)
- func GenerateSecp256k1KeyWithID(keyID string) (jwk.Key, error)
- func InteropSafeAnoncryptDefaults() (keyAlg string, contentAlg string)
- func Sign(ctx context.Context, plaintext []byte, privateKey jwk.Key, opts SignOptions) ([]byte, error)
- func Verify(ctx context.Context, signed []byte, publicKey jwk.Key) ([]byte, error)
- func VerifyWithResolver(ctx context.Context, signed []byte, resolver KeyResolver) ([]byte, error)
- type AlgorithmSupport
- type ContentAlgorithmInfo
- type ContentEncryptor
- type ECDH1PUKeyAgreement
- func (e *ECDH1PUKeyAgreement) DeriveKey() ([]byte, jwk.Key, error)
- func (e *ECDH1PUKeyAgreement) DeriveKeyForDecryption(ephemeralPubKey jwk.Key, senderPubKey jwk.Key) ([]byte, error)
- func (e *ECDH1PUKeyAgreement) DeriveKeyWithTag(ccTag []byte) ([]byte, jwk.Key, error)
- func (e *ECDH1PUKeyAgreement) GenerateEphemeralKey() error
- type EncryptedMessage
- type EncryptionOptions
- type JWEHeader
- type JWSHeader
- type KeyAlgorithmInfo
- type KeyResolver
- type KeyStore
- type Recipient
- type RecipientHeader
- type Secp256k1Signer
- type Secp256k1Verifier
- type SignOptions
- type Signature
- type SignedMessage
- type XC20PAEAD
- func (x *XC20PAEAD) Decrypt(ciphertext, aad []byte) ([]byte, error)
- func (x *XC20PAEAD) DecryptSeparate(nonce, ciphertext, tag, aad []byte) ([]byte, error)
- func (x *XC20PAEAD) DecryptWithNonce(nonce, ciphertext, aad []byte) ([]byte, error)
- func (x *XC20PAEAD) Encrypt(plaintext, aad []byte) ([]byte, error)
- func (x *XC20PAEAD) EncryptSeparate(nonce, plaintext, aad []byte) (ciphertext, tag []byte, err error)
- func (x *XC20PAEAD) EncryptWithNonce(nonce, plaintext, aad []byte) ([]byte, error)
- func (x *XC20PAEAD) KeySize() int
- func (x *XC20PAEAD) NonceSize() int
- func (x *XC20PAEAD) Overhead() int
Constants ¶
const ( AlgECDHESA256KW = "ECDH-ES+A256KW" // ECDH-ES with AES-256 Key Wrap (anoncrypt) AlgECDHESA128KW = "ECDH-ES+A128KW" // ECDH-ES with AES-128 Key Wrap AlgECDH1PUA256KW = "ECDH-1PU+A256KW" // ECDH-1PU with AES-256 Key Wrap (authcrypt) )
Key Agreement Algorithms
const ( EncA256GCM = "A256GCM" // AES-256-GCM content encryption EncA256CBCHS512 = "A256CBC-HS512" // AES-256-CBC with HMAC-SHA-512 EncXC20P = "XC20P" // XChaCha20-Poly1305 content encryption (DIDComm default for anoncrypt) EncA128GCM = "A128GCM" // AES-128-GCM content encryption EncA128CBCHS256 = "A128CBC-HS256" // AES-128-CBC with HMAC-SHA-256 )
Content Encryption Algorithms
const ( SigEdDSA = "EdDSA" // EdDSA signing (Ed25519) SigES256 = "ES256" // ECDSA with P-256 and SHA-256 SigES256K = "ES256K" // ECDSA with secp256k1 and SHA-256 SigES384 = "ES384" // ECDSA with P-384 and SHA-384 SigES512 = "ES512" // ECDSA with P-521 and SHA-512 )
Signing Algorithms
const ( CurveX25519 = "X25519" // Curve25519 for key agreement CurveEd25519 = "Ed25519" // Ed25519 for signing CurveP256 = "P-256" // NIST P-256 CurveP384 = "P-384" // NIST P-384 CurveP521 = "P-521" // NIST P-521 CurveSecp256k1 = "secp256k1" // secp256k1 (Bitcoin/Ethereum curve) )
Curve names
const ( // XC20PKeySize is the key size for XChaCha20-Poly1305 (256 bits) XC20PKeySize = chacha20poly1305.KeySize // 32 bytes // XC20PNonceSize is the nonce size for XChaCha20-Poly1305 (192 bits) XC20PNonceSize = chacha20poly1305.NonceSizeX // 24 bytes // XC20PTagSize is the authentication tag size (128 bits) XC20PTagSize = 16 )
Variables ¶
var ( ErrEncryptionFailed = errors.New("didcomm/crypto: encryption failed") ErrDecryptionFailed = errors.New("didcomm/crypto: decryption failed") ErrSigningFailed = errors.New("didcomm/crypto: signing failed") ErrVerificationFailed = errors.New("didcomm/crypto: verification failed") ErrUnsupportedAlgorithm = errors.New("didcomm/crypto: unsupported algorithm") ErrInvalidKey = errors.New("didcomm/crypto: invalid key") ErrInvalidNonce = errors.New("didcomm/crypto: invalid nonce") ErrNoRecipients = errors.New("didcomm/crypto: no recipients specified") ErrRecipientNotFound = errors.New("didcomm/crypto: recipient key not found") ErrInvalidJWE = errors.New("didcomm/crypto: invalid JWE") ErrInvalidJWS = errors.New("didcomm/crypto: invalid JWS") )
Sentinel errors for cryptographic operations.
Functions ¶
func DIDCommAnoncryptDefaults ¶
DIDCommAnoncryptDefaults returns the default algorithms for DIDComm anoncrypt.
func DIDCommAuthcryptDefaults ¶
DIDCommAuthcryptDefaults returns the default algorithms for DIDComm authcrypt.
func Decrypt ¶
Decrypt decrypts a JWE using the provided private key. Supports both standard JOSE algorithms via jwx and custom algorithms (XC20P, ECDH-1PU).
func DecryptECDH1PU ¶
func DecryptECDH1PU(ctx context.Context, encrypted []byte, recipientPrivateKey, senderPublicKey jwk.Key) ([]byte, error)
DecryptECDH1PU decrypts a JWE that uses ECDH-1PU (authcrypt). Requires the recipient's private key and the sender's public key.
func DecryptWithKeyStore ¶
DecryptWithKeyStore decrypts a JWE using a key store to find the appropriate key.
func Encrypt ¶
func Encrypt(ctx context.Context, plaintext []byte, recipientKeys []jwk.Key, opts EncryptionOptions) ([]byte, error)
Encrypt encrypts a plaintext message for the given recipients. Returns a JWE compact serialization or JSON serialization depending on recipient count.
For algorithms not natively supported by jwx (XC20P, ECDH-1PU), this function delegates to custom implementations.
func GenerateContentEncryptionKey ¶
GenerateContentEncryptionKey generates a random key for the specified content encryption algorithm.
func GenerateSecp256k1Key ¶
GenerateSecp256k1Key generates a new secp256k1 key pair.
func GenerateSecp256k1KeyWithID ¶
GenerateSecp256k1KeyWithID generates a new secp256k1 key pair with a key ID.
func InteropSafeAnoncryptDefaults ¶
InteropSafeAnoncryptDefaults returns anoncrypt algorithms that work with jwx natively. Use these for immediate interoperability before XC20P is implemented.
func Sign ¶
func Sign(ctx context.Context, plaintext []byte, privateKey jwk.Key, opts SignOptions) ([]byte, error)
Sign creates a JWS signature over the plaintext using the private key.
func VerifyWithResolver ¶
VerifyWithResolver verifies a JWS using a resolver to fetch the public key.
Types ¶
type AlgorithmSupport ¶
type AlgorithmSupport int
AlgorithmSupport indicates the support level for an algorithm.
const ( SupportNative AlgorithmSupport = iota // Algorithm is natively supported by jwx SupportCustom // We have a custom implementation SupportNotImplemented // Algorithm is recognized but not yet implemented SupportUnknown // Algorithm is not recognized )
type ContentAlgorithmInfo ¶
type ContentAlgorithmInfo struct {
Name string
Support AlgorithmSupport
KeySize int // Required key size in bytes
NonceSize int // Required nonce size in bytes
TagSize int // Authentication tag size in bytes
}
ContentAlgorithmInfo contains information about a content encryption algorithm.
func GetContentAlgorithmInfo ¶
func GetContentAlgorithmInfo(enc string) (ContentAlgorithmInfo, bool)
GetContentAlgorithmInfo returns information about a content encryption algorithm.
type ContentEncryptor ¶
type ContentEncryptor interface {
// Encrypt encrypts plaintext with AAD, generating a random nonce
Encrypt(plaintext, aad []byte) ([]byte, error)
// EncryptWithNonce encrypts plaintext with a specific nonce
EncryptWithNonce(nonce, plaintext, aad []byte) ([]byte, error)
// Decrypt decrypts ciphertext (with prepended nonce) using AAD
Decrypt(ciphertext, aad []byte) ([]byte, error)
// DecryptWithNonce decrypts ciphertext with a specific nonce
DecryptWithNonce(nonce, ciphertext, aad []byte) ([]byte, error)
// KeySize returns the required key size in bytes
KeySize() int
// NonceSize returns the required nonce size in bytes
NonceSize() int
// Overhead returns the authentication tag overhead
Overhead() int
}
ContentEncryptor is an interface for content encryption algorithms.
func NewContentEncryptor ¶
func NewContentEncryptor(algorithm string, key []byte) (ContentEncryptor, error)
NewContentEncryptor creates a ContentEncryptor for the specified algorithm.
type ECDH1PUKeyAgreement ¶
type ECDH1PUKeyAgreement struct {
// SenderPrivateKey is the sender's static private key
SenderPrivateKey jwk.Key
// RecipientPublicKey is the recipient's static public key
RecipientPublicKey jwk.Key
// EphemeralPrivateKey is the sender's ephemeral private key (generated per message)
EphemeralPrivateKey jwk.Key
// Algorithm is the key wrapping algorithm (e.g., "ECDH-1PU+A256KW")
Algorithm string
// ContentEncryption is the content encryption algorithm (e.g., "A256CBC-HS512")
ContentEncryption string
// APU is Agreement PartyU Info (sender identifier, typically base64url-encoded DID)
APU []byte
// APV is Agreement PartyV Info (recipient identifier)
APV []byte
// CCTag is the content ciphertext authentication tag (used in ECDH-1PU KDF per draft-madden-jose-ecdh-1pu)
// This binds the key derivation to the specific ciphertext, providing key commitment.
CCTag []byte
}
ECDH1PUKeyAgreement performs ECDH-1PU key agreement.
func NewECDH1PU ¶
func NewECDH1PU(senderKey, recipientKey jwk.Key, algorithm, contentEnc string) (*ECDH1PUKeyAgreement, error)
NewECDH1PU creates a new ECDH-1PU key agreement instance. For encryption: senderKey must be the sender's private key, recipientKey is recipient's public key. For decryption: senderKey can be nil, recipientKey must be the recipient's private key.
func (*ECDH1PUKeyAgreement) DeriveKey ¶
func (e *ECDH1PUKeyAgreement) DeriveKey() ([]byte, jwk.Key, error)
DeriveKey derives the content encryption key using ECDH-1PU. Returns the derived key and the ephemeral public key (for inclusion in JWE header). Note: This method does NOT include the cc_tag. Use DeriveKeyWithTag for ECDH-1PU key commitment.
func (*ECDH1PUKeyAgreement) DeriveKeyForDecryption ¶
func (e *ECDH1PUKeyAgreement) DeriveKeyForDecryption(ephemeralPubKey jwk.Key, senderPubKey jwk.Key) ([]byte, error)
DeriveKeyForDecryption derives the key for decryption given the ephemeral public key.
func (*ECDH1PUKeyAgreement) DeriveKeyWithTag ¶
DeriveKeyWithTag derives the key using ECDH-1PU with optional key commitment (cc_tag). If ccTag is nil or empty, uses standard Concat KDF. If ccTag is provided, includes the content ciphertext authentication tag in the KDF per draft-madden-jose-ecdh-1pu for key commitment. Returns the derived key and the ephemeral public key.
func (*ECDH1PUKeyAgreement) GenerateEphemeralKey ¶
func (e *ECDH1PUKeyAgreement) GenerateEphemeralKey() error
GenerateEphemeralKey generates a new ephemeral key pair for the key agreement. The curve is determined by the recipient's public key.
type EncryptedMessage ¶
type EncryptedMessage struct {
// Protected is the base64url-encoded protected header
Protected string `json:"protected"`
// Recipients contains per-recipient encrypted key material
Recipients []Recipient `json:"recipients"`
// IV is the initialization vector (base64url-encoded)
IV string `json:"iv"`
// Ciphertext is the encrypted content (base64url-encoded)
Ciphertext string `json:"ciphertext"`
// Tag is the authentication tag (base64url-encoded)
Tag string `json:"tag"`
// AAD is additional authenticated data (base64url-encoded), optional
AAD string `json:"aad,omitempty"`
}
EncryptedMessage represents a DIDComm encrypted message (JWE).
type EncryptionOptions ¶
type EncryptionOptions struct {
// Algorithm is the key agreement algorithm. Default: ECDH-ES (anoncrypt)
Algorithm string
// Encryption is the content encryption algorithm. Default: A256GCM
Encryption string
// SenderKey is the sender's private key (required for ECDH-1PU authcrypt)
SenderKey jwk.Key
// SenderDID is the sender's DID (for APU)
SenderDID string
}
EncryptionOptions configures encryption behavior.
func AuthcryptOptions ¶
func AuthcryptOptions(senderKey jwk.Key, senderDID string) EncryptionOptions
AuthcryptOptions returns options for authenticated encryption (authcrypt).
func DefaultEncryptionOptions ¶
func DefaultEncryptionOptions() EncryptionOptions
DefaultEncryptionOptions returns options for anonymous encryption (anoncrypt).
type JWEHeader ¶
type JWEHeader struct {
// Algorithm is the key agreement algorithm (e.g., ECDH-ES, ECDH-1PU)
Algorithm string `json:"alg"`
// Encryption is the content encryption algorithm (e.g., A256GCM, A256CBC-HS512)
Encryption string `json:"enc"`
// Type is the media type of the JWE (should be "didcomm-encrypted+json")
Type string `json:"typ,omitempty"`
// SenderKeyID is the sender's key ID (for ECDH-1PU authcrypt)
SenderKeyID string `json:"skid,omitempty"`
// AgreementPartyUInfo is the APU for ECDH (base64url-encoded sender DID)
AgreementPartyUInfo string `json:"apu,omitempty"`
// AgreementPartyVInfo is the APV for ECDH (base64url-encoded recipient DIDs hash)
AgreementPartyVInfo string `json:"apv,omitempty"`
// EphemeralPublicKey is the ephemeral public key used for ECDH key agreement
EphemeralPublicKey json.RawMessage `json:"epk,omitempty"`
}
JWEHeader represents the protected header of a JWE.
type JWSHeader ¶
type JWSHeader struct {
// Algorithm is the signing algorithm (EdDSA, ES256, ES256K)
Algorithm string `json:"alg"`
// KeyID identifies the signing key
KeyID string `json:"kid,omitempty"`
// Type is the media type (should be "didcomm-signed+json")
Type string `json:"typ,omitempty"`
}
JWSHeader represents the protected header of a JWS.
type KeyAlgorithmInfo ¶
type KeyAlgorithmInfo struct {
Name string
Support AlgorithmSupport
RequiresSenderKey bool // Indicates if the algorithm requires a sender key (authcrypt)
}
KeyAlgorithmInfo contains information about a key agreement algorithm.
func GetKeyAlgorithmInfo ¶
func GetKeyAlgorithmInfo(alg string) (KeyAlgorithmInfo, bool)
GetKeyAlgorithmInfo returns information about a key agreement algorithm.
type KeyResolver ¶
KeyResolver resolves public keys by key ID.
type KeyStore ¶
type KeyStore interface {
// GetPrivateKey retrieves a private key by key ID
GetPrivateKey(ctx context.Context, kid string) (jwk.Key, error)
// ListKeyIDs returns all available key IDs
ListKeyIDs(ctx context.Context) ([]string, error)
}
KeyStore provides access to private keys for decryption.
type Recipient ¶
type Recipient struct {
// Header contains per-recipient unprotected header
Header RecipientHeader `json:"header"`
// EncryptedKey is the encrypted content encryption key (base64url-encoded)
EncryptedKey string `json:"encrypted_key"`
}
Recipient represents a JWE recipient.
type RecipientHeader ¶
type RecipientHeader struct {
// KeyID identifies the recipient's key
KeyID string `json:"kid"`
// EphemeralPublicKey is the sender's ephemeral public key
EphemeralPublicKey json.RawMessage `json:"epk,omitempty"`
}
RecipientHeader contains per-recipient JWE header parameters.
type Secp256k1Signer ¶
type Secp256k1Signer struct {
// contains filtered or unexported fields
}
Secp256k1Signer implements JWS signing using ES256K.
func NewSecp256k1Signer ¶
func NewSecp256k1Signer(key jwk.Key) (*Secp256k1Signer, error)
NewSecp256k1Signer creates a new ES256K signer from a JWK.
func (*Secp256k1Signer) KeyID ¶
func (s *Secp256k1Signer) KeyID() string
KeyID returns the key ID if available.
func (*Secp256k1Signer) PublicKey ¶
func (s *Secp256k1Signer) PublicKey() (jwk.Key, error)
PublicKey returns the public key as a JWK.
type Secp256k1Verifier ¶
type Secp256k1Verifier struct {
// contains filtered or unexported fields
}
Secp256k1Verifier implements JWS verification using ES256K.
func NewSecp256k1Verifier ¶
func NewSecp256k1Verifier(key jwk.Key) (*Secp256k1Verifier, error)
NewSecp256k1Verifier creates a new ES256K verifier from a JWK.
func (*Secp256k1Verifier) Verify ¶
func (v *Secp256k1Verifier) Verify(payload, signature []byte) error
Verify verifies a raw signature against the payload.
type SignOptions ¶
type SignOptions struct {
// Algorithm is the signing algorithm. If empty, inferred from key type.
Algorithm string
// Detached indicates whether to use detached payload
Detached bool
}
SignOptions configures signing behavior.
type Signature ¶
type Signature struct {
// Protected is the base64url-encoded protected header
Protected string `json:"protected"`
// Signature is the base64url-encoded signature value
Signature string `json:"signature"`
}
Signature represents a single JWS signature.
type SignedMessage ¶
type SignedMessage struct {
// Payload is the base64url-encoded message
Payload string `json:"payload"`
// Signatures contains one or more signatures
Signatures []Signature `json:"signatures"`
}
SignedMessage represents a DIDComm signed message (JWS).
type XC20PAEAD ¶
type XC20PAEAD struct {
// contains filtered or unexported fields
}
XC20PAEAD wraps the XChaCha20-Poly1305 AEAD cipher for DIDComm use.
func NewXC20P ¶
NewXC20P creates a new XChaCha20-Poly1305 AEAD instance. The key must be exactly 32 bytes (256 bits).
func (*XC20PAEAD) Decrypt ¶
Decrypt decrypts ciphertext that was encrypted with Encrypt. The input should be: nonce (24 bytes) || ciphertext || tag (16 bytes)
func (*XC20PAEAD) DecryptSeparate ¶
DecryptSeparate decrypts ciphertext with a separate tag. This is useful for JWE decryption where ciphertext and tag are separate fields.
func (*XC20PAEAD) DecryptWithNonce ¶
DecryptWithNonce decrypts ciphertext using a specific nonce. The ciphertext should NOT include the nonce prefix. Input format: ciphertext || tag (16 bytes)
func (*XC20PAEAD) Encrypt ¶
Encrypt encrypts plaintext with additional authenticated data (AAD). Returns the ciphertext with the authentication tag appended. A random nonce is generated and prepended to the ciphertext.
Output format: nonce (24 bytes) || ciphertext || tag (16 bytes)
func (*XC20PAEAD) EncryptSeparate ¶
func (x *XC20PAEAD) EncryptSeparate(nonce, plaintext, aad []byte) (ciphertext, tag []byte, err error)
EncryptSeparate encrypts plaintext and returns ciphertext and tag separately. This is useful for JWE construction where ciphertext and tag are separate fields.
func (*XC20PAEAD) EncryptWithNonce ¶
EncryptWithNonce encrypts plaintext using a specific nonce. This is useful for deterministic testing or when the nonce is derived from other data.
Output format: nonce (24 bytes) || ciphertext || tag (16 bytes)