aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO.md3
-rw-r--r--src/device.rs99
-rw-r--r--src/tests/device.rs50
3 files changed, 150 insertions, 2 deletions
diff --git a/TODO.md b/TODO.md
index 992b501..e2fb3fe 100644
--- a/TODO.md
+++ b/TODO.md
@@ -4,8 +4,6 @@
- `NK_build_aes_key`
- `NK_is_AES_supported`
- `NK_send_startup`
- - `NK_unlock_encrypted_volume`
- - `NK_lock_encrypted_volume`
- `NK_unlock_hidden_volume`
- `NK_lock_hidden_volume`
- `NK_create_hidden_volume`
@@ -39,3 +37,4 @@
- Consider implementing `Into<CommandError>` for `(Device, CommandError)`
- Check error handling in PasswordSafe::drop().
- Disable creation of multiple password safes at the same time.
+- Check timing in Storage tests.
diff --git a/src/device.rs b/src/device.rs
index d6b9780..f901306 100644
--- a/src/device.rs
+++ b/src/device.rs
@@ -408,6 +408,30 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {
))
}
}
+
+ /// Locks the Nitrokey device.
+ ///
+ /// This disables the password store if it has been unlocked. On the Nitrokey Storage, this
+ /// also disables the volumes if they have been enabled.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use nitrokey::{CommandStatus, Device};
+ /// # use nitrokey::CommandError;
+ ///
+ /// # fn try_main() -> Result<(), CommandError> {
+ /// let device = nitrokey::connect()?;
+ /// match device.lock() {
+ /// CommandStatus::Success => println!("Locked the Nitrokey device."),
+ /// CommandStatus::Error(err) => println!("Could not lock the Nitrokey device: {:?}", err),
+ /// };
+ /// # Ok(())
+ /// # }
+ /// ```
+ fn lock(&self) -> CommandStatus {
+ unsafe { CommandStatus::from(nitrokey_sys::NK_lock_device()) }
+ }
}
/// Connects to a Nitrokey device. This method can be used to connect to any connected device,
@@ -509,6 +533,81 @@ impl Storage {
false => Err(CommandError::Unknown),
}
}
+
+ /// Enables the encrypted storage volume.
+ ///
+ /// Once the encrypted volume is enabled, it is presented to the operating system as a block
+ /// device. The API does not provide any information on the name or path of this block device.
+ ///
+ /// # Errors
+ ///
+ /// - [`InvalidString`][] if the provided password contains a null byte
+ /// - [`WrongPassword`][] if the provided user password is wrong
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use nitrokey::{CommandStatus};
+ /// # use nitrokey::CommandError;
+ ///
+ /// # fn try_main() -> Result<(), CommandError> {
+ /// let device = nitrokey::Storage::connect()?;
+ /// match device.enable_encrypted_volume("123456") {
+ /// CommandStatus::Success => println!("Enabled the encrypted volume."),
+ /// CommandStatus::Error(err) => println!("Could not enable the encrypted volume: {:?}", err),
+ /// };
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
+ pub fn enable_encrypted_volume(&self, user_pin: &str) -> CommandStatus {
+ let user_pin = CString::new(user_pin);
+ if user_pin.is_err() {
+ return CommandStatus::Error(CommandError::InvalidString);
+ }
+ let user_pin = user_pin.unwrap();
+ unsafe { CommandStatus::from(nitrokey_sys::NK_unlock_encrypted_volume(user_pin.as_ptr())) }
+ }
+
+ /// Disables the encrypted storage volume.
+ ///
+ /// Once the volume is disabled, it can be no longer accessed as a block device. If the
+ /// encrypted volume has not been enabled, this method still returns a success.
+ ///
+ /// # Example
+ ///
+ /// ```no_run
+ /// use nitrokey::{CommandStatus};
+ /// # use nitrokey::CommandError;
+ ///
+ /// fn use_volume() {}
+ ///
+ /// # fn try_main() -> Result<(), CommandError> {
+ /// let device = nitrokey::Storage::connect()?;
+ /// match device.enable_encrypted_volume("123456") {
+ /// CommandStatus::Success => {
+ /// println!("Enabled the encrypted volume.");
+ /// use_volume();
+ /// match device.disable_encrypted_volume() {
+ /// CommandStatus::Success => println!("Disabled the encrypted volume."),
+ /// CommandStatus::Err(err) => {
+ /// println!("Could not disable the encrypted volume: {:?}", err);
+ /// },
+ /// };
+ /// },
+ /// CommandStatus::Error(err) => println!("Could not enable the encrypted volume: {:?}", err),
+ /// };
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString
+ /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword
+ pub fn disable_encrypted_volume(&self) -> CommandStatus {
+ unsafe { CommandStatus::from(nitrokey_sys::NK_lock_encrypted_volume()) }
+ }
}
impl Drop for Storage {
diff --git a/src/tests/device.rs b/src/tests/device.rs
index 68f1a39..7f7a819 100644
--- a/src/tests/device.rs
+++ b/src/tests/device.rs
@@ -1,10 +1,24 @@
use std::ffi::CStr;
+use std::process::Command;
+use std::{thread, time};
use tests::util::{Target, ADMIN_PASSWORD, USER_PASSWORD};
use {Authenticate, CommandError, CommandStatus, Config, Device};
static ADMIN_NEW_PASSWORD: &str = "1234567890";
static USER_NEW_PASSWORD: &str = "abcdefghij";
+fn count_nitrokey_block_devices() -> usize {
+ thread::sleep(time::Duration::from_secs(2));
+ let output = Command::new("lsblk")
+ .args(&["-o", "MODEL"])
+ .output()
+ .expect("Could not list block devices");
+ String::from_utf8_lossy(&output.stdout)
+ .split("\n")
+ .filter(|&s| s == "Nitrokey Storage")
+ .count()
+}
+
#[test]
#[cfg_attr(not(feature = "test-no-device"), ignore)]
fn connect_no_device() {
@@ -227,3 +241,39 @@ fn unlock_user_pin() {
);
device.authenticate_user(USER_PASSWORD).unwrap();
}
+
+#[test]
+#[cfg_attr(not(feature = "test-storage"), ignore)]
+fn encrypted_volume() {
+ let device = Target::connect().unwrap();
+ assert_eq!(CommandStatus::Success, device.lock());
+
+ assert_eq!(1, count_nitrokey_block_devices());
+ assert_eq!(CommandStatus::Success, device.disable_encrypted_volume());
+ assert_eq!(1, count_nitrokey_block_devices());
+ assert_eq!(
+ CommandStatus::Error(CommandError::WrongPassword),
+ device.enable_encrypted_volume("123")
+ );
+ assert_eq!(1, count_nitrokey_block_devices());
+ assert_eq!(
+ CommandStatus::Success,
+ device.enable_encrypted_volume(USER_PASSWORD)
+ );
+ assert_eq!(2, count_nitrokey_block_devices());
+ assert_eq!(CommandStatus::Success, device.disable_encrypted_volume());
+ assert_eq!(1, count_nitrokey_block_devices());
+}
+
+#[test]
+#[cfg_attr(not(feature = "test-storage"), ignore)]
+fn lock() {
+ let device = Target::connect().unwrap();
+
+ assert_eq!(
+ CommandStatus::Success,
+ device.enable_encrypted_volume(USER_PASSWORD)
+ );
+ assert_eq!(CommandStatus::Success, device.lock());
+ assert_eq!(1, count_nitrokey_block_devices());
+}