Diffie-Hellman Key Exchange Algorithm: Working, Explanation, and Security

Diffie-Hellman algorithm and working of this algorithm.

I find the Diffie-Hellman key exchange to be one of the most elegant ideas in all of cryptography, because it solves a problem that seems almost paradoxical at first glance: how can two people agree on a shared secret while communicating entirely over a channel that an eavesdropper can listen to completely? Diffie-Hellman is a method for two parties to establish a shared secret key over an insecure channel, without ever transmitting the key itself. Its importance is hard to overstate — it underlies the key exchange step in TLS/SSL (which secures most of the web), SSH, VPN protocols, and many other systems where I need two parties to establish secure, encrypted communication without having met beforehand to exchange secrets in person.

History and Background

I credit Whitfield Diffie and Martin Hellman with publishing this method in their landmark 1976 paper “New Directions in Cryptography,” which is widely regarded as the paper that founded public-key cryptography as a field. Ralph Merkle also contributed foundational ideas around the same time (Merkle’s puzzles), and the method is sometimes called Diffie-Hellman-Merkle key exchange in recognition of this. What I find historically fascinating is that classified work by British intelligence (GCHQ) — specifically by Malcolm Williamson — had actually developed equivalent ideas a few years earlier, around 1974, but this work remained secret until it was declassified in 1997, long after Diffie and Hellman’s public work had already transformed the field. Diffie and Hellman’s 1976 paper predates RSA (1977) and set the conceptual stage for the entire idea that cryptographic keys could be split into public and private components — even though, notably, the original Diffie-Hellman protocol itself is a key-exchange mechanism, not a full public-key encryption scheme.

Problem Statement

I use Diffie-Hellman to solve the key distribution problem: two parties, who have never met and share no prior secret, want to establish a shared secret key over a communication channel that a third party can freely observe (but not alter, in the basic version). Before public-key cryptography, secure communication required parties to have exchanged secret keys through some trusted, secure channel beforehand — which is impractical at internet scale. The problem Diffie-Hellman solves is enabling this shared secret to be derived even when every single message exchanged between the two parties is visible to an eavesdropper, relying on a mathematical asymmetry: certain operations are easy to compute in one direction but computationally infeasible to reverse.

Core Concepts

  • Prime modulus (p): A large prime number that defines the finite field (or group) in which all arithmetic for the exchange takes place.
  • Generator (g): A primitive root modulo $p$, meaning its powers generate all (or a large subgroup) of the nonzero elements modulo $p$.
  • Private key: A randomly chosen secret integer that each party keeps to themselves and never transmits.
  • Public key: A value computed from the private key, the generator, and the modulus, which is safely shared over the insecure channel.
  • Shared secret: The final value both parties independently compute, which is identical for both, and which an eavesdropper cannot feasibly compute from the intercepted public values.
  • Discrete logarithm problem: The computational problem of finding the exponent $x$ given $g$, $p$, and $g^x \bmod p$ — believed to be computationally hard for well-chosen large parameters, and this hardness is what makes Diffie-Hellman secure.

How It Works

I walk through the classic Diffie-Hellman exchange between two parties, whom I’ll call Alice and Bob:

  1. Alice and Bob publicly agree on a large prime $p$ and a generator $g$ (these values do not need to be secret).
  2. Alice privately chooses a random secret integer $a$ (her private key).
  3. Bob privately chooses a random secret integer $b$ (his private key).
  4. Alice computes her public key $A = g^a \bmod p$ and sends $A$ to Bob over the insecure channel.
  5. Bob computes his public key $B = g^b \bmod p$ and sends $B$ to Alice over the insecure channel.
  6. Alice computes the shared secret as $s = B^a \bmod p$.
  7. Bob computes the shared secret as $s = A^b \bmod p$.
  8. Because of the algebraic properties of modular exponentiation, both computations yield the same value $s = g^{ab} \bmod p$, which becomes their shared secret key, even though neither party ever transmitted $a$, $b$, or $s$ directly.

Working Principle

The internal logic rests entirely on a mathematical asymmetry: computing $g^x \bmod p$ given $g$, $x$, and $p$ (modular exponentiation) is computationally easy, even for very large numbers, using efficient algorithms like fast exponentiation. But going the other direction — given $g$, $p$, and $g^x \bmod p$, finding $x$ — is believed to be computationally infeasible for well-chosen large primes, and this is known as the discrete logarithm problem. An eavesdropper watching the exchange sees $p$, $g$, $A=g^a \bmod p$, and $B=g^b \bmod p$, but to compute the shared secret $g^{ab} \bmod p$, they would need to solve the discrete logarithm problem to recover $a$ or $b$ from the intercepted public values — and no efficient classical algorithm is known for this problem when the parameters are large enough (this specific difficulty, of computing $g^{ab}$ from $g^a$ and $g^b$ without knowing $a$ or $b$, is called the Computational Diffie-Hellman problem, and it’s believed to be as hard as the discrete logarithm problem itself).

Mathematical Foundation

Given a publicly agreed prime $p$ and generator $g$, the exchange proceeds as follows.

Alice’s public key:

$$ A = g^a \bmod p $$

Bob’s public key:

$$ B = g^b \bmod p $$

Alice computes the shared secret:

$$ s = B^a \bmod p = (g^b)^a \bmod p = g^{ba} \bmod p $$

Bob computes the shared secret:

$$ s = A^b \bmod p = (g^a)^b \bmod p = g^{ab} \bmod p $$

Since exponentiation is commutative ($g^{ab} = g^{ba}$), both parties arrive at the identical value:

$$ s = g^{ab} \bmod p $$

The security of the scheme rests on the assumed computational hardness of the discrete logarithm problem: given $p$, $g$, and $A = g^a \bmod p$, finding $a$ requires (for classical computers, with well-chosen parameters) time exponential (or at least sub-exponential, using the best known algorithms like the General Number Field Sieve for discrete logs) in the bit-length of $p$.

Diagrams

sequenceDiagram
    participant Alice
    participant Eavesdropper
    participant Bob
    Note over Alice,Bob: Publicly agree on prime p and generator g
    Alice->>Alice: choose private key a
    Bob->>Bob: choose private key b
    Alice->>Eavesdropper: send A = g^a mod p
    Eavesdropper->>Bob: A = g^a mod p (visible, unmodified)
    Bob->>Eavesdropper: send B = g^b mod p
    Eavesdropper->>Alice: B = g^b mod p (visible, unmodified)
    Alice->>Alice: compute s = B^a mod p
    Bob->>Bob: compute s = A^b mod p
    Note over Alice,Bob: Both now share the same secret s = g^(ab) mod p

Pseudocode

function DiffieHellman():
    // Publicly agreed values
    p = large_prime()
    g = primitive_root_mod(p)

    // Alice's side
    a = random_private_key(1, p-2)
    A = mod_exp(g, a, p)
    send(A) to Bob

    // Bob's side
    b = random_private_key(1, p-2)
    B = mod_exp(g, b, p)
    send(B) to Alice

    // Shared secret computation
    alice_secret = mod_exp(B, a, p)
    bob_secret = mod_exp(A, b, p)

    assert alice_secret == bob_secret
    return alice_secret   // == g^(ab) mod p

Step-by-Step Example

I will use small numbers here purely for illustration; real-world use requires primes hundreds or thousands of bits long.

  • Publicly agreed: $p = 23$, $g = 5$ (5 is a primitive root modulo 23).
  • Alice picks private key $a = 6$. She computes $A = 5^6 \bmod 23$.
    • $5^2 = 25 \equiv 2 \pmod{23}$, $5^4 = 2^2 = 4 \pmod{23}$, $5^6 = 5^4 \cdot 5^2 = 4 \cdot 2 = 8 \pmod{23}$. So $A = 8$.
  • Bob picks private key $b = 15$. He computes $B = 5^{15} \bmod 23$.
    • Using repeated squaring: $5^1=5$, $5^2=2$, $5^4=4$, $5^8=16 \pmod{23}$ (since $4^2=16$). $15 = 8+4+2+1$, so $B = 5^8 \cdot 5^4 \cdot 5^2 \cdot 5^1 = 16 \cdot 4 \cdot 2 \cdot 5 \bmod 23$.
    • $16 \cdot 4 = 64 \equiv 18 \pmod{23}$; $18 \cdot 2 = 36 \equiv 13 \pmod{23}$; $13 \cdot 5 = 65 \equiv 19 \pmod{23}$. So $B = 19$.
  • Alice and Bob exchange $A=8$ and $B=19$ over the (insecure) channel.
  • Alice computes $s = B^a \bmod p = 19^6 \bmod 23$.
  • Bob computes $s = A^b \bmod p = 8^{15} \bmod 23$.
  • Carrying out this modular arithmetic (which I’ll trust to the underlying math rather than hand-compute every step here), both calculations converge to the same shared secret, $s = 2$.
  • An eavesdropper who intercepted $p=23$, $g=5$, $A=8$, $B=19$ would need to solve the discrete logarithm problem to recover $a$ or $b$ and derive $s=2$ — trivial for numbers this small, but computationally infeasible for the large primes (2048 bits or more) used in real systems.

Time Complexity

Each party performs one modular exponentiation to compute their public key, and one more to compute the shared secret. Using fast (repeated squaring) exponentiation, computing $g^x \bmod p$ takes $O(\log x)$ multiplications, and each modular multiplication of $k$-bit numbers costs $O(k^2)$ using schoolbook multiplication (or faster with more advanced multiplication algorithms). So each exponentiation costs roughly $O(k^3)$ for $k$-bit numbers using simple methods, or better with optimized big-integer arithmetic. Since each party only performs a small, constant number of exponentiations (typically two), the overall computational cost of the protocol itself is efficient and practical even for the large key sizes (2048+ bits) used in real deployments.

Space Complexity

Each party needs to store the public parameters $p$ and $g$, their own private key, the other party’s public key, and the resulting shared secret — all of which are single integers of size $O(k)$ bits, where $k$ is the chosen security parameter (key length). So the space complexity is $O(k)$, extremely modest even for cryptographically strong key sizes, since I’m only ever storing a handful of large integers, not arrays or matrices that scale with input size.

Correctness Analysis

I verify correctness algebraically: both parties compute $g^{ab} \bmod p$, just by different paths — Alice computes $(g^b)^a \bmod p$ and Bob computes $(g^a)^b \bmod p$ — and because exponentiation is commutative under modular arithmetic (a property inherited directly from the fact that ordinary integer exponentiation satisfies $(g^b)^a = (g^a)^b = g^{ab}$, and this equality is preserved when reducing modulo $p$), both parties are mathematically guaranteed to arrive at an identical value, with no possibility of divergence given correct implementation. Security correctness (as opposed to functional correctness) is a separate matter and rests on an unproven but widely believed computational assumption: that the discrete logarithm problem (and the related Computational and Decisional Diffie-Hellman problems) is hard for classical computers given large enough parameters. I should note that this assumption does not hold against a sufficiently large quantum computer, since Shor’s algorithm can solve discrete logarithms efficiently on such a machine — this is why post-quantum key exchange methods are an active area of research and eventual replacement for classical Diffie-Hellman in security-critical, long-lived systems.

Advantages

  • It allows two parties to establish a shared secret without ever having communicated securely before, solving the key distribution problem elegantly.
  • The mathematics is relatively simple to implement correctly compared to some other cryptographic primitives.
  • It underlies “forward secrecy” when used with ephemeral key pairs (Ephemeral Diffie-Hellman, or DHE/ECDHE), meaning even if long-term keys are later compromised, past session keys remain secure.
  • It has withstood decades of cryptanalysis when implemented with sufficiently large, well-chosen parameters.
  • Elliptic Curve variants (ECDH) provide equivalent security with much smaller key sizes, making it efficient for constrained devices.

Disadvantages

  • The basic protocol, as I’ve described it, provides no authentication, making it vulnerable to man-in-the-middle attacks unless combined with digital signatures or certificates to verify identities.
  • It is vulnerable to attack if implemented with small or poorly chosen primes (notably, the “Logjam” attack exploited widespread reuse of weak, small standard primes).
  • It’s vulnerable to future quantum computers via Shor’s algorithm, meaning long-term confidentiality of data exchanged today could be at risk if intercepted and stored for later decryption (“harvest now, decrypt later”).
  • Choosing cryptographically strong parameters (safe primes, appropriate generator) requires care; poor implementation choices have historically led to real-world vulnerabilities.
  • It only establishes a shared secret; it does not itself provide encryption, so it must be combined with a symmetric cipher to actually protect communications.

Applications

  • The key exchange phase of TLS/SSL, securing HTTPS web traffic (commonly using ECDHE for forward secrecy).
  • SSH, for establishing secure remote shell connections.
  • VPN protocols like IPsec, for establishing secure tunnels between networks.
  • Secure messaging applications, often as part of more complex protocols (like the Signal Protocol’s use of variants of Diffie-Hellman in its “X3DH” and “Double Ratchet” mechanisms).
  • IoT device provisioning, where lightweight elliptic curve variants (ECDH) are used due to constrained computational resources.
  • Any system needing to establish a fresh, secure session key over a network without pre-shared secrets.

Implementation in C

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// Educational implementation using small numbers.
// Real-world use requires big-integer arithmetic libraries and
// cryptographically secure random number generation with large primes.

// Fast modular exponentiation: computes (base^exp) mod mod
long long mod_exp(long long base, long long exp, long long mod) {
    long long result = 1;
    base = base % mod;
    while (exp > 0) {
        if (exp % 2 == 1)                 // if exponent is odd
            result = (result * base) % mod;
        exp = exp >> 1;                   // divide exponent by 2
        base = (base * base) % mod;       // square the base
    }
    return result;
}

int main() {
    srand((unsigned) time(NULL));

    // Step 1: publicly agreed parameters (small values for demonstration only)
    long long p = 23;   // prime modulus
    long long g = 5;    // generator (primitive root mod p)

    printf("Public parameters: p = %lld, g = %lld\n", p, g);

    // Step 2: Alice picks a private key and computes her public key
    long long a = 2 + rand() % (int)(p - 3);  // private key in [2, p-2]
    long long A = mod_exp(g, a, p);
    printf("Alice's private key a = %lld, public key A = %lld\n", a, A);

    // Step 3: Bob picks a private key and computes his public key
    long long b = 2 + rand() % (int)(p - 3);
    long long B = mod_exp(g, b, p);
    printf("Bob's private key b = %lld, public key B = %lld\n", b, B);

    // Step 4: exchange A and B over the (insecure) channel, then compute shared secret
    long long alice_secret = mod_exp(B, a, p);
    long long bob_secret = mod_exp(A, b, p);

    printf("Alice computes shared secret: %lld\n", alice_secret);
    printf("Bob computes shared secret:   %lld\n", bob_secret);

    if (alice_secret == bob_secret)
        printf("Success: both parties derived the same shared secret.\n");
    else
        printf("Error: shared secrets do not match.\n");

    return 0;
}

Sample Input and Output

With $p=23$, $g=5$, and randomly chosen private keys, a typical run produces output like:

Public parameters: p = 23, g = 5
Alice's private key a = 6, public key A = 8
Bob's private key b = 15, public key B = 19
Alice computes shared secret: 2
Bob computes shared secret:   2
Success: both parties derived the same shared secret.

This matches my hand-worked example earlier, confirming both parties independently arrive at the shared secret value of 2.

Optimization Techniques

  • Fast modular exponentiation (repeated squaring): I always use this instead of naive repeated multiplication, reducing exponentiation from $O(x)$ multiplications to $O(\log x)$.
  • Elliptic Curve Diffie-Hellman (ECDH): Using elliptic curve groups instead of modular arithmetic over large primes achieves equivalent security with far smaller key sizes and faster computation, which matters a lot for mobile and embedded devices.
  • Precomputed safe primes and standard groups: Using well-vetted, standardized groups (like those in RFC 3526 or RFC 7919) avoids subtle weaknesses that can arise from generating primes carelessly.
  • Ephemeral key pairs: Generating a fresh private/public key pair for every session (rather than reusing long-term keys) provides forward secrecy, limiting the damage from any future key compromise.
  • Constant-time implementations: Using constant-time modular exponentiation routines prevents timing side-channel attacks that could otherwise leak information about the private key.

Common Mistakes

  • Failing to authenticate the exchanged public keys, leaving the protocol vulnerable to man-in-the-middle attacks — Diffie-Hellman alone confirms nothing about who is on the other end.
  • Using a small or non-safe prime, or a poorly chosen generator, both of which can make the discrete logarithm problem tractable for an attacker.
  • Reusing the same private/public key pair across many sessions, which sacrifices forward secrecy.
  • Implementing modular exponentiation naively (without repeated squaring), leading to impractically slow performance for real-world key sizes.
  • Using a non-constant-time implementation, which can leak private key information through timing side channels.

Further Reading

  • Diffie, W., Hellman, M. “New Directions in Cryptography.” IEEE Transactions on Information Theory, 1976: https://ee.stanford.edu/~hellman/publications/24.pdf
  • RFC 3526, “More Modular Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange (IKE)”: https://datatracker.ietf.org/doc/html/rfc3526
  • RFC 7919, “Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for TLS”: https://datatracker.ietf.org/doc/html/rfc7919
  • Menezes, A. J., van Oorschot, P. C., Vanstone, S. A. “Handbook of Applied Cryptography.” CRC Press: https://cacr.uwaterloo.ca/hac/
  • Wikipedia overview: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
Total
0
Shares

Leave a Reply

Previous Post
SHA algorithm and working of this algorithm

SHA Hashing Algorithm: Working, Explanation, and Cryptographic Security

Next Post
Linear programming algorithm and working of this algorithm

Linear Programming Algorithm: Working, Explanation, and Optimization Methods

Related Posts