AES-DH Implementation
Loading...
Searching...
No Matches
exchange.h
1#pragma once
2
3#include <numeric>
4#include <stdexcept>
5#include <iostream>
6
7#include "network.h"
8#include "prime.h"
9
34namespace exchange {
35
36
47 uint64_t compute_intermediary(const uint64_t& p, const uint64_t& g, const uint64_t& k) {
48 // We can write the key as: k = (p-1)q + r
49 // Which turns g**k % p into g**((p-1)q + r) % p
50 // By simplifying the exponent, we get ((g**(p-1))**q)g**r
51 // According to Fermat's Little Theorem, g**(p-1) = 1, so
52 // we can reduce all that down to g**r % p.
53 // This only applies if p is co-prime to g.
54 uint64_t r = k % (p - 1), q = (k - r) / (p - 1);
55 return prime::raise(g, r, p);
56 }
57
58
65 uint64_t exchange_keys(const bool& server) {
66 // Generate our private key, and the other user's intermediary.
67 uint64_t a = 0, k = std::rand(), p = 0, g = 0;
68
69 if (server) {
70
71 // Firstly, we generate our p, which will be our mod value
72 // (And public), and then generate a q value, which we'll
73 // use for g. These follows the relationship p = jq + 1,
74 // Where j = 2. See 2.2 of the Reference.
75 // This ensures that p is a "safe prime," which has the following
76 // helpful properties:
77 // 1. Every quadratic nonresidue is a primitive root (Which we need for g)
78 // 2. The least positive primitive root is a prime number.
79 // What does this mean? It basically lets us quickly find an associated g
80 // value, rather than going through an expensive algorithm to compute
81 // primitive roots for a number.
82 auto pair = prime::generate();
83 p = std::get<0>(pair);
84 auto q = std::get<1>(pair);
85
86 // Next, we calculate h, which we'll use to generate g.
87 // We simply need to find a number such that h^((p-1)/q) % p
88 // Is greater than one. (I think the Reference has a typo in
89 // this section were they are missing the raise ^).
90 //
91 // Any interesting tibit of knowledge for you:
92 // I've also found suggestions of generating g by omitting
93 // h, and simply taking the smallest primitive root of p.
94 // We take the smallest because g should usually be small.
95 // According to Wikipedia, this is:
96 // "Because of the random self-reducibility of the discrete
97 // logarithm problem a small g is equally secure as any other
98 // generator of the same group."
99 // - https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
100 // That being said, I had an implementation to find a primitive
101 // root for a value p, which would ensure that g would be as small
102 // as possible, but it was so SLOW. This method is lightning quick
103 // Which is probably why the Reference suggests it. In fact,
104 // there are probably far more efficient ways of generating h,
105 // Since we're just brute forcing it here.
106 uint64_t h = 1;
107 while (prime::raise(h++, (p-1)/q, p) <= 1) {}
108
109 // With an h, we can generate g.
110 g = prime::raise(h, (p-1)/q, p);
111
112 // Send them across.
113 if (network::send_value(p) == -1)
114 throw std::runtime_error("Failed to send key!");
115 if (network::send_value(g) == -1)
116 throw std::runtime_error("Failed to send key!");
117
118 // Then, we send our intermediary, and receive the client.
120 throw std::runtime_error("Failed to send key!");
122 }
123
124 else {
125 // Collect the server's p,g, and intermediary.
129
130 // Calculate our intermediary, and send it back.
132 throw std::runtime_error("Failed to send key!");
133 }
134
135 // Both server and client can now calculate their shared key.
136 auto sk = prime::raise(a, k, p);
137 return sk;
138 }
139}
The namespace for Key-Exchange functions.
Definition exchange.h:34
uint64_t exchange_keys(const bool &server)
Exchange keys on an established connection.
Definition exchange.h:65
uint64_t compute_intermediary(const uint64_t &p, const uint64_t &g, const uint64_t &k)
Compute the intermeidary value to send across the wire.
Definition exchange.h:47
int send_value(const T &value, const network::meta &type=DATA, const size_t &timeout=5)
Send a value.
Definition network.h:109
const T recv_value(const size_t &timeout=5)
Receive a value.
Definition network.h:131
std::pair< uint64_t, uint64_t > generate()
Generates a prime number.
Definition prime.h:93
uint64_t raise(uint64_t value, uint64_t exp, const uint64_t &mod)
A O(logn) raise operation that works within modulus to prevent overflow.
Definition prime.h:64