Golang中如何使用Openssl_encrypt进行加密和解密?

Golang中如何使用Openssl_encrypt进行加密和解密? 大家好,

我是论坛的新成员,这是我的第一个主题。

很抱歉需要翻译。

我需要使用与 openssl_encrypt (PHP) 相同的方法进行加密,但我没有找到解决方案。我尝试解密一个用 openssl_decrypt 加密的数据,以便之后反过来操作,但这并不奏效。

我需要在 Go 中重现以下代码:

$crypted = openssl_encrypt(
    serialize($unencrypted_data),
    'AES-256-CTR',
    $key,
    0,
    $iv
);

我尝试了相反的操作(解密一个用 openssl_encrypt 加密的数据):

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "fmt"
)

func main() {
    iv, _ := base64.StdEncoding.DecodeString("NjIxNDM4MTFjODFhODRkYw==")
    fmt.Println(string(iv))

    key := []byte("key")
    fmt.Println(string(key))

    text, _ := base64.StdEncoding.DecodeString("TktXS3hKWnFZY3YwTXVpR0JKR0pYMkU4SlJ5aWFSZC9DZDJFaW1xdHNxVmZMT2JGUFI0YnRzakxMVkJsS1YyWEpYUEo0R2k4UDhGSERkQkRRTWtxUWcrbnhkU2NtTXlBTHJaM2M4cSs=")
    fmt.Println(text)

    cipherBlock, _ := aes.NewCipher(key)
    fmt.Println(cipherBlock)

    mode := cipher.NewCBCDecrypter(cipherBlock, iv)    
    mode.CryptBlocks(text[0:64], text[0:64])
    fmt.Println(string(text))
}

结果(不正确):�Zf�^��7jZ��X}lM�ܿ/�:��w�kt5�����Z��|�pM�+/�?J��ʍ�_e��JXPJ4Gi8P8FHDdBDQMkqQg+nxdScmMyALrZ3c8q+

谢谢


更多关于Golang中如何使用Openssl_encrypt进行加密和解密?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中如何使用Openssl_encrypt进行加密和解密?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中实现与PHP的openssl_encrypt兼容的AES-256-CTR加密解密,需要注意以下几点:

  1. 密钥长度:AES-256需要32字节密钥
  2. IV长度:CTR模式需要16字节IV
  3. 序列化:PHP的serialize()需要对应Go的序列化处理
  4. 编码:PHP默认使用base64输出

以下是完整的示例代码:

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io"
)

// 加密函数,兼容PHP openssl_encrypt
func opensslEncrypt(data interface{}, key []byte) (string, error) {
    // 序列化数据(这里使用JSON替代PHP serialize)
    serialized, err := json.Marshal(data)
    if err != nil {
        return "", err
    }

    // 确保密钥长度为32字节(AES-256)
    if len(key) < 32 {
        paddedKey := make([]byte, 32)
        copy(paddedKey, key)
        key = paddedKey
    } else {
        key = key[:32]
    }

    // 生成16字节IV
    iv := make([]byte, aes.BlockSize)
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
        return "", err
    }

    // 创建AES cipher
    block, err := aes.NewCipher(key)
    if err != nil {
        return "", err
    }

    // 创建CTR模式加密器
    stream := cipher.NewCTR(block, iv)
    ciphertext := make([]byte, len(serialized))
    stream.XORKeyStream(ciphertext, serialized)

    // 组合IV和密文,然后base64编码
    encrypted := append(iv, ciphertext...)
    return base64.StdEncoding.EncodeToString(encrypted), nil
}

// 解密函数,兼容PHP openssl_decrypt
func opensslDecrypt(encrypted string, key []byte, result interface{}) error {
    // base64解码
    data, err := base64.StdEncoding.DecodeString(encrypted)
    if err != nil {
        return err
    }

    // 确保密钥长度为32字节
    if len(key) < 32 {
        paddedKey := make([]byte, 32)
        copy(paddedKey, key)
        key = paddedKey
    } else {
        key = key[:32]
    }

    // 分离IV和密文(前16字节是IV)
    if len(data) < aes.BlockSize {
        return fmt.Errorf("ciphertext too short")
    }
    iv := data[:aes.BlockSize]
    ciphertext := data[aes.BlockSize:]

    // 创建AES cipher
    block, err := aes.NewCipher(key)
    if err != nil {
        return err
    }

    // 创建CTR模式解密器
    stream := cipher.NewCTR(block, iv)
    plaintext := make([]byte, len(ciphertext))
    stream.XORKeyStream(plaintext, ciphertext)

    // 反序列化数据
    return json.Unmarshal(plaintext, result)
}

func main() {
    // 示例数据
    data := map[string]interface{}{
        "name":  "John Doe",
        "email": "john@example.com",
        "age":   30,
    }

    key := []byte("my-32-byte-long-secret-key-1234567890")

    // 加密
    encrypted, err := opensslEncrypt(data, key)
    if err != nil {
        fmt.Println("加密错误:", err)
        return
    }
    fmt.Println("加密结果:", encrypted)

    // 解密
    var decrypted map[string]interface{}
    err = opensslDecrypt(encrypted, key, &decrypted)
    if err != nil {
        fmt.Println("解密错误:", err)
        return
    }
    fmt.Println("解密结果:", decrypted)
}

对于你提供的具体解密问题,这里是一个修复版本:

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "encoding/base64"
    "fmt"
)

func main() {
    // 注意:你的IV是base64编码的,但看起来长度不对
    // CTR模式需要16字节IV
    iv, _ := base64.StdEncoding.DecodeString("NjIxNDM4MTFjODFhODRkYw==")
    fmt.Printf("IV长度: %d字节\n", len(iv))
    
    // AES-256需要32字节密钥
    key := []byte("32-byte-long-key-for-aes-256-ctr")
    if len(key) < 32 {
        // 填充密钥到32字节
        paddedKey := make([]byte, 32)
        copy(paddedKey, key)
        key = paddedKey
    }
    
    // 密文
    ciphertext, _ := base64.StdEncoding.DecodeString("TktXS3hKWnFZY3YwTXVpR0JKR0pYMkU4SlJ5aWFSZC9DZDJFaW1xdHNxVmZMT2JGUFI0YnRzakxMVkJsS1YyWEpYUEo0R2k4UDhGSERkQkRRTWtxUWcrbnhkU2NtTXlBTHJaM2M4cSs=")
    
    // 创建cipher
    block, err := aes.NewCipher(key[:32])
    if err != nil {
        fmt.Println("创建cipher错误:", err)
        return
    }
    
    // 使用CTR模式(不是CBC)
    stream := cipher.NewCTR(block, iv)
    
    // 解密
    plaintext := make([]byte, len(ciphertext))
    stream.XORKeyStream(plaintext, ciphertext)
    
    fmt.Println("解密结果:", string(plaintext))
}

关键点:

  1. 使用cipher.NewCTR而不是cipher.NewCBCDecrypter
  2. 确保密钥长度为32字节(AES-256)
  3. IV长度必须为16字节
  4. CTR模式不需要填充,直接XOR操作

如果你的PHP代码使用了不同的序列化方式,可能需要调整序列化/反序列化部分。对于PHP的serialize(),可以考虑使用第三方库如github.com/techoner/gophp/serialize来处理。

回到顶部