微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在php openssl_encrypt和golang河豚中匹配河豚加密

如何解决在php openssl_encrypt和golang河豚中匹配河豚加密

PHP

$key = "testtesttest";
$text = "bublijuja";
$iv = openssl_random_pseudo_bytes( openssl_cipher_iv_length("blowfish"));
for($i = 0; $i < strlen($iv); $i++)
{
    echo ord($iv[$i])." ";
}
echo "\n";
$et = openssl_encrypt( $text,"blowfish",$key,OPENSSL_RAW_DATA,$iv );
for($i = 0; $i < strlen($et); $i++)
{
    echo ord($et[$i])." ";
}
echo "\n";

此打印(第一行是IV,第二行是加密的文本:

253 145 220 198 224 78 40 124 
208 51 12 30 46 92 13 181 19 210 50 57 174 207 93 130 

将该IV复制到golang:

package main

import (
    "golang.org/x/crypto/blowfish"
    "crypto/cipher"
    "fmt"
)



func main() {
    key  := "testtesttest"
    plaintext := "bublijuja"
    byteSlice := []int{253,145,220,198,224,78,40,124}
    iv := make([]byte,len(byteSlice))
    for i,b := range byteSlice {
        iv[i] = byte(b)
    }
    fmt.Println(iv)
    ciphertext := make([]byte,blowfish.BlockSize+len(plaintext))
    block,err := blowfish.NewCipher([]byte(key))
    if err != nil {
    fmt.Println(err.Error())
    return
    }
    mode := cipher.NewCBCEncrypter(block,iv)
    mode.CryptBlocks(ciphertext,pad([]byte(plaintext)))

    fmt.Println(ciphertext)
}


func pad(pt []byte) []byte {
    // calculate modulus of plaintext to blowfish's cipher block size
    // if result is not 0,then we need to pad
    modulus := len(pt) % blowfish.BlockSize
    if modulus != 0 {
        // how many bytes do we need to pad to make pt to be a multiple of
        //blowfish's block size?
        padlen := blowfish.BlockSize - modulus
        // let's add the required padding
        for i := 0; i < padlen; i++ {
            // add the pad,one at a time
            pt = append(pt,0)
        }
    }
    // return the whole-multiple-of-blowfish.BlockSize-sized plaintext
    // to the calling function
    return pt
}

我得到:

[253 145 220 198 224 78 40 124]
[61 82 97 183 42 220 119 173 114 107 250 139 174 236 113 91 0]

我也尝试过ECB模式。 我一次可以匹配前8个字节,但是我搞砸了。 我试图弄清楚PHP版本是如何处理它的,以便可以匹配go的实现,但是到目前为止我还是失败了。

解决方法

以下问题导致不同的结果:

  • Blowfish的块大小为8个字节,而变量的键大小为4到56个字节。在PHP中,有一个bug用于Blowfish,它将较短的键填充为16个字节(0值)。从7.1.8版开始,有一个禁止使用此标志的标志:OPENSSL_DONT_ZERO_PAD_KEY。如果另外设置了此标志(OPENSSL_RAW_DATA | OPENSSL_DONT_ZERO_PAD_KEY),则将在要求的环境中产生以下输出:

    253 145 220 198 224 78 40 124 
    61 82 97 183 42 220 119 173 26 156 153 20 152 139 105 237 
    

    Here有一个在线PHP环境,可以在其中设置标志。

  • 在Go中定义的填充为零填充,而在PHP代码中,openssl使用PKCS7填充(默认)。对于PKCS7,需要进行以下更改(无注释,使用相同的名称):

    func pad(pt []byte) []byte {
        modulus := len(pt) % blowfish.BlockSize
        padlen := blowfish.BlockSize - modulus
        for i := 0; i < padlen; i++ {
            pt = append(pt,byte(padlen))
        }
        return pt
    }
    

    通过此更改,Go-代码给出了相同的结果:

    [253 145 220 198 224 78 40 124]
    [61 82 97 183 42 220 119 173 26 156 153 20 152 139 105 237 0]
    

    最后的0是由密文缓冲区太大引起的。在Go代码中,输出缓冲区的长度是用纯文本长度加上块大小(Blowfish为8字节)计算的,这确保了有足够的填充空间,因为 maximum 填充是一个块。如果填充时间较短,则缓冲区太大,例如在当前情况下,明文的长度为9个字节,这导致17个字节的缓冲区。密文的长度为16个字节,最后是0。如果需要,可以将确切所需的缓冲区大小确定为纯文本长度加上填充长度(后者的确定类似于padlen中的pad功能)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。