我最近在I2P源代码(Java)中发现了以下片段:
private final SessionKey calculateSessionKey(BigInteger myPrivateValue, BigInteger publicPeerValue) {
SessionKey key = new SessionKey();
BigInteger exchangedKey = publicPeerValue.modPow(myPrivateValue, CryptoConstants.elgp);
byte buf[] = exchangedKey.toByteArray();
byte val[] = new byte[32];
if (buf.length < val.length) {
System.arraycopy(buf, 0, val, 0, buf.length);
... //irrelevant details
} else { // (buf.length >= val.length)
System.arraycopy(buf, 0, val, 0, val.length);
... //irrelevant details
}
key.setData(val);
return key;
}
据我所知,buf[]
的前256位被直接复制到会话密钥,并且不会在其上运行SHA256摘要。我不是加密专家(也不是java),任何人都可以解释我,这不是安全漏洞吗?我的意思是,在标准的Diffie-Hellman维基页面中,SHA哈希也在密钥上运行。
如果确实如此,您是否也可以举例说明如何利用它?
答案 0 :(得分:5)
在攻击者可以利用密钥交换的意义上没有“泄漏”,但肯定会丢失熵。因为密钥大小似乎是32字节,这可能不是灾难性的,但我个人在接受这种实现时会遇到很多麻烦。
Diffie-Hellman协议明确指出RFC 2631
必须保留前导零,以便ZZ占用与p一样多的八位字节。
协议的实现中不存在对前导零的保留。
最后,因为设计师决定不填充,所以值重叠:70
,7000
和700000
例如被认为是相同的值,而他们显然不是。
此外,BigInteger.toByteArray()
将返回签名值的双补码编码。这意味着它经常被填充00
个值的字节,即使该值已经与八位字节中的p具有相同的大小。所以密钥的第一个字节很可能是00
。即使不是这样,第一个字节也受到模数的限制,因此第一个字节的值永远不会高于编码p的第一个字节。
更新:我asked on crypto.stackexchange.com看看其余的关键字节是否可以被认为是由一个随机Oracle(一个似乎为外界生成随机字节的确定性函数)生成的,幸运的是they seem to do。这意味着AES密钥中留有足够的熵以防止(强力)攻击AES分组密码。
正如所解释的那样,由于密钥的大小,即使是所有这些缺陷的总和也很难被利用。但绝对可以肯定的是,密钥不会像预期的那样携带256位熵。这对于加密分析师来说足以宣布这个实现被破坏了。当然,使用较小的密钥大小会更糟糕。
注意:所有十六进制值。
答案 1 :(得分:4)
正如owlstead所解释的那样,这不是一个安全漏洞。但 是自I2P开始以来一直存在的错误,我们将修复一个错误。不幸的是,修复此问题所需的更改与我们现有的传输无法向后兼容,因此这将被整合到我们的传输的下一个版本中。
有兴趣的人可以关注这个错误的进展here。