ошибка truecrypt в реализации serpent

Я просматривал реализацию Serpent в TrueCrypt (7.1a) и что-то не так! Вот интерфейс этого алгоритма:

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(ключ, 32*8, кс);

Здесь очевидно, что в параметре будет передано значение 256.

Мне интересно, что другие люди думают об этом? Кто-нибудь еще может подтвердить этот баг?


person user3369634    schedule 02.03.2014    source источник
comment
TL;DR – truecrypt.org/bugs   -  person CBroe    schedule 02.03.2014


Ответы (1)


Как главный разработчик VeraCrypt, пользователь перенаправил меня на этот пост, так как VeraCrypt основан на исходном коде TrueCrypt.

Изучив вопрос, который вы подняли, я могу подтвердить, что это действительно ошибка в коде и что вызовы serpent_set_key должны передавать 32 вместо 256 в качестве параметра.

К счастью, эта ошибка никак не влияет на корректность или безопасность при выполнении программы, поэтому никто не обнаружил ее до вас. Таким образом, мы НЕ можем квалифицировать это как ошибку.

Позвольте мне объяснить это в трех пунктах:

  1. давайте посмотрим на реализацию алгоритма Serpent serpent_set_key : параметр keylen используется только для копирования ключа пользователя в буфер ks, который гарантированно имеет минимальный размер 560 (см. в SERPENT_KS определить в crypt.h). Таким образом, даже если keylen равно 256 вместо 32, мы никогда не будем писать за пределами выделенной памяти ks.
  2. расширение внутреннего ключа, которое следует после этого цикла, создаст расширенный ключ Serpent, используя только первые 32 байта userKey, как в спецификации алгоритма Serpent. Таким образом, все байты, идущие после первых 32, будут отброшены и никогда не будут использованы. Это объясняет, почему результат вычисления правильный, даже если ему передано 256 байт вместо ожидаемых 32 байт.
  3. если мы перечислим все вызовы среды выполнения, ведущие к serpent_set_key, мы заметим, что, за исключением случая автотестов, все вызовы используют 256-байтовый буфер для параметра userKey, даже если его первые 32 байта заполнены (см. MASTER_KEYDATA_SIZE в крипто.h). Таким образом, во время выполнения мы никогда не будем читать за пределами выделенного буферного пространства. Остается случай автотестов (например, в Tests.c или CipherTestDialogProc в Dlgcode.c), где для userKey используется 32-байтовый буфер: здесь мы будем читать за пределами выделенного пространства, но на практике это не причиняет никакого вреда, потому что память вокруг этого буфера доступна для чтения.

Я надеюсь, что это проясняет, почему эта ошибка безвредна. При этом его нужно исправить, и это то, что мы будем делать в VeraCrypt.

Для справки, похоже, что эта ошибка была вызвана путаницей между twofish_set_key и serpent_set_key : объявление двух функций имеет одинаковый тип параметров, но twofish_set_key ожидает длину пользовательского ключа в битах, тогда как serpent_set_key ожидает ее в байтах! Очевидно, у нас должно быть такое же соглашение для размера ключа.

person Mounir IDRASSI    schedule 27.09.2014
comment
OK Я согласен, что эта проблема не влияет на нормальную работу программы, однако это как минимум ошибка в чистой реализации алгоритма! - person user3369634; 27.09.2014
comment
Я передал это исправление в VeraCrypt (sourceforge.net/p/veracrypt/code /ci/). На самом деле, поскольку мы используем только ключи фиксированного размера (256 бит), я полностью удалил параметр длины ключа, что решает проблему, но также минимизирует размер кода, который очень важен для загрузчика (мы изо всех сил пытаемся сделать его как можно меньше в чтобы иметь возможность добавлять новые функции). - person Mounir IDRASSI; 28.09.2014