Golang如何实现类似PHP的openssl_private_encrypt功能

Golang如何实现类似PHP的openssl_private_encrypt功能 我正在尝试将我的项目从 PHP 迁移到 Go,但我发现 Go 没有私钥加密方法。

据我所知,Go 只支持私钥解密(rsa.DecryptOAEP)。

但 PHP 有一个名为 openssl_private_encrypt 的函数 PHP: openssl_private_encrypt - Manual

有什么我可以使用的替代方法吗?

谢谢

2 回复

PHP的 openssl_private_encrypt 手册是密码学扩展的一部分。这是PHP全球范围内使用的官方密码学库。

在Golang中,有两种选择来获取使用OpenSSL私钥进行加密解密的函数:

  • 选项1: 构建你自己的加密解密函数。Golang有官方的密码学包。你可以在这里查看加密解密的示例。
  • 选项2: 使用Golang社区包。有很多现成的库可以进行加密解密。例如:
    • https://github.com/VIBHOR94/go-openssl
    • https://github.com/spacemonkeygo/openssl
    • https://github.com/forgoer/openssl
    • https://github.com/Luzifer/go-openssl

尝试比较它们,找出最适合你的方案。 希望这能解答你的问题。blush

更多关于Golang如何实现类似PHP的openssl_private_encrypt功能的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中实现类似PHP的openssl_private_encrypt功能,可以使用RSA私钥进行加密(签名操作)。这实际上是使用私钥对数据进行签名,而不是传统意义上的加密。以下是两种实现方式:

方法1:使用PKCS#1 v1.5签名(最接近PHP默认行为)

package main

import (
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "crypto/x509"
    "encoding/pem"
    "fmt"
    "log"
)

func privateEncryptPKCS1v15(privateKeyPEM []byte, data []byte) ([]byte, error) {
    // 解析PEM格式的私钥
    block, _ := pem.Decode(privateKeyPEM)
    if block == nil {
        return nil, fmt.Errorf("failed to parse PEM block")
    }

    // 解析私钥
    privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        // 尝试PKCS8格式
        key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
        if err != nil {
            return nil, fmt.Errorf("failed to parse private key: %v", err)
        }
        var ok bool
        privKey, ok = key.(*rsa.PrivateKey)
        if !ok {
            return nil, fmt.Errorf("not an RSA private key")
        }
    }

    // 计算数据的哈希
    hashed := sha256.Sum256(data)
    
    // 使用私钥签名(相当于PHP的openssl_private_encrypt)
    signature, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, hashed[:])
    if err != nil {
        return nil, fmt.Errorf("signing failed: %v", err)
    }

    return signature, nil
}

func main() {
    // 示例私钥(实际使用时替换为你的私钥)
    privateKeyPEM := `-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAwV2Bd5J...
-----END RSA PRIVATE KEY-----`

    data := []byte("Hello, World!")
    
    encrypted, err := privateEncryptPKCS1v15([]byte(privateKeyPEM), data)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("Encrypted/Signed data: %x\n", encrypted)
}

方法2:使用PSS签名(更安全)

func privateEncryptPSS(privateKeyPEM []byte, data []byte) ([]byte, error) {
    block, _ := pem.Decode(privateKeyPEM)
    if block == nil {
        return nil, fmt.Errorf("failed to parse PEM block")
    }

    privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
        if err != nil {
            return nil, fmt.Errorf("failed to parse private key: %v", err)
        }
        var ok bool
        privKey, ok = key.(*rsa.PrivateKey)
        if !ok {
            return nil, fmt.Errorf("not an RSA private key")
        }
    }

    hashed := sha256.Sum256(data)
    
    // 使用PSS签名
    signature, err := rsa.SignPSS(rand.Reader, privKey, crypto.SHA256, hashed[:], nil)
    if err != nil {
        return nil, fmt.Errorf("PSS signing failed: %v", err)
    }

    return signature, nil
}

方法3:直接使用私钥加密(不推荐,仅用于兼容)

func privateEncryptRaw(privateKeyPEM []byte, data []byte) ([]byte, error) {
    block, _ := pem.Decode(privateKeyPEM)
    if block == nil {
        return nil, fmt.Errorf("failed to parse PEM block")
    }

    privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
        if err != nil {
            return nil, fmt.Errorf("failed to parse private key: %v", err)
        }
        var ok bool
        privKey, ok = key.(*rsa.PrivateKey)
        if !ok {
            return nil, fmt.Errorf("not an RSA private key")
        }
    }

    // 注意:RSA私钥加密有长度限制
    // 数据长度必须小于密钥长度-11字节(PKCS#1 v1.5填充)
    maxLen := (privKey.N.BitLen() / 8) - 11
    if len(data) > maxLen {
        return nil, fmt.Errorf("data too large for RSA key size")
    }

    // 使用私钥直接加密(不推荐用于生产)
    encrypted, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.Hash(0), data)
    if err != nil {
        return nil, fmt.Errorf("encryption failed: %v", err)
    }

    return encrypted, nil
}

验证示例(对应PHP的openssl_public_decrypt)

func publicDecrypt(publicKeyPEM []byte, encryptedData []byte) ([]byte, error) {
    block, _ := pem.Decode(publicKeyPEM)
    if block == nil {
        return nil, fmt.Errorf("failed to parse PEM block")
    }

    pubKey, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        return nil, fmt.Errorf("failed to parse public key: %v", err)
    }

    rsaPubKey, ok := pubKey.(*rsa.PublicKey)
    if !ok {
        return nil, fmt.Errorf("not an RSA public key")
    }

    // 验证签名/解密
    return rsaPubKey.N.Bytes()[:len(encryptedData)], nil
}

注意:PHP的openssl_private_encrypt实际上执行的是私钥签名操作。在Go中,你应该根据具体用途选择:

  • 如果用于签名验证:使用方法1或2
  • 如果确实需要私钥加密:使用方法3(但通常不推荐)

实际迁移时,需要确认PHP代码中openssl_private_encrypt的具体用途,以选择正确的Go实现方式。

回到顶部