3

我在这里尝试做的是创建一个函数,每次调用它时都会将相同的输入加密为完全不同的输出。此函数的基础是 xor,但为了防止容易发现字符串中的重复模式。我添加了基于时间和字符串部分的随机散列,以在解密时进行自我验证。

我所要求的只是我是否在这里犯了任何类型的错误,这些错误可能会向有经验的人揭示隐藏的文本,而无需对字符串进行暴力破解。(我知道 php 有一个仅用于加密的模块,但这是一个糟糕的版本,以防加密模块不可用。)第二:我不要求你重写这个函数或为我写一些东西,我要求的是一个简单的指导我做错了什么。我知道一个可能的安全漏洞是我默认使用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'));
4

3 回答 3

13

你自己发明的任何密码无疑都会有漏洞——如果我们这些 Stack Overflow 上的人无法检测到它,那并不意味着其他人不会。密码学的第一条规则是不要发明自己的密码:使用现有的密码,并在可能的情况下使用众所周知且经过测试的实现。如果您绝对不能使用标准库,请实现现有的密码,例如TEA - 或者更好的是,找到您选择的语言的现有实现。

于 2010-12-23T23:08:04.337 回答
7

您的算法在长度块中运行strlen($hash)==strlen($tmphash)编辑:错误,但见下文。

在密文中,第一个这样的块等于($tmphash XOR $hash)。以下各等于(a_block_of_plaintext XOR $tmphash XOR $hash)

第一个密文块是您数据的密钥。只需将密文与密文的第一个块重复进行异或运算,即可得到明文。无需密码。

我不是 PHP 程序员,所以也许我遗漏了一些东西,但实际攻击与此没有太大区别。

作为一般规则,仅使用专业级加密模块。如果它们不可用,则您的应用程序不安全。

编辑:通过重读我注意到的问题$hash$tmphash有不同的长度。 $hash是 512 位和$tmphash160 位。但是,这并没有改变基本思想;由于 512 和 160 的最小公倍数是 2560,因此块每 2560 位同步一次。因此,您只能破译每个 2560 位块的前 160 位。

于 2010-12-24T00:42:13.050 回答
3

我的 php 不是很好,而且我是一个拥有一个学期的加密货币的家伙,所以绝不是专家。在评估加密系统的强度时,通常假设对手可以完全访问您的算法和实现。

我看到这条线:

 $tmphash = pack('H*',sha1(sin(microtime(1))));

我认为这是你的关键。就像我说的,我的 PHP 很糟糕,所以如果我错了,请纠正我。

如果 php sha1 函数返回 40 位十六进制数,这将为您提供 WEP 的密钥空间。上次查,WEP大概3分钟就可以破解。我不完全确定这是否是基于协议中的固有漏洞通过信息泄漏,或者这是因为超小的密钥空间。但是,对于密码安全来说,16^40 似乎不是一个足够大的密钥空间。

此外,基于此,我只需要知道用户生成此请求的大致时间,您将大大减少您需要搜索的关键空间。如果 php 中的 microtime() 方法实际上为您提供了自纪元以来的当前微秒,这会将我的关键搜索空间从 16^40(sha1 的 php 输出?)减少到我对您的用户有信心的时间范围内的微秒数从您那里收到此数据。我可以编写一个破解程序,从我最有信心的时候(我嗅探数据包的时候)开始运行这个密钥空间,然后从那里退出,直到我达到某种阈值。

你总是可以玩“我的算法是秘密”的游戏,但我认识的大多数安全专业人士并不真的觉得这是一个非常有效的论点(或者一个有趣的游戏)。这些只是一个受过非常基础教育的家伙遇到的两个论点,它们只针对您的键空间。

不要自己实施这样的事情。这是个坏主意。如果您正在为课程编写玩具程序,那很酷,但如果这是针对任何类型的生产系统,我强烈建议使用经过验证的真正密码系统。

-Brian J. Stinar-

于 2010-12-24T00:11:03.940 回答