Kryptografie in Rust: Verschlüsselung und Hashing mit den Bibliotheken ring und sha2

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Kryptografie in Rust: Verschlüsselung und Hashing mit den Bibliotheken ring und sha2



Rust ist eine systemnahe Programmiersprache, die Speichersicherheit und hohe Leistung garantiert. Dank dieser Eigenschaften eignet sie sich ideal für kryptografische Aufgaben. In diesem Artikel betrachten wir zwei beliebte Bibliotheken: ring (für symmetrische Verschlüsselung und Hashing) und sha2 (für reines Hashing). Sie erfahren, wie Sie Daten mit AES-GCM verschlüsseln, SHA-256-Hashes berechnen und HMAC-Signaturen erstellen.



Warum Rust für Kryptografie?

Rust eliminiert ganze Klassen von Schwachstellen (Pufferüberläufe, Datenrennen) bereits zur Kompilierzeit. Kryptografische Bibliotheken in Rust wie ring sind in Assembler und C mit sicheren Wrappern geschrieben, was eine mit C vergleichbare Geschwindigkeit bei gleichzeitiger Zuverlässigkeit von Rust bietet.



Projekt einrichten

Erstellen Sie ein neues Projekt und fügen Sie die Abhängigkeiten in Cargo.toml hinzu:

[dependencies]ring = "0.17"sha2 = "0.10"hex = "0.4"  # für bequeme Anzeige von Bytes


Symmetrische Verschlüsselung: AES-GCM mit ring

AES-GCM (Galois/Counter Mode) ist ein moderner Standard für symmetrische Verschlüsselung, der sowohl Vertraulichkeit als auch Authentifizierung (Integritätsprüfung) bietet. Die Bibliothek ring stellt eine einfache und sichere API bereit.



Daten verschlüsseln

Für die Verschlüsselung werden benötigt: ein Schlüssel (256 Bit), eine Nonce (96 Bit) und der Klartext. Die Nonce muss für jede Verschlüsselung mit demselben Schlüssel eindeutig sein.

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

fn encrypt_aes_gcm(key: &[u8; 32], plaintext: &[u8]) -> Vec<u8> { let rng = SystemRandom::new(); let unbound_key = UnboundKey::new(&AES_256_GCM, key).unwrap(); let key = LessSafeKey::new(unbound_key);

// Zufällige Nonce generieren let mut nonce_bytes = [0u8; 12]; rng.fill(&mut nonce_bytes).unwrap(); let nonce = Nonce::assume_unique_for_key(nonce_bytes);

// Verschlüsselung mit leeren Zusatzdaten (AAD) let mut in_out = plaintext.to_vec(); let tag = key.seal_in_place_separate_tag(nonce, Aad::empty(), &mut in_out).unwrap(); // Nonce + verschlüsselte Daten + Authentifizierungstag zurückgeben let mut result = nonce_bytes.to_vec(); result.extend_from_slice(&in_out); result.extend_from_slice(tag.as_ref()); result}


Entschlüsselung

Zur Entschlüsselung extrahieren wir Nonce, Tag und den verschlüsselten Text und rufen dann open_in_place auf.

fn decrypt_aes_gcm(key: &[u8; 32], ciphertext: &[u8]) -> Option<Vec<u8>> {    if ciphertext.len() < 28 { return None; } // 12 (Nonce) + 16 (Tag) Minimum

let (nonce_bytes, rest) = ciphertext.split_at(12); let (encrypted, tag_bytes) = rest.split_at(rest.len() - 16); let nonce = Nonce::assume_unique_for_key(*nonce_bytes); let unbound_key = UnboundKey::new(&AES_256_GCM, key).unwrap(); let key = LessSafeKey::new(unbound_key);

let mut in_out = encrypted.to_vec(); in_out.extend_from_slice(tag_bytes); // ring erwartet den Tag am Ende match key.open_in_place(nonce, Aad::empty(), &mut in_out) { Ok(plaintext) => { let plain_len = plaintext.len(); Some(plaintext[..plain_len].to_vec()) }, Err(_) => None // falscher Schlüssel oder beschädigte Daten }}


Anwendungsbeispiel

fn main() {    let key = b"0123456789abcdef0123456789abcdef"; // 32 Bytes    let data = b"Geheime Nachricht für Rust!";        let encrypted = encrypt_aes_gcm(key, data);    println!("Verschlüsselt (hex): {}", hex::encode(&encrypted));        if let Some(decrypted) = decrypt_aes_gcm(key, &encrypted) {        println!("Entschlüsselt: {}", String::from_utf8(decrypted).unwrap())                    

Empfehlungen