Skip to content

Instantly share code, notes, and snippets.

@elazarl
Created March 31, 2014 20:49
Show Gist options
  • Save elazarl/9901904 to your computer and use it in GitHub Desktop.
Save elazarl/9901904 to your computer and use it in GitHub Desktop.
An ECDSA based signature scheme compatible with openssl sha256 -sign/-verify
// A signer/verifier compatible with openssl ecdsa signature scheme
//
// $ openssl ecparam -name prime256v1 -genkey -noout >ec.pem
// $ openssl ec -pubout <ec.pem >ecpub.pem
//
// and with sha256 verification
//
// $ echo a|openssl sha256 -sign ec.pem > sig.bin
// $ echo a|openssl sha256 -verify ecpub.pem -signature sig.bin
//
// Usage example:
//
// $ echo a|go run ecdsa_sign.go -key ec.pem > sig.bin
// $ echo a|go run ecdsa_sign.go -key ecpub.pem -verify sig.bin
// true
// $ echo aa|go run ecdsa_sign.go -key ecpub.pem -verify sig.bin
// false
package main
import (
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/hex"
"encoding/pem"
"flag"
"fmt"
"io"
"io/ioutil"
"math/big"
"os"
)
func orDie(msg string, err error) {
if err != nil {
fmt.Println(msg+":", err)
os.Exit(1)
}
}
type ECSignature struct {
R *big.Int
S *big.Int
}
func main() {
keyfile := flag.String("key", "", "relevant key (public to verify, private to sign")
verify := flag.String("verify", "", "signature file to verify input with")
hexOut := flag.Bool("hex", false, "should I output hexadecimal string")
flag.Parse()
if *keyfile == "" {
fmt.Println("Argument key must be provided")
os.Exit(1)
}
pemdata, err := ioutil.ReadFile(*keyfile)
orDie("Error reading key "+*keyfile, err)
der, _ := pem.Decode(pemdata)
h := sha256.New()
io.Copy(h, os.Stdin)
if *verify == "" {
key, err := x509.ParseECPrivateKey(der.Bytes)
orDie("Parsing key", err)
var sig ECSignature
// no need to trim anything, prime256 param has 256 bit,
// exactly like sha256 output
sig.R, sig.S, err = ecdsa.Sign(rand.Reader, key, h.Sum(nil))
orDie("signing", err)
sigBytes, err := asn1.Marshal(sig)
orDie("marshal to ASN.1", err)
if *hexOut {
sigBytes = []byte(hex.EncodeToString(sigBytes) + "\n")
}
os.Stdout.Write(sigBytes)
} else {
key, err := x509.ParsePKIXPublicKey(der.Bytes)
orDie("Parsing key", err)
if _, ok := key.(*ecdsa.PublicKey); !ok {
fmt.Printf("Provided key is not an ECDSA key: %T\n", key)
os.Exit(1)
}
sigder, err := ioutil.ReadFile(*verify)
orDie("Read signature", err)
var sig ECSignature
_, err = asn1.Unmarshal(sigder, &sig)
orDie("Parsing signature", err)
fmt.Println(ecdsa.Verify(key.(*ecdsa.PublicKey), h.Sum(nil), sig.R, sig.S))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment