Rust PC/SC智能卡读写库pcsc的使用,支持跨平台智能卡和读卡器通信功能

Rust PC/SC智能卡读写库pcsc的使用,支持跨平台智能卡和读卡器通信功能

简介

pcsc-rust 是 Rust 语言对 PC/SC API 的绑定,用于智能卡通信。它具有以下特点:

  • 友好、安全的 API
  • 在 Linux、Windows 和 macOS 上经过测试
  • 几乎零开销

安装

Cargo.toml 中添加依赖:

[dependencies]
pcsc = "2"

示例

以下是连接到第一个可用读卡器中的卡片、发送 APDU 命令并打印响应的完整示例:

use pcsc::*;

fn main() {
    // 建立PC/SC上下文
    let ctx = match Context::establish(Scope::User) {
        Ok(ctx) => ctx,
        Err(err) => {
            eprintln!("Failed to establish context: {}", err);
            std::process::exit(1);
        }
    };

    // 列出可用读卡器
    let mut readers_buf = [0; 2048];
    let mut readers = match ctx.list_readers(&mut readers_buf) {
        Ok(readers) => readers,
        Err(err) => {
            eprintln!("Failed to list readers: {}", err);
            std::process::exit(1);
        }
    };

    // 使用第一个读卡器
    let reader = match readers.next() {
        Some(reader) => reader,
        None => {
            println!("No readers are connected.");
            return;
        }
    };
    println!("Using reader: {:?}", reader);

    // 连接到卡片
    let card = match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) {
        Ok(card) => card,
        Err(Error::NoSmartcard) => {
            println!("A smartcard is not present in the reader.");
            return;
        }
        Err(err) => {
            eprintln!("Failed to connect to card: {}", err);
            std::process::exit(1);
        }
    };

    // 发送APDU命令
    let apdu = b"\x00\xa4\x04\x00\x0A\xA0\x00\x00\x00\x62\x03\x01\x0C\x06\x01";
    println!("Sending APDU: {:?}", apdu);
    let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
    let rapdu = match card.transmit(apdu, &mut rapdu_buf) {
        Ok(rapdu) => rapdu,
        Err(err) => {
            eprintln!("Failed to transmit APDU command to card: {}", err);
            std::process::exit(1);
        }
    };
    println!("APDU response: {:?}", rapdu);
}

示例输出:

$ ./target/debug/examples/readme
Using reader: "SCM Microsystems Inc. SCR 355 [CCID Interface] 00 00"
Sending APDU: [0, 164, 4, 0, 10, 160, 0, 0, 0, 98, 3, 1, 12, 6, 1]
APDU response: [106, 130]

完整示例代码

以下是一个更完整的示例,包含错误处理和更多操作:

use pcsc::*;
use std::time::Duration;

fn main() -> Result<(), pcsc::Error> {
    // 1. 建立PC/SC上下文
    let ctx = Context::establish(Scope::User)?;
    
    // 2. 列出所有读卡器
    let mut readers_buf = [0; 2048];
    let readers = ctx.list_readers(&mut readers_buf)?;
    
    // 3. 检查是否有可用读卡器
    let reader = readers.into_iter().next()
        .ok_or_else(|| {
            println!("没有检测到读卡器");
            pcsc::Error::NoReadersAvailable
        })?;
    println!("使用的读卡器: {:?}", reader);

    // 4. 连接到卡片
    let card = ctx.connect(reader, ShareMode::Shared, Protocols::ANY)?;
    
    // 5. 设置超时时间
    card.set_timeout(Duration::from_secs(5))?;
    
    // 6. 发送SELECT APDU命令
    let select_apdu = b"\x00\xA4\x04\x00\x0A\xA0\x00\x00\x00\x62\x03\x01\x0C\x06\x01";
    println!("发送SELECT APDU命令: {:?}", select_apdu);
    
    let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
    let rapdu = card.transmit(select_apdu, &mut rapdu_buf)?;
    println!("APDU响应: {:?}", rapdu);
    
    // 7. 发送GET STATUS命令
    let status_apdu = b"\x80\xF2\x00\x00\x00";
    println!("\n发送GET STATUS命令: {:?}", status_apdu);
    
    let rapdu = card.transmit(status_apdu, &mut rapdu_buf)?;
    println!("APDU响应: {:?}", rapdu);
    
    Ok(())
}

许可证

MIT 许可证。


1 回复

Rust PC/SC智能卡读写库pcsc的使用指南

完整示例代码

下面是一个完整的示例,展示了如何使用pcsc库进行智能卡操作:

use pcsc::*;

fn main() -> Result<(), pcsc::Error> {
    // 1. 初始化PC/SC上下文
    let ctx = Context::establish(Scope::User)?;
    
    // 2. 列出所有可用读卡器
    let readers = match ctx.list_readers_owned() {
        Ok(readers) => readers,
        Err(Error::NoReadersAvailable) => {
            eprintln!("没有找到可用的智能卡读卡器");
            return Ok(());
        }
        Err(err) => return Err(err),
    };
    
    // 打印找到的读卡器
    for (i, reader) in readers.iter().enumerate() {
        println!("[{}] 读卡器: {}", i, reader.to_string_lossy());
    }
    
    if readers.is_empty() {
        return Ok(());
    }
    
    // 3. 连接到第一个读卡器
    let card = ctx.connect(&readers[0], ShareMode::Shared, Protocols::ANY)?;
    
    // 4. 使用事务发送APDU命令
    {
        let transaction = card.transaction()?;
        
        // SELECT命令(选择MF)
        let select_apdu = b"\x00\xA4\x04\x00\x00";
        let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
        let rapdu = transaction.transmit(select_apdu, &mut rapdu_buf)?;
        
        println!("SELECT响应: {:02X?}", rapdu);
        
        // 事务结束时自动提交
    }
    
    // 5. 直接发送APDU命令(不适用事务)
    let status_apdu = b"\x00\xB0\x00\x00\x00";
    let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
    let rapdu = card.transmit(status_apdu, &mut rapdu_buf)?;
    
    println!("STATUS响应: {:02X?}", rapdu);
    
    Ok(())
}

异步API完整示例

use pcsc::*;
use futures::executor::block_on;

async fn async_card_operations() -> Result<(), pcsc::Error> {
    // 1. 异步建立上下文
    let ctx = Context::establish(Scope::User)?;
    
    // 2. 异步列出读卡器
    let readers = ctx.list_readers_owned()?;
    if readers.is_empty() {
        eprintln!("没有可用的读卡器");
        return Ok(());
    }
    
    // 3. 异步连接读卡器
    let card = ctx.connect_async(&readers[0], ShareMode::Shared, Protocols::ANY).await?;
    
    // 4. 异步发送APDU命令
    let select_apdu = b"\x00\xA4\x04\x00\x00";
    let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
    let rapdu = card.transmit_async(select_apdu, &mut rapdu_buf).await?;
    
    println!("异步响应: {:02X?}", rapdu);
    
    Ok(())
}

fn main() -> Result<(), pcsc::Error> {
    block_on(async_card_operations())
}

监听卡状态变化示例

use pcsc::*;

fn main() -> Result<(), pcsc::Error> {
    let ctx = Context::establish(Scope::User)?;
    
    // 获取读卡器状态变化
    let mut states = ctx.get_status_change(None, &[])?;
    
    loop {
        println!("等待读卡器状态变化...");
        
        // 等待状态变化(10秒超时)
        ctx.get_status_change(Some(Duration::from_secs(10)), &mut states)?;
        
        for state in &states {
            println!(
                "读卡器: {}, 事件状态: {:?}",
                state.reader().to_string_lossy(),
                state.event_state()
            );
        }
    }
}

注意事项

  1. 在实际使用时,请根据您的智能卡类型调整APDU命令
  2. 不同读卡器和智能卡可能有不同的协议支持
  3. 事务操作可以确保命令的原子性,建议对需要连续执行的命令使用事务
  4. 异步API适合需要高性能或需要同时处理多个连接的应用场景
回到顶部