iris/crypto/sign/sign.go

146 lines
3.8 KiB
Go
Raw Normal View History

// Package sign signs and verifies any format of data by
// using the ECDSA P-384 digital signature and authentication algorithm.
//
// https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm
// https://apps.nsa.gov/iaarchive/library/ia-guidance/ia-solutions-for-classified/algorithm-guidance/suite-b-implementers-guide-to-fips-186-3-ecdsa.cfm
// https://www.nsa.gov/Portals/70/documents/resources/everyone/csfc/csfc-faqs.pdf
package sign
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509" // the key encoding.
"encoding/pem" // the data encoding format.
"errors"
"math/big"
// the, modern, hash implementation,
// commonly used in popular crypto concurrencies too.
"golang.org/x/crypto/sha3"
)
// MustGenerateKey generates a public and private key pair.
// It panics if any error occurred.
func MustGenerateKey() *ecdsa.PrivateKey {
privateKey, err := GenerateKey()
if err != nil {
panic(err)
}
return privateKey
}
// GenerateKey generates a public and private key pair.
func GenerateKey() (*ecdsa.PrivateKey, error) {
return ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
}
// GeneratePrivateKey generates a private key as pem text.
// It returns empty on any error.
func GeneratePrivateKey() string {
privateKey, err := GenerateKey()
if err != nil {
return ""
}
privateKeyB, err := marshalPrivateKey(privateKey)
if err != nil {
return ""
}
return string(privateKeyB)
}
// Sign signs the "data" using the "privateKey".
// It returns the signature.
func Sign(privateKey *ecdsa.PrivateKey, data []byte) ([]byte, error) {
h := sha3.New256()
_, err := h.Write(data)
if err != nil {
return nil, err
}
digest := h.Sum(nil)
r, s, err := ecdsa.Sign(rand.Reader, privateKey, digest)
if err != nil {
return nil, err
}
// sig := elliptic.Marshal(elliptic.P256(), r, s)
sig := append(r.Bytes(), s.Bytes()...)
return sig, nil
}
// Verify verifies the "data" in signature "sig" (96 length if 384) using the "publicKey".
// It reports whether the signature is valid or not.
func Verify(publicKey *ecdsa.PublicKey, sig, data []byte) (bool, error) {
h := sha3.New256()
_, err := h.Write(data)
if err != nil {
return false, err
}
digest := h.Sum(nil)
// 0:32 & 32:64 for 256, always because it's constant.
// 0:48 & 48:96 for 384 but it is not constant-time, so it's 96 or 97 length,
// also something like that elliptic.Unmarshal(elliptic.P384(), sig)
// doesn't work.
r := new(big.Int).SetBytes(sig[0:32])
s := new(big.Int).SetBytes(sig[32:64])
return ecdsa.Verify(publicKey, digest, r, s), nil
}
var errNotValidBlock = errors.New("invalid block")
// ParsePrivateKey accepts a pem x509-encoded private key and decodes to *ecdsa.PrivateKey.
func ParsePrivateKey(key []byte) (*ecdsa.PrivateKey, error) {
block, _ := pem.Decode(key)
if block == nil {
return nil, errNotValidBlock
}
return x509.ParseECPrivateKey(block.Bytes)
}
// ParsePublicKey accepts a pem x509-encoded public key and decodes to *ecdsa.PrivateKey.
func ParsePublicKey(key []byte) (*ecdsa.PublicKey, error) {
block, _ := pem.Decode(key)
if block == nil {
return nil, errNotValidBlock
}
publicKeyV, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
publicKey, ok := publicKeyV.(*ecdsa.PublicKey)
if !ok {
return nil, errNotValidBlock
}
return publicKey, nil
}
func marshalPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) {
privateKeyAnsDer, err := x509.MarshalECPrivateKey(key)
if err != nil {
return nil, err
}
return pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privateKeyAnsDer}), nil
}
func marshalPublicKey(key *ecdsa.PublicKey) ([]byte, error) {
publicKeyAnsDer, err := x509.MarshalPKIXPublicKey(key)
if err != nil {
return nil, err
}
return pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: publicKeyAnsDer}), nil
}