Rust中的密码学:使用ring和sha2库进行加密和哈希
Rust是一种系统编程语言,保证内存安全和高性能。凭借这些特性,它非常适合密码学任务。在本文中,我们将介绍两个流行的库:ring(用于对称加密和哈希)和sha2(用于纯哈希)。您将学习如何使用AES-GCM加密数据、计算SHA-256哈希以及创建HMAC签名。
为什么选择Rust进行密码学?
Rust在编译阶段消除了整类漏洞(缓冲区溢出、数据竞争)。像ring这样的Rust密码学库使用汇编和C语言编写,并带有安全封装,从而提供与C相当的速度,同时具备Rust的可靠性。
项目设置
创建一个新项目并在Cargo.toml中添加依赖项:
[dependencies]ring = "0.17"sha2 = "0.10"hex = "0.4" # 用于方便地显示字节对称加密:使用ring的AES-GCM
AES-GCM(伽罗瓦/计数器模式)是一种现代对称加密标准,既提供机密性,也提供认证(完整性检查)。ring库提供了简单且安全的API。
数据加密
加密需要:密钥(256位)、nonce(96位)和明文。每个使用同一密钥的加密操作必须使用唯一的nonce。
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);
// 生成随机nonce let mut nonce_bytes = [0u8; 12]; rng.fill(&mut nonce_bytes).unwrap(); let nonce = Nonce::assume_unique_for_key(nonce_bytes);
// 使用空附加数据(AAD)进行加密 let mut in_out = plaintext.to_vec(); let tag = key.seal_in_place_separate_tag(nonce, Aad::empty(), &mut in_out).unwrap(); // 返回nonce + 加密数据 + 认证标签 let mut result = nonce_bytes.to_vec(); result.extend_from_slice(&in_out); result.extend_from_slice(tag.as_ref()); result}解密
解密时,提取nonce、标签和密文,然后调用open_in_place。
fn decrypt_aes_gcm(key: &[u8; 32], ciphertext: &[u8]) -> Option<Vec<u8>> { if ciphertext.len() < 28 { return None; } // 至少12(nonce)+ 16(标签)
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期望标签在末尾 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 // 密钥错误或数据损坏 }}使用示例
fn main() { let key = b"0123456789abcdef0123456789abcdef"; // 32字节 let data = b"给Rust的秘密消息!"; let encrypted = encrypt_aes_gcm(key, data); println!("加密后(hex):{}", hex::encode(&encrypted)); if let Some(decrypted) = decrypt_aes_gcm(key, &encrypted) { println!("解密后:{}", String::from_utf8(decrypted).unwrap())