storj/pkg/pkcrypto/signing.go

72 lines
1.9 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package pkcrypto
import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"encoding/asn1"
"math/big"
)
// ECDSASignature holds the `r` and `s` values in an ecdsa signature
// (see https://golang.org/pkg/crypto/ecdsa)
type ECDSASignature struct {
R, S *big.Int
}
var authECCurve = elliptic.P256()
// GeneratePrivateKey returns a new PrivateKey for signing messages
func GeneratePrivateKey() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(authECCurve, rand.Reader)
}
// VerifySignature checks the signature against the passed data and public key
func VerifySignature(signedData, data []byte, pubKey crypto.PublicKey) error {
key, ok := pubKey.(*ecdsa.PublicKey)
if !ok {
return ErrUnsupportedKey.New("%T", key)
}
signature := new(ECDSASignature)
if _, err := asn1.Unmarshal(signedData, signature); err != nil {
return ErrVerifySignature.New("unable to unmarshal ecdsa signature: %v", err)
}
digest := SHA256Hash(data)
if !ecdsa.Verify(key, digest, signature.R, signature.S) {
return ErrVerifySignature.New("signature is not valid")
}
return nil
}
// SignBytes signs the given data with the private key and returns the new
// signature. Normally, data here is a digest of some longer string of bytes.
func SignBytes(key crypto.PrivateKey, data []byte) ([]byte, error) {
ecKey, ok := key.(*ecdsa.PrivateKey)
if !ok {
return nil, ErrUnsupportedKey.New("%T", key)
}
r, s, err := ecdsa.Sign(rand.Reader, ecKey, data)
if err != nil {
return nil, ErrSign.Wrap(err)
}
return asn1.Marshal(ECDSASignature{R: r, S: s})
}
// SignHashOf signs a SHA-256 digest of the given data and returns the new
// signature.
func SignHashOf(key crypto.PrivateKey, data []byte) ([]byte, error) {
hash := SHA256Hash(data)
signature, err := SignBytes(key, hash)
if err != nil {
return nil, ErrSign.Wrap(err)
}
return signature, nil
}