Skip to content

Security: mzattahri/srp

Security

SECURITY.md

Security Policy

Security Considerations

Verifier Storage

The verifier value computed by ComputeVerifier is a cryptographic secret that MUST be:

  • Encrypted at rest in your database
  • Protected with appropriate access controls
  • Treated with the same care as password hashes
  • Never transmitted over unencrypted connections
  • Never logged or exposed in error messages

Server State Persistence

When using Server.Save() for stateless architectures:

  • The returned state contains sensitive cryptographic material
  • Always encrypt the state before storage (e.g., encrypted session store, JWE)
  • Use authenticated encryption (e.g., AES-GCM)
  • Set appropriate expiration times
  • Never expose the state in URLs or logs

Parameter Selection

Recommended configuration for production:

import (
    "crypto"
    "runtime"
    _ "crypto/sha256"
    "golang.org/x/crypto/argon2"
    "mz.attahri.com/code/srp/v2"
)

func SecureKDF(username, password string, salt []byte) ([]byte, error) {
    p := []byte(username + ":" + password)
    // Argon2id with reasonable parameters
    key := argon2.IDKey(p, salt, 3, 256*1024, runtime.NumCPU(), 32)
    return key, nil
}

var SecureParams = &srp.Params{
    Name:  "DH4096-SHA256-Argon2",
    Group: srp.RFC5054Group4096,  // 4096-bit or larger
    Hash:  crypto.SHA256,           // SHA256 or stronger
    KDF:   SecureKDF,               // Modern KDF (Argon2, scrypt)
}

Do NOT use in production:

  • RFC5054Group1024 or RFC5054Group1536 (too small)
  • RFC5054KDF with SHA1 (deprecated, for RFC compatibility only)
  • Custom KDFs without proper password stretching

Input Validation

The library validates:

  • Username: max 255 bytes (MaxUsernameLength)
  • Password: max 1024 bytes (MaxPasswordLength)
  • Salt: minimum 8 bytes (MinSaltLength), default 16 bytes (SaltLength)

Applications SHOULD additionally:

  • Enforce password complexity requirements
  • Implement rate limiting on authentication attempts
  • Monitor for brute force attacks
  • Use account lockout mechanisms

Rate Limiting

Implement rate-limiting.

// Example: Implement rate limiting before SRP authentication
if rateLimiter.IsExceeded(username) {
    return ErrTooManyAttempts
}

server, err := srp.NewServer(params, username, salt, verifier)
// ... continue SRP flow

Transport Security

Always use TLS when:

  • Transmitting the verifier during registration
  • Conducting SRP authentication
  • Exchanging ephemeral keys (A, B, M1, M2)

SRP protects against eavesdropping on the password itself, but the protocol messages must still be protected against man-in-the-middle attacks.

Salt Management

  • Generate salts with NewSalt() or NewSaltWithLength()
  • Use a unique salt per user
  • Salts can be public - they should be retrievable without authentication
  • Minimum 8 bytes, recommended 12-16 bytes
  • Never reuse salts across users

Session Keys

The shared session key from SessionKey():

  • Is ephemeral and unique per session
  • Can be used for additional encryption beyond TLS
  • Should be cleared from memory after use
  • Should have a limited lifetime

Threat Model

SRP protects against:

  • Password database breaches (verifiers are not passwords)
  • Passive eavesdropping
  • Dictionary attacks on intercepted traffic

SRP does NOT protect against:

  • Malware on client or server
  • Phishing attacks
  • Weak passwords
  • Side-channel attacks
  • Quantum computers (future threat)

There aren't any published security advisories