我在这里试图做的是创建一个函数,每次调用它时,它都会将相同的输入加密为完全不同的输出。这个函数的基础是xor,但是为了防止在字符串中容易发现重复的模式。我添加了基于时间和字符串部分的随机散列,以便在描述时进行自我验证。
我所要求的是,如果我在这里犯了任何错误,可以揭示隐藏的文字经验丰富的人,而不做一个野蛮的字符串。
(我知道php有一个只用于加密的模块,但如果加密模块不可用,这是一个糟糕的mans版本。)
第二:我不要求你重写这个函数或者为我写一些东西,我要求的是一个简单的指导我做错了什么。
我知道一个可能的安全漏洞是我默认使用salsa,空字符串都是零,但优势是这是php中可用的最长散列,其次,哪个傻瓜会使用空密码来保护他们的数据?
function crapt($str,$pass,$hmac = false,$meth = 'salsa20') {
$hash = pack('H*',($hmac===false) ? hash($meth,$pass) : hash_hmac($meth,$pass,$hmac));
$str = gzdeflate($str,9);
$tmphash = pack('H*',sha1(sin(microtime(1))));
$str = $tmphash.((string)$str ^ (string)str_repeat($tmphash,strlen($str)/strlen($tmphash)+1));
$str .= pack('H*',sha1($str));
return (string)$str ^ (string)str_repeat($hash,strlen($str)/strlen($hash)+1);
}
function decrapt($str,$pass,$hmac = false,$meth = 'salsa20') {
$hash = pack('H*',($hmac===false) ? hash($meth,$pass) : hash_hmac($meth,$pass,$hmac));
$str = (string)$str ^ (string)str_repeat($hash,strlen($str)/strlen($hash)+1);
$check = substr($str,-20);
$str = substr($str,0,strlen($str)-20);
if(pack('H*',sha1($str))!==$check) return false;
$tmphash = substr($str,0,20);
$str = substr($str,20);
return gzinflate((string)$str ^ (string)str_repeat($tmphash,strlen($str)/strlen($tmphash)+1));
}
var_dump(decrapt(crapt('sometext','secretpassword'),'secretpassword'));
最佳答案
你的算法在长度strlen($hash)==strlen($tmphash)
的块中运行。编辑:错了,但请看下面。
在密文中,第一个这样的块等于($tmphash XOR $hash)
。以下各项均等于(a_block_of_plaintext XOR $tmphash XOR $hash)
。
密文的第一块是数据的密钥。只要将密文与第一个密文块的重复进行异或,就可以得到明文。不需要密码。
我不是一个php程序员,所以也许我遗漏了一些东西,但是实际的攻击与此没有多大区别。
一般情况下,只能使用专业级密码模块。如果它们不可用,则说明您的应用程序不安全。
编辑:通过重读这个问题,我注意到$hash
和$tmphash
有不同的长度。$hash
是512位,$tmphash
是160位。然而,这并没有改变基本思想;因为512和160的最小公倍数是2560,所以块每2560位同步一次。
因此,每2560位块只能破译前160位。