crypto

package
v0.0.0-...-efe2ce5 Latest Latest
Warning

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

Go to latest
Published: Apr 25, 2024 License: Apache-2.0, MIT Imports: 14 Imported by: 0

Documentation

Overview

Package crypto provides cryptographic keys and operations, as used in atproto (the protocol)

This package attempts to abstract away the specific curves, compressions, signature variations, and other implementation details. The goal is to provide as few knobs and options as possible when working with this library. Use of cryptography in atproto is specified in https://atproto.com/specs/cryptography.

The two currently supported curve types are:

"Low-S" signatures are enforced for both key types, both when creating signatures and during verification, as required by the atproto specification.

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrInvalidSignature = errors.New("crytographic signature invalid")

Functions

This section is empty.

Types

type PrivateKey

type PrivateKey interface {
	Equal(other PrivateKey) bool

	PublicKey() (PublicKey, error)

	// Hashes the raw bytes using SHA-256, then signs the digest bytes.
	// Always returns a "low-S" signature (for elliptic curve systems where that is ambiguous).
	HashAndSign(content []byte) ([]byte, error)
}

Common interface for all the supported atproto cryptographic systems, when secret key material may not be directly available to be exported as bytes.

Example
// create secure private key, and corresponding public key
priv, err := GeneratePrivateKeyK256()
if err != nil {
	panic("failed to generate key")
}
pub, err := priv.PublicKey()
if err != nil {
	panic("failed to get public key")
}

// sign a message
msg := []byte("hello world")
sig, _ := priv.HashAndSign(msg)

// verify the message
if err = pub.HashAndVerify(msg, sig); err != nil {
	fmt.Println("Verification Failed")
} else {
	fmt.Println("Success!")
}
Output:

Success!

type PrivateKeyExportable

type PrivateKeyExportable interface {
	PrivateKey

	// Untyped (no multicodec) encoding of the secret key material.
	// The encoding format is curve-specific, and is generally "compact" for private keys.
	// No ASN.1 or other enclosing structure is applied to the bytes.
	Bytes() []byte
}

Common interface for all the supported atproto cryptographic systems, when secret key material is directly available to be exported as bytes.

func ParsePrivateMultibase

func ParsePrivateMultibase(encoded string) (PrivateKeyExportable, error)

Loads a private key from multibase string encoding, with multicodec indicating the key type.

type PrivateKeyK256

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

Implements the PrivateKeyExportable and PrivateKey interfaces for the NIST K-256 / secp256k1 / ES256K cryptographic curve. Secret key material is naively stored in memory.

func GeneratePrivateKeyK256

func GeneratePrivateKeyK256() (*PrivateKeyK256, error)

Creates a secure new cryptographic key from scratch, with the indicated curve type.

func ParsePrivateBytesK256

func ParsePrivateBytesK256(data []byte) (*PrivateKeyK256, error)

Loads a PrivateKeyK256 from raw bytes, as exported by the PrivateKey.Bytes method.

Calling code needs to know the key type ahead of time, and must remove any string encoding (hex encoding, base64, etc) before calling this function.

func (PrivateKeyK256) Bytes

func (k PrivateKeyK256) Bytes() []byte

Serializes the secret key material in to a raw binary format, which can be parsed by ParsePrivateBytesK256.

For K-256, this is the "compact" encoding and is 32 bytes long. There is no ASN.1 or other enclosing structure.

func (*PrivateKeyK256) Equal

func (k *PrivateKeyK256) Equal(other PrivateKey) bool

Checks if the two private keys are the same. Note that the naive == operator does not work for most equality checks.

func (PrivateKeyK256) HashAndSign

func (k PrivateKeyK256) HashAndSign(content []byte) ([]byte, error)

First hashes the raw bytes, then signs the digest, returning a binary signature.

SHA-256 is the hash algorithm used, as specified by atproto. Signing digests is the norm for ECDSA, and required by some backend implementations. This method does not "double hash", it simply has name which clarifies that hashing is happening.

Calling code is responsible for any string encoding of signatures (eg, hex or base64). For K-256, the signature is 64 bytes long.

NIST ECDSA signatures can have a "malleability" issue, meaning that there are multiple valid signatures for the same content with the same signing key. This method always returns a "low-S" signature, as required by atproto.

func (*PrivateKeyK256) Multibase

func (k *PrivateKeyK256) Multibase() string

Multibase string encoding of the private key, including a multicodec indicator

func (PrivateKeyK256) PublicKey

func (k PrivateKeyK256) PublicKey() (PublicKey, error)

Outputs the PublicKey corresponding to this PrivateKeyK256; it will be a PublicKeyK256.

type PrivateKeyP256

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

Implements the PrivateKeyExportable and PrivateKey interfaces for the NIST P-256 / secp256r1 / ES256 cryptographic curve. Secret key material is naively stored in memory.

func GeneratePrivateKeyP256

func GeneratePrivateKeyP256() (*PrivateKeyP256, error)

Creates a secure new cryptographic key from scratch.

func ParsePrivateBytesP256

func ParsePrivateBytesP256(data []byte) (*PrivateKeyP256, error)

Loads a PrivateKeyP256 from raw bytes, as exported by the PrivateKeyP256.Bytes method.

Calling code needs to know the key type ahead of time, and must remove any string encoding (hex encoding, base64, etc) before calling this function.

func (*PrivateKeyP256) Bytes

func (k *PrivateKeyP256) Bytes() []byte

Serializes the secret key material in to a raw binary format, which can be parsed by ParsePrivateBytesP256.

For P-256, this is the "compact" encoding and is 32 bytes long. There is no ASN.1 or other enclosing structure.

func (*PrivateKeyP256) Equal

func (k *PrivateKeyP256) Equal(other PrivateKey) bool

Checks if the two private keys are the same. Note that the naive == operator does not work for most equality checks.

func (*PrivateKeyP256) HashAndSign

func (k *PrivateKeyP256) HashAndSign(content []byte) ([]byte, error)

First hashes the raw bytes, then signs the digest, returning a binary signature.

SHA-256 is the hash algorithm used, as specified by atproto. Signing digests is the norm for ECDSA, and required by some backend implementations. This method does not "double hash", it simply has name which clarifies that hashing is happening.

Calling code is responsible for any string encoding of signatures (eg, hex or base64). For P-256, the signature is 64 bytes long.

NIST ECDSA signatures can have a "malleability" issue, meaning that there are multiple valid signatures for the same content with the same signing key. This method always returns a "low-S" signature, as required by atproto.

func (*PrivateKeyP256) Multibase

func (k *PrivateKeyP256) Multibase() string

Multibase string encoding of the private key, including a multicodec indicator

func (*PrivateKeyP256) PublicKey

func (k *PrivateKeyP256) PublicKey() (PublicKey, error)

Outputs the PublicKey corresponding to this PrivateKeyP256; it will be a PublicKeyP256.

type PublicKey

type PublicKey interface {
	Equal(other PublicKey) bool

	// Compact byte serialization (for elliptic curve systems where encoding is ambiguous).
	Bytes() []byte

	// Hashes the raw bytes using SHA-256, then verifies the signature of the digest bytes.
	HashAndVerify(content, sig []byte) error

	// Same as HashAndVerify(), only does not require "low-S" signature. Used for, eg, JWT validation.
	HashAndVerifyLenient(content, sig []byte) error

	// String serialization of the key bytes using common parameters:
	// compressed byte serialization; multicode varint code prefix; base58btc
	// string encoding ("z" prefix)
	Multibase() string

	// String serialization of the key bytes as a did:key.
	DIDKey() string

	// Non-compact byte serialization (for elliptic curve systems where
	// encoding is ambiguous)
	//
	// This is not used frequently, or directly in atproto, but some
	// serializations and encodings require it.
	//
	// For systems with no compressed/uncompressed distinction, returns the same
	// value as Bytes().
	UncompressedBytes() []byte
}

Common interface for all the supported atproto cryptographic systems.

Example
pub, err := ParsePublicDIDKey("did:key:zDnaembgSGUhZULN2Caob4HLJPaxBh92N7rtH21TErzqf8HQo")
if err != nil {
	panic("failed to parse did:key")
}

// parse existing base64 message and signature to raw bytes
msg, _ := base64.RawStdEncoding.DecodeString("oWVoZWxsb2V3b3JsZA")
sig, _ := base64.RawStdEncoding.DecodeString("2vZNsG3UKvvO/CDlrdvyZRISOFylinBh0Jupc6KcWoJWExHptCfduPleDbG3rko3YZnn9Lw0IjpixVmexJDegg")
if err = pub.HashAndVerify(msg, sig); err != nil {
	fmt.Println("Verification Failed")
} else {
	fmt.Println("Success!")
}
Output:

Success!

func ParsePublicDIDKey

func ParsePublicDIDKey(didKey string) (PublicKey, error)

Loads a PublicKey from did:key string serialization.

The did:key format encodes the key type.

func ParsePublicMultibase

func ParsePublicMultibase(encoded string) (PublicKey, error)

Loads a public key from multibase string encoding, with multicodec indicating the key type.

type PublicKeyK256

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

K-256 / secp256k1 / ES256K Implements the PublicKey interface for the NIST K-256 / secp256k1 / ES256K cryptographic curve.

func ParsePublicBytesK256

func ParsePublicBytesK256(data []byte) (*PublicKeyK256, error)

Loads a PublicKeyK256 raw bytes, as exported by the PublicKey.Bytes method. This is the "compressed" curve format.

Calling code needs to know the key type ahead of time, and must remove any string encoding (hex encoding, base64, etc) before calling this function.

func ParsePublicUncompressedBytesK256

func ParsePublicUncompressedBytesK256(data []byte) (*PublicKeyK256, error)

Loads a PublicKeyK256 from raw bytes, as exported by the PublicKey.UncompressedBytes method.

Calling code needs to know the key type ahead of time, and must remove any string encoding (hex encoding, base64, etc) before calling this function.

func (*PublicKeyK256) Bytes

func (k *PublicKeyK256) Bytes() []byte

Serializes the key in to "compressed" binary format.

func (*PublicKeyK256) DIDKey

func (k *PublicKeyK256) DIDKey() string

Returns a did:key string encoding of the public key, as would be encoded in a DID PLC operation:

  • compressed / compacted binary representation
  • prefix with appropriate curve multicodec bytes
  • encode bytes with base58btc
  • add "z" prefix to indicate encoding
  • add "did:key:" prefix

func (*PublicKeyK256) Equal

func (k *PublicKeyK256) Equal(other PublicKey) bool

Checks if the two public keys are the same. Note that the naive == operator does not work for most equality checks.

func (*PublicKeyK256) HashAndVerify

func (k *PublicKeyK256) HashAndVerify(content, sig []byte) error

First hashes the raw bytes, then verifies the digest, returning `nil` for valid signatures, or an error for any failure.

SHA-256 is the hash algorithm used, as specified by atproto. Signing digests is the norm for ECDSA, and required by some backend implementations. This method does not "double hash", it simply has name which clarifies that hashing is happening.

Calling code is responsible for any string decoding of signatures (eg, hex or base64) before calling this function.

This method requires a "low-S" signature, as specified by atproto.

func (*PublicKeyK256) HashAndVerifyLenient

func (k *PublicKeyK256) HashAndVerifyLenient(content, sig []byte) error

Same as HashAndVerify(), only does not require "low-S" signature.

Used for, eg, JWT validation.

func (*PublicKeyK256) Multibase

func (k *PublicKeyK256) Multibase() string

Returns a multibased string encoding of the public key, including a multicodec indicator and compressed curve bytes serialization

func (*PublicKeyK256) UncompressedBytes

func (k *PublicKeyK256) UncompressedBytes() []byte

Serializes the key in to "uncompressed" binary format.

type PublicKeyP256

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

Implements the PublicKey interface for the NIST P-256 / secp256r1 / ES256 cryptographic curve.

func ParsePublicBytesP256

func ParsePublicBytesP256(data []byte) (*PublicKeyP256, error)

Loads a PublicKeyP256 raw bytes, as exported by the PublicKey.Bytes method. This is the "compressed" curve format.

Calling code needs to know the key type ahead of time, and must remove any string encoding (hex encoding, base64, etc) before calling this function.

func ParsePublicUncompressedBytesP256

func ParsePublicUncompressedBytesP256(data []byte) (*PublicKeyP256, error)

Loads a PublicKeyP256 from raw bytes, as exported by the PublicKey.UncompressedBytes method.

Calling code needs to know the key type ahead of time, and must remove any string encoding (hex encoding, base64, etc) before calling this function.

func (*PublicKeyP256) Bytes

func (k *PublicKeyP256) Bytes() []byte

Serializes the key in to "compressed" binary format.

func (*PublicKeyP256) DIDKey

func (k *PublicKeyP256) DIDKey() string

did:key string encoding of the public key, as would be encoded in a DID PLC operation:

  • compressed / compacted binary representation
  • prefix with appropriate curve multicodec bytes
  • encode bytes with base58btc
  • add "z" prefix to indicate encoding
  • add "did:key:" prefix

func (*PublicKeyP256) Equal

func (k *PublicKeyP256) Equal(other PublicKey) bool

Checks if the two public keys are the same. Note that the naive == operator does not work for most equality checks.

func (*PublicKeyP256) HashAndVerify

func (k *PublicKeyP256) HashAndVerify(content, sig []byte) error

Hashes the raw bytes using SHA-256, then verifies the signature against the digest bytes.

Signing digests is the norm for ECDSA, and required by some backend implementations. This method does not "double hash", it simply has name which clarifies that hashing is happening.

Calling code is responsible for any string decoding of signatures (eg, hex or base64) before calling this function.

This method requires a "low-S" signature, as specified by atproto.

func (*PublicKeyP256) HashAndVerifyLenient

func (k *PublicKeyP256) HashAndVerifyLenient(content, sig []byte) error

Same as HashAndVerify(), only does not require "low-S" signature.

Used for, eg, JWT validation.

func (*PublicKeyP256) Multibase

func (k *PublicKeyP256) Multibase() string

Multibase string encoding of the public key, including a multicodec indicator and compressed curve bytes serialization

func (*PublicKeyP256) UncompressedBytes

func (k *PublicKeyP256) UncompressedBytes() []byte

Serializes the key in to "uncompressed" binary format.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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