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 cookieserver_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
impl AuthChallengeResponse
Sourcepub fn from_message(message: &ControlMessage) -> Result<Self, Error>
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:
- Verify the server_hash matches the expected HMAC
- Use the server_nonce to compute the client’s authentication response
- Clear sensitive data from memory after use
Trait Implementations§
Source§impl Clone for AuthChallengeResponse
impl Clone for AuthChallengeResponse
Source§fn clone(&self) -> AuthChallengeResponse
fn clone(&self) -> AuthChallengeResponse
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more