繁体   English   中英

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

[英]Matching blowfish encryption in php openssl_encrypt and golang blowfish

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 实现,但到目前为止我失败了。

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

  • 河豚有一个8字节块大小和4个56字节之间的可变密钥大小。 在 PHP 中,Blowfish 有一个错误,它将较短的键填充到 16 个字节,其中包含 0 个值。 从 7.1.8 版开始,有一个标志可以防止这种情况: OPENSSL_DONT_ZERO_PAD_KEY 如果另外设置了此标志 ( OPENSSL_RAW_DATA | 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 代码中,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 - Code 给出了相同的结果:

     [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。 如果需要,确切需要的缓冲区大小可以确定为明文长度加上填充长度(后者的确定类似于pad函数中的padlen )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM