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:
- P-256/secp256r1, internally implemented using golang's stdlib cryptographic library
- K-256/secp256r1, internally implemented using https://gitlab.com/yawning/secp256k1-voi
"Low-S" signatures are enforced for both key types, both when creating signatures and during verification, as required by the atproto specification.
Index ¶
- Variables
- type PrivateKey
- type PrivateKeyExportable
- type PrivateKeyK256
- type PrivateKeyP256
- type PublicKey
- type PublicKeyK256
- func (k *PublicKeyK256) Bytes() []byte
- func (k *PublicKeyK256) DIDKey() string
- func (k *PublicKeyK256) Equal(other PublicKey) bool
- func (k *PublicKeyK256) HashAndVerify(content, sig []byte) error
- func (k *PublicKeyK256) HashAndVerifyLenient(content, sig []byte) error
- func (k *PublicKeyK256) Multibase() string
- func (k *PublicKeyK256) UncompressedBytes() []byte
- type PublicKeyP256
- func (k *PublicKeyP256) Bytes() []byte
- func (k *PublicKeyP256) DIDKey() string
- func (k *PublicKeyP256) Equal(other PublicKey) bool
- func (k *PublicKeyP256) HashAndVerify(content, sig []byte) error
- func (k *PublicKeyP256) HashAndVerifyLenient(content, sig []byte) error
- func (k *PublicKeyP256) Multibase() string
- func (k *PublicKeyP256) UncompressedBytes() []byte
Examples ¶
Constants ¶
This section is empty.
Variables ¶
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 ¶
Loads a PublicKey from did:key string serialization.
The did:key format encodes the key type.
func ParsePublicMultibase ¶
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.