From 9f20d74d76ca46c7de6782faa716f016d5775351 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Tue, 19 Apr 2022 11:11:29 +0300 Subject: [PATCH] [#190] crypto/ecdsa: Use separate types for RFC-6979 signature algo Signed-off-by: Leonard Lyubich --- bearer/bearer.go | 5 +-- client/container.go | 18 ++------- crypto/crypto_test.go | 11 +----- crypto/ecdsa/init.go | 5 +-- crypto/ecdsa/public.go | 89 ++++++++++++++++++++++++++---------------- crypto/ecdsa/signer.go | 86 ++++++++++++++++++---------------------- object/id/id.go | 5 +-- reputation/trust.go | 5 +-- session/session.go | 5 +-- 9 files changed, 105 insertions(+), 124 deletions(-) diff --git a/bearer/bearer.go b/bearer/bearer.go index 568dad1..0c895c3 100644 --- a/bearer/bearer.go +++ b/bearer/bearer.go @@ -219,11 +219,8 @@ func (b *Token) Sign(key ecdsa.PrivateKey) error { } var sig neofscrypto.Signature - var signer neofsecdsa.Signer - signer.SetKey(key) - - err = sig.Calculate(signer, data) + err = sig.Calculate(neofsecdsa.Signer(key), data) if err != nil { return fmt.Errorf("calculate signature: %w", err) } diff --git a/client/container.go b/client/container.go index 889e855..2176585 100644 --- a/client/container.go +++ b/client/container.go @@ -90,12 +90,8 @@ func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResCon } var sig neofscrypto.Signature - var signer neofsecdsa.Signer - signer.SetKey(c.prm.key) - signer.MakeDeterministic() - - err = sig.Calculate(signer, data) + err = sig.Calculate(neofsecdsa.SignerRFC6979(c.prm.key), data) if err != nil { return nil, fmt.Errorf("calculate signature: %w", err) } @@ -442,12 +438,8 @@ func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) (* } var sig neofscrypto.Signature - var signer neofsecdsa.Signer - signer.SetKey(c.prm.key) - signer.MakeDeterministic() - - err = sig.Calculate(signer, data) + err = sig.Calculate(neofsecdsa.SignerRFC6979(c.prm.key), data) if err != nil { return nil, fmt.Errorf("calculate signature: %w", err) } @@ -664,12 +656,8 @@ func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL) } var sig neofscrypto.Signature - var signer neofsecdsa.Signer - signer.SetKey(c.prm.key) - signer.MakeDeterministic() - - err = sig.Calculate(signer, data) + err = sig.Calculate(neofsecdsa.SignerRFC6979(c.prm.key), data) if err != nil { return nil, fmt.Errorf("calculate signature: %w", err) } diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index f5cb31b..5d4ab9d 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -23,17 +23,10 @@ func TestSignature(t *testing.T) { for _, f := range []func() neofscrypto.Signer{ func() neofscrypto.Signer { - var key neofsecdsa.Signer - key.SetKey(k.PrivateKey) - - return &key + return neofsecdsa.Signer(k.PrivateKey) }, func() neofscrypto.Signer { - var key neofsecdsa.Signer - key.SetKey(k.PrivateKey) - key.MakeDeterministic() - - return &key + return neofsecdsa.SignerRFC6979(k.PrivateKey) }, } { signer := f() diff --git a/crypto/ecdsa/init.go b/crypto/ecdsa/init.go index 36e256d..7ed440a 100644 --- a/crypto/ecdsa/init.go +++ b/crypto/ecdsa/init.go @@ -8,9 +8,6 @@ func init() { }) neofscrypto.RegisterScheme(neofscrypto.ECDSA_DETERMINISTIC_SHA256, func() neofscrypto.PublicKey { - var key PublicKey - key.MakeDeterministic() - - return &key + return new(PublicKeyRFC6979) }) } diff --git a/crypto/ecdsa/public.go b/crypto/ecdsa/public.go index c6d32dc..7c2dfa3 100644 --- a/crypto/ecdsa/public.go +++ b/crypto/ecdsa/public.go @@ -11,28 +11,11 @@ import ( "github.com/nspcc-dev/neo-go/pkg/crypto/keys" ) -// PublicKey implements neofscrypto.PublicKey based on ECDSA. +// PublicKey is a wrapper over ecdsa.PublicKey used for NeoFS needs. +// Provides neofscrypto.PublicKey interface. // -// Supported schemes: -// - neofscrypto.ECDSA_SHA512 (default) -// - neofscrypto.ECDSA_DETERMINISTIC_SHA256 -type PublicKey struct { - deterministic bool - - key ecdsa.PublicKey -} - -// SetKey specifies ecdsa.PublicKey to be used for ECDSA signature verification. -func (x *PublicKey) SetKey(key ecdsa.PublicKey) { - x.key = key -} - -// MakeDeterministic makes PublicKey to use Deterministic ECDSA scheme -// (see neofscrypto.ECDSA_DETERMINISTIC_SHA256). By default, -// neofscrypto.ECDSA_SHA512 is used. -func (x *PublicKey) MakeDeterministic() { - x.deterministic = true -} +// Instances MUST be initialized from ecdsa.PublicKey using type conversion. +type PublicKey ecdsa.PublicKey // MaxEncodedSize returns size of the compressed ECDSA public key. func (x PublicKey) MaxEncodedSize() int { @@ -50,7 +33,7 @@ func (x PublicKey) Encode(buf []byte) int { panic(fmt.Sprintf("too short buffer %d", len(buf))) } - return copy(buf, (*keys.PublicKey)(&x.key).Bytes()) + return copy(buf, (*keys.PublicKey)(&x).Bytes()) } // Decode decodes compressed binary representation of the PublicKey. @@ -62,7 +45,7 @@ func (x *PublicKey) Decode(data []byte) error { return err } - x.key = (ecdsa.PublicKey)(*pub) + *x = (PublicKey)(*pub) return nil } @@ -86,18 +69,58 @@ func unmarshalXY(data []byte) (x *big.Int, y *big.Int) { return } -// Verify verifies data signature calculated by algorithm depending on -// PublicKey state: -// - Deterministic ECDSA with SHA-256 hashing if MakeDeterministic called -// - ECDSA with SHA-512 hashing, otherwise +// Verify verifies data signature calculated by ECDSA algorithm with SHA-512 hashing. func (x PublicKey) Verify(data, signature []byte) bool { - if x.deterministic { - h := sha256.Sum256(data) - return (*keys.PublicKey)(&x.key).Verify(signature, h[:]) - } - h := sha512.Sum512(data) r, s := unmarshalXY(signature) - return r != nil && s != nil && ecdsa.Verify(&x.key, h[:], r, s) + return r != nil && s != nil && ecdsa.Verify((*ecdsa.PublicKey)(&x), h[:], r, s) +} + +// PublicKeyRFC6979 is a wrapper over ecdsa.PublicKey used for NeoFS needs. +// Provides neofscrypto.PublicKey interface. +// +// Instances MUST be initialized from ecdsa.PublicKey using type conversion. +type PublicKeyRFC6979 ecdsa.PublicKey + +// MaxEncodedSize returns size of the compressed ECDSA public key. +func (x PublicKeyRFC6979) MaxEncodedSize() int { + return 33 +} + +// Encode encodes ECDSA public key in compressed form into buf. +// Uses exactly MaxEncodedSize bytes of the buf. +// +// Encode panics if buf length is less than MaxEncodedSize. +// +// See also Decode. +func (x PublicKeyRFC6979) Encode(buf []byte) int { + if len(buf) < 33 { + panic(fmt.Sprintf("too short buffer %d", len(buf))) + } + + return copy(buf, (*keys.PublicKey)(&x).Bytes()) +} + +// Decode decodes binary representation of the ECDSA public key. +// +// See also Encode. +func (x *PublicKeyRFC6979) Decode(data []byte) error { + pub, err := keys.NewPublicKeyFromBytes(data, elliptic.P256()) + if err != nil { + return err + } + + *x = (PublicKeyRFC6979)(*pub) + + return nil +} + +// Verify verifies data signature calculated by deterministic ECDSA algorithm +// with SHA-256 hashing. +// +// See also RFC 6979. +func (x PublicKeyRFC6979) Verify(data, signature []byte) bool { + h := sha256.Sum256(data) + return (*keys.PublicKey)(&x).Verify(signature, h[:]) } diff --git a/crypto/ecdsa/signer.go b/crypto/ecdsa/signer.go index 4271530..4962b9d 100644 --- a/crypto/ecdsa/signer.go +++ b/crypto/ecdsa/signer.go @@ -10,53 +10,23 @@ import ( neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto" ) -// Signer implements neofscrypto.Signer based on ECDSA. +// Signer wraps ecdsa.PrivateKey and represents signer based on ECDSA with +// SHA-512 hashing. Provides neofscrypto.Signer interface. // -// Supported schemes: -// - neofscrypto.ECDSA_SHA512 (default) -// - neofscrypto.ECDSA_DETERMINISTIC_SHA256 -// -// Instances MUST be initialized with ecdsa.PrivateKey using SetKey. -type Signer struct { - deterministic bool +// Instances MUST be initialized from ecdsa.PrivateKey using type conversion. +type Signer ecdsa.PrivateKey - key ecdsa.PrivateKey -} - -// SetKey specifies ecdsa.PrivateKey to be used for ECDSA signature calculation. -func (x *Signer) SetKey(key ecdsa.PrivateKey) { - x.key = key -} - -// MakeDeterministic makes Signer to use Deterministic ECDSA scheme -// (see neofscrypto.ECDSA_DETERMINISTIC_SHA256). By default, -// neofscrypto.ECDSA_SHA512 is used. -func (x *Signer) MakeDeterministic() { - x.deterministic = true -} - -// Scheme returns signature scheme depending on Signer state: -// - neofscrypto.ECDSA_DETERMINISTIC_SHA256 if MakeDeterministic called -// - neofscrypto.ECDSA_SHA512 otherwise. +// Scheme returns neofscrypto.ECDSA_SHA512. +// Implements neofscrypto.Signer. func (x Signer) Scheme() neofscrypto.Scheme { - if x.deterministic { - return neofscrypto.ECDSA_DETERMINISTIC_SHA256 - } - return neofscrypto.ECDSA_SHA512 } -// Sign signs data with algorithm depending on Signer state: -// - Deterministic ECDSA with SHA-256 hashing if MakeDeterministic called -// - ECDSA with SHA-512 hashing, otherwise +// Sign signs data using ECDSA algorithm with SHA-512 hashing. +// Implements neofscrypto.Signer. func (x Signer) Sign(data []byte) ([]byte, error) { - if x.deterministic { - p := keys.PrivateKey{PrivateKey: x.key} - return p.Sign(data), nil - } - h := sha512.Sum512(data) - r, s, err := ecdsa.Sign(rand.Reader, &x.key, h[:]) + r, s, err := ecdsa.Sign(rand.Reader, (*ecdsa.PrivateKey)(&x), h[:]) if err != nil { return nil, err } @@ -64,13 +34,35 @@ func (x Signer) Sign(data []byte) ([]byte, error) { return elliptic.Marshal(elliptic.P256(), r, s), nil } +// Public initializes PublicKey and returns it as neofscrypto.PublicKey. +// Implements neofscrypto.Signer. func (x Signer) Public() neofscrypto.PublicKey { - var pub PublicKey - pub.SetKey(x.key.PublicKey) - - if x.deterministic { - pub.MakeDeterministic() - } - - return &pub + return (*PublicKey)(&x.PublicKey) +} + +// SignerRFC6979 wraps ecdsa.PrivateKey and represents signer based on deterministic +// ECDSA with SHA-256 hashing (RFC 6979). Provides neofscrypto.Signer interface. +// +// Instances SHOULD be initialized from ecdsa.PrivateKey using type conversion. +type SignerRFC6979 ecdsa.PrivateKey + +// Scheme returns neofscrypto.ECDSA_DETERMINISTIC_SHA256. +// Implements neofscrypto.Signer. +func (x SignerRFC6979) Scheme() neofscrypto.Scheme { + return neofscrypto.ECDSA_DETERMINISTIC_SHA256 +} + +// Sign signs data using deterministic ECDSA algorithm with SHA-256 hashing. +// Implements neofscrypto.Signer. +// +// See also RFC 6979. +func (x SignerRFC6979) Sign(data []byte) ([]byte, error) { + p := keys.PrivateKey{PrivateKey: (ecdsa.PrivateKey)(x)} + return p.Sign(data), nil +} + +// Public initializes PublicKeyRFC6979 and returns it as neofscrypto.PublicKey. +// Implements neofscrypto.Signer. +func (x SignerRFC6979) Public() neofscrypto.PublicKey { + return (*PublicKeyRFC6979)(&x.PublicKey) } diff --git a/object/id/id.go b/object/id/id.go index 05ad3c3..7fbd8b6 100644 --- a/object/id/id.go +++ b/object/id/id.go @@ -123,11 +123,8 @@ func (id ID) CalculateIDSignature(key ecdsa.PrivateKey) (neofscrypto.Signature, } var sig neofscrypto.Signature - var signer neofsecdsa.Signer - signer.SetKey(key) - - return sig, sig.Calculate(signer, data) + return sig, sig.Calculate(neofsecdsa.Signer(key), data) } // Marshal marshals ID into a protobuf binary form. diff --git a/reputation/trust.go b/reputation/trust.go index 9485a28..c0f3d40 100644 --- a/reputation/trust.go +++ b/reputation/trust.go @@ -277,11 +277,8 @@ func (x *GlobalTrust) Sign(key *ecdsa.PrivateKey) error { } var sig neofscrypto.Signature - var signer neofsecdsa.Signer - signer.SetKey(*key) - - err = sig.Calculate(signer, data) + err = sig.Calculate(neofsecdsa.Signer(*key), data) if err != nil { return fmt.Errorf("calculate signature: %w", err) } diff --git a/session/session.go b/session/session.go index 60066e2..681b024 100644 --- a/session/session.go +++ b/session/session.go @@ -176,11 +176,8 @@ func (t *Token) Sign(key *ecdsa.PrivateKey) error { } var sig neofscrypto.Signature - var signer neofsecdsa.Signer - signer.SetKey(*key) - - err = sig.Calculate(signer, digest) + err = sig.Calculate(neofsecdsa.Signer(*key), digest) if err != nil { return err }