2019-02-07 09:04:29 +00:00
|
|
|
// 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
|
2019-02-07 17:08:52 +00:00
|
|
|
func VerifySignature(signedData, data []byte, pubKey crypto.PublicKey) error {
|
2019-02-07 09:04:29 +00:00
|
|
|
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)
|
|
|
|
}
|
2019-02-07 17:08:52 +00:00
|
|
|
digest := SHA256Hash(data)
|
2019-02-07 09:04:29 +00:00
|
|
|
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) {
|
2019-02-07 17:08:52 +00:00
|
|
|
hash := SHA256Hash(data)
|
2019-02-07 09:04:29 +00:00
|
|
|
signature, err := SignBytes(key, hash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, ErrSign.Wrap(err)
|
|
|
|
}
|
|
|
|
return signature, nil
|
|
|
|
}
|