Blog | G5 Cyber Security

Challenge/Response Authentication

TL;DR

This guide explains how to implement challenge/response authentication where a server requests challenges from clients before granting access. This is more secure than simple password-based systems.

1. Understanding Challenge/Response Authentication

Challenge/response authentication works like this:

  1. The client attempts to connect or request a resource.
  2. The server sends a random ‘challenge’ to the client.
  3. The client performs an operation on the challenge (e.g., hashing it with a secret key).
  4. The client sends the result (‘response’) back to the server.
  5. The server repeats the operation and compares its result to the client’s response. If they match, access is granted.

This prevents attackers from simply replaying captured authentication data.

2. Choosing a Challenge/Response Method

Several methods exist. Here are two common ones:

We will focus on hashing with salt for simplicity.

3. Server-Side Implementation

  1. Generate Random Salts: Use a cryptographically secure random number generator.
  2. Store Salt and Challenge ID: Associate each challenge with a unique ID, store the salt, and track which clients have received which challenges (to prevent reuse).
  3. Verify Responses: When you receive a response, re-hash the stored salt using the client’s secret key. Compare this to the received response.

Example Python code (using secrets module for random number generation):

import secrets
import hashlib

def generate_challenge(client_id):
  salt = secrets.token_hex(16) # Generate a 32-character hex string
  challenge_id = secrets.token_hex(8)
  return salt, challenge_id

def verify_response(client_secret, received_response, salt):
  expected_response = hashlib.sha256((salt + client_secret).encode()).hexdigest()
  return expected_response == received_response

4. Client-Side Implementation

  1. Receive Challenge: Get the challenge (salt) and ID from the server.
  2. Calculate Response: Hash the salt with your secret key using the same algorithm as the server.
  3. Send Response: Send the calculated hash back to the server, along with the challenge ID.

Example Python code:

import hashlib

def calculate_response(secret_key, salt):
  return hashlib.sha256((salt + secret_key).encode()).hexdigest()

5. Security Considerations

6. Example Workflow

  1. Client connects.
  2. Server generates salt and ID, sends them to the client.
  3. Client calculates response using its secret key and the received salt.
  4. Client sends response + challenge ID back to server.
  5. Server recalculates expected response from stored salt and client’s secret key (if known).
  6. Server compares received response with recalculated response. If they match, access granted; otherwise, denied.
Exit mobile version