【问题标题】:is this xor based encryption function safe?这种基于异或的加密功能安全吗?
【发布时间】:2010-12-24 09:32:26
【问题描述】:

我在这里尝试做的是创建一个函数,该函数将在每次调用时将相同的输入加密为完全不同的输出。此函数的基础是 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'));

【问题讨论】:

  • +1 表示 craptdecrapt。 :-D
  • PHP 应该总是有它的加密模块可用。请使用它:正确进行加密非常困难。压缩输入,生成随机 IV,并使用带有 Rijndael 的 CBC 模式进行加密。将未加密的 IV 添加到加密文本中,以便在解密时使用。
  • 如果你对加密感兴趣,欢迎加入cryptography.SE

标签: php cryptography xor


【解决方案1】:

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

【讨论】:

  • +1 我不了解 TEA,但真正重要的是不要自己发明它。没有任何理由这样做,结果很可能不会比您已经使用的更好、更容易或以任何方式更可取。
  • @Fredrik 我只推荐 TEA,因为它实施起来非常简单,如果他坚持自己写的话,而且它有一定程度的同行评审。显然,如果他使用现有的库,像 AES 这样更知名的库将是更好的选择。
  • 当然,我没有反对的意思,我只是没有意见。
  • @Fredrik 没想到你是——我只是想澄清一下我的推理。
  • 我发现了这个关于 xxtea(据说更好的茶)cipherdev.org/break-xxtea.c.txt
【解决方案2】:

您的算法在长度为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 位。

【讨论】:

  • 我认为你是正确的。给定 $tphash,我可以解密所有后续加密。我很惊讶你在这里发现了 str_repeat。我错过了,直到你向我们展示。我的假设是,这只接受最多 sha1 输出的输出大小。这是一种比我提出的更优雅的攻击。
  • $hash 是用salsa20得到的,输出512位(可以看这里:cr.yp.to/salsa20.html
  • $tmphash 是用 sha1 获得的,它输出 160 位 -- en.wikipedia.org/wiki/SHA-1 重复 tmphash 16 次和哈希 5 次后,你得到一个 2560 位的超级块
  • 你太快了。我查看了 salsa20 并尝试编辑我的评论,因为我知道 sha1 长度,然后在超时之后,我删除了它,然后我看到了你所有的回复。谢谢,这对我来说更清楚了。我不知道 512 是怎么来的。
  • 您可以免费获得每个块的前 160 位,但您也可以计算其余的:异或后续块将给出明文的异或结果,这很容易进行密码分析。一旦你有了它,你就可以确定重复密钥并破译整个消息。这是 vinegere 密码的一种变体。
【解决方案3】:

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

我看到了这条线:

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

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

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

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

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

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

-布莱恩·J·斯蒂纳尔-

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-01
    • 2016-03-24
    • 2014-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多