AuthChallengeResponse

Struct AuthChallengeResponse 

Source
pub struct AuthChallengeResponse {
    pub server_hash: Vec<u8>,
    pub server_nonce: Vec<u8>,
}
Expand description

Parsed response from the AUTHCHALLENGE command.

Contains the server’s challenge values needed to complete SAFECOOKIE authentication. These values are used to compute the HMAC-SHA256 authentication token.

§Fields

  • server_hash: HMAC proving the server knows the cookie
  • server_nonce: Random value to prevent replay attacks

§Security

Both values are cryptographically significant:

  • server_hash: Computed as HMAC-SHA256(cookie, "Tor safe cookie authentication server-to-controller hash" || client_nonce || server_nonce)
  • server_nonce: 32 random bytes generated by Tor for this challenge

The client must verify the server_hash before sending its authentication response to prevent man-in-the-middle attacks.

§Example

use stem_rs::response::{ControlMessage, AuthChallengeResponse};

// Parse a typical AUTHCHALLENGE response
let msg = ControlMessage::from_str(
    "250 AUTHCHALLENGE \
     SERVERHASH=B16F72DACD4B5ED1531F3FCC04B593D46A1E30267E636EA7C7F8DD7A2B7BAA05 \
     SERVERNONCE=653574272ABBB49395BD1060D642D653CFB7A2FCE6A4955BCFED819703A9998C\r\n",
    None,
    false
).unwrap();

let response = AuthChallengeResponse::from_message(&msg).unwrap();

// Both values are 32 bytes (256 bits)
assert_eq!(response.server_hash.len(), 32);
assert_eq!(response.server_nonce.len(), 32);

// First bytes match the hex encoding
assert_eq!(response.server_hash[0], 0xB1);
assert_eq!(response.server_nonce[0], 0x65);

Fields§

§server_hash: Vec<u8>

The server’s HMAC-SHA256 hash proving knowledge of the cookie.

This 32-byte value is computed by the server using the cookie file contents, the client nonce, and the server nonce. The client should verify this hash before proceeding with authentication.

§Verification

To verify, compute:

HMAC-SHA256(cookie, "Tor safe cookie authentication server-to-controller hash"
            || client_nonce || server_nonce)

and compare with this value using constant-time comparison.

§server_nonce: Vec<u8>

The server’s random nonce for this authentication attempt.

This 32-byte random value is generated fresh for each AUTHCHALLENGE request. It prevents replay attacks by ensuring each authentication attempt uses unique values.

§Usage

Include this nonce when computing the client’s authentication hash:

HMAC-SHA256(cookie, "Tor safe cookie authentication controller-to-server hash"
            || client_nonce || server_nonce)

Implementations§

Source§

impl AuthChallengeResponse

Source

pub fn from_message(message: &ControlMessage) -> Result<Self, Error>

Parses an AUTHCHALLENGE response from a control message.

Extracts the server hash and server nonce from the response, converting them from hexadecimal strings to raw bytes.

§Arguments
  • message - The control message to parse
§Errors

Returns Error::Protocol if:

  • The response status is not OK (2xx)
  • The response contains multiple lines (should be single-line)
  • The response is empty
  • The first word is not “AUTHCHALLENGE”
  • The SERVERHASH mapping is missing or invalid
  • The SERVERNONCE mapping is missing or invalid
  • Either value is not exactly 64 hexadecimal characters
§Example
use stem_rs::response::{ControlMessage, AuthChallengeResponse};

// Valid response
let msg = ControlMessage::from_str(
    "250 AUTHCHALLENGE \
     SERVERHASH=680A73C9836C4F557314EA1C4EDE54C285DB9DC89C83627401AEF9D7D27A95D5 \
     SERVERNONCE=F8EA4B1F2C8B40EF1AF68860171605B910E3BBCABADF6FC3DB1FA064F4690E85\r\n",
    None,
    false
).unwrap();

let response = AuthChallengeResponse::from_message(&msg).unwrap();
assert_eq!(response.server_hash.len(), 32);

// Invalid: missing SERVERNONCE
let bad_msg = ControlMessage::from_str(
    "250 AUTHCHALLENGE \
     SERVERHASH=680A73C9836C4F557314EA1C4EDE54C285DB9DC89C83627401AEF9D7D27A95D5\r\n",
    None,
    false
).unwrap();

assert!(AuthChallengeResponse::from_message(&bad_msg).is_err());
§Security

After parsing, the caller should:

  1. Verify the server_hash matches the expected HMAC
  2. Use the server_nonce to compute the client’s authentication response
  3. Clear sensitive data from memory after use

Trait Implementations§

Source§

impl Clone for AuthChallengeResponse

Source§

fn clone(&self) -> AuthChallengeResponse

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AuthChallengeResponse

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.