golang实现摘要签名和验证的过程:
两个步骤:
- 利用私钥对一个摘要进行签名。
$ ./test -command sign -key ./privatekey.pem -text "12345"
MEUCIE7DsGmTHJ3VGZec2UF9hRX7jq9Yd7F2kS7kEL132js8AiEA/ZlyIpo86Rn3waR8m2c4BtQPu8cNjYAnroibK+ujslY=
- 利用公钥验证签名是否有效。
$ ./test -command verify -cert ./publickey.pem -text "12345" -sign "MEQCIFuvcVHlztAN7YVehgCDYzVSo1Q10iTKeJE5ydxzfih5AiAC2ETt/8XuE1VHaGkLsiJkRSueh65Leq2VKkmFKxB/sQ=="
Successed to verify Signature and nonce
下面是代码原文:
package main
import (
"fmt"
"flag"
"io/ioutil"
"math/big"
"crypto/ecdsa"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"encoding/asn1"
"encoding/base64"
"encoding/pem"
)
type ECDSASignature struct {
R, S *big.Int
}
var (
command string
certfile string
keyfile string
text string
sign string
)
func main() {
flag.StringVar(&command, "command", "", "Command: sign/verify")
flag.StringVar(&keyfile, "key", "", "Private key file")
flag.StringVar(&certfile, "cert", "", "Public key file")
flag.StringVar(&text, "text", "", "Text content to be signed")
flag.StringVar(&sign, "sign", "", "Signed content to be verifed")
flag.Parse()
switch command {
case "sign":
if keyfile == "" || text == "" {
fmt.Printf("ERROR: either key file or text is empty\n")
return
}
Sign(keyfile, text)
case "verify":
if certfile == "" || text == "" || sign == "" {
fmt.Printf("ERROR: either key file or text or sign is empty\n")
return
}
Verify(certfile, text, sign)
default:
fmt.Printf("ERROR: unknown command\n")
return
}
}
func Sign(keyFile, text string) {
keyBuff, err := ioutil.ReadFile(keyFile)
if err != nil {
fmt.Printf("ERROR: failed to read keystore file: %s, error: %v\n", keyFile, err)
return
}
block, _ := pem.Decode(keyBuff)
if block == nil {
fmt.Printf("ERROR: block of decoded private key is nil\n")
return
}
privKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
fmt.Printf("ERROR: failed get ECDSA private key, %v\n", err)
return
}
ecPrivKey := privKey.(*ecdsa.PrivateKey)
hash := sha256.Sum256([]byte(text))
r, s, err := ecdsa.Sign(rand.Reader, ecPrivKey, hash[:])
if err != nil {
fmt.Printf("ERROR: failed to get signature, %v\n", err)
return
}
// asn1 output DER format
signature, err := asn1.Marshal(ECDSASignature{
R: r,
S: s,
})
if err != nil {
fmt.Printf("ERROR: asn1.Marshal ECDSA signature: %v\n", err)
return
}
fmt.Printf("%s\n", base64.StdEncoding.EncodeToString(signature))
}
func Verify(certFile, text string, sign string) {
certBuff, err := ioutil.ReadFile(certFile)
if err != nil {
fmt.Printf("ERROR: failed to read keystore file: %s, error: %s\n", certFile, err)
return
}
block, _ := pem.Decode(certBuff)
if block == nil {
fmt.Printf("ERROR: block of decoded private key is nil\n")
return
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
fmt.Printf("ERROR: failed get ECDSA private key, error: %v\n", err)
return
}
arr := []byte(text)
h := sha256.New()
h.Write(arr)
hashed := h.Sum(nil)
signatureDec, _ := base64.StdEncoding.DecodeString(sign)
sig := new(ECDSASignature)
_, err = asn1.Unmarshal(signatureDec, sig)
if err != nil {
fmt.Printf("ERROR: failed unmashalling signature, error: %v", err)
return
}
pub, _ := cert.PublicKey.(*ecdsa.PublicKey)
if !ecdsa.Verify(pub, hashed[:], sig.R, sig.S) {
fmt.Printf("ERROR: Failed to verify Signature: %v\n", err)
return
}
fmt.Printf("Successed to verify Signature and nonce\n")
return
}