React Native Quick Crypto
API Reference

DiffieHellman

Secure key exchange protocol

The Diffie-Hellman module implements the Diffie-Hellman key exchange protocol, allowing two parties to establish a shared secret over an insecure channel without ever transmitting the secret itself. This is fundamental to secure communication protocols like TLS, SSH, and VPNs.

Real-World Applications

TLS/SSL handshakes, VPN connections (IPsec, WireGuard), secure messaging protocols (Signal, WhatsApp), SSH key exchange, and P2P encrypted file sharing.

Table of Contents

Theory

The Diffie-Hellman protocol allows two parties (Alice and Bob) to agree on a shared secret even when all their communication is being monitored:

  1. Public Parameters: Both parties agree on a large prime number pp and a generator gg
  2. Private Keys: Alice picks random secret aa, Bob picks random secret bb (never shared)
  3. Public Keys: Alice computes A=ga(modp)A = g^a \pmod p, Bob computes B=gb(modp)B = g^b \pmod p
  4. Exchange: Alice sends AA to Bob, Bob sends BB to Alice (safe even if intercepted!)
  5. Shared Secret: Both compute the same secret ss:
s=Ba(modp)=(gb)a(modp)=gba(modp)s = B^a \pmod p = (g^b)^a \pmod p = g^{ba} \pmod p s=Ab(modp)=(ga)b(modp)=gab(modp)s = A^b \pmod p = (g^a)^b \pmod p = g^{ab} \pmod p

The security relies on the Discrete Logarithm Problem: Given g, p, and g^a, it's computationally infeasible to find a.

Example

Think of it like mixing paint: Alice and Bob each start with a common color (yellow), add their secret color (Alice adds red, Bob adds blue), exchange the mixed colors publicly, then add their secret color again. Both end up with the same final color (brown), but an observer can't recreate it without knowing the secret colors.


Class: DiffieHellman

The DiffieHellman class implements the Diffie-Hellman key agreement protocol. Instances are created using getDiffieHellman() for standard groups or createDiffieHellman() for custom parameters.

dh.generateKeys([encoding])

Generates private and public Diffie-Hellman key values. Must be called before computeSecret().

Parameters:

NameTypeDescription
encodingstringOptional encoding for the return value: 'hex', 'base64', or 'base64url'. If omitted, returns Buffer

Returns: Buffer or string - The public key

Examples:

import { getDiffieHellman } from 'react-native-quick-crypto';

const dh = getDiffieHellman('modp15');

// Generate keys and get public key as Buffer
const publicKey = dh.generateKeys();
console.log('Public key:', publicKey.toString('hex'));

// Generate keys and get public key as hex string
const publicKeyHex = dh.generateKeys('hex');

// Generate keys and get public key as base64
const publicKeyB64 = dh.generateKeys('base64');

Important: Each call to generateKeys() creates a new key pair. Call it only once per DH instance.


dh.computeSecret(otherPublicKey[, inputEncoding][, outputEncoding])

Computes the shared secret using otherPublicKey as the other party's public key.

Parameters:

NameTypeDescription
otherPublicKeystring | Buffer | TypedArray | DataViewThe other party's public key
inputEncodingstringEncoding of otherPublicKey if it's a string: 'hex', 'base64', or 'base64url'
outputEncodingstringEncoding for the return value: 'hex', 'base64', or 'base64url'. If omitted, returns Buffer

Returns: Buffer or string - The computed shared secret

Important: The shared secret should be hashed before use as an encryption key to remove structural weaknesses.

Examples:

import { getDiffieHellman } from 'react-native-quick-crypto';

// Alice's side
const alice = getDiffieHellman('modp15');
const alicePublicKey = alice.generateKeys();

// Bob's side
const bob = getDiffieHellman('modp15');
const bobPublicKey = bob.generateKeys();

// Compute shared secret (both get the same value!)
const aliceSecret = alice.computeSecret(bobPublicKey);
const bobSecret = bob.computeSecret(alicePublicKey);

console.log(aliceSecret.equals(bobSecret)); // true

// With hex encoding
const aliceSecretHex = alice.computeSecret(bobPublicKey.toString('hex'), 'hex', 'hex');

dh.getPublicKey([encoding])

Returns the Diffie-Hellman public key.

Parameters:

NameTypeDescription
encodingstringOptional encoding: 'hex', 'base64', or 'base64url'

Returns: Buffer or string

Examples:

const dh = getDiffieHellman('modp14');
dh.generateKeys();

const publicKey = dh.getPublicKey(); // Buffer
const publicKeyHex = dh.getPublicKey('hex'); // string

dh.getPrivateKey([encoding])

Returns the Diffie-Hellman private key. Never transmit this value!

Parameters:

NameTypeDescription
encodingstringOptional encoding: 'hex', 'base64', or 'base64url'

Returns: Buffer or string

Security Warning: The private key must be kept secret. Anyone who obtains it can compute the shared secret.


dh.getPrime([encoding])

Returns the Diffie-Hellman prime.

Parameters:

NameTypeDescription
encodingstringOptional encoding: 'hex', 'base64', or 'base64url'

Returns: Buffer or string


dh.getGenerator([encoding])

Returns the Diffie-Hellman generator.

Parameters:

NameTypeDescription
encodingstringOptional encoding: 'hex', 'base64', or base64url'

Returns: Buffer or string


dh.setPublicKey(publicKey[, encoding])

Sets the Diffie-Hellman public key. Useful for restoring a DH instance from saved state.

Parameters:

NameTypeDescription
publicKeystring | BufferThe public key to set
encodingstringEncoding of publicKey if it's a string

dh.setPrivateKey(privateKey[, encoding])

Sets the Diffie-Hellman private key. Useful for restoring a DH instance from saved state.

Parameters:

NameTypeDescription
privateKeystring | BufferThe private key to set
encodingstringEncoding of privateKey if it's a string

Module Methods

getDiffieHellman(groupName)

Creates a DiffieHellman instance using a standardized, well-known group. Recommended for most applications.

Parameters:

NameTypeDescription
groupNamestringName of the standard group (see Standard Groups)

Returns: DiffieHellman instance

Examples:

import { getDiffieHellman } from 'react-native-quick-crypto';

// 2048-bit group (minimum for modern use)
const dh2048 = getDiffieHellman('modp14');

// 3072-bit group (recommended)
const dh3072 = getDiffieHellman('modp15');

// 4096-bit group (high security)
const dh4096 = getDiffieHellman('modp16');

createDiffieHellman(prime[, primeEncoding][, generator][, generatorEncoding])

Creates a DiffieHellman instance with custom parameters. Advanced use only - use standard groups unless you have specific requirements.

Parameters:

NameTypeDescription
primenumber | string | BufferPrime number (if number, generates prime of that bit length)
primeEncodingstringEncoding of prime if it's a string: 'hex', 'base64'
generatornumber | string | BufferGenerator (default: 2)
generatorEncodingstringEncoding of generator if it's a string

Returns: DiffieHellman instance

Examples:

import { createDiffieHellman } from 'react-native-quick-crypto';

// Generate new 2048-bit prime (slow! - do once and save)
const dh = createDiffieHellman(2048);
const prime = dh.getPrime('hex');
const generator = dh.getGenerator('hex');

// Later, reuse the same parameters
const dh2 = createDiffieHellman(prime, 'hex', generator, 'hex');

Warning: Generating custom primes is very slow and requires cryptographic expertise to avoid weak parameters. Use standard groups instead.


Standard Groups

Standardized Diffie-Hellman groups from RFC 3526 and RFC 5114. These are well-tested, secure, and widely compatible.

GroupBitsSecurity LevelUse Case
modp142048~112-bitMinimum for modern applications
modp153072~128-bitRecommended general purpose
modp164096~152-bitHigh security applications
modp176144~176-bitVery high security
modp188192~192-bitMaximum security

Recommendation: Use modp15 (3072-bit) or higher for new applications.

import { getDiffieHellman } from 'react-native-quick-crypto';

// ✅ Good - Modern security
const dh = getDiffieHellman('modp15');

// ✅ Better - High security
const dh = getDiffieHellman('modp16');

// ⚠️ Acceptable but minimum - Upgrade if possible
const dh = getDiffieHellman('modp14');

Real-World Examples

Example 1: Secure Chat Application

End-to-end encrypted messaging using ephemeral Diffie-Hellman:

import {
  getDiffieHellman,
  createHash,
  createCipheriv,
  createDecipheriv,
  randomBytes
} from 'react-native-quick-crypto';

class SecureChatSession {
  private dh: any;
  private sessionKey?: Buffer;

  constructor(curveName: string = 'modp15') {
    // Create new DH instance for this session (Perfect Forward Secrecy)
    this.dh = getDiffieHellman('modp15');
    this.dh.generateKeys();
  }

  getPublicKey(): string {
    return this.dh.getPublicKey('base64');
  }

  establishSession(peerPublicKeyB64: string): void {
    const peerPublicKey = Buffer.from(peerPublicKeyB64, 'base64');
    const sharedSecret = this.dh.computeSecret(peerPublicKey);

    // Derive session key using SHA-256
    const hash = createHash('sha256');
    hash.update(sharedSecret);
    hash.update('chat-session-key'); // Application-specific salt
    this.sessionKey = hash.digest();

    console.log('Secure session established!');
  }

  encryptMessage(message: string): { iv: string; ciphertext: string } {
    if (!this.sessionKey) throw new Error('Session not established');

    const iv = randomBytes(16);
    const cipher = createCipheriv('aes-256-cbc', this.sessionKey, iv);

    let ciphertext = cipher.update(message, 'utf8', 'base64');
    ciphertext += cipher.final('base64');

    return {
      iv: iv.toString('base64'),
      ciphertext
    };
  }

  decryptMessage(encrypted: { iv: string; ciphertext: string }): string {
    if (!this.sessionKey) throw new Error('Session not established');

    const iv = Buffer.from(encrypted.iv, 'base64');
    const decipher = createDecipheriv('aes-256-cbc', this.sessionKey, iv);

    let message = decipher.update(encrypted.ciphertext, 'base64', 'utf8');
    message += decipher.final('utf8');

    return message;
  }
}

// Usage
const alice = new SecureChatSession();
const bob = new SecureChatSession();

// Exchange public keys
const alicePubKey = alice.getPublicKey();
const bobPubKey = bob.getPublicKey();

// Establish sessions
alice.establishSession(bobPubKey);
bob.establishSession(alicePubKey);

// Send encrypted message
const encrypted = alice.encryptMessage('Hello Bob!');
const decrypted = bob.decryptMessage(encrypted);
console.log(decrypted); // "Hello Bob!"

Example 2: Perfect Forward Secrecy

Implement Perfect Forward Secrecy by using ephemeral (one-time) DH keys:

import { getDiffieHellman, createHash } from 'react-native-quick-crypto';

class SecureConnection {
  private longTermPublicKey: Buffer;
  private longTermPrivateKey: Buffer;

  constructor() {
    // Long-term identity keys (saved, reused)
    const identity = getDiffieHellman('modp15');
    identity.generateKeys();
    this.longTermPublicKey = identity.getPublicKey();
    this.longTermPrivateKey = identity.getPrivateKey();
  }

  createEphemeralSession(peerLongTermPublicKey: Buffer): {
    ephemeralPublicKey: Buffer;
    sessionKey: Buffer;
  } {
    // Generate NEW ephemeral DH keys for this session only
    const ephemeral = getDiffieHellman('modp15');
    const ephemeralPublicKey = ephemeral.generateKeys();

    // Compute shared secret using ephemeral keys
    const ephemeralSecret = ephemeral.computeSecret(peerLongTermPublicKey);

    // Derive session key
    const hash = createHash('sha256');
    hash.update(ephemeralSecret);
    hash.update(this.longTermPublicKey); // Mix in identity
    hash.update(peerLongTermPublicKey);
    const sessionKey = hash.digest();

    // Discard ephemeral private key after use
    // Even if long-term keys are later compromised,
    // this session cannot be decrypted!

    return {
      ephemeralPublicKey,
      sessionKey
    };
  }
}

// Usage
const alice = new SecureConnection();
const bob = new SecureConnection();

// Alice creates session
const aliceSession = alice.createEphemeralSession(bob.longTermPublicKey);

// Each session uses different ephemeral keys
// Past sessions remain secure even if current keys are compromised

Example 3: Authenticated Diffie-Hellman

Prevent Man-in-the-Middle attacks by signing public keys:

import {
  getDiffieHellman,
  createSign,
  createVerify,
  createHash,
  generateKeyPairSync
} from 'react-native-quick-crypto';

class AuthenticatedDH {
  private dh: any;
  private signingKeys: { publicKey: any; privateKey: any };

  constructor() {
    // DH for key exchange
    this.dh = getDiffieHellman('modp15');
    this.dh.generateKeys();

    // RSA for authentication
    this.signingKeys = generateKeyPairSync('rsa', {
      modulusLength: 2048
    });
  }

  getSignedPublicKey(): {
    dhPublicKey: string;
    signature: string;
    signingPublicKey: any;
  } {
    const dhPublicKey = this.dh.getPublicKey('base64');

    // Sign DH public key with RSA key
    const sign = createSign('SHA256');
    sign.update(dhPublicKey);
    const signature = sign.sign(this.signingKeys.privateKey, 'base64');

    return {
      dhPublicKey,
      signature,
      signingPublicKey: this.signingKeys.publicKey
    };
  }

  verifyAndEstablishSecret(peerData: {
    dhPublicKey: string;
    signature: string;
    signingPublicKey: any;
  }): Buffer {
    // Verify peer's signature
    const verify = createVerify('SHA256');
    verify.update(peerData.dhPublicKey);
    const isValid = verify.verify(
      peerData.signingPublicKey,
      peerData.signature,
      'base64'
    );

    if (!isValid) {
      throw new Error('Peer authentication failed! MITM attack detected.');
    }

    // Compute shared secret
    const peerDHKey = Buffer.from(peerData.dhPublicKey, 'base64');
    const sharedSecret = this.dh.computeSecret(peerDHKey);

    // Hash the secret
    const hash = createHash('sha256');
    hash.update(sharedSecret);
    return hash.digest();
  }
}

// Usage
const alice = new AuthenticatedDH();
const bob = new AuthenticatedDH();

// Exchange signed public keys
const aliceData = alice.getSignedPublicKey();
const bobData = bob.getSignedPublicKey();

// Establish secrets (verified!)
try {
  const aliceSecret = alice.verifyAndEstablishSecret(bobData);
  const bobSecret = bob.verifyAndEstablishSecret(aliceData);
  
  console.log(aliceSecret.equals(bobSecret)); // true
  console.log('Authenticated secure channel established!');
} catch (error) {
  console.error('Authentication failed:', error.message);
}

Example 4: Multi-Party Key Agreement

Three-party Diffie-Hellman for group messaging:

import { getDiffieHellman, createHash } from 'react-native-quick-crypto';

// Simple 3-party DH using pairwise secrets
class ThreePartyDH {
  private dh: any;
  private name: string;

  constructor(name: string) {
    this.name = name;
    this.dh = getDiffieHellman('modp14');
    this.dh.generateKeys();
  }

  getPublicKey(): Buffer {
    return this.dh.getPublicKey();
  }

  computeGroupKey(
    peer1PublicKey: Buffer,
    peer2PublicKey: Buffer
  ): Buffer {
    // Compute pairwise secrets
    const secret1 = this.dh.computeSecret(peer1PublicKey);
    const secret2 = this.dh.computeSecret(peer2PublicKey);

    // Combine secrets deterministically
    const combined = Buffer.concat([
      secret1.length < secret2.length ? secret1 : secret2,
      secret1.length < secret2.length ? secret2 : secret1
    ]);

    // Derive group key
    const hash = createHash('sha256');
    hash.update(combined);
    hash.update('group-key-v1');
    return hash.digest();
  }
}

// Usage: Alice, Bob, and Charlie all compute the same group key
const alice = new ThreePartyDH('Alice');
const bob = new ThreePartyDH('Bob');
const charlie = new ThreePartyDH('Charlie');

const alicePub = alice.getPublicKey();
const bobPub = bob.getPublicKey();
const charliePub = charlie.getPublicKey();

const aliceGroupKey = alice.computeGroupKey(bobPub, charliePub);
const bobGroupKey = bob.computeGroupKey(alicePub, charliePub);
const charlieGroupKey = charlie.computeGroupKey(alicePub, bobPub);

// All three compute the same group key!
console.log(aliceGroupKey.equals(bobGroupKey)); // true
console.log(bobGroupKey.equals(charlieGroupKey)); // true

Security Considerations

Critical Security Rules

  1. Use standard groups - modp15 or higher for new applications
  2. Hash the shared secret - Never use raw DH output as encryption key
  3. Authenticate peers - Vanilla DH is vulnerable to MITM attacks
  4. Use ephemeral keys - Generate new DH keys per session (Perfect Forward Secrecy)
  5. Minimum 2048 bits - Smaller groups are vulnerable to pre-computation attacks

Best Practices

1. Group Selection:

// ✅ Good - Modern security
const dh = getDiffieHellman('modp15');

// ✅ Better - High security
const dh = getDiffieHellman('modp16');

// ❌ Bad - Too small
const dh = createDiffieHellman(1024); // Vulnerable!

2. Secret Derivation:

// ✅ Good - Hash the shared secret
const sharedSecret = dh.computeSecret(peerPublicKey);
const hash = createHash('sha256');
hash.update(sharedSecret);
const encryptionKey = hash.digest();

// ❌ Bad - Use raw secret
const sharedSecret = dh.computeSecret(peerPublicKey);
const iv = Buffer.alloc(16); // Example IV
const cipher = createCipheriv('aes-256-cbc', sharedSecret, iv); // Weak!

3. Authentication:

// ✅ Good: Sign public keys with long-term identity
// const signature = signWithIdentityKey(d hPublicKey);
// send({ dhPublicKey, signature });

// ❌ Bad: No authentication (vulnerable to MITM)
// send({ dhPublicKey });

4. Perfect Forward Secrecy:

// ✅ Good - New DH instance per session
function newSession() {
  const dh = getDiffieHellman('modp15');
  dh.generateKeys();
  return dh;
}

// ❌ Bad - Reuse same DH instance
const dh = getDiffieHellman('modp15');
dh.generateKeys();
// ... reuse for multiple sessions

4. Public Key Validation:

// ✅ Good - Validate received public keys
const { createECDH } = require('react-native-quick-crypto');
const ecdh = createECDH('prime256v1');
ecdh.generateKeys();
const receivedPublicKey = Buffer.from('...', 'hex'); // From peer

try {
  const secret = ecdh.computeSecret(receivedPublicKey);
} catch (error) {
  console.error('Invalid public key:', (error as Error).message);
  // Reject the key exchange
}

// ❌ Bad - No validation
const untrustedPublicKey = Buffer.from('...', 'hex');
// const secret = ecdh.computeSecret(untrustedPublicKey); // Could throw!

Man-in-the-Middle (MITM) Vulnerability

Basic Diffie-Hellman doesn't authenticate the parties. An attacker can perform two separate key exchanges:

Alice ← Attacker → Bob
  ↓       ↓         ↓
  K1      K1 + K2   K2

Protection: Combine with authentication (certificates, pre-shared keys, or signed DH public keys).


Common Errors

Different shared secrets

Cause: Both parties must use the same group and exchange keys correctly.

// ❌ Wrong - Different groups
const alice = getDiffieHellman('modp14');
const bob = getDiffieHellman('modp15'); // Different!

// ✅ Correct - Same group
const group = 'modp15';
const alice = getDiffieHellman(group);
const bob = getDiffieHellman(group);

Cause: Using own public key instead of peer's.

// ❌ Wrong: Using own public key
// const secret = alice.computeSecret(alice.getPublicKey()); // Wrong!

// ✅ Correct: Using peer's public key
const alice = getDiffieHellman('modp15');
const bob = getDiffieHellman('modp15');
alice.generateKeys();
bob.generateKeys();
const secret = alice.computeSecret(bob.getPublicKey());

Error: Supplied key is too small

Cause: Using a group with insufficient bit length.

Solution: Use modp14 (2048-bit) or larger:

// ❌ Wrong - Too small
const dh = createDiffieHellman(1024);

// ✅ Correct - Adequate size
const dh = getDiffieHellman('modp14'); // 2048-bit

Error: ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY

Cause: The provided public key is invalid or corrupted.

Solutions:

  • Verify encoding matches ('hex', 'base64', etc.)
  • Check for transmission errors
  • Ensure both parties use the same group
// ✅ Correct - Matching encodings
const publicKey = dh.getPublicKey('base64');
const secret = peer.computeSecret(publicKey, 'base64');

Performance Notes

Key Generation Performance (modp15/3072-bit, typical mobile device):

  • Key generation: ~50-100ms
  • Secret computation: ~10-20ms

Recommendations:

  1. Generate keys once per session, not per message
  2. Use smaller groups for low-power devices (but minimum modp14)
  3. Consider ECDH for better performance - 10-100× faster than DH
  4. Pre-generate DH instances if you know you'll need them
// Example: Background key generation
import { getDiffieHellman } from 'react-native-quick-crypto';

async function prepareSecureSession(): Promise<any> {
  return new Promise((resolve) => {
    setTimeout(() => {
      const dh = getDiffieHellman('modp15');
      dh.generateKeys();
      resolve(dh);
    }, 0);
  });
}

// Usage
const dh = await prepareSecureSession();
// DH instance ready for immediate use

Performance Comparison

GroupKey GenComputeTotalSecurity
modp14 (2048)~30ms~8ms~38msMinimum
modp15 (3072)~80ms~15ms~95msRecommended
modp16 (4096)~200ms~30ms~230msHigh
ECDH P-256~5ms~2ms~7msEquivalent to modp15

Conclusion: For mobile applications with frequent rekeying, consider using ECDH instead of traditional DH for better performance.

On this page