欢迎来到我的博客,愿共同成长!!!

信徒

路虽远,行则将至

签名验签

1. 生成公私钥对

以下算法只支持生成RSA和ECDSA的公私钥对:

 1 import (
 2     "crypto/ecdsa"
 3     "crypto/elliptic"
 4     "crypto/rand"
 5     "crypto/rsa"
 6     "crypto/x509"
 7     "errors"
 8     "fmt"
 9 )
10 
11 // the size of ecdsa algorithm
12 const (
13     curveP256 = 256
14     curveP384 = 384
15     curveP521 = 521
16 )
17 
18 type AlgoType uint8
19 
20 const (
21     RSA AlgoType = iota + 1 // rsa
22     ECC                     // ecdsa
23 )
24 
25 // GenerateKeyPairs generates a key pairs as specified in the request. Currently,
26 // only ECDSA and RSA are supported.
27 //
28 // GenerateKeyPairs returns DER encoding private key and public key.
29 func GenerateKeyPairs(algo AlgoType, size int) ([]byte, []byte, error) {
30     switch algo {
31     case RSA:
32         if size < 2048 {
33             return nil, nil, errors.New("RSA key is too weak")
34         }
35         if size > 8192 {
36             return nil, nil, errors.New("RSA key size too large")
37         }
38         priv, err := rsa.GenerateKey(rand.Reader, size)
39         if err != nil {
40             return nil, nil, fmt.Errorf("generate rsa key: %v", err.Error())
41         }
42         pub := priv.Public()
43         pubBytes := x509.MarshalPKCS1PublicKey(pub.(*rsa.PublicKey))
44         privBytes := x509.MarshalPKCS1PrivateKey(priv)
45         return privBytes, pubBytes, nil
46     case ECC:
47         var curve elliptic.Curve
48         switch size {
49         case curveP256:
50             curve = elliptic.P256()
51         case curveP384:
52             curve = elliptic.P384()
53         case curveP521:
54             curve = elliptic.P521()
55         default:
56             return nil, nil, errors.New("invalid ecdsa curve")
57         }
58         priv, err := ecdsa.GenerateKey(curve, rand.Reader)
59         if err != nil {
60             return nil, nil, fmt.Errorf("generate ecdsa key: %v", err.Error())
61         }
62         pubBytes, err := x509.MarshalPKIXPublicKey(priv.Public())
63         if err != nil {
64             return nil, nil, fmt.Errorf("marshal ecdsa public key: %v", err.Error())
65         }
66         privBytes, err := x509.MarshalECPrivateKey(priv)
67         if err != nil {
68             return nil, nil, fmt.Errorf("marshal ecdsa private key: %v", err.Error())
69         }
70         return privBytes, pubBytes, nil
71     default:
72         return nil, nil, errors.New("invalid algorithm")
73     }
74 }

2. 签名

签名的步骤如下:

① 基于待签名的数据生成摘要;

② 使用私钥对摘要生成签名。

代码如下:

// Sign signs a message using a specific private key. Private key passed must
// be DER encoding. Note that using sha256 hash function to create digest.
//
// Sign returns a signature.
func Sign(privKey, msg []byte) ([]byte, error) {
    priv, err := ParsePrivateKeyDER(privKey)
    if err != nil {
        return nil, fmt.Errorf("parse private key: %v", err.Error())
    }
    // create digest
    h := sha256.New()
    h.Write(msg)
    digest := h.Sum(nil)
    // sign
    sign, err := priv.Sign(rand.Reader, digest, crypto.SHA256)
    if err != nil {
        return nil, fmt.Errorf("sign: %v", err.Error())
    }
    return sign, nil
}

由上面代码可以看出,我们使用的是sha256算法计算摘要,也可以使用其它散列算法。

由于前面生成的私钥是ASN.1 DER编码的,所以需要将其解析成crypto.Signer才能调用签名的接口,解析的代码如下:

 1 // ParsePrivateKeyDER parses a PKCS #1, PKCS #8, ECDSA, or Ed25519 DER-encoded
 2 // private key. The key must not be in PEM format.
 3 func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) {
 4     generalKey, err := x509.ParsePKCS8PrivateKey(keyDER)
 5     if err != nil {
 6         generalKey, err = x509.ParsePKCS1PrivateKey(keyDER)
 7         if err != nil {
 8             generalKey, err = x509.ParseECPrivateKey(keyDER)
 9             if err != nil {
10                 return nil, errors.New("parse private key field.")
11             }
12         }
13     }
14 
15     switch generalKey.(type) {
16     case *rsa.PrivateKey:
17         return generalKey.(*rsa.PrivateKey), nil
18     case *ecdsa.PrivateKey:
19         return generalKey.(*ecdsa.PrivateKey), nil
20     }
21 
22     // should never reach here
23     return nil, errors.New("parse private key field.")
24 }

3. 验签

验签的过程是将源数据再次使用上述的散列算法计算摘要,然后使用公钥将签名解签,最后将解签的结果与摘要进行对比,相同则说明验签通过,代码如下:

// VerifySignature verifies signature. Currently, only ECDSA and RSA are supported.
// Note that signature(including R and S) must be marshaled using ASN.1 standard
// when using ecdsa algorithm.
func VerifySignature(pubKey, sign, msg []byte) error {
    //Create digest
    hash := sha256.New()
    hash.Write(msg)
    digest := hash.Sum(nil)

    pub, err := x509.ParsePKIXPublicKey(pubKey)
    if err != nil {
        pub, err = x509.ParsePKCS1PublicKey(pubKey)
        if err != nil {
            return fmt.Errorf("public key of unknown type: %v", err.Error())
        }
    }
    switch pub.(type) {
    case *rsa.PublicKey:
        publickey := pub.(*rsa.PublicKey)
        err = rsa.VerifyPKCS1v15(publickey, crypto.SHA256, digest, sign)
        if err != nil {
            return fmt.Errorf("verify signature: %v", err.Error())
        }
    case *ecdsa.PublicKey:
        publickey := pub.(*ecdsa.PublicKey)
        parsedSign := struct {
            R *big.Int
            S *big.Int
        }{}
        rest, err := asn1.Unmarshal(sign, &parsedSign)
        if err != nil {
            return fmt.Errorf("parse ecc signature using ASN.1 standard: %v", err.Error())
        }
        if len(rest) > 0 {
            return errors.New("extra data in marshaled sign data.")
        }
        isValid := ecdsa.Verify(publickey, digest, parsedSign.R, parsedSign.S)
        if !isValid {
            return errors.New("verify signature failed.")
        }
    }

    return nil
}
posted @ 2019-12-25 17:22  LeslieRan  阅读(283)  评论(0)    收藏  举报