 # blu-sta's solution

## to Diffie Hellman in the C# Track

Published at Oct 16 2018 · 0 comments
Instructions
Test suite
Solution

Diffie-Hellman key exchange.

Alice and Bob use Diffie-Hellman key exchange to share secrets. They start with prime numbers, pick private keys, generate and share public keys, and then generate a shared secret key.

## Step 0

The test program supplies prime numbers p and g.

## Step 1

Alice picks a private key, a, greater than 1 and less than p. Bob does the same to pick a private key b.

## Step 2

Alice calculates a public key A.

``````A = g**a mod p
``````

Using the same p and g, Bob similarly calculates a public key B from his private key b.

## Step 3

Alice and Bob exchange public keys. Alice calculates secret key s.

``````s = B**a mod p
``````

Bob calculates

``````s = A**b mod p
``````

The calculations produce the same result! Alice and Bob now share secret s.

## Hints

This exercise requires you to perform calculations on large numbers. To correctly represent large numbers, the BigInteger struct is used.

## Source

Wikipedia, 1024 bit key from www.cryptopp.com/wiki. http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### DiffieHellmanTest.cs

``````// This file was auto-generated based on version 1.0.0 of the canonical data.

using System.Linq;
using System.Numerics;
using Xunit;

public class DiffieHellmanTest
{
[Fact]
public void Private_key_is_in_range_1_p()
{
var p = new BigInteger(7919);
var privateKeys = Enumerable.Range(0, 10).Select(_ => DiffieHellman.PrivateKey(p)).ToArray();
foreach (var privateKey in privateKeys)
{
Assert.InRange(privateKey, new BigInteger(1), p);
}
}

[Fact(Skip = "Remove to run test")]
public void Private_key_is_random()
{
var p = new BigInteger(7919);
var privateKeys = Enumerable.Range(0, 10).Select(_ => DiffieHellman.PrivateKey(p)).ToArray();
Assert.Equal(privateKeys.Distinct().Count(), privateKeys.Length);
}

[Fact(Skip = "Remove to run test")]
public void Can_calculate_public_key_using_private_key()
{
var p = new BigInteger(23);
var g = new BigInteger(5);
var privateKey = new BigInteger(6);
Assert.Equal(new BigInteger(8), DiffieHellman.PublicKey(p, g, privateKey));
}

[Fact(Skip = "Remove to run test")]
public void Can_calculate_secret_using_other_partys_public_key()
{
var p = new BigInteger(23);
var theirPublicKey = new BigInteger(19);
var myPrivateKey = new BigInteger(6);
Assert.Equal(new BigInteger(2), DiffieHellman.Secret(p, theirPublicKey, myPrivateKey));
}

[Fact(Skip = "Remove to run test")]
public void Key_exchange()
{
var p = new BigInteger(23);
var g = new BigInteger(5);
var alicePrivateKey = DiffieHellman.PrivateKey(p);
var bobPrivateKey = DiffieHellman.PrivateKey(p);
var alicePublicKey = DiffieHellman.PublicKey(p, g, alicePrivateKey);
var bobPublicKey = DiffieHellman.PublicKey(p, g, bobPrivateKey);
var secretA = DiffieHellman.Secret(p, bobPublicKey, alicePrivateKey);
var secretB = DiffieHellman.Secret(p, alicePublicKey, bobPrivateKey);
Assert.Equal(secretA, secretB);
}
}``````
``````﻿using System.Numerics;
using System.Security.Cryptography;

public static class DiffieHellman
{
public static BigInteger PrivateKey(BigInteger primeP)
{
var rng = new RNGCryptoServiceProvider();
var bytes = new byte[primeP.ToByteArray().Length];

while (true)
{
rng.GetBytes(bytes);
var bigInt = new BigInteger(bytes);
if (bigInt < primeP && bigInt > 1)
return bigInt;
}
}

public static BigInteger PublicKey(BigInteger primeP, BigInteger primeG, BigInteger privateKey) =>
GenerateKey(primeP, primeG, privateKey);

public static BigInteger Secret(BigInteger primeP, BigInteger publicKey, BigInteger privateKey) =>
GenerateKey(primeP, publicKey, privateKey);

private static BigInteger GenerateKey(BigInteger c, BigInteger a, BigInteger b) =>
new BigInteger((BigInteger.Pow(a, (int)b) % c).ToByteArray());
}``````