为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
FFIVE 2022-06-27 17:24:44
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 mainimport (    "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 实现,但到目前为止我失败了。
查看完整描述

1 回答

?
手掌心

TA贡献1942条经验 获得超3个赞

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


Blowfish具有 8 字节的块大小和4 到 56 字节之间的可变密钥大小。在 PHP 中,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 

这里有一个可以设置标志的在线PHP环境。


Go 中定义的填充是零填充,而在 PHP 代码中 PKCS7 填充由 openssl 使用(默认情况下)。对于 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 字节)计算的,这确保有足够的空间用于填充,因为最大填充是一个块。对于较短的填充,缓冲区太大,例如在当前情况下,明文的长度为 9 个字节,这导致缓冲区为 17 个字节。密文的长度为 16 个字节,最后是 0。如果需要,可以将确切需要的缓冲区大小确定为明文长度加上填充长度(后者的确定类似于函数padlen中的pad内容)。


查看完整回答
反对 回复 2022-06-27
  • 1 回答
  • 0 关注
  • 214 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信