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

代码说明

  1. TransportNativeHID - 提供与Ledger设备的HID连接功能
  2. APDUCommand - 定义APDU协议命令结构:
    • cla: 指令类别
    • ins: 具体指令代码
    • p1/p2: 指令参数
    • data: 附加数据载荷
  3. 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(())
}

注意事项

  1. 使用前确保Ledger设备已通过USB连接并解锁
  2. 需要在设备上打开相应的应用程序(如比特币、以太坊等)
  3. 在Linux系统上可能需要配置udev规则
  4. 某些操作可能需要用户手动在设备上确认

高级用法

对于更复杂的交互,可以结合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()
}

这个示例展示了如何:

  1. 初始化HID传输
  2. 构建标准的APDU命令
  3. 发送命令并接收响应
  4. 解析设备版本信息

这个库为Rust开发者提供了直接与Ledger硬件钱包交互的能力,是构建安全加密货币应用的重要基础组件。

回到顶部