(handle: &mut libhid::Handle, report: &nitrokey::Report
) -> Result<()> where P: AsRef<[u8]>, { let mut retry = SEND_TRY_COUNT; loop { let result = handle.feature().send_to(0, report.as_ref()); retry -= 1; match result { Ok(_) => { return Ok(()); }, Err(err) => { if retry > 0 { thread::sleep(time::Duration::from_millis(SEND_RECV_DELAY_MS)); continue; } else { return Err(Error::HidError(err)); } }, } } } /// Receive a HID feature report from the device represented by the given handle. fn receive
(handle: &mut libhid::Handle) -> Result ::new();
let result = handle.feature().get_from(0, report.as_mut());
retry -= 1;
match result {
Ok(size) => {
if size < mem::size_of_val(&report) {
if retry > 0 {
continue;
} else {
return Err(Error::Error("Failed to receive complete report".to_string()));
}
}
if !report.is_valid() {
if retry > 0 {
continue;
} else {
return Err(Error::Error("Failed to receive report: CRC mismatch".to_string()));
}
}
return Ok(report);
},
Err(err) => {
if retry > 0 {
thread::sleep(time::Duration::from_millis(SEND_RECV_DELAY_MS));
continue;
} else {
return Err(Error::HidError(err));
}
},
}
}
}
/// Find and open the nitrokey device and execute a function on it.
fn nitrokey_do(function: &NitroFunc) -> Result<()> {
let hid = libhid::init()?;
// The Manager::find method is plain stupid as it still returns an
// iterable. Using it does not help in more concise error handling.
for device in hid.devices() {
if device.vendor_id() == nitrokey::VID && device.product_id() == nitrokey::PID {
return function(&mut device.open()?);
}
}
return Err(Error::Error("Nitrokey device not found".to_string()));
}
/// Open the encrypted volume on the nitrokey.
fn open() -> Result<()> {
return nitrokey_do(&|handle| {
let passphrase = pinentry::inquire_passphrase()?;
let payload = nitrokey::EnableEncryptedVolumeCommand::new(&passphrase);
let report = nitrokey::Report::from(payload);
send(handle, &report)?;
// We need to give the stick some time to handle the command. If we
// don't, we might just receive stale data from before.
thread::sleep(time::Duration::from_millis(SEND_RECV_DELAY_MS));
receive::