golang实战-数字签名与认证

2023-10-27

一. 数字签名 

        设想一个场景:Alice 给 Bob 发送了一段消息(明天我请你吃饭),该消息使用 Bob 的公钥加密(公钥加密才能确保消息被截获后也只有 Bob 本人能用自己的私钥解密),但是由于 Bob 的公钥可能其他人也有,Tom 也可以使用 Bob 的公钥加密信息后发送给 Bob,所以 Bob 无法确保这条信息是 Alice 本人发送的,但是如果每条信息都加上 Alice 本人的签名,Bob 接收到信息之后就知道真的是 Alice 发送的,也能通过第三方机构防止 Alice 否认该消息。

        数字签名就是由发送者对消息进行签名,具体方式是先对消息计算散列值,然后使用发送者的私钥对该散列值进行非对称加密得到数字签名,要发送的消息跟随数字签名一同发送。接收者拿到消息后,使用发送者的公钥对数字签名进行非对称解密得到散列值,然后对消息进行哈希计算得到散列值,将解密得到的散列值与哈希得到的散列值进行比较,如果二者相等,说明该消息确实是发送者本人发送的。

        常用的进行数字签名的方式有 RSA 和椭圆曲线。

二. golang实战

1. 使用rsa进行数字签名与认证

        crypto/rsa 包提供了 SignPKCS1v15 方法进行数字签名,VerifyPKCS1v15 方法进行数字签名认证。

使用 rsa 私钥文件进行数字签名步骤如下。

(1)读取私钥文件内容,使用 pem.Decode 将内容解析成 pem 格式块

(2)通过 x509.ParsePKCS1PrivateKey 将 pem 块中的 PKCS # 1, ASN.1 DER 格式的字符串解析成 rsa.PrivateKey

(3)计算发送内容散列值

(4)通过 rsa.SignPKCS1v15 使用私钥对散列值进行签名,该函数返回值就是数字签名内容

使用 rsa 公钥文件进行认证数字签名步骤如下。

(1)读取公钥文件内容,使用 pem.Decode 将内容解析成 pem 格式块

(2)通过 x509.ParsePKIXPublicKey 将 pem 块中的 DER 格式字符串解析成 rsa.PublicKey

(3)计算接收内容的散列值

(4)通过 rsa.VerifyPKCS1v15 使用公钥对散列值进行认证,如果该返回返回 err == nil,则表示认证成功

package main

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha512"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"math/big"
	"os"
)

func rsaSignature(plainText []byte, privateKeyFile string) ([]byte, error) {
	// 读取私钥文件并解析成rsa.PrivateKey
	file, err := os.Open(privateKeyFile)
	if err != nil {
		return nil, err
	}
	stat, err := file.Stat()
	if err != nil {
		return nil, err
	}
	buf := make([]byte, stat.Size())
	file.Read(buf)
	defer file.Close()

	block, _ := pem.Decode(buf)
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)

	// 计算原始内容的散列值
	h := sha512.New()
	h.Write(plainText)
	hValue := h.Sum(nil)

	// 通过rsa.SignPKCS1v15使用私钥对原始内容散列值进行签名
	digestSign, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA512, hValue)
	return digestSign, err
}

func rsaVerifySign(plainText []byte, publicKeyFile string, signed []byte) bool {
	// 读取公钥文件并解析成rsa.PublicKey
	file, err := os.Open(publicKeyFile)
	if err != nil {
		return false
	}
	stat, err := file.Stat()
	if err != nil {
		return false
	}
	buf := make([]byte, stat.Size())
	file.Read(buf)
	defer file.Close()

	block, _ := pem.Decode(buf)
	publicKeyInt, err := x509.ParsePKIXPublicKey(block.Bytes)
	publicKey := publicKeyInt.(*rsa.PublicKey)

	// 计算原始内容的散列值
	h := sha512.New()
	h.Write(plainText)
	hValue := h.Sum(nil)

	// 确认签名
	err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA512,hValue, signed)

	return err == nil
}

func main() {
	content := []byte("Hello digest sign")
	sign, err := rsaSignature(content, "private.pem")
	if err != nil {
		return
	}
	fmt.Println("signature:",sign)
	fmt.Println("verify result:", rsaVerifySign(content, "public.pem", sign))
}

运行结果如下所示。 

2. 使用椭圆曲线进行数字签名与认证

package main

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha512"
	"crypto/x509"
	"encoding/pem"
	"fmt"
	"math/big"
	"os"
)

func eccSignature(plainText []byte, privateKeyFile string) ([]byte, []byte, error){
	// 读取私钥文件并解析成ecdsa.PrivateKey
	file, err := os.Open(privateKeyFile)
	if err != nil {
		return nil, nil, err
	}
	stat, err := file.Stat()
	if err != nil {
		return nil, nil, err
	}
	buf := make([]byte, stat.Size())
	file.Read(buf)
	defer file.Close()

	block, _ := pem.Decode(buf)
	privateKey, _ := x509.ParseECPrivateKey(block.Bytes)

	// 计算原始内容的散列值
	h := sha512.New()
	h.Write(plainText)
	hValue := h.Sum(nil)

	r, s, err := ecdsa.Sign(rand.Reader, privateKey, hValue)
	rText, _ := r.MarshalText()
	sText, _ := s.MarshalText()

	return rText, sText, nil
}

func eccVerifySign(plainText []byte, publicKeyFile string, rText []byte, sText []byte) bool {
	// 读取公钥文件并解析成ecdsa.PublicKey
	file, err := os.Open(publicKeyFile)
	if err != nil {
		return false
	}
	stat, err := file.Stat()
	if err != nil {
		return false
	}
	buf := make([]byte, stat.Size())
	file.Read(buf)
	defer file.Close()

	block, _ := pem.Decode(buf)
	publicKeyInt, err := x509.ParsePKIXPublicKey(block.Bytes)
	publicKey := publicKeyInt.(*ecdsa.PublicKey)

	// 计算原始内容的散列值
	h := sha512.New()
	h.Write(plainText)
	hValue := h.Sum(nil)

	var r, s big.Int
	r.UnmarshalText(rText)
	s.UnmarshalText(sText)

	return ecdsa.Verify(publicKey, hValue, &r, &s)
}

func main() {
	r, s, err := eccSignature(content, "ecc_private.pem")
	if err != nil {
		return
	}
	fmt.Println("r:", string(r))
	fmt.Println("s:", string(s))
	fmt.Println("verify result:", eccVerifySign(content, "ecc_public.pem", r, s))
}

运行结果如下所示。 

三. 数字签名存在的问题

         验证签名的一端无法确认公钥是否真的属于发送者。如上,中间人 Tom 拦截了 Alice 的公钥,并使用自己的公钥发送给 Bob,之后 Tom 将 Alice 的数据拦截,再自己生成数据并进行签名,而 Bob 却无法得知公钥已经被偷换了。

        这个问题使用数字证书可以解决。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

golang实战-数字签名与认证 的相关文章

  • W. Richard Stevens Unix网络编程 作品集

    W Richard Stevens 写的那三卷书以怎样的顺序看是比较好的 按我的经验来看先粗略的看一遍卷一 然后再结合卷一看卷二 卷二要看几遍 每遍都会有收获 然后卷三大概看看就行 之后就是看源码 看bsd lite的 在最后就是看linu
  • svn客户端Tortoise SVN使用方法

    svn客户端Tortoise SVN使用方法 转载自 http www cnblogs com armyfai p 3985660 html 该博主介绍比较详细 这里只转载其中svn客户端使用部分 1 首先我们需要下载 svn小乌龟 后 进

随机推荐

  • Webservice实践(二)Webservice 客户端开发

    现在我们首先进行客户端开发的实践 从客户端实践来了解一下webservice的应用场景 比如说现在已经有一个webservice服务 提供的翻译方面的功能服务 主要是免费的webservice接口现在很多都被封了 我们需要编写一个客户端来使
  • Caffe中计算图像均值的实现(cifar10)

    在深度学习中 在进行test时经常会减去train数据集的图像均值 这样做的好处是 属于数据预处理中的数据归一化 降低数据间相似性 可以将数值调整到一个合理的范围 以下code是用于计算cifar10中训练集的图像均值 include fu
  • 代码越写越乱?那是因为你没用责任链

    路人 Java充电社 2022 08 04 08 06 发表于上海 收录于合集 java充电社244个 大家好 我是路人 最近 我让团队内一位成员写了一个导入功能 他使用了责任链模式 代码堆的非常多 bug 也多 没有达到我预期的效果 实际
  • springboot-单点登录

    单点登录 第一节 简介 1 1 什么是单点登陆 单点登录 Single Sign On 简称为 SSO 是目前比较流行的企业业务整合的解决方案之一 SSO的定义是在多个应用系统中 用户只需要登录一次就可以访问所有相互信任的应用系统 较大的企
  • 2023年美赛C题思路复盘

    论文标题 Riddle of Wordle Mining the Secret of Number Scores Solution Words Wordle之谜 挖掘数字得分和解字词的秘密 文章目录 前言 一 题目重述 拟解决的问题 我们的
  • mybatis异常:Could not find result map XXXX

    在使用mybatis框架 报这个错误时 是mapper文件中 查询语句的返回类型写错了 即该用resultType用成了resultMap 如果你要返回基本类型 或者返回已存在的pojo对象 用resultType修饰 如果要使用resul
  • Android ImageLoader用法总结

    前言 imageloader作为一个开源的框架被广泛的使用 尤其对于新手而言 更是如此 本人在项目中每当用到imageloader的时候都是从网上百度然后复制粘贴 现在觉得那样没得意义 因此写此博客 当作以后发复习资料 同时稍微研究下ima
  • springboot依赖

  • 三层架构:界面层、业务逻辑层、数据访问层

    进行用户的插入操作 1 spring会接管三层架构中的那些对象的创建 2 非spring接管下的三层项目构建 从下往上 1 实体类 com bjpowernode pojo Users package com bjpowernode poj
  • 【web开发】扩展与全面接管springmvc

    1 扩展springmvc 方法 编写一个配置类 Configuration 实现WebMvcConfigurer接口 不能标注 EnableWebMvc 特点 既保留了springboot所有的自动配置 也能用我们扩展的配置 示例 pom
  • 数据结构和算法(压缩矩阵和队列模拟)

    具体思路和分析放在末尾 稀疏矩阵的处理方法是 1 记录矩阵一共有几行几列 有多少个不同的值 2 把具有不同值的元素的行列和值记录都在一个小规模的矩阵中 从而缩小程序的规模 原始矩阵转换稀疏矩阵的思路 1 遍历原始的二维数组 得到有效数据的个
  • vue 的表单验证

    1 使用
  • zlib库各历史版本下载网址

    https zlib net fossils
  • Element——el-table给所有的row和column数据加上索引

    问题场景 开发中发现el table在使用cell style时无法获取row column的索引信息 解决思路 在其他可以获取到行列索引的方法中对行列数据添加索引属性 解决方法 利用el table的cell class name配置 以
  • 【Detectron2】详解Detectron2中Mask RCNN的部分代码

    整体来说 Backbone RPN和Fast RCNN是三个相对独立的模块 Backbone对每张图片产生5 level的特征 并送入RPN RPN对送入的特征 首先经过3x3卷积 随后用sibling 1x1卷积产生分类和bbox信息 分
  • Java类的封装

    目录 1 什么是类的封装 2 如何实现类的封装 1 private操作符 2 get与set 1 语法格式 2 封装演示 1 什么是类的封装 隐藏对象的属性和实现细节 仅对外提供公共访问方式 类的封装可以让使用者使用更加简单 数据也会更加安
  • 华为OD机试 Java 实现【密码验证合格程序】【牛客练习题 HJ20】,附详细解题思路

    一 题目描述 密码要求 长度超过8位 包括大小写字母 数字 其它符号 以上四种至少三种 不能有长度大于2的包含公共元素的子串重复 注 其他符号不含空格或换行 二 输入描述 一组字符串 三 输出描述 如果符合要求输出 OK 否则输出NG 四
  • Vcpkg 的安装与使用

    Vcpkg 的安装与使用 欢迎大家来我的博客逛逛 hauhau cn 需求 先确保你已经安装了 Windows7 及以上的版本 Git Visual Studio 2015 Update 3 及以上的版本 关于美化 Windows Term
  • 避免Flex RSL重复load 提高module加载性能

    本文编译后的补丁下载链接 http download csdn net source 1908278 多模块应用 每加载一个模块都会重复加载模块所使用的RSL 现在增加一个 private static var loadedRSLs Dic
  • golang实战-数字签名与认证

    一 数字签名 设想一个场景 Alice 给 Bob 发送了一段消息 明天我请你吃饭 该消息使用 Bob 的公钥加密 公钥加密才能确保消息被截获后也只有 Bob 本人能用自己的私钥解密 但是由于 Bob 的公钥可能其他人也有 Tom 也可以使