this repo has no description
0
fork

Configure Feed

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

crypto: self-review and style tweaks

+80 -69
+1 -1
atproto/crypto/examples_test.go
··· 6 6 ) 7 7 8 8 func ExamplePublicKey() { 9 - pub, err := ParsePublicDidKey("did:key:zDnaembgSGUhZULN2Caob4HLJPaxBh92N7rtH21TErzqf8HQo") 9 + pub, err := ParsePublicDIDKey("did:key:zDnaembgSGUhZULN2Caob4HLJPaxBh92N7rtH21TErzqf8HQo") 10 10 if err != nil { 11 11 panic("failed to parse did:key") 12 12 }
+9 -9
atproto/crypto/interop_fixtures_test.go
··· 14 14 type InteropFixture struct { 15 15 MessageBase64 string `json:"messageBase64"` 16 16 Algorithm string `json:"algorithm"` 17 - DidDocSuite string `json:"didDocSuite"` 18 - PublicKeyDid string `json:"publicKeyDid"` 17 + DIDDocSuite string `json:"didDocSuite"` 18 + PublicKeyDID string `json:"publicKeyDid"` 19 19 PublicKeyMultibase string `json:"publicKeyMultibase"` 20 20 SignatureBase64 string `json:"signatureBase64"` 21 21 ValidSignature bool `json:"validSignature"` ··· 51 51 assert := assert.New(t) 52 52 53 53 // parse all the fields 54 - pkDid, err := ParsePublicDidKey(row.PublicKeyDid) 54 + pkDID, err := ParsePublicDIDKey(row.PublicKeyDID) 55 55 assert.NoError(err) 56 56 keyBytes, err := base58.Decode(row.PublicKeyMultibase[1:]) 57 57 assert.NoError(err) ··· 61 61 assert.NoError(err) 62 62 63 63 var pkCompMultibase PublicKey 64 - switch row.DidDocSuite { 64 + switch row.DIDDocSuite { 65 65 case "EcdsaSecp256r1VerificationKey2019": 66 66 pkCompMultibase, err = ParsePublicBytesP256(keyBytes) 67 67 assert.NoError(err) ··· 69 69 pkCompMultibase, err = ParsePublicBytesK256(keyBytes) 70 70 assert.NoError(err) 71 71 default: 72 - t.Fatal("expected DidDocSuite") 72 + t.Fatal("expected DIDDocSuite") 73 73 } 74 74 75 75 // verify encodings 76 - assert.Equal(pkDid, pkCompMultibase, "key equality") 77 - assert.Equal(row.PublicKeyDid, pkDid.DidKey(), "did:key re-encoding") 76 + assert.Equal(pkDID, pkCompMultibase, "key equality") 77 + assert.Equal(row.PublicKeyDID, pkDID.DIDKey(), "did:key re-encoding") 78 78 79 79 // verify signatures 80 80 if row.ValidSignature { 81 - assert.NoError(pkDid.HashAndVerify(msgBytes, sigBytes), "keyType=%v format=%v", row.Algorithm, "did:key") 81 + assert.NoError(pkDID.HashAndVerify(msgBytes, sigBytes), "keyType=%v format=%v", row.Algorithm, "did:key") 82 82 assert.NoError(pkCompMultibase.HashAndVerify(msgBytes, sigBytes), "keyType=%v format=%v", row.Algorithm, "multibase") 83 83 } else { 84 - assert.Error(pkDid.HashAndVerify(msgBytes, sigBytes), "keyType=%v format=%v", row.Algorithm, "did:key") 84 + assert.Error(pkDID.HashAndVerify(msgBytes, sigBytes), "keyType=%v format=%v", row.Algorithm, "did:key") 85 85 assert.Error(pkCompMultibase.HashAndVerify(msgBytes, sigBytes), "keyType=%v format=%v", row.Algorithm, "multibase") 86 86 } 87 87
+9 -5
atproto/crypto/k256.go
··· 23 23 pubK256 *secp256k1secec.PublicKey 24 24 } 25 25 26 + var _ PrivateKey = (*PrivateKeyK256)(nil) 27 + var _ PrivateKeyExportable = (*PrivateKeyK256)(nil) 28 + var _ PublicKey = (*PublicKeyK256)(nil) 29 + 26 30 var k256Options = &secp256k1secec.ECDSAOptions{ 27 31 // Used to *verify* digest, not to re-hash 28 32 Hash: crypto.SHA256, ··· 64 68 // Serializes the secret key material in to a raw binary format, which can be parsed by [ParsePrivateBytesK256]. 65 69 // 66 70 // For K-256, this is the "compact" encoding and is 32 bytes long. There is no ASN.1 or other enclosing structure. 67 - func (k *PrivateKeyK256) Bytes() []byte { 71 + func (k PrivateKeyK256) Bytes() []byte { 68 72 return k.privK256.Bytes() 69 73 } 70 74 71 75 // Outputs the [PublicKey] corresponding to this [PrivateKeyK256]; it will be a [PublicKeyK256]. 72 - func (k *PrivateKeyK256) Public() (PublicKey, error) { 76 + func (k PrivateKeyK256) Public() (PublicKey, error) { 73 77 pub := PublicKeyK256{pubK256: k.privK256.PublicKey()} 74 78 err := pub.ensureBytes() 75 79 if err != nil { ··· 85 89 // Calling code is responsible for any string encoding of signatures (eg, hex or base64). For K-256, the signature is 64 bytes long. 86 90 // 87 91 // 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. 88 - func (k *PrivateKeyK256) HashAndSign(content []byte) ([]byte, error) { 92 + func (k PrivateKeyK256) HashAndSign(content []byte) ([]byte, error) { 89 93 hash := sha256.Sum256(content) 90 94 return k.privK256.Sign(rand.Reader, hash[:], k256Options) 91 95 } ··· 170 174 func (k *PublicKeyK256) HashAndVerify(content, sig []byte) error { 171 175 hash := sha256.Sum256(content) 172 176 if !k.pubK256.Verify(hash[:], sig, k256Options) { 173 - return fmt.Errorf("crypto: invalid signature") 177 + return ErrInvalidSignature 174 178 } 175 179 return nil 176 180 } ··· 190 194 // - encode bytes with base58btc 191 195 // - add "z" prefix to indicate encoding 192 196 // - add "did:key:" prefix 193 - func (k *PublicKeyK256) DidKey() string { 197 + func (k *PublicKeyK256) DIDKey() string { 194 198 return "did:key:" + k.Multibase() 195 199 }
+30 -32
atproto/crypto/keys.go
··· 1 1 package crypto 2 2 3 3 import ( 4 + "errors" 4 5 "fmt" 5 6 "strings" 6 7 7 8 "github.com/mr-tron/base58" 8 9 ) 9 10 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. 11 + // Common interface for all the supported atproto cryptographic systems, when 12 + // secret key material may not be directly available to be exported as bytes. 11 13 type PrivateKey interface { 12 14 Equal(other PrivateKey) bool 13 15 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. 16 + // If necessary, pre-verifies that the public key curve point is valid and 17 + // will be possible to encode as bytes or a string later. 16 18 Public() (PublicKey, error) 17 19 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. 20 + // Hashes the raw bytes using SHA-256, then signs the digest bytes. 21 + // Always returns a "low-S" signature (for elliptic curve systems where that is ambigious). 21 22 HashAndSign(content []byte) ([]byte, error) 22 23 } 23 24 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. 25 + // Common interface for all the supported atproto cryptographic systems, when 26 + // secret key material is directly available to be exported as bytes. 25 27 type PrivateKeyExportable interface { 26 - Equal(other PrivateKey) bool 28 + PrivateKey 27 29 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. 30 + // Untyped (no multicodec) encoding of the secret key material. 31 + // The encoding format is curve-specific, and is generally "compact" for private keys. 32 + // No ASN.1 or other enclosing structure is applied to the bytes. 33 33 Bytes() []byte 34 - 35 - // Same as PrivateKey.Public() 36 - Public() (PublicKey, error) 37 - 38 - // Same as PrivateKey.HashAndSign() 39 - HashAndSign(content []byte) ([]byte, error) 40 34 } 41 35 42 - // Common interface for public keys of all the supported cryptographic systems in the atproto ecosystem. 36 + // Common interface for all the supported atproto cryptographic systems. 43 37 type PublicKey interface { 44 38 Equal(other PublicKey) bool 45 39 46 - // Outputs a compact byte serialization of this key. 40 + // Compact byte serialization (for elliptic curve systems where encoding is ambigious). 47 41 Bytes() []byte 48 42 49 - // Hashes content bytes with SHA-256, then verifies the signature of the 50 - // digest. 43 + // Hashes the raw bytes using SHA-256, then verifies the signature of the digest bytes. 51 44 HashAndVerify(content, sig []byte) error 52 45 53 - // String serialization of the public key using common parameters: 46 + // String serialization of the key bytes using common parameters: 54 47 // compressed byte serialization; multicode varint code prefix; base58btc 55 48 // string encoding ("z" prefix) 56 49 Multibase() string 57 50 58 - // String serialization of the public key as did:key. 59 - DidKey() string 51 + // String serialization of the key bytes as a did:key. 52 + DIDKey() string 60 53 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 54 + // Non-compact byte serialization (for elliptic curve systems where 55 + // encoding is ambigious) 56 + // 57 + // This is not used frequently, or directly in atproto, but some 58 + // serializations and encodings require it. 59 + // 60 + // For systems with no compressed/uncompressed distinction, returns the same 65 61 // value as Bytes(). 66 62 UncompressedBytes() []byte 67 63 } 68 64 69 - // Parses a public key from multibase encoding, with multicodec indicating the key type. 65 + var ErrInvalidSignature = errors.New("crytographic signature invalid") 66 + 67 + // Loads a public key from multibase string encoding, with multicodec indicating the key type. 70 68 func ParsePublicMultibase(encoded string) (PublicKey, error) { 71 69 if len(encoded) < 2 || encoded[0] != 'z' { 72 70 return nil, fmt.Errorf("crypto: not a multibase base58btc string") ··· 92 90 // Loads a [PublicKey] from did:key string serialization. 93 91 // 94 92 // The did:key format encodes the key type. 95 - func ParsePublicDidKey(didKey string) (PublicKey, error) { 93 + func ParsePublicDIDKey(didKey string) (PublicKey, error) { 96 94 if !strings.HasPrefix(didKey, "did:key:z") { 97 95 return nil, fmt.Errorf("string is not a DID key: %s", didKey) 98 96 }
+2 -2
atproto/crypto/keys_test.go
··· 53 53 assert.NoError(err) 54 54 55 55 // public key encoding 56 - pubDidKeyString := pub.DidKey() 57 - pubDK, err := ParsePublicDidKey(pubDidKeyString) 56 + pubDIDKeyString := pub.DIDKey() 57 + pubDK, err := ParsePublicDIDKey(pubDIDKeyString) 58 58 assert.NoError(err) 59 59 assert.True(pub.Equal(pubDK)) 60 60
+19 -10
atproto/crypto/p256.go
··· 8 8 "crypto/sha256" 9 9 "crypto/x509" 10 10 "fmt" 11 + "log" 11 12 "math/big" 12 13 13 14 "github.com/mr-tron/base58" ··· 23 24 type PublicKeyP256 struct { 24 25 pubP256 *ecdsa.PublicKey 25 26 } 27 + 28 + var _ PrivateKey = (*PrivateKeyP256)(nil) 29 + var _ PrivateKeyExportable = (*PrivateKeyP256)(nil) 30 + var _ PublicKey = (*PublicKeyP256)(nil) 26 31 27 32 // Creates a secure new cryptographic key from scratch. 28 33 func GeneratePrivateKeyP256() (*PrivateKeyP256, error) { ··· 56 61 if err != nil { 57 62 return nil, fmt.Errorf("invalid P-256/secp256r1 private key: %w", err) 58 63 } 59 - priv := PrivateKeyP256{privP256: sk.(*ecdsa.PrivateKey)} 64 + skECDSA, ok := sk.(*ecdsa.PrivateKey) 65 + if !ok { 66 + return nil, fmt.Errorf("expected ECDSA privatekey from internal encoding") 67 + } 68 + priv := PrivateKeyP256{privP256: skECDSA} 60 69 err = priv.ensureBytes() 61 70 if err != nil { 62 71 return nil, err ··· 85 94 func (k *PrivateKeyP256) Bytes() []byte { 86 95 skEcdh, err := k.privP256.ECDH() 87 96 if err != nil { 88 - panic("unexpected failure to export P-256 private key, after being exportable at parse time") 97 + log.Fatal("unexpected failure to export P-256 private key, after being exportable at parse time") 89 98 } 90 99 return skEcdh.Bytes() 91 100 } ··· 192 201 func (k *PublicKeyP256) UncompressedBytes() []byte { 193 202 pkEcdh, err := k.pubP256.ECDH() 194 203 if err != nil { 195 - panic("unexpected invalid P-256/secp256r1 public key, was verified at parse time") 204 + log.Fatal("unexpected invalid P-256/secp256r1 public key, was verified at parse time") 196 205 } 197 206 return pkEcdh.Bytes() 198 207 } ··· 202 211 return elliptic.MarshalCompressed(k.pubP256.Curve, k.pubP256.X, k.pubP256.Y) 203 212 } 204 213 205 - // First hashes the raw bytes, then verifies the digest, returning `nil` for valid signatures, or an error for any failure. 214 + // Hashes the raw bytes using SHA-256, then verifies the signature against the digest bytes. 206 215 // 207 - // 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. 216 + // 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. 208 217 // 209 218 // Calling code is responsible for any string decoding of signatures (eg, hex or base64) before calling this function. 210 219 // ··· 221 230 s.SetBytes(sig[32:]) 222 231 223 232 if !ecdsa.Verify(k.pubP256, hash[:], r, s) { 224 - return fmt.Errorf("crypto: invalid signature") 233 + return ErrInvalidSignature 225 234 } 226 235 227 236 // ensure that signature is low-S 228 237 if !sigSIsLowS_P256(s) { 229 - return fmt.Errorf("crypto: invalid signature (high-S P-256)") 238 + return ErrInvalidSignature 230 239 } 231 240 232 241 return nil 233 242 } 234 243 235 - // Returns a multibase string encoding of the public key, including a multicodec indicator and compressed curve bytes serialization 244 + // Multibase string encoding of the public key, including a multicodec indicator and compressed curve bytes serialization 236 245 func (k *PublicKeyP256) Multibase() string { 237 246 kbytes := k.Bytes() 238 247 // multicodec p256-pub, code 0x1200, varint-encoded bytes: [0x80, 0x24] ··· 240 249 return "z" + base58.Encode(kbytes) 241 250 } 242 251 243 - // Returns a did:key string encoding of the public key, as would be encoded in a DID PLC operation: 252 + // did:key string encoding of the public key, as would be encoded in a DID PLC operation: 244 253 // 245 254 // - compressed / compacted binary representation 246 255 // - prefix with appropriate curve multicodec bytes 247 256 // - encode bytes with base58btc 248 257 // - add "z" prefix to indicate encoding 249 258 // - add "did:key:" prefix 250 - func (k *PublicKeyP256) DidKey() string { 259 + func (k *PublicKeyP256) DIDKey() string { 251 260 return "did:key:" + k.Multibase() 252 261 }
+10 -10
atproto/crypto/w3c_didkey_test.go
··· 11 11 "github.com/stretchr/testify/assert" 12 12 ) 13 13 14 - type DidKeyFixture struct { 14 + type DIDKeyFixture struct { 15 15 PrivateKeyBytesBase58 string `json:"privateKeyBytesBase58"` 16 16 PrivateKeyBytesHex string `json:"privateKeyBytesHex"` 17 - PublicDidKey string `json:"publicDidKey"` 17 + PublicDIDKey string `json:"publicDidKey"` 18 18 } 19 19 20 - func TestDidKeyFixtures(t *testing.T) { 20 + func TestDIDKeyFixtures(t *testing.T) { 21 21 22 22 fixtureBatches := []struct { 23 23 path string ··· 40 40 t.Fatal(err) 41 41 } 42 42 43 - var fixtures []DidKeyFixture 43 + var fixtures []DIDKeyFixture 44 44 if err := json.Unmarshal(fixBytes, &fixtures); err != nil { 45 45 t.Fatal(err) 46 46 } 47 47 48 48 for _, row := range fixtures { 49 - testDidKeyFixture(t, row, batch.keyType) 49 + testDIDKeyFixture(t, row, batch.keyType) 50 50 } 51 51 } 52 52 } 53 53 54 - func testDidKeyFixture(t *testing.T, row DidKeyFixture, keyType string) { 54 + func testDIDKeyFixture(t *testing.T, row DIDKeyFixture, keyType string) { 55 55 assert := assert.New(t) 56 56 57 57 var raw []byte ··· 86 86 if err != nil { 87 87 t.Fatal(err) 88 88 } 89 - kDidKey, err := ParsePublicDidKey(row.PublicDidKey) 89 + kDIDKey, err := ParsePublicDIDKey(row.PublicDIDKey) 90 90 if err != nil { 91 91 t.Fatal(err) 92 92 } 93 - assert.Equal(kBytes.Equal(kDidKey), true) 94 - assert.Equal(row.PublicDidKey, kBytes.DidKey()) 95 - assert.Equal(row.PublicDidKey, kDidKey.DidKey()) 93 + assert.Equal(kBytes.Equal(kDIDKey), true) 94 + assert.Equal(row.PublicDIDKey, kBytes.DIDKey()) 95 + assert.Equal(row.PublicDIDKey, kDIDKey.DIDKey()) 96 96 }