8.1.1ECC数字签名(ECDSA)核心代码
下面通过一个案例验证数字签名,如例所示。
例1-1 ECDSA
1 package main
2 import (
3 "crypto/ecdsa"
4 "crypto/elliptic"
5 "crypto/rand"
6 "crypto/sha256"
7 "encoding/hex"
8 "fmt"
9 "log"
10 "math/big"
11 )
12 func main() {
13 fmt.Println("生成签名-------------------------------")
14 privKey, pubKey := NewKeyPair()
15 msg := sha256.Sum256([]byte("hello world"))
16 r, s, _ := ecdsa.Sign(rand.Reader, &privKey, msg[:])
17 strSigR := fmt.Sprintf("%x", r)
18 strSigS := fmt.Sprintf("%x", s)
19 fmt.Println("r、s的10进制分别为:", r, s)
20 fmt.Println("r、s的16进制分别为:", strSigR, strSigS)
21 signatureDer := MakeSignatureDerString(strSigR, strSigS)
22 fmt.Println("数字签名DER格式为:", signatureDer)
23 res := VerifySig(pubKey, msg[:], r, s)
24 fmt.Println("签名验证结果:", res)
25 res = VerifySignature(pubKey, msg[:], strSigR, strSigS)
26 fmt.Println("签名验证结果:", res)
27 }
28 func NewKeyPair() (ecdsa.PrivateKey, []byte) {
29 curve := elliptic.P256()
30 private, err := ecdsa.GenerateKey(curve, rand.Reader)
31 if err != nil {
32 log.Panic(err)
33 }
34 pubKey := append(private.X.Bytes(), private.Y.Bytes()...)
35 return *private, pubKey
36 }
37 func MakeSignatureDerString(r, s string) string {
38 lenSigR := len(r) / 2
39 lenSigS := len(s) / 2
40 lenSequence := lenSigR + lenSigS + 4
41 strLenSigR := DecimalToHex(int64(lenSigR))
42 strLenSigS := DecimalToHex(int64(lenSigS))
43 strLenSequence := DecimalToHex(int64(lenSequence))
44 derString := "30" + strLenSequence
45 derString = derString + "02" + strLenSigR + r
46 derString = derString + "02" + strLenSigS + s
47 derString = derString + "01"
48 return derString
49 }
50 func VerifySig(pubKey, message []byte, r, s *big.Int) bool {
51 curve := elliptic.P256()
52 keyLen := len(pubKey)
53 x := big.Int{}
54 y := big.Int{}
55 x.SetBytes(pubKey[:(keyLen / 2)])
56 y.SetBytes(pubKey[(keyLen / 2):])
57 rawPubKey := ecdsa.PublicKey{curve, &x, &y}
58 res := ecdsa.Verify(&rawPubKey, message, r, s)
59 return res
60 }
61 func VerifySignature(pubKey, message []byte, r, s string) bool {
62 curve := elliptic.P256()
63 keyLen := len(pubKey)
64 x := big.Int{}
65 y := big.Int{}
66 x.SetBytes(pubKey[:(keyLen / 2)])
67 y.SetBytes(pubKey[(keyLen / 2):])
68 rawPubKey := ecdsa.PublicKey{curve, &x, &y}
69 rint := big.Int{}
70 sint := big.Int{}
71 rByte, _ := hex.DecodeString(r)
72 sByte, _ := hex.DecodeString(s)
73 rint.SetBytes(rByte)
74 sint.SetBytes(sByte)
75 res := ecdsa.Verify(&rawPubKey, message, &rint, &sint)
76 return res
77 }
78 func DecimalToHex(n int64) string {
79 if n < 0 {
80 log.Println("Decimal to hexadecimal error: the argument must be greater than zero.")
81 return ""
82 }
83 if n == 0 {
84 return "0"
85 }
86 hex := map[int64]int64{10: 65, 11: 66, 12: 67, 13: 68, 14: 69, 15: 70}
87 s := ""
88 for q := n; q > 0; q = q / 16 {
89 m := q % 16
90 if m > 9 && m < 16 {
91 m = hex[m]
92 s = fmt.Sprintf("%v%v", string(m), s)
93 continue
94 }
95 s = fmt.Sprintf("%v%v", m, s)
96 }
97 return s
98 }
运行结果如图所示。由于数字签名字段过长,这里只截取了一部分。
图8.1 运行结果