Курс — Хакинг на Rust. #26 Инструменты хакера на Rust. Криптоанализ и безопасность. Пример: Подбор ключей с использованием многопоточности
Здравствуйте, дорогие друзья.
Подбор ключей методом brute-force — ресурсоёмкая задача, требующая проверки триллионов комбинаций. Rust, благодаря нулевой стоимости абстракций и эффективному управлению памятью, идеально подходит для реализации высокопроизводительных многопоточных атак. В этом разделе мы рассмотрим, как использовать многопоточность для ускорения перебора ключей.
8.3.1. Почему многопоточность критична?
Однопоточный brute-force неэффективен:
- Современные CPU имеют 8–16 ядер, которые можно загрузить параллельно.
- Криптографические операции (например, AES) требуют значительных вычислительных ресурсов.
Rust позволяет безопасно распределить нагрузку между потоками без риска data races.
8.3.2. Пример 1: Базовый brute-force (однопоточный)
Предположим, мы хотим подобрать 4-байтный ключ для XOR-шифра:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
fn xor_decrypt(data: &[u8], key: u32) -> Vec<u8> { data.iter().enumerate().map(|(i, &b)| b ^ ((key >> (8 * (3 - i % 4))) & 0xFF) as u8).collect() } fn single_thread_brute_force(ciphertext: &[u8]) -> Option<u32> { for key in 0..=u32::MAX { let decrypted = xor_decrypt(ciphertext, key); if is_plaintext_valid(&decrypted) { return Some(key); } } None } |
Этот код проверяет все 4 294 967 296 возможных ключей. На CPU с тактовой частотой 3 GHz это займёт ~1.4 секунды (при условии 1 цикл на ключ), но реальное время будет больше из-за сложности is_plaintext_valid
.
8.3.3. Многопоточный brute-force с Rayon
Crate rayon
позволяет легко распараллелить итераторы:
1 2 3 4 5 6 7 8 |
use rayon::prelude::*; fn parallel_brute_force(ciphertext: &[u8]) -> Option<u32> { (0..=u32::MAX).into_par_iter().find_any(|&key| { let decrypted = xor_decrypt(ciphertext, key); is_plaintext_valid(&decrypted) }) } |
Как это работает :
into_par_iter()
преобразует диапазон в параллельный итератор.find_any()
останавливает все потоки при нахождении ключа.
Результат :
- На 8 ядрах время уменьшится примерно в 8 раз.
8.3.4. Оптимизация: Разделение пространства ключей
Для больших ключей (например, 64 бита) u64::MAX
не помещается в память. Решение: разбить диапазон на части:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
use rayon::prelude::*; fn parallel_brute_force_optimized(ciphertext: &[u8]) -> Option<u64> { let chunk_size = 1 << 24; // 16 млн ключей на поток (0..u64::MAX).step_by(chunk_size).into_par_iter() .find_map_any(|start| { let end = start + chunk_size; (start..end).find(|&key| { let decrypted = xor_decrypt(ciphertext, key); is_plaintext_valid(&decrypted) }) }) } |
Преимущества :
- Уменьшает накладные расходы на управление потоками.
- Позволяет обрабатывать ключи произвольной длины.
8.3.5. Пример 2: Подбор AES-ключа
AES-128 имеет 16-байтный ключ (128 бит), что делает полный перебор невозможным. Но если ключ слабый (например, содержит повторяющиеся байты), можно оптимизировать атаку:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
use aes::Aes128; use block_modes::{BlockMode, Ecb}; use block_modes::block_padding::Pkcs7; use rayon::prelude::*; type AesEcb = Ecb<Aes128, Pkcs7>; fn crack_aes_ecb(ciphertext: &[u8], known_plaintext: &[u8]) -> Option<[u8; 16]> { // Генерируем ключи с повторяющимися байтами (паттерн "AABBCCDDEEFF...") let patterns = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]; patterns.into_par_iter().find_map(|pattern| { let key = [pattern; 16]; let cipher = AesEcb::new_from_slices(&key, Default::default()).unwrap(); if let Ok(plaintext) = cipher.decrypt_vec(ciphertext) { if plaintext.starts_with(known_plaintext) { Some(key) } else { None } } else { None } }) } |
Этот код проверяет ключи с повторяющимися байтами, что сокращает пространство перебора.
8.3.6. Инструменты для ускорения
- SIMD-инструкции :
Используйте cratepacked_simd
для векторизации операций XOR или AES. - GPU-ускорение :
Через craterust_cuda
или OpenCL. - Оптимизация кода :
- Избегайте аллокаций внутри циклов.
- Используйте битовые маски для фильтрации ключей.
8.3.7. Этический аспект
Используйте многопоточные атаки только в легальных сценариях:
- Аудит собственных систем.
- Участие в CTF-соревнованиях.
- Обучение в тестовой среде.
Задачи для самостоятельного решения :
- Реализуйте brute-force для 8-символьного пароля (латиница + цифры).
- Добавьте поддержку GPU в пример с XOR-шифром.
- Сравните скорость однопоточной и многопоточной версий.
Вывод : Многопоточность в Rust позволяет эффективно использовать ресурсы CPU для криптоанализа. Однако даже с ней brute-force остаётся непрактичным для современных ключей длиной 128+ бит. Используйте эти знания для защиты своих систем, а не их взлома.

На этом все. Всем хорошего дня!