目錄
- Ecc簽名的Go實作
-
- crypto/ecdsa包
- 簽名
- 驗證簽名
- 測試代碼
- 截圖
- 參考
在Go-數字簽名詳解與Rsa數字簽名代碼中已經講了數字簽名的原理,就不重複了
Ecc簽名的Go實作
crypto/ecdsa包
使用私鑰對任意長度的hash值(必須是較大資訊的hash結果)進行簽名,傳回簽名結果(一對大整數)。私鑰的安全性取決于密碼讀取器的熵度(随機程度)。
使用公鑰驗證hash值和兩個大整數r、s構成的簽名,并傳回簽名是否合法。
簽名
- 使用sha256.Sum356擷取摘要
- 使用ecdsa.Sign進行簽名
- 對r s進行序列化
// Ecc 簽名
// plainText 明文
// priPath 私鑰路徑
// 傳回 簽名結果
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
}
驗證簽名
- -使用sha256.Sum356擷取摘要
- 對r s進行反序列化
- 使用ecdsa.Verify進行簽名認證
// 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/gocrypto
參考
《現代密碼學教程 谷利澤 楊義先等》
Go标準庫-crypto/ecdsa
Go-标準庫-crypto/sha256