Go语言代码实现数字签名过程

一、数字签名流程图

https://gss2.bdstatic.com/-fo3dSag_xI4khGkpoWK1HF6hhy/baike/c0%3Dbaike80%2C5%2C5%2C80%2C26/sign=ee20e526367adab429dd1311eabdd879/adaf2edda3cc7cd99b2962d73901213fb80e91b3.jpg

二、实现场景描述

直接使用百度百科中关于数字签名的应用例子,如下:

假如现在 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)
	}
	
}

 

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现RPC框架的过程可以分为以下几个步骤: 1. 定义服务接口:定义服务接口以及服务方法,并且确定参数和返回值的类型。 2. 定义服务端:服务端需要实现服务接口中的方法,并且提供网络通信功能,接收客户端请求并将请求转发给服务方法进行处理。 3. 定义客户端:客户端需要提供网络通信功能,以及调用远程服务的方法,并将请求发送给服务端进行处理。 4. 序列化和反序列化:客户端和服务端需要将数据进行序列化和反序列化,以便在网络中进行传输。 5. 注册服务:服务端需要将实现了服务接口的对象注册到服务框架中,以便客户端可以调用。 下面是使用Go语言实现RPC框架的代码示例: 1. 定义服务接口 ```go type Arith interface { Multiply(args *Args, reply *int) error } type Args struct { A, B int } ``` 2. 定义服务端 ```go type ArithService struct{} func (s *ArithService) Multiply(args *Args, reply *int) error { *reply = args.A * args.B return nil } func main() { rpc.Register(new(ArithService)) listener, err := net.Listen("tcp", ":1234") if err != nil { log.Fatal("ListenTCP error:", err) } for { conn, err := listener.Accept() if err != nil { log.Fatal("Accept error:", err) } go rpc.ServeConn(conn) } } ``` 3. 定义客户端 ```go func main() { client, err := rpc.Dial("tcp", "localhost:1234") if err != nil { log.Fatal("Dial error:", err) } args := &Args{7, 8} var reply int err = client.Call("Arith.Multiply", args, &reply) if err != nil { log.Fatal("Call error:", err) } fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply) } ``` 以上代码实现了一个简单的RPC框架,客户端通过`rpc.Dial`方法连接到服务端,然后调用`client.Call`方法调用远程服务。服务端通过`rpc.ServeConn`方法接收客户端请求并将请求转发给服务方法进行处理。注意,以上代码仅为示例代码,实际情况中需要考虑安全性和可靠性等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值