diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/device.rs | 99 | ||||
-rw-r--r-- | src/tests/device.rs | 50 |
2 files changed, 149 insertions, 0 deletions
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()); +} |