SRP-6a (Secure Remote Password Protocol, Version 6a) is a cryptographic protocol that allows secure authentication without the server ever knowing the user's password. In this deep dive, we'll explore how ZeroNote uses SRP-6a to ensure your authentication data remains completely private.

๐Ÿ” What is SRP-6a?

The Secure Remote Password (SRP) protocol is a zero-knowledge proof authentication system. Unlike traditional password authentication where the server stores password hashes, SRP-6a allows the server to verify that a client knows the password without the server ever learning what that password is.

๐ŸŽฏ Key Benefits of SRP-6a

  • Zero-Knowledge: Server never sees the password
  • Mutual Authentication: Both client and server prove their identity
  • Forward Secrecy: Past sessions remain secure even if long-term secrets are compromised
  • Resistance to Attacks: Protected against dictionary, replay, and man-in-the-middle attacks

๐Ÿงฎ The Mathematics Behind SRP-6a

SRP-6a is based on the discrete logarithm problem in finite fields. Here's the mathematical foundation:

Setup Parameters


N = Large safe prime (typically 2048+ bits)
g = Generator modulo N
k = Multiplier parameter (k = H(N, g))
H() = Cryptographic hash function (SHA-256)
        

Registration Phase

When a user registers, the following happens:


// Client side (registration)
const password = "user_password";
const salt = crypto.getRandomValues(new Uint8Array(32));

// Derive password verifier
const x = H(salt + H(username + ":" + password));
const v = g^x mod N;

// Send to server: username, salt, v (verifier)
// Server stores: username, salt, v
// Password is never transmitted or stored!
        

๐Ÿ”„ The Authentication Dance

The SRP-6a authentication process involves a carefully choreographed exchange of cryptographic values:

Step 1: Client Initiates


// Client generates ephemeral keypair
const a = randomBigInt(); // Private ephemeral key
const A = g^a mod N;      // Public ephemeral key

// Send username and A to server
        

Step 2: Server Responds


// Server generates its ephemeral keypair
const b = randomBigInt(); // Private ephemeral key
const B = (k*v + g^b) mod N; // Public ephemeral key

// Server sends salt and B to client
        

Step 3: Both Sides Compute Session Key


// Client side computation
const u = H(A + B);
const x = H(salt + H(username + ":" + password));
const S_client = (B - k*g^x)^(a + u*x) mod N;
const K_client = H(S_client);

// Server side computation  
const u = H(A + B);
const S_server = (A * v^u)^b mod N;
const K_server = H(S_server);

// If authentication is successful: K_client === K_server
        

๐Ÿ›ก๏ธ Security Proofs and Verification

The final step involves mutual proof of knowledge:


// Client proves knowledge of password
const M1 = H(A + B + K_client);

// Server verifies and responds with proof
const M2 = H(A + M1 + K_client);

// Both sides now have authenticated session key K
        

โšก ZeroNote's SRP-6a Implementation

At ZeroNote, we've implemented SRP-6a with additional security enhancements:

Enhanced Security Features

  • 4096-bit safe primes for maximum security
  • PBKDF2 key stretching before SRP-6a computation
  • Constant-time operations to prevent timing attacks
  • Session binding to prevent session hijacking
  • Rate limiting on authentication attempts

Code Example: ZeroNote SRP-6a Client


class ZeroNoteSRPClient {
    constructor() {
        this.N = BigInt('0x' + ZERONOTE_SRP_PRIME_4096);
        this.g = BigInt(2);
        this.k = this.computeK();
    }

    async authenticate(username, password) {
        // Step 1: Generate client ephemeral
        this.a = this.generatePrivateEphemeral();
        this.A = this.modPow(this.g, this.a, this.N);

        // Step 2: Send username and A, receive salt and B
        const response = await fetch('/api/auth/challenge', {
            method: 'POST',
            body: JSON.stringify({ username, A: this.A.toString(16) })
        });
        
        const { salt, B } = await response.json();
        this.B = BigInt('0x' + B);

        // Step 3: Compute session key
        const u = this.computeU(this.A, this.B);
        const x = await this.computeX(salt, username, password);
        const S = this.computeClientS(this.B, this.k, this.g, x, this.a, u);
        this.K = await this.hashBigInt(S);

        // Step 4: Generate proof
        const M1 = await this.computeM1(this.A, this.B, this.K);
        
        // Step 5: Send proof and verify server response
        const authResponse = await fetch('/api/auth/verify', {
            method: 'POST',
            body: JSON.stringify({ M1: M1.toString(16) })
        });

        const { M2, sessionToken } = await authResponse.json();
        
        // Verify server proof
        const expectedM2 = await this.computeM2(this.A, M1, this.K);
        if (M2 !== expectedM2.toString(16)) {
            throw new Error('Server authentication failed');
        }

        return { sessionToken, sessionKey: this.K };
    }

    // ... implementation details ...
}
        

๐Ÿ” Common SRP-6a Vulnerabilities and Mitigations

Small Subgroup Attacks

Vulnerability: Malicious clients can choose special values for A that belong to small subgroups.
Mitigation: Always validate that A and B are in the correct range and not zero.

2-for-1 Dictionary Attacks

Vulnerability: Attacker can test two passwords per authentication attempt.
Mitigation: Use proper parameter validation and rate limiting.

Implementation Pitfalls

โš ๏ธ Critical Implementation Notes

  • Never reuse ephemeral values (a, b)
  • Always use cryptographically secure random number generation
  • Implement constant-time comparisons for M1/M2 verification
  • Validate all received parameters before computation
  • Use safe primes and verify generator properties

๐Ÿš€ Performance Considerations

SRP-6a involves multiple large number exponentiations, which can be computationally expensive. ZeroNote optimizes performance through:

  • Precomputed tables for common exponentiations
  • Montgomery ladder for efficient modular exponentiation
  • WebAssembly implementation for client-side performance
  • Caching of session keys for subsequent requests

๐Ÿ”— Integration with ZeroNote's Architecture

SRP-6a is just one component of ZeroNote's comprehensive security architecture:

  1. SRP-6a Authentication: Proves user identity without revealing password
  2. Derived Session Keys: Used for encrypting subsequent API communications
  3. Note Encryption: Separate encryption keys derived from user input
  4. Forward Secrecy: Each session uses unique ephemeral keys

๐Ÿ“š Further Reading

Want to dive deeper into SRP-6a? Here are some excellent resources:

๐ŸŽฏ Key Takeaways

SRP-6a represents the gold standard for password-based authentication in zero-knowledge systems. By implementing SRP-6a, ZeroNote ensures that even we, as the service provider, never have access to your passwords. This is cryptographic proof that your authentication data remains private, even from us.