Rust PKCS#11加密接口库pkcs11的使用,支持硬件安全模块(HSM)和智能卡的跨平台加密操作
Rust PKCS#11加密接口库pkcs11的使用,支持硬件安全模块(HSM)和智能卡的跨平台加密操作
库介绍
这是一个为Rust提供PKCS#11支持的库。它既提供了低级别的API来映射PKCS#11功能到Rust,也提供了更高级别的API以便更容易使用,并为编程PKCS#11带来更多安全性。
状态
该库完全支持PKCS#11 v2.40中的所有功能。技术上它应该可以与从v2.00开始的任何Cryptoki版本一起工作。例如,对于仅在v2.01中添加的C_WaitForSlotEvent
有特殊处理。您可以使用低级别API成功实现并达到所有低级别Cryptoki语义和结构。所有这些都使用SoftHSM进行了集成测试。
兼容性矩阵
以下是与该库一起工作的已知令牌:
- SoftHSM version 2
- Nitrokey HSM 2
- CardConnect SmartCard-HSM
- Safenet iKey 2032
- 可能还有很多其他…
如果您使用此库与未列出的HSM,请提出问题。
安装
在项目目录中运行以下Cargo命令:
cargo add pkcs11
或在Cargo.toml中添加:
pkcs11 = "0.5.0"
示例代码
use pkcs11::types::*;
use pkcs11::Ctx;
use std::path::Path;
fn main() {
// 初始化PKCS#11上下文
let ctx = Ctx::new(Path::new("/path/to/pkcs11/module.so")).unwrap();
// 初始化库
ctx.C_Initialize(CInitializeArgs {
CreateMutex: None,
DestroyMutex: None,
LockMutex: None,
UnlockMutex: None,
flags: CKF_OS_LOCKING_OK,
pReserved: std::ptr::null_mut(),
}).unwrap();
// 获取槽列表
let mut slot_count = 0;
ctx.C_GetSlotList(CK_TRUE, std::ptr::null_mut(), &mut slot_count).unwrap();
let mut slots = vec![0; slot_count as usize];
ctx.C_GetSlotList(CK_TRUE, slots.as_mut_ptr(), &mut slot_count).unwrap();
// 打开会话
let mut session = 0;
ctx.C_OpenSession(
slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION,
std::ptr::null(),
None,
&mut session
).unwrap();
// 登录
ctx.C_Login(session, CKU_USER, "123456".as_bytes(), "123456".len() as CK_ULONG).unwrap();
// 在这里执行加密操作...
// 登出
ctx.C_Logout(session).unwrap();
// 关闭会话
ctx.C_CloseSession(session).unwrap();
// 终止库
ctx.C_Finalize(std::ptr::null_mut()).unwrap();
}
完整示例代码
以下是一个更完整的示例,展示了如何使用PKCS#11库进行RSA密钥生成和加密操作:
use pkcs11::types::*;
use pkcs11::Ctx;
use std::path::Path;
fn main() -> Result<(), pkcs11::errors::Error> {
// 1. 初始化PKCS#11上下文
let ctx = Ctx::new(Path::new("/usr/local/lib/softhsm/libsofthsm2.so"))?;
// 2. 初始化库
ctx.C_Initialize(CInitializeArgs {
CreateMutex: None,
DestroyMutex: None,
LockMutex: None,
UnlockMutex: None,
flags: CKF_OS_LOCKING_OK,
pReserved: std::ptr::null_mut(),
})?;
// 3. 获取槽列表
let mut slot_count = 0;
ctx.C_GetSlotList(CK_TRUE, std::ptr::null_mut(), &mut slot_count)?;
let mut slots = vec![0; slot_count as usize];
ctx.C_GetSlotList(CK_TRUE, slots.as_mut_ptr(), &mut slot_count)?;
// 4. 打开会话
let mut session = 0;
ctx.C_OpenSession(
slots[0],
CKF_SERIAL_SESSION | CKF_RW_SESSION,
std::ptr::null(),
None,
&mut session
)?;
// 5. 登录
ctx.C_Login(session, CKU_USER, "1234".as_bytes(), 4)?;
// 6. 生成RSA密钥对
let mut public_key = 0;
let mut private_key = 0;
let pub_key_template = vec![
CKA_CLASS.into(), CKO_PUBLIC_KEY.into(),
CKA_KEY_TYPE.into(), CKK_RSA.into(),
CKA_MODULUS_BITS.into(), 2048u64.into(),
CKA_PUBLIC_EXPONENT.into(), vec![0x01, 0x00, 0x01].into(),
CKA_TOKEN.into(), true.into(),
CKA_VERIFY.into(), true.into(),
];
let priv_key_template = vec![
CKA_CLASS.into(), CKO_PRIVATE_KEY.into(),
CKA_KEY_TYPE.into(), CKK_RSA.into(),
CKA_TOKEN.into(), true.into(),
CKA_PRIVATE.into(), true.into(),
CKA_SIGN.into(), true.into(),
];
ctx.C_GenerateKeyPair(
session,
&CK_MECHANISM {
mechanism: CKM_RSA_PKCS_KEY_PAIR_GEN,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
},
pub_key_template.as_ptr(),
pub_key_template.len() as u64,
priv_key_template.as_ptr(),
priv_key_template.len() as u64,
&mut public_key,
&mut private_key,
)?;
// 7. 使用公钥加密数据
let data = b"Hello, PKCS#11!";
let mut encrypted_data = vec![0; 256];
let mut encrypted_len = 0;
ctx.C_EncryptInit(
session,
&CK_MECHANISM {
mechanism: CKM_RSA_PKCS,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
},
public_key,
)?;
ctx.C_Encrypt(
session,
data.as_ptr(),
data.len() as u64,
encrypted_data.as_mut_ptr(),
&mut encrypted_len,
)?;
encrypted_data.truncate(encrypted_len as usize);
println!("Encrypted data: {:?}", encrypted_data);
// 8. 使用私钥解密数据
let mut decrypted_data = vec![0; 256];
let mut decrypted_len = 0;
ctx.C_DecryptInit(
session,
&CK_MECHANISM {
mechanism: CKM_RSA_PKCS,
pParameter: std::ptr::null_mut(),
ulParameterLen: 0,
},
private_key,
)?;
ctx.C_Decrypt(
session,
encrypted_data.as_ptr(),
encrypted_data.len() as u64,
decrypted_data.as_mut_ptr(),
&mut decrypted_len,
)?;
decrypted_data.truncate(decrypted_len as usize);
println!("Decrypted data: {:?}", String::from_utf8_lossy(&decrypted_data));
// 9. 清理
ctx.C_Logout(session)?;
ctx.C_CloseSession(session)?;
ctx.C_Finalize(std::ptr::null_mut())?;
Ok(())
}
注意事项
- 该库仍在开发中,高层次的Rust友好API正在设计过程中
- 测试目前使用SoftHSM2完成
- 支持从PKCS#11 v2.00开始的版本
- 需要提供PKCS#11模块的路径(如.so/.dll文件)
- 实际使用时需要根据具体的HSM设备调整参数
1 回复
Rust PKCS#11加密接口库pkcs11的使用指南
以下是基于提供内容整理的完整示例demo,展示了如何使用pkcs11库与HSM设备进行交互:
use pkcs11::{
types::{Attribute, Mechanism, ObjectClass},
Context,
};
fn main() -> Result<(), pkcs11::Error> {
// 1. 初始化PKCS#11库
// 注意: 替换为您的实际PKCS#11库路径
let ctx = Context::load("/usr/local/lib/softhsm/libsofthsm2.so")?;
ctx.initialize()?;
// 2. 获取槽位信息
let slots = ctx.get_slot_list(true)?;
println!("可用槽位: {:?}", slots);
// 假设使用第一个槽位
let slot = slots[0];
let token_info = ctx.get_token_info(slot)?;
println!("令牌信息: {:?}", token_info.label());
// 3. 打开会话并登录
let session = ctx.open_session(
slot,
pkcs11::types::CKF_RW_SESSION | pkcs11::types::CKF_SERIAL_SESSION,
)?;
session.login(pkcs11::types::CKU_USER, "1234")?;
// 4. 生成RSA密钥对
let pub_key_template = vec![
Attribute::Token(true),
Attribute::Private(false),
Attribute::Encrypt(true),
Attribute::Verify(true),
Attribute::PublicExponent(vec![0x01, 0x00, 0x01]), // 65537
Attribute::ModulusBits(2048.into()),
];
let priv_key_template = vec![
Attribute::Token(true),
Attribute::Private(true),
Attribute::Sensitive(true),
Attribute::Decrypt(true),
Attribute::Sign(true),
];
let (pub_key, priv_key) = session.generate_key_pair(
&Mechanism::RsaPkcsKeyPairGen,
&pub_key_template,
&priv_key_template,
)?;
println!("成功生成RSA密钥对");
// 5. 加密和解密示例
let data = b"Hello, PKCS#11!";
println!("原始数据: {:?}", data);
// 加密
let encrypted = session.encrypt(&Mechanism::RsaPkcs, pub_key, data.to_vec())?;
println!("加密后数据(长度: {}): {:?}", encrypted.len(), encrypted);
// 解密
let decrypted = session.decrypt(&Mechanism::RsaPkcs, priv_key, encrypted)?;
println!("解密后数据: {:?}", decrypted);
assert_eq!(data, decrypted.as_slice());
// 6. 签名和验证示例
let data_to_sign = b"data to be signed";
// 签名
session.sign_init(&Mechanism::RsaPkcs, priv_key)?;
let signature = session.sign(data_to_sign.to_vec())?;
println!("签名结果(长度: {}): {:?}", signature.len(), signature);
// 验证
session.verify_init(&Mechanism::RsaPkcs, pub_key)?;
let valid = session.verify(data_to_sign.to_vec(), signature)?;
println!("签名验证结果: {}", valid);
assert!(valid);
// 7. 清理资源
session.logout()?;
session.close()?;
ctx.finalize()?;
Ok(())
}
代码说明
-
初始化部分:
- 加载PKCS#11动态库(需根据平台选择正确的文件)
- 初始化PKCS#11上下文
-
设备交互部分:
- 获取可用槽位列表
- 获取令牌信息
- 打开读写会话并登录
-
加密操作:
- 生成RSA密钥对(2048位)
- 使用公钥加密数据
- 使用私钥解密数据
-
签名操作:
- 使用私钥创建签名
- 使用公钥验证签名
-
资源清理:
- 登出会话
- 关闭会话
- 释放PKCS#11库
运行准备
- 安装SoftHSM2或其他PKCS#11兼容设备
- 配置正确的库路径
- 设置正确的PIN码(示例中使用"1234")
注意事项
- 实际使用时需要处理各种可能的错误
- 敏感操作应放在安全环境中执行
- 生产环境应使用更安全的密钥管理方式