{"id":828,"date":"2024-10-15T16:10:35","date_gmt":"2024-10-15T22:10:35","guid":{"rendered":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/?p=828"},"modified":"2024-10-15T16:10:40","modified_gmt":"2024-10-15T22:10:40","slug":"udp-wg","status":"publish","type":"post","link":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/2024\/10\/15\/udp-wg\/","title":{"rendered":"UDP-WG"},"content":{"rendered":"\n<p class=\"has-small-font-size\">Hello everybody! I&#8217;m proud to announce the completion of my Project: UDP-WG. It&#8217;s a heavily documented C++ codebase that implements both the UDP Network Protocol, and the WireGuard VPN protocol. These implementations are used to create the <code>main<\/code> program, which allows instances to communicate with each other using either of these two protocols!<\/p>\n\n\n\n<p class=\"has-small-font-size\">The repository is located at: <a href=\"https:\/\/github.com\/kkernick\/UDP-WG\">https:\/\/github.com\/kkernick\/UDP-WG<\/a>, and you can view the rendered documentation at <a href=\"https:\/\/kkernick.github.io\/UDP-WG\">https:\/\/kkernick.github.io\/UDP-WG<\/a>. The below Walkthrough is a verbatim copy of the README, and you can optionally view it as either as:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-small-font-size\">A GitHub Rendered Markdown File: <a href=\"https:\/\/github.com\/kkernick\/UDP-WG\/blob\/main\/Discussion%20Questions.md\" data-type=\"link\" data-id=\"https:\/\/github.com\/kkernick\/UDP-WG\/blob\/main\/Discussion%20Questions.md\">https:\/\/github.com\/kkernick\/UDP-WG\/blob\/main\/README.md<\/a><\/li>\n\n\n\n<li class=\"has-small-font-size\">A PDF: <a href=\"https:\/\/github.com\/kkernick\/UDP-WG\/blob\/main\/README.pdf\">https:\/\/github.com\/kkernick\/UDP-WG\/blob\/main\/README.pdf<\/a><\/li>\n<\/ol>\n\n\n\n<p class=\"has-small-font-size\">The Discussion Questions have been appended to this document, but you can view them in both the above formats within the repository! Thank you!<\/p>\n\n\n\n<p class=\"has-small-font-size\">This repository contains an emulated implementation of both the UDP network protocol, alongside the WireGuard VPN protocol, as a means to better understand not only these protocols in isolation, but how they might be used in practice. The intention of this repository\u2019s creation is primarily as a learning aid to explore Virtual Private Networks through a heavily documented codebase outlining how WireGuard works.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Warning:<br>This implementation of UDP and WireGuard is built atop a traditional TCP Linux Socket, and as such these implementations do not work with other WireGuard implementations or servers.<\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">Outline of the Repository<\/h2>\n\n\n\n<p class=\"has-small-font-size\">There\u2019s three primary ways to approach this repository:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-small-font-size\">Want to dive into the codebase and see how UDP and WireGuard can be implemented in C++? This repository contains heavily documented source files, helping to understand how these protocols work.\n<ol class=\"wp-block-list\">\n<li class=\"has-small-font-size\">Want to better understand UDP? <code>udp.h<\/code> contains our UDP packet implementation, which is used directly by our WireGuard implementation to send packets across the network!<\/li>\n\n\n\n<li class=\"has-small-font-size\">Want to understand how WireGuard works? <code>wireguard.h<\/code> contains our WireGuard implementation, and all the cryptographic algorithms used by it are contained in <code>crypto.h<\/code>. We use both OpenSSL and Sodium for cryptography, allowing you to get a taste of how you might work with both libraries.<\/li>\n\n\n\n<li class=\"has-small-font-size\">Want to understand how to make a network-enabled C++ application? <code>main.cpp<\/code> contains the code for the main application, with <code>shared.h<\/code> containing the functions needed for thread-safe input and output, and <code>network.h<\/code> containing the code for a threaded, Dynamic Network Thread.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li class=\"has-small-font-size\">Want to see these implementations working in action? <code>main<\/code> uses our implementations to allow peers to communicate across the network using UDP packets, alongside connecting to peers acting as WireGuard servers to securely communicate with peers while staying anonymous and avoiding eavesdroppers!<\/li>\n\n\n\n<li class=\"has-small-font-size\">Want to view the codebase without descending into the raw C++? A Doxygen site is available in the <code>docs<\/code> folder which provides rendered HTML for all the various namespaces, functions, and classes. A live version is available at https:\/\/kkernick.github.io\/UDP-WG<\/li>\n<\/ol>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Tip:<br>Feeling overwhelmed? Start out with the application! There, you can get a feel on how the code actually comes together and understand the general flow of logic. When you then look into the code itself, or the Doxygen site, you\u2019ll have a better appreciation of what the various parts are used for.<\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">Application Walkthrough<\/h2>\n\n\n\n<p class=\"has-small-font-size\">This codebase compiles into a network application where peers across the network can communicate with each other using UDP packets. We use WireGuard in a similar fashion to how you might be familiar with VPNs: A private tunnel that masks your IP address and protects your traffic within the tunnel via strong encryption. All peers are capable of becoming a WireGuard server for another peer, which involves the two peers completing a handshake to derive shared transport keys, and then the establishment of a end point for the client on the server\u2019s device.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Runtime and Build-Time Dependencies<\/h3>\n\n\n\n<p class=\"has-small-font-size\">UDP-WG relies on OpenSSL and Sodium for its cryptographic operations. You\u2019ll need to install both if you want to run the application, or build it from source. Due to the nature of shared libraries, the pre-compiled application may be linked against versions of these two libraries that aren\u2019t currently on your system. If you see the following error, or something similar:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>.\/main: error while loading shared libraries: libsodium.so.23: cannot open shared object file: No such file or directory<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">Then you\u2019ll need to compile the application using your own versions. You can build the application by typing <code>make<\/code> within the UDP-WG directory. We use the <code>g++<\/code> compiler from the GNU Compiler Collection (GCC), and use the aforementioned OpenSSL and Sodium libraries. You should be able to find all of these in whatever package manager your distribution uses; below is a few of the most popular distributions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-small-font-size\">Debian-Based Distributions: <code>sudo apt-get install g++ libssl-dev libsodium-dev<\/code><\/li>\n\n\n\n<li class=\"has-small-font-size\">Fedora\/RHEL: <code>sudo dnf install gnu-c++ openssl-devel libsodium<\/code><\/li>\n\n\n\n<li class=\"has-small-font-size\">Arch-Based Distributions: <code>sudo pacman -Syu gcc openssl libsodium<\/code><\/li>\n<\/ul>\n\n\n\n<p class=\"has-small-font-size\">We provide two pre-compiled binaries, based on the version of Sodium. Sodium 23 is the current version used by Ubuntu, and this version is accordingly named <code>main23<\/code>. The latest version of Sodium, Sodium 26, has also been built for rolling release distributions, and is named <code>main26<\/code>. If both executables have errors in dynamic linking, you\u2019ll need to compile the application so that it links to your specific versions of OpenSSL and Sodium.<\/p>\n\n\n\n<p class=\"has-small-font-size\">Upon the start of program execution, UDP-WG tests its cryptographic implementations to ensure that they work as expected. You should see output like the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>Key Generation: Success!  \nKey Exchange: Success!  \nEncryption: Success!  \nDecryption: Success!  \nAED: Success: Modified message! Refusing to decrypt!  \nHash: Success!  \nHMAC: Success!  \nHMAC Authenticity: Success!  \nMAC: Success!  \nMAC Authenticity: Success!  \nIf there were any failures, the program is unstable and may not work properly! Ensure that OpenSSL is on the latest version, and try reco  \nmpiling\/using the precompiled version if issues persist!  \nPress Enter to Continue<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">If any of the text is in red, or do not specify \u201cSuccess,\u201d then there\u2019s an issue with the application that will cause errors should you continue the application. If this happens, try compiling the application for your system by running <code>make<\/code>. The output binary <code>main<\/code>, should work correctly.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Command Line Arguments<\/h3>\n\n\n\n<p class=\"has-small-font-size\">To run the application simply run <code>.\/mainXX<\/code> from your terminal, where <code>XX<\/code> is the pre-compiled version. If you\u2019re using a self-compiled version, the executable should just be <code>main<\/code>. To see what options are available on the command line, use the <code>--help<\/code> flag:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>main (--port=5000) (--addr=127.0.0.1) (--help) (--verbose) (--packet) (--log=main.log)  \n --port=5000: The port to listen on for new connections  \n --addr=127.0.0.1: The address to listen on  \n --verbose: Print verbose information, including from the network thread  \n --packet: Print the entire packet for new messages, not just the data.  \n --log: Log information to main.log  \n --help: Display this message<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-small-font-size\"><code>--port<\/code> specifies the port that the application will bind to for network communication. If you launch multiple instances of the program on the same computer, you\u2019ll need to provide a unique port for each. If the port is already in use, the application will report such an error and close; by default, the application binds to port 5000.<\/li>\n\n\n\n<li class=\"has-small-font-size\"><code>--addr<\/code> specifies the address that should be used by the application. If you\u2019re only talking to instances of the program on a single computer, leave this as the localhost address; if you want to talk across a network, use the public IP of the computer.<\/li>\n\n\n\n<li class=\"has-small-font-size\"><code>--verbose<\/code> prints verbose information to the console.<\/li>\n\n\n\n<li class=\"has-small-font-size\"><code>--packet<\/code> will print the entire packet in a neatly visualized block, rather than simply printing the source and data contained.<\/li>\n\n\n\n<li class=\"has-small-font-size\"><code>--log<\/code> will write out status messages to the provided log file, such as <code>--log=server.txt<\/code><\/li>\n\n\n\n<li class=\"has-small-font-size\"><code>--help<\/code> displays the help message.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Sending UDP Packets<\/h3>\n\n\n\n<p class=\"has-small-font-size\">Once you\u2019ve confirmed that the cryptographic operations work correctly, you should be brought to the home screen:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>UDP-WG  \nPublic Key: 228ab162c75472dd6c84636f5a5dd  \nNot connected to a WireGuard Server  \nWhat would you like to do?  \n1. Send a UDP message  \n2. View new messages (0)  \n3. Connect to a WireGuard Server  \n4. Quit  \nInput:<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">For sending UDP packets, we\u2019re only interested in option one and two. This home page constantly updates, and the (0) value in option two contains the amount of unread messages that you have received. When a new message is received, the value will turn green to alert you! Let\u2019s send a message to another computer; to do this, we\u2019ll need to have the program running on both machines, and ensure that firewalls and other security systems will permit the traffic to our chosen port. First, we choose option 1, which will bring us to the following dialog:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>Enter IP:PORT or Alias<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">Here, you can either provide the raw IP:Port combination, or an Alias if you\u2019ve already sent a message to this peer before. For our case, we\u2019re going to send a packet to the instance of this program running on the machine located at <code>192.168.101.221<\/code>, bound to the default port of 5000:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Tip:<br>Example output in this document will preface user provided input with the &gt; character!<\/p>\n\n\n\n<p class=\"has-small-font-size\">Warning:<br>This program does not resolve domain names, so <code>mydomain.com:5000<\/code> will not work! If you aren\u2019t sure what the IP of your peer is, use <code>ping<\/code>!<\/p>\n<\/blockquote>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>Enter IP:PORT or Alias  \n&gt; 192.168.101.221:5000  \nEnter an alias name to associate with this peer!\n&gt; peer<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">Here, we specify our machine, and provide an alias. This way, when we want to send another message to the peer, we can simply provide the alias:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>Enter IP:PORT or Alias  \n&gt; peer  \nWhat would you like to send?\n&gt; Hello!<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">You should then be brought back to the home screen, and your data will be packaged into a UDP packet, and sent across to the other peer. Let\u2019s take a look at their home screen!<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>UDP-WG  \nPublic Key: f4c87b8d3472b7a5ebec26ef824da87  \nNot connected to a WireGuard Server  \nWhat would you like to do?  \n1. Send a UDP message  \n2. View new messages (1)  \n3. Connect to a WireGuard Server  \n4. Quit  \nInput:<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">Notice the new message (Unfortunately, this document doesn\u2019t allow us to have color in the code blocks). Let\u2019s see what the peer sent by selecting 2!<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>Message from: 16777343:5000  \nHello!  \n\nWould you like to reply (y\/N)<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">The IP address might look a little usual, but this is simply the internal representation of the <code>127.0.0.1<\/code><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Note:<br>The standard IPv4 representation is actually just four bytes separated by dots (Hence why they only go to 255). You can very easily convert these into hexadecimal by simply converting each 255 pair into a two digit hexadecimal value (Max <code>0xFF<\/code> or 255), and putting them together in reverse order. For <code>127.0.0.1<\/code>, we\u2019d convert it into Hex as <code>7F.00.00.01<\/code>. Since network addresses are stored in Big-Endian format, we put them in reverse order <code>0100007F<\/code>, which in decimal is 16777343!<\/p>\n<\/blockquote>\n\n\n\n<p class=\"has-small-font-size\">Here, we see the source, alongside the data that we sent. If you want slightly more information, turn on the <code>--packet<\/code> argument!<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>0======1======2======3======4  \n|       PSEUDO-HEADER       |  \n=============================  \n|         16777343          |  \n|        3714427072         |  \n|  0   |  17  |     26      |  \n=============================  \n|           HEADER          |  \n=============================  \n|    5000     |    5000     |  \n|     26      |    41472    |  \n=============================  \n|            DATA           |  \n=============================  \n| Hello!                    |  \n=============================  \n\nWould you like to reply (y\/N)<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">Here, we see the contents of the Psuedo-Header, including the source address, destination address (3714427072 = <code>0xDD65A8C0<\/code> = <code>C0.A8.65.DD<\/code> = <code>192.168.101.221<\/code>), UDP identifier = 17, and the length of the whole packet 26. In the Header, we see the source and destination port, both 5000, the length again, and the checksum value of 41472. Finally, we have the data. You may notice that the source address is the local address. You may expect an attempt to reply to be send back to itself, since it would be pointed to <code>localhost:5000<\/code>, or the running program, but you can actually reply! Let\u2019s reply:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>Would you like to reply (y\/N)  \n&gt; y  \nWhat would you like to send?  \n&gt; Hi!<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">Sure enough the message gets routed, let\u2019s look back at first instance:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>UDP-WG  \nPublic Key: 228ab162c75472dd6c84636f5a5dd  \nNot connected to a WireGuard Server  \nWhat would you like to do?  \n1. Send a UDP message  \n2. View new messages (1)  \n3. Connect to a WireGuard Server  \n4. Quit  \nInput: 2  \n\nMessage from: 16777343:5000  \nHi!  \n\nWould you like to reply (y\/N)<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Info:<br>Why does this work? The Network Thread that facilitates all network communications, upon discovering a new destination, automatically gets into contact with the remote Network Thread, and establishes a <em>File Descriptor<\/em> that the two can communicate over. Both Network Threads associate this FD with the claimed source of the other peer, which means the first network thread associates this FD with the destination <code>192.168.101.221<\/code>, whereas the second peer associates the FD with the first peer\u2019s claimed source IP, which defaults to <code>127.0.0.1<\/code>. Therefore, all packets sent to <code>127.0.0.1:5000<\/code> will be sent to the other peer. To fix this use the <code>--addr<\/code> command line argument to provide your public facing IP! For example: <code>.\/main --addr=192.168.101.1<\/code> for the first program, and <code>.\/main --addr=192.168.101.221<\/code>.<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">Sending UDP Packets Across WireGuard<\/h3>\n\n\n\n<p class=\"has-small-font-size\">Let\u2019s say we have three users of the program, Alice at <code>192.168.101.1:3000<\/code>, Bob at <code>192.168.100.1:4000<\/code>, and Carol at <code>192.168.100.193:5000<\/code>. Alice wants to communicate with Carol, but wants to employ the WireGuard protocol to secure the communication. Why might we want to do this?<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-small-font-size\">Perhaps Eve is also on the <code>192.168.101.0\/24<\/code> subnet, and has set her network interface card to promiscuous mode to capture all packets on the network. Alice cannot trust her local subnet, but <code>192.168.100.0\/24<\/code> is a trusted network. If she can create a tunnel into the <code>192.168.100.0\/24<\/code> network, she can safely communicate within it. She can use WireGuard to create a secure tunnel into this secure network, thwarting Eve by encrypting her traffic within the insecure network.<\/li>\n\n\n\n<li class=\"has-small-font-size\">Perhaps Alice doesn\u2019t trust Carol. Maybe Alice\u2019s computer uses a static IP, and she worried that if Carol knew her true address, she may try to use a Denial of Service attack to take Alice off the network. Alice could instead use a WireGuard server to rout her traffic through the server, obscuring her actual IP. If Carol tried to attack her, Alice could simply close the instance with the server.<\/li>\n<\/ul>\n\n\n\n<p class=\"has-small-font-size\">In this application, WireGuard is used to connect a <em>Client<\/em> with a <em>Server<\/em>. Once a Handshake has been performed, the Server creates an <em>End-Point<\/em> for the Client on their machine. The Client can then encrypt their packets and send them to the End Point. Once received, the Server will decrypt the packets, read the embedded UDP packet, and then send that packet to its intended target. Likewise, other peers on the network can send plaintext packets to the End Point, and the Server will encrypt them and send them to the client. Let\u2019s consider the two example situations from before:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-small-font-size\">To securely encrypt her packets, Alice will create a WireGuard connection with Bob, who will act as the server. Alice will then encrypt her packets before sending them within the <code>192.168.101.0\/24<\/code> subnet. When Bob receives the packets, he will decrypt the content and send the original packet, designated for Carol, in plaintext across the trusted <code>192.168.100.0\/24<\/code> subnet. Trying to eavesdrop upon the connection, Eve will be only able to capture encrypted WireGuard packets, and her attempts to read what Alice is sending will be thwarted.<\/li>\n\n\n\n<li class=\"has-small-font-size\">To hide her IP, Alice will once again create a WireGuard connection with Bob. She will then send her packets to Bob encrypted, who will decrypt them and send them to the distrusted Carol. When Carol receives the packets, they will be sourced from the End Point. While she will seamlessly be able to reply through the End Point, allowing two-way communication (Something simple IP spoofing would be unable to accommodate), if Carol ever tried to attack Alice, she could simply terminate the WireGuard connection with Bob. Bob will then close the End Point, and Carol will have no ability to further communicate with Alice.<\/li>\n<\/ul>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Note:<br>The WireGuard protocol can effectively be thought of us as a Key-Exchange, akin to Diffie-Hellman. This means that, in the first example, Alice could just as easily create a WireGuard connection with Carol directly, and cut out Bob as a middle man; this would have the benefit of not allowing Bob to read the decrypted plaintext packets, which is useful if Bob may not be someone who can be fully trusted. However, our application does not accommodate this manner of communication. This isn\u2019t because WireGuard does not support it, nor because our implementation can\u2019t, but merely because of how we decided to showcase WireGuard in a functional application!<\/p>\n<\/blockquote>\n\n\n\n<p class=\"has-small-font-size\">So, how does Alice establish a WireGuard connection with Bob? It\u2019s actually quite easy. First, let\u2019s have each peer start an instance of the program with the correct arguments:<\/p>\n\n\n\n<ul class=\"wp-block-list has-small-font-size\">\n<li>Alice: <code>.\/main --addr=192.168.101.1 --port=3000<\/code><\/li>\n\n\n\n<li>Bob: <code>.\/main --addr=192.168.100.1 --port=4000<\/code><\/li>\n\n\n\n<li>Carol: <code>.\/main --addr=192.168.100.193 --port=5000<\/code><\/li>\n<\/ul>\n\n\n\n<p class=\"has-small-font-size\">Then, Alice selects <code>3. Connect to a WireGuard Server<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>Enter IP:PORT or Alias  \n&gt; 192.168.100.1:4000  \nEnter an alias name to associate with this peer!  \n&gt; Bob  \nWaiting for peer to respond<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">Bob will then receive a notification:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>Peer: 23439552:3000 Wants to connect to your WireGuard server.  \nTheir provided Public Key: 9e5dd6ca98a6741c4d59013a021d752  \nYour Public Key: 2fc343ab3fead63c718829d2061de  \nAccept (y\/N)? Or C to send a cookie\n&gt; y<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">In this application, public keys are sent across the wire in plaintext. This presents a possible vulnerability in which Eve could intercept the packets and initiate her own Handshake, one with Alice, and another Bob. Then, she could transparently encrypt the packets using Transport Keys derived from both peers. This vulnerability does not exist in the official WireGuard implementation, as both the public key and configuration is stored in a configuration file, rather than be communicated across the network; rather than require users to generate and point to these configurations, UDP-WG simplifies the exchange by sending the public keys across the wire to initiate the handshake.<\/p>\n\n\n\n<p class=\"has-small-font-size\">With that said, we presume that Bob and Alice have some means to verify the authenticity of the public keys, as the first 16 bytes of the truncated key are displayed both on the home screen, and during the key exchange. If Bob recognizes the key as belonging to Alice, he has three options on how to respond:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-small-font-size\">Accept the Request for a Handshake. This will result in Bob opening an End Point on his computer, located at a random port, that is then used for secure WireGuard communication to and from Alice.<\/li>\n\n\n\n<li class=\"has-small-font-size\">Refuse the Connection. One principle of WireGuard is that of <em>Stealth<\/em>. Servers and Clients should not reveal themselves unless the correct information is presented, which means that if the Server does not want to accept the connection, the Client wants to terminate the connection for any reason, or an issue occurs in the Handshake, the responsible peer does not communicate any such termination. Instead, they simply ignore the peer, letting the connection timeout. That way, if Bob doesn\u2019t want to allow Eve to establish a WireGuard connection into the subnet herself, he can simply ignore her requests, and Eve would be unable to deduce if Bob actively refused her connections, or if she simply contacted a server that wasn\u2019t exposing a WireGuard server.<\/li>\n\n\n\n<li class=\"has-small-font-size\">Send a cookie. When under load, a WireGuard server may want to defer a Handshake; rather than simply refusing the connection, Bob would send back an encrypted cookie, generated from a random value that only the server knows, hashed with the IP and Port of Alice\u2019s computer. Alice would decrypt this cookie, and after waiting a bit once again request a Handshake, this time providing the cookie. Bob would recognize this cookie, and give Alice priority on the handshake.<\/li>\n<\/ol>\n\n\n\n<p class=\"has-small-font-size\">Bob isn\u2019t currently under load, and recognizes Alice\u2019s public key, so accepts the Handshake. He then sends his own public key over to Alice, who will get her own notification:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>The Server's Public Key: 2fc343ab3fead63c718829d2061de. Is this correct? (y\/  \nN)\n&gt; y<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">Again, Alice needs to confirm that she is truly speaking with Bob, and confirms that the public key matches what she is expecting. Once she confirms, UDP-WG will perform the WireGuard handshake, and both Alice and Bob will derive a set of common transport keys that they can use to securely encrypt data to send to one another. These keys are cycled every two minutes by using a set of Ephemeral Keys on top of their Static Keys (The public portion of which was sent across the wire).<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Note:<br>The Ephemeral Keys exist to ensures perfect forward secrecy, as even if Alice and Bob have their Static Keys leaked, Eve would be unable to decrypt the prior messages sent across the insecure network as she would not have the Ephemeral Keys, which are randomly generated and constantly changed. Keys are exchanged every two minutes, or after 2**60 messages<\/p>\n<\/blockquote>\n\n\n\n<p class=\"has-small-font-size\">Alice\u2019s home screen will then update to reflect this new WireGuard connection:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>   __  ______  ____      _       ________  \n  \/ \/ \/ \/ __ \\\/ __ \\    | |     \/ \/ ____\/  \n \/ \/ \/ \/ \/ \/ \/ \/_\/ \/____| | \/| \/ \/ \/ __  \n\/ \/_\/ \/ \/_\/ \/ ____\/_____\/ |\/ |\/ \/ \/_\/ \/  \n\\____\/_____\/_\/          |__\/|__\/\\____\/  \nPublic Key: 9e5dd6ca98a6741c4d59013a021d752  \nConnected to server!  \nWhat would you like to do?  \n1. Send a UDP message over WireGuard  \n2. View new messages (0)  \n3. Disconnect from the WireGuard Server  \n4. Quit  \nInput:<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">Let\u2019s go over her new options:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-small-font-size\"><code>Send a UDP message over WireGuard<\/code> will function identically to the original UDP Message option, where Alice can provide the address and port of Carol, give her an alias, and provide the data to send. However, rather than sending this packet directly to Carol, UDP-WG will instead encrypt this packet using the shared Transport Key and send it to the End Point Bob created for her. When this packet receives Bob, he will decrypt it using his own copy of the Transport Keys, get the UDP packet placed within the WireGuard Packet, and send that packet to Carol as the intended destination. By spoofing the source to the End Point, Carol will receive the message as having been sent from the End Point, and her plaintext reply will be sent back to Bob, who will use his shared Transport Key to encrypt the packet before sending it back to Alice, who can then decrypt it and read Carol\u2019s reply, again formatted such that source appears as Carol\u2019s IP address, rather than the End Point, and the destination is Alice\u2019s actual IP address, not the End Point. This ensures a seamless communication, where neither Alice or Carol need to be aware of the WireGuard server routing their packets.<\/li>\n\n\n\n<li class=\"has-small-font-size\"><code>Disconnect from the WireGuard Server<\/code> terminates the connection between Alice and Bob. When Alice closes the connection, Bob will notice and immediately close the End Point to prevent any further traffic from being processed.<\/li>\n<\/ol>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Tip:<br>The re-keying algorithm that occurs every two minutes occurs silently in the background, avoiding Alice and Bob having to directly engage as they did with the initial Handshake. Upon completion of the handshake, the <em>mode<\/em> changes, so you have a visual indication of when it happens!<\/p>\n<\/blockquote>\n\n\n\n<h4 class=\"wp-block-heading\">Cookies<\/h4>\n\n\n\n<p class=\"has-small-font-size\">In the above example, what if Bob was under load and handling numerous WireGuard connections simultaneously? In this case, Bob would want to send a cookie to defer the Handshake process with Alice until a later date, which is mandated to at least five seconds after the initial attempt to handshake. Fortunately, this process is entirely automatic. Recall the prompt that Bob received when Alice first initialized the connection:<\/p>\n\n\n\n<pre class=\"wp-block-code\" style=\"font-size:12px\"><code>Peer: 23439552:3000 Wants to connect to your WireGuard server.  \nTheir provided Public Key: 9e5dd6ca98a6741c4d59013a021d752  \nYour Public Key: 2fc343ab3fead63c718829d2061de  \nAccept (y\/N)? Or C to send a cookie\n&gt; C<\/code><\/pre>\n\n\n\n<p class=\"has-small-font-size\">By providing <code>C<\/code> or <code>c<\/code>, Bob will not send a Response Packet, but instead a <em>Cookie<\/em>. The Cookie is a random value that changes every two minutes, hashed with Alice\u2019s IP+Port, and further encrypted with the Bob\u2019s public key using the original <code>mac1<\/code> value as Additional Authenticated Data. In essence, Bob returns a cryptographic value tied to the initial Handshake between him and Alice, that Alice will promptly decrypt and store. After the timeout period, when Alice requests a second handshake, she will automatically pass that value by calculating a second MAC, stored in the <code>mac2<\/code> section of the Packet, that is a MAC using the cookie value as the key, and the rest of the Packet as data. Bob can then verify that this <code>mac2<\/code> address is valid, both in the context of Alice\u2019s previous handshake, and also in the context of the random secret (As if Alice took longer than two minutes, then random secret on Bob\u2019s server will have changed and thus invalidated the cookie).<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Note:<br>Cookies act like a sort of priority queue for the server. If the server is sent a packet with either an empty or invalid <code>mac2<\/code>, (IE no cookie has been sent or the sent cookie expired), they can send a cookie in response. However, if the <code>mac2<\/code> <em>is<\/em> valid, they will continue the handshake process. This ensures that Alice will only need to wait at a maximum of five seconds, plus the time to actually complete the handshake itself.<\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">Codebase Walkthrough<\/h2>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Tip:<br>This Walkthrough assumes a basic understanding of C++. If you need a refresher, my previous project <a href=\"https:\/\/github.com\/kkernick\/AES-DH\">AES-DH<\/a>, has some general tips and explanations. That being said, this codebase was written such that you <em>should<\/em> be able to understand the process through the documentation alone, even if the specific idiosyncrasies of C++\u2019s syntax does not make it clear through the code itself.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"has-small-font-size\">The codebase is broken up into logical files, each containing a namespace sharing the same name as the file itself. Therefore, if you see functions like <code>wireguard::Handshake<\/code>, you know the file that this function belongs to is <code>wireguard.h<\/code>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-small-font-size\">The <code>wireguard.h<\/code> file contains all the functions and variables used by the WireGuard implementation, including the functions for initiating a handshake, and the structure of the various packets sent between peers.<\/li>\n\n\n\n<li class=\"has-small-font-size\">The <code>udp.h<\/code> file contains the <code>udp::packet<\/code>, our implementation of the UDP protocol.<\/li>\n\n\n\n<li class=\"has-small-font-size\">The <code>main.cpp<\/code> file contains the main application.<\/li>\n<\/ul>\n\n\n\n<p class=\"has-small-font-size\">If you\u2019re interested in looking at some of the auxiliary files:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-small-font-size\"><code>crypto.h<\/code> contains the implementations of the cryptographic algorithms needed by WireGuard. They use implementations from both OpenSSL and Sodium.<\/li>\n\n\n\n<li class=\"has-small-font-size\"><code>shared.h<\/code> contains various shared objects and functions, particularly mediated input and output.<\/li>\n<\/ul>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Tip:<br>Unsure which files to start with? Consider starting with <code>shared.h<\/code>, which provides the common definitions used by all the subsequent files. Then, move to <code>crypto.h<\/code> to get an understanding of the underlying cryptographic functions and data structures. With that, you\u2019ll be equipped to understand <code>udp.h<\/code> and <code>wireguard.h<\/code>, in that order, and can finally finish with <code>network.h<\/code> and <code>main.cpp<\/code>. That said, feel free to jump to whichever section most interests you, the documentation should be more the sufficient such that you don\u2019t need to read the entire codebase to understand a particular part!<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">UDP<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Note:<br>The implementation of the UDP protocol was created in reference to <a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc768\">RFC 768<\/a><\/p>\n<\/blockquote>\n\n\n\n<p class=\"has-small-font-size\">The WireGuard Protocol passes data over the UDP protocol, and as such this repository provides a sample implementation of UDP for these packets to be sent over. The <code>udp::packet<\/code> consists of three major components:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-small-font-size\">The Psuedo-Header: This contains the source and destination IP addresses, alongside a protocol number (17 for UDP), and a length for the entire packet.<\/li>\n\n\n\n<li class=\"has-small-font-size\">The Header: This contains the source and destination port the length of the entire packet, and a checksum to ensure that the values in the Psuedo-Header and Header were not changed in transit.<\/li>\n\n\n\n<li class=\"has-small-font-size\">The Data: Raw bytes that compose the content of the packet.<\/li>\n<\/ol>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Note:<br>The Psuedo-Header is typically treated as an ephemeral part of the packet, meaning that it\u2019s not actually sent as part of the packet. The reason this is possible is because both the IP addresses of source and destination are already available a layer down, within the IP Header. The Psuedo-Header exists such that these addresses can be included in the checksum calculation. UDP-WG does sent the Psuedo-Header, as its emulated network stack does not have access to the raw IP headers that are used by the Socket.<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">WireGuard<\/h3>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Note:<br>The implementation of the WireGuard protocol was made in reference to the <a href=\"https:\/\/www.wireguard.com\/papers\/wireguard.pdf\">original whitepaper<\/a><\/p>\n<\/blockquote>\n\n\n\n<p class=\"has-small-font-size\">All the code related to the WireGuard implementation are available in the <code>wireguard<\/code> namespace, and can be broadly classified into the following groups:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-small-font-size\">The Static Keys: UDP-WG generates a set of static keys on program start. This simplifies the handshake process, and removes the need to generate physical files that are then sent between the respect peers and loaded into the program.<\/li>\n\n\n\n<li class=\"has-small-font-size\">Constants: WireGuard uses many fixed constants as the start for cryptographic operations in the handshake. Some examples include the <code>CONSTRUCTION<\/code> constant used to create the Chaining Key Value used to eventually derive the Transport Keys and the <code>LABEL_MAC1<\/code> and <code>LABEL_COOKIE<\/code> that are to create the <code>mac1<\/code> value of the handshake packets, and the cookie respectively. Another type of constant is the <code>REKEY<\/code> and <code>RJECT<\/code> constants, which specify either the amount of time in seconds, or messages sent, that require a <code>REKEY<\/code>, or an outright rejection of the connection.<\/li>\n<\/ol>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Info:<br>According to the WireGuard reference, a WireGuard server will continue to handle packets after the <code>REKEY<\/code> threshold has been reached, although it will continually prompt the client to re-key. Once the <code>RJECT<\/code> threshold has exceeded, the server will refuse to handle packets until a successful re-key occurs.<\/p>\n<\/blockquote>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li class=\"has-small-font-size\">Configuration: During a Handshake, UDP-WG will construct a <code>config<\/code> structure that contains all the relevant information needed to communicate with the peer. For a client, this value is stored in the <code>wireguard_server<\/code> variable in <code>main.cpp<\/code>. For the server, this value is passed onto the newly create WireGuard Thread that manages the End Point.<\/li>\n\n\n\n<li class=\"has-small-font-size\">Random Value: The cookie that is sent by the server when under load uses a random value that changes every two minutes. the <code>Rm<\/code> is a class that implements this behavior, with the <code>cookie_random<\/code> an instance of this object that is used when creating a cookie.<\/li>\n\n\n\n<li class=\"has-small-font-size\">Packets: The WireGuard Reference contains four unique packets that are sent during handshake and subsequent communication:\n<ol class=\"wp-block-list\">\n<li>The Initial Packet, sent from the Initiator of a handshake to the Responder.<\/li>\n\n\n\n<li>The Response Packet, sent from the Responder back to the Initiator.<\/li>\n\n\n\n<li>The Cookie Packet, which is sent by the Responder to the Initiator in lieu of a Response Packet when under load<\/li>\n\n\n\n<li>The Transport Packet, which is sent after a handshake has completed, and includes the data encrypted by the shared Transport Keys.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Info:<br>These packets are implemented as derivatives of an abstract <code>Packet<\/code> class. This is due to the need to convert the <code>cryto::string<\/code> used to store secrets and other values in WireGuard, to raw bytes that can be sent across the network. The <code>Packet<\/code> class contains two methods: <code>Packet::Serialize()<\/code>, which convert a <code>crypto::string<\/code> packet into a string of bytes, and <code>Packet::Expand()<\/code> which performs the inverse of <code>Serialize<\/code>.<\/p>\n<\/blockquote>\n\n\n\n<ol start=\"6\" class=\"wp-block-list\">\n<li class=\"has-small-font-size\">Handshake Functions: The WireGuard Handshake occurs in two stages. In the first stage, <code>Handshake1<\/code>, the Initiator generates their set of ephemeral keys, ties the eventual Transport Keys to these values and their Static Keys, before sending it across to the Responder who inverses the process using the Initial Packet sent by the Initiator to arrive at a shared value <code>C<\/code> and <code>H<\/code>. In <code>Handshake2<\/code> the Responder generates their own set of Ephemeral Keys, and ties both them and their Static Keys to these shared values. The Initiator preforms the inverse of the process using the Response Packet sent by the Responder, and both arrive at a set of shared Transport Keys. This communication is controlled by the <code>Handshake<\/code> function. <code>Handshake<\/code> also manages generation and parsing of cookies.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Cryptographic Functions and Others<\/h4>\n\n\n\n<p class=\"has-small-font-size\">The auxiliary cryptographic functions used by the WireGuard implementation relies on two libraries:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-small-font-size\">OpenSSL, which provides the implementation of:\n<ol class=\"wp-block-list\">\n<li><code>HASH<\/code> using BLAKE2s hashing algorithm<\/li>\n\n\n\n<li><code>MAC<\/code> using BLAKE2s\u2019 keyed-hash functionality<\/li>\n\n\n\n<li><code>HMAC<\/code> using HMAC-BLAKE2s.<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li class=\"has-small-font-size\">Sodium, which provides the implementation of:\n<ol class=\"wp-block-list\">\n<li><code>DH<\/code> and <code>DH_GENERATE<\/code> using the Curve25519 ECC algorithm.<\/li>\n\n\n\n<li><code>ENCRYPT<\/code> and <code>DECRYPT<\/code> using the ChaCha20-Poly1305 stream cipher and message authentication code.<\/li>\n\n\n\n<li><code>XENCRYPT<\/code> and <code>XDECRYPT<\/code> using the XChaCha20-Poly1305 stream cipher and message authentication code.<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"has-small-font-size\">Note:<br>The WireGuard Reference uses the name <code>AEAD<\/code> (Authenticated Encryption with Associated Data) and <code>XAEAD<\/code> to refer to the encryption and decryption functions using the standard ChaCha20, and extended XChaCha20 functions respectively. The Difference between ChaCha20 and its extended variant come from the increased size of the nonce value. ChaCha20 uses a 96 bit nonce, whereas XChaCha20 uses a 192 bit nonce; when a nonce is chosen at random, the latter is a stronger mode of encryption. ChaCha\u2019s name is a delightful reference to the algorithm that it was based upon: Salsa.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"has-small-font-size\">Additionally, there are other members of importance:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-small-font-size\">The <code>KDF<\/code> function implements the <code>HKDF<\/code> key derivation algorithm as outlined in the WireGuard reference, utilizing the above functions.<\/li>\n\n\n\n<li class=\"has-small-font-size\">The <code>crypto::string<\/code> is a class for storing unsigned cryptographic bytes that are wiped when leaving scope.<\/li>\n\n\n\n<li class=\"has-small-font-size\">The <code>crypto::keypair<\/code> is a general purpose pair of <code>crypto::strings<\/code> that are used both in a private\/public configuration, such as the Static and Ephemeral keys, and as a unrelated collection of two values, such as the ciphertext and nonce returned by <code>XENCRYPT<\/code>.<\/li>\n<\/ol>\n\n\n\n<p class=\"has-small-font-size\">These cryptographic functions exist within the <code>crypto<\/code> namespace.<\/p>\n\n\n\n<p class=\"has-small-font-size\">Another part of the WireGuard standard is the use of timestamps, to which the TAI64N format is mandated. The implementation of this format, and auxiliary functions for working with it, exist in the <code>shared<\/code> namespace.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">UDP-WG<\/h3>\n\n\n\n<p class=\"has-small-font-size\">Code pertaining to the creation of the actual application utilizing the UDP and WG implementations is available in:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-small-font-size\">The <code>shared<\/code> namespace contains various functions and structures used throughout the program, particularly handling thread-safe input and output.<\/li>\n\n\n\n<li class=\"has-small-font-size\">The <code>main.cpp<\/code> file contains the code that drives the application.<\/li>\n\n\n\n<li class=\"has-small-font-size\">The <code>network<\/code> namespace contains the Network Thread and associated <code>network::queue<\/code> used for sending packets across the network, discovering new peers, and maintaining existing connections.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Discussion Questions<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-small-font-size\">What is the purpose of the UDP Psuedo-Header? Does it contain any information unique to the other headers of the packet in the OSI model?<\/li>\n\n\n\n<li class=\"has-small-font-size\">Recall that in a WireGuard Handshake, peers employ not only a set key-pair of statically generated keys, but also a set of ephemeral keys that persist only for the duration of the connection, and are changed on each re-key. What is the point of these ephemeral keys?<\/li>\n\n\n\n<li class=\"has-small-font-size\">Advertisements for commercial VPN services often tout that they provided military grade encryption, such that nobody can see your network activity. The <code>main<\/code> application emulates this sort of relationship, where peers connect to the commercial VPN\u2019s servers before being routed to their destination. In both these schemes, at what point is the packet encrypted? At what point is it plaintext? Who can see the network activity of the client?<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Hello everybody! I&#8217;m proud to announce the completion of my Project: UDP-WG. It&#8217;s a heavily documented C++ codebase that implements both the UDP Network Protocol, and the WireGuard VPN protocol. These implementations are used to create the main program, which allows instances to communicate with each other using either of these two protocols! The repository &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/2024\/10\/15\/udp-wg\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;UDP-WG&#8221;<\/span><\/a><\/p>\n","protected":false},"author":660,"featured_media":829,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-828","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","entry"],"featured_image_src":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-content\/uploads\/sites\/119\/2024\/10\/WireGuard-Logo.wine_-600x400.png","featured_image_src_square":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-content\/uploads\/sites\/119\/2024\/10\/WireGuard-Logo.wine_-600x600.png","author_info":{"display_name":"Kyle Kernick","author_link":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/author\/kyle-kernick\/"},"_links":{"self":[{"href":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-json\/wp\/v2\/posts\/828","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-json\/wp\/v2\/users\/660"}],"replies":[{"embeddable":true,"href":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-json\/wp\/v2\/comments?post=828"}],"version-history":[{"count":3,"href":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-json\/wp\/v2\/posts\/828\/revisions"}],"predecessor-version":[{"id":832,"href":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-json\/wp\/v2\/posts\/828\/revisions\/832"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-json\/wp\/v2\/media\/829"}],"wp:attachment":[{"href":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-json\/wp\/v2\/media?parent=828"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-json\/wp\/v2\/categories?post=828"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpsites.ucalgary.ca\/jacobson-cpsc\/wp-json\/wp\/v2\/tags?post=828"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}