Rust硬件钱包通信库ledger-transport-hid的使用:支持Ledger设备的HID协议传输与交互
Rust硬件钱包通信库ledger-transport-hid的使用:支持Ledger设备的HID协议传输与交互
基本信息
- License: Apache-2.0
- 版本: 0.11.0
- 分类: 密码学, 认证
- 仓库: zondax/ledger-rs
- 文档: ledger-transport-hid 0.11.0文档
安装
在项目目录中运行以下Cargo命令:
cargo add ledger-transport-hid
或者在Cargo.toml中添加:
ledger-transport-hid = "0.11.0"
使用示例
以下是一个完整的示例代码,展示如何使用ledger-transport-hid库与Ledger设备进行交互:
use ledger_transport_hid::TransportNativeHID;
use ledger_transport::APDUCommand;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建HID传输实例
let transport = TransportNativeHID::new()?;
// 准备APDU命令
let command = APDUCommand {
cla: 0xE0, // 指令类
ins: 0x02, // 指令码
p1: 0x00, // 参数1
p2: 0x00, // 参数2
data: Vec::new(), // 数据字段
};
// 发送命令到设备
let response = transport.exchange(&command).await?;
// 处理响应
println!("Response: {:?}", response);
Ok(())
}
完整示例代码
下面是一个更完整的示例,包含错误处理和多个APDU命令交互:
use ledger_transport_hid::TransportNativeHID;
use ledger_transport::{APDUCommand, APDUError};
use tokio::runtime::Runtime;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建Tokio运行时
let rt = Runtime::new()?;
rt.block_on(async {
// 创建HID传输实例
let transport = match TransportNativeHID::new() {
Ok(t) => t,
Err(e) => {
eprintln!("无法连接Ledger设备: {}", e);
return Err(Box::new(e));
}
};
// 示例1: 获取设备信息
let get_info_cmd = APDUCommand {
cla: 0xE0,
ins: 0x01, // GET_APP_INFO指令
p1: 0x00,
p2: 0x00,
data: Vec::new(),
};
match transport.exchange(&get_info_cmd).await {
Ok(response) => {
println!("设备信息: {:?}", response);
}
Err(e) => {
eprintln!("获取设备信息失败: {}", e);
return Err(Box::new(e));
}
}
// 示例2: 获取公钥
let get_pubkey_cmd = APDUCommand {
cla: 0xE0,
ins: 0x02, // GET_PUBLIC_KEY指令
p1: 0x00,
p2: 0x00,
data: vec![0x01, 0x02, 0x03], // 示例数据
};
match transport.exchange(&get_pubkey_cmd).await {
Ok(response) => {
println!("公钥响应: {:?}", response);
}
Err(e) => {
eprintln!("获取公钥失败: {}", e);
return Err(Box::new(e));
}
}
Ok(())
})
}
代码说明
- TransportNativeHID - 提供与Ledger设备的HID连接功能
- APDUCommand - 定义APDU协议命令结构:
- cla: 指令类别
- ins: 具体指令代码
- p1/p2: 指令参数
- data: 附加数据载荷
- exchange方法 - 异步发送APDU命令并接收响应
注意事项
- 确保设备已通过USB连接且已解锁
- 不同Ledger应用(如比特币、以太坊等)使用不同的APDU指令集
- 需要处理设备可能返回的各种错误状态码
- 部分操作可能需要用户在设备上手动确认
- 建议为每个操作添加适当的超时处理
高级用法
对于需要更复杂交互的场景,可以结合使用多个APDU命令:
use ledger_transport_hid::TransportNativeHID;
use ledger_transport::APDUCommand;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let transport = TransportNativeHID::new()?;
// 多步骤交互示例
let commands = vec![
APDUCommand { cla: 0xE0, ins: 0x10, p1: 0x00, p2: 0x00, data: vec![0x01] },
APDUCommand { cla: 0xE0, ins: 0x11, p1: 0x00, p2: 0x00, data: vec![0x02] },
APDUCommand { cla: 0xE0, ins: 0x12, p1: 0x00, p2: 0x00, data: vec![0x03] },
];
for cmd in commands {
let response = transport.exchange(&cmd).await?;
println!("Command {:02X} response: {:?}", cmd.ins, response);
}
Ok(())
}
错误处理
建议实现自定义错误处理逻辑:
use thiserror::Error;
#[derive(Error, Debug)]
pub enum LedgerError {
#[error("设备连接错误")]
ConnectionError(#[from] std::io::Error),
#[error("APDU通信错误")]
ApduError(#[from] APDUError),
#[error("设备拒绝操作")]
RejectedByDevice,
#[error("无效响应")]
InvalidResponse,
}
fn handle_ledger_error(error: impl std::error::Error) {
match error.downcast_ref::<APDUError>() {
Some(APDUError::Io(e)) => eprintln!("IO错误: {}", e),
Some(APDUError::Device(e)) => eprintln!("设备错误: {}", e),
None => eprintln!("未知错误: {}", error),
}
}
这个库为Rust开发者提供了与Ledger硬件钱包设备直接交互的能力,适合构建需要高安全性的加密货币应用。
1 回复
Rust硬件钱包通信库ledger-transport-hid使用指南
ledger-transport-hid
是一个Rust库,用于通过HID协议与Ledger硬件钱包设备进行通信和交互。它提供了底层传输功能,是构建Ledger设备应用程序的基础。
主要功能
- 通过USB HID协议与Ledger设备通信
- 支持设备发现和连接管理
- 提供异步和同步API
- 处理APDU命令的发送和响应
安装
在Cargo.toml中添加依赖:
[dependencies]
ledger-transport-hid = "0.1"
tokio = { version = "1.0", features = ["full"] } # 如果使用异步API
基本使用方法
同步API示例
use ledger_transport_hid::TransportNativeHID;
use ledger_transport::Exchange;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 创建传输实例
let transport = TransportNativeHID::new()?;
// 准备APDU命令
let apdu = vec![0xE0, 0x01, 0x00, 0x00, 0x00];
// 发送命令并获取响应
let response = transport.exchange(&apdu)?;
println!("Received response: {:?}", response);
Ok(())
}
异步API示例
use ledger_transport_hid::TransportAsyncHID;
use ledger_transport::ExchangeAsync;
use tokio::runtime::Runtime;
async fn async_example() -> Result<(), Box<dyn std::error::Error>> {
// 创建异步传输实例
let transport = TransportAsyncHID::new().await?;
// 准备APDU命令
let apdu = vec![0xE0, 0x01, 0x00, 0x00, 0x00];
// 发送命令并获取响应
let response = transport.exchange(&apdu).await?;
println!("Received async response: {:?}", response);
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let rt = Runtime::new()?;
rt.block_on(async_example())
}
设备管理
列出可用设备
use ledger_transport_hid::Devices;
fn list_devices() -> Result<(), Box<dyn std::error::Error>> {
let devices = Devices::list_devices()?;
println!("Found {} Ledger device(s)", devices.len());
for device in devices {
println!("- {:?}", device);
}
Ok(())
}
设备连接超时设置
use ledger_transport_hid::TransportNativeHID;
use std::time::Duration;
fn connect_with_timeout() -> Result<(), Box<dyn std::error::Error>> {
let transport = TransportNativeHID::new()?
.set_timeout(Duration::from_secs(10));
// 使用transport...
Ok(())
}
错误处理
use ledger_transport_hid::{TransportNativeHID, Error};
fn handle_errors() -> Result<(), Box<dyn std::error::Error>> {
let transport = match TransportNativeHID::new() {
Ok(t) => t,
Err(Error::NoDeviceFound) => {
eprintln!("No Ledger device found");
return Ok(());
}
Err(e) => return Err(Box::new(e)),
};
// 使用transport...
Ok(())
}
注意事项
- 使用前确保Ledger设备已通过USB连接并解锁
- 需要在设备上打开相应的应用程序(如比特币、以太坊等)
- 在Linux系统上可能需要配置udev规则
- 某些操作可能需要用户手动在设备上确认
高级用法
对于更复杂的交互,可以结合ledger-apdu
crate构建标准的APDU命令:
use ledger_apdu::APDUCommand;
use ledger_transport_hid::TransportNativeHID;
use ledger_transport::Exchange;
fn send_complex_command() -> Result<(), Box<dyn std::error::Error>> {
let transport = TransportNativeHID::new()?;
let command = APDUCommand {
cla: 0xE0,
ins: 0x02,
p1: 0x00,
p2: 0x00,
data: vec![0x01, 0x02, 0x03],
};
let response = transport.exchange(&command.serialize())?;
println!("Response: {:?}", response);
Ok(())
}
完整示例代码
以下是一个完整的Ledger设备交互示例,展示了如何获取设备的版本信息:
use ledger_apdu::APDUCommand;
use ledger_transport_hid::TransportNativeHID;
use ledger_transport::Exchange;
fn get_device_version() -> Result<(), Box<dyn std::error::Error>> {
// 创建传输实例
let transport = TransportNativeHID::new()?;
// 构建获取版本信息的APDU命令
let command = APDUCommand {
cla: 0xE0, // 指令类
ins: 0x01, // 指令码 (GET_VERSION)
p1: 0x00, // 参数1
p2: 0x00, // 参数2
data: vec![], // 无数据
};
// 发送命令并获取响应
let response = transport.exchange(&command.serialize())?;
// 解析响应数据
if response.len() >= 3 {
println!("Device Version: {}.{}.{}", response[0], response[1], response[2]);
} else {
println!("Unexpected response format: {:?}", response);
}
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
get_device_version()
}
这个示例展示了如何:
- 初始化HID传输
- 构建标准的APDU命令
- 发送命令并接收响应
- 解析设备版本信息
这个库为Rust开发者提供了直接与Ledger硬件钱包交互的能力,是构建安全加密货币应用的重要基础组件。