Привет, Хабр!
Сегодня рассмотрим такую библиотеку в Rust, как RustCrypto. RustCrypto — это набор библиотек, реализующих различные криптографические алгоритмы, такие как AES, RSA, SHA, и многие другие.
Симметричное шифрование AES
AES — это стандарт симметричного шифрования, принятый в качестве стандарта федерального правительства США в 2001 году.AES поддерживает различные длины ключей, и на сегодняшний день является одним из самых используемых стандартов.
Чтобы приступить к работе с AES в Rust, необходимо установить соответствующие библиотеки RustCrypto. Для этого открываем файл Cargo.toml и добавляем следующие зависимости:
[dependencies] aes = "0.7" aes-gcm = "0.10" # для работы с режимом GCM rand = "0.8" # для генерации случайных значений
Начнем с того, как зашифровать текстовые данные с помощью AES-256-GCM:
use aes_gcm::aead::{Aead, KeyInit, OsRng}; use aes_gcm::{Aes256Gcm, Nonce}; // AES-256-GCM use rand::Rng; fn encrypt_data(plaintext: &[u8], key: &[u8]) -> Vec<u8> { // создаем шифратор с ключом let cipher = Aes256Gcm::new(key.into()); // генерируем случайный nonce let nonce = Nonce::from_slice(&rand::thread_rng().gen::<[u8; 12]>()); // шифруем данные let ciphertext = cipher.encrypt(nonce, plaintext) .expect("Ошибка шифрования!"); // возвращаем зашифрованные данные и nonce [nonce.as_slice(), &ciphertext].concat() } fn main() { // пример открытого текста let plaintext = b"Привет, Хабр! Это секретное сообщение."; // генерируем ключ let key = rand::thread_rng().gen::<[u8; 32]>(); // 256-битный ключ // шифруем данные let ciphertext = encrypt_data(plaintext, &key); println!("Зашифрованные данные: {:?}", ciphertext); }
После шифрования данных, следующий шаг – дешифрование:
use aes_gcm::aead::{Aead, KeyInit}; use aes_gcm::{Aes256Gcm, Nonce}; fn decrypt_data(ciphertext: &[u8], key: &[u8]) -> Vec<u8> { // создаем дешифратор с ключом let cipher = Aes256Gcm::new(key.into()); // извлекаем nonce (первые 12 байт) let nonce = Nonce::from_slice(&ciphertext[..12]); // извлекаем зашифрованные данные let ciphertext = &ciphertext[12..]; // дешифруем данные let plaintext = cipher.decrypt(nonce, ciphertext) .expect("Ошибка дешифрования!"); plaintext } fn main() { // пример зашифрованных данных let ciphertext = vec![/* ваши зашифрованные данные */]; // используем ранее сгенерированный ключ let key = [/* ваш 256-битный ключ */]; // дешифруем данные let plaintext = decrypt_data(&ciphertext, &key); println!("Дешифрованные данные: {:?}", String::from_utf8_lossy(&plaintext)); }
Необходимо убедиться, что ключи хранятся в защищенном месте и недоступны для посторонних. В Rust, генерация ключей может быть выполнена с помощью либы rand:
use rand::Rng; fn generate_key() -> [u8; 32] { rand::thread_rng().gen::<[u8; 32]>() // генерируем 256-битный ключ } fn main() { let key = generate_key(); println!("Сгенерированный ключ: {:?}", key); }
Асимметричное шифрование
Асимметричное шифрование использует пару ключей: публичный ключ для шифрования данных и приватный ключ для их расшифровки. Основная фича заключается в том, что данные, зашифрованные публичным ключом, могут быть расшифрованы только соответствующим приватным ключом, и наоборот.
RSA — это один из самых известных и алгоритмов асимметричного шифрования. Рассмотрим его реализую в RustCrypto.
Принципы работы RSA:
-
Генерация ключей: В основе RSA лежит математика с использованием больших простых чисел. Сначала выбираются два случайных простых числа, которые перемножаются для получения модуля
. Публичный ключ состоит из модуля
и экспоненты
, а приватный ключ включает модули
и экспоненту
, получаемую из
и произведения
.
-
Шифрование: Сообщение преобразуется в число, которое возводится в степень
eи берётся по модулюn, чтобы получить зашифрованное сообщение. -
Дешифрование: Зашифрованное сообщение возводится в степень
dи берется по модулюnдля получения оригинального сообщения.
Для того чтобы начать работу с RSA в Rust, понадобится библиотека rsa, которая входит в состав RustCrypto.
Откроем файл Cargo.toml и добавим:
[dependencies] rsa = "0.6.0" # версия библиотеки RSA rand = "0.8" # для генерации случайных чисел
Начнем с генерации пары ключей:
use rsa::{RsaPrivateKey, RsaPublicKey, PaddingScheme}; use rand::rngs::OsRng; // используем надежный генератор случайных чисел fn generate_keys() -> (RsaPrivateKey, RsaPublicKey) { // генерируем 2048-битный приватный ключ let mut rng = OsRng; let private_key = RsaPrivateKey::new(&mut rng, 2048) .expect("Ошибка генерации ключа"); // получаем публичный ключ из приватного let public_key = RsaPublicKey::from(&private_key); (private_key, public_key) }
Теперь зашифруем некоторые данные с использованием публичного ключа:
fn encrypt_message(public_key: &RsaPublicKey, message: &[u8]) -> Vec<u8> { let mut rng = OsRng; let padding = PaddingScheme::new_pkcs1v15_encrypt(); // используем PKCS1 v1.5 для шифрования // шифруем сообщение public_key .encrypt(&mut rng, padding, message) .expect("Ошибка шифрования") } fn main() { // генерируем ключи let (private_key, public_key) = generate_keys(); // исходное сообщение let message = b"Привет, Хабр!"; // зашифровываем сообщение let encrypted_data = encrypt_message(&public_key, message); println!("Зашифрованное сообщение: {:?}", encrypted_data); }
Теперь расшифруем данные с использованием приватного ключа:
fn decrypt_message(private_key: &RsaPrivateKey, encrypted_data: &[u8]) -> Vec<u8> { let padding = PaddingScheme::new_pkcs1v15_encrypt(); // дешифруем сообщение private_key .decrypt(padding, encrypted_data) .expect("Ошибка дешифрования") } fn main() { // генерируем ключи let (private_key, public_key) = generate_keys(); // исходное сообщение let message = b"Привет, Хабр!"; // зашифровываем сообщение let encrypted_data = encrypt_message(&public_key, message); // дешифровываем сообщение let decrypted_data = decrypt_message(&private_key, &encrypted_data); println!("Расшифрованное сообщение: {:?}", String::from_utf8_lossy(&decrypted_data)); }
Симметричное и асимметричное шифрование имеют свои особенности и подходят для разных задач.
|
Особенность |
Симметричное шифрование |
Асимметричное шифрование |
|---|---|---|
|
Ключи |
Один ключ для шифрования и дешифрования |
Два ключа: публичный для шифрования, приватный для дешифрования |
|
Скорость |
Быстрее |
Медленнее |
|
Использование |
Шифрование данных, где важна скорость |
Обмен ключами, цифровые подписи |
|
Управление ключами |
Требует безопасного обмена ключами |
Не требует обмена приватным ключом |
|
Целостность и аутентификация |
Дополнительные механизмы, например, HMAC |
Цифровые подписи встроены |
HMAC
HMAC— это криптографический механизм, используемый для проверки целостности и аутентификации сообщений. HMAC строится на основе хэш-функций и симметричного ключа, обеспечивая защиту от атак, таких как подмена данных. В
Чтобы начать работу с HMAC, добавляем следующие зависимости в Cargo.toml:
[dependencies] hmac = "0.12" # для работы с HMAC sha2 = "0.10" # для хэш-функций SHA-2 rand = "0.8" # для генерации случайных значений
Реализация HMAC с использованием SHA-256:
use hmac::{Hmac, Mac, NewMac}; use sha2::Sha256; // создаем тип HMAC с SHA-256 type HmacSha256 = Hmac<Sha256>; fn create_hmac(key: &[u8], data: &[u8]) -> Vec<u8> { // создаем новый HMAC let mut mac = HmacSha256::new_from_slice(key) .expect("Ошибка создания HMAC"); // пишем данные в HMAC mac.update(data); // финализируем HMAC и извлекаем хеш-код mac.finalize().into_bytes().to_vec() } fn main() { // пример ключа и данных let key = b"секретный_ключ"; let data = b"Привет, Хабр! Это важное сообщение."; // генерируем HMAC let hmac_code = create_hmac(key, data); println!("HMAC: {:?}", hmac_code); }
Проверим целостность сообщения с HMAC:
fn verify_hmac(key: &[u8], data: &[u8], expected_hmac: &[u8]) -> bool { // создаем новый HMAC let mut mac = HmacSha256::new_from_slice(key) .expect("Ошибка создания HMAC"); // пишем данные в HMAC mac.update(data); // пытаемся проверить HMAC mac.verify_slice(expected_hmac).is_ok() } fn main() { // пример ключа и данных let key = b"секретный_ключ"; let data = b"Привет, Хабр! Это важное сообщение."; // генерируем HMAC let hmac_code = create_hmac(key, data); // проверяем целостность данных if verify_hmac(key, data, &hmac_code) { println!("Целостность данных подтверждена!"); } else { println!("Целостность данных нарушена!"); } }
Подробнее о RustCrypto можно узнать здесь.
Больше про все аспекты программирования эксперты OTUS рассказывают в рамках практических онлайн-курсов. С полным каталогом курсов можно ознакомиться по ссылке.
ссылка на оригинал статьи https://habr.com/ru/articles/833714/
Добавить комментарий