CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sjcl

Stanford JavaScript Crypto Library providing comprehensive cryptographic operations including AES encryption, hash functions, key derivation, and elliptic curve cryptography.

Pending
Overview
Eval results
Files

key-exchange.mddocs/

Key Exchange

SJCL provides Secure Remote Password (SRP) protocol implementation for password-authenticated key agreement, allowing secure authentication and key derivation without transmitting passwords over the network.

Capabilities

SRP (Secure Remote Password)

The Secure Remote Password protocol allows two parties to authenticate each other and derive a shared secret using only a password, without ever transmitting the password itself.

/**
 * Calculate SRP verifier for user registration
 * @param {string} I - Username/identity
 * @param {string} P - Password
 * @param {BitArray} s - Salt (random value)
 * @param {Object} [group] - SRP group parameters (default: SRP-6a with 1024-bit prime)
 * @returns {BitArray} SRP verifier value
 */
sjcl.keyexchange.srp.makeVerifier(I, P, s, group);

/**
 * Calculate SRP x value (private key derived from password)
 * @param {string} I - Username/identity
 * @param {string} P - Password
 * @param {BitArray} s - Salt value
 * @returns {BitArray} SRP x value (private key)
 */
sjcl.keyexchange.srp.makeX(I, P, s);

Usage Examples:

const sjcl = require('sjcl');

// User registration phase
function registerUser(username, password) {
  // Generate random salt
  const salt = sjcl.random.randomWords(4); // 128-bit salt
  
  // Calculate verifier for storage on server
  const verifier = sjcl.keyexchange.srp.makeVerifier(username, password, salt);
  
  // Store username, salt, and verifier on server
  // NEVER store the actual password
  return {
    username: username,
    salt: salt,
    verifier: verifier
  };
}

// Example registration
const userRecord = registerUser("alice@example.com", "strongPassword123");
console.log("User registered with salt:", sjcl.codec.hex.fromBits(userRecord.salt));
console.log("Verifier:", sjcl.codec.hex.fromBits(userRecord.verifier));

// Calculate x value (used internally during authentication)
const xValue = sjcl.keyexchange.srp.makeX("alice@example.com", "strongPassword123", userRecord.salt);
console.log("X value:", sjcl.codec.hex.fromBits(xValue));

SRP Protocol Overview

The SRP protocol consists of several phases:

1. Registration Phase

During user registration, the client calculates a verifier that the server stores instead of the password.

const sjcl = require('sjcl');

function srpRegistration(username, password) {
  // Client generates salt (or server can generate and send to client)
  const salt = sjcl.random.randomWords(4);
  
  // Client calculates verifier
  const verifier = sjcl.keyexchange.srp.makeVerifier(username, password, salt);
  
  // Send username, salt, and verifier to server for storage
  return {
    username: username,
    salt: sjcl.codec.hex.fromBits(salt),
    verifier: sjcl.codec.hex.fromBits(verifier)
  };
}

// Usage
const registration = srpRegistration("user@domain.com", "mySecurePassword");
console.log("Registration data:", registration);

2. Authentication Phase

During authentication, both client and server perform calculations to verify the password without transmitting it.

const sjcl = require('sjcl');

// Client-side authentication start
function clientAuthStart(username, password, saltFromServer) {
  // Convert salt from hex if received from server
  const salt = sjcl.codec.hex.toBits(saltFromServer);
  
  // Calculate x (private key)
  const x = sjcl.keyexchange.srp.makeX(username, password, salt);
  
  // In full SRP implementation, client would also:
  // 1. Generate random 'a' value
  // 2. Calculate A = g^a mod N (public key)
  // 3. Send A to server
  
  return {
    x: x,
    // Additional SRP values would be calculated here
  };
}

// Server-side verification preparation
function serverPrepareAuth(storedUserRecord) {
  // Server has stored: username, salt, verifier
  // In full SRP implementation, server would:
  // 1. Generate random 'b' value
  // 2. Calculate B = (kv + g^b) mod N
  // 3. Send B and salt to client
  
  return {
    salt: storedUserRecord.salt,
    // B value would be calculated and included
  };
}

SRP Security Properties

Key Features

  1. Password Never Transmitted: The actual password never goes over the network
  2. Zero-Knowledge: Server learns nothing about the password
  3. Mutual Authentication: Both parties verify each other's identity
  4. Forward Secrecy: Session keys are ephemeral
  5. Offline Attack Resistance: Server compromise doesn't immediately reveal passwords

Security Considerations

const sjcl = require('sjcl');

// Best practices for SRP implementation
class SRPBestPractices {
  static generateSecureSalt() {
    // Use at least 128 bits of random salt
    return sjcl.random.randomWords(4);
  }
  
  static validateUsername(username) {
    // Normalize username to prevent attacks
    return username.toLowerCase().trim();
  }
  
  static strengthenPassword(password) {
    // Consider additional password strengthening
    // This is a simplified example
    if (password.length < 8) {
      throw new Error("Password too short");
    }
    return password;
  }
  
  static secureRegistration(username, password) {
    const normalizedUsername = SRPBestPractices.validateUsername(username);
    const strengthenedPassword = SRPBestPractices.strengthenPassword(password);
    const salt = SRPBestPractices.generateSecureSalt();
    
    const verifier = sjcl.keyexchange.srp.makeVerifier(
      normalizedUsername, 
      strengthenedPassword, 
      salt
    );
    
    return {
      username: normalizedUsername,
      salt: salt,
      verifier: verifier,
      timestamp: Date.now()
    };
  }
}

// Usage with best practices
try {
  const secureReg = SRPBestPractices.secureRegistration("User@Example.com", "MyStrongPassword123!");
  console.log("Secure registration successful");
} catch (error) {
  console.error("Registration failed:", error.message);
}

Advanced SRP Usage

Custom Group Parameters

SRP can use different mathematical groups for different security levels:

const sjcl = require('sjcl');

// Example of using SRP with custom parameters
function srpWithCustomGroup(username, password, salt, customGroup) {
  // Custom group would define different prime modulus and generator
  // This is an advanced feature for specific security requirements
  
  const verifier = sjcl.keyexchange.srp.makeVerifier(
    username, 
    password, 
    salt, 
    customGroup
  );
  
  return verifier;
}

// Note: Custom groups require careful cryptographic analysis
// Default parameters are recommended for most applications

SRP with Additional Key Derivation

Combine SRP with other key derivation methods:

const sjcl = require('sjcl');

function enhancedSRPRegistration(username, password, additionalEntropy) {
  // Generate salt
  const salt = sjcl.random.randomWords(4);
  
  // Optional: Strengthen password with additional entropy
  const strengthenedPassword = password + additionalEntropy;
  
  // Calculate SRP verifier
  const verifier = sjcl.keyexchange.srp.makeVerifier(username, strengthenedPassword, salt);
  
  // Derive additional keys using HKDF
  const masterKey = sjcl.misc.hkdf(
    verifier,
    256,
    salt,
    sjcl.codec.utf8String.toBits("SRP-master-key")
  );
  
  const authKey = sjcl.misc.hkdf(
    masterKey,
    256,
    salt,
    sjcl.codec.utf8String.toBits("authentication")
  );
  
  return {
    username: username,
    salt: salt,
    verifier: verifier,
    authKey: authKey
  };
}

// Usage
const enhancedReg = enhancedSRPRegistration(
  "user@example.com", 
  "password123", 
  "device-specific-entropy"
);

Integration Examples

Web Application Integration

Example of integrating SRP into a web application:

const sjcl = require('sjcl');

class WebSRPClient {
  constructor(apiEndpoint) {
    this.apiEndpoint = apiEndpoint;
  }
  
  async register(username, password) {
    // Client-side registration
    const salt = sjcl.random.randomWords(4);
    const verifier = sjcl.keyexchange.srp.makeVerifier(username, password, salt);
    
    // Send to server
    const registrationData = {
      username: username,
      salt: sjcl.codec.hex.fromBits(salt),
      verifier: sjcl.codec.hex.fromBits(verifier)
    };
    
    // In real implementation, this would be an HTTP request
    console.log("Would send to server:", registrationData);
    return true;
  }
  
  async authenticate(username, password) {
    // Step 1: Get salt from server
    // const { salt } = await fetch(`${this.apiEndpoint}/auth/salt/${username}`);
    
    // Step 2: Calculate client credentials
    const salt = sjcl.random.randomWords(4); // In real app, from server
    const x = sjcl.keyexchange.srp.makeX(username, password, salt);
    
    // Step 3: Continue with full SRP protocol
    // (Additional steps would involve A/B value exchange)
    
    console.log("Authentication x value calculated");
    return { success: true, sessionKey: "derived-session-key" };
  }
}

// Usage
const srpClient = new WebSRPClient("https://api.example.com");
// srpClient.register("user@example.com", "securePassword");

Security Recommendations

  1. Salt Generation: Always use cryptographically secure random salts (≥128 bits)
  2. Password Policy: Enforce strong password requirements
  3. Username Handling: Normalize usernames consistently
  4. Timing Attacks: Be aware that SRP operations are not constant-time
  5. Group Parameters: Use well-vetted SRP group parameters
  6. Protocol Completion: Implement the full SRP protocol, not just verifier generation
  7. Session Management: Properly manage derived session keys
  8. Transport Security: Always use SRP over secure channels (HTTPS/TLS)

Common Use Cases

  1. Password-Based Authentication: Secure login without password transmission
  2. Zero-Knowledge Proofs: Prove password knowledge without revealing it
  3. Mutual Authentication: Both client and server authenticate each other
  4. Key Agreement: Derive shared session keys from passwords
  5. Enterprise SSO: Single sign-on systems requiring password verification
  6. Secure Messaging: Authenticate messaging clients without storing passwords

Limitations

  1. Protocol Complexity: SRP requires careful implementation of the full protocol
  2. Performance: More computationally expensive than simple password hashing
  3. Implementation Risk: Incorrect implementation can compromise security
  4. Limited Library Support: Not all platforms have mature SRP implementations
  5. User Experience: May require additional steps compared to traditional authentication

Install with Tessl CLI

npx tessl i tessl/npm-sjcl

docs

big-number-arithmetic.md

bit-array-utilities.md

cipher-modes.md

data-encoding.md

elliptic-curve-cryptography.md

hash-functions.md

high-level-encryption.md

index.md

key-derivation.md

key-exchange.md

message-authentication.md

random-number-generation.md

symmetric-encryption.md

tile.json