A pure Python implementation of the Secure Remote Password protocol (SRP version 6a) with GSA mode support.
SRP (Secure Remote Password) is a password-authenticated key exchange protocol that allows secure authentication without transmitting the password over the network. This implementation follows RFC 5054 and includes support for GSA (Grand Slam Authentication) mode.
- Pure Python - No external dependencies, uses only Python standard library
- Multiple Key Sizes - Support for 1024 to 8192-bit primes from RFC 5054
- GSA Mode - Compatible with GSA authentication services
- Hash Cash - Includes proof-of-work implementation for rate limiting
- Type Hints - Full type annotation support
pip install srp6from srp6 import SRPClient, pbkdf2_sha256
# Create client with username
client = SRPClient(b"user@example.com")
# Derive password using PBKDF2 (typically from server's salt)
password = b"secret_password"
salt = b"server_provided_salt"
derived_password = pbkdf2_sha256(password, salt, iterations=10000)
client.password = derived_password
# Get public ephemeral to send to server
A = client.get_public_ephemeral()
# After receiving server's salt and public ephemeral B:
# Generate client proof M1
M1 = client.generate(salt=server_salt, server_public=server_B)
# Get session key for encrypted communication
session_key = client.session_keyfrom srp6 import SRPClient, SRP_1024, SRP_4096
# Use 1024-bit prime (faster, less secure)
client_1024 = SRPClient(b"user", group=1024)
# Use 4096-bit prime (slower, more secure)
client_4096 = SRPClient(b"user", group=4096)
# Or pass the group directly
client = SRPClient(b"user", group=SRP_4096)from srp6 import generate_hashcash, verify_hashcash
# Generate proof of work
bits = 11 # Difficulty level (number of leading zero bits)
challenge = "server_challenge_string"
hashcash = generate_hashcash(bits, challenge)
# Verify proof of work
is_valid = verify_hashcash(hashcash, bits)class SRPClient:
def __init__(
self,
username: bytes,
a: int | None = None,
group: SRPGroup | int | None = None
):
"""
Initialize SRP client.
Args:
username: The username/identity bytes
a: Optional private ephemeral value (for testing)
group: SRP group - SRPGroup instance, bit size (1024/2048/4096), or None for default (2048)
"""Properties:
password- Set the derived password (from PBKDF2)session_key- Get the computed session key KM- Get the client proof M1group- Get the SRP group being used
Methods:
get_public_ephemeral()- Get client's public ephemeral Agenerate(salt, server_public)- Generate client proof M1generate_m2()- Generate M2 for verification
All groups from RFC 5054 (1024 to 8192 bits):
SRP_1024- 1024 bits (128 bytes) - Legacy, not recommendedSRP_1536- 1536 bits (192 bytes) - LegacySRP_2048- 2048 bits (256 bytes) - Standard (default)SRP_3072- 3072 bits (384 bytes) - Enhanced securitySRP_4096- 4096 bits (512 bytes) - High securitySRP_6144- 6144 bits (768 bytes) - Very high securitySRP_8192- 8192 bits (1024 bytes) - Maximum security
# Hashing
hash_sha256(data: bytes) -> bytes
pbkdf2_sha256(password: bytes, salt: bytes, iterations: int, dklen: int = 32) -> bytes
# Byte conversions
bytes_to_int(b: bytes) -> int
int_to_bytes(n: int, length: int | None = None) -> bytes
to_hex(data: bytes) -> str
from_hex(hex_str: str) -> bytesThis implementation supports GSA (Grand Slam Authentication) mode, which differs from standard SRP-6a in the following ways:
-
Identity not included in x computation - The password verifier x is computed as
H(salt || H(":" || password))instead ofH(salt || H(I || ":" || password)) -
Generator padding - The generator g is padded to N_BYTES when computing
H(g)for the M1 proof -
No padding for A, B, S - The public ephemerals A and B, and the shared secret S are NOT padded in their respective computations
N- Large safe prime (N = 2q+1, where q is prime)g- Generator modulo Nk- Multiplier parameter:k = H(N || pad(g))s- User's saltI- Usernamep- Cleartext passwordH()- One-way hash function (SHA-256)x- Private key derived from password and saltv- Password verifier stored on servera,b- Secret ephemeral valuesA,B- Public ephemeral valuesS- Premaster secretK- Session keyM1,M2- Proofs
x = H(s || H(I || ":" || p)) # Private key
v = g^x % N # Verifier (stored on server)
The server stores: (I, s, v). The password p is never stored.
Client Server
------ ------
| |
| -------- I, A = g^a % N ------> |
| |
| <------- s, B = kv + g^b % N -- |
| |
| u = H(pad(A) || pad(B)) | u = H(pad(A) || pad(B))
| x = H(s || H(I || ":" || p)) |
| S = (B - kg^x)^(a + ux) % N | S = (Av^u)^b % N
| K = H(S) | K = H(S)
| |
| -------- M1 = H(...) ----------> | (verify M1)
| |
| (verify M2) <------ M2 = H(...) -- |
| |
| [Session key K established] |
- Generate random
a, computeA = g^a % N - Receive
s,Bfrom server - Compute
u = H(pad(A) || pad(B)) - Compute
k = H(N || pad(g)) - Derive
x = H(s || H(I || ":" || p)) - Compute
S = (B - k * g^x)^(a + u*x) % N - Compute session key
K = H(S) - Compute proof
M1 = H(H(N) XOR H(g) || H(I) || s || A || B || K)
- Look up
s,vfor userI - Generate random
b, computeB = k*v + g^b % N - Receive
Afrom client - Compute
u = H(pad(A) || pad(B)) - Compute
S = (A * v^u)^b % N - Compute session key
K = H(S) - Verify client proof
M1 - Compute server proof
M2 = H(A || M1 || K)
The protocol aborts if any of these conditions occur:
- Client aborts if
B % N == 0(malicious server) - Client aborts if
u == 0(compromised exchange) - Server aborts if
A % N == 0(malicious client) - Server aborts if client proof
M1is invalid
Client Server
------ ------
| |
| -------- username, A --------> |
| |
| <------- salt, B ------------- |
| |
| -------- M1 (proof) ---------> |
| |
| <------- M2 (verification) --- |
| |
| [Session key K established] |
See the examples directory for complete working examples:
- 01_signup.py - User registration, generating salt and verifier
- 02_authentication.py - Complete authentication handshake
- 03_different_groups.py - Using different prime group sizes
- 04_hashcash.py - Hash cash proof-of-work for rate limiting
Run examples:
python examples/01_signup.py
python examples/02_authentication.py- RFC 2945 - The SRP Authentication and Key Exchange System
- RFC 5054 - Using SRP for TLS Authentication
- Stanford SRP Homepage
MIT License - see LICENSE for details.