WireGuard Implementation for lwIP

Overview

WireGuard Implementation for lwIP

This project is a C implementation of the WireGuard® protocol intended to be used with the lwIP IP stack

Motivation

There is a desire to use secure communication in smaller embedded devices to communicate with off-premises devices; WireGuard® seems perfect for this task due to its small code base and secure nature

This project tackles the problem of using WireGuard® on embedded systems in that it is:

  • malloc-free so fits into a fixed RAM size
  • written entirely in C
  • has low memory requirements in terms of stack size, flash storage and RAM
  • compatible with the popular lwIP IP stack

Code Layout

The code is split into four main portions

  • wireguard.c contains the bulk of the WireGuard® protocol code and is not specific to any particular IP stack
  • wireguardif.c contains the lwIP integration code and makes a netif network interface and handles periodic tasks such as keepalive/expiration timers
  • wireguard-platform.h contains the definition of the four functions to be implemented per platform (a sample implementation is given in wireguard-platform.sample)
  • crypto code (see below)

Crypto Code

The supplied cryptographic routines are written entirely in C and are not optimised for any particular platform. These work and use little memory but will probably be slow on your platform.

You probably want to swap out the suplied versions for optimised C or assembly versions or those available throught the O/S or crypto libraries on your platform. Simply edit the crypto.h header file to point at the routines you want to use.

The crypto routines supplied are:

Integrating into your platform

You will need to implement a platform file that provides four functions

  • a monotonic counter used for calculating time differences - e.g. sys_now() from lwIP
  • a tain64n timestamp function, although there are workarounds if you don't have access to a realtime clock
  • an indication of whether the system is currently under load and should generate cookie reply messages
  • a good random number generator

lwIP Code Example

(note error checking omitted)

#include "wireguardif.h"

static struct netif wg_netif_struct = {0};
static struct netif *wg_netif = NULL;
static uint8_t wireguard_peer_index = WIREGUARDIF_INVALID_INDEX;

static void wireguard_setup() {
	struct wireguard_interface wg;
	struct wireguardif_peer peer;
	ip_addr_t ipaddr = IPADDR4_INIT_BYTES(192, 168, 40, 10);
	ip_addr_t netmask = IPADDR4_INIT_BYTES(255, 255, 255, 0);
	ip_addr_t gateway = IPADDR4_INIT_BYTES(192, 168, 40, 1);

	// Setup the WireGuard device structure
	wg.private_key = "8BU1giso23adjCk93dnpLJnK788bRAtpZxs8d+Jo+Vg=";
	wg.listen_port = 51820;
	wg.bind_netif = NULL;

	// Register the new WireGuard network interface with lwIP
	wg_netif = netif_add(&wg_netif_struct, &ipaddr, &netmask, &gateway, &wg, &wireguardif_init, &ip_input);

	// Mark the interface as administratively up, link up flag is set automatically when peer connects
	netif_set_up(wg_netif);

	// Initialise the first WireGuard peer structure
	wireguardif_peer_init(&peer);
	peer.public_key = "cDfetaDFWnbxts2Pbz4vFYreikPEEVhTlV/sniIEBjo=";
	peer.preshared_key = NULL;
	// Allow all IPs through tunnel
	peer.allowed_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0);
	peer.allowed_mask = IPADDR4_INIT_BYTES(0, 0, 0, 0);

	// If we know the endpoint's address can add here
	peer.endpoint_ip = IPADDR4_INIT_BYTES(10, 0, 0, 12);
	peer.endport_port = 12345;

	// Register the new WireGuard peer with the netwok interface
	wireguardif_add_peer(wg_netif, &peer, &wireguard_peer_index);

	if ((wireguard_peer_index != WIREGUARDIF_INVALID_INDEX) && !ip_addr_isany(&peer.endpoint_ip)) {
		// Start outbound connection to peer
		wireguardif_connect(wg_net, wireguard_peer_index);
	}
}

More Information

WireGuard® was created and developed by Jason A. Donenfeld. "WireGuard" and the "WireGuard" logo are registered trademarks of Jason A. Donenfeld. See https://www.wireguard.com/ for more information

This project is not approved, sponsored or affiliated with WireGuard or with the community.

License

The code is copyrighted under BSD 3 clause Copyright (c) 2021 Daniel Hope (www.floorsense.nz)

See LICENSE for details

Contact

Daniel Hope at Smartalock

Comments
  • Crash on esp8266 arduino ide

    Crash on esp8266 arduino ide

    I was trying to port this to esp8266, compiled and uploads fine but i get constant crash and reboot, here is the decoded stack trace, my board version 2.6.3

    Exception 9: LoadStoreAlignmentCause: Load or store to an unaligned address
    PC: 0x402047fc: mul at C:\Users\lan\Documents\ARDUINO_SKETCHES\ESP_WIREGUARD/x25519.c line 61
    EXCVADDR: 0x3ffe87dd
    
    Decoding stack results
    0x402048b4: mul1 at C:\Users\lan\Documents\ARDUINO_SKETCHES\ESP_WIREGUARD/x25519.c line 156
    0x40204a02: x25519 at C:\Users\lan\Documents\ARDUINO_SKETCHES\ESP_WIREGUARD/x25519.c line 157
    0x40202836: wireguard_generate_public_key at C:\Users\lan\Documents\ARDUINO_SKETCHES\ESP_WIREGUARD/wireguard.c line 415
    0x40203885: wireguard_device_init at C:\Users\lan\Documents\ARDUINO_SKETCHES\ESP_WIREGUARD/wireguard.c line 986
    0x402045fe: wireguardif_init at C:\Users\lan\Documents\ARDUINO_SKETCHES\ESP_WIREGUARD/wireguardif.c line 920
    0x4021315c: netif_set_addr_LWIP2 at core/netif.c line 717
    0x40213210: netif_add_LWIP2 at core/netif.c line 375
    0x40204550: wireguardif_init at C:\Users\lan\Documents\ARDUINO_SKETCHES\ESP_WIREGUARD/wireguardif.c line 881
    0x4010091f: free(void*) at C:\Users\lan\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\umm_malloc\umm_malloc.cpp line 362
    0x40204f73: WireGuard::begin(IPAddress const&, char const*, char const*, char const*, unsigned short) at C:\Users\lan\Documents\ARDUINO_SKETCHES\ESP_WIREGUARD/ESP_WIREGUARD.ino line 45
    0x40217d40: ip4_input at core/ipv4/ip4.c line 1167
    0x4020691e: __delay(unsigned long) at C:\Users\lan\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_wiring.cpp line 54
    0x4020509d: setup() at C:\Users\lan\Documents\ARDUINO_SKETCHES\ESP_WIREGUARD/ESP_WIREGUARD.ino line 98
    0x4020647c: loop_wrapper() at C:\Users\lan\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\cores\esp8266\core_esp8266_main.cpp line 177
    

    here is the sketch all crypto and wireguard were placed on the root of the sketch.

    #include <Arduino.h>
    #include <ESP8266WiFi.h>
    #include <IPAddress.h>
    #include "lwip/err.h"
    #include "lwip/sys.h"
    #include "lwip/ip.h"
    #include "lwip/netdb.h"
    
    extern "C" {
    #include "wireguardif.h"
    #include "wireguard-platform.h"
    }
    
    // Wireguard instance
    static struct netif wg_netif_struct = {0};
    static struct netif *wg_netif = NULL;
    static uint8_t wireguard_peer_index = WIREGUARDIF_INVALID_INDEX;
    
    char private_key[] = "8BU1giso23adjCk93dnpLJnK788bRAtpZxs8d+Jo+Vg=";  // [Interface] PrivateKey
    IPAddress local_ip(192, 168, 0, 111);         // [Interface] Address
    char public_key[] = "x6tAoOCzdZxB2x8un4NxcW6zCbtZ9tSeSAjbS1VZPQ8=";     // [Peer] PublicKey
    char endpoint_address[] = "link.arc.soracom.io";    // [Peer] Endpoint
    int endpoint_port = 13231;              // [Peer] Endpoint
    
    class WireGuard
    {
      public:
        void begin(const IPAddress& localIP, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort);
    };
    
    void WireGuard::begin(const IPAddress& localIP, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort) {
      struct wireguardif_init_data wg;
      struct wireguardif_peer peer;
      ip_addr_t ipaddr = IPADDR4_INIT(static_cast<uint32_t>(localIP));
      ip_addr_t netmask = IPADDR4_INIT_BYTES(255, 255, 255, 0);
      ip_addr_t gateway = IPADDR4_INIT_BYTES(0, 0, 0, 0);
    
    
      // Setup the WireGuard device structure
      wg.private_key = privateKey;
      wg.listen_port = remotePeerPort;//51820;
      wg.bind_netif = NULL;
    
      // Register the new WireGuard network interface with lwIP
      wg_netif = netif_add(&wg_netif_struct, ip_2_ip4(&ipaddr), ip_2_ip4(&netmask), ip_2_ip4(&gateway), &wg, &wireguardif_init, &ip_input);
    
      // Mark the interface as administratively up, link up flag is set automatically when peer connects
      netif_set_up(wg_netif);
    
      // Initialise the first WireGuard peer structure
      wireguardif_peer_init(&peer);
      peer.public_key = remotePeerPublicKey;
      peer.preshared_key = NULL;
      
      // Allow all IPs through tunnel
      ip_addr_t allowed_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0);
      peer.allowed_ip = allowed_ip;
      ip_addr_t allowed_mask = IPADDR4_INIT_BYTES(0, 0, 0, 0);
      peer.allowed_mask = allowed_mask;
    
      // If we know the endpoint's address can add here
      ip_addr_t endpoint_ip = IPADDR4_INIT_BYTES(10, 10, 10, 1);
      peer.endpoint_ip = endpoint_ip;
      peer.endport_port = 13231;
    
      // Initialize the platform
      wireguard_platform_init();
    
      // Register the new WireGuard peer with the netwok interface
      wireguardif_add_peer(wg_netif, &peer, &wireguard_peer_index);
    
      if ((wireguard_peer_index != WIREGUARDIF_INVALID_INDEX) && !ip_addr_isany(&peer.endpoint_ip)) {
        // Start outbound connection to peer
        wireguardif_connect(wg_netif, wireguard_peer_index);
        netif_set_default(wg_netif);
      }
    }
    
    static WireGuard wireg;
    
    void setup() {
      // put your setup code here, to run once:
      Serial.println("Connected. Initializing WireGuard...");
      Serial.begin(115200);
      Serial.println("Connecting to the AP...");
    
      WiFi.mode(WIFI_STA);
      WiFi.begin("MikroTik1", "");
    
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("Connected. Initializing WireGuard...");
      delay( 5000 );
      wireg.begin(
        local_ip,
        private_key,
        endpoint_address,
        public_key,
        endpoint_port);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
    
    }
    
    opened by rjjrbatarao 6
  • wireguard_check_replay() always rejects first data packet of session

    wireguard_check_replay() always rejects first data packet of session

    In wireguard.c, line 326, wireguard_check_replay() test for the seq argument being non-zero. This is almost the first thing that the function does, and if seq is zero then the function always returns false (i.e. rejecting the packet). Since seq is the sequential packet count, beginning at zero, this means that the first data packet of a session will always be dropped by WireGuard and will require retransmission. Furthermore, since sessions are re-created every 2-3 minutes - resetting the sequence count to zero - single packets may continue to be dropped at regular intervals.

    This (and other) behaviour of wireguard_check_replay() appears to come directly from RFC2401:

    if (seq == 0) return 0;             /* first == 0 or wrapped */
    

    However the replay-checking logic in the Linux WireGuard function counter_validate(), which implements a different windowing algorithm based on RFC6479, appears to contain no such special treatment of a sequence value of zero.

    Since the dropped packets will tend to be re-transmitted, either by the TCP layer, or by the application, no actual failures are likely to be observed, but the behaviour (and that of the RFC2401 example code) is puzzling.

    opened by bwindrim 1
  • Replay window is only 4 packets wide, instead of 32

    Replay window is only 4 packets wide, instead of 32

    In wireguard_check_replay(), wireguard.c line 324, the replay window size is declared as:

    size_t ReplayWindowSize = sizeof(keypair->replay_bitmap); // 32 bits
    

    but this gives a value of 4, so that only 4 of the 32 bits in the replay bitmap are used. In RFC2401, which this is based on, the window size is declared as:

    enum { ReplayWindowSize = 32 };

    This discrepancy shouldn't cause failures, but could cause out-of-order packets to be dropped unnecessarily.

    opened by bwindrim 1
  • Added #if around definitions of x25519 macros for selection of Cortex-M0 versions.

    Added #if around definitions of x25519 macros for selection of Cortex-M0 versions.

    Allows selection of the Cortex assembly implementation in a project without the need to edit crypto.h itself. This should make it easier to incorporate wireguard-lwip into a larger SDK, as a submodule.

    This is my first GitHub pull request, so please forgive (or correct) any errors of form or etiquette.

    opened by bwindrim 0
  • Implementation on ESP8266

    Implementation on ESP8266

    Hi,

    Trying to get this to work on an ESP8266 project (while I'm a complete novice which isnt helping) I cant figure out where in the code wireguard_interface is defined and I am getting compile errors such as error: aggregate 'wireguard_setup()::wireguard_interface wg' has incomplete type and cannot be defined. Any advice would be greatly appreciated on getting a connection up and running.

    opened by LordBoBCUP 3
Owner
Daniel
Daniel
WireGuard implementation for ESP32 Arduino

WireGuard Implementation for ESP32 Arduino This is an implementation of the WireGuard® for ESP32 Arduino. Almost all of this code is based on the Wire

Kenta IDA 589 Jan 2, 2023
This is a kernel module for FreeBSD to support WireGuard

WireGuard for FreeBSD This is a kernel module for FreeBSD to support WireGuard. It is being developed here before its eventual submission to FreeBSD 1

WireGuard 38 Jan 4, 2023
Generate Vanity Public Keys for WireGuard.

wgmine Generate Vanity Public Keys for WireGuard You know what opening a wireguard config and finding out comments have been stripped feels like. You

Alessandro Romani 22 Oct 22, 2022
Single C file TLS 1.2/1.3 implementation, using tomcrypt as crypto library

TLSe Single C file TLS 1.3, 1.2, 1.1 and 1.0(without the weak ciphers) implementation, using libtomcrypt as crypto library. It also supports DTLS 1.2

Eduard Suica 481 Dec 31, 2022
C++11 implementation of Socket.IO client

By virtue of being written in C++, this client works in several different platforms. The examples folder contains an iPhone, QT and Console example chat client! It depends on websocket++ and is inspired by socket.io-clientpp.

Socket.IO 2k Jan 3, 2023
hessian2-codec it is a complete C++ implementation of hessian2 spec

hessian2-codec is a C++ library from Alibaba for hessian2 codec. It is a complete C++ implementation of hessian2 spec. Because it was originally intended to implement the Dubbo Filter of Envoy, it did not provide good support for serialization of user-defined types (there is only one way to implement user-defined types using ADL, but it is not very complete and does not support nested types well). At the moment it is simply deserializing content into some C++ intermediate types.

Alibaba 16 Nov 15, 2022
FreeModbus is a Modbus ASCII/RTU and Modbus TCP implementation for embedded systems

FreeModbus is a Modbus ASCII/RTU and Modbus TCP implementation for embedded systems. It provides an implementation of the Modbus Application Protocol

Mahmood Hosseini 22 Oct 11, 2022
Custom WebSocket implementation in C for educational and recreational purposes.

C WebSockets WARNING! The library is in an active development state and is not even alpha yet. Use it at your own risk. Nothing is documented, anythin

Tsoding 17 May 25, 2022
Backroll is a pure Rust implementation of GGPO rollback networking library.

backroll-rs Backroll is a pure Rust implementation of GGPO rollback networking library. Development Status This is still in an early beta stage. At ti

Hourai Teahouse 276 Jan 2, 2023
STARTTLS implementation for mail servers that don't have it.

smtpd-starttls-proxy - a STARTTLS implementation for mail servers ----------------------------------------------------------------- smtpd-starttls-p

Laurent Bercot 6 Dec 21, 2021
An Ace of Spades server implementation done in C

SpadesX What is SpadesX and why ? TL;DR Ace of Spades server written in C (Currently in full on development and thus early Alpha) Now if you would lik

null 38 Jan 5, 2023
An implementation of CBOR in C

CBOR This is a simple, small decoder for CBOR, the Concise Binary Object Representation. CBOR is defined by IETF RFC 8949, and Wikipedia has a good de

Kyunghwan Kwon 29 Dec 14, 2022
eBPF implementation that runs on top of Windows

eBPF for Windows eBPF is a well-known technology for providing programmability and agility, especially for extending an OS kernel, for use cases such

Microsoft 1.7k Jan 9, 2023
An implementation of the Mobile Adapter GB protocol, to connect to custom game servers.

libmobile Library that implements the Mobile Adapter GB protocol, in a way that should be easy to integrate into a plethora of different emulators/har

REON Team 10 Nov 5, 2022
The implementation of the Domino Network protocol based program.

spacex The implementation of the Domino distributed storage network protocol for the Smart Ecology. With a fully featured and well documented that pro

DominoNetwork 4 Sep 26, 2021
Simple HTTP protocol implementation in C

C-SimpleHTTP A simple HTTP protocol implementation in C How do i run it? First of all, this project is made in c, then you will need GCC Compiler. The

Spar 8 May 25, 2022
LAppS - Lua Application Server for micro-services with default communication over WebSockets. The fastest and most vertically scalable WebSockets server implementation ever. Low latency C++ <-> Lua stack roundtrip.

LAppS - Lua Application Server This is an attempt to provide very easy to use Lua Application Server working over WebSockets protocol (RFC 6455). LApp

null 48 Oct 13, 2022
This project is implementation of TFTP protocol from scratch

TFTP This project is implementation of TFTP protocol from scratch

Ali 4 Jul 23, 2022
A language server protocol implementation

A barebone LSP implementation Starting point for server implementations of the LSP protocol. Provides the infrastructure to easily hook in functionali

Henner Zeller 5 Jan 7, 2023