Библиотека RustCrypto: симметричное и асимметричное шифрование

от автора

Привет, Хабр!

Сегодня рассмотрим такую библиотеку в 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 лежит математика с использованием больших простых чисел. Сначала выбираются два случайных простых числа, которые перемножаются для получения модуля n. Публичный ключ состоит из модуля n и экспоненты e, а приватный ключ включает модули n и экспоненту d, получаемую из e и произведения (p-1)*(q-1).

  • Шифрование: Сообщение преобразуется в число, которое возводится в степень 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *