diff options
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | TODO.md | 1 | ||||
| -rw-r--r-- | src/device.rs | 31 | ||||
| -rw-r--r-- | src/pws.rs | 6 | ||||
| -rw-r--r-- | tests/device.rs | 23 | 
5 files changed, 61 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ecaef3..2551350 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@  - Add the `Storage::change_update_pin` method that changes the firmware update    PIN.  - Add the `Device::factory_reset` method that performs a factory reset. +- Add the `Device::build_aes_key` method that builds a new AES key on the Nitrokey.  # v0.2.3 (2018-12-31) @@ -1,6 +1,5 @@  - Add support for the currently unsupported commands:      - `NK_set_unencrypted_volume_rorw_pin_type_user` -    - `NK_build_aes_key`      - `NK_is_AES_supported`      - `NK_send_startup`      - `NK_unlock_hidden_volume` diff --git a/src/device.rs b/src/device.rs index 8702405..bc48cd2 100644 --- a/src/device.rs +++ b/src/device.rs @@ -540,6 +540,37 @@ pub trait Device: Authenticate + GetPasswordSafe + GenerateOtp {          let admin_pin_string = get_cstring(admin_pin)?;          unsafe { get_command_result(nitrokey_sys::NK_factory_reset(admin_pin_string.as_ptr())) }      } + +    /// Builds a new AES key on the Nitrokey. +    /// +    /// The AES key is used to encrypt the password safe and the encrypted volume.  You may need +    /// to call this method after a factory reset using `gpg --card-edit`.  You can also use it to +    /// destory the data stored in the password safe or on the encrypted volume. +    /// +    /// # Errors +    /// +    /// - [`InvalidString`][] if the provided password contains a null byte +    /// - [`WrongPassword`][] if the admin password is wrong +    /// +    /// # Example +    /// +    /// ```no_run +    /// use nitrokey::Device; +    /// # use nitrokey::CommandError; +    /// +    /// # fn try_main() -> Result<(), CommandError> { +    /// let device = nitrokey::connect()?; +    /// match device.build_aes_key("12345678") { +    ///     Ok(()) => println!("New AES keys have been built."), +    ///     Err(err) => println!("Could not build new AES keys: {}", err), +    /// }; +    /// #     Ok(()) +    /// # } +    /// ``` +    fn build_aes_key(&self, admin_pin: &str) -> Result<(), CommandError> { +        let admin_pin_string = get_cstring(admin_pin)?; +        unsafe { get_command_result(nitrokey_sys::NK_build_aes_key(admin_pin_string.as_ptr())) } +    }  }  /// Connects to a Nitrokey device.  This method can be used to connect to any connected device, @@ -71,6 +71,11 @@ pub trait GetPasswordSafe {      /// has been used.  Otherwise, other applications can access the password store without      /// authentication.      /// +    /// If this method returns an `AesDecryptionFailed` (Nitrokey Pro) or `Unknown` (Nitrokey +    /// Storage) error, the AES data object on the smart card could not be accessed.  This problem +    /// occurs after a factory reset using `gpg --card-edit` and can be fixed using the +    /// [`Device::build_aes_key`][] command. +    ///      /// # Errors      ///      /// - [`AesDecryptionFailed`][] if the secret for the password safe could not be decrypted @@ -104,6 +109,7 @@ pub trait GetPasswordSafe {      /// [`device`]: struct.PasswordSafe.html#method.device      /// [`lock`]: trait.Device.html#method.lock      /// [`AesDecryptionFailed`]: enum.CommandError.html#variant.AesDecryptionFailed +    /// [`Device::build_aes_key`]: trait.Device.html#method.build_aes_key      /// [`InvalidString`]: enum.CommandError.html#variant.InvalidString      /// [`Unknown`]: enum.CommandError.html#variant.Unknown      /// [`WrongPassword`]: enum.CommandError.html#variant.WrongPassword diff --git a/tests/device.rs b/tests/device.rs index 363b8d8..06e014e 100644 --- a/tests/device.rs +++ b/tests/device.rs @@ -347,6 +347,29 @@ fn factory_reset() {  }  #[test] +#[cfg_attr(not(any(feature = "test-pro", feature = "test-storage")), ignore)] +fn build_aes_key() { +    let device = Target::connect().unwrap(); + +    let pws = device.get_password_safe(USER_PASSWORD).unwrap(); +    assert_eq!(Ok(()), pws.write_slot(0, "test", "testlogin", "testpw")); +    drop(pws); + +    assert_eq!( +        Err(CommandError::WrongPassword), +        device.build_aes_key(USER_PASSWORD) +    ); +    assert_eq!(Ok(()), device.build_aes_key(ADMIN_PASSWORD)); + +    let device = device.authenticate_admin(ADMIN_PASSWORD).unwrap().device(); + +    let pws = device.get_password_safe(USER_PASSWORD).unwrap(); +    assert_ne!("test".to_string(), pws.get_slot_name(0).unwrap()); +    assert_ne!("testlogin".to_string(), pws.get_slot_login(0).unwrap()); +    assert_ne!("testpw".to_string(), pws.get_slot_password(0).unwrap()); +} + +#[test]  #[cfg_attr(not(feature = "test-storage"), ignore)]  fn change_update_pin() {      let device = Storage::connect().unwrap();  | 
