【问题标题】:AES-256-CBC encryption Golang and PHPAES-256-CBC 加密 Golang 和 PHP
【发布时间】:2021-06-07 00:22:39
【问题描述】:

我正在尝试在 golang 中实现 AES-256-CBC 加密。我有一个已经使用多年的有效 PHP 代码。我在 Golang 中获取加密值,但对于相同的有效负载/密钥/iv 组合,这些值与 PHP 的输出不匹配。

为简化起见,我在下面的代码中对有效负载/密钥/iv 进行了硬编码。我还从我的 go 代码中删除了详细的错误消息。

这是我的 GO 代码

func encryption() {
    plaintext := []byte("12345678912345678912345678900000")
    key, _ := base64.StdEncoding.DecodeString("cidRgzwfcgztwae/mccalIeedOAmA/CbU3HEqWz1Ejk=")
    iv, _ := hex.DecodeString("162578ddce177a4a7cb2f7c738fa052d")

    /*php seem to use PKCS7 padding to make the source string match the blocksize 
     requirement for AES-256-CBC.
     From what I understand, I need to do padding manually in Golang. 
     Correct me if wrong */
    plaintext, _ = Pkcs7Pad(plaintext, aes.BlockSize)

    block, _ := aes.NewCipher(key)

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

    mode := cipher.NewCBCEncrypter(block, iv)

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

    fmt.Printf("EncryptedText %v\n", string(ciphertext))
    fmt.Printf("EncryptedText as hex %v\n", hex.EncodeToString(ciphertext))
}

func Pkcs7Pad(b []byte, blocksize int) ([]byte, error) {
    if blocksize <= 0 {
        return nil, errors.New("Invalid block size")
    }
    if b == nil || len(b) == 0 {
        return nil, errors.New("Invalid block size")
    }
    n := blocksize - (len(b) % blocksize)
    pb := make([]byte, len(b)+n)
    copy(pb, b)
    copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n))
    return pb, nil
}

我的 Go 输出是

EncryptedText |8??X?z??F ?0ĺe?,??G?V?
Gce??dM????z?,*ȁҼ
EncryptedText as hex 7c38bad658907a81d14620c930c4ba658c1f022cdb1392479856cc0a471d6365dfc5644db6b28cef7ac02c2ac881d2bc

我有一个 PHP 代码来执行相同的任务,这给了我不同的输出。

function encryption() {
    $plaintext = "12345678912345678912345678900000";
    $key = base64_decode("cidRgzwfcgztwae/mccalIeedOAmA/CbU3HEqWz1Ejk=");
    $iv = hex2bin("162578ddce177a4a7cb2f7c738fa052d");

    //php openssl_encrypt function seem to use pkcs7pad to make the source string match the blocksize requirement for AES-256-CBC

    $ciphertext = openssl_encrypt($plaintext, 'AES-256-CBC', $key, 0, $iv );
    print $ciphertext;
}

PHP 输出是

fDi61liQeoHRRiDJMMS6ZYwfAizbE5JHmFbMCkcdY2XfxWRNtrKM73rALCrIgdK8

显然,我想让我的 Golang 实现获得与 PHP 相同的输出。由于我需要与我的 Golang 代码和现有 PHP 代码进行通信,因此我希望在 PHP 和 Golang 中都进行相同的加密和解密工作。

有什么想法吗?

【问题讨论】:

    标签: php go encryption aes cbc-mac


    【解决方案1】:

    您的方法存在一些问题:

    • openssl_encrypt,默认输出base 64编码字符串(不是十六进制)
    • 我怀疑你的pkcs7Pad(你没有包括在内)正在做一些意想不到的事情(因为你在mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)中跳过了ciphertext的开头

    注意:我无法复制您的结果,因为您没有包含您的 pkcs7Pad(指向 playground 的链接是个好主意,因为它可以确保其他人能够复制您的问题) .

    我相信下面的代码会给出你想要的(结果与 php 匹配——我没有做任何进一步的测试):

    
    func main() {
        plaintext := []byte("12345678912345678912345678900000")
        key, err := base64.StdEncoding.DecodeString("cidRgzwfcgztwae/mccalIeedOAmA/CbU3HEqWz1Ejk=")
        if err != nil {
            panic(err)
        }
        iv, err := hex.DecodeString("162578ddce177a4a7cb2f7c738fa052d")
        if err != nil {
            panic(err)
        }
    
        plaintext = pkcs7Pad(plaintext, aes.BlockSize)
    
        block, err := aes.NewCipher(key)
        if err != nil {
            panic(err)
        }
    
        ciphertext := make([]byte, len(plaintext))
    
        mode := cipher.NewCBCEncrypter(block, iv)
    
        mode.CryptBlocks(ciphertext, plaintext)
    
        fmt.Printf("EncryptedText %v\n", string(ciphertext))
        fmt.Printf("EncryptedText as hex %v\n", hex.EncodeToString(ciphertext))
        fmt.Printf("EncryptedText as base 64 %v\n", base64.StdEncoding.EncodeToString(ciphertext))
    }
    
    func pkcs7Pad(ciphertext []byte, blockSize int) []byte {
        padding := blockSize - len(ciphertext)%blockSize
        padtext := bytes.Repeat([]byte{byte(padding)}, padding)
        return append(ciphertext, padtext...)
    }
    

    playground试试吧

    【讨论】:

    • 糟糕,我已经编辑了问题并添加了 Pkcs7Pad 方法。对不起,我错过了。同时让我在你的操场上玩耍
    • 在我的问题的 PHP 代码库中,openssl_encrypt 方法针对选项属性传递了一个“0”值。但是,当我检查 documentation 时,openssl_encrypt 方法需要常量 OPENSSL_RAW_DATA OPENSSL_ZERO_PADDING 反对选项参数。这些常量的值分别为 1 和 2,而不是 0(PHP 代码正在传递)。当我将 PHP 代码更改为发送 OPENSSL_RAW_DATA 而不是 0 时,其结果与 Golang 的结果匹配。
    • 很好 - 所以主要问题是不同的输出格式。现在我有了你所有的代码,我可以运行它并验证它不会产生你在问题中陈述的输出(十六进制以000000000000000000000000000000007c 开头;见playground。这是因为你传递@ 987654336@到CryptBlocks
    • 这帮助我解决了我的问题。所以我给你打勾。谢谢
    猜你喜欢
    • 2019-11-17
    • 2018-11-18
    • 1970-01-01
    • 2014-02-06
    • 1970-01-01
    • 2012-08-05
    • 2013-08-11
    • 2022-11-16
    相关资源
    最近更新 更多