将 PHP AES 加密移植到 Golang

我的电子商务提供商在 PHP、Java、JavaScript、C# 和 Python 中有这个库来加密我的请求,因为我的 API 是用 Go 制作的,我自然想,为什么不用 Go 做呢?


哦,男孩……我不知道我在做什么。


这是原始的PHP代码:


class AesCrypto {

    /**

    * Encrypt string with a given key

    * @param strToEncrypt

    * @param key

    * @return String encrypted string

    */

    public static function encrypt($plaintext, $key128) {

        $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-128-cbc'));

        $cipherText = openssl_encrypt($plaintext, 'AES-128-CBC', hex2bin($key128), 1, $iv);

        return base64_encode($iv.$cipherText);

    }

}

我用 Go 尝试了几种略有不同的方法,我想最低限度是这样的:


func encrypt(text string, key string) string {

    data := []byte(text)

    block, _ := aes.NewCipher([]byte(key))

    gcm, err := cipher.NewGCM(block)

    if err != nil {

        panic(err.Error())

    }

    nonce := make([]byte, gcm.NonceSize())

    if _, err = io.ReadFull(rand.Reader, nonce); err != nil {

        panic(err.Error())

    }

    ciphertext := gcm.Seal(nonce, nonce, data, nil)

    encoded := base64.StdEncoding.EncodeToString([]byte(ciphertext))

    return encoded

}

我创建了这个函数来加密和解密,它们工作正常,但是当我将它发送给我的提供商时它不起作用。


由key电子商务提供商分配,长度为 32 个字节,我知道长度“告诉”newCipher选择 AES-256,对吗?那么它永远不会对应于 AES-128,如 PHP func 中所示。


除了检查我的电子商务提供商的服务或尝试使用 PHP 代码解密之外,我该如何移植此 PHP 代码?


这是另一个尝试(来自 Go 加密文档):


func encrypt4(text string, keyString string) string {

    key, _ := hex.DecodeString(keyString)

    plaintext := []byte(text)

    if len(plaintext)%aes.BlockSize != 0 {

        panic("plaintext is not a multiple of the block size")

    }


    block, err := aes.NewCipher(key)

    if err != nil {

        panic(err)

    }


    ciphertext := make([]byte, aes.BlockSize+len(plaintext))

    iv := ciphertext[:aes.BlockSize]

    if _, err := io.ReadFull(rand.Reader, iv); err != nil {

        panic(err)

    }


    mode := cipher.NewCBCEncrypter(block, iv)

    mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)

    final := base64.StdEncoding.EncodeToString(ciphertext)

    return final

}


BIG阳
浏览 230回答 1
1回答

白板的微信

GCM 与 CBC 模式不同。密钥是十六进制编码的,所以一个 32 字节的字符串代表一个 16 字节(或 128 位)的密钥。在 CBC 模式下,明文必须被填充,以便它是块大小的倍数。PHP 的 openssl_encrypt 自动执行此操作(使用PKCS#5/7),但在 Go 中必须明确完成。综上所述,我们最终得到了文档中 CBC 加密示例的轻微变化:package mainimport (    "bytes"    "crypto/aes"    "crypto/cipher"    "crypto/rand"    "encoding/base64"    "encoding/hex"    "io")func encrypt(plaintext, key16 string) string {    padded := pkcs7pad([]byte(plaintext), aes.BlockSize)    key, err := hex.DecodeString(key16)    if err != nil {        panic(err)    }    block, err := aes.NewCipher(key)    if err != nil {        panic(err)    }    buffer := make([]byte, aes.BlockSize+len(padded)) // IV followed by ciphertext    iv, ciphertext := buffer[:aes.BlockSize], buffer[aes.BlockSize:]    if _, err := io.ReadFull(rand.Reader, iv); err != nil {        panic(err)    }    mode := cipher.NewCBCEncrypter(block, iv)    mode.CryptBlocks(ciphertext, padded)    return base64.StdEncoding.EncodeToString(buffer)}func pkcs7pad(plaintext []byte, blockSize int) []byte {    padding := blockSize - len(plaintext)%blockSize    return append(plaintext, bytes.Repeat([]byte{byte(padding)}, padding)...)}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go