Криптография в Rust: шифрование и хеширование с ring и sha2

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Криптография в Rust: шифрование и хеширование с библиотеками ring и sha2

Rust — это системный язык программирования, который обеспечивает безопасность памяти и производительность, сравнимую с C/C++. Благодаря своей строгой системе типов и модели владения, Rust идеально подходит для реализации криптографических алгоритмов, где ошибки могут привести к серьёзным уязвимостям. В этой статье мы рассмотрим, как использовать популярные библиотеки ring и sha2 для выполнения базовых криптографических операций: симметричного шифрования, хеширования и вычисления HMAC.

Библиотека ring: универсальный инструмент для криптографии

Библиотека ring — это одна из самых популярных криптографических библиотек для Rust. Она предоставляет безопасные реализации многих алгоритмов, включая AES-GCM для шифрования, SHA-256 для хеширования и HMAC для аутентификации сообщений. ring написана на Rust и C, что обеспечивает высокую производительность и безопасность.

Для начала работы добавьте зависимость в ваш Cargo.toml:

[dependencies]
ring = "0.17"

Симметричное шифрование с AES-GCM

AES-GCM (Galois/Counter Mode) — это режим шифрования, который обеспечивает как конфиденциальность, так и аутентификацию данных. Он широко используется в современных протоколах, таких как TLS.

Пример шифрования и дешифрования строки с помощью ring:

use ring::aead::{Aad, LessSafeKey, Nonce, UnboundKey, AES_256_GCM};
use ring::error::Unspecified;
use ring::rand::{SecureRandom, SystemRandom};

fn encrypt(plaintext: &[u8], key: &[u8; 32]) -> Result<Vec<u8>, Unspecified> {
    let rng = SystemRandom::new();
    let unbound_key = UnboundKey::new(&AES_256_GCM, key)?;
    let key = LessSafeKey::new(unbound_key);

    // Генерация случайного nonce (12 байт)
    let mut nonce_bytes = [0u8; 12];
    rng.fill(&mut nonce_bytes)?;
    let nonce = Nonce::assume_unique_for_key(nonce_bytes);

    // Буфер для зашифрованных данных + тег аутентификации
    let mut in_out = plaintext.to_vec();
    key.seal_in_place_append_tag(nonce, Aad::empty(), &mut in_out)?;

    // Возвращаем nonce + зашифрованные данные
    let mut result = nonce_bytes.to_vec();
    result.extend_from_slice(&in_out);
    Ok(result)
}

fn decrypt(ciphertext: &[u8], key: &[u8; 32]) -> Result<Vec<u8>, Unspecified> {
    let unbound_key = UnboundKey::new(&AES_256_GCM, key)?;
    let key = LessSafeKey::new(unbound_key);

    // Извлекаем nonce (первые 12 байт)
    let (nonce_bytes, encrypted) = ciphertext.split_at(12);
    let nonce = Nonce::assume_unique_for_key(nonce_bytes.try_into().unwrap());

    let mut in_out = encrypted.to_vec();
    let plaintext = key.open_in_place(nonce, Aad::empty(), &mut in_out)?;
    Ok(plaintext.to_vec())
}

fn main() {
    let key = b"01234567890123456789012345678901"; // 32 байта для AES-256
    let data = b"Секретное сообщение";

    let encrypted = encrypt(data, key).unwrap();
    println!("Зашифровано: {:?}", encrypted);

    let decrypted = decrypt(&encrypted, key).unwrap();
    println!("Расшифровано: {}", String::from_utf8(decrypted).unwrap());
}

Этот код демонстрирует полный цикл шифрования: генерацию случайного nonce, шифрование с тегом аутентификации и последующее дешифрование. Обратите внимание, что nonce должен быть уникальным для каждого шифрования с одним и тем же ключом.

Хеширование с библиотекой sha2

Библиотека sha2 предоставляет реализации алгоритмов семейства SHA-2, включая SHA-256, SHA-384 и SHA-512. Хеширование используется для проверки целостности данных, хранения паролей и создания цифровых подписей.

Добавьте зависимость:

[dependencies]
sha2 = "0.10"

Пример хеширования строки с SHA-256:

use sha2::{Sha256, Digest};

fn hash_string(input: &str) -> String {
    let mut hasher = Sha256::new();
    hasher.update(input.as_bytes());
    let result = hasher.finalize();
    format!("{:x}", result)
}

fn main() {
    let data = "Привет, мир!";
    let hash = hash_string(data);
    println!("SHA-256 хеш: {}", hash);
    // Вывод: SHA-256 хеш: 3f7c6b9b8c8e5a3d0b2f1c4e8a9d6b7                    

Рекомендаций