golang中的数字签名
數(shù)字簽名
數(shù)字簽名的方法
簽名的生成和驗證
- 有原始數(shù)據(jù)對其進行哈希運算 -> 散列值
- 使用非對稱加密的私鑰對散列值加密 -> 簽名
- 將原始數(shù)據(jù)和簽名一并發(fā)送給對方
- 接收數(shù)據(jù)
- 原始數(shù)據(jù)
- 數(shù)字簽名
- 數(shù)字簽名, 需要使用公鑰解密, 得到散列值
- 對原始數(shù)據(jù)進行哈希運算得到新的散列值
非對稱加密和數(shù)字簽名
總結(jié):
- 公鑰加密, 私鑰解密
使用RSA進行數(shù)字簽名
使用rsa生成密鑰對
使用私鑰進行數(shù)字簽名
打開磁盤的私鑰文件
將私鑰文件中的內(nèi)容讀出
使用pem對數(shù)據(jù)解碼, 得到了pem.Block結(jié)構(gòu)體變量
x509將數(shù)據(jù)解析成私鑰結(jié)構(gòu)體 -> 得到了私鑰
創(chuàng)建一個哈希對象 -> md5/sha1
給哈希對象添加數(shù)據(jù)
計算哈希值
使用rsa中的函數(shù)對散列值簽名
func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error) 參數(shù)1: rand.Reader 參數(shù)2: 非對稱加密的私鑰 參數(shù)3: 使用的哈希算法crypto.sha1crypto.md5 參數(shù)4: 數(shù)據(jù)計算之后得到的散列值 返回值: - s: 得到的簽名數(shù)據(jù) - err: 錯誤信息使用公鑰進行簽名認證
打開公鑰文件, 將文件內(nèi)容讀出 - []byte
使用pem解碼 -> 得到pem.Block結(jié)構(gòu)體變量
使用x509對pem.Block中的Bytes變量中的數(shù)據(jù)進行解析 -> 得到一接口
進行類型斷言 -> 得到了公鑰結(jié)構(gòu)體
對原始消息進行哈希運算(和簽名使用的哈希算法一致) -> 散列值
簽名認證 - rsa中的函數(shù)
func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error) 參數(shù)1: 公鑰 參數(shù)2: 哈希算法 -> 與簽名使用的哈希算法一致 參數(shù)3: 將原始數(shù)據(jù)進行哈希原始得到的散列值 參數(shù)4: 簽名的字符串 返回值: - nil -> 驗證成功- !=nil -> 失敗使用橢圓曲線進行數(shù)字簽名
橢圓曲線在go中對應的包: import "crypto/elliptic"
使用橢圓曲線在go中進行數(shù)字簽名: import "crypto/ecdsa"
美國FIPS186-2標準, 推薦使用5個素域上的橢圓曲線, 這5個素數(shù)模分別是:
P~192~ = 2^192^ - 2^64^ - 1
P~224~ = 2^224^ - 2^96^ + 1
P~256~ = 2^256^ - 2^224^ + 2^192^ - 2^96^ -1
P~384~ = 2^384^ - 2^128^ - 2^96^ + 2^32^ -1
P~512~ = 2^512^ - 1
秘鑰對稱的生成, 并保存到磁盤
使用ecdsa生成密鑰對
func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error)將私鑰寫入磁盤
-
使用x509進行序列化
func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) -
將得到的切片字符串放入pem.Block結(jié)構(gòu)體中
block := pem.Block{
Type : "描述....",
Bytes : MarshalECPrivateKey返回值中的切片字符串,
}
-
使用pem編碼
pem.Encode();
將公鑰寫入磁盤
-
從私鑰中得到公鑰
-
使用x509進行序列化
func MarshalPKIXPublicKey(pub interface{}) ([]byte, error) -
將得到的切片字符串放入pem.Block結(jié)構(gòu)體中
block := pem.Block{
Type : "描述....",
Bytes : MarshalECPrivateKey返回值中的切片字符串,
}
-
使用pem編碼
pem.Encode();
使用私鑰進行數(shù)字簽名
打開私鑰文件, 將內(nèi)容讀出來 ->[]byte
使用pem進行數(shù)據(jù)解碼 -> pem.Decode()
使用x509, 對私鑰進行還原
func ParseECPrivateKey(der []byte) (key *ecdsa.PrivateKey, err error)對原始數(shù)據(jù)進行哈希運算 -> 散列值
進行數(shù)字簽名
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) - 得到的r和s不能直接使用, 因為這是指針應該將這兩塊內(nèi)存中的數(shù)據(jù)進行序列化 -> []bytefunc (z *Int) MarshalText() (text []byte, err error)使用公鑰驗證數(shù)字簽名
打開公鑰文件, 將里邊的內(nèi)容讀出 -> []byte
pem解碼 -> pem.Decode()
使用x509對公鑰還原
func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error)將接口 -> 公鑰
對原始數(shù)據(jù)進行哈希運算 -> 得到散列值
簽名的認證 - > ecdsa
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool - 參數(shù)1: 公鑰 - 參數(shù)2: 原始數(shù)據(jù)生成的散列值 - 參數(shù)3,4: 通過簽名得到的連個點func (z *Int) UnmarshalText(text []byte) error數(shù)字簽名無法解決的問題
代碼
RSA簽名和認證
// RSA簽名 - 私鑰 func SignatureRSA(plainText []byte, fileName string) []byte{//1. 打開磁盤的私鑰文件file, err := os.Open(fileName)if err != nil {panic(err)}//2. 將私鑰文件中的內(nèi)容讀出info, err := file.Stat()if err != nil {panic(err)}buf := make([]byte, info.Size())file.Read(buf)file.Close()//3. 使用pem對數(shù)據(jù)解碼, 得到了pem.Block結(jié)構(gòu)體變量block, _ := pem.Decode(buf)//4. x509將數(shù)據(jù)解析成私鑰結(jié)構(gòu)體 -> 得到了私鑰privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)if err != nil {panic(err)}//5. 創(chuàng)建一個哈希對象 -> md5/sha1 -> sha512// sha512.Sum512()myhash := sha512.New()//6. 給哈希對象添加數(shù)據(jù)myhash.Write(plainText)//7. 計算哈希值hashText := myhash.Sum(nil)//8. 使用rsa中的函數(shù)對散列值簽名sigText, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA512, hashText)if err != nil {panic(err)}return sigText } // RSA簽名驗證 func VerifyRSA(plainText, sigText []byte, pubFileName string) bool {//1. 打開公鑰文件, 將文件內(nèi)容讀出 - []bytefile, err := os.Open(pubFileName)if err != nil {panic(err)}info, err := file.Stat()if err != nil {panic(err)}buf := make([]byte, info.Size())file.Read(buf)file.Close()//2. 使用pem解碼 -> 得到pem.Block結(jié)構(gòu)體變量block, _ := pem.Decode(buf)//3. 使用x509對pem.Block中的Bytes變量中的數(shù)據(jù)進行解析 -> 得到一接口pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)if err != nil {panic(err)}//4. 進行類型斷言 -> 得到了公鑰結(jié)構(gòu)體publicKey := pubInterface.(*rsa.PublicKey)//5. 對原始消息進行哈希運算(和簽名使用的哈希算法一致) -> 散列值hashText := sha512.Sum512(plainText)//6. 簽名認證 - rsa中的函數(shù)err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA512, hashText[:], sigText)if err == nil {return true}return false }func main() {src := []byte("在消息認證碼中,需要發(fā)送者和接收者之間共享密鑰,而這個密鑰不能被主動攻擊者Mallory獲取。如果這個密鑰落入Mallory手中,則Mallory也可以計算出MAC值,從而就能夠自由地進行篡改和偽裝攻擊,這樣一來消息認證碼就無法發(fā)揮作用了。")sigText := SignatureRSA(src, "private.pem")bl := VerifyRSA(src, sigText, "public.pem")fmt.Println(bl) }總結(jié)
以上是生活随笔為你收集整理的golang中的数字签名的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: golang中的消息认证
- 下一篇: go run的错误