44 CONSTRUCTION = (
"Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s", 32),
52 IDENTIFIER = (
"WireGuard v1 zx2c4 Jason@zx2c4.com", 34),
69 LABEL_MAC1 = (
"mac1----", 8),
70 LABEL_COOKIE = (
"cookie--", 8);
85 REKEY_MSGS = 1152921504606846976,
88 RJECT_MSGS = 1.844674407370954e19,
147 uint64_t cookie_timestamp;
174 if (current - timer > 120) {
204 std::vector<crypto::string> values;
214 std::stringstream out;
215 for (
const auto& x : values)
216 out << std::string(reinterpret_cast<const char*>(x.bytes()), x.length());
227 void Expand(
const std::string& buffer,
const bool& fill=
false) {
233 for (
auto& x : values) {
235 if (index > buffer.length())
236 throw std::runtime_error(
"Buffer does not contain entire packet!");
240 memcpy(x.bytes(), &buffer[index], x.length());
247 if (fill && index < buffer.length()) {
248 auto& last = values.back();
249 size_t extra = buffer.length() - index, start = last.length();
250 last.resize(start + extra);
251 memcpy(last.bytes() + start, &buffer[index], extra);
265 static constexpr size_t reserved = 0, sender = 1, ephemeral = 2, stat = 3,
266 timestamp = 4, mac1 = 5, mac2 = 6;
269 InitPacket() {Packet::values = {4, 4, 32, 48, 28, 16, 16}; values[0][0] = WG_HANDSHAKE;}
275 crypto::string& operator[](
const size_t& val) {
return Packet::values[val];}
276 const crypto::string& operator[](
const size_t& val)
const {
return Packet::values[val];}
287 static constexpr size_t reserved = 0, sender = 1, receiver = 2, ephemeral = 3,
288 empty = 4, mac1 = 5, mac2 = 6;
291 ResponsePacket() {Packet::values = {4, 4, 4, 32, 48, 16, 16}; values[0][0] = WG_HANDSHAKE;}
295 crypto::string& operator[](
const size_t& val) {
return Packet::values[val];}
296 const crypto::string& operator[](
const size_t& val)
const {
return Packet::values[val];}
327 static constexpr size_t reserved = 0, receiver = 1, nonce = 2, cookie = 3;
329 CookiePacket() {Packet::values = {4, 4, 24, 32}; values[0][0] = WG_COOKIE;}
333 crypto::string& operator[](
const size_t& val) {
return Packet::values[val];}
334 const crypto::string& operator[](
const size_t& val)
const {
return Packet::values[val];}
346 static constexpr size_t reserved = 0, receiver = 1, counter = 2, packet = 3;
350 TransportPacket() {Packet::values = {4, 4, 8, 1}; values[0][0] = WG_TRANSPORT;}
357 packet[TransportPacket::receiver] =
config.identity;
358 packet[TransportPacket::counter] = {
reinterpret_cast<unsigned char*
>(&
config.send),
sizeof(uint64_t)};
380 auto counter = *
reinterpret_cast<const uint64_t*
>(&t_packet[TransportPacket::counter]);
381 if (counter <
config.recv)
throw std::runtime_error(
"Incorrect counter!");
388 crypto::string& operator[](
const size_t& val) {
return Packet::values[val];}
389 const crypto::string& operator[](
const size_t& val)
const {
return Packet::values[val];}
438 std::uniform_int_distribution<std::mt19937::result_type> byte_dist(0,0xFF);
439 for (
size_t x = 0; x < 4; ++x) {
440 msg[InitPacket::sender][x] = byte_dist(rng);
476 msg[InitPacket::ephemeral] = ephemeral.pub();
481 else ephemeral.pub() = msg[InitPacket::ephemeral];
484 C = KDF(1, C, ephemeral.pub())[0];
499 if (init) dh =
crypto::DH(ephemeral.priv(), remote_pub);
500 else dh =
crypto::DH(pair.priv(), ephemeral.pub());
504 auto temp = KDF(2, C, dh);
505 C = temp[0];
auto K = temp[1];
518 if (init) msg[InitPacket::stat] =
crypto::ENCRYPT(K, 0, pair.pub(), H);
521 else if (!init &&
crypto::DECRYPT(K, 0, msg[InitPacket::stat], H) != remote_pub)
522 throw std::runtime_error(
"Static could not be decrypted!");
534 temp = KDF(2, C,
crypto::DH(pair.priv(), remote_pub));
539 C = temp[0]; K = temp[1];
560 throw std::runtime_error(
"Invalid timestamp!");
561 con.timestamp = timestamp; con.identity = msg[InitPacket::sender];
569 auto ma = msg[InitPacket::reserved] + msg[InitPacket::sender] +
570 msg[InitPacket::ephemeral] + msg[InitPacket::stat] + msg[InitPacket::timestamp];
575 throw std::runtime_error(
"Invalid MAC!");
582 if (con.cookie_timestamp != 0) {
585 ma = ma + msg[InitPacket::mac1];
588 if (init) msg[InitPacket::mac2] =
crypto::MAC(con.cookie, ma);
603 if (
crypto::MAC(cookie, ma) != msg[InitPacket::mac2])
604 throw std::runtime_error(
"Invalid Cookie MAC!");
643 std::uniform_int_distribution<std::mt19937::result_type> byte_dist(0,0xFF);
644 for (
size_t x = 0; x < 4; ++x) msg[ResponsePacket::sender][x] = byte_dist(rng);
645 msg[ResponsePacket::receiver] = msg[InitPacket::sender];
649 msg[ResponsePacket::ephemeral] = ephemeral.pub();
654 if (msg[ResponsePacket::receiver] != msg[InitPacket::sender])
655 throw std::runtime_error(
"Receiver/Sender mismatch!");
658 ephemeral.pub() = msg[ResponsePacket::ephemeral];
693 C = temp[0];
auto L = temp[1];
auto K = temp[2];
699 if (!init) {msg[ResponsePacket::empty] =
crypto::ENCRYPT(K, 0, EPSILON, H);}
700 else if (
crypto::DECRYPT(K, 0, msg[ResponsePacket::empty], H) != EPSILON)
701 throw std::runtime_error(
"Derived key is invalid! Refusing to continue!");
715 auto ma = msg[ResponsePacket::reserved] + msg[ResponsePacket::sender] + msg[ResponsePacket::receiver] + msg[ResponsePacket::ephemeral] + msg[ResponsePacket::empty];
718 throw std::runtime_error(
"Invalid MAC! Refusing to continue!");
734 .identity = msg[ResponsePacket::sender],
735 .self = msg[InitPacket::sender],
736 .keys = {transport_keys[0], transport_keys[1]}
747 con.self = msg[ResponsePacket::sender];
748 con.keys = {transport_keys[1], transport_keys[0]};
795 const bool& cookie=false
799 InitPacket init_packet;
800 ResponsePacket response_packet;
810 Handshake1(ephemeral, remote_pub, conf, init_packet, init, C, H);
811 out.
enqueue({peer, init_packet.Serialize()});
818 auto response = in.
pop({WG_HANDSHAKE, WG_COOKIE}, 50);
821 if (response.data()[0] == WG_HANDSHAKE) {
822 response_packet = ResponsePacket(response.data());
823 Handshake2(ephemeral, remote_pub, conf, response_packet, init, C, H);
827 auto packet = TransportPacket::Create(conf, {peer,
"Hello!"});
834 auto cookie_packet = CookiePacket(response.data());
836 auto cipher = cookie_packet[CookiePacket::cookie];
837 auto nonce = cookie_packet[CookiePacket::nonce];
838 auto aad = init_packet[InitPacket::mac1];
854 init_packet = InitPacket(in.
pop(WG_HANDSHAKE, 300).
data());
857 if (cookie && conf.cookie_timestamp == 0) {
860 CookiePacket cookie_packet;
863 cookie_packet[CookiePacket::receiver] = init_packet[InitPacket::sender];
870 auto aad = init_packet[InitPacket::mac1];
872 cookie_packet[CookiePacket::cookie] = pair.first();
873 cookie_packet[CookiePacket::nonce] = pair.second();
876 out.
enqueue({peer, cookie_packet.Serialize()});
878 conf.cookie_timestamp = 1;
887 Handshake1(ephemeral, remote_pub, conf, init_packet, init, C, H);
888 Handshake2(ephemeral, remote_pub, conf, response_packet, init, C, H);
891 out.
enqueue({peer, response_packet.Serialize()});
893 auto packet = in.
pop(WG_TRANSPORT, 50);
895 throw std::runtime_error(
"Test packet failed!");
898 conf.cookie_timestamp = 0;
919 string pub_key, priv_key;
920 string testing_string =
"Hello, World!", data = (
"Additional Data!", 32), encrypt, priv;
924 auto pair = DH_GENERATE();
925 pub_key = pair.pub();
926 priv_key = pair.priv();
927 if (pub_key.
length() != 32 || priv_key.
length() != 32)
throw std::runtime_error(
"Incorrect size!");
928 output(
"Success!",
"Key Generation", SUCCESS);
930 catch (std::runtime_error& c) {
output(
"Failed: " + std::string(c.what()),
"Key Generation", ERROR);}
934 auto server = DH_GENERATE();
935 auto client = DH_GENERATE();
936 if (
crypto::DH(server.priv(), client.pub()) !=
crypto::DH(client.priv(), server.pub()))
throw std::runtime_error(
"Exchange failed!");
937 output(
"Success!",
"Key Exchange", SUCCESS);
939 catch (std::runtime_error& c) {
output(
"Failed: " + std::string(c.what()),
"Key Exchange", ERROR);}
944 encrypt = ENCRYPT(priv, 0, testing_string, data);
945 xencrypt = XENCRYPT(priv, testing_string, data);
946 output(
"Success!",
"Encryption", SUCCESS);
948 catch (std::runtime_error& c) {
output(
"Failed: " + std::string(c.what()),
"Encryption", ERROR);}
952 auto decrypted = DECRYPT(priv, 0, encrypt, data);
953 auto xdecrypted = XDECRYPT(priv, xencrypt, data);
954 if (decrypted != testing_string.
to())
throw std::runtime_error(
"Incorrect decryption");
955 if (xdecrypted != testing_string.
to())
throw std::runtime_error(
"Incorrect decryption");
956 output(
"Success!",
"Decryption", SUCCESS);
958 catch (std::runtime_error& c) {
output(
"Failed: " + std::string(c.what()),
"Decryption", ERROR);}
962 encrypt[0] = ~encrypt[0];
963 auto decrypt = DECRYPT(priv, 0, encrypt, data);
965 xencrypt.first()[0] = ~xencrypt.first()[0];
966 auto xdecrypt = XDECRYPT(priv, xencrypt, data);
967 output(
"Failed!",
"AED", ERROR);
969 catch (std::runtime_error& c) {
output(
"Success: " + std::string(c.what()),
"AED", SUCCESS);}
973 if (HASH(testing_string) != HASH(testing_string))
throw std::runtime_error(
"Incorrect hash");
974 if (HASH(testing_string) == HASH(data))
throw std::runtime_error(
"Incorrect hash");
975 if (HASH(testing_string).length() != 32)
throw std::runtime_error(
"Incorrect size!");
976 output(
"Success!",
"Hash", SUCCESS);
978 catch (std::runtime_error& c) {
output(
"Failed: " + std::string(c.what()),
"Hash", ERROR);}
983 hmac = HMAC(testing_string, data);
984 if (hmac != HMAC(testing_string, data))
throw std::runtime_error(
"Incorrect HMAC");
985 if (hmac.
length() != 32)
throw std::runtime_error(
"Incorrect size!");
986 output(
"Success!",
"HMAC", SUCCESS);
988 catch (std::runtime_error& c) {
output(
"Failed: " + std::string(c.what()),
"HMAC", ERROR);}
991 auto mod = testing_string, mod2 = data;
992 mod[0] = ~mod[0]; mod2[0] = ~mod2[0];
994 if (HMAC(mod, data) == hmac)
throw std::runtime_error(
"Failed modifying key");
995 if (HMAC(testing_string, mod2) == hmac)
throw std::runtime_error(
"Failed modifying input");
996 output(
"Success!",
"HMAC Authenticity", SUCCESS);
998 catch (std::runtime_error& c) {
output(
"Failed: " + std::string(c.what()),
"HMAC Authenticity", ERROR);}
1003 mac = MAC(testing_string, data);
1004 if (mac != MAC(testing_string, data))
throw std::runtime_error(
"Incorrect MAC");
1005 if (mac.
length() != 16)
throw std::runtime_error(
"Incorrect size!");
1006 output(
"Success!",
"MAC", SUCCESS);
1008 catch (std::runtime_error& c) {
output(
"Failed: " + std::string(c.what()),
"MAC", ERROR);}
1011 auto mod = testing_string, mod2 = data;
1012 mod[0] = ~mod[0]; mod2[0] = ~mod2[0];
1014 if (MAC(mod, data) == mac)
throw std::runtime_error(
"Failed modifying key");
1015 if (MAC(testing_string, mod2) == hmac)
throw std::runtime_error(
"Failed modifying input");
1016 output(
"Success!",
"MAC Authenticity", SUCCESS);
1018 catch (std::runtime_error& c) {
output(
"Failed: " + std::string(c.what()),
"MAC Authenticity", ERROR);}
1020 prompt(
"If there were any failures, the program is unstable and may not work properly! Ensure that OpenSSL is on the latest version, and try recompiling/using the precompiled version if issues persist!");
A simple private-public keypair.
Definition crypto.h:284
A cryptographically secure string.
Definition crypto.h:63
std::string to() const
Return a std::string representation of the string.
Definition crypto.h:244
const size_t length() const
Return the length of the string.
Definition crypto.h:211
void enqueue(const udp::packet &in)
Enqueue a packet.
Definition network.h:75
udp::packet pop(const tag type=NONE, const size_t &iterations=-1)
Remove the first packet of the type byte.
Definition network.h:89
A UDP Packet.
Definition udp.h:59
std::string data() const
Return the data.
Definition udp.h:351
Definition wireguard.h:323
The initial packet sent from initiator to responder.
Definition wireguard.h:260
For both security and ease of use, we want to use crypto::string as much as possible....
Definition wireguard.h:200
void Expand(const std::string &buffer, const bool &fill=false)
Construct a Packet from a std::string.
Definition wireguard.h:227
std::string Serialize()
Serialize the packet.
Definition wireguard.h:213
The packet sent by the responder to the initiator during the handshake.
Definition wireguard.h:283
A controlled wrapper for the secret random value used for the WireGuard cookies.
Definition wireguard.h:155
const crypto::string & Get()
Get the current value.
Definition wireguard.h:172
A WireGuard packet for sending Transport Messages.
Definition wireguard.h:342
static udp::packet Return(config &config, const udp::packet &packet)
Receive an encrypted WireGuard communication.
Definition wireguard.h:374
The cryptographic implementations for WireGuard.
Definition crypto.h:42
string XDECRYPT(string key, const keypair &pair, const string &data)
Decrypt with XChaCha20-Poly1305.
Definition crypto.h:557
std::vector< string > KDF(const size_t &n, const string &key, const string &input)
Perform the HKDF scheme on our HMAC function.
Definition crypto.h:767
string DH(const string &priv, const string &pub)
Definition crypto.h:342
keypair DH_GENERATE()
Generate a Curve25519 keypair.
Definition crypto.h:388
string ENCRYPT(string key, const uint64_t &counter, const string &plain, const string &data)
Encrypt with ChaCha20-Poly1305.
Definition crypto.h:450
string HASH(const string &in)
Generate a BLAKE2s256 Hash of the input.
Definition crypto.h:605
keypair XENCRYPT(string key, const string &plain, const string &data)
Encrypt with XChaCha20-Poly1305.
Definition crypto.h:521
string DECRYPT(string key, const uint64_t &counter, const string &cipher, const string &data)
Decrypt with ChaCha20-Poly1305.
Definition crypto.h:486
string MAC(const string &key, const string &input)
OpenSSL makes no difference between HMAC-BLAKE2s256 and Keyed BLAKE2s256 Besides setting the size....
Definition crypto.h:743
The shared namespace.
Definition shared.h:19
bool TimestampGreater(const crypto::string &a, const crypto::string &b)
Compares two timestamps.
Definition shared.h:94
void output(const std::string &message, const std::string &thread="SYS", const message_type &t=STANDARD)
Output to STDOUT, thread safe.
Definition shared.h:208
std::string connection_string(const connection &c)
Get a string representation of the connection.
Definition shared.h:58
crypto::string Timestamp()
Get the current TAI64N timestamp.
Definition shared.h:72
uint64_t TimeSeconds()
Get the current UNIX timestamp.
Definition shared.h:131
void prompt(const std::string &message)
Prompt the user and wait until they have confirmed it.
Definition shared.h:284
void clear()
Clear the screen.
Definition shared.h:244
This namespace includes the WireGuard implementation,.
Definition udp.h:26
void Handshake2(const crypto::keypair &init_ephemeral, const crypto::string &remote_pub, config &con, ResponsePacket &msg, const bool &init, crypto::string &C, crypto::string &H)
Complete the Handshake.
Definition wireguard.h:629
void Handshake1(crypto::keypair &ephemeral, const crypto::string &remote_pub, config &con, InitPacket &msg, const bool &init, crypto::string &C, crypto::string &H)
The first half of the Handshake process.
Definition wireguard.h:426
void test()
Test the WireGuard Cryptographic Functions.
Definition wireguard.h:915
struct wireguard::config config
A WireGuard Configuration.
config Handshake(const crypto::string &remote_pub, const connection &peer, const bool &init, Q &in, Q &out, config conf={}, const bool &cookie=false)
Perform a WireGuard Handshake.
Definition wireguard.h:788
A WireGuard Configuration.
Definition wireguard.h:113