一、数字签名流程图
二、实现场景描述
直接使用百度百科中关于数字签名的应用例子,如下:
假如现在 Alice 向 Bob 传送数字信息,为了保证信息传送的保密性、真实性、完整性和不可否认性,需要对传送的信息进行数字加密和签名,其传送过程为:
1.Alice 准备好要传送的数字信息(明文);
2.Alice 对数字信息进行哈希运算,得到一个信息摘要;
3.Alice 用自己的私钥对信息摘要进行加密得到 Alice 的数字签名,并将其附在数字信息上;
4.Alice 随机产生一个加密密钥,并用此密码对要发送的信息进行加密,形成密文;
5.Alice 用 Bob 的公钥对刚才随机产生的加密密钥进行加密,将加密后的 DES 密钥连同密文一起传送给Bob;
6.Bob 收到 Alice 传送来的密文和加密过的 DES 密钥,先用自己的私钥对加密的 DES 密钥进行解密,得到 Alice随机产生的加密密钥;
7.Bob 然后用随机密钥对收到的密文进行解密,得到明文的数字信息,然后将随机密钥抛弃;
8.Bob 用 Alice 的公钥对 Alice 的数字签名进行解密,得到信息摘要;
9.Bob 用相同的哈希算法对收到的明文再进行一次哈希运算,得到一个新的信息摘要;
10.Bob 将收到的信息摘要和新产生的信息摘要进行比较,如果一致,说明收到的信息没有被修改过。
假定Alice和Bob都已知对方的公钥。
以上过程使用的技术:
1、哈希运算:Go语言可以使用sha256哈希运算包将明文信息运算为256为位的哈希值,该值不可逆且唯一。
2、对称加密:使用DES对称加密对明文进行加密。
3、非对称加密:这里使用RSA非对称加密实现数字签名。
三、实现代码
1、DES对称加密代码如下:
package encryp
import (
"bytes"
"crypto/des"
"crypto/cipher"
)
func padding(src []byte,blocksize int) []byte {
n:=len(src)
padnum:=blocksize-n%blocksize
pad:=bytes.Repeat([]byte{byte(padnum)},padnum)
dst:=append(src,pad...)
return dst
}
func unpadding(src []byte) []byte {
n:=len(src)
unpadnum:=int(src[n-1])
dst:=src[:n-unpadnum]
return dst
}
func EncryptDES(src []byte,key []byte) []byte {
block,_:=des.NewCipher(key)
src=padding(src,block.BlockSize())
blockmode:=cipher.NewCBCEncrypter(block,key)
blockmode.CryptBlocks(src,src)
return src
}
func DecryptDES(src []byte,key []byte) []byte {
block,_:=des.NewCipher(key)
blockmode:=cipher.NewCBCDecrypter(block,key)
blockmode.CryptBlocks(src,src)
src=unpadding(src)
return src
}
2、RSA非对称加密代码如下:
package encryp
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
)
var privateKey = []byte(`
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDfw1/P15GQzGGYvNwVmXIGGxea8Pb2wJcF7ZW7tmFdLSjOItn9
kvUsbQgS5yxx+f2sAv1ocxbPTsFdRc6yUTJdeQolDOkEzNP0B8XKm+Lxy4giwwR5
LJQTANkqe4w/d9u129bRhTu/SUzSUIr65zZ/s6TUGQD6QzKY1Y8xS+FoQQIDAQAB
AoGAbSNg7wHomORm0dWDzvEpwTqjl8nh2tZyksyf1I+PC6BEH8613k04UfPYFUg1
0F2rUaOfr7s6q+BwxaqPtz+NPUotMjeVrEmmYM4rrYkrnd0lRiAxmkQUBlLrCBiF
u+bluDkHXF7+TUfJm4AZAvbtR2wO5DUAOZ244FfJueYyZHECQQD+V5/WrgKkBlYy
XhioQBXff7TLCrmMlUziJcQ295kIn8n1GaKzunJkhreoMbiRe0hpIIgPYb9E57tT
/mP/MoYtAkEA4Ti6XiOXgxzV5gcB+fhJyb8PJCVkgP2wg0OQp2DKPp+5xsmRuUXv
720oExv92jv6X65x631VGjDmfJNb99wq5QJBAMSHUKrBqqizfMdOjh7z5fLc6wY5
M0a91rqoFAWlLErNrXAGbwIRf3LN5fvA76z6ZelViczY6sKDjOxKFVqL38ECQG0S
pxdOT2M9BM45GJjxyPJ+qBuOTGU391Mq1pRpCKlZe4QtPHioyTGAAMd4Z/FX2MKb
3in48c0UX5t3VjPsmY0CQQCc1jmEoB83JmTHYByvDpc8kzsD8+GmiPVrausrjj4p
y2DQpGmUic2zqCxl6qXMpBGtFEhrUbKhOiVOJbRNGvWW
-----END RSA PRIVATE KEY-----
`)
var publicKey = []byte(`
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfw1/P15GQzGGYvNwVmXIGGxea
8Pb2wJcF7ZW7tmFdLSjOItn9kvUsbQgS5yxx+f2sAv1ocxbPTsFdRc6yUTJdeQol
DOkEzNP0B8XKm+Lxy4giwwR5LJQTANkqe4w/d9u129bRhTu/SUzSUIr65zZ/s6TU
GQD6QzKY1Y8xS+FoQQIDAQAB
-----END PUBLIC KEY-----
`)
// 加密
func RsaEncrypt(origData []byte) ([]byte, error) {
//解密pem格式的公钥
block, _ := pem.Decode(publicKey)
if block == nil {
return nil, errors.New("public key error")
}
// 解析公钥
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
// 类型断言
pub := pubInterface.(*rsa.PublicKey)
//加密
return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}
// 解密
func RsaDecrypt(ciphertext []byte) ([]byte, error) {
//解密
block, _ := pem.Decode(privateKey)
if block == nil {
return nil, errors.New("private key error!")
}
//解析PKCS1格式的私钥
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
// 解密
return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
}
3、服务器端Alice发送信息代码:
package main
import (
"encryp"
"crypto/sha256"
"fmt"
)
type sgTure struct{
info []byte //数字信息(加密)
sginfo []byte //签名信息
randKey string //对称加密的密钥,随机生成
}
func main() {
//发送的信息,Bob,你欠我的500元钱不用还了
info:="hello,Bob,don't still owe me 500 yuan money"
//将信息生成信息摘要
data := []byte(info)
sat:=sha256.Sum256(data)
//用私钥对摘要进行加密,生成数字签名
sginfo:=encryp.RsaEncrypt(sat)
//将明文信息用随机密钥进行加密
randkey=getRandStr()
info:=encryp.EncryptDES(data,randkey)
//以上信息打包发送给Bob
sgture:=sgTure{
info,
sginfo:sginfo,
randKey:randkey
}
sendToBob(sgture)
}
4、客户端Bob接收信息代码:
func main(){
//获取Alice发送的信息
valueAll:=getInfofromAlice()
//使用Bob发送的随机对称密钥进行解密
data:=encryp.DecryptDES(valueAll.info,valueAll.randKey)
//将该信息生成哈希摘要
sat:=sha256.Sum256(data)
//使用Alice的公钥进行解密
sat1:=encryp.RsaDecrypt(valueAll.sginfo)
//如果哈希摘要相同,获取该信息
if sat==sat1{
value:=string(data)
}
}