Golang中如何使用OpenSSL签名HTTP请求

Golang中如何使用OpenSSL签名HTTP请求 大家好, 我们有一个私有的RSA密钥和一个密码短语, 如何使用这个密钥对请求进行签名?

我知道如何使用证书对请求进行签名,并且以下方法有效:

cert, err := tls.LoadX509KeyPair(path+"user.crt", path+"user.key")
	if err != nil {
		log.Fatal(err)
	}
tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}
t := &http.Transport{
		TLSClientConfig: tlsConfig,
	}
client := &http.Client{
		Transport: t,
	}
.....
.....
resp, err := client.Do(request)

它运行得很好…

但是在Go语言中如何实现同样的功能呢?这里有一个用PHP完成的示例:

....
$data = json_encode($data);

    $privateKey = openssl_pkey_get_private(
        file_get_contents(__DIR__ . 'private.pem'),
        file_get_contents(__DIR__ . 'password.txt')
    );
openssl_sign($data, $sign, $privateKey);
    $sign = base64_encode($sign);

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'apiurl');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Content-Type: application/json',
        'Sign: ' . $sign,
    ]);

在Go语言中如何获取签名呢?


更多关于Golang中如何使用OpenSSL签名HTTP请求的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中如何使用OpenSSL签名HTTP请求的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中,你可以使用crypto/rsacrypto/x509包来加载私钥并进行签名。以下是一个完整的示例:

package main

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

// 加载加密的PEM私钥
func loadPrivateKey(keyPath, password string) (*rsa.PrivateKey, error) {
	// 读取密钥文件
	keyBytes, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}

	// 解码PEM块
	block, _ := pem.Decode(keyBytes)
	if block == nil {
		return nil, fmt.Errorf("failed to parse PEM block")
	}

	// 如果密钥是加密的,使用密码解密
	if x509.IsEncryptedPEMBlock(block) {
		decryptedBlock, err := x509.DecryptPEMBlock(block, []byte(password))
		if err != nil {
			return nil, err
		}
		block.Bytes = decryptedBlock
		block.Type = "RSA PRIVATE KEY"
	}

	// 解析私钥
	privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		// 尝试PKCS8格式
		key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
		if err != nil {
			return nil, err
		}
		return key.(*rsa.PrivateKey), nil
	}

	return privateKey, nil
}

// 使用私钥对数据进行签名
func signData(data []byte, privateKey *rsa.PrivateKey) (string, error) {
	// 创建数据的哈希
	hashed := sha256.Sum256(data)

	// 使用PKCS1v15进行签名
	signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed[:])
	if err != nil {
		return "", err
	}

	// 返回Base64编码的签名
	return base64.StdEncoding.EncodeToString(signature), nil
}

func main() {
	// 你的数据
	data := map[string]interface{}{
		"name":  "test",
		"value": 123,
	}

	// 将数据转换为JSON
	jsonData, err := json.Marshal(data)
	if err != nil {
		log.Fatal(err)
	}

	// 加载私钥(假设私钥文件为private.pem,密码从文件读取)
	passwordBytes, err := ioutil.ReadFile("password.txt")
	if err != nil {
		log.Fatal(err)
	}
	password := string(passwordBytes)

	privateKey, err := loadPrivateKey("private.pem", password)
	if err != nil {
		log.Fatal(err)
	}

	// 对数据进行签名
	signature, err := signData(jsonData, privateKey)
	if err != nil {
		log.Fatal(err)
	}

	// 创建HTTP请求
	req, err := http.NewRequest("POST", "https://apiurl", bytes.NewBuffer(jsonData))
	if err != nil {
		log.Fatal(err)
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Sign", signature)

	// 发送请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	// 处理响应
	body, _ := ioutil.ReadAll(resp.Body)
	fmt.Println(string(body))
}

如果你使用的是PKCS8格式的私钥,这里还有一个使用crypto/rsacrypto/x509的替代方案:

// 使用PKCS8格式的私钥
func loadPKCS8PrivateKey(keyPath, password string) (*rsa.PrivateKey, error) {
	keyBytes, err := ioutil.ReadFile(keyPath)
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(keyBytes)
	if block == nil {
		return nil, fmt.Errorf("failed to parse PEM block")
	}

	// 解密加密的PKCS8私钥
	var decryptedKey []byte
	if block.Type == "ENCRYPTED PRIVATE KEY" {
		decryptedKey, err = x509.DecryptPEMBlock(block, []byte(password))
		if err != nil {
			return nil, err
		}
	} else {
		decryptedKey = block.Bytes
	}

	key, err := x509.ParsePKCS8PrivateKey(decryptedKey)
	if err != nil {
		return nil, err
	}

	return key.(*rsa.PrivateKey), nil
}

这个实现与你的PHP代码功能相同:

  1. 加载加密的PEM私钥
  2. 使用密码解密私钥
  3. 对JSON数据进行SHA256哈希
  4. 使用RSA私钥进行PKCS1v15签名
  5. 将签名进行Base64编码
  6. 将签名添加到HTTP请求头中
回到顶部