SPEKE (Simple Password Exponential Key Exchange) using OpenSSL

Introduction

David P. Jablon published a paper in 1996 called Strong Password-Only Authenticated Key Exchange where he describes a new protocol based on Diffie-Hellman-Merkle key exchange. Diffie-Hellman key exchange is susceptible to MITM attack but with just Modular Multiplication and a cryptographic hash function, the attacker must also know a pre-shared secret.

OpenSSL example

Although it doesn’t support out of the box, we only have to use some BN and cryptographic hash functions to make it all work. Here I’m using SHA-256.

DH Functions

const char OAKLEY_PRIME_MODP1024[]=
	"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
	"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
	"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
	"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
	"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
	"FFFFFFFFFFFFFFFF";
  
DH     *client=NULL, *server=NULL;
BN_CTX *ctx;

// derive SHA-256 hash of password    
void hash (uint8_t out[], char *pwd)
{
  SHA256_CTX ctx;
  
  SHA256_Init (&ctx);
  SHA256_Update (&ctx, pwd, strlen (pwd));
  SHA256_Final (out, &ctx);
}

int init_dh (char *pwd, DH **dh)
{
  uint8_t h[SHA256_DIGEST_LENGTH];
  
  // create parameters
  dh[0]=DH_new();

  // set p prime
  BN_hex2bn (&dh[0]->p, OAKLEY_PRIME_MODP1024);
  //BN_hex2bn (&dh[0]->g, "2");
  
  // set generator using SHA-256 (pwd) * SHA-256 (pwd) mod p
  hash (h, pwd);
  dh[0]->g=BN_new();
  BN_bin2bn (h, SHA256_DIGEST_LENGTH, dh[0]->g);
  
  BN_mod_sqr (dh[0]->g, dh[0]->g, dh[0]->p, ctx);
  
  return DH_generate_key (dh[0]);
}

void dump (uint8_t x[])
{
  size_t i;
  for (i=0; i<128; i++) {
    printf ("%02X", x[i]);
  }
}

int main (int argc, char *argv[])
{
  char    *pwd="password";
  uint8_t s1[512], s2[512];
  BIGNUM  *key1, *key2;
  
  puts ("\n  SPEKE example using OpenSSL DH Library");
  
  if (argc==2) {
    pwd=argv[1];
  }
  
  ctx=BN_CTX_new ();
  
  // initialize DH parameters
  if (init_dh (pwd, &client)==1) 
  {
    if (init_dh (pwd, &server)==1) 
    {
      // server does
      printf ("\n  computing server key");
      DH_compute_key (s1, client->pub_key, server);
      printf ("\n  key 1 : "); dump (s1);
      
      // client does
      printf ("\n\n  computing client key");
      DH_compute_key (s2, server->pub_key, client);
      printf ("\n  key 2 : "); dump (s2);
      
      // keys match? we only check first 32 bytes
      printf ("\n\n  Key exchange %s\n", 
        memcmp (s1, s2, 32)==0 ? "succeeded" : "failed");
    } else {
      printf ("\n  server initialization failed");
    }
  } else {
    printf ("\n  client initialization failed");
  }
  
  if (client!=NULL) DH_free(client);
  if (server!=NULL) DH_free(server);
  
  BN_CTX_free (ctx);
  
  return 0;
}

Big Number Library

const char OAKLEY_PRIME_MODP1024[]=
	"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
	"29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
	"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
	"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
	"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
	"FFFFFFFFFFFFFFFF";
    
// derive SHA-256 hash of password    
void hash (uint8_t out[], char *pwd)
{
  SHA256_CTX ctx;
  
  SHA256_Init (&ctx);
  SHA256_Update (&ctx, pwd, strlen (pwd));
  SHA256_Final (out, &ctx);
}

void speke (char *pwd)
{
  BIGNUM *p, *g, *x, *y, *A, *B, *s1, *s2;
  BN_CTX *ctx;
  uint8_t h[SHA256_DIGEST_LENGTH];

  // initialize context
  ctx = BN_CTX_new ();
  BN_CTX_init (ctx);
  
  p=BN_new();
  BN_hex2bn (&p, OAKLEY_PRIME_MODP1024);
  
  // set generator using SHA-256 (pwd) * SHA-256 (pwd) mod p
  hash (h, pwd);
  g=BN_new();
  BN_bin2bn (h, SHA256_DIGEST_LENGTH, g);
  
  BN_mod_sqr (g, g, p, ctx);
  
  // generate 2 128-bit random values, x and y
  x=BN_new();
  BN_rand (x, 128, -1, 0);
  
  y=BN_new();
  BN_rand (y, 128, -1, 0);
  
  // Alice does g ^ x mod p
  A=BN_new();
  BN_mod_exp (A, g, x, p, ctx);
  
  // Bob does g ^ y mod p
  B=BN_new();
  BN_mod_exp (B, g, y, p, ctx);

  // *************************************
  // Bob and Alice exchange A and B values
  // *************************************
  
  // Alice computes session key
  s1=BN_new();
  BN_mod_exp (s1, B, x, p, ctx);
  
  // Bob computes session key
  s2=BN_new();
  BN_mod_exp (s2, A, y, p, ctx);
  
  // check if both keys match
  if (BN_cmp (s1, s2) == 0) {
    printf ("\n  Key exchange succeeded");
    printf ("\n  Key = %s\n", BN_bn2hex (s1));
  } else {
    printf ("\n  Key exchange failed\n");
  }
  
  BN_free (s2);
  BN_free (s1);
  BN_free (p);
  BN_free (g);
  BN_free (y);
  BN_free (x);
  BN_free (B);
  BN_free (A);
  
  // release context
  BN_CTX_free (ctx);
}

A really simple change in Diffie-Hellman key exchange makes a MITM attack much more difficult. Of course you should probably use primes in excess of 2048-bits and not 1024-bits which I’ve used here.

Advertisements
This entry was posted in bspeke, cryptography, diffie hellman merkle, encryption, key exchange protocol, oakley groups, openssl, prime numbers, programming, public key exchange, security, speke, wspeke. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s