cryptsetup backend безопасно с многопоточностью?
Существует ли крипто-бэкенд для cryptsetup, который либо всегда безопасен для потоков, либо может быть легко использован (или даже изменен, предпочтительно с минимальными усилиями) безопасным для потоков способом для простой проверки правильности ключа?
Предыстория и что я пробовал:
Я начал с тестирования, могу ли я изменить источник cryptsetup, чтобы просто протестировать несколько ключей с помощью pthreads. Это сбой, я думаю, что я использовал gcrypt изначально. В конце концов я попробовал все бэкэнды, доступные в стабильном исходном тексте cryptsetup, и обнаружил, что openssl и nettle, похоже, избегают сбоев.
Однако мое тестирование было не очень тщательным, и, хотя оно (особенно крапива) не дает сбоя, кажется, что оно не работает правильно при использовании потоков. При использовании одного потока он всегда работает, но увеличение количества потоков повышает вероятность того, что он никогда не найдет правильный ключ.
Это для перебора устройств LUKS. Я знаю, что pbkdf замедляет его сканирование. Я также знаю, что ключевое пространство AES не может быть исчерпано, даже если KDF там не было. Это просто для удовольствия сделать его распределенным и многопоточным.
Я заметил в источнике cryptsetup (libdevmapper.c):
/*
* libdevmapper is not context friendly, switch context on every DM call.
* FIXME: this is not safe if called in parallel but neither is DM lib.
*/
Однако, возможно, я просто не правильно его использую.
if(!LUKS_open_key_with_hdr(CRYPT_ANY_SLOT, key, strlen(key), &cd->u.luks1.hdr, &vk, cd)) {
return 0;
}
Каждый рабочий поток делает это. Я вызываю crypt_init() и crypt_load() только один раз перед запуском рабочих потоков и передаю им свою отдельную копию struct crypt_device. vk создается локально для каждой попытки. Ключи просто выбираются из списка слов с контролем доступа мьютексом. Я обнаружил, что если каждый поток вызывает эти функции (crypt_init и crypt_load) каждый раз, кажется, что происходит сбой.
Совершенно неправильно пытаться начать удалять и переписывать код, который использует dmcrypt? В LUKS_endec_template() он присоединяет устройство петли к устройству шифрования и создает устройство dm, которое оно в конечном итоге дает open(), которое затем передает fd для read_blockwise(). Моя идея состояла в том, чтобы просто пропустить все это, поскольку мне не нужно использовать устройство, кроме как для проверки ключа. Однако простое открытие устройства шифрования напрямую (и передача его read_blockwise()) не работает.