this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

crypto: update godocs for new API

+111 -65
+2 -4
atproto/crypto/docs.go
··· 1 - // Cryptographic keys and operations as used in atproto 1 + // Package crypto provides cryptographic keys and operations, as used in atproto (the protocol) 2 2 // 3 3 // 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. 4 4 // 5 5 // The two currently supported curve types are: 6 6 // 7 7 // - P-256/secp256r1, internally implemented using golang's stdlib cryptographic library 8 - // - K-256/secp256r1, internally implemented using <gitlab.com/yawning/secp256k1-voi> 8 + // - K-256/secp256r1, internally implemented using https://gitlab.com/yawning/secp256k1-voi 9 9 // 10 10 // "Low-S" signatures are enforced for both key types, both when creating signatures and during verification, as required by the atproto specification. 11 - // 12 - // This package uses concrete types for private keys, meaning that the secret key material is present in memory. 13 11 package crypto
+14 -11
atproto/crypto/k256.go
··· 11 11 secp256k1secec "gitlab.com/yawning/secp256k1-voi/secec" 12 12 ) 13 13 14 - // K-256 / secp256k1 / ES256K 14 + // Implements the [PrivateKeyExportable] and [PrivateKey] interfaces for the NIST K-256 / secp256k1 / ES256K cryptographic curve. 15 + // Secret key material is naively stored in memory. 15 16 type PrivateKeyK256 struct { 16 17 privK256 *secp256k1secec.PrivateKey 17 18 } 18 19 20 + // K-256 / secp256k1 / ES256K 21 + // Implements the [PublicKey] interface for the NIST K-256 / secp256k1 / ES256K cryptographic curve. 19 22 type PublicKeyK256 struct { 20 23 pubK256 *secp256k1secec.PublicKey 21 24 } ··· 38 41 return &PrivateKeyK256{privK256: key}, nil 39 42 } 40 43 41 - // Loads a [PrivateKey] of the indicated curve type from raw bytes, as exported by the [PrivateKey.Bytes()] method. (XXX) 44 + // Loads a [PrivateKeyK256] from raw bytes, as exported by the PrivateKey.Bytes method. 42 45 // 43 46 // 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. 44 47 func ParsePrivateBytesK256(data []byte) (*PrivateKeyK256, error) { ··· 50 53 } 51 54 52 55 // Checks if the two private keys are the same. Note that the naive == operator does not work for most equality checks. 53 - func (k *PrivateKeyK256) Equal(other PrivateKeyExportable) bool { 56 + func (k *PrivateKeyK256) Equal(other PrivateKey) bool { 54 57 otherK256, ok := other.(*PrivateKeyK256) 55 58 if ok { 56 59 return k.privK256.Equal(otherK256.privK256) ··· 58 61 return false 59 62 } 60 63 61 - // Serializes the secret key material in to a raw binary format, which can be parsed by [ParsePrivateKeyBytes]. 64 + // Serializes the secret key material in to a raw binary format, which can be parsed by [ParsePrivateBytesK256]. 62 65 // 63 - // The encoding format is curve-specific, and is generally "compact" for private keys. Both P-256 and K-256 private keys end up 32 bytes long. There is no ASN.1 or other enclosing structure to the binary encoding. 66 + // For K-256, this is the "compact" encoding and is 32 bytes long. There is no ASN.1 or other enclosing structure. 64 67 func (k *PrivateKeyK256) Bytes() []byte { 65 68 return k.privK256.Bytes() 66 69 } 67 70 68 - // Outputs the PublicKey corresponding to this PrivateKey. 71 + // Outputs the [PublicKey] corresponding to this [PrivateKeyK256]; it will be a [PublicKeyK256]. 69 72 func (k *PrivateKeyK256) Public() (PublicKey, error) { 70 73 pub := PublicKeyK256{pubK256: k.privK256.PublicKey()} 71 74 err := pub.ensureBytes() ··· 79 82 // 80 83 // 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. 81 84 // 82 - // Calling code is responsible for any string encoding of signatures (eg, hex or base64). Both P-256 and K-256 signatures are 64 bytes long. 85 + // Calling code is responsible for any string encoding of signatures (eg, hex or base64). For K-256, the signature is 64 bytes long. 83 86 // 84 87 // 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. 85 88 func (k *PrivateKeyK256) HashAndSign(content []byte) ([]byte, error) { ··· 87 90 return k.privK256.Sign(rand.Reader, hash[:], k256Options) 88 91 } 89 92 90 - // Loads a [PublicKey] of the indicated curve type from raw bytes, as exported by the [PublicKey.Bytes] method. This is the "compressed" curve format. 93 + // Loads a [PublicKeyK256] raw bytes, as exported by the PublicKey.Bytes method. This is the "compressed" curve format. 91 94 // 92 95 // 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. 93 96 func ParsePublicBytesK256(data []byte) (*PublicKeyK256, error) { ··· 111 114 return &pub, nil 112 115 } 113 116 114 - // Loads a [PublicKey] of the indicated curve type from raw bytes, as exported by the [PublicKey.UncompressedBytes] method. 117 + // Loads a [PublicKeyK256] from raw bytes, as exported by the PublicKey.UncompressedBytes method. 115 118 // 116 119 // 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. 117 120 func ParsePublicUncompressedBytesK256(data []byte) (*PublicKeyK256, error) { ··· 145 148 return nil 146 149 } 147 150 148 - // Serializes the [PublicKey] in to "uncompressed" binary format. 151 + // Serializes the key in to "uncompressed" binary format. 149 152 func (k *PublicKeyK256) UncompressedBytes() []byte { 150 153 p := k.pubK256.Point() 151 154 return p.UncompressedBytes() 152 155 } 153 156 154 - // Serializes the [PublicKey] in to "compressed" binary format. 157 + // Serializes the key in to "compressed" binary format. 155 158 func (k *PublicKeyK256) Bytes() []byte { 156 159 p := k.pubK256.Point() 157 160 return p.CompressedBytes()
+71 -28
atproto/crypto/keys.go
··· 7 7 "github.com/mr-tron/base58" 8 8 ) 9 9 10 + // Common interface for private keys of all the supported cryptographic systems in the atproto ecosystem, in a format which may or may not have secret key material directly available in memory to be exported as bytes. 10 11 type PrivateKey interface { 12 + Equal(other PrivateKey) bool 13 + 14 + // Returns the public key for this private key. Verifies that the public 15 + // key is valid and will be possible to encode as bytes or a string later. 11 16 Public() (PublicKey, error) 17 + 18 + // First hashes the raw bytes, then signs the digest, returning a binary 19 + // signature. SHA-256 is the hash algorithm used, as specified by atproto. 20 + // This method always returns a "low-S" signature, as required by atproto. 12 21 HashAndSign(content []byte) ([]byte, error) 13 22 } 14 23 24 + // Common interface for private keys of all the supported cryptographic systems in the atproto ecosystem, in a format which does have secret key material directly available in memory to be exported as bytes. 15 25 type PrivateKeyExportable interface { 26 + Equal(other PrivateKey) bool 27 + 28 + // Outputs an untyped (no multicodec) compact encoding of the secret key 29 + // material. The encoding format is curve-specific, and is generally 30 + // "compact" for private keys. Both P-256 and K-256 private keys end up 32 31 + // bytes long. There is no ASN.1 or other enclosing structure to the binary 32 + // encoding. 16 33 Bytes() []byte 17 - Equal(other PrivateKeyExportable) bool 34 + 35 + // Same as PrivateKey.Public() 18 36 Public() (PublicKey, error) 37 + 38 + // Same as PrivateKey.HashAndSign() 19 39 HashAndSign(content []byte) ([]byte, error) 20 40 } 21 41 42 + // Common interface for public keys of all the supported cryptographic systems in the atproto ecosystem. 22 43 type PublicKey interface { 23 - UncompressedBytes() []byte 24 - Bytes() []byte 25 44 Equal(other PublicKey) bool 45 + 46 + // Outputs a compact byte serialization of this key. 47 + Bytes() []byte 48 + 49 + // Hashes content bytes with SHA-256, then verifies the signature of the 50 + // digest. 26 51 HashAndVerify(content, sig []byte) error 52 + 53 + // String serialization of the public key using common parameters: 54 + // compressed byte serialization; multicode varint code prefix; base58btc 55 + // string encoding ("z" prefix) 27 56 Multibase() string 57 + 58 + // String serialization of the public key as did:key. 28 59 DidKey() string 29 60 30 - // these are likely to be deprecated 61 + // Outputs a non-compact byte serialization of this key. This is not used 62 + // frequently, or directly in atproto, but some serializations and 63 + // encodings require it. 64 + // For curves with no compressed/uncompressed distinction, returns the same 65 + // value as Bytes(). 66 + UncompressedBytes() []byte 67 + 68 + // Outputs a DID cryptographic suite type name for this curve, as used in 69 + // some DID documents. 70 + // This method may be removed in the future. 31 71 LegacyDidDocSuite() string 72 + 73 + // Helper to serialize in a format used in older DID documents: 74 + // uncompressed byte encoding, no multicodec prefix, base58btc multibase 75 + // string encoding ("z" prefix) 76 + // This method may be removed in the future. 32 77 LegacyMultibase() string 33 78 } 34 79 35 - // Parses a public key in multibase encoding, as would be found in a older DID Document `verificationMethod` section. 36 - // 37 - // This implementation does not handle the many possible multibase encodings (eg, base32), only the base58btc encoding that would be found in a DID Document. 38 - // 39 - // This function is deprecated! 40 - func ParsePublicLegacyMultibase(encoded string, didDocSuite string) (PublicKey, error) { 41 - if len(encoded) < 2 || encoded[0] != 'z' { 42 - return nil, fmt.Errorf("crypto: not a multibase base58btc string") 43 - } 44 - data, err := base58.Decode(encoded[1:]) 45 - if err != nil { 46 - return nil, fmt.Errorf("crypto: not a multibase base58btc string") 47 - } 48 - switch didDocSuite { 49 - case "EcdsaSecp256r1VerificationKey2019": 50 - return ParsePublicUncompressedBytesP256(data) 51 - case "EcdsaSecp256k1VerificationKey2019": 52 - return ParsePublicUncompressedBytesK256(data) 53 - default: 54 - return nil, fmt.Errorf("unhandled legacy crypto suite: %s", didDocSuite) 55 - } 56 - } 57 - 58 80 // Parses a public key from multibase encoding, with multicodec indicating the key type. 59 81 func ParsePublicMultibase(encoded string) (PublicKey, error) { 60 82 if len(encoded) < 2 || encoded[0] != 'z' { ··· 74 96 // multicodec secp256k1-pub, code 0xE7, varint bytes: [0xE7, 0x01] 75 97 return ParsePublicBytesK256(data[2:]) 76 98 } else { 77 - return nil, fmt.Errorf("unexpected multicode code for multibase-encoded key") 99 + return nil, fmt.Errorf("unsupported atproto key type (unknown multicodec prefix)") 78 100 } 79 101 } 80 102 ··· 88 110 mb := strings.TrimPrefix(didKey, "did:key:") 89 111 return ParsePublicMultibase(mb) 90 112 } 113 + 114 + // Parses a public key in multibase encoding, as would be found in a older DID Document `verificationMethod` section: uncompressed binary, no multicodec prefix, and base58btc multibase string encoding. 115 + // 116 + // This function is likely to be deprecated and removed. 117 + func ParsePublicLegacyMultibase(encoded string, didDocSuite string) (PublicKey, error) { 118 + if len(encoded) < 2 || encoded[0] != 'z' { 119 + return nil, fmt.Errorf("crypto: not a multibase base58btc string") 120 + } 121 + data, err := base58.Decode(encoded[1:]) 122 + if err != nil { 123 + return nil, fmt.Errorf("crypto: not a multibase base58btc string") 124 + } 125 + switch didDocSuite { 126 + case "EcdsaSecp256r1VerificationKey2019": 127 + return ParsePublicUncompressedBytesP256(data) 128 + case "EcdsaSecp256k1VerificationKey2019": 129 + return ParsePublicUncompressedBytesK256(data) 130 + default: 131 + return nil, fmt.Errorf("unhandled legacy crypto suite: %s", didDocSuite) 132 + } 133 + }
+24 -22
atproto/crypto/p256.go
··· 13 13 "github.com/mr-tron/base58" 14 14 ) 15 15 16 - // P-256 / secp256r1 / ES256 16 + // Implements the [PrivateKeyExportable] and [PrivateKey] interfaces for the NIST P-256 / secp256r1 / ES256 cryptographic curve. 17 + // Secret key material is naively stored in memory. 17 18 type PrivateKeyP256 struct { 18 19 privP256 *ecdsa.PrivateKey 19 20 } 20 21 22 + // Implements the [PublicKey] interface for the NIST P-256 / secp256r1 / ES256 cryptographic curve. 21 23 type PublicKeyP256 struct { 22 24 pubP256 *ecdsa.PublicKey 23 25 } 24 26 25 - // Creates a secure new cryptographic key from scratch, with the indicated curve type. 27 + // Creates a secure new cryptographic key from scratch. 26 28 func GeneratePrivateKeyP256() (*PrivateKeyP256, error) { 27 29 key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 28 30 if err != nil { ··· 36 38 return &priv, nil 37 39 } 38 40 39 - // Loads a [PrivateKey] of the indicated curve type from raw bytes, as exported by the [PrivateKey.Bytes()] method. 41 + // Loads a [PrivateKeyP256] from raw bytes, as exported by the PrivateKeyP256.Bytes method. 40 42 // 41 43 // 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. 42 44 func ParsePrivateBytesP256(data []byte) (*PrivateKeyP256, error) { ··· 63 65 } 64 66 65 67 // Checks if the two private keys are the same. Note that the naive == operator does not work for most equality checks. 66 - func (k *PrivateKeyP256) Equal(other PrivateKeyExportable) bool { 68 + func (k *PrivateKeyP256) Equal(other PrivateKey) bool { 67 69 otherP256, ok := other.(*PrivateKeyP256) 68 70 if ok { 69 71 return k.privP256.Equal(otherP256.privP256) ··· 71 73 return false 72 74 } 73 75 74 - // Outputs the PublicKey corresponding to this PrivateKey. 75 - func (k *PrivateKeyP256) Public() (PublicKey, error) { 76 - pub := PublicKeyP256{pubP256: k.privP256.Public().(*ecdsa.PublicKey)} 77 - err := pub.ensureBytes() 78 - if err != nil { 79 - return nil, err 80 - } 81 - return &pub, nil 82 - } 83 - 84 76 // internal helper which checks that they key will be possible to export later 85 77 func (k *PrivateKeyP256) ensureBytes() error { 86 78 _, err := k.privP256.ECDH() 87 79 return err 88 80 } 89 81 90 - // Serializes the secret key material in to a raw binary format, which can be parsed by [ParsePrivateKeyBytes]. 82 + // Serializes the secret key material in to a raw binary format, which can be parsed by [ParsePrivateBytesP256]. 91 83 // 92 - // The encoding format is curve-specific, and is generally "compact" for private keys. Both P-256 and K-256 private keys end up 32 bytes long. There is no ASN.1 or other enclosing structure to the binary encoding. 84 + // For P-256, this is the "compact" encoding and is 32 bytes long. There is no ASN.1 or other enclosing structure. 93 85 func (k *PrivateKeyP256) Bytes() []byte { 94 86 skEcdh, err := k.privP256.ECDH() 95 87 if err != nil { ··· 98 90 return skEcdh.Bytes() 99 91 } 100 92 93 + // Outputs the [PublicKey] corresponding to this [PrivateKeyP256]; it will be a [PublicKeyP256]. 94 + func (k *PrivateKeyP256) Public() (PublicKey, error) { 95 + pub := PublicKeyP256{pubP256: k.privP256.Public().(*ecdsa.PublicKey)} 96 + err := pub.ensureBytes() 97 + if err != nil { 98 + return nil, err 99 + } 100 + return &pub, nil 101 + } 102 + 101 103 // First hashes the raw bytes, then signs the digest, returning a binary signature. 102 104 // 103 105 // 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. 104 106 // 105 - // Calling code is responsible for any string encoding of signatures (eg, hex or base64). Both P-256 and K-256 signatures are 64 bytes long. 107 + // Calling code is responsible for any string encoding of signatures (eg, hex or base64). For P-256, the signature is 64 bytes long. 106 108 // 107 109 // 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. 108 110 func (k *PrivateKeyP256) HashAndSign(content []byte) ([]byte, error) { ··· 118 120 return sig, nil 119 121 } 120 122 121 - // Loads a [PublicKey] of the indicated curve type from raw bytes, as exported by the [PublicKey.Bytes] method. This is the "compressed" curve format. 123 + // Loads a [PublicKeyP256] raw bytes, as exported by the PublicKey.Bytes method. This is the "compressed" curve format. 122 124 // 123 125 // 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. 124 126 func ParsePublicBytesP256(data []byte) (*PublicKeyP256, error) { ··· 143 145 return &pub, nil 144 146 } 145 147 146 - // Loads a [PublicKey] of the indicated curve type from raw bytes, as exported by the [PublicKey.UncompressedBytes] method. 148 + // Loads a [PublicKeyP256] from raw bytes, as exported by the PublicKey.UncompressedBytes method. 147 149 // 148 150 // 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. 149 151 func ParsePublicUncompressedBytesP256(data []byte) (*PublicKeyP256, error) { ··· 186 188 return err 187 189 } 188 190 189 - // Serializes the [PublicKey] in to "uncompressed" binary format. 191 + // Serializes the key in to "uncompressed" binary format. 190 192 func (k *PublicKeyP256) UncompressedBytes() []byte { 191 193 pkEcdh, err := k.pubP256.ECDH() 192 194 if err != nil { ··· 195 197 return pkEcdh.Bytes() 196 198 } 197 199 198 - // Serializes the [PublicKey] in to "compressed" binary format. 200 + // Serializes the key in to "compressed" binary format. 199 201 func (k *PublicKeyP256) Bytes() []byte { 200 202 return elliptic.MarshalCompressed(k.pubP256.Curve, k.pubP256.X, k.pubP256.Y) 201 203 } ··· 230 232 return nil 231 233 } 232 234 233 - // Returns a multibased string encoding of the public key, including a multicodec indicator and compressed curve bytes serialization 235 + // Returns a multibase string encoding of the public key, including a multicodec indicator and compressed curve bytes serialization 234 236 func (k *PublicKeyP256) Multibase() string { 235 237 kbytes := k.Bytes() 236 238 // multicodec p256-pub, code 0x1200, varint-encoded bytes: [0x80, 0x24]