diff --git a/docs/examples/rust/secure_compare.rs b/docs/examples/rust/secure_compare.rs index cc96e68fa..c5b18a5b8 100644 --- a/docs/examples/rust/secure_compare.rs +++ b/docs/examples/rust/secure_compare.rs @@ -83,7 +83,7 @@ fn main() { } } - if comparison.get_result().expect("result") { + if comparison.result().expect("result") { println!("[+] match OK"); } else { println!("[-] no match"); diff --git a/src/wrappers/themis/rust/src/keys.rs b/src/wrappers/themis/rust/src/keys.rs index 4b108f031..0b72b9936 100644 --- a/src/wrappers/themis/rust/src/keys.rs +++ b/src/wrappers/themis/rust/src/keys.rs @@ -355,11 +355,10 @@ impl KeyPair { /// However, it does verify that _the kinds_ of the keys match: i.e., that they are both /// either RSA or ECDSA keys. An error is returned if that’s not the case. You can check /// the kind of the key beforehand via its `kind()` method. - pub fn try_join(private_key: S, public_key: P) -> Result - where - S: Into, - P: Into, - { + pub fn try_join( + private_key: impl Into, + public_key: impl Into, + ) -> Result { let (private_key, public_key) = (private_key.into(), public_key.into()); match (private_key.kind(), public_key.kind()) { (KeyKind::RsaPrivate, KeyKind::RsaPublic) => {} @@ -383,7 +382,7 @@ impl RsaPrivateKey { /// Parses a key from a byte slice. /// /// Returns an error if the slice does not contain a valid RSA private key. - pub fn try_from_slice>(bytes: T) -> Result { + pub fn try_from_slice(bytes: impl AsRef<[u8]>) -> Result { let key = KeyBytes::copy_slice(bytes.as_ref())?; match get_key_kind(&key)? { KeyKind::RsaPrivate => Ok(Self { inner: key }), @@ -403,7 +402,7 @@ impl RsaPublicKey { /// Parses a key from a byte slice. /// /// Returns an error if the slice does not contain a valid RSA public key. - pub fn try_from_slice>(bytes: T) -> Result { + pub fn try_from_slice(bytes: impl AsRef<[u8]>) -> Result { let key = KeyBytes::copy_slice(bytes.as_ref())?; match get_key_kind(&key)? { KeyKind::RsaPublic => Ok(Self { inner: key }), @@ -423,7 +422,7 @@ impl EcdsaPrivateKey { /// Parses a key from a byte slice. /// /// Returns an error if the slice does not contain a valid ECDSA private key. - pub fn try_from_slice>(bytes: T) -> Result { + pub fn try_from_slice(bytes: impl AsRef<[u8]>) -> Result { let key = KeyBytes::copy_slice(bytes.as_ref())?; match get_key_kind(&key)? { KeyKind::EcdsaPrivate => Ok(Self { inner: key }), @@ -443,7 +442,7 @@ impl EcdsaPublicKey { /// Parses a key from a byte slice. /// /// Returns an error if the slice does not contain a valid ECDSA public key. - pub fn try_from_slice>(bytes: T) -> Result { + pub fn try_from_slice(bytes: impl AsRef<[u8]>) -> Result { let key = KeyBytes::copy_slice(bytes.as_ref())?; match get_key_kind(&key)? { KeyKind::EcdsaPublic => Ok(Self { inner: key }), @@ -468,7 +467,7 @@ impl PrivateKey { /// Parses a key from a byte slice. /// /// Returns an error if the slice does not contain a valid RSA or ECDSA private key. - pub fn try_from_slice>(bytes: T) -> Result { + pub fn try_from_slice(bytes: impl AsRef<[u8]>) -> Result { let key = KeyBytes::copy_slice(bytes.as_ref())?; match get_key_kind(&key)? { KeyKind::RsaPrivate => Ok(Self { inner: key }), @@ -487,7 +486,7 @@ impl PublicKey { /// Parses a key from a byte slice. /// /// Returns an error if the slice does not contain a valid RSA or ECDSA public key. - pub fn try_from_slice>(bytes: T) -> Result { + pub fn try_from_slice(bytes: impl AsRef<[u8]>) -> Result { let key = KeyBytes::copy_slice(bytes.as_ref())?; match get_key_kind(&key)? { KeyKind::RsaPublic => Ok(Self { inner: key }), diff --git a/src/wrappers/themis/rust/src/secure_cell.rs b/src/wrappers/themis/rust/src/secure_cell.rs index 65504fc6b..c59be1f76 100644 --- a/src/wrappers/themis/rust/src/secure_cell.rs +++ b/src/wrappers/themis/rust/src/secure_cell.rs @@ -100,6 +100,7 @@ use crate::utils::into_raw_parts; /// /// This is modeless, basic cell. First you provide the master key to a new `SecureCell` object /// then you select the desired operation mode and your Secure Cell is ready to go. +#[derive(Debug)] pub struct SecureCell { master_key: KeyBytes, } @@ -169,6 +170,7 @@ impl SecureCell { /// # Ok(()) /// # } /// ``` +#[derive(Debug)] pub struct SecureCellSeal(SecureCell); impl SecureCellSeal { @@ -488,6 +490,7 @@ fn decrypt_seal(master_key: &[u8], user_context: &[u8], message: &[u8]) -> Resul /// # Ok(()) /// # } /// ``` +#[derive(Debug)] pub struct SecureCellTokenProtect(SecureCell); impl SecureCellTokenProtect { @@ -544,7 +547,7 @@ impl SecureCellTokenProtect { /// # fn main() -> Result<(), themis::Error> { /// use themis::secure_cell::SecureCell; /// - /// let cell = SecureCell::with_key(b"password").unwrap().token_protect(); + /// let cell = SecureCell::with_key(b"password")?.token_protect(); /// /// cell.encrypt_with_context(b"byte string", format!("owned string"))?; /// cell.encrypt_with_context(&[1, 2, 3, 4, 5], vec![6, 7, 8, 9, 10])?; @@ -884,10 +887,9 @@ fn decrypt_token_protect( /// Note that in context imprint mode you *must* provide non-empty context. Also keep in mind that /// Secure Cell cannot verify integrity and correctness of the decrypted data so you have to have /// some other means in place to validate the output. +#[derive(Debug)] pub struct SecureCellContextImprint(SecureCell); -// TODO: maybe panic if a SecureCell with an empty context is switched into context imprint mode - impl SecureCellContextImprint { /// Encrypts the provided message, combining it with provided user context, and returns /// the encrypted data. diff --git a/src/wrappers/themis/rust/src/secure_comparator.rs b/src/wrappers/themis/rust/src/secure_comparator.rs index 370e82faf..ef3df64ae 100644 --- a/src/wrappers/themis/rust/src/secure_comparator.rs +++ b/src/wrappers/themis/rust/src/secure_comparator.rs @@ -81,7 +81,7 @@ //! request = comparison.proceed_compare(&reply)?; //! } //! -//! if !comparison.get_result()? { +//! if !comparison.result()? { //! unimplemented!("handle failed comparison here"); //! } //! # Ok(()) @@ -121,17 +121,17 @@ //! send(&reply); // This function should send the `reply` to the client. //! } //! -//! if !comparison.get_result()? { +//! if !comparison.result()? { //! unimplemented!("handle failed comparison here"); //! } //! # Ok(()) //! # } //! ``` //! -//! Both the server and the client use [`get_result`] to get the comparison result +//! Both the server and the client use [`result`] to get the comparison result //! after it [`is_complete`]: //! -//! [`get_result`]: struct.SecureComparator.html#method.get_result +//! [`result`]: struct.SecureComparator.html#method.result //! [`is_complete`]: struct.SecureComparator.html#method.is_complete use std::os::raw::c_void; @@ -151,10 +151,15 @@ use crate::utils::into_raw_parts; /// Please see [module-level documentation][secure_comparator] for examples. /// /// [secure_comparator]: index.html +#[derive(Debug)] pub struct SecureComparator { comp_ctx: *mut secure_comparator_t, } +// It safe to move secure_comparator_t to another thread, it does not depend on any thread-local +// state. However, it needs external synchronization for safe concurrent usage (hence no Sync). +unsafe impl Send for SecureComparator {} + impl SecureComparator { /// Prepares a new comparison. /// @@ -188,7 +193,7 @@ impl SecureComparator { /// a `SecureComparator` to make a new comparison. /// /// You can use this method only before the comparison has been started. That is, - /// [`append_secret`] is safe call only before [`begin_compare`] or [`proceed_compare`]. + /// [`append_secret`] is safe to call only before [`begin_compare`] or [`proceed_compare`]. /// It will fail with an error if you try to append more data when you’re in the middle of /// a comparison or after it has been completed. /// @@ -214,7 +219,7 @@ impl SecureComparator { /// # Ok(()) /// # } /// ``` - pub fn append_secret>(&mut self, secret: S) -> Result<()> { + pub fn append_secret(&mut self, secret: impl AsRef<[u8]>) -> Result<()> { let (secret_ptr, secret_len) = into_raw_parts(secret.as_ref()); unsafe { @@ -302,7 +307,7 @@ impl SecureComparator { /// Please see [module-level documentation][secure_comparator] for examples. /// /// [secure_comparator]: index.html - pub fn proceed_compare>(&mut self, peer_data: D) -> Result> { + pub fn proceed_compare(&mut self, peer_data: impl AsRef<[u8]>) -> Result> { let (peer_compare_data_ptr, peer_compare_data_len) = into_raw_parts(peer_data.as_ref()); let mut compare_data = Vec::new(); @@ -335,7 +340,6 @@ impl SecureComparator { let error = Error::from_compare_status(status); match error.kind() { ErrorKind::CompareSendOutputToPeer => {} - // TODO: signal that this does not need to be sent ErrorKind::Success => {} _ => { return Err(error); @@ -348,6 +352,34 @@ impl SecureComparator { Ok(compare_data) } + /// Checks if this comparison is complete. + /// + /// Comparison that failed irrecoverably due to an error is also considered complete. + /// + /// # Examples + /// + /// Typically you would use this method to terminate the comparison loop. Please see + /// [module-level documentation][secure_comparator] for examples. + /// + /// [secure_comparator]: index.html + /// + /// It is safe to call this method at any point, even if the comparison has not been initiated + /// yet (in which case it is obviously not complete): + /// + /// ``` + /// use themis::secure_comparator::SecureComparator; + /// + /// let mut comparison = SecureComparator::new(); + /// + /// assert!(!comparison.is_complete()); + /// ``` + pub fn is_complete(&self) -> bool { + match self.result() { + Err(ref e) if e.kind() == ErrorKind::CompareNotReady => false, + _ => true, + } + } + /// Returns the result of comparison. /// /// Let it be a surprise: `true` if data has been found equal on both peers, `false` otherwise. @@ -370,7 +402,7 @@ impl SecureComparator { /// comparison.append_secret(b"999-04-1234")?; /// # other_peer.append_secret(b"999-04-1234")?; /// - /// assert!(comparison.get_result().is_err()); + /// assert!(comparison.result().is_err()); /// /// // Perform comparison /// # @@ -382,11 +414,11 @@ impl SecureComparator { /// # request = comparison.proceed_compare(&reply)?; /// } /// - /// assert!(comparison.get_result().is_ok()); + /// assert!(comparison.result().is_ok()); /// # Ok(()) /// # } /// ``` - pub fn get_result(&self) -> Result { + pub fn result(&self) -> Result { let status = unsafe { secure_comparator_get_result(self.comp_ctx) }; let error = Error::from_match_status(status); match error.kind() { @@ -395,34 +427,6 @@ impl SecureComparator { _ => Err(error), } } - - /// Checks if this comparison is complete. - /// - /// Comparison that failed irrecoverably due to an error is also considered complete. - /// - /// # Examples - /// - /// Typically you would use this method to terminate the comparison loop. Please see - /// [module-level documentation][secure_comparator] for examples. - /// - /// [secure_comparator]: index.html - /// - /// It is safe to call this method at any point, even if the comparison has not been initiated - /// yet (in which case it is obviously not complete): - /// - /// ``` - /// use themis::secure_comparator::SecureComparator; - /// - /// let mut comparison = SecureComparator::new(); - /// - /// assert!(!comparison.is_complete()); - /// ``` - pub fn is_complete(&self) -> bool { - match self.get_result() { - Err(ref e) if e.kind() == ErrorKind::CompareNotReady => false, - _ => true, - } - } } impl Default for SecureComparator { diff --git a/src/wrappers/themis/rust/src/secure_message.rs b/src/wrappers/themis/rust/src/secure_message.rs index 40df8f8aa..948a2f0fb 100644 --- a/src/wrappers/themis/rust/src/secure_message.rs +++ b/src/wrappers/themis/rust/src/secure_message.rs @@ -101,7 +101,7 @@ use crate::utils::into_raw_parts; /// # Ok(()) /// # } /// ``` -#[derive(Clone)] +#[derive(Debug)] pub struct SecureMessage { key_pair: KeyPair, } @@ -206,7 +206,7 @@ impl SecureMessage { /// /// assert!(signed_message.windows(message.len()).any(|subslice| subslice == message)); /// ``` -#[derive(Clone)] +#[derive(Debug)] pub struct SecureSign { private_key: PrivateKey, } @@ -314,7 +314,7 @@ impl SecureSign { /// /// assert!(secure_c.verify(&signed_message).is_err()); /// ``` -#[derive(Clone)] +#[derive(Debug)] pub struct SecureVerify { public_key: PublicKey, } diff --git a/src/wrappers/themis/rust/src/secure_session.rs b/src/wrappers/themis/rust/src/secure_session.rs index 116642243..b5cc1112b 100644 --- a/src/wrappers/themis/rust/src/secure_session.rs +++ b/src/wrappers/themis/rust/src/secure_session.rs @@ -143,6 +143,10 @@ struct SecureSessionContext { last_error: Option, } +// It safe to move secure_session_t to another thread, it does not depend on any thread-local +// state. However, it needs external synchronization for safe concurrent usage (hence no Sync). +unsafe impl Send for SecureSession {} + /// Transport delegate for Secure Session. /// /// This is an interface you need to provide for Secure Session operation. @@ -412,8 +416,8 @@ impl SecureSession { /// Returns ID of the remote peer. /// - /// This method will return an error if the connection has not been established yet. - pub fn get_remote_id(&self) -> Result> { + /// Returns `None` if the connection has not been established yet and there is no peer. + pub fn remote_peer_id(&self) -> Result>> { let mut id = Vec::new(); let mut id_len = 0; @@ -437,7 +441,7 @@ impl SecureSession { id.set_len(id_len); } - Ok(id) + Ok(if id.is_empty() { None } else { Some(id) }) } /// Initiates connection to the remote peer. diff --git a/tests/rust/secure_comparator.rs b/tests/rust/secure_comparator.rs index 09c2e1a0c..d85a47a66 100644 --- a/tests/rust/secure_comparator.rs +++ b/tests/rust/secure_comparator.rs @@ -31,8 +31,8 @@ fn compare_matching_data() { assert!(comparator1.is_complete()); assert!(comparator2.is_complete()); - assert!(comparator1.get_result().unwrap()); - assert!(comparator2.get_result().unwrap()); + assert!(comparator1.result().unwrap()); + assert!(comparator2.result().unwrap()); } #[test] @@ -56,8 +56,8 @@ fn compare_different_data() { let data = comparator2.proceed_compare(&data).unwrap(); let _ata = comparator1.proceed_compare(&data).unwrap(); - assert!(!comparator1.get_result().unwrap()); - assert!(!comparator2.get_result().unwrap()); + assert!(!comparator1.result().unwrap()); + assert!(!comparator2.result().unwrap()); } #[test] @@ -75,8 +75,8 @@ fn split_secrets() { let data = comparator2.proceed_compare(&data).unwrap(); let _ata = comparator1.proceed_compare(&data).unwrap(); - assert!(comparator1.get_result().unwrap()); - assert!(comparator2.get_result().unwrap()); + assert!(comparator1.result().unwrap()); + assert!(comparator2.result().unwrap()); } #[test] @@ -121,8 +121,8 @@ fn data_corruption() { let data = comparator2.proceed_compare(&data).unwrap(); let _ata = comparator1.proceed_compare(&data).unwrap(); - assert!(comparator1.get_result().unwrap()); - assert!(comparator2.get_result().unwrap()); + assert!(comparator1.result().unwrap()); + assert!(comparator2.result().unwrap()); } #[test] @@ -140,8 +140,8 @@ fn reusing_comparators() { let data = comparator2.proceed_compare(&data).unwrap(); let _ata = comparator1.proceed_compare(&data).unwrap(); - assert!(!comparator1.get_result().unwrap()); - assert!(!comparator2.get_result().unwrap()); + assert!(!comparator1.result().unwrap()); + assert!(!comparator2.result().unwrap()); // You can't append more data and restart the comparison after it is complete. assert!(comparator1.append_secret(b"something").is_err()); @@ -150,6 +150,6 @@ fn reusing_comparators() { // Though you can still view the previous results as much as you wish. assert!(comparator1.is_complete()); assert!(comparator2.is_complete()); - assert!(!comparator1.get_result().unwrap()); - assert!(!comparator2.get_result().unwrap()); + assert!(!comparator1.result().unwrap()); + assert!(!comparator2.result().unwrap()); } diff --git a/tests/rust/secure_session.rs b/tests/rust/secure_session.rs index a4d1641f3..9a7d24c88 100644 --- a/tests/rust/secure_session.rs +++ b/tests/rust/secure_session.rs @@ -52,8 +52,8 @@ fn no_transport() { assert!(!client.is_established()); assert!(!server.is_established()); - assert!(client.get_remote_id().unwrap().is_empty()); - assert!(server.get_remote_id().unwrap().is_empty()); + assert_eq!(client.remote_peer_id(), Ok(None)); + assert_eq!(server.remote_peer_id(), Ok(None)); // Connection and key negotiation sequence. let connect_request = client.connect_request().expect("connect request"); @@ -71,8 +71,14 @@ fn no_transport() { assert!(client.is_established()); assert!(server.is_established()); - assert_eq!(client.get_remote_id().unwrap(), name_server.as_bytes()); - assert_eq!(server.get_remote_id().unwrap(), name_client.as_bytes()); + assert_eq!( + client.remote_peer_id(), + Ok(Some(name_server.as_bytes().to_vec())) + ); + assert_eq!( + server.remote_peer_id(), + Ok(Some(name_client.as_bytes().to_vec())) + ); // Try sending a message back and forth. let plaintext = b"test message please ignore";