Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Тема
Описание
Доп.

Экосистема crates под названием RustCrypto

Хэширование

  • sha2, sha3 — SHA-2 / SHA-3 семейства.
  • blake2, blake3 — быстрые криптографические хэши.

Симметричное шифрование

  • aes — AES-128/192/256.
  • chacha20 — ChaCha20 потоковый шифр.
  • cipher — общий трейт для блочных/потоковых шифров.

Асимметричное шифрование и подписи

  • rsa — работа с RSA.
  • ed25519-dalek — подписи Ed25519.
  • p256, k256 — эллиптические кривые NIST P-256 и secp256k1 (биткоин).

Форматы и протоколы

  • password-hash — работа с паролями (Argon2, scrypt, PBKDF2).
  • jwt / jsonwebtoken — JSON Web Tokens.
  • tlsrustls (TLS-библиотека на чистом Rust, замена OpenSSL).

Если нужно просто использовать шифрование, подписи, хэши без глубокого погружения в детали:

  • ring

    • Надёжная и быстрая библиотека, обёртка над проверенными реализациями C/ASM.
    • Поддержка AES, ChaCha20, RSA, Ed25519, HMAC, HKDF, SHA-2, SHA-3.
    • Часто используется в веб-серверах (например, hyper, jsonwebtoken).
  • age

    • Удобное шифрование файлов, альтернатива GPG.

Хэширование

Зачем нужно

  • Проверка целостности данных (например, сравнение скачанного файла с контрольной суммой).
  • Хранение паролей (не хранить пароль напрямую, а хранить его хэш).
  • Быстрая идентификация данных (ключи в структурах, fingerprint документов).

Как работает

  • На вход подаются данные любого размера.
  • Алгоритм выдаёт фиксированное "отпечаток" (обычно 256 или 512 бит).
  • Хэш необратим: нельзя восстановить исходные данные из хэша.
  • Малое изменение входных данных → полностью другой хэш.

Примеры алгоритмов: SHA-2, SHA-3, BLAKE2, BLAKE3.


Симметричное шифрование

Зачем нужно

  • Для защиты данных, когда отправитель и получатель знают общий секретный ключ.
  • Например: зашифровать файл, базу данных, сообщение в мессенджере.

Как работает

  • Один и тот же ключ используется и для шифрования, и для расшифровки.
  • Быстрое и эффективное, подходит для больших объёмов данных.
  • Проблема: как безопасно передать ключ получателю.

Примеры алгоритмов: AES, ChaCha20, часто с режимами аутентификации (AES-GCM, ChaCha20-Poly1305).


3. Асимметричное шифрование и подписи

Зачем нужно

  • Для защиты, когда нет общего секрета заранее.
  • Для цифровых подписей (доказательство, что сообщение пришло от конкретного отправителя).
  • Для безопасной передачи симметричных ключей.

Как работает

  • Есть пара ключей:

    • публичный ключ (можно распространять всем),
    • приватный ключ (хранится в секрете).
  • Шифрование:

    • сообщение зашифровано публичным ключом → расшифровать может только владелец приватного.
  • Подпись:

    • сообщение подписывается приватным ключом → проверить может любой с публичным ключом.

Примеры алгоритмов:

  • RSA
  • ECC (эллиптические кривые: Ed25519, secp256k1, P-256)

Как они используются вместе

На практике криптография обычно комбинируется:

  1. Хэширование → хранение паролей, проверка целостности.
  2. Симметричное шифрование → быстрое шифрование данных.
  3. Асимметричное шифрование → обмен ключами для симметричного шифра + подписи.

Пример: HTTPS/TLS

  • Клиент и сервер договариваются о симметричном ключе через асимметричную криптографию (RSA/ECDH).
  • Затем весь трафик шифруется симметрично (AES, ChaCha20).
  • Сертификаты подписаны центром сертификации → проверка подлинности через подписи.

Практические сценарии

  • Хранение паролей: argon2, bcrypt, scrypt.
  • Подписи: ed25519-dalek, rsa, p256.
  • Шифрование файлов: aes-gcm, chacha20poly1305, age.
  • Сеть (TLS, HTTPS): rustls вместо OpenSSL.
  • Хэширование: sha2, blake3.

Пример (хэш пароля с Argon2)


use argon2::{self, Config};

fn main() {
    let password = b"super_secret";
    let salt = b"random_salt";

    // Хэшируем пароль
    let config = Config::default();
    let hash = argon2::hash_encoded(password, salt, &config).unwrap();

    println!("Хэш пароля: {}", hash);

    // Проверяем пароль
    let is_valid = argon2::verify_encoded(&hash, password).unwrap();
    println!("Пароль верный? {}", is_valid);
}

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

crate subtle

Атака на время

Для сравнения с постоянным временем в Rust рассмотрите возможность использования crate subtle от dalek

Реализуйте следующие функции:

  • generate_password(): генерирует случайный пароль заданной длины и набора символов;
  • select_rand_val(): извлекает случайный элемент из заданного среза;
  • get_file_hash(): возвращает хэш SHA-3 файла, указанного в его пути.
  • hash_password(): возвращает хэш пароля Argon2 для данного пароля.
  • new_access_token(): генерирует уникальное криптографически безопасное случайное значение в a-zA-Z0-9наборе символов и содержит точно 64символы.

use std::path::PathBuf;

use rand::{
    distributions::Alphanumeric,
    seq::{IteratorRandom, SliceRandom},
    Rng, SeedableRng,
};
use rand_chacha::ChaCha8Rng;
use sha3::{Digest, Sha3_256};

fn generate_password<'a>(elements: impl Into<&'a str>, len: usize) -> String {
    let mut rng = rand::thread_rng();

    elements
        .into()
        .chars()
        .choose_multiple(&mut rng, len)
        .to_vec()
        .into_iter()
        .collect()
}

fn select_rand_val(slice: &[T]) -> Option<&T> {
    let mut rng = rand::thread_rng();
    slice.choose(&mut rng)
}

fn new_access_token() -> String {
    let mut rng = ChaCha8Rng::from_entropy();
    (0..64).map(|_| rng.sample(Alphanumeric)).collect()
}

fn get_file_hash(path: impl Into) -> Option> {
    let str = std::fs::read_to_string(path.into()).ok()?;
    let hash = Sha3_256::digest(str.as_bytes()).to_vec();
    Some(hash)
}

fn hash_password<'a>(password: impl Into<&'a str>) -> String {
    let mut hasher = argonautica::Hasher::default();
    hasher
        .with_password(password.into())
        .opt_out_of_secret_key(true)
        .hash()
        .unwrap()
}

fn main() {
    println!("{}", generate_password("abcd", 5));
    println!("{}", select_rand_val(&[1, 2, 3, 4]).unwrap());
    println!("{}", new_access_token());
    println!("{}", hash_password("password"));

    let mut path = std::env::current_dir().unwrap();
    path.push("README.md");
    dbg!(get_file_hash(path).unwrap());
}