Documentation
¶
Overview ¶
Package crypto is a thin ergonomic layer on top of the normal golang crypto packages or `x/crypto`.
It aims to solve the following problems with the standard crypto packages:
- different algorithms have different APIs and ergonomics, which makes it hard to use them interchangeably
- occasionally, it's quite hard to figure out how to do simple tasks (like encoding/decoding keys)
- it's still necessary to make some educated choices (e.g. which hash function to use for signatures)
- sometimes features are left out (e.g. ed25519 to X25519 for key exchange, secp256k1...)
- some hash functions are not available in the standard library with no easy way to extend it (e.g. KECCAK-256)
To do so, this package provides and implements a set of shared interfaces for all algorithms. As not all algorithms support all features (e.g. RSA keys don't support key exchange), some interfaces are optionally implemented.
An additional benefit of shared interfaces is that a shared test suite can be written to test all algorithms, which this package does.
Example ¶
package main
import (
"bytes"
"encoding/base64"
"fmt"
"github.com/ucan-wg/go-varsig"
"code.sonr.org/go/did-it/crypto"
"code.sonr.org/go/did-it/crypto/p256"
)
func main() {
// This example demonstrates how to use the crypto package without going over all the features.
// We will use P-256 keys, but they all work the same way (although not all have all the features).
// 0: Generate a key pair
pubAlice, privAlice, err := p256.GenerateKeyPair()
handleErr(err)
// 1: Serialize a key, read it back, verify it's the same
privAliceBytes := privAlice.ToPKCS8DER()
privAlice2, err := p256.PrivateKeyFromPKCS8DER(privAliceBytes)
handleErr(err)
fmt.Println("Keys are equals:", privAlice.Equal(privAlice2))
// 2: Sign a message, verify the signature.
// Signatures can be made in raw bytes (SignToBytes) or ASN.1 DER format (SignToASN1).
msg := []byte("hello world")
sig, err := privAlice.SignToBytes(msg)
handleErr(err)
fmt.Println("Signature is valid:", pubAlice.VerifyBytes(msg, sig))
// 3: Signatures are done with an opinionated default configuration, but you can override it.
// For example, the default hash function for P-256 is SHA-256, but you can use SHA-384 instead.
opts := []crypto.SigningOption{crypto.WithSigningHash(crypto.SHA384)}
sig384, err := privAlice.SignToBytes(msg, opts...)
handleErr(err)
fmt.Println("Signature is valid (SHA-384):", pubAlice.VerifyBytes(msg, sig384, opts...))
// 4: Key exchange: generate a second key-pair and compute a shared secret.
// ⚠️ Security Warning: The shared secret returned by key agreement should NOT be used directly as an encryption key.
// It must be processed through a Key Derivation Function (KDF) such as HKDF before being used in cryptographic protocols.
// Using the raw shared secret directly can lead to security vulnerabilities.
pubBob, privBob, err := p256.GenerateKeyPair()
handleErr(err)
shared1, err := privAlice.KeyExchange(pubBob)
handleErr(err)
shared2, err := privBob.KeyExchange(pubAlice)
handleErr(err)
fmt.Println("Shared secrets are identical:", bytes.Equal(shared1, shared2))
// 5: Bonus: one very annoying thing in cryptographic protocols is that the other side needs to know the configuration
// you used for your signature. Having defaults or implied config only work sor far.
// To solve this problem, this package integrates varsig: a format to describe the signing configuration. This varsig
// can be attached to the signature, and the other side doesn't have to guess any more. Here is how it works:
varsigBytes := privAlice.Varsig(opts...).Encode()
fmt.Println("Varsig:", base64.StdEncoding.EncodeToString(varsigBytes))
sig, err = privAlice.SignToBytes(msg, opts...)
handleErr(err)
varsigDecoded, err := varsig.Decode(varsigBytes)
handleErr(err)
fmt.Println("Signature with varsig is valid:", pubAlice.VerifyBytes(msg, sig, crypto.WithVarsig(varsigDecoded)))
}
func handleErr(err error) {
if err != nil {
panic(err)
}
}
Output: Keys are equals: true Signature is valid: true Signature is valid (SHA-384): true Shared secrets are identical: true Varsig: NAHsAYAkIF8= Signature with varsig is valid: true
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Hash ¶
type Hash uint
Hash is similar to crypto.Hash but can be extended with more values.
const ( // From "crypto" MD4 Hash = 1 + iota // import golang.org/x/crypto/md4 MD5 // import crypto/md5 SHA1 // import crypto/sha1 SHA224 // import crypto/sha256 SHA256 // import crypto/sha256 SHA384 // import crypto/sha512 SHA512 // import crypto/sha512 MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA RIPEMD160 // import golang.org/x/crypto/ripemd160 SHA3_224 // import golang.org/x/crypto/sha3 SHA3_256 // import golang.org/x/crypto/sha3 SHA3_384 // import golang.org/x/crypto/sha3 SHA3_512 // import golang.org/x/crypto/sha3 SHA512_224 // import crypto/sha512 SHA512_256 // import crypto/sha512 BLAKE2s_256 // import golang.org/x/crypto/blake2s BLAKE2b_256 // import golang.org/x/crypto/blake2b BLAKE2b_384 // import golang.org/x/crypto/blake2b BLAKE2b_512 // import golang.org/x/crypto/blake2b // Extensions KECCAK_256 KECCAK_512 )
func FromVarsigHash ¶
FromVarsigHash converts a varsig.Hash value to the corresponding Hash value.
func (Hash) New ¶
New returns a new hash.Hash calculating the given hash function. New panics if the hash function is not linked into the binary.
func (Hash) ToVarsigHash ¶
ToVarsigHash returns the corresponding varsig.Hash value.
type PrivateKey ¶
type PrivateKey interface {
// Equal returns true if other is the same PrivateKey
Equal(other PrivateKey) bool
// Public returns the matching PublicKey.
Public() PublicKey
// ToPKCS8DER serializes the PrivateKey into the PKCS#8 DER (binary) format.
ToPKCS8DER() []byte
// ToPKCS8PEM serializes the PrivateKey into the PKCS#8 PEM (string) format.
ToPKCS8PEM() string
}
type PrivateKeyKeyExchange ¶
type PrivateKeyKeyExchange interface {
PrivateKey
// PublicKeyIsCompatible checks that the given PublicKey is compatible to perform key exchange.
PublicKeyIsCompatible(remote PublicKey) bool
// KeyExchange computes the shared key using the given PublicKey.
KeyExchange(remote PublicKey) ([]byte, error)
}
type PrivateKeySigningASN1 ¶
type PrivateKeySigningASN1 interface {
PrivateKey
// Varsig returns the varsig.Varsig corresponding to the given parameters and private key.
Varsig(opts ...SigningOption) varsig.Varsig
// SignToASN1 creates a signature in the ASN.1 format.
SignToASN1(message []byte, opts ...SigningOption) ([]byte, error)
}
type PrivateKeySigningBytes ¶
type PrivateKeySigningBytes interface {
PrivateKey
// Varsig returns the varsig.Varsig corresponding to the given parameters and private key.
Varsig(opts ...SigningOption) varsig.Varsig
// SignToBytes creates a signature in the "raw bytes" format.
// This format can make some assumptions and may not be what you expect.
// Ideally, this format is defined by the same specification as the underlying crypto scheme.
SignToBytes(message []byte, opts ...SigningOption) ([]byte, error)
}
type PrivateKeyToBytes ¶
type PrivateKeyToBytes interface {
PrivateKey
// ToBytes serializes the PrivateKey into "raw bytes", without metadata or structure.
// This format can make some assumptions and may not be what you expect.
// Ideally, this format is defined by the same specification as the underlying crypto scheme.
ToBytes() []byte
}
type PublicKey ¶
type PublicKey interface {
// Equal returns true if other is the same PublicKey
Equal(other PublicKey) bool
// ToPublicKeyMultibase format the PublicKey into a string compatible with a PublicKeyMultibase field
// in a DID Document.
ToPublicKeyMultibase() string
// ToX509DER serializes the PublicKey into the X.509 DER (binary) format.
ToX509DER() []byte
// ToX509PEM serializes the PublicKey into the X.509 PEM (string) format.
ToX509PEM() string
}
type PublicKeySigningASN1 ¶
type PublicKeySigningASN1 interface {
PublicKey
// VerifyASN1 checks a signature in the ASN.1 format.
VerifyASN1(message, signature []byte, opts ...SigningOption) bool
}
type PublicKeySigningBytes ¶
type PublicKeySigningBytes interface {
PublicKey
// VerifyBytes checks a signature in the "raw bytes" format.
// This format can make some assumptions and may not be what you expect.
// Ideally, this format is defined by the same specification as the underlying crypto scheme.
VerifyBytes(message, signature []byte, opts ...SigningOption) bool
}
type PublicKeyToBytes ¶
type PublicKeyToBytes interface {
PublicKey
// ToBytes serializes the PublicKey into "raw bytes", without metadata or structure.
// This format can make some assumptions and may not be what you expect.
// Ideally, this format is defined by the same specification as the underlying crypto scheme.
ToBytes() []byte
}
type SigningOption ¶
type SigningOption func(opts *SigningOpts)
func WithPayloadEncoding ¶
func WithPayloadEncoding(encoding varsig.PayloadEncoding) SigningOption
WithPayloadEncoding specify the encoding that was used on the message before signing it. This will be included in the resulting varsig.
func WithSigningHash ¶
func WithSigningHash(hash Hash) SigningOption
WithSigningHash specify the hash algorithm to be used for signatures
func WithVarsig ¶
func WithVarsig(vsig varsig.Varsig) SigningOption
WithVarsig configure the signing or verification parameters from a varsig. If you use WithVarsig, you should NOT use other options.
type SigningOpts ¶
type SigningOpts struct {
// contains filtered or unexported fields
}
SigningOpts contains the resulting signature configuration.
func CollectSigningOptions ¶
func CollectSigningOptions(opts []SigningOption) SigningOpts
CollectSigningOptions collects the signing options into a SigningOpts.
func (SigningOpts) HashOrDefault ¶
func (opts SigningOpts) HashOrDefault(_default Hash) Hash
HashOrDefault returns the hash algorithm to be used for signatures, or the default if not specified.
func (SigningOpts) PayloadEncoding ¶
func (opts SigningOpts) PayloadEncoding() varsig.PayloadEncoding
PayloadEncoding returns the encoding used on the message before signing it.
func (SigningOpts) VarsigMatch ¶
VarsigMatch returns true if the given varsig parameters match the signing options.