github.com/code-to-go/safepool.lib@v0.0.0-20221205180519-ee25e63c226e/security/sign.go.bk (about)

     1  package security
     2  
     3  import (
     4  	"crypto/ed25519"
     5  	"crypto/rand"
     6  	"encoding/binary"
     7  	"io"
     8  	"github.com/code-to-go/safepool.lib/core"
     9  	"github.com/code-to-go/safepool.lib/protocol"
    10  
    11  	"github.com/golang/protobuf/proto"
    12  )
    13  
    14  type PublicKey ed25519.PublicKey
    15  type PrivateKey ed25519.PrivateKey
    16  
    17  const (
    18  	PublicKeySize  = ed25519.PublicKeySize
    19  	PrivateKeySize = ed25519.PrivateKeySize
    20  	SignatureSize  = ed25519.SignatureSize
    21  )
    22  
    23  type SignedData struct {
    24  	Signature [SignatureSize]byte
    25  	Signer    PublicKey
    26  }
    27  
    28  type Public struct {
    29  	Id    PublicKey
    30  	Nick  string
    31  	Email string
    32  }
    33  
    34  func NewIdentity() (model.Identity, error) {
    35  	public, private, err := ed25519.GenerateKey(rand.Reader)
    36  	if core.IsErr(err, "cannot generate ed25519 identity: %v") {
    37  		return model.Identity{}, err
    38  	}
    39  
    40  	return model.Identity{
    41  		Curve:   "ed25519",
    42  		Public:  PublicKey(public),
    43  		Private: PrivateKey(private),
    44  	}, nil
    45  }
    46  
    47  func Sign(private PrivateKey, data []byte) ([]byte, error) {
    48  	return ed25519.Sign(ed25519.PrivateKey(private), data), nil
    49  }
    50  
    51  func Verify(key PublicKey, data []byte, sig []byte) bool {
    52  	return ed25519.Verify(ed25519.PublicKey(key), data, sig)
    53  }
    54  
    55  func SignAndWrite(private PrivateKey, data []byte, w io.Writer, signatures [][]byte) error {
    56  	sign, err := Sign(private, data)
    57  	if core.IsErr(err, "cannot sign data: %v") {
    58  		return err
    59  	}
    60  	signedData := protocol.SignedData{
    61  		Version: 1,
    62  		Data:    data,
    63  	}
    64  
    65  	for _, s := range signatures {
    66  		signedData.Signatures = append(signedData.Signatures, s)
    67  	}
    68  	signedData.Signatures = append(signedData.Signatures, sign)
    69  
    70  	signedDataB, err := proto.Marshal(&signedData)
    71  	if core.IsErr(err, "cannot marshal signed data: %v") {
    72  		return err
    73  	}
    74  
    75  	lenB := make([]byte, 4)
    76  	binary.BigEndian.PutUint32(lenB, uint32(len(signedDataB)))
    77  	w.Write(lenB)
    78  	_, err = w.Write(signedDataB)
    79  	if core.IsErr(err, "cannot write signed data to stream: %v") {
    80  		return err
    81  	}
    82  	return nil
    83  }
    84  
    85  func ReadAndVerify(publics []PublicKey, r io.Reader) (data []byte, signatures [][]byte, err error) {
    86  	lenB := make([]byte, 4)
    87  	_, err = r.Read(lenB)
    88  	if core.IsErr(err, "cannot read length of data") {
    89  		return nil, nil, err
    90  	}
    91  
    92  	data = make([]byte, binary.BigEndian.Uint32(lenB))
    93  	_, err = r.Read(data)
    94  	if core.IsErr(err, "cannot read signed data") {
    95  		return nil, nil, err
    96  	}
    97  
    98  	var signedData protocol.SignedData
    99  	err = proto.Unmarshal(data, &signedData)
   100  	if core.IsErr(err, "cannot unmarshall signed data: %v") {
   101  		return nil, nil, err
   102  	}
   103  
   104  	if signedData.Version >= 2.0 {
   105  		return nil, nil, core.ErrInvalidVersion
   106  	}
   107  
   108  	verified := false
   109  out:
   110  	for _, s := range signedData.Signatures {
   111  		for _, p := range publics {
   112  			if Verify(p, signedData.Data, s) {
   113  				verified = true
   114  				break out
   115  			}
   116  		}
   117  	}
   118  
   119  	if verified {
   120  		return signedData.Data, signedData.Signatures, nil
   121  	} else {
   122  		return nil, nil, core.ErrInvalidSignature
   123  	}
   124  }