[#190] Refactor cryptographic functionality

Remove `signature` and `util/signature` packages. Re-implement their
functionality in new `crypto` package. Generalize the approach of
digital signature computation and verification by adding `Signer` and
`PublicKey` primitives similar to standard `crypto` package. Support
already exising in protocol signature schemes.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
remotes/fyrchik/split-info-format
Leonard Lyubich 2022-04-05 14:13:34 +03:00 committed by LeL
parent 2deaaeef05
commit ea043f4ca3
33 changed files with 728 additions and 627 deletions

View File

@ -4,14 +4,15 @@ import (
"crypto/ecdsa"
"crypto/elliptic"
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-api-go/v2/acl"
v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/nspcc-dev/neofs-sdk-go/owner"
"github.com/nspcc-dev/neofs-sdk-go/signature"
sigutil "github.com/nspcc-dev/neofs-sdk-go/util/signature"
)
var (
@ -210,15 +211,27 @@ func (b *Token) Sign(key ecdsa.PrivateKey) error {
return err
}
v2 := (*acl.BearerToken)(b)
signWrapper := v2signature.StableMarshalerWrapper{SM: v2.GetBody()}
m := (*acl.BearerToken)(b)
sig, err := sigutil.SignData(&key, signWrapper)
data, err := m.GetBody().StableMarshal(nil)
if err != nil {
return err
return fmt.Errorf("marshal body: %w", err)
}
v2.SetSignature(sig.ToV2())
var sig neofscrypto.Signature
var signer neofsecdsa.Signer
signer.SetKey(key)
err = sig.Calculate(signer, data)
if err != nil {
return fmt.Errorf("calculate signature: %w", err)
}
var sigV2 refs.Signature
sig.WriteToV2(&sigV2)
m.SetSignature(&sigV2)
return nil
}
@ -229,11 +242,26 @@ func (b Token) VerifySignature() error {
return nil
}
v2 := (acl.BearerToken)(b)
m := (acl.BearerToken)(b)
return sigutil.VerifyData(
v2signature.StableMarshalerWrapper{SM: v2.GetBody()},
signature.NewFromV2(v2.GetSignature()))
sigV2 := m.GetSignature()
if sigV2 == nil {
return errors.New("missing signature")
}
data, err := m.GetBody().StableMarshal(nil)
if err != nil {
return fmt.Errorf("marshal body: %w", err)
}
var sig neofscrypto.Signature
sig.ReadFromV2(*sigV2)
if !sig.Verify(data) {
return errors.New("wrong signature")
}
return nil
}
// Issuer returns owner.ID associated with the key that signed bearer token.

View File

@ -2,20 +2,20 @@ package client
import (
"context"
"fmt"
v2container "github.com/nspcc-dev/neofs-api-go/v2/container"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
rpcapi "github.com/nspcc-dev/neofs-api-go/v2/rpc"
"github.com/nspcc-dev/neofs-api-go/v2/rpc/client"
v2session "github.com/nspcc-dev/neofs-api-go/v2/session"
v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-sdk-go/container"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
"github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/nspcc-dev/neofs-sdk-go/owner"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/nspcc-dev/neofs-sdk-go/signature"
sigutil "github.com/nspcc-dev/neofs-sdk-go/util/signature"
)
// PrmContainerPut groups parameters of ContainerPut operation.
@ -81,20 +81,33 @@ func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResCon
}
// TODO: check private key is set before forming the request
// sign container
cnr := prm.cnr.ToV2()
data, err := cnr.StableMarshal(nil)
if err != nil {
return nil, fmt.Errorf("marshal container: %w", err)
}
var sig neofscrypto.Signature
var signer neofsecdsa.Signer
signer.SetKey(c.prm.key)
signer.MakeDeterministic()
err = sig.Calculate(signer, data)
if err != nil {
return nil, fmt.Errorf("calculate signature: %w", err)
}
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
// form request body
reqBody := new(v2container.PutRequestBody)
reqBody.SetContainer(prm.cnr.ToV2())
// sign container
signWrapper := v2signature.StableMarshalerWrapper{SM: reqBody.GetContainer()}
sig, err := sigutil.SignData(&c.prm.key, signWrapper, sigutil.SignWithRFC6979())
if err != nil {
return nil, err
}
reqBody.SetSignature(sig.ToV2())
reqBody.SetSignature(&sigv2)
// form meta header
var meta v2session.RequestMetaHeader
@ -235,9 +248,14 @@ func (c *Client) ContainerGet(ctx context.Context, prm PrmContainerGet) (*ResCon
session.NewTokenFromV2(body.GetSessionToken()),
)
cnr.SetSignature(
signature.NewFromV2(body.GetSignature()),
)
var sig *neofscrypto.Signature
if sigv2 := body.GetSignature(); sigv2 != nil {
sig = new(neofscrypto.Signature)
sig.ReadFromV2(*sigv2)
}
cnr.SetSignature(sig)
res.setContainer(cnr)
}
@ -414,22 +432,34 @@ func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) (*
panic(panicMsgMissingContainer)
}
// sign container ID
var cidV2 refs.ContainerID
prm.id.WriteToV2(&cidV2)
data, err := cidV2.StableMarshal(nil)
if err != nil {
return nil, fmt.Errorf("marshal container ID: %w", err)
}
var sig neofscrypto.Signature
var signer neofsecdsa.Signer
signer.SetKey(c.prm.key)
signer.MakeDeterministic()
err = sig.Calculate(signer, data)
if err != nil {
return nil, fmt.Errorf("calculate signature: %w", err)
}
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
// form request body
reqBody := new(v2container.DeleteRequestBody)
reqBody.SetContainerID(&cidV2)
signWrapper := delContainerSignWrapper{body: reqBody}
// sign container
sig, err := sigutil.SignData(&c.prm.key, signWrapper, sigutil.SignWithRFC6979())
if err != nil {
return nil, err
}
reqBody.SetSignature(sig.ToV2())
reqBody.SetSignature(&sigv2)
// form meta header
var meta v2session.RequestMetaHeader
@ -558,9 +588,14 @@ func (c *Client) ContainerEACL(ctx context.Context, prm PrmContainerEACL) (*ResC
session.NewTokenFromV2(body.GetSessionToken()),
)
table.SetSignature(
signature.NewFromV2(body.GetSignature()),
)
var sig *neofscrypto.Signature
if sigv2 := body.GetSignature(); sigv2 != nil {
sig = new(neofscrypto.Signature)
sig.ReadFromV2(*sigv2)
}
table.SetSignature(sig)
res.setTable(table)
}
@ -620,19 +655,33 @@ func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL)
panic("eACL table not set")
}
// form request body
reqBody := new(v2container.SetExtendedACLRequestBody)
reqBody.SetEACL(prm.table.ToV2())
// sign the eACL table
signWrapper := v2signature.StableMarshalerWrapper{SM: reqBody.GetEACL()}
eaclV2 := prm.table.ToV2()
sig, err := sigutil.SignData(&c.prm.key, signWrapper, sigutil.SignWithRFC6979())
data, err := eaclV2.StableMarshal(nil)
if err != nil {
return nil, err
return nil, fmt.Errorf("marshal eACL: %w", err)
}
reqBody.SetSignature(sig.ToV2())
var sig neofscrypto.Signature
var signer neofsecdsa.Signer
signer.SetKey(c.prm.key)
signer.MakeDeterministic()
err = sig.Calculate(signer, data)
if err != nil {
return nil, fmt.Errorf("calculate signature: %w", err)
}
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
// form request body
reqBody := new(v2container.SetExtendedACLRequestBody)
reqBody.SetEACL(eaclV2)
reqBody.SetSignature(&sigv2)
// form meta header
var meta v2session.RequestMetaHeader

View File

@ -8,10 +8,10 @@ import (
"github.com/nspcc-dev/neofs-api-go/v2/refs"
"github.com/nspcc-dev/neofs-sdk-go/acl"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/nspcc-dev/neofs-sdk-go/owner"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/nspcc-dev/neofs-sdk-go/signature"
"github.com/nspcc-dev/neofs-sdk-go/version"
)
@ -20,7 +20,7 @@ type Container struct {
token *session.Token
sig *signature.Signature
sig *neofscrypto.Signature
}
// New creates, initializes and returns blank Container instance.
@ -171,12 +171,12 @@ func (c *Container) SetSessionToken(t *session.Token) {
}
// Signature returns signature of the marshaled container.
func (c Container) Signature() *signature.Signature {
func (c Container) Signature() *neofscrypto.Signature {
return c.sig
}
// SetSignature sets signature of the marshaled container.
func (c *Container) SetSignature(sig *signature.Signature) {
func (c *Container) SetSignature(sig *neofscrypto.Signature) {
c.sig = sig
}

View File

@ -11,7 +11,6 @@ import (
netmaptest "github.com/nspcc-dev/neofs-sdk-go/netmap/test"
ownertest "github.com/nspcc-dev/neofs-sdk-go/owner/test"
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
sigtest "github.com/nspcc-dev/neofs-sdk-go/signature/test"
"github.com/nspcc-dev/neofs-sdk-go/version"
versiontest "github.com/nspcc-dev/neofs-sdk-go/version/test"
"github.com/stretchr/testify/require"
@ -86,15 +85,6 @@ func TestContainer_SessionToken(t *testing.T) {
require.Equal(t, tok, cnr.SessionToken())
}
func TestContainer_Signature(t *testing.T) {
sig := sigtest.Signature()
cnr := container.New()
cnr.SetSignature(sig)
require.Equal(t, sig, cnr.Signature())
}
func TestContainer_ToV2(t *testing.T) {
t.Run("nil", func(t *testing.T) {
var x *container.Container

View File

@ -0,0 +1,51 @@
package neofscrypto_test
import (
"math/rand"
"testing"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
"github.com/stretchr/testify/require"
)
func TestSignature(t *testing.T) {
data := make([]byte, 512)
rand.Read(data)
k, err := keys.NewPrivateKey()
require.NoError(t, err)
var s neofscrypto.Signature
var m refs.Signature
for _, f := range []func() neofscrypto.Signer{
func() neofscrypto.Signer {
var key neofsecdsa.Signer
key.SetKey(k.PrivateKey)
return &key
},
func() neofscrypto.Signer {
var key neofsecdsa.Signer
key.SetKey(k.PrivateKey)
key.MakeDeterministic()
return &key
},
} {
signer := f()
err := s.Calculate(signer, data)
require.NoError(t, err)
s.WriteToV2(&m)
s.ReadFromV2(m)
valid := s.Verify(data)
require.True(t, valid)
}
}

48
crypto/doc.go 100644
View File

@ -0,0 +1,48 @@
/*
Package neofscrypto collects NeoFS cryptographic primitives.
Signer type unifies entities for signing NeoFS data.
// instantiate Signer
// select data to be signed
var sig Signature
err := sig.Calculate(signer, data)
// ...
// attach signature to the request
SDK natively supports several signature schemes that are implemented
in nested packages.
PublicKey allows to verify signatures.
// get signature to be verified
// compose signed data
isValid := sig.Verify(data)
// ...
Signature can be also used to process NeoFS API V2 protocol messages
(see neo.fs.v2.refs package in https://github.com/nspcc-dev/neofs-api).
On client side:
import "github.com/nspcc-dev/neofs-api-go/v2/refs"
var msg refs.Signature
sig.WriteToV2(&msg)
// send msg
On server side:
// recv msg
var sig neofscrypto.Signature
sig.ReadFromV2(msg)
// process sig
Using package types in an application is recommended to potentially work with
different protocol versions with which these types are compatible.
*/
package neofscrypto

View File

@ -0,0 +1,11 @@
/*
Package neofsecdsa collects ECDSA primitives for NeoFS cryptography.
Signer and PublicKey provide corresponding interfaces from neofscrypto package.
Package import causes registration of next signature schemes via neofscrypto.RegisterScheme:
- neofscrypto.ECDSA_SHA512
- neofscrypto.ECDSA_DETERMINISTIC_SHA256
*/
package neofsecdsa

View File

@ -0,0 +1,16 @@
package neofsecdsa
import neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
func init() {
neofscrypto.RegisterScheme(neofscrypto.ECDSA_SHA512, func() neofscrypto.PublicKey {
return new(PublicKey)
})
neofscrypto.RegisterScheme(neofscrypto.ECDSA_DETERMINISTIC_SHA256, func() neofscrypto.PublicKey {
var key PublicKey
key.MakeDeterministic()
return &key
})
}

View File

@ -0,0 +1,78 @@
package neofsecdsa
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/sha256"
"crypto/sha512"
"math/big"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
)
// PublicKey implements neofscrypto.PublicKey based on ECDSA.
//
// Supported schemes:
// - neofscrypto.ECDSA_SHA512 (default)
// - neofscrypto.ECDSA_DETERMINISTIC_SHA256
type PublicKey struct {
deterministic bool
key ecdsa.PublicKey
}
// 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
}
// Decode decodes compressed binary representation of the PublicKey.
//
// See also Signer.EncodePublicKey.
func (x *PublicKey) Decode(data []byte) error {
pub, err := keys.NewPublicKeyFromBytes(data, elliptic.P256())
if err != nil {
return err
}
x.key = (ecdsa.PublicKey)(*pub)
return nil
}
// similar to elliptic.Unmarshal but without IsOnCurve check.
func unmarshalXY(data []byte) (x *big.Int, y *big.Int) {
if len(data) != 65 {
return
} else if data[0] != 4 { // uncompressed form
return
}
p := elliptic.P256().Params().P
x = new(big.Int).SetBytes(data[1:33])
y = new(big.Int).SetBytes(data[33:])
if x.Cmp(p) >= 0 || y.Cmp(p) >= 0 {
x, y = nil, nil
}
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
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)
}

View File

@ -0,0 +1,86 @@
package neofsecdsa
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha512"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
)
// Signer implements neofscrypto.Signer based on ECDSA.
//
// Supported schemes:
// - neofscrypto.ECDSA_SHA512 (default)
// - neofscrypto.ECDSA_DETERMINISTIC_SHA256
//
// Instances MUST be initialized with ecdsa.PrivateKey using SetKey.
type Signer struct {
deterministic bool
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.
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
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[:])
if err != nil {
return nil, err
}
return elliptic.Marshal(elliptic.P256(), r, s), nil
}
// MaxPublicKeyEncodedSize returns size of the compressed ECDSA public key
// of the Signer.
func (x Signer) MaxPublicKeyEncodedSize() int {
return 33
}
// EncodePublicKey encodes ECDSA public key of the Signer in compressed form
// into buf. Uses exactly MaxPublicKeyEncodedSize bytes of the buf.
//
// EncodePublicKey panics if buf length is less than MaxPublicKeyEncodedSize.
//
// See also PublicKey.Decode.
func (x Signer) EncodePublicKey(buf []byte) int {
if len(buf) < 33 {
panic(fmt.Sprintf("too short buffer %d", len(buf)))
}
return copy(buf, (*keys.PublicKey)(&x.key.PublicKey).Bytes())
}

View File

@ -0,0 +1,85 @@
package neofscrypto
import (
"fmt"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
)
// Signature represents a confirmation of data integrity received by the
// digital signature mechanism.
//
// Signature is mutually compatible with github.com/nspcc-dev/neofs-api-go/v2/refs.Signature
// message. See ReadFromV2 / WriteToV2 methods.
//
// Note that direct typecast is not safe and may result in loss of compatibility:
// _ = Signature(refs.Signature{}) // not recommended
type Signature refs.Signature
// ReadFromV2 reads Signature from the refs.Signature message.
//
// See also WriteToV2.
func (x *Signature) ReadFromV2(m refs.Signature) {
*x = Signature(m)
}
// WriteToV2 writes Signature to the refs.Signature message.
// The message must not be nil.
//
// See also ReadFromV2.
func (x Signature) WriteToV2(m *refs.Signature) {
*m = (refs.Signature)(x)
}
// Calculate signs data using Signer and encodes public key for subsequent
// verification.
//
// Signer MUST NOT be nil.
//
// See also Verify.
func (x *Signature) Calculate(signer Signer, data []byte) error {
signature, err := signer.Sign(data)
if err != nil {
return fmt.Errorf("signer %T failure: %w", signer, err)
}
key := make([]byte, signer.MaxPublicKeyEncodedSize())
key = key[:signer.EncodePublicKey(key)]
m := (*refs.Signature)(x)
scheme := refs.SignatureScheme(signer.Scheme())
if scheme > 0 {
scheme-- // to sync numeric values
}
m.SetScheme(scheme)
m.SetSign(signature)
m.SetKey(key)
return nil
}
// Verify verifies data signature using encoded public key. True means valid
// signature.
//
// Verify fails if signature scheme is not supported (see RegisterScheme).
//
// See also Calculate.
func (x Signature) Verify(data []byte) bool {
m := (*refs.Signature)(&x)
f, ok := publicKeys[Scheme(m.GetScheme()+1)] // increment to sync numeric values
if !ok {
return false
}
key := f()
err := key.Decode(m.GetKey())
if err != nil {
return false
}
return key.Verify(data, m.GetSign())
}

83
crypto/signer.go 100644
View File

@ -0,0 +1,83 @@
package neofscrypto
import (
"fmt"
)
// Scheme represents digital signature algorithm with fixed cryptographic hash function.
//
// Non-positive values are reserved and depend on context (e.g. unsupported scheme).
type Scheme uint32
//nolint:revive
const (
_ Scheme = iota
ECDSA_SHA512 // ECDSA with SHA-512 hashing (FIPS 186-3)
ECDSA_DETERMINISTIC_SHA256 // Deterministic ECDSA with SHA-256 hashing (RFC 6979)
)
// maps Scheme to blank PublicKey constructor.
var publicKeys = make(map[Scheme]func() PublicKey)
// RegisterScheme registers a function that returns a new blank PublicKey
// instance for the given Scheme. This is intended to be called from the init
// function in packages that implement signature schemes.
//
// RegisterScheme panics if function for the given Scheme is already registered.
func RegisterScheme(scheme Scheme, f func() PublicKey) {
_, ok := publicKeys[scheme]
if ok {
panic(fmt.Sprintf("scheme %v is already registered", scheme))
}
publicKeys[scheme] = f
}
// Signer is an interface of entities that can be used for signing operations
// in NeoFS. Unites secret and public parts. For example, an ECDSA private key
// or external auth service.
//
// See also PublicKey.
type Signer interface {
// Scheme returns corresponding signature scheme.
Scheme() Scheme
// Sign signs digest of the given data. Implementations encapsulate data
// hashing that depends on Scheme. For example, if scheme uses SHA-256, then
// Sign signs SHA-256 hash of the data.
Sign(data []byte) ([]byte, error)
// MaxPublicKeyEncodedSize returns maximum size required for binary-encoded
// public key.
//
// MaxPublicKeyEncodedSize MUST NOT return value greater than any return of
// EncodePublicKey.
MaxPublicKeyEncodedSize() int
// EncodePublicKey encodes public key into buf. Returns number of bytes
// written.
//
// EncodePublicKey MUST panic if buffer size is insufficient and less than
// MaxPublicKeyEncodedSize (*). EncodePublicKey MUST return negative value
// on any failure except (*).
//
// EncodePublicKey is expected to be compatible with PublicKey.Decode for
// similar signature schemes.
EncodePublicKey(buf []byte) int
}
// PublicKey represents a public key using fixed signature scheme supported by
// NeoFS.
//
// See also Signer.
type PublicKey interface {
// Decode decodes binary public key.
//
// Decode is expected to be compatible with Signer.EncodePublicKey for
// similar signature schemes.
Decode([]byte) error
// Verify checks signature of the given data. True means correct signature.
Verify(data, signature []byte) bool
}

View File

@ -8,8 +8,8 @@ import (
v2acl "github.com/nspcc-dev/neofs-api-go/v2/acl"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/nspcc-dev/neofs-sdk-go/signature"
"github.com/nspcc-dev/neofs-sdk-go/version"
)
@ -20,7 +20,7 @@ type Table struct {
version version.Version
cid *cid.ID
token *session.Token
sig *signature.Signature
sig *neofscrypto.Signature
records []Record
}
@ -74,12 +74,12 @@ func (t *Table) SetSessionToken(tok *session.Token) {
}
// Signature returns Table signature.
func (t Table) Signature() *signature.Signature {
func (t Table) Signature() *neofscrypto.Signature {
return t.sig
}
// SetSignature sets Table signature.
func (t *Table) SetSignature(sig *signature.Signature) {
func (t *Table) SetSignature(sig *neofscrypto.Signature) {
t.sig = sig
}

View File

@ -9,7 +9,6 @@ import (
"github.com/nspcc-dev/neofs-sdk-go/eacl"
eacltest "github.com/nspcc-dev/neofs-sdk-go/eacl/test"
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
"github.com/nspcc-dev/neofs-sdk-go/signature"
"github.com/nspcc-dev/neofs-sdk-go/version"
"github.com/stretchr/testify/require"
)
@ -102,17 +101,6 @@ func TestTable_SessionToken(t *testing.T) {
require.Equal(t, tok, table.SessionToken())
}
func TestTable_Signature(t *testing.T) {
sig := signature.New()
sig.SetKey([]byte{1, 2, 3})
sig.SetSign([]byte{4, 5, 6})
table := eacl.NewTable()
table.SetSignature(sig)
require.Equal(t, sig, table.Signature())
}
func TestTable_ToV2(t *testing.T) {
t.Run("nil", func(t *testing.T) {
var x *eacl.Table

View File

@ -7,11 +7,10 @@ import (
"errors"
"fmt"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
signatureV2 "github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-api-go/v2/object"
"github.com/nspcc-dev/neofs-sdk-go/checksum"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
sigutil "github.com/nspcc-dev/neofs-sdk-go/util/signature"
)
var (
@ -120,24 +119,27 @@ func CalculateAndSetSignature(key ecdsa.PrivateKey, obj *Object) error {
// VerifyIDSignature verifies object ID signature.
func (o *Object) VerifyIDSignature() bool {
oID, set := o.ID()
if !set {
m := (*object.Object)(o)
sigV2 := m.GetSignature()
if sigV2 == nil {
return false
}
var idV2 refs.ObjectID
oID.WriteToV2(&idV2)
idV2 := m.GetObjectID()
if idV2 == nil {
return false
}
sig := o.Signature()
data, err := idV2.StableMarshal(nil)
if err != nil {
return false
}
err := sigutil.VerifyData(
signatureV2.StableMarshalerWrapper{
SM: &idV2,
},
sig,
)
var sig neofscrypto.Signature
sig.ReadFromV2(*sigV2)
return err == nil
return sig.Verify(data)
}
// SetIDWithSignature sets object identifier and signature.

View File

@ -51,22 +51,6 @@ func TestVerificationFields(t *testing.T) {
obj.ToV2().GetObjectID().GetValue()[0]--
},
},
{
corrupt: func() {
obj.Signature().Key()[0]++
},
restore: func() {
obj.Signature().Key()[0]--
},
},
{
corrupt: func() {
obj.Signature().Sign()[0]++
},
restore: func() {
obj.Signature().Sign()[0]--
},
},
}
for _, item := range items {

View File

@ -7,9 +7,8 @@ import (
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
signatureV2 "github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-sdk-go/signature"
sigutil "github.com/nspcc-dev/neofs-sdk-go/util/signature"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
)
// ID represents NeoFS object identifier in a container.
@ -117,17 +116,18 @@ func (id ID) String() string {
}
// CalculateIDSignature signs object id with provided key.
func (id ID) CalculateIDSignature(key ecdsa.PrivateKey) (signature.Signature, error) {
var idV2 refs.ObjectID
id.WriteToV2(&idV2)
func (id ID) CalculateIDSignature(key ecdsa.PrivateKey) (neofscrypto.Signature, error) {
data, err := id.Marshal()
if err != nil {
return neofscrypto.Signature{}, fmt.Errorf("marshal ID: %w", err)
}
sign, err := sigutil.SignData(&key,
signatureV2.StableMarshalerWrapper{
SM: &idV2,
},
)
var sig neofscrypto.Signature
var signer neofsecdsa.Signer
return *sign, err
signer.SetKey(key)
return sig, sig.Calculate(signer, data)
}
// Marshal marshals ID into a protobuf binary form.

View File

@ -8,10 +8,10 @@ import (
"github.com/nspcc-dev/neofs-api-go/v2/refs"
"github.com/nspcc-dev/neofs-sdk-go/checksum"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/owner"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/nspcc-dev/neofs-sdk-go/signature"
"github.com/nspcc-dev/neofs-sdk-go/version"
)
@ -109,14 +109,29 @@ func (o *Object) SetID(v oid.ID) {
}
// Signature returns signature of the object identifier.
func (o *Object) Signature() *signature.Signature {
return signature.NewFromV2(
(*object.Object)(o).GetSignature())
func (o *Object) Signature() *neofscrypto.Signature {
sigv2 := (*object.Object)(o).GetSignature()
if sigv2 == nil {
return nil
}
var sig neofscrypto.Signature
sig.ReadFromV2(*sigv2)
return &sig
}
// SetSignature sets signature of the object identifier.
func (o *Object) SetSignature(v *signature.Signature) {
(*object.Object)(o).SetSignature(v.ToV2())
func (o *Object) SetSignature(v *neofscrypto.Signature) {
var sigv2 *refs.Signature
if v != nil {
sigv2 = new(refs.Signature)
v.WriteToV2(sigv2)
}
(*object.Object)(o).SetSignature(sigv2)
}
// Payload returns payload bytes.

View File

@ -11,7 +11,6 @@ import (
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
ownertest "github.com/nspcc-dev/neofs-sdk-go/owner/test"
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
"github.com/nspcc-dev/neofs-sdk-go/signature"
"github.com/nspcc-dev/neofs-sdk-go/version"
"github.com/stretchr/testify/require"
)
@ -49,18 +48,6 @@ func TestObject_SetID(t *testing.T) {
require.Equal(t, id, oID)
}
func TestObject_SetSignature(t *testing.T) {
obj := New()
sig := signature.New()
sig.SetKey([]byte{1, 2, 3})
sig.SetSign([]byte{4, 5, 6})
obj.SetSignature(sig)
require.Equal(t, sig, obj.Signature())
}
func TestObject_SetPayload(t *testing.T) {
obj := New()
@ -208,7 +195,6 @@ func TestObject_SetParent(t *testing.T) {
par := New()
par.SetID(randID(t))
par.SetContainerID(cidtest.ID())
par.SetSignature(signature.New())
obj.SetParent(par)

View File

@ -9,7 +9,6 @@ import (
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
ownertest "github.com/nspcc-dev/neofs-sdk-go/owner/test"
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
sigtest "github.com/nspcc-dev/neofs-sdk-go/signature/test"
"github.com/nspcc-dev/neofs-sdk-go/version"
)
@ -62,7 +61,6 @@ func generate(withParent bool) *object.Object {
x.SetSplitID(SplitID())
x.SetPayloadChecksum(checksumtest.Checksum())
x.SetPayloadHomomorphicHash(checksumtest.Checksum())
x.SetSignature(sigtest.Signature())
if withParent {
x.SetParent(generate(false))

View File

@ -17,7 +17,7 @@ func TestSessionCache_GetUnmodifiedToken(t *testing.T) {
require.NoError(t, err)
check := func(t *testing.T, tok *session.Token, extra string) {
require.Empty(t, tok.Signature().Sign(), extra)
require.False(t, tok.VerifySignature(), extra)
require.Nil(t, tok.Context(), extra)
}

View File

@ -669,8 +669,7 @@ func TestCopySessionTokenWithoutSignatureAndContext(t *testing.T) {
require.Equal(t, from.OwnerID().String(), to.OwnerID().String())
require.Equal(t, from.SessionKey(), to.SessionKey())
require.Empty(t, to.Signature().Sign())
require.Empty(t, to.Signature().Key())
require.False(t, to.VerifySignature())
t.Run("empty object context", func(t *testing.T) {
octx := sessiontest.ObjectContext()

View File

@ -5,7 +5,6 @@ import (
"github.com/mr-tron/base58"
"github.com/nspcc-dev/neofs-api-go/v2/reputation"
"github.com/nspcc-dev/neofs-sdk-go/util/signature"
)
// PeerID represents peer ID compatible with NeoFS API v2.
@ -27,7 +26,7 @@ func PeerIDFromV2(id *reputation.PeerID) *PeerID {
}
// SetPublicKey sets peer ID as a compressed public key.
func (x *PeerID) SetPublicKey(v [signature.PublicKeyCompressedSize]byte) {
func (x *PeerID) SetPublicKey(v [33]byte) {
(*reputation.PeerID)(x).SetPublicKey(v[:])
}

View File

@ -5,7 +5,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-sdk-go/reputation"
"github.com/nspcc-dev/neofs-sdk-go/util/signature"
"github.com/stretchr/testify/require"
)
@ -17,7 +16,7 @@ func PeerID() *reputation.PeerID {
panic(err)
}
key := [signature.PublicKeyCompressedSize]byte{}
key := [33]byte{}
copy(key[:], p.Bytes())
v.SetPublicKey(key)

View File

@ -2,12 +2,13 @@ package reputation
import (
"crypto/ecdsa"
"errors"
"fmt"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
"github.com/nspcc-dev/neofs-api-go/v2/reputation"
signatureV2 "github.com/nspcc-dev/neofs-api-go/v2/signature"
"github.com/nspcc-dev/neofs-sdk-go/signature"
sigutil "github.com/nspcc-dev/neofs-sdk-go/util/signature"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
"github.com/nspcc-dev/neofs-sdk-go/version"
)
@ -264,31 +265,58 @@ func (x *GlobalTrust) Trust() *Trust {
// Sign signs global trust value with key.
func (x *GlobalTrust) Sign(key *ecdsa.PrivateKey) error {
v2 := (*reputation.GlobalTrust)(x)
sig, err := sigutil.SignData(key,
signatureV2.StableMarshalerWrapper{SM: v2.GetBody()})
if err != nil {
return err
if key == nil {
return errors.New("nil private key")
}
v2.SetSignature(sig.ToV2())
m := (*reputation.GlobalTrust)(x)
data, err := m.GetBody().StableMarshal(nil)
if err != nil {
return fmt.Errorf("marshal body: %w", err)
}
var sig neofscrypto.Signature
var signer neofsecdsa.Signer
signer.SetKey(*key)
err = sig.Calculate(signer, data)
if err != nil {
return fmt.Errorf("calculate signature: %w", err)
}
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
m.SetSignature(&sigv2)
return nil
}
// VerifySignature verifies global trust signature.
func (x *GlobalTrust) VerifySignature() error {
v2 := (*reputation.GlobalTrust)(x)
m := (*reputation.GlobalTrust)(x)
sigV2 := v2.GetSignature()
sigV2 := m.GetSignature()
if sigV2 == nil {
sigV2 = new(refs.Signature)
return errors.New("missing signature")
}
return sigutil.VerifyData(
signatureV2.StableMarshalerWrapper{SM: v2.GetBody()},
signature.NewFromV2(sigV2),
)
data, err := m.GetBody().StableMarshal(nil)
if err != nil {
return fmt.Errorf("marshal body: %w", err)
}
var sig neofscrypto.Signature
sig.ReadFromV2(*sigV2)
if !sig.Verify(data) {
return errors.New("wrong signature")
}
return nil
}
// Marshal marshals GlobalTrust into a protobuf binary form.

View File

@ -2,12 +2,14 @@ package session
import (
"crypto/ecdsa"
"errors"
"fmt"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
"github.com/nspcc-dev/neofs-api-go/v2/session"
v2signature "github.com/nspcc-dev/neofs-api-go/v2/signature"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
"github.com/nspcc-dev/neofs-sdk-go/owner"
"github.com/nspcc-dev/neofs-sdk-go/signature"
sigutil "github.com/nspcc-dev/neofs-sdk-go/util/signature"
)
// Token represents NeoFS API v2-compatible
@ -162,18 +164,32 @@ func (t *Token) SetIat(iat uint64) {
//
// Returns signature calculation errors.
func (t *Token) Sign(key *ecdsa.PrivateKey) error {
tV2 := (*session.Token)(t)
signedData := v2signature.StableMarshalerWrapper{
SM: tV2.GetBody(),
if key == nil {
return errors.New("nil private key")
}
sig, err := sigutil.SignData(key, signedData)
tV2 := (*session.Token)(t)
digest, err := tV2.GetBody().StableMarshal(nil)
if err != nil {
panic(fmt.Sprintf("unexpected error from Token.StableMarshal: %v", err))
}
var sig neofscrypto.Signature
var signer neofsecdsa.Signer
signer.SetKey(*key)
err = sig.Calculate(signer, digest)
if err != nil {
return err
}
tV2.SetSignature(sig.ToV2())
var sigV2 refs.Signature
sig.WriteToV2(&sigV2)
tV2.SetSignature(&sigV2)
return nil
}
@ -182,19 +198,20 @@ func (t *Token) Sign(key *ecdsa.PrivateKey) error {
func (t *Token) VerifySignature() bool {
tV2 := (*session.Token)(t)
signedData := v2signature.StableMarshalerWrapper{
SM: tV2.GetBody(),
digest, err := tV2.GetBody().StableMarshal(nil)
if err != nil {
panic(fmt.Sprintf("unexpected error from Token.StableMarshal: %v", err))
}
return sigutil.VerifyData(signedData, t.Signature()) == nil
}
sigV2 := tV2.GetSignature()
if sigV2 == nil {
return false
}
// Signature returns Token signature.
func (t *Token) Signature() *signature.Signature {
return signature.NewFromV2(
(*session.Token)(t).
GetSignature(),
)
var sig neofscrypto.Signature
sig.ReadFromV2(*sigV2)
return sig.Verify(digest)
}
// SetContext sets context of the Token.

View File

@ -185,7 +185,7 @@ func TestNewToken(t *testing.T) {
token := session.NewToken()
// check initial values
require.Nil(t, token.Signature())
require.False(t, token.VerifySignature())
require.Nil(t, token.OwnerID())
require.Nil(t, token.SessionKey())
require.Nil(t, token.ID())

View File

@ -1,94 +0,0 @@
package signature
import (
"github.com/nspcc-dev/neofs-api-go/v2/refs"
)
// Signature represents v2-compatible signature.
type Signature refs.Signature
// Scheme represents signature scheme.
type Scheme uint32
// Supported signature schemes.
const (
ECDSAWithSHA512 Scheme = iota
RFC6979WithSHA256
)
func (x Scheme) String() string {
return refs.SignatureScheme(x).String()
}
// NewFromV2 wraps v2 Signature message to Signature.
//
// Nil refs.Signature converts to nil.
func NewFromV2(sV2 *refs.Signature) *Signature {
return (*Signature)(sV2)
}
// New creates and initializes blank Signature.
//
// Defaults:
// - key: nil;
// - signature: nil.
func New() *Signature {
return NewFromV2(new(refs.Signature))
}
// Key sets binary public key.
func (s *Signature) Key() []byte {
return (*refs.Signature)(s).GetKey()
}
// SetKey returns binary public key.
func (s *Signature) SetKey(v []byte) {
(*refs.Signature)(s).SetKey(v)
}
// Sign return signature value.
func (s *Signature) Sign() []byte {
return (*refs.Signature)(s).GetSign()
}
// SetSign sets signature value.
func (s *Signature) SetSign(v []byte) {
(*refs.Signature)(s).SetSign(v)
}
// Scheme returns signature scheme.
func (s *Signature) Scheme() Scheme {
return Scheme((*refs.Signature)(s).GetScheme())
}
// SetScheme sets signature scheme.
func (s *Signature) SetScheme(v Scheme) {
(*refs.Signature)(s).SetScheme(refs.SignatureScheme(v))
}
// ToV2 converts Signature to v2 Signature message.
//
// Nil Signature converts to nil.
func (s *Signature) ToV2() *refs.Signature {
return (*refs.Signature)(s)
}
// Marshal marshals Signature into a protobuf binary form.
func (s *Signature) Marshal() ([]byte, error) {
return (*refs.Signature)(s).StableMarshal(nil)
}
// Unmarshal unmarshals protobuf binary representation of Signature.
func (s *Signature) Unmarshal(data []byte) error {
return (*refs.Signature)(s).Unmarshal(data)
}
// MarshalJSON encodes Signature to protobuf JSON format.
func (s *Signature) MarshalJSON() ([]byte, error) {
return (*refs.Signature)(s).MarshalJSON()
}
// UnmarshalJSON decodes Signature from protobuf JSON format.
func (s *Signature) UnmarshalJSON(data []byte) error {
return (*refs.Signature)(s).UnmarshalJSON(data)
}

View File

@ -1,66 +0,0 @@
package signature
import (
"testing"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
"github.com/stretchr/testify/require"
)
func TestSignatureEncoding(t *testing.T) {
s := New()
s.SetKey([]byte("key"))
s.SetSign([]byte("sign"))
t.Run("binary", func(t *testing.T) {
data, err := s.Marshal()
require.NoError(t, err)
s2 := New()
require.NoError(t, s2.Unmarshal(data))
require.Equal(t, s, s2)
})
t.Run("json", func(t *testing.T) {
data, err := s.MarshalJSON()
require.NoError(t, err)
s2 := New()
require.NoError(t, s2.UnmarshalJSON(data))
require.Equal(t, s, s2)
})
}
func TestNewSignatureFromV2(t *testing.T) {
t.Run("from nil", func(t *testing.T) {
var x *refs.Signature
require.Nil(t, NewFromV2(x))
})
}
func TestSignature_ToV2(t *testing.T) {
t.Run("nil", func(t *testing.T) {
var x *Signature
require.Nil(t, x.ToV2())
})
}
func TestNewSignature(t *testing.T) {
t.Run("default values", func(t *testing.T) {
sg := New()
// check initial values
require.Nil(t, sg.Key())
require.Nil(t, sg.Sign())
// convert to v2 message
sgV2 := sg.ToV2()
require.Nil(t, sgV2.GetKey())
require.Nil(t, sgV2.GetSign())
})
}

View File

@ -1,15 +0,0 @@
package sigtest
import (
"github.com/nspcc-dev/neofs-sdk-go/signature"
)
// Signature returns random pkg.Signature.
func Signature() *signature.Signature {
x := signature.New()
x.SetKey([]byte("key"))
x.SetSign([]byte("sign"))
return x
}

View File

@ -1,119 +0,0 @@
package signature
import (
"crypto/ecdsa"
"errors"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-sdk-go/signature"
)
type DataSource interface {
ReadSignedData([]byte) ([]byte, error)
SignedDataSize() int
}
type DataWithSignature interface {
DataSource
GetSignature() *signature.Signature
SetSignature(*signature.Signature)
}
type SignOption func(*cfg)
const (
// PrivateKeyCompressedSize is constant with compressed size of private key (SK).
// D coordinate stored, recover PK by formula x, y = curve.ScalarBaseMul(d,bytes).
PrivateKeyCompressedSize = 32
// PublicKeyCompressedSize is constant with compressed size of public key (PK).
PublicKeyCompressedSize = 33
// PublicKeyUncompressedSize is constant with uncompressed size of public key (PK).
// First byte always should be 0x4 other 64 bytes is X and Y (32 bytes per coordinate).
// 2 * 32 + 1.
PublicKeyUncompressedSize = 65
)
var (
// ErrEmptyPrivateKey is returned when used private key is empty.
ErrEmptyPrivateKey = errors.New("empty private key")
// ErrInvalidPublicKey is returned when public key cannot be unmarshalled.
ErrInvalidPublicKey = errors.New("invalid public key")
// ErrInvalidSignature is returned if signature cannot be verified.
ErrInvalidSignature = errors.New("invalid signature")
)
func SignData(key *ecdsa.PrivateKey, src DataSource, opts ...SignOption) (res *signature.Signature, err error) {
err = signDataWithHandler(key, src, func(key, sig []byte, scheme signature.Scheme) {
res = new(signature.Signature)
res.SetKey(key)
res.SetSign(sig)
res.SetScheme(scheme)
}, opts...)
return
}
func VerifyData(dataSrc DataSource, sig *signature.Signature, opts ...SignOption) error {
return verifyDataWithSource(dataSrc, func() ([]byte, []byte, signature.Scheme) {
return sig.Key(), sig.Sign(), sig.Scheme()
}, opts...)
}
func SignDataWithHandler(key *ecdsa.PrivateKey, src DataSource, handler func(key, sig []byte)) error {
return signDataWithHandler(key, src, func(key, sig []byte, scheme signature.Scheme) {
handler(key, sig)
})
}
func signDataWithHandler(
key *ecdsa.PrivateKey,
src DataSource,
handler func(key, sig []byte, scheme signature.Scheme),
opts ...SignOption,
) error {
if key == nil {
return ErrEmptyPrivateKey
}
data, err := dataForSignature(src)
if err != nil {
return err
}
defer bytesPool.Put(&data)
cfg := getConfig(opts...)
sigData, err := sign(cfg.scheme, key, data)
if err != nil {
return err
}
handler((*keys.PublicKey)(&key.PublicKey).Bytes(), sigData, cfg.scheme)
return nil
}
func VerifyDataWithSource(dataSrc DataSource, sigSrc func() (key, sig []byte)) error {
return verifyDataWithSource(dataSrc, func() ([]byte, []byte, signature.Scheme) {
key, sign := sigSrc()
return key, sign, signature.ECDSAWithSHA512
})
}
func verifyDataWithSource(
dataSrc DataSource,
sigSrc func() (key, sig []byte, scheme signature.Scheme),
opts ...SignOption,
) error {
data, err := dataForSignature(dataSrc)
if err != nil {
return err
}
defer bytesPool.Put(&data)
cfg := getConfig(opts...)
return verify(cfg, data, sigSrc)
}

View File

@ -1,114 +0,0 @@
package signature
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"fmt"
"math/big"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-sdk-go/signature"
)
var curve = elliptic.P256()
type cfg struct {
schemeFixed bool
scheme signature.Scheme
}
func getConfig(opts ...SignOption) *cfg {
cfg := &cfg{
scheme: signature.ECDSAWithSHA512,
}
for i := range opts {
opts[i](cfg)
}
return cfg
}
func sign(scheme signature.Scheme, key *ecdsa.PrivateKey, msg []byte) ([]byte, error) {
switch scheme {
case signature.ECDSAWithSHA512:
h := sha512.Sum512(msg)
x, y, err := ecdsa.Sign(rand.Reader, key, h[:])
if err != nil {
return nil, err
}
return elliptic.Marshal(elliptic.P256(), x, y), nil
case signature.RFC6979WithSHA256:
p := &keys.PrivateKey{PrivateKey: *key}
return p.Sign(msg), nil
default:
panic(fmt.Sprintf("unsupported scheme %s", scheme))
}
}
func verify(cfg *cfg, msg []byte, f func() (key, sign []byte, scheme signature.Scheme)) error {
key, sign, scheme := f()
pub, err := keys.NewPublicKeyFromBytes(key, elliptic.P256())
if err != nil {
return fmt.Errorf("%w: %v", ErrInvalidPublicKey, err)
}
if !cfg.schemeFixed {
cfg.scheme = scheme
}
switch cfg.scheme {
case signature.ECDSAWithSHA512:
h := sha512.Sum512(msg)
r, s := unmarshalXY(sign)
if r != nil && s != nil && ecdsa.Verify((*ecdsa.PublicKey)(pub), h[:], r, s) {
return nil
}
return ErrInvalidSignature
case signature.RFC6979WithSHA256:
h := sha256.Sum256(msg)
if pub.Verify(sign, h[:]) {
return nil
}
return ErrInvalidSignature
default:
return fmt.Errorf("unsupported signature scheme %s", cfg.scheme)
}
}
// unmarshalXY converts a point, serialized by Marshal, into an x, y pair.
// It is an error if the point is not in uncompressed form.
// On error, x,y = nil.
// Unlike the original version of the code, we ignore that x or y not on the curve
// --------------
// It's copy-paste elliptic.Unmarshal(curve, data) stdlib function, without last line
// of code.
// Link - https://golang.org/pkg/crypto/elliptic/#Unmarshal
func unmarshalXY(data []byte) (x *big.Int, y *big.Int) {
if len(data) != PublicKeyUncompressedSize {
return
} else if data[0] != 4 { // uncompressed form
return
}
p := curve.Params().P
x = new(big.Int).SetBytes(data[1:PublicKeyCompressedSize])
y = new(big.Int).SetBytes(data[PublicKeyCompressedSize:])
if x.Cmp(p) >= 0 || y.Cmp(p) >= 0 {
x, y = nil, nil
}
return
}
func SignWithRFC6979() SignOption {
return func(c *cfg) {
c.schemeFixed = true
c.scheme = signature.RFC6979WithSHA256
}
}

View File

@ -1,31 +0,0 @@
package signature
import (
"errors"
"sync"
)
var bytesPool = sync.Pool{
New: func() interface{} {
b := make([]byte, 5<<20)
return &b
},
}
func dataForSignature(src DataSource) ([]byte, error) {
if src == nil {
return nil, errors.New("nil source")
}
buf := *bytesPool.Get().(*[]byte)
if size := src.SignedDataSize(); size < 0 {
return nil, errors.New("negative length")
} else if size <= cap(buf) {
buf = buf[:size]
} else {
buf = make([]byte, size)
}
return src.ReadSignedData(buf)
}