Home >Backend Development >PHP Tutorial >Blowfish加密,分别使用PHP和C++实现,但结果不同.

Blowfish加密,分别使用PHP和C++实现,但结果不同.

WBOY
WBOYOriginal
2016-06-23 14:04:051394browse

先是MD5实验,结果相同,但使用Blowfish实验,怎么做也成功不了
调用如下:

<?php         $cipher = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_ECB, '');    $iv   = '00000000';    $key  = "strkey11";    $stext = '38A0E9312DDA8F7C16B9A12159168C76';    $stext = md5($stext, true);    //经过调试知道,在这时$stext的值与C++中MD5后的结果一致    if (mcrypt_generic_init($cipher, $key, $iv) != -1)    {        $dtext = mcrypt_generic($cipher,$stext );        mcrypt_generic_deinit($cipher);        // Display the result in hex.        printf("blowfish encrypted:<br>%s<br><br>",strtoupper(bin2hex($dtext)));    }    mcrypt_module_close($cipher);

C++的是这样:
    MD5_CTX md5;    unsigned char str[16];    md5.MD5String(strSource.c_str() ,str);    BlockCipher *bf;    char key[] = "strkey11";              //Key    bf = new BlowFish();    bf->setKey((void *)key, 8*8);    bf->encrypt((void *)str, 8);      //unsigned char str[16];    bf->encrypt((void *)(str+8), 8);    char temp1[4] = {0};    char buff1[128] = {0};    for(int i = 0;i<16;i++)    {        sprintf(temp1,"%02x",str[i]);        strcat(buff1,temp1);    }    AnsiString strResult = String(buff1).UpperCase();    delete bf;


回复讨论(解决方案)

$iv   = '00000000'; ???
按 bf->setKey((void *)key, 8*8); 理解
应该是
$iv = "\x00\x00\x00\x00\x00\x00\x00\x00";
吧?

IV is ignored in ECB. IV MUST exist in CFB, CBC, STREAM, nOFB and OFB modes.
MCRYPT_MODE_ECB的模式,$iv是忽略的,应该不是这个问题。

好像是加密之前要padding,你试试看
$size = mcrypt_get_block_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$input = pkcs5_pad($input, $size); 

function pkcs5_pad ($text, $blocksize)
{
    $pad = $blocksize - (strlen($text) % $blocksize);
    return $text . str_repeat(chr($pad), $pad);
}

function pkcs5_unpad($text)
{
    $pad = ord($text{strlen($text)-1});
    if ($pad > strlen($text)) return false;
    if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;
    return substr($text, 0, -1 * $pad);

嗯,用不上$iv

楼上的方法,是在PHP的mcrypt模块中使用的吗?

我查了下资料,在使用Pear的BF加密类的时候,要先padding

怎么用不上?
if(mcrypt_generic_init($cipher, $key,  $iv) ...
$iv 需要是纯二进制数据,这是最容易忽视的

呵呵,谢谢楼上,我不是很懂加密原理,但这一例中,明显$iv是个被忽略的参数,你可以试验用随机字串填充$iv来看加密结果,不会有变化。

另外,这个是Blowfish加密,你可以想成其他算法了吧

错别字纠正:可以-〉可 能

测不测都无所谓
因为没有c++环境,测了也没用

如果想判定是否为 php 代码问题,你至少需要给出 3 组C++加密的结果(明文和密文)

谢谢,我这就算一下,还需要C++的blowfish代码吗?我可以email

不需要C++的blowfish代码,即使他有问题也不是 php 讨论的问题
要你给出他的结果,是用于检查 php 运行结果用的

C++的几组结果:
原1:38A0E9312DDA8F7C16B9A12159168C76
密1:C58BF3EB9AE84385D90EE7020AC7CECB

原2:CKGVRGEBTSMTKLQLDQXERBNOXZROEFOL
密2:0FA050CC105E92EBAE46492428561D74

原3:ZOVVTOAMEDCSQJLCJUZKSDCNPQRHMBQG
密3:2E49406676B5C4E28057D22EB5D5AF73

原4:C58BF3EB9AE84385D90EE7020AC7CECB
密4:5A4D282F291F98A5C0748834925EBCFC

to 9楼:


我想提供C++的代码,只是想,你可能手头没这个库,给你好做测试,没别的意思

突然发现你这么写没有什么意义了
都 $stext = md5($stext, true); 了
解密还有效吗?
既然解密不出明文,那就没有查错的意义了

这明显是不可逆的加密,你不会说现在才看出来吧?另外,你现在还坚持$iv是必要的这一说法吗?

请看我最最最开始的代码....

我的问题是:PHP和C++对相同明文处理后的结果不同

再说了,我第一楼都讲明了,MD5后,C++与PHP的结果也是一致的,只是在后面的Blowfish阶段,出现了不同

这样说就避过MD5的问题了吧

就是说,你只看后半段就可以,MD5操作后的结果没问题,再向后有问题

c++的结果是不是有问题,这里有个在线blowfish加密的,你可以验证一下
http://webnet77.com/cgi-bin/helpers/blowfish.pl

bin2hex(md5('38A0E9312DDA8F7C16B9A12159168C76', true))

= df22a2ca739c2c2735e3bf4543a5206c

把这个输入http://webnet77.com/cgi-bin/helpers/blowfish.pl, key是strkey11

结果是:
B03249EF836AD65BA5BF9DAF03271CED
757DA563987175799A3B6E540B68889E

和你的结果不一样

谢谢楼上,你多了一步处理bin2hex,这个处理会不会影响最后结果呀,我感觉输入不同了,是不是呀?

另外这个http://webnet77.com/cgi-bin/helpers/blowfish.pl输出结果的处理方式也不一样,长度涨了一倍,一般blowfish是不变长的吧

C++的代码我都已经贴出来了,少了个C++的BF的类库,好像是用的Google当时公开的,用了好久了,记不清了,不过应该没错误,你留下Email帮我看下?

不好意思!
本来兴致勃勃的想帮你解决问题的,但发现是在弄不可逆的就没兴趣了

blowfish 是可逆的加密算法,密文长度随明文而变


首先你要弄清楚到底是PHP错了还是C++错了,我之前用bin2hex确实不对,但是md5之后是二进制数据没法验证,
你能不能不要用md5直接字符abcdefgh, 加密后是什么?

网页结果是
明文 abcdefgh
密文 5B4148819C51DCB5

首先,C++的加密结果是可逆的,我想这不存在谁对谁错的问题,我相信PHP的结果也是可逆的,只是他们在加密解密中间状态的密文的表现形式不同,而我们恰好要用密文做对比...

嗯,C++不MD5,处理abcdefgh,结果为12DB6214F5EAB031,其中KEY为"strkey11",显示出来的格式是16进制,通过把blowfish处理结果的每个BYTE转化成16进制字母来生成的

我之所以在PHP中用MD5输出成二进制,是为了和C++匹配,而C++中,Blowfish正好接收两组BYTE来处理,都省了转化与填充,也少了出错过程

我用了PHP的在线解码
http://www.tools4noobs.com/online_tools/decrypt/

5B4148819C51DCB5能解密出来,但是12DB6214F5EAB031解不出来

是不是C++程序有什么不一样?只要能加密解密不能算错,但是要互相能解密加密就必须遵循一样的算法。

同样的对称算法,同样的key,不大可能密文是不一样的,除了有些随机干扰。但是从blowfish的算法看,
并没有随机干扰,是不是有可能是pbox,sbox定义的不一样?

关于C++代码,有两个问题你可以确认一下
1)bf->setKey((void *)key, 8*8); 第二个参数应该是key的长度,为什么是8*8?
2)PHP有设置ECB模式,但是c++里没有,是不是缺省就是ECB?

我找到原因了,你的算法跟PHP的blowfish算法不一样,c++的算法是blowfish-compat

所以改成$cipher = mcrypt_module_open('blowfish-compat', '', MCRYPT_MODE_ECB, '');
这样就应该可以了。

赞美楼上!问题解决了99.9%,就是这个算法,PHP结果出来了后,我是这样处理的:

strtoupper(bin2hex($data))
,但结果比预期长了一倍,其实到这里已经可以结束了,因为虽然长了一倍,前半段就是我要的结果,已经可以用了。

但有个小问题,我有点不明白PHP的转16进制方法,怎么转过来会长一倍呢,能不能直接转成等长的?

看C++的转化,代码这样的
sprintf(temp1,"%02x",str[i]);
,我曾经找blowfish的原理看了下,没看大明白,但感觉应该是位置置换,不会变长呀

再能解决这个问题,就真完美了,呵呵 

我知道什么问题了,我用来做验证的C++程序是从原程序中截出来后改的,我在把明文处理成数组的时候,只截了一半(原程序中处理的数据是一半长度的...),所以出来的是半长,你那个全长是对的

结帖了,这个话题我有空整理一下,发在BLOG上吧,现在网上找不到C++与PHP结果互通的做法

显然,没有花功夫帮你排错是正确的选择

版主说话不靠谱,我也遇到这个问题,感谢Meteorlet的热心

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:php,jsNext article:PHP怎么让mysql数据表自动归类?