UDP-WG Implementation
Loading...
Searching...
No Matches
wireguard.h
1#pragma once
2
3#include "shared.h"
4#include "udp.h"
5
6using namespace shared;
7
8
15namespace wireguard {
16
17
18 // The key pair is generated on runtime.
19 auto pair = crypto::DH_GENERATE();
20
21
22 // See Section 5.4 of the Reference, but these are just various
23 // constants that are used as the base to construct the various
24 // values we sent across the wire.
25 const crypto::string
26
27 // An empty value, its used frequently for AAD in encryption.
28 // Why? it's just another way to detect if the data was modified.
29 EPSILON = 32,
30
31 // Used to initialize the C value, which eventually becomes our
32 // Transport Keys. Why? You may notice that the string contains
33 // each cryptographic function used in WireGuard:
34 // Noise: The logic of the KeyExchange itself.
35 // IKpsk2: The specific pattern of Noise: https://noiseexplorer.com/patterns/IKpsk2/
36 // 22519: Curve25519 for Key Generation.
37 // ChaChaPoly: ChaCha20-Poly1305 for Encryption/Decryption
38 // BLAKE2s: For Hashing and HMAC.
39 // So, this would allow for different version of WireGuard, say if a new cryptographic
40 // scheme was released that was better than what we currently use, or a vulnerability
41 // is discovered, without needing to provide a version flag in the packet. New versions
42 // of WireGuard that use updated algorithms will communicate, but older versions that
43 // use insecure/outdated values will fail immediately. Quite clver.
44 CONSTRUCTION = ("Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s", 32),
45
46 // This is used to initialize the H value, which is an accumulated
47 // value by hashing pretty much every intermediary and final value
48 // calculated in the Handshake. Why? As you can see from the string
49 // This provides an EXPLICIT version, unlike CONSTRUCTION, which
50 // again allows WireGuard to seamlessly "update" without allowing
51 // outdates clients to work with newer ones.
52 IDENTIFIER = ("WireGuard v1 zx2c4 Jason@zx2c4.com", 34),
53
54 // Labels for generating the MAC1 and COOKIE. These are used as keys
55 // for hashing and encrypting? Why? These values are hashed
56 // prior to being used as keys with a public key, and we don't
57 // want to transmit the public key in the clear unless we have to:
58 // If a vulnerability is discovered in Curve25519, we don't want
59 // to give attackers an ability to derive the private key. If
60 // Curve25519 is broken in typical implementations where we DON'T
61 // just send the public key across the wire, the attacker would
62 // need to additionally break BLAKE2 to figure out the original
63 // public key given only the hash, and the label used to construct it.
64 // The Reference mentions this directly: "One modification [to the initiator's message]
65 // would be to compute msg.static rather as Aead(κ, 0, Hash(S^pub_i), Hi).
66 // The additional hash ensures that this elliptic curve point would not be transmitted directly,
67 // and hence the entire handshake would have some limited degree of non-forward secret
68 // post-quantum security, provided the public keys are not made known by some other means.)"
69 LABEL_MAC1 = ("mac1----", 8),
70 LABEL_COOKIE = ("cookie--", 8);
71
72
73 // 6.1 of the Wiregurad Reference outlines these constants.
74 // Either in messages or seconds, where applicable.
75 // I find the MSGS constants comically large, especially
76 // given the RJECT_TIME is only 3 minutes. For reference,
77 // a peer would need to send 6405119 message every NANOSECOND
78 // to reach the REKEY_MSGS in 3 minutes. I presume the idea
79 // was not TIME or MSGS, but TIME and MSGS, such that a rekey
80 // happens both when the time is up, and when the message
81 // count is hit, but it is still such a massive amount of messages
82 // compared to such a small timeout.
83 const uint64_t
84 // How many messages before we rekey.
85 REKEY_MSGS = 1152921504606846976,
86
87 // How many messages before we reject the connection
88 RJECT_MSGS = 1.844674407370954e19,
89
90 // How long since we last got a packet until we rekey.
91 REKEY_TIME = 120,
92
93 // How long since we last got a packet until we reject.
94 RJECT_TIME = 180,
95
96 // How long we wait before timing out on a rekey attempt
97 REKEY_TOUT = 5,
98
99 // How often we're allowed to ping. We don't actually use
100 // this value, because the Network Thread manages heartbeats
101 // itself, but it's here for completeness.
102 KEEPALIVE = 10;
103
104
113 typedef struct config {
114
115 // The last timestamp they sent
116 crypto::string timestamp = 12;
117
118 // The peer's identity, and ours.
119 crypto::string identity = 4;
120 crypto::string self = 4;
121
122 // Our shared transport keys.
123 crypto::keypair keys;
124
125 // Our send/recv nonces.
126 uint64_t send = 0;
127 uint64_t recv = 0;
128
129 // So the network thread know's how to spoof connections.
130 // Packets that reach the thread are directed to src.
131 // Packets that are sent by source are spoofed to be
132 // coming from us before being encrypted and sent.
133 connection src = {};
134
135 // The main network thread also receives a connection,
136 // but doesn't actually use wireguard. Set it to false in that case.
137 bool on = false;
138
139 // The cookie. This is randomly generated garbage that is
140 // encrypted by the server, sent across, and then decrypted
141 // by the client and stored. On reconnection, the client
142 // then computes it's mac2 using this decrypt noise,
143 // which the server can verify, so long as the timestamp
144 // hasn't exceed 120 seconds (And thus the random noise)
145 // has changed.
146 crypto::string cookie;
147 uint64_t cookie_timestamp;
149
150
155 class Rm {
156 private:
157
158 // The random value, and a timer.
160 uint64_t timer = TimeSeconds();
161
162 public:
163 Rm() = default;
164
173 auto current = TimeSeconds();
174 if (current - timer > 120) {
175 R = crypto::DH_GENERATE().priv();
176 timer = current;
177 }
178 return R;
179 }
180 };
181 Rm cookie_random;
182
183
200 class Packet {
201 protected:
202
203 // Our list of strings that makes up the pack
204 std::vector<crypto::string> values;
205
206 public:
207 Packet() = default;
208
213 std::string Serialize() {
214 std::stringstream out;
215 for (const auto& x : values)
216 out << std::string(reinterpret_cast<const char*>(x.bytes()), x.length());
217 return out.str();
218 }
219
227 void Expand(const std::string& buffer, const bool& fill=false) {
228
229 // Extract from the buffer based on the pre-set size of each vector
230 // string. Because this uses the current length, Expand needs to be
231 // used on a new Packet, as making changes could change the internal sizes!
232 size_t index = 0;
233 for (auto& x : values) {
234 // If we run out of bytes, throw an error.
235 if (index > buffer.length())
236 throw std::runtime_error("Buffer does not contain entire packet!");
237
238 // Otherwise write the requested about of bytes into the crypto::string,
239 // from the current position in the buffer
240 memcpy(x.bytes(), &buffer[index], x.length());
241
242 // Update the index.
243 index += x.length();
244 }
245
246 // If we're filling, dump all the remaining bytes into the last element.
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);
252 }
253 }
254 };
255
256
260 class InitPacket : public Packet {
261 public:
262
263 // So we can index the vector a la packet[InitPacket::reserved];
264 // We combine type + reserve because they're both static.
265 static constexpr size_t reserved = 0, sender = 1, ephemeral = 2, stat = 3,
266 timestamp = 4, mac1 = 5, mac2 = 6;
267
268 // Initialize the InitPacket with the correct byte sizes.
269 InitPacket() {Packet::values = {4, 4, 32, 48, 28, 16, 16}; values[0][0] = WG_HANDSHAKE;}
270
271 // Initialize the InitPacket from a buffer.
272 InitPacket(const std::string& buffer) : InitPacket() {Expand(buffer);}
273
274 // Index operator
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];}
277 };
278
279
283 class ResponsePacket : public Packet {
284 public:
285
286 // Names
287 static constexpr size_t reserved = 0, sender = 1, receiver = 2, ephemeral = 3,
288 empty = 4, mac1 = 5, mac2 = 6;
289
290 // Default values and constructors
291 ResponsePacket() {Packet::values = {4, 4, 4, 32, 48, 16, 16}; values[0][0] = WG_HANDSHAKE;}
292 ResponsePacket(const std::string& buffer) : ResponsePacket() {Expand(buffer);}
293
294 // Index operator.
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];}
297 };
298
299
323 class CookiePacket : public Packet {
324 public:
325
326 // Names
327 static constexpr size_t reserved = 0, receiver = 1, nonce = 2, cookie = 3;
328 // Default values and constructors. We bump the cookie size to accommodate AAD info.
329 CookiePacket() {Packet::values = {4, 4, 24, 32}; values[0][0] = WG_COOKIE;}
330 CookiePacket(const std::string& buffer) : CookiePacket() {Expand(buffer);}
331
332 // Index operator.
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];}
335 };
336
337
342 class TransportPacket : public Packet {
343 public:
344
345 // Names
346 static constexpr size_t reserved = 0, receiver = 1, counter = 2, packet = 3;
347
348 // Default values. Notice we default the packet value to 1, but tell Expand
349 // to fill however many bytes were in the buffer.
350 TransportPacket() {Packet::values = {4, 4, 8, 1}; values[0][0] = WG_TRANSPORT;}
351 TransportPacket(const std::string& buffer) : TransportPacket() {Expand(buffer, true);}
352
353 //Construct a packet with a valid WireGuard connection, and some data.
354 static udp::packet Create(config& config, const udp::packet& in) {
355 // Build the package
356 TransportPacket packet;
357 packet[TransportPacket::receiver] = config.identity;
358 packet[TransportPacket::counter] = {reinterpret_cast<unsigned char*>(&config.send), sizeof(uint64_t)};
359 packet[TransportPacket::packet] = crypto::ENCRYPT(config.keys.priv(), config.send, in.buffer(), EPSILON);
360
361 // Increment our send nonce, then collapse the struct into a byte array.
362 ++config.send;
363 return {config.src, packet.Serialize()};
364 }
365
366
374 static udp::packet Return(config& config, const udp::packet& packet) {
375
376 // Rebuild the packet.
377 TransportPacket t_packet = packet.data();
378
379 // Ensure the counter is correct, decrypt content, update nonce.
380 auto counter = *reinterpret_cast<const uint64_t*>(&t_packet[TransportPacket::counter]);
381 if (counter < config.recv) throw std::runtime_error("Incorrect counter!");
382 auto data = crypto::DECRYPT(config.keys.second(), config.recv, t_packet[TransportPacket::packet], EPSILON);
383 ++config.recv;
384 return udp::packet(data.to());
385 }
386
387 // Index operator.
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];}
390 };
391
392
393
427 crypto::keypair& ephemeral,
428 const crypto::string& remote_pub,
429 config& con,
430 InitPacket& msg,
431 const bool& init,
434 ) {
435
436 // Randomly generate an identity
437 if (init) {
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);
441 }
442 }
443
444 // C is our chaining key value. Starting with CONSTRUCTION,
445 // (Hence the name, we build off this with subsequent crytographic
446 // operations. This value will be the same on both peers, and will
447 // be used to derive the transport keys.
448 C = crypto::HASH(CONSTRUCTION);
449
450 // H is the hash result value. We use the
451 // responder's public key to hash
452 H = crypto::HASH(C + IDENTIFIER);
453
454 // The initiator hashes the the responder's public key into H,
455 // linking it with the responder.
456 if (init) H = crypto::HASH(H + remote_pub);
457 else H = crypto::HASH(H + pair.pub());
458
459 // The initiator generates new Ephemeral keys, whereas
460 // the responder simply takes the public that was added.
461 // An important thing to understand is the difference between
462 // a peer's Static and Ephemeral Keys. The Static Keys are
463 // stored in the pair variable at the top of this namespace.
464 // They don't change (Normal WireGuard applications would
465 // generate this to be permanent between two peers).
466 // However, for every handshake, each peer generates a set
467 // of Ephemeral Keys, which they use alongside their static
468 // keys to derive the eventual Transport Keys. These Ephemeral
469 // Keys are regenerated on each handshake, and re-key.
470 // The idea is to ensure perfect forward secrecy: The
471 // leakage of either peer's private keys will prevent
472 // past messages from being decrypted, since they were encrypted
473 // with Ephemeral Keys that are changed every two minutes.
474 if (init) {
475 ephemeral = crypto::DH_GENERATE();
476 msg[InitPacket::ephemeral] = ephemeral.pub();
477 }
478
479 // The responder simply extracts the public component of the initiator's
480 // Ephemeral Key (Which was sent along in the InitPacket.
481 else ephemeral.pub() = msg[InitPacket::ephemeral];
482
483 // Tie both C and H to the initiator's public ephemeral key.
484 C = KDF(1, C, ephemeral.pub())[0];
485 H = crypto::HASH(H + ephemeral.pub());
486
487 // This is really neat; because the initiator creates
488 // this value by multiplying the private key of the ephemeral,
489 // (Which the responder doesn't know), with the RESPONDER'S PUBLIC KEY
490 // The responder can derive the same value by using their key,
491 // the RESPONDER'S PRIVATE KEY, against the ephemeral's public
492 // portion, sent in msg[ephemeral].
493 // This is the ECC of how g**(b*a) = g**(a*b) of
494 // traditional DH, and ensures that the only person who
495 // can return a shared value, as this dh is used immediately
496 // after, is the person who has the private part of the
497 // remote public the initiator used, IE the remote.
499 if (init) dh = crypto::DH(ephemeral.priv(), remote_pub);
500 else dh = crypto::DH(pair.priv(), ephemeral.pub());
501
502 // Use KDF to not only update our C, but create an encryption
503 // key K that we can use to encrypt the noise of the InitPacket.
504 auto temp = KDF(2, C, dh);
505 C = temp[0]; auto K = temp[1];
506
507 // Now, we can ensure that both sides have the same information.
508 // If the above DH did not match, then K cannot be correctly derived,
509 // which means the attempt to decrypt the static value of the
510 // message would return garbage. The remote knows that its
511 // speaking to the intended target if it can successfully
512 // decrypt the initiator's public key.
513 //
514 // Cleverly, we attach H as AAD. H can only be correctly derived
515 // from the remote's public key, which means that anyone that
516 // is sniffing for packets will be unable to make this decryption
517 // off of only the information contained in the packet.
518 if (init) msg[InitPacket::stat] = crypto::ENCRYPT(K, 0, pair.pub(), H);
519
520 // The responder need only decrypt and ensure that value is their public key.
521 else if (!init && crypto::DECRYPT(K, 0, msg[InitPacket::stat], H) != remote_pub)
522 throw std::runtime_error("Static could not be decrypted!");
523
524 // Update the hash to include the static, tying this
525 // exchange to the message.
526 H = crypto::HASH(H + msg[InitPacket::stat]);
527
528 // Now, we tie in the actual Static Keys. You may notice that there's no
529 // if (init) block here, because multiplying the PRIVATE-INIT with PUBLIC-RESPONSE
530 // is the same as multiplying the PRIVATE_RESPONSE with PUBLIC_INIT, and based
531 // on how we provide that information, this returns the same value, despite
532 // the input being different values. Again, this is like the magic of traditional
533 // Diffie-Hellman.
534 temp = KDF(2, C, crypto::DH(pair.priv(), remote_pub));
535
536 // Again, we use KDF to not only update C with our static keys,
537 // but derive an encrypt key to encrypt the next piece of information
538 // in the packet: The timestamp.
539 C = temp[0]; K = temp[1];
540
541 // The initiator now adds the timestamp. As Per Section 5.1
542 // of the Reference, the server keeps track of the greatest
543 // value timestamp sent across an entire connection, and will
544 // drop those that are before it. We encrypt the timestamp with
545 // our K derived from the second key-exchange, hiding the current
546 // timestamp from being transmitted in the clear.
547 if (init) {msg[InitPacket::timestamp] = crypto::ENCRYPT(K, 0, Timestamp(), H);}
548
549 // Decrypt the timestamp.
550 else {
551 // Add all the information we need to communicate with this peer in the future.
552 auto timestamp = crypto::DECRYPT(K, 0, msg[InitPacket::timestamp], H);
553
554 // Remember, this Handshake is run not only on initial connection, but every
555 // 2 minutes (And also after 2**60 messages, which is the equvilent of sending
556 // 30,000 packets every second for the next 1,000,000 years straight), so
557 // if we're passing an existing configuration, ensure that there isn't any
558 // replay attack by sending older packets.
559 if (TimestampGreater(con.timestamp, timestamp))
560 throw std::runtime_error("Invalid timestamp!");
561 con.timestamp = timestamp; con.identity = msg[InitPacket::sender];
562 }
563
564 // Store the timestamp into our running hash value.
565 H = crypto::HASH(H + msg[InitPacket::timestamp]);
566
567 // Now, we hash everything up to the mac in our packet, ensuring that none of it is modified
568 // in transit.
569 auto ma = msg[InitPacket::reserved] + msg[InitPacket::sender] +
570 msg[InitPacket::ephemeral] + msg[InitPacket::stat] + msg[InitPacket::timestamp];
571 if (init) msg[InitPacket::mac1] = crypto::MAC(crypto::HASH(LABEL_MAC1 + remote_pub), ma);
572
573 // The responder ensures that the mac is valid.
574 else if (crypto::MAC(crypto::HASH(LABEL_MAC1 + pair.pub()), ma) != msg[InitPacket::mac1])
575 throw std::runtime_error("Invalid MAC!");
576
577 // So long as the cookie sent across is not older than the refreshing random number, we
578 // compute and verify mac2. We don't actually check if the cookie timestamp is valid,
579 // because then we'd need to store that on the server. Instead, an invalid cookie
580 // will simply cause an exception to be raised when the server tries to decrypt it,
581 // which we can catch and thus stop the exchange
582 if (con.cookie_timestamp != 0) {
583
584 // Add the first mac to be included in our mac2.
585 ma = ma + msg[InitPacket::mac1];
586
587 // Store our previously decrypted cookie
588 if (init) msg[InitPacket::mac2] = crypto::MAC(con.cookie, ma);
589
590 // According to the Reference, this is supposed to be the expected behavior:
591 // If there was no mac2 provided, or the mac2 is invalid (IE the client doesn't
592 // have a cookie, or their cookie is expired), and they are under load,
593 // they can send a cookie in response as opposed to the second part of the handshake.
594 // If the cookie IS valid, then the behavior is somewhat ambiguous. The Reference don't explicitly
595 // say that the server is REQUIRED to continue the handshake when presented with a valid cookie,
596 // but that seems to be the whole point: If Server under load, give the client a cookie so that
597 // they are prioritized once the situation calms down. Here, we don't have any means to detect
598 // whether the server is under load, and the server explicitly just asks if they want
599 // to send a cookie instead of completing the handshake. Therefore, all the responder does here
600 // is verify that the cookie is correct.
601 else {
602 auto cookie = crypto::MAC(cookie_random.Get(), connection_string(con.src));
603 if (crypto::MAC(cookie, ma) != msg[InitPacket::mac2])
604 throw std::runtime_error("Invalid Cookie MAC!");
605 }
606 }
607 }
608
609
630 const crypto::keypair& init_ephemeral,
631 const crypto::string& remote_pub,
632 config& con,
633 ResponsePacket& msg,
634 const bool& init,
637 ) {
638
639
640 // The responder generates an identity, and ephemeral keys.
641 crypto::keypair ephemeral;
642 if (!init) {
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];
646
647 // Generate the responder's ephemeral keys.
648 ephemeral = crypto::DH_GENERATE();
649 msg[ResponsePacket::ephemeral] = ephemeral.pub();
650 }
651
652 // The initiator ensures we have a valid packet, and grabs the ephemeral public from the packet
653 else {
654 if (msg[ResponsePacket::receiver] != msg[InitPacket::sender])
655 throw std::runtime_error("Receiver/Sender mismatch!");
656
657 // Extract the public.
658 ephemeral.pub() = msg[ResponsePacket::ephemeral];
659 }
660
661 // Update our C for the responder's public ephemeral.
662 C = crypto::KDF(1, C, ephemeral.pub())[0];
663 H = crypto::HASH(H + ephemeral.pub());
664
665 // The responder then multiplies their ephemeral keys to the public of the initiators.
666 // Just like before, the initiator, with the private key, can reach the same value
667 // by simply reversing the two. This effecttively ties the two sets of ephemeral
668 // keys together, ensuring that only the two peers that have the private keys
669 // for each set can advance past this point (Both Static and Ephemeral).
670 // Then, we tie these second set of ephemeral keys to the initiator, by
671 // multiplying the private key once more against the initiator's public key.
672 // Again, they can recreate the same state by simply multiplying the public
673 // part of the response's ephemeral (Which is sent across the wire), and
674 // their private static key.
675 //
676 if (!init) {
677 C = crypto::KDF(1, C, crypto::DH(ephemeral.priv(), init_ephemeral.pub()))[0];
678 C = crypto::KDF(1, C, crypto::DH(ephemeral.priv(), remote_pub))[0];
679 }
680 else {
681 C = crypto::KDF(1, C, crypto::DH(init_ephemeral.priv(), ephemeral.pub()))[0];
682 C = crypto::KDF(1, C, crypto::DH(pair.priv(), ephemeral.pub()))[0];
683 }
684
685 // Now we use KDF to generate a K for encryption of the empty section of the packet.
686 // The "empty" section is quite literal: The KDF is passed an empty 32 byte
687 // string for input, and we're encrypting EPSILON, or just zeros.
688 // This is likely just for sanity testing: If the initiator doesn't decrypt
689 // zeros (Their empty isn't quite so empty) Then they know that the person
690 // they're talking to isn't the person they want to, and they hangup the
691 // handshake immediately.
692 auto temp = crypto::KDF(3, C, crypto::string(32));
693 C = temp[0]; auto L = temp[1]; auto K = temp[2];
694 H = crypto::HASH(H + L);
695
696 // Encrypt the H into our empty section of the packet. This ensures
697 // that we have the same C value, as otherwise our K wouldn't match,
698 // and the decryption would fail.
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!");
702
703 // Again, update H with the content of this new section.
704 H = crypto::HASH(H + msg[ResponsePacket::empty]);
705
706 // Just like before, the responder creates a mac containing all the data in the packet, ensuring that
707 // it doesn't get modified in transit. The initiator then ensures that the value matches.
708 // A note: We don't do anything with mac2 here, since it's only updated if we have a Cookie. This implies
709 // that the CLIENT can send a Cookie to the SERVER, which I find very funny. I like the idea
710 // of the overworked server sending a cookie to the client, and then once they finally get around to
711 // connecting with the client, the client--some personal computer--decides that they're a little too
712 // busy right now, and passively aggressively send a cookie back. I presume that this is designed for
713 // servers talking to one another, where the client might reasonably have a load, but for the purposes
714 // of this implementation, a client cookie would just be petty.
715 auto ma = msg[ResponsePacket::reserved] + msg[ResponsePacket::sender] + msg[ResponsePacket::receiver] + msg[ResponsePacket::ephemeral] + msg[ResponsePacket::empty];
716 if (!init) msg[ResponsePacket::mac1] = crypto::MAC(crypto::HASH(LABEL_MAC1 + remote_pub), ma);
717 else if (crypto::MAC(crypto::HASH(LABEL_MAC1 + pair.pub()), ma) != msg[ResponsePacket::mac1])
718 throw std::runtime_error("Invalid MAC! Refusing to continue!");
719
720
721 // Now that we have a shared key C that has been built
722 // using both Static and Ephemeral keys from both sides,
723 // we derive two transport keys, one for sending, and one for receiving.
724 // See 5.4.5 of the Reference
725 auto transport_keys = crypto::KDF(2, C, EPSILON);
726
727 // When the initiator sends a packet encrypted with their sending key,
728 // The responder decrypts it with the same key, but it's their receiving
729 // key. So, we just need to flip them around accordingly.
730 if (init) {
731
732 // Add all the information we need to communicate with this peer in the future.
733 con = {
734 .identity = msg[ResponsePacket::sender],
735 .self = msg[InitPacket::sender],
736 .keys = {transport_keys[0], transport_keys[1]}
737 };
738 }
739
740 // The responder just needs to flip the order of the keys, and do
741 // some updating of the connection (Notice that the initiator is not updating
742 // a connection, but creating a new one, but the Responder, updating an existing
743 // connection, needs to reset the send/recv (Because we're definitely going to hit
744 // that 2**60 REKEY).
745 else {
746 // Add the information we hadn't yet derived.
747 con.self = msg[ResponsePacket::sender];
748 con.keys = {transport_keys[1], transport_keys[0]};
749 con.recv = 0;
750 con.send = 0;
751 }
752 }
753
754
788 template <typename Q> config Handshake(
789 const crypto::string& remote_pub,
790 const connection& peer,
791 const bool& init,
792 Q& in,
793 Q& out,
794 config conf = {},
795 const bool& cookie=false
796 ) {
797
798 // Setup our Packets.
799 InitPacket init_packet;
800 ResponsePacket response_packet;
801
802
803 // Setup the values we need to carry across Handshake1 and Handshake2
804 crypto::string C, H;
805 crypto::keypair ephemeral;
806
807 if (init) {
808
809 // The initiator generates their InitPacket, and sends it across.
810 Handshake1(ephemeral, remote_pub, conf, init_packet, init, C, H);
811 out.enqueue({peer, init_packet.Serialize()});
812
813 // Then, they wait for one of two things:
814 // A HANDSHAKE, which means the responder sent us back a reply,
815 // and we can finalize the connection.
816 // A COOKIE, which means the server deferred the connection
817 // for later.
818 auto response = in.pop({WG_HANDSHAKE, WG_COOKIE}, 50);
819
820 // If HANDSHAKE, extract the data, complete the handshake!
821 if (response.data()[0] == WG_HANDSHAKE) {
822 response_packet = ResponsePacket(response.data());
823 Handshake2(ephemeral, remote_pub, conf, response_packet, init, C, H);
824
825 // Ensure we can send a packet.
826 conf.src = peer;
827 auto packet = TransportPacket::Create(conf, {peer, "Hello!"});
828 out.enqueue(packet);
829 }
830
831 // If COOKIE, decrypt the content to get the raw value, and
832 // store that for later.
833 else {
834 auto cookie_packet = CookiePacket(response.data());
835 auto key = crypto::HASH(LABEL_COOKIE + remote_pub);
836 auto cipher = cookie_packet[CookiePacket::cookie];
837 auto nonce = cookie_packet[CookiePacket::nonce];
838 auto aad = init_packet[InitPacket::mac1];
839
840 conf.cookie = crypto::XDECRYPT(key, {cipher, nonce}, aad);
841 conf.cookie_timestamp = TimeSeconds();
842 return conf;
843 }
844 }
845
846
847 // The responder waits until the initiator finishes Handshake1, and then
848 // runs through both it, and Handshake2, before returning the result of the
849 // second back to the initiator.
850 else {
851
852 // The first packet we give slightly more time so that the
853 // client can read our public key and ensure it's what they expected.
854 init_packet = InitPacket(in.pop(WG_HANDSHAKE, 300).data());
855
856 // If we want to send a cookie, and there isn't already one.
857 if (cookie && conf.cookie_timestamp == 0) {
858
859 // Generate the Cookie. See 5.4.7 of the Reference.
860 CookiePacket cookie_packet;
861
862 // Set the receiver.
863 cookie_packet[CookiePacket::receiver] = init_packet[InitPacket::sender];
864
865 // Generate the cookie by using our public key, and using it
866 // to encrypt our random value, and the peer's IP+Port, using
867 // the mac1 of the original message as AAD
868 auto key = crypto::HASH(LABEL_COOKIE + pair.pub());
869 auto plain = crypto::MAC(cookie_random.Get(), connection_string(peer));
870 auto aad = init_packet[InitPacket::mac1];
871 auto pair = crypto::XENCRYPT(key, plain, aad);
872 cookie_packet[CookiePacket::cookie] = pair.first();
873 cookie_packet[CookiePacket::nonce] = pair.second();
874
875 // Send it back, update our cookie.
876 out.enqueue({peer, cookie_packet.Serialize()});
877 conf.cookie = plain;
878 conf.cookie_timestamp = 1;
879 return conf;
880 }
881
882 // Otherwise, complete the handshake.
883 else {
884
885 // We need to set this here for the cookie.
886 conf.src = peer;
887 Handshake1(ephemeral, remote_pub, conf, init_packet, init, C, H);
888 Handshake2(ephemeral, remote_pub, conf, response_packet, init, C, H);
889
890 // Send the result back, ensure we can communicate
891 out.enqueue({peer, response_packet.Serialize()});
892 conf.src = peer;
893 auto packet = in.pop(WG_TRANSPORT, 50);
894 if (TransportPacket::Return(conf, packet).data() != "Hello!")
895 throw std::runtime_error("Test packet failed!");
896
897 // Clear the timestamp.
898 conf.cookie_timestamp = 0;
899 }
900 }
901 conf.on = true;
902 return conf;
903 }
904
905
915 void test() {
916 using namespace crypto;
917
918 // Ensure we can successfully derive a keypair.
919 string pub_key, priv_key;
920 string testing_string = "Hello, World!", data = ("Additional Data!", 32), encrypt, priv;
921 keypair xencrypt;
922
923 try {
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);
929 }
930 catch (std::runtime_error& c) {output("Failed: " + std::string(c.what()), "Key Generation", ERROR);}
931
932 // Key Exchange
933 try {
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);
938 }
939 catch (std::runtime_error& c) {output("Failed: " + std::string(c.what()), "Key Exchange", ERROR);}
940
941 // Ensure our FieldInteger operations work correctly.
942 // Ensure we can successfully encrypt.
943 try {
944 encrypt = ENCRYPT(priv, 0, testing_string, data);
945 xencrypt = XENCRYPT(priv, testing_string, data);
946 output("Success!", "Encryption", SUCCESS);
947 }
948 catch (std::runtime_error& c) {output("Failed: " + std::string(c.what()), "Encryption", ERROR);}
949
950 // Ensure we can successfully decrypt.
951 try {
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);
957 }
958 catch (std::runtime_error& c) {output("Failed: " + std::string(c.what()), "Decryption", ERROR);}
959
960 // Ensure that changing the ciphertext results in errors.
961 try {
962 encrypt[0] = ~encrypt[0];
963 auto decrypt = DECRYPT(priv, 0, encrypt, data);
964
965 xencrypt.first()[0] = ~xencrypt.first()[0];
966 auto xdecrypt = XDECRYPT(priv, xencrypt, data);
967 output("Failed!", "AED", ERROR);
968 }
969 catch (std::runtime_error& c) {output("Success: " + std::string(c.what()), "AED", SUCCESS);}
970
971 // Ensure the the Blake Hash works correctly
972 try {
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);
977 }
978 catch (std::runtime_error& c) {output("Failed: " + std::string(c.what()), "Hash", ERROR);}
979
980 // Ensure the the Blake HMAC works correctly
981 crypto::string hmac;
982 try {
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);
987 }
988 catch (std::runtime_error& c) {output("Failed: " + std::string(c.what()), "HMAC", ERROR);}
989
990 try {
991 auto mod = testing_string, mod2 = data;
992 mod[0] = ~mod[0]; mod2[0] = ~mod2[0];
993
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);
997 }
998 catch (std::runtime_error& c) {output("Failed: " + std::string(c.what()), "HMAC Authenticity", ERROR);}
999
1000 // Ensure the the Blake HMAC works correctly
1001 string mac;
1002 try {
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);
1007 }
1008 catch (std::runtime_error& c) {output("Failed: " + std::string(c.what()), "MAC", ERROR);}
1009
1010 try {
1011 auto mod = testing_string, mod2 = data;
1012 mod[0] = ~mod[0]; mod2[0] = ~mod2[0];
1013
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);
1017 }
1018 catch (std::runtime_error& c) {output("Failed: " + std::string(c.what()), "MAC Authenticity", ERROR);}
1019
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!");
1021 clear();
1022 }
1023}
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
Definition shared.h:45