【go密码学】-数字签名

jincheng828 · · 951 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

介绍

数字签名就是只有消息的发送者才能产生的别人无法伪造的一段数字串,这段数字串是对信息真实性的有效证明。

  • 发送者:生成签名
  • 接受者:验证签名

非对称密码机制

非对称加密中,公钥用于加密,私钥用于解密。数字签名中相反,私钥生成签名,公钥验证签名

数字签名方法

直接对消息签名

clipboard.png

对消息的散列值签名

先用单向散列函数求出消息的散列值,然后再将散列值进行加密。

clipboard.png

数字签名算法

RSA

案例一

package main

import (
    "crypto/rsa"
    "crypto/rand"
    "fmt"
    "crypto/md5"
    "encoding/base64"
    "crypto"
)

//用公钥加密,私钥解密
//用私钥签名,公钥验证
//公钥是公开的,任何人可以使用公钥,私钥非公开(保存好)

//一,编程实现,公钥加密,私钥解密的过程
func crypt() {
    //创建私钥
    priv, _ := rsa.GenerateKey(rand.Reader, 1024)
    fmt.Println("输出系统自动产生的私钥", priv)

    //创建公钥
    pub := priv.PublicKey

    //准备加密的明文
    org := []byte("hello kongyixueyuan")

    //公钥加密
    cipherTxt, _ := rsa.EncryptOAEP(md5.New(), rand.Reader, &pub, org, nil)
    //打印密文
    fmt.Println("密文为:", cipherTxt)
    fmt.Println("密文为:", base64.StdEncoding.EncodeToString(cipherTxt))

    //用私钥解密
    plaintext, _ := rsa.DecryptOAEP(md5.New(), rand.Reader, priv, cipherTxt, nil)
    //打印解密后的结果
    fmt.Println("明文为:", string(plaintext))

}

//二,编程实现,私钥签名,公钥验证的过程
func sign() {

    //创建私钥
    priv, _ := rsa.GenerateKey(rand.Reader, 1024)
    //创建公钥
    pub := &priv.PublicKey

    plaintxt := []byte("zhaoyingkui")

    //实现hash散列
    h := md5.New()
    h.Write(plaintxt)
    hashed := h.Sum(nil)

    //通过RSA实现数字签名
    //数组签名的作用为验证是否被篡改,A->B,当B收到数据时,验证是否由A传递的消息

    opts := rsa.PSSOptions{rsa.PSSSaltLengthAuto, crypto.MD5}
    sig, _ := rsa.SignPSS(rand.Reader, priv, crypto.MD5, hashed, &opts)

    fmt.Println("签名的结果为", sig)

    //通过公钥实现验证签名
    err := rsa.VerifyPSS(pub, crypto.MD5, hashed, sig, &opts)
    if err == nil {
        fmt.Println("验证成功")
    }

}

func main() {

    //crypt()
    sign()

}

案例二
server.go

package main

import (
    "net"
    "fmt"
    "encoding/pem"
    "crypto/x509"
    "crypto/rsa"
    "crypto/md5"
    "crypto"
)

//接收网络传送过来的数据
//公钥验签
var publicKey = []byte(`
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyOnQ8Dbm1/UIkmSfeMKd
K1LRJGX7T18vjZ7P4w3f/Jft/LKCwkxyC2H7x03An+EdHP7dreRhNytzbQaseIgH
EYjFapaCEz+JpMNm+qY4ZpApzvPvqm/tut4T1J0HG33iiBqnyMJRZg8LjUXV2tEw
fnHm5yCX36kOkN/YCW7ZbeO6aqw7gMyvJDiLGIYgCy2Daqe1MH1RP91djrt6tWcf
qVmUR+HxvJFkvUZZHqFUUZyJefNcY7JQDLSz5F22VB7ZLd9sSX38My353pNy4D19
yeo5/54Z5AbSeRUMYJSFFbxwJzfewyVq2nV7EUJEj7lk0NmksB+S6w1a+a8cWydJ
/QIDAQAB
-----END PUBLIC KEY-----
`)

func Recive() []byte {
    netListen, _ := net.Listen("tcp", "127.0.0.1:1234")
    defer netListen.Close()

    //监听端口,并接收数据
    for {
        conn, _ := netListen.Accept()
        //设置接收数据的内存缓存
        data := make([]byte, 2048)
        for {
            n, _ := conn.Read(data)
            //返回接收的数据
            return data[:n]
        }
    }
}

func main() {

    //fmt.Println(Recive())
    //获得接收到的数据
    data := Recive()
    //拆分数据
    plaintxt := data[:11]
    fmt.Println("接收的名文为", string(plaintxt))

    //获得接收到的数据中的数字签名的结果
    sig := data[11:]

    //通过公钥做验证
    block, _ := pem.Decode(publicKey)
    pubInterface, _ := x509.ParsePKIXPublicKey(block.Bytes)
    pub := pubInterface.(*rsa.PublicKey)

    //验证发送方是否为zhaoyingkui
    h := md5.New()
    h.Write([]byte(plaintxt))
    hashed := h.Sum(nil)

    e := rsa.VerifyPSS(pub, crypto.MD5, hashed, sig, nil)
    if e == nil {
        fmt.Println("接受数据成功,数据确实是",string(plaintxt))
    }

}

client.go

package main

import (
    "crypto/md5"
    "encoding/pem"
    "crypto/x509"
    "crypto/rsa"
    "crypto"
    "crypto/rand"
    "net"
    "fmt"
)

//发送消息,需要对数据进行签名
//私钥做签名
var privateKey = []byte(`
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAyOnQ8Dbm1/UIkmSfeMKdK1LRJGX7T18vjZ7P4w3f/Jft/LKC
wkxyC2H7x03An+EdHP7dreRhNytzbQaseIgHEYjFapaCEz+JpMNm+qY4ZpApzvPv
qm/tut4T1J0HG33iiBqnyMJRZg8LjUXV2tEwfnHm5yCX36kOkN/YCW7ZbeO6aqw7
gMyvJDiLGIYgCy2Daqe1MH1RP91djrt6tWcfqVmUR+HxvJFkvUZZHqFUUZyJefNc
Y7JQDLSz5F22VB7ZLd9sSX38My353pNy4D19yeo5/54Z5AbSeRUMYJSFFbxwJzfe
wyVq2nV7EUJEj7lk0NmksB+S6w1a+a8cWydJ/QIDAQABAoIBAAQo+z+OE3eTRksp
tDee5/w2qcf0KKD7GpP3HtzXs7SaPL5Hv/df99iOfdUhogRtd9na2SI5oV2wE6LF
SZrxThwp1dSgKy9U2HfF6AL2oCJXh9YWLPc9fBGreYOkgLosAB3LV4ALrf3L//Q7
5vKx9CwaFarhfOOPr5KGYAXJ+syQqi3CjQrPGTLsoyYPB5oc5CA45eHIctoS90M3
cCRb5pu8vlbmeMUh9G9GMdjD3zuefndOBnwcpErLf2xPuM/Qav9LI7bP25UaZe1u
zuTm93AjAtjS9zTvyqbVx/xq7C+LA4EaEeBzxNuUPHAGEhuf4kQGOPl48XKM3aNk
lc/UoUECgYEA5vTg6lJKkyHvA5JJvOLSRqrGd220TvO0EPmdp3PUGSFWdldC1ev1
M42f8tbzBBeQJlIMBTeGi5Sa8QRVVZXWYmjKkcpDreZJCKz4dVPyeg93MRUhDA7J
8+2GSypKO+MpTty3WY7y0K0Lyk7381to7QTfqXzMc1d/Q/W2rqdrITECgYEA3rL3
4EzaxisRG9yaxu1ndGFcaTX9JUm+RTDPd5wecfE2mrSqfWwcXjsJ/BOqim1pwPQe
1/7e6PwyPqqd9It+E5f3zLwN5fvHISSjawU+sCLgpPY4YQvybf2cLsfyQrIQw1Ig
4Mo+DTBp4EAGYLszn/8yk7A6PIkev/+W22s1oo0CgYEArYriGpC9QrOj4t4glFMn
yDv4p7MCYrUS4BKA2VvaywtW6dOGADKubA+GWbYUo0WFZpYOPDlN20JN7r7f1FC1
6Axv8n62vkwlIuS+SYNL11YZrQMAcwwFykn3uDFN2JRH7N9C0oPshssQ6fLOs8lD
HZ6k5blF84GSuqE+pRxeDnECgYAagUJvN7ZyD34hysfBFVBS0aOmAf73CSfUJFMM
8U/OT98n2ojQFKXrsSsnDVAm2Y7UoDlri7IMGLgCLVxPVqrSuiuL+nXNAYJZt3qb
qiwj2oLSH1vmcP2RibWk+7chqP/Fv2iaWHe6KiDvx676pE0opb7nRPopakh2oXz1
8I+ZoQKBgDR/aXBDXcDzHC4dM3dYzkSf0bn8LXyANkEjHovSH/QSs4m+d2BkGlSy
yB3kgNSnEa9vNoffQcRvRlQbS58zTF8Z4iGjnoCHS6Q2yJBFm9L+EaRJlF6tOERk
ngLn8mAtV/IGigWBpZCVeEIHH1nG1DLatF2VDCQifQXZ5oRcZZr6
-----END RSA PRIVATE KEY-----
`)

func SignData(msg string) []byte {
    //准备签名的数据
    plaintxt:=[]byte(msg)
    h:=md5.New()
    h.Write(plaintxt)
    hashed:=h.Sum(nil)

    fmt.Println(hashed)

    //将字节数组转换成私钥类型
    block,_:=pem.Decode(privateKey)
    priv,_:=x509.ParsePKCS1PrivateKey(block.Bytes)

    //签名
    opts:=&rsa.PSSOptions{rsa.PSSSaltLengthAuto,crypto.MD5}
    sig,_:=rsa.SignPSS(rand.Reader,priv,crypto.MD5,hashed,opts)

    //返回签名结果
    return sig
}

//通过TCP将数据和签名结果发送给接收端
func Send(data []byte) {
    conn,_:=net.ResolveTCPAddr("tcp4","127.0.0.1:1234")
    n,_:=net.DialTCP("tcp",nil,conn)
    //将数据通过tcp协议发送给接收方
    n.Write(data)
    fmt.Println("发送结束")

}

func main() {

    //获得签名的结果
    var dt = "hello world"
    sg:=SignData(dt)
    //dt是准发送出去的数据
    var data = make([]byte,len(dt)+len(sg))
    copy(data[0:11],[]byte(dt))
    copy(data[11:],sg)
    //data数组其实有两部分组成,发出去的数据+签名结果
    Send(data)
}

DSA

ECDSA

一种利用椭圆曲线密码来实现的数字签名算法。


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:jincheng828

查看原文:【go密码学】-数字签名

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:1006366459

951 次点击  ∙  1 赞  
加入收藏 微博
1 回复  |  直到 2019-11-27 10:17:40
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传