Criptografía en Rust: cifrado y hash con las bibliotecas ring y sha2
Rust es un lenguaje de programación de sistemas que proporciona seguridad de memoria y rendimiento comparable a C/C++. Gracias a su estricto sistema de tipos y modelo de propiedad, Rust es ideal para implementar algoritmos criptográficos, donde los errores pueden provocar vulnerabilidades graves. En este artículo, veremos cómo usar las bibliotecas populares ring y sha2 para realizar operaciones criptográficas básicas: cifrado simétrico, hash y cálculo de HMAC.
Biblioteca ring: herramienta universal para criptografía
La biblioteca ring es una de las bibliotecas criptográficas más populares para Rust. Proporciona implementaciones seguras de muchos algoritmos, incluyendo AES-GCM para cifrado, SHA-256 para hash y HMAC para autenticación de mensajes. ring está escrita en Rust y C, lo que garantiza alto rendimiento y seguridad.
Para empezar, agregue la dependencia en su Cargo.toml:
[dependencies]ring = "0.17"Cifrado simétrico con AES-GCM
AES-GCM (Galois/Counter Mode) es un modo de cifrado que proporciona tanto confidencialidad como autenticación de datos. Se usa ampliamente en protocolos modernos como TLS.
Ejemplo de cifrado y descifrado de una cadena con 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);
// Generación de nonce aleatorio (12 bytes) let mut nonce_bytes = [0u8; 12]; rng.fill(&mut nonce_bytes)?; let nonce = Nonce::assume_unique_for_key(nonce_bytes);
// Buffer para datos cifrados + etiqueta de autenticación let mut in_out = plaintext.to_vec(); key.seal_in_place_append_tag(nonce, Aad::empty(), &mut in_out)?;
// Devolvemos nonce + datos cifrados 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);
// Extraemos nonce (primeros 12 bytes) 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 bytes para AES-256 let data = b"Mensaje secreto";
let encrypted = encrypt(data, key).unwrap(); println!("Cifrado: {:?}", encrypted);
let decrypted = decrypt(&encrypted, key).unwrap(); println!("Descifrado: {}", String::from_utf8(decrypted).unwrap());}Este código demuestra el ciclo completo de cifrado: generación de nonce aleatorio, cifrado con etiqueta de autenticación y posterior descifrado. Tenga en cuenta que el nonce debe ser único para cada cifrado con la misma clave.
Hash con la biblioteca sha2
La biblioteca sha2 proporciona implementaciones de los algoritmos de la familia SHA-2, incluyendo SHA-256, SHA-384 y SHA-512. El hash se utiliza para verificar la integridad de datos, almacenar contraseñas y crear firmas digitales.
Agregue la dependencia:
[dependencies]sha2 = "0.10"Ejemplo de hash de una cadena con SHA-256:
use sha2: También en la biblioteca
Migraciones de bases de datos en C++: revisión de herramientas y bibliotecas
Frameworks CLI para PHP: Symfony Console y Laravel Zero — guía completa
Envío de SMS en Go (Golang): integración con API de biblioteca
Swinject para Swift: guía completa con ejemplos
Trabajo con imágenes en C++: bibliotecas CImg y STB Image