serpent实现中的truecrypt bug

时间:2014-03-02 00:53:29

标签: truecrypt

我正在浏览TrueCrypt(7.1a)中的Serpent实现,看起来不对劲!以下是此算法的界面:

void serpent_set_key(const unsigned __int8 userKey[], int keylen, unsigned __int8 *ks);
void serpent_encrypt(const unsigned __int8 *inBlock, unsigned __int8 *outBlock, unsigned __int8 *ks);
void serpent_decrypt(const unsigned __int8 *inBlock,  unsigned __int8 *outBlock, unsigned __int8 *ks);

这里感兴趣的功能是serpent_set_key。用户密钥长度为32个字节,keylen应为其大小,ks是用于加密/解密的输出密钥。问题是实施。这是开头的相关片段:

unsigned __int32 a,b,c,d,e;
unsigned __int32 *k = (unsigned __int32 *)ks;
unsigned __int32 t;
int i;

for (i = 0; i < keylen / (int)sizeof(__int32); i++)
    k[i] = LE32(((unsigned __int32*)userKey)[i]);

for循环实际上是将数据从用户密钥复制到实现密钥。它通过将数据“查看”为4字节整数来完成。现在,如果密钥len以字节形式发送(32是正确的值)但是......

,则一切正常

在trueCrypt的所有实现中,都会在两个地方调用它。这是第一个: 在CipherInit中调用如下:

case SERPENT:
    serpent_set_key (key, CipherGetKeySize(SERPENT) * 8, ks);
    break;

CipherGetKeySize(SERPENT)将返回32(字节),因此传入的参数将具有256的值!这是正确的,因为关键的长度,但不是这个实现!这将导致'serpent_set_key'中的缓冲区溢出,因为for循环将运行64次而不是8次! 调用它的另一个地方是EAInit,如下所示:

serpent_set_key(key,32 * 8,ks);

很明显,传入的参数将是256.

我很好奇其他人对此的看法?其他人可以确认这个错误吗?

1 个答案:

答案 0 :(得分:3)

作为VeraCrypt的主要开发人员,由于VeraCrypt基于TrueCrypt源,因此用户已将我重定向到此帖子。

在研究了你提出的问题之后,我可以确认这确实是代码中的错误,并且对serpent_set_key的调用应该传递32而不是256作为参数。

幸运,这个错误对程序执行过程中的正确性或安全性没有影响,这就是没有人在你之前发现它的原因。因此,我们不能将此视为错误。

让我用三点来解释:

  1. 让我们看一下serpent_set_key的Serpent算法实现:参数keylen仅用于将用户密钥复制到保证<{1}}缓冲区中/ strong>最小尺寸 560 (查看crypt.h中的ks定义)。因此,即使SERPENT_KS是256而不是32,我们也永远不会超出分配的keylen内存。
  2. 此循环之后的内部密钥扩展将使用仅用户密钥的前32个字节来构建扩展的Serpent密钥,如Serpent算法规范中所示。因此,在前32个之后的所有字节将被丢弃,并且它们将永远不会被使用。这解释了为什么即使传递256个字节而不是预期的32个字节,计算结果也是正确的。
  3. 如果我们将所有运行时调用列为ks的引导,我们会注意到,除了自动测试的情况之外,所有调用都使用256字节缓冲区作为userKey参数,即使它是第一个填充32个字节(在crypto.h中查看serpent_set_key)。因此,在运行时,我们永远不会超出分配缓冲区空间。它仍然是自动测试的例子(在Tests.c中为ei或在Dlgcode.c中为MASTER_KEYDATA_SIZE),其中32字节缓冲区用于userKey:这里我们将读取超出分配的空间但实际上它没有&#39 ; t会造成任何伤害,因为此缓冲区周围的内存是可读的。
  4. 我希望这可以澄清为什么这个错误是无害的。话虽如此,它必须得到纠正,这是我们在VeraCrypt中所做的事情。

    对于记录,似乎这个错误是由CipherTestDialogProctwofish_set_key之间的混淆引起的:两个函数的声明具有相同类型的参数,但serpent_set_key期望用户密钥长度(以位为单位),而twofish_set_key则以字节为单位!显然,我们应该对密钥的大小采用相同的约定。