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()
);
}
}
}
注意事项
- 在实际使用时,请根据您的智能卡类型调整APDU命令
- 不同读卡器和智能卡可能有不同的协议支持
- 事务操作可以确保命令的原子性,建议对需要连续执行的命令使用事务
- 异步API适合需要高性能或需要同时处理多个连接的应用场景