在Go-數字簽名詳解與Rsa數字簽名代碼中已經講了數字簽名的原理,就不重複了git
Ecc簽名的Go實現func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error)
使用私鑰對任意長度的hash值(必須是較大信息的hash結果)進行簽名,返回簽名結果(一對大整數)。私鑰的安全性取決於密碼讀取器的熵度(隨機程度)。golang
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool
使用公鑰驗證hash值和兩個大整數r、s構成的簽名,並返回簽名是否合法。安全
// Ecc 簽名
// plainText 明文
// priPath 私鑰路徑
// 返回 簽名結果ide
func ECCSign(plainText []byte,priPath string) ([]byte,[]byte,error) { // get pem.Block block,err := util.GetKey(priPath) if err != nil{ _, file, line, _ := runtime.Caller(0) return nil,nil,util.Error(file,line+1,err.Error()) } // x509 priKey,err := x509.ParseECPrivateKey(block.Bytes) if err != nil{ _, file, line, _ := runtime.Caller(0) return nil,nil,util.Error(file,line+1,err.Error()) } hashText := sha256.Sum256(plainText) // sign r,s,err := ecdsa.Sign(rand.Reader,priKey,hashText[:]) if err != nil{ _, file, line, _ := runtime.Caller(0) return nil,nil,util.Error(file,line+1,err.Error()) } // marshal rText,err := r.MarshalText() if err != nil{ _, file, line, _ := runtime.Caller(0) return nil,nil,util.Error(file,line+1,err.Error()) } sText,err := s.MarshalText() if err != nil{ _, file, line, _ := runtime.Caller(0) return nil,nil,util.Error(file,line+1,err.Error()) } return rText,sText,nil }
// ECC 簽名驗證
// plainText 明文
// rText,sText 簽名
// pubPath公鑰文件路徑
// 返回 驗簽結果 錯誤測試
func ECCVerify(plainText,rText,sText []byte,pubPath string) (bool,error) { // get pem.Block block,err := util.GetKey(pubPath) if err != nil{ _, file, line, _ := runtime.Caller(0) return false,util.Error(file,line+1,err.Error()) } // x509 pubInter,err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil{ _, file, line, _ := runtime.Caller(0) return false,util.Error(file,line+1,err.Error()) } // assert pubKey := pubInter.(*ecdsa.PublicKey) hashText := sha256.Sum256(plainText) var r,s big.Int // unmarshal err = r.UnmarshalText(rText) if err != nil{ _, file, line, _ := runtime.Caller(0) return false,util.Error(file,line+1,err.Error()) } err = s.UnmarshalText(sText) if err != nil{ _, file, line, _ := runtime.Caller(0) return false,util.Error(file,line+1,err.Error()) } // verify ok := ecdsa.Verify(pubKey,hashText[:],&r,&s) return ok,nil }
plainText := []byte("張華考上了北京大學;李萍進了中等技術學校;我在百貨公司當售貨員:咱們都有美好的將來") rText,sText, _ := ECCSign(plainText,"./eccPrivate.pem") ok, err := ECCVerify(plainText,rText,sText,"./eccPublic.pem") fmt.Println(err) fmt.Printf("驗證成功? %t",ok)截圖
所有代碼放到了gitee.com/frankyu365/gocryptospa
《現代密碼學教程 谷利澤 楊義先等》
Go標準庫-crypto/ecdsa
Go-標準庫-crypto/sha256code