Rust加密库xsalsa20poly1305的使用,提供XSalsa20-Poly1305算法实现的高性能加密与认证功能

Rust加密库xsalsa20poly1305的使用

关于XSalsa20Poly1305

XSalsa20Poly1305(也称为NaCl的crypto_secretbox)是一种基于Salsa20流密码(带有XSalsa20 192位nonce扩展)和Poly1305通用哈希函数的认证加密算法,适用于快速、恒定时间的软件实现。

请注意:该crate已弃用,建议改用crypto_secretbox crate。

安全说明

该crate已由Cure53进行过一次安全审计(版本0.8.0),未发现重大问题。

许可证

可选择以下任一种:

  • Apache License, Version 2.0
  • MIT license

示例代码

以下是一个使用XSalsa20Poly1305进行加密和解密的完整示例:

use xsalsa20poly1305::{XSalsa20Poly1305, Key, Nonce}; // 导入必要类型
use xsalsa20poly1305::aead::{Aead, NewAead}; // 导入AEAD trait

fn main() {
    // 生成随机密钥和nonce
    let key = Key::from_slice(b"an example very very secret key."); // 32字节密钥
    let nonce = Nonce::from_slice(b"extra long nonce!"); // 24字节nonce
    
    // 创建加密器实例
    let cipher = XSalsa20Poly1305::new(key);
    
    // 要加密的明文
    let plaintext = b"plaintext message";
    
    // 加密
    let ciphertext = cipher.encrypt(nonce, plaintext.as_ref())
        .expect("加密失败");
    println!("加密后的密文: {:?}", ciphertext);
    
    // 解密
    let decrypted = cipher.decrypt(nonce, ciphertext.as_ref())
        .expect("解密失败");
    println!("解密后的明文: {:?}", decrypted);
    
    assert_eq!(plaintext, decrypted.as_slice());
}

完整示例代码

以下是一个更完整的示例,包含随机生成密钥和nonce:

use xsalsa20poly1305::{XSalsa20Poly1305, Key, Nonce};
use xsalsa20poly1305::aead::{Aead, NewAead};
use rand_core::{OsRng, RngCore};

fn main() {
    // 生成随机密钥(32字节)
    let mut key = [0u8; 32];
    OsRng.fill_bytes(&mut key);
    let key = Key::from_slice(&key);
    
    // 生成随机nonce(24字节)
    let mut nonce = [0u8; 24];
    OsRng.fill_bytes(&mut nonce);
    let nonce = Nonce::from_slice(&nonce);
    
    // 创建加密器实例
    let cipher = XSalsa20Poly1305::new(key);
    
    // 要加密的明文
    let plaintext = b"这是一个需要加密的秘密消息";
    
    // 加密
    let ciphertext = cipher.encrypt(nonce, plaintext.as_ref())
        .expect("加密失败");
    println!("加密后的密文: {:?}", ciphertext);
    
    // 解密
    let decrypted = cipher.decrypt(nonce, ciphertext.as_ref())
        .expect("解密失败");
    
    // 将解密结果转为字符串输出
    let decrypted_text = String::from_utf8(decrypted).unwrap();
    println!("解密后的明文: {}", decrypted_text);
    
    assert_eq!(plaintext, decrypted_text.as_bytes());
}

代码说明

  1. 使用rand_core::OsRng生成安全的随机密钥和nonce
  2. Key需要32字节长度,Nonce需要24字节长度
  3. 加密和解密需要使用相同的nonce值
  4. 实际应用中应妥善保管密钥,避免硬编码在代码中

注意:该crate已标记为弃用,建议考虑使用替代方案如crypto_secretbox crate。


1 回复

Rust加密库xsalsa20poly1305使用指南

简介

xsalsa20poly1305是一个Rust实现的XSalsa20-Poly1305加密算法库,提供了高性能的加密与认证功能。该算法是Salsa20流密码与Poly1305认证器的组合,特别适合需要同时保证机密性和完整性的场景。

特性

  • 高性能的XSalsa20流密码实现
  • 结合Poly1305消息认证码
  • 提供简单易用的API
  • 支持Rust的no_std环境
  • 经过良好的测试和审计

安装

在Cargo.toml中添加依赖:

[dependencies]
xsalsa20poly1305 = "0.9"

基本用法

加密示例

use xsalsa20poly1305::{
    aead::{Aead, KeyInit, OsRng},
    XSalsa20Poly1305, Nonce
};

fn encrypt_message() -> Result<(), xsalsa20poly1305::Error> {
    // 生成随机密钥
    let key = XSalsa20Poly1305::generate_key(&mut OsRng);
    
    // 创建加密器实例
    let cipher = XSalsa20Poly1305::new(&key);
    
    // 生成随机nonce (24字节)
    let nonce = XSalsa20Poly1305::generate_nuce(&mut OsRng);
    
    // 要加密的消息
    let plaintext = b"Hello, world!";
    
    // 加密
    let ciphertext = cipher.encrypt(&nonce, plaintext.as_ref())?;
    
    println!("加密结果: {:?}", ciphertext);
    Ok(())
}

解密示例

use xsalsa20poly1305::{
    aead::{Aead, KeyInit},
    XSalsa20Poly1305, Nonce
};

fn decrypt_message(
    key: &[u8; 32],
    nonce: &Nonce,
    ciphertext: &[u8]
) -> Result<Vec<u8>, xsalsa20poly1305::Error> {
    let cipher = XSalsa20Poly1305::new(key.into());
    let plaintext = cipher.decrypt(nonce, ciphertext)?;
    Ok(plaintext)
}

高级用法

关联数据(AAD)认证

use xsalsa20poly1305::{
    aead::{AeadInPlace, KeyInit, OsRng},
    XSalsa20Poly1305, Nonce
};

fn encrypt_with_aad() -> Result<(), xsalsa20poly1305::Error> {
    let key = XSalsa20Poly1305::generate_key(&mut OsRng);
    let cipher = XSalsa20Poly1305::new(&key);
    let nonce = XSalsa20Poly1305::generate_nonce(&mut OsRng);
    
    let mut buffer = b"Hello, world!".to_vec();
    let aad = b"additional authenticated data";
    
    cipher.encrypt_in_place(&nonce, aad, &mut buffer)?;
    
    println!("加密结果(带AAD): {:?}", buffer);
    Ok(())
}

密钥和Nonce处理

use xsalsa20poly1305::{Key, Nonce};

// 从字节数组创建密钥(32字节)
let key_bytes: [u8; 32] = [0; 32];
let key = Key::from(key_bytes);

// 从字节数组创建nonce(24字节)
let nonce_bytes: [u8; 24] = [0; 24];
let nonce = Nonce::from(nonce_bytes);

安全注意事项

  1. 每个密钥只能使用一次nonce,重复使用会破坏安全性
  2. 确保使用安全的随机数生成器生成密钥和nonce
  3. 密钥和nonce需要安全存储和传输
  4. 考虑使用更高层次的协议如libsodium的secretbox API

性能优化

对于需要高性能的场景,可以考虑:

use xsalsa20poly1305::XSalsa20Poly1305;
use xsalsa20poly1305::aead::{AeadCore, KeyInit};

// 预分配缓冲区
let mut buffer = vec![0; 1024];

// 重用加密器实例
let cipher = XSalsa20Poly1305::new(&key);

完整示例

以下是一个完整的加密解密示例:

use xsalsa20poly1305::{
    aead::{Aead, KeyInit, OsRng},
    XSalsa20Poly1305, Nonce
};

fn main() -> Result<(), xsalsa20poly1305::Error> {
    // 1. 生成随机密钥和nonce
    let key = XSalsa20Poly1305::generate_key(&mut OsRng);
    let nonce = XSalsa20Poly1305::generate_nonce(&mut OsRng);
    
    // 2. 创建加密器实例
    let cipher = XSalsa20Poly1305::new(&key);
    
    // 3. 准备要加密的消息
    let plaintext = b"这是一个需要加密的秘密消息";
    
    // 4. 加密消息
    let ciphertext = cipher.encrypt(&nonce, plaintext.as_ref())?;
    println!("加密后的数据: {:?}", ciphertext);
    
    // 5. 解密消息
    let decrypted = cipher.decrypt(&nonce, ciphertext.as_ref())?;
    println!("解密后的数据: {:?}", String::from_utf8(decrypted).unwrap());
    
    Ok(())
}

带AAD的完整示例

use xsalsa20poly1305::{
    aead::{AeadInPlace, KeyInit, OsRng},
    XSalsa20Poly1305, Nonce
};

fn main() -> Result<(), xsalsa20poly1305::Error> {
    // 1. 生成密钥和nonce
    let key = XSalsa20Poly1305::generate_key(&mut OsRng);
    let nonce = XSalsa20Poly1305::generate_nonce(&mut OsRng);
    
    // 2. 创建加密器
    let cipher = XSalsa20Poly1305::new(&key);
    
    // 3. 准备数据和AAD
    let mut buffer = b"这是需要加密的数据".to_vec();
    let aad = b"这是关联认证数据";
    
    // 4. 加密(原地操作)
    cipher.encrypt_in_place(&nonce, aad, &mut buffer)?;
    println!("加密后数据(带AAD): {:?}", buffer);
    
    // 5. 解密
    cipher.decrypt_in_place(&nonce, aad, &mut buffer)?;
    println!("解密后数据: {:?}", String::from_utf8(buffer).unwrap());
    
    Ok(())
}
回到顶部