forked from TrueCloudLab/frostfs-sdk-go
[#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>
This commit is contained in:
parent
2deaaeef05
commit
ea043f4ca3
33 changed files with 728 additions and 627 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
51
crypto/crypto_test.go
Normal file
51
crypto/crypto_test.go
Normal 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
Normal file
48
crypto/doc.go
Normal 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
|
11
crypto/ecdsa/doc.go
Normal file
11
crypto/ecdsa/doc.go
Normal 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
|
16
crypto/ecdsa/init.go
Normal file
16
crypto/ecdsa/init.go
Normal 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
|
||||
})
|
||||
}
|
78
crypto/ecdsa/public.go
Normal file
78
crypto/ecdsa/public.go
Normal 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)
|
||||
}
|
86
crypto/ecdsa/signer.go
Normal file
86
crypto/ecdsa/signer.go
Normal 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())
|
||||
}
|
85
crypto/signature.go
Normal file
85
crypto/signature.go
Normal 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
Normal file
83
crypto/signer.go
Normal 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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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[:])
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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())
|
||||
})
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
Loading…
Reference in a new issue