数字签名

数字签名的方法

签名的生成和验证

  1. 签名

    • 有原始数据对其进行哈希运算 -> 散列值
    • 使用非对称加密的私钥对散列值加密 -> 签名
    • 将原始数据和签名一并发送给对方
  2. 验证
    • 接收数据

      • 原始数据
      • 数字签名
    • 数字签名, 需要使用公钥解密, 得到散列值
    • 对原始数据进行哈希运算得到新的散列值

非对称加密和数字签名

总结:

  1. 数据通信

    • 公钥加密, 私钥解密
  2. 数字签名:
- 私钥加密, 公钥解密

使用RSA进行数字签名

  1. 使用rsa生成密钥对

    1. 生成密钥对
    2. 序列化
    3. 保存到磁盘文件
  2. 使用私钥进行数字签名

    1. 打开磁盘的私钥文件

    2. 将私钥文件中的内容读出

    3. 使用pem对数据解码, 得到了pem.Block结构体变量

    4. x509将数据解析成私钥结构体 -> 得到了私钥

    5. 创建一个哈希对象 -> md5/sha1

    6. 给哈希对象添加数据

    7. 计算哈希值

    8. 使用rsa中的函数对散列值签名

      func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) (s []byte, err error)
      参数1: rand.Reader
      参数2: 非对称加密的私钥
      参数3: 使用的哈希算法crypto.sha1crypto.md5
      参数4: 数据计算之后得到的散列值
      返回值:
      - s: 得到的签名数据
      - err: 错误信息
      
  3. 使用公钥进行签名认证

    1. 打开公钥文件, 将文件内容读出 - []byte

    2. 使用pem解码 -> 得到pem.Block结构体变量

    3. 使用x509对pem.Block中的Bytes变量中的数据进行解析 -> 得到一接口

    4. 进行类型断言 -> 得到了公钥结构体

    5. 对原始消息进行哈希运算(和签名使用的哈希算法一致) -> 散列值

      1. 创建哈希接口
      2. 添加数据
      3. 哈希运算
    6. 签名认证 - rsa中的函数

      func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) (err error)
      参数1: 公钥
      参数2: 哈希算法 -> 与签名使用的哈希算法一致
      参数3: 将原始数据进行哈希原始得到的散列值
      参数4: 签名的字符串
      返回值: - nil -> 验证成功- !=nil -> 失败
      

使用椭圆曲线进行数字签名

椭圆曲线在go中对应的包: import "crypto/elliptic"

使用椭圆曲线在go中进行数字签名: import "crypto/ecdsa"

美国FIPS186-2标准, 推荐使用5个素域上的椭圆曲线, 这5个素数模分别是:

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

  1. 秘钥对称的生成, 并保存到磁盘

    1. 使用ecdsa生成密钥对

      func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error)
      
    2. 将私钥写入磁盘

      • 使用x509进行序列化

        func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error)
        
      • 将得到的切片字符串放入pem.Block结构体中

        block := pem.Block{

        Type : "描述....",

        Bytes : MarshalECPrivateKey返回值中的切片字符串,

        }

      • 使用pem编码

        pem.Encode();

    3. 将公钥写入磁盘

      • 从私钥中得到公钥

      • 使用x509进行序列化

        func MarshalPKIXPublicKey(pub interface{}) ([]byte, error)
        
      • 将得到的切片字符串放入pem.Block结构体中

        block := pem.Block{

        Type : "描述....",

        Bytes : MarshalECPrivateKey返回值中的切片字符串,

        }

      • 使用pem编码

        pem.Encode();

  2. 使用私钥进行数字签名

    1. 打开私钥文件, 将内容读出来 ->[]byte

    2. 使用pem进行数据解码 -> pem.Decode()

    3. 使用x509, 对私钥进行还原

      func ParseECPrivateKey(der []byte) (key *ecdsa.PrivateKey, err error)
      
    4. 对原始数据进行哈希运算 -> 散列值

    5. 进行数字签名

      func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error)
      - 得到的r和s不能直接使用, 因为这是指针应该将这两块内存中的数据进行序列化 -> []bytefunc (z *Int) MarshalText() (text []byte, err error)
      
  3. 使用公钥验证数字签名

    1. 打开公钥文件, 将里边的内容读出 -> []byte

    2. pem解码 -> pem.Decode()

    3. 使用x509对公钥还原

      func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error)
      
    4. 将接口 -> 公钥

    5. 对原始数据进行哈希运算 -> 得到散列值

    6. 签名的认证 - > ecdsa

      func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool
      - 参数1: 公钥
      - 参数2: 原始数据生成的散列值
      - 参数3,4: 通过签名得到的连个点func (z *Int) UnmarshalText(text []byte) error
      

数字签名无法解决的问题

代码

RSA签名和认证

// RSA签名 - 私钥
func SignatureRSA(plainText []byte, fileName string) []byte{//1. 打开磁盘的私钥文件file, err := os.Open(fileName)if err != nil {panic(err)}//2. 将私钥文件中的内容读出info, err := file.Stat()if err != nil {panic(err)}buf := make([]byte, info.Size())file.Read(buf)file.Close()//3. 使用pem对数据解码, 得到了pem.Block结构体变量block, _ := pem.Decode(buf)//4. x509将数据解析成私钥结构体 -> 得到了私钥privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)if err != nil {panic(err)}//5. 创建一个哈希对象 -> md5/sha1 -> sha512// sha512.Sum512()myhash := sha512.New()//6. 给哈希对象添加数据myhash.Write(plainText)//7. 计算哈希值hashText := myhash.Sum(nil)//8. 使用rsa中的函数对散列值签名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. 打开公钥文件, 将文件内容读出 - []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结构体变量block, _ := pem.Decode(buf)//3. 使用x509对pem.Block中的Bytes变量中的数据进行解析 ->  得到一接口pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)if err != nil {panic(err)}//4. 进行类型断言 -> 得到了公钥结构体publicKey := pubInterface.(*rsa.PublicKey)//5. 对原始消息进行哈希运算(和签名使用的哈希算法一致) -> 散列值hashText := sha512.Sum512(plainText)//6. 签名认证 - rsa中的函数err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA512, hashText[:], sigText)if err == nil {return true}return false
}func main() {src := []byte("在消息认证码中,需要发送者和接收者之间共享密钥,而这个密钥不能被主动攻击者Mallory获取。如果这个密钥落入Mallory手中,则Mallory也可以计算出MAC值,从而就能够自由地进行篡改和伪装攻击,这样一来消息认证码就无法发挥作用了。")sigText := SignatureRSA(src, "private.pem")bl := VerifyRSA(src, sigText, "public.pem")fmt.Println(bl)
}

golang中的数字签名相关推荐

  1. golang中base64 md5 sha256的编解码及摘要算法、aes、des、sha1

    golang中base64 md5 sha256的编解码及摘要算法.aes.rsa.des.sha1 golang中base64 md5 sha256的编解码及摘要算法 关于加密解密 AES DES ...

  2. Golang中Buffer高效拼接字符串以及自定义线程安全Buffer

    本文原创文章,转载注明出处,博客地址 https://segmentfault.com/u/to... 第一时间看后续精彩文章.觉得好的话,顺手分享到朋友圈吧,感谢支持. Go中可以使用"+ ...

  3. 如何在golang中关闭bufio.reader_Golang 并发模型系列:1. 轻松入门流水线模型

    Go语言中文网,致力于每日分享编码.开源等知识,欢迎关注我,会有意想不到的收获! Golang作为一个实用主义的编程语言,非常注重性能,在语言特性上天然支持并发,它有多种并发模型,通过流水线模型系列文 ...

  4. go语言的iota是什么意思_关于Golang中的iota

    快速一览 iota是Golang中提供的一个简化常量和枚举编程的标识符,合理的使用这个标识符可以让代码变得更简洁,省去大量的不必要的代码. 比如下面的这个常量定义 const ( a = 1 b = ...

  5. Golang中的panic和recover(捕获异常)

    Golang中的panic和recover(捕获异常) 参考文章: (1)Golang中的panic和recover(捕获异常) (2)https://www.cnblogs.com/zhzhlong ...

  6. golang 中string和int类型相互转换

    总结了golang中字符串和各种int类型之间的相互转换方式: string转成int: test_int, err := strconv.Atoi(test_string) if err != ni ...

  7. golang中并发sync和channel

    golang中并发sync和channel chenbaoke · 2014-12-08 13:00:01 · 19151 次点击 · 预计阅读时间 5 分钟 · 不到1分钟之前 开始浏览 这是一个创 ...

  8. golang中的sync.WaitGroup

    golang中的sync.WaitGroup Posted on 2015/04/09刚才看golang的sync的包,看见一个很有用的功能.就是WaitGroup. 先说说WaitGroup的用途: ...

  9. 初步解读Golang中的接口相关编写方法

    初步解读Golang中的接口相关编写方法 概述如果说goroutine和channel是Go并发的两大基石,那么接口是Go语言编程中数据类型的关键.在Go语言的实际编程中,几乎所有的数据结构都围绕接口 ...

最新文章

  1. mysql-5.7 innodb 的并行任务调度详解
  2. 正則表達式基本元字符集及其含义(上)
  3. python个人项目-软工作业个人项目wc.exe(python实现)
  4. 图解Numpy的tile函数
  5. SQL性能优化工具TKPROF
  6. 删除有序数组中的重复项 IIPython解法
  7. 使用模板引擎artTemplate的几个问题总结
  8. php删除字段某个字段,php数如何组删除某个字段
  9. java怎么使用floor_Java NavigableSet floor()用法及代码示例
  10. MPS的DCDC国产代换件
  11. 制定目标的SMART原则(思维导图)
  12. 个人网站首页设计模板
  13. 与电影同行的日子(同步更新)
  14. 物联网的背景及其发展
  15. MYSQL SQL 不等于
  16. 如何固定输出每行打印的个数
  17. Matlab中结构体struct创建和使用
  18. 区块链开发之windows环境配置
  19. shardingsphere: SpringBoot整合shardingjdbc实现读写分离
  20. CS61B sp2018笔记 | Efficient Programming

热门文章

  1. 【Android 热修复】热修复原理 ( 合并两个 Element[] dexElements | 自定义 Application 加载 Dex 设置 | 源码资源 )
  2. 【错误记录】Flutter 报错 ( Dart SDK is not configured )
  3. 【计算理论】计算复杂性 ( 证明 非确定性图灵机 与 确定性图灵机 的时间复杂度 之间的指数关系 )
  4. go语言中将函数作为变量传递
  5. 数据库复习总结(12)数据检索
  6. 浅谈Socket编程
  7. Centos Openldap服务器数据库主备(二)
  8. UpdatePanel 后台注册脚本失效
  9. 汇编指令中的字母会区分大小写吗?(除了字符型数据,其他地方都不区分)
  10. ArcGIS for qml - 地址地标转换为经纬度(地理编码)