Wednesday, January 20, 2021

Using ECDSA in GO to Sign and Verify messages

 



In this post we will review how to sign and verify messages in GO using ECDSA. This is an asymmetric encryption mechanism that is based on elliptic curve cryptography.


This post covers using a-symmetric encryption for sign/verify. In case of need of a-symmetric encryption to encrypt/decrypt, check this post.


First, lets generate a private key.



import (
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"fmt"
"github.com/decred/dcrd/dcrec/secp256k1"
"math/big"
)

func main() {
privateKeySecp256k1, err := secp256k1.GeneratePrivateKey()
if err != nil {
panic(err)
}
privateKey := (*ecdsa.PrivateKey)(privateKeySecp256k1)



The private key is based on a secret. This secret can be exported if we want to later import reload the same private key.



exportedSecret := fmt.Sprintf("%x", privateKey.D)

d := new(big.Int)
d.SetString(exportedSecret, 16)
privateKey = new(ecdsa.PrivateKey)
privateKey.PublicKey.Curve = secp256k1.S256()
privateKey.D = d

privateKey.PublicKey.X, privateKey.PublicKey.Y = privateKey.PublicKey.Curve.ScalarBaseMult(privateKey.D.Bytes())



From the private key, we can deduce the public key. The public key is used for verification of the signature, and as its name implied, is public, so we should send to the party that needs to verify the sender identity. The public key can be send using the X,Y variables, and imported on the other party side.



publicKey := privateKey.PublicKey
exportedPublicX := fmt.Sprintf("%x", publicKey.X)
exportedPublicY := fmt.Sprintf("%x", publicKey.Y)

x := new(big.Int)
x.SetString(exportedPublicX, 16)
y := new(big.Int)
y.SetString(exportedPublicY, 16)

importedPublicKey := ecdsa.PublicKey{
Curve: secp256k1.S256(),
X: x,
Y: y,
}



Once we have a private key (generated or imported) we can sign messages. First we hash the message using sha256, and then we sign the hash. The result of the signature is two variables: R,S. These should be sent as additional metadata for authentication of the message sender identify (as well as the public key that we have already sent). 




message := "Hello World!"
hash := sha256.Sum256([]byte(message))

r, s, err := ecdsa.Sign(rand.Reader, privateKey, hash[:])
if err != nil {
panic(err)
}



To verify the message we use the public key.



publicKey := privateKey.PublicKey
verified := ecdsa.Verify(&publicKey, hash[:], r, s)
if !verified {
panic("verify failed")
}




No comments:

Post a Comment