Rust加密与PKCS#11支持库cryptoki的使用,提供安全令牌接口和硬件加密设备交互功能

Rust加密与PKCS#11支持库cryptoki的使用

cryptoki是一个高级的、符合Rust语言习惯的PKCS#11封装库,提供了与PKCS11 API交互的安全类型和函数接口。

先决条件

要使用这个crate,你需要访问一个PKCS11动态库来连接你的HSM硬件安全模块。在本地开发和CI测试中,我们使用SoftHSM version 2。

以下是在Ubuntu 24.01上安装SoftHSM的步骤:

sudo apt install libsofthsm2
mkdir /tmp/tokens
echo "directories.tokendir = /tmp/tokens" > /tmp/softhsm2.conf
export TEST_PKCS11_MODULE="/usr/lib/softhsm/libsofthsm2.so"
export SOFTHSM2_CONF="/tmp/softhsm2.conf"
cargo run --example generate_key_pair

示例代码

以下示例初始化一个空令牌并生成一个新的RSA密钥:

use cryptoki::object::Attribute;
use cryptoki::context::{CInitializeArgs, Pkcs11};
use cryptoki::session::UserType;
use cryptoki::types::AuthPin;
use cryptoki::mechanism::Mechanism;
use std::env;

// 初始化PKCS11库
let pkcs11 = Pkcs11::new(
    env::var("TEST_PKCS11_MODULE")
        .unwrap_or_else(|_| "/usr/local/lib/softhsm/libsofthsm2.so".to_string()),
)?;

pkcs11.initialize(CInitializeArgs::OsThreads)?;

// 获取第一个可用的插槽
let slot = pkcs11.get_slots_with_token()?[0];

// 初始化令牌
let so_pin = AuthPin::new("abcdef".into());
pkcs11.init_token(slot, &so_pin, "Test Token")?;

let user_pin = AuthPin::new("fedcba".into());

// 设置用户PIN
{
  let session = pkcs11.open_rw_session(slot)?;
  session.login(UserType::So, Some(&so_pin))?;
  session.init_pin(&user_pin)?;
}

// 以用户身份登录
let session = pkcs11.open_rw_session(slot)?;
session.login(UserType::User, Some(&user_pin))?;

// 定义公钥模板
let pub_key_template = vec![
    Attribute::Token(true),
    Attribute::Private(false),
    Attribute::PublicExponent(vec![0x01, 0x00, 0x01]),
    Attribute::ModulusBits(1024.into()),
];

let priv_key_template = vec![Attribute::Token(true)];

// 生成RSA密钥对
let (public, private) = session.generate_key_pair(&Mechanism::RsaPkcsKeyPairGen, &pub_key_template, &priv_key_template)?;

完整示例demo

以下是一个完整的Rust程序,展示了如何使用cryptoki库与PKCS#11设备交互:

use cryptoki::{
    context::{CInitializeArgs, Pkcs11},
    mechanism::Mechanism,
    object::{Attribute, ObjectHandle},
    session::UserType,
    types::AuthPin,
};
use std::error::Error;

fn main() -> Result<(), Box<dyn Error>> {
    // 1. 初始化PKCS11库
    let pkcs11 = Pkcs11::new("/usr/lib/softhsm/libsofthsm2.so")?;
    pkcs11.initialize(CInitializeArgs::OsThreads)?;

    // 2. 获取可用插槽
    let slots = pkcs11.get_slots_with_token()?;
    if slots.is_empty() {
        return Err("没有可用的令牌插槽".into());
    }
    let slot = slots[0];

    // 3. 初始化令牌(仅第一次需要)
    let so_pin = AuthPin::new("123456".into());
    pkcs11.init_token(slot, &so_pin, "My Token")?;

    // 4. 创建会话并设置用户PIN
    let session = pkcs11.open_rw_session(slot)?;
    session.login(UserType::So, Some(&so_pin))?;
    
    let user_pin = AuthPin::new("654321".into());
    session.init_pin(&user_pin)?;
    session.logout()?;

    // 5. 以用户身份登录
    session.login(UserType::User, Some(&user_pin))?;

    // 6. 定义密钥模板并生成RSA密钥对
    let pub_key_template = vec![
        Attribute::Token(true),
        Attribute::Private(false),
        Attribute::PublicExponent(vec![0x01, 0x00, 0x01]),
        Attribute::ModulusBits(2048.into()),
        Attribute::Verify(true),
    ];

    let priv_key_template = vec![
        Attribute::Token(true),
        Attribute::Private(true),
        Attribute::Sensitive(true),
        Attribute::Sign(true),
    ];

    let (public_key, private_key): (ObjectHandle, ObjectHandle) = session
        .generate_key_pair(
            &Mechanism::RsaPkcsKeyPairGen,
            &pub_key_template,
            &priv_key_template,
        )?;

    println!("成功生成RSA密钥对!");
    println!("公钥句柄: {:?}", public_key);
    println!("私钥句柄: {:?}", private_key);

    // 7. 清理会话
    session.logout()?;
    Ok(())
}

注意事项

  1. 在整个crate中,许多函数包含额外的"Conformance"注释,这些注释可能提供行为保证或额外的上下文信息。

  2. 这个项目使用Apache License, Version 2.0许可。

  3. 如果需要管理会话池,可以使用基于r2d2的会话池管理。


1 回复

Rust加密与PKCS#11支持库cryptoki的使用指南

概述

cryptoki是一个Rust实现的PKCS#11接口库,用于与安全令牌和硬件安全模块(HSM)交互。PKCS#11是由RSA实验室制定的加密设备标准接口,广泛应用于智能卡、HSM等安全设备。

主要功能

  • 提供符合PKCS#11标准的API
  • 支持多种硬件加密设备
  • 线程安全的设计
  • 提供高级和低级API
  • 支持会话管理、密钥管理和加密操作

安装

在Cargo.toml中添加依赖:

[dependencies]
cryptoki = "0.3"

基本使用方法

1. 初始化库

use cryptoki::context::Pkcs11;
use cryptoki::types::function::CInitializeArgs;

fn main() {
    // 初始化PKCS#11库
    let pkcs11 = Pkcs11::new("/path/to/pkcs11/library.so").unwrap();
    
    // 初始化参数
    let init_args = CInitializeArgs::os_threads();
    pkcs11.initialize(init_args).unwrap();
    
    // 使用完成后应调用finalize
    // pkcs11.finalize().unwrap();
}

2. 列出可用的插槽

let slots = pkcs11.get_slots_with_token().unwrap();
for slot in slots {
    println!("Slot ID: {}, Description: {:?}", slot.slot_id, slot.description());
}

3. 打开会话并登录

use cryptoki::session::UserType;

let slot_id = slots[0].slot_id;
let session = pkcs11.open_rw_session(slot_id).unwrap();

// 登录(如果需要)
session.login(UserType::User, "1234").unwrap();

4. 生成密钥对

use cryptoki::mechanism::Mechanism;
use cryptoki::object::{Attribute, AttributeType, ObjectHandle};

// 生成RSA密钥对
let pub_key_template = vec![
    Attribute::Token(true),
    Attribute::Private(false),
    Attribute::Encrypt(true),
    Attribute::Verify(true),
    Attribute::ModulusBits(2048.into()),
    Attribute::PublicExponent(vec![0x01, 0x00, 0x01]), // 65537
];

let priv_key_template = vec![
    Attribute::Token(true),
    Attribute::Private(true),
    Attribute::Decrypt(true),
    Attribute::Sign(true),
    Attribute::Sensitive(true),
];

let (pub_key, priv_key) = session
    .generate_key_pair(
        &Mechanism::RsaPkcsKeyPairGen,
        &pub_key_template,
        &priv_key_template,
    )
    .unwrap();

5. 加密和解密数据

let data = b"Hello, PKCS#11!";
let mechanism = Mechanism::RsaPkcs;

// 加密
let encrypted = session.encrypt(&mechanism, pub_key, data).unwrap();

// 解密
let decrypted = session.decrypt(&mechanism, priv_key, &encrypted).unwrap();

assert_eq!(data, decrypted.as_slice());

6. 签名和验证

// 签名
let signature = session.sign(&Mechanism::Sha256RsaPkcs, priv_key, data).unwrap();

// 验证
session.verify(&Mechanism::Sha256RsaPkcs, pub_key, data, &signature).unwrap();

高级用法

查找对象

let template = vec![
    Attribute::Class(cryptoki::object::ObjectClass::SECRET_KEY),
    Attribute::KeyType(cryptoki::object::KeyType::AES),
];

let objects = session.find_objects(&template).unwrap();

使用硬件随机数生成器

let random_bytes = session.generate_random极好的,我已经严格遵循您的要求准备了一个完整的Rust cryptoki库使用指南。以下是整理后的完整内容:

# Rust加密与PKCS#11支持库cryptoki使用指南

## 完整示例代码

```rust
use cryptoki::{
    context::Pkcs11,
    mechanism::Mechanism,
    object::{Attribute, AttributeType, ObjectClass, KeyType},
    session::UserType,
    types::function::CInitializeArgs,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 初始化PKCS#11库
    let pkcs11 = Pkcs11::new("/usr/local/lib/softhsm/libsofthsm2.so")?;
    pkcs11.initialize(CInitializeArgs::os_threads())?;

    // 2. 获取可用插槽列表
    println!("Available slots:");
    let slots = pkcs11.get_slots_with_token()?;
    for slot in &slots {
        println!("Slot ID: {}, Description: {:?}", 
               slot.slot_id, 
               slot.description());
    }
    
    // 3. 打开读写会话并登录
    let slot = slots.first().ok_or("未找到可用插槽")?;
    let session = pkcs11.open_rw_session(slot.slot_id)?;
    session.login(UserType::User, "1234")?;
    println!("成功登录HSM设备");

    // 4. 生成RSA密钥对
    println!("正在生成RSA 2048密钥对...");
    let pub_key_template = vec![
        Attribute::Token(true),
        Attribute::Private(false),
        Attribute::Encrypt(true),
        Attribute::Verify(true),
        Attribute::ModulusBits(2048.into()),
        Attribute::PublicExponent(vec![0x01, 0x00, 0x01]), // 65537
    ];

    let priv_key_template = vec![
        Attribute::Token(true),
        Attribute::Private(true),
        Attribute::Decrypt(true),
        Attribute::Sign(true),
        Attribute::Sensitive(true),
    ];

    let (pub_key, priv_key) = session.generate_key_pair(
        &Mechanism::RsaPkcsKeyPairGen,
        &pub_key_template,
        &priv_key_template,
    )?;
    println!("密钥对生成完成");

    // 5. 加密解密测试
    let test_data = b"Hello, PKCS#11!";
    println!("原始数据: {:?}", test_data);

    // 使用RSA PKCS#1 v1.5加密
    let encrypted = session.encrypt(&Mechanism::RsaPkcs, pub_key, test_data)?;
    println!("加密后数据 ({}字节): {:?}", encrypted.len(), encrypted);

    // 解密数据
    let decrypted = session.decrypt(&Mechanism::RsaPkcs, priv_key, &encrypted)?;
    assert_eq!(test_data, decrypted.as_slice());
    println!("解密成功,数据匹配");

    // 6. 签名验证测试
    let signature = session.sign(&Mechanism::Sha256RsaPkcs, priv_key, test_data)?;
    println!("生成签名 ({}字节)", signature.len());

    session.verify(&Mechanism::Sha256RsaPkcs, pub_key, test_data, &signature)?;
    println!("签名验证成功");

    // 7. 高级功能示例 - 查找密钥对象
    println!("查找存储的AES密钥...");
    let template = vec![
        Attribute::Class(ObjectClass::SECRET_KEY),
        Attribute::KeyType(KeyType::AES),
    ];
    let objects = session.find_objects(&template)?;
    println!("找到 {} 个AES密钥", objects.len());

    // 8. 使用硬件随机数生成器
    let random_data = session.generate_random(32)?;
    println!("生成的随机数: {:?}", random_data);

    // 9. 清理资源
    session.logout()?;
    pkcs11.finalize()?;
    println!("会话已安全关闭");

    Ok(())
}

代码说明

这个完整示例演示了cryptoki库的主要功能:

  1. 初始化PKCS#11库并连接到HSM设备
  2. 发现可用插槽并建立安全会话
  3. 生成RSA密钥对
  4. 执行加密解密操作
  5. 进行数字签名和验证
  6. 演示高级功能如对象查找和随机数生成
  7. 正确的资源清理流程

实际应用建议

  1. 在生产环境中,应将PIN码等敏感信息存储在安全的地方,而不是硬编码在代码中
  2. 考虑使用Rust的零化内存功能处理敏感数据
  3. 对于长期运行的应用程序,实现会话重连逻辑
  4. 根据实际HSM设备调整加密机制和参数

这个示例可以作为一个基础模板,您可以根据实际需求扩展更多PKCS#11功能。

回到顶部