golang中的数字签名

数字签名

数字签名的方法

签名的生成和验证

  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.sha1
      	crypto.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不能直接使用, 因为这是指针
      	应该将这两块内存中的数据进行序列化 -> []byte
      	func (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. 打开公钥文件, 将文件内容读出 - []byte
   file, 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)
}

猜你喜欢

转载自blog.csdn.net/ma2595162349/article/details/113004058
今日推荐