RSA跨语言生成签名和验证签名

PHP私钥生成签名
 
<?php
declare(strict_types=1);
ini_set('display_errors', 'On');
error_reporting(-1);

$privateKeyFile = __DIR__ . '/rsa_private_key.pem'; // 私钥文件路径

$privateKeyContents = file_get_contents($privateKeyFile); // 获取私钥的内容(即字符串)
$privateKeyResource = openssl_pkey_get_private($privateKeyContents);
$privateKeyResource === false && exit('openssl_pkey_get_private() is false.');

// 签名参数
$params = ['name' => '张三', 'gender' => '男', 'birth' => 2003];

// 按照参数名ASCII字典序排序(即按照a~z升序)
ksort($params);

// 转成“key1=value1&key2=value2&key3=value3”格式的字符串
$data = urldecode(http_build_query($params));

$signature = '';

// 生成签名,这里openssl_sign()函数缺省签名算法参数(第四个参数),即使用缺省值OPENSSL_ALGO_SHA1
openssl_sign($data, $signature, $privateKeyResource) || exit('openssl_sign() is false.');

$signature = base64_encode($signature);

echo "$data ===> $signature";
// birth=2003&gender=男&name=张三 ===> cv7MwgoDnX47VZDu2w8eREr/hCisbKeOmPIjjfdvPAdWTKgEpfXXLi1RlYI/hNVOsytVwFp3kEm+8DAAtQzNIKJ7UXjHi/kCFCLhTkQQjOg0Ci8xer3t4OLtOZgx0/UwPAAzrR3UDQKKZl12VVtQSQraMlTik8ILuksB0xvDoOx5dkVTWJKDmM4E7zrYGP15Z9F6vrK9gSi9aIri75ZOnCXHi27qCF0LEdhkrj5nCHdWw9/sdAWGqxYcAtjNpgDuI/ek7uGnaP6sIpK0pGc3J85Kge+KyDXPb6fRRFyNAHh4tt3BKppAtGl2OSpJDtjp9LiFIPXV3mrFPYnahFUyiA==
 
 
 
Go公钥验证签名
 
package main

import (
   "crypto"
   "crypto/rsa"
   "crypto/sha1"
   "crypto/x509"
   "encoding/base64"
   "encoding/pem"
   "fmt"
   "os"
   "path/filepath"
)

func main() {
   currentPath, err := filepath.Abs(".")
   if err != nil {
      panic("获取当前路径出错:" + err.Error())
   }

   // 构造公钥文件的硬盘路径
   publicKeyFile := currentPath + "/rsa_public_key.pem"

   // 打开公钥文件
   var file *os.File
   file, err = os.Open(publicKeyFile)
   if err != nil {
      panic("打开公钥文件出错:" + err.Error())
   }

   // 关闭公钥文件
   defer func(file *os.File) {
      err = file.Close()
      if err != nil {
         panic("关闭公钥文件出错:" + err.Error())
      }
   }(file)

   // 读取公钥文件
   contents, _ := file.Stat()
   buffers := make([]byte, contents.Size())
   _, err = file.Read(buffers)
   if err != nil {
      panic("读取公钥文件出错:" + err.Error())
   }

   // 解析公钥文件
   var publicKeyAny any
   pemDecode, _ := pem.Decode(buffers)                          // pem解码
   publicKeyAny, err = x509.ParsePKIXPublicKey(pemDecode.Bytes) // x509解码
   if err != nil {
      panic("解析公钥文件出错:" + err.Error())
   }

   // 断言
   publicKey, ok := publicKeyAny.(*rsa.PublicKey)
   if !ok {
      panic("不是合法的公钥文件")
   }

   // 签名参数
   params := "birth=2003&gender=男&name=张三"

   // 签名字符串
   signature := "cv7MwgoDnX47VZDu2w8eREr/hCisbKeOmPIjjfdvPAdWTKgEpfXXLi1RlYI/hNVOsytVwFp3kEm+8DAAtQzNIKJ7UXjHi/kCFCLhTkQQjOg0Ci8xer3t4OLtOZgx0/UwPAAzrR3UDQKKZl12VVtQSQraMlTik8ILuksB0xvDoOx5dkVTWJKDmM4E7zrYGP15Z9F6vrK9gSi9aIri75ZOnCXHi27qCF0LEdhkrj5nCHdWw9/sdAWGqxYcAtjNpgDuI/ek7uGnaP6sIpK0pGc3J85Kge+KyDXPb6fRRFyNAHh4tt3BKppAtGl2OSpJDtjp9LiFIPXV3mrFPYnahFUyiA=="

   // 签名字符串是base64编码,需要先解码
   var sig []byte
   sig, err = base64.StdEncoding.DecodeString(signature)
   if err != nil {
      panic("base64解码出错:" + err.Error())
   }

   hash := sha1.New() // 重要说明:生成签名时使用SHA1算法,这里要用sha1.New()
   _, err = hash.Write([]byte(params))
   if err != nil {
      panic("写入哈希对象出错:" + err.Error())
   }
   hashSum := hash.Sum(nil)

   // 使用公钥验证签名
   err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA1, hashSum, sig) // 重要说明:生成签名时使用SHA1算法,这里要用crypto.SHA1
   if err != nil {
      fmt.Println("签名错误:", err.Error())
   } else {
      fmt.Println("签名正确")
   }
}

Copyright © 2024 码农人生. All Rights Reserved