Я просматривал реализацию 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.
Мне интересно, что другие люди думают об этом? Кто-нибудь еще может подтвердить этот баг?