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(())
}

代码说明

  1. 初始化部分

    • 加载PKCS#11动态库(需根据平台选择正确的文件)
    • 初始化PKCS#11上下文
  2. 设备交互部分

    • 获取可用槽位列表
    • 获取令牌信息
    • 打开读写会话并登录
  3. 加密操作

    • 生成RSA密钥对(2048位)
    • 使用公钥加密数据
    • 使用私钥解密数据
  4. 签名操作

    • 使用私钥创建签名
    • 使用公钥验证签名
  5. 资源清理

    • 登出会话
    • 关闭会话
    • 释放PKCS#11库

运行准备

  1. 安装SoftHSM2或其他PKCS#11兼容设备
  2. 配置正确的库路径
  3. 设置正确的PIN码(示例中使用"1234")

注意事项

  1. 实际使用时需要处理各种可能的错误
  2. 敏感操作应放在安全环境中执行
  3. 生产环境应使用更安全的密钥管理方式
回到顶部