├── .gitignore ├── library.properties ├── src ├── crypto.c ├── crypto │ └── refc │ │ ├── poly1305-donna.h │ │ ├── x25519-license.txt │ │ ├── poly1305-donna.c │ │ ├── blake2s.h │ │ ├── chacha20.h │ │ ├── chacha20poly1305.h │ │ ├── x25519.h │ │ ├── blake2s.c │ │ ├── poly1305-donna-32.h │ │ ├── chacha20.c │ │ ├── chacha20poly1305.c │ │ └── x25519.c ├── WireGuard-ESP32.h ├── wireguard-platform.c ├── wireguard-platform.h ├── crypto.h ├── WireGuard.cpp ├── wireguardif.h ├── wireguard.h ├── wireguardif.c └── wireguard.c ├── .vscode ├── tasks.json └── c_cpp_properties.json ├── LICENSE ├── README.md └── examples ├── uptime_udp └── uptime_udp.ino ├── uptime_post └── uptime_post.ino └── disconnect └── disconnect.ino /.gitignore: -------------------------------------------------------------------------------- 1 | build.sh -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=WireGuard-ESP32 2 | version=0.1.5 3 | author=Kenta Ida 4 | maintainer=Kenta Ida 5 | sentence=WireGuard implementation for Arduino ESP32 6 | paragraph= 7 | category=Communication 8 | url=https://github.com/ciniml/WireGuard-ESP32-Arduino 9 | includes=WireGuard-ESP32.h 10 | architectures=esp32,Inkplate 11 | -------------------------------------------------------------------------------- /src/crypto.c: -------------------------------------------------------------------------------- 1 | #include "crypto.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | void crypto_zero(void *dest, size_t len) { 8 | volatile uint8_t *p = (uint8_t *)dest; 9 | while (len--) { 10 | *p++ = 0; 11 | } 12 | } 13 | 14 | bool crypto_equal(const void *a, const void *b, size_t size) { 15 | uint8_t neq = 0; 16 | while (size > 0) { 17 | neq |= *(uint8_t *)a ^ *(uint8_t *)b; 18 | a += 1; 19 | b += 1; 20 | size -= 1; 21 | } 22 | return (neq) ? false : true; 23 | } 24 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "build", 8 | "type": "shell", 9 | "options": { 10 | "cwd": "${workspaceFolder}/examples/ping" 11 | }, 12 | "command": "bash ./build.sh", 13 | "group": { 14 | "kind": "build", 15 | "isDefault": true 16 | } 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceFolder}/**", 7 | "${env:HOME}/.arduino15/packages/esp32/hardware/esp32/1.0.4/**" 8 | ], 9 | "forcedInclude": ["Arduino.h"], 10 | "defines": [], 11 | "compilerPath": "/usr/bin/clang", 12 | "cStandard": "c11", 13 | "cppStandard": "c++14", 14 | "intelliSenseMode": "linux-gcc-x64" 15 | } 16 | ], 17 | "version": 4 18 | } -------------------------------------------------------------------------------- /src/crypto/refc/poly1305-donna.h: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT 2 | #ifndef POLY1305_DONNA_H 3 | #define POLY1305_DONNA_H 4 | 5 | #include 6 | 7 | typedef struct poly1305_context { 8 | size_t aligner; 9 | unsigned char opaque[136]; 10 | } poly1305_context; 11 | 12 | void poly1305_init(poly1305_context *ctx, const unsigned char key[32]); 13 | void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes); 14 | void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]); 15 | 16 | #endif /* POLY1305_DONNA_H */ 17 | -------------------------------------------------------------------------------- /src/WireGuard-ESP32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * WireGuard implementation for ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) 3 | * SPDX-License-Identifier: BSD-3-Clause 4 | */ 5 | #pragma once 6 | #include 7 | 8 | class WireGuard 9 | { 10 | private: 11 | bool _is_initialized = false; 12 | public: 13 | bool begin(const IPAddress& localIP, const IPAddress& Subnet, const IPAddress& Gateway, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort); 14 | bool begin(const IPAddress& localIP, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort); 15 | void end(); 16 | bool is_initialized() const { return this->_is_initialized; } 17 | }; 18 | -------------------------------------------------------------------------------- /src/crypto/refc/x25519-license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2016 Cryptography Research, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/crypto/refc/poly1305-donna.c: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT 2 | 3 | #include "poly1305-donna.h" 4 | #include "poly1305-donna-32.h" 5 | 6 | void 7 | poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) { 8 | poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; 9 | size_t i; 10 | 11 | /* handle leftover */ 12 | if (st->leftover) { 13 | size_t want = (poly1305_block_size - st->leftover); 14 | if (want > bytes) 15 | want = bytes; 16 | for (i = 0; i < want; i++) 17 | st->buffer[st->leftover + i] = m[i]; 18 | bytes -= want; 19 | m += want; 20 | st->leftover += want; 21 | if (st->leftover < poly1305_block_size) 22 | return; 23 | poly1305_blocks(st, st->buffer, poly1305_block_size); 24 | st->leftover = 0; 25 | } 26 | 27 | /* process full blocks */ 28 | if (bytes >= poly1305_block_size) { 29 | size_t want = (bytes & ~(poly1305_block_size - 1)); 30 | poly1305_blocks(st, m, want); 31 | m += want; 32 | bytes -= want; 33 | } 34 | 35 | /* store leftover */ 36 | if (bytes) { 37 | for (i = 0; i < bytes; i++) 38 | st->buffer[st->leftover + i] = m[i]; 39 | st->leftover += bytes; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/crypto/refc/blake2s.h: -------------------------------------------------------------------------------- 1 | // Taken from RFC7693 - https://tools.ietf.org/html/rfc7693 2 | // BLAKE2s Hashing Context and API Prototypes 3 | #ifndef _BLAKE2S_H 4 | #define _BLAKE2S_H 5 | 6 | #define BLAKE2S_BLOCK_SIZE 64 7 | 8 | #include 9 | #include 10 | 11 | // state context 12 | typedef struct { 13 | uint8_t b[64]; // input buffer 14 | uint32_t h[8]; // chained state 15 | uint32_t t[2]; // total number of bytes 16 | size_t c; // pointer for b[] 17 | size_t outlen; // digest size 18 | } blake2s_ctx; 19 | 20 | // Initialize the hashing context "ctx" with optional key "key". 21 | // 1 <= outlen <= 32 gives the digest size in bytes. 22 | // Secret key (also <= 32 bytes) is optional (keylen = 0). 23 | int blake2s_init(blake2s_ctx *ctx, size_t outlen, 24 | const void *key, size_t keylen); // secret key 25 | 26 | // Add "inlen" bytes from "in" into the hash. 27 | void blake2s_update(blake2s_ctx *ctx, // context 28 | const void *in, size_t inlen); // data to be hashed 29 | 30 | // Generate the message digest (size given in init). 31 | // Result placed in "out". 32 | void blake2s_final(blake2s_ctx *ctx, void *out); 33 | 34 | // All-in-one convenience function. 35 | int blake2s(void *out, size_t outlen, // return buffer for digest 36 | const void *key, size_t keylen, // optional secret key 37 | const void *in, size_t inlen); // data to be hashed 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Kenta Ida (fuga@fugafuga.org) 2 | Copyright (c) 2021 Daniel Hope (www.floorsense.nz) 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this 10 | list of conditions and the following disclaimer in the documentation and/or 11 | other materials provided with the distribution. 12 | * Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of 13 | its contributors may be used to endorse or promote products derived from this 14 | software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 23 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | Author: Daniel Hope 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WireGuard Implementation for ESP32 Arduino 2 | 3 | This is an implementation of the [WireGuard®](https://www.wireguard.com/) for ESP32 Arduino. 4 | 5 | Almost all of this code is based on the [WireGuard Implementation for lwIP](https://github.com/smartalock/wireguard-lwip), but some potion of the code is adjusted to build with ESP32 Arduino. 6 | 7 | ## How to use 8 | 9 | 1. Include `WireGuard-ESP32.h` at the early part of the sketch. 10 | 11 | ```c++ 12 | #include 13 | ``` 14 | 15 | 2. Define the instance of the `WireGuard` class at module level. 16 | 17 | ```c++ 18 | static WireGuard wg; 19 | ``` 20 | 21 | 3. Connect to WiFi AP by using `WiFi` class. 22 | 23 | ```c++ 24 | WiFi.begin(ssid, password); 25 | while( !WiFi.isConnected() ) { 26 | delay(1000); 27 | } 28 | ``` 29 | 30 | 4. Sync the system time via NTP. 31 | 32 | ```c++ 33 | configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com"); 34 | ``` 35 | 36 | 5. Start the WireGuard interface. 37 | 38 | ```c++ 39 | wg.begin( 40 | local_ip, // IP address of the local interface 41 | private_key, // Private key of the local interface 42 | endpoint_address, // Address of the endpoint peer. 43 | public_key, // Public key of the endpoint peer. 44 | endpoint_port); // Port pf the endpoint peer. 45 | ``` 46 | 47 | You can see an example sketch `uptime_post.ino`, which connects SORACOM Arc WireGuard endpoint and post uptime to SORACOM Harvest via WireGuard connection. 48 | 49 | ## License 50 | 51 | The original WireGuard implementation for lwIP is licensed under BSD 3 clause license so the code in this repository also licensed under the same license. 52 | 53 | Original license is below: 54 | 55 | The code is copyrighted under BSD 3 clause Copyright (c) 2021 Daniel Hope (www.floorsense.nz) 56 | 57 | See LICENSE for details 58 | -------------------------------------------------------------------------------- /src/wireguard-platform.c: -------------------------------------------------------------------------------- 1 | /* 2 | * WireGuard implementation for ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) 3 | * SPDX-License-Identifier: BSD-3-Clause 4 | */ 5 | 6 | #include "wireguard-platform.h" 7 | 8 | #include 9 | #include "crypto.h" 10 | #include "lwip/sys.h" 11 | #include "mbedtls/entropy.h" 12 | #include "mbedtls/ctr_drbg.h" 13 | #include "esp_system.h" 14 | 15 | static struct mbedtls_ctr_drbg_context random_context; 16 | static struct mbedtls_entropy_context entropy_context; 17 | static bool is_platform_initialized = false; 18 | 19 | static int entropy_hw_random_source( void *data, unsigned char *output, size_t len, size_t *olen ) { 20 | esp_fill_random(output, len); 21 | *olen = len; 22 | return 0; 23 | } 24 | 25 | void wireguard_platform_init() { 26 | if( is_platform_initialized ) return; 27 | 28 | mbedtls_entropy_init(&entropy_context); 29 | mbedtls_ctr_drbg_init(&random_context); 30 | mbedtls_entropy_add_source(&entropy_context, entropy_hw_random_source, NULL, 134, MBEDTLS_ENTROPY_SOURCE_STRONG); 31 | mbedtls_ctr_drbg_seed(&random_context, mbedtls_entropy_func, &entropy_context, NULL, 0); 32 | 33 | is_platform_initialized = true; 34 | } 35 | 36 | void wireguard_random_bytes(void *bytes, size_t size) { 37 | uint8_t *out = (uint8_t *)bytes; 38 | mbedtls_ctr_drbg_random(&random_context, bytes, size); 39 | } 40 | 41 | uint32_t wireguard_sys_now() { 42 | // Default to the LwIP system time 43 | return sys_now(); 44 | } 45 | 46 | void wireguard_tai64n_now(uint8_t *output) { 47 | // See https://cr.yp.to/libtai/tai64.html 48 | // 64 bit seconds from 1970 = 8 bytes 49 | // 32 bit nano seconds from current second 50 | 51 | // Get timestamp. Note that the timestamp must be synced by NTP, 52 | // or at least preserved in NVS, not to go back after reset. 53 | // Otherwise, the WireGuard remote peer rejects handshake. 54 | struct timeval tv; 55 | gettimeofday(&tv, NULL); 56 | uint64_t millis = (tv.tv_sec * 1000LL + (tv.tv_usec / 1000LL)); 57 | 58 | // Split into seconds offset + nanos 59 | uint64_t seconds = 0x400000000000000aULL + (millis / 1000); 60 | uint32_t nanos = (millis % 1000) * 1000; 61 | U64TO8_BIG(output + 0, seconds); 62 | U32TO8_BIG(output + 8, nanos); 63 | } 64 | 65 | bool wireguard_is_under_load() { 66 | return false; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/crypto/refc/chacha20.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | * list of conditions and the following disclaimer in the documentation and/or 13 | * other materials provided with the distribution. 14 | * 15 | * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of 16 | * its contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | * Author: Daniel Hope 31 | */ 32 | 33 | // RFC7539 implementation of ChaCha20 with modified nonce size for WireGuard 34 | // https://tools.ietf.org/html/rfc7539 35 | // Adapted from https://cr.yp.to/streamciphers/timings/estreambench/submissions/salsa20/chacha8/ref/chacha.c by D. J. Bernstein (Public Domain) 36 | // HChaCha20 is described here: https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html 37 | #ifndef _CHACHA20_H_ 38 | #define _CHACHA20_H_ 39 | 40 | #include 41 | 42 | #define CHACHA20_BLOCK_SIZE (64) 43 | #define CHACHA20_KEY_SIZE (32) 44 | 45 | struct chacha20_ctx { 46 | uint32_t state[16]; 47 | }; 48 | 49 | void chacha20_init(struct chacha20_ctx *ctx, const uint8_t *key, const uint64_t nonce); 50 | void chacha20(struct chacha20_ctx *ctx, uint8_t *out, const uint8_t *in, uint32_t len); 51 | void hchacha20(uint8_t *out, const uint8_t *nonce, const uint8_t *key); 52 | 53 | #endif /* _CHACHA20_H_ */ 54 | -------------------------------------------------------------------------------- /examples/uptime_udp/uptime_udp.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // WiFi configuration --- UPDATE this configuration for your WiFi AP 6 | char ssid[] = "ssid"; 7 | char password[] = "password"; 8 | 9 | // WireGuard configuration --- UPDATE this configuration from JSON 10 | char private_key[] = "(Private Key) "; // [Interface] PrivateKey 11 | IPAddress local_ip(1,2,3,4); // [Interface] Address 12 | char public_key[] = "(Public Key)"; // [Peer] PublicKey 13 | char endpoint_address[] = "link.arc.soracom.io"; // [Peer] Endpoint 14 | int endpoint_port = 11010; // [Peer] Endpoint 15 | 16 | static constexpr const uint32_t UPDATE_INTERVAL_MS = 5000; 17 | 18 | static WireGuard wg; 19 | 20 | void setup() 21 | { 22 | Serial.begin(115200); 23 | Serial.println("Connecting to the AP..."); 24 | WiFi.begin(ssid, password); 25 | while( !WiFi.isConnected() ) { 26 | delay(1000); 27 | } 28 | Serial.println("Adjusting system time..."); 29 | configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com"); 30 | 31 | Serial.println("Connected. Initializing WireGuard..."); 32 | wg.begin( 33 | local_ip, 34 | private_key, 35 | endpoint_address, 36 | public_key, 37 | endpoint_port); 38 | } 39 | 40 | void loop() 41 | { 42 | static uint64_t send_count = 0; 43 | WiFiUDP client; 44 | if( !client.beginPacket("uni.soracom.io", 23080) ) { 45 | Serial.println("Failed to begin packet..."); 46 | delay(5000); 47 | return; 48 | } 49 | 50 | uint64_t uptime_msec = millis(); 51 | uint8_t buffer[16]; 52 | buffer[ 0] = (uptime_msec >> 0) & 0xff; 53 | buffer[ 1] = (uptime_msec >> 8) & 0xff; 54 | buffer[ 2] = (uptime_msec >> 16) & 0xff; 55 | buffer[ 3] = (uptime_msec >> 24) & 0xff; 56 | buffer[ 4] = (uptime_msec >> 32) & 0xff; 57 | buffer[ 5] = (uptime_msec >> 40) & 0xff; 58 | buffer[ 6] = (uptime_msec >> 48) & 0xff; 59 | buffer[ 7] = (uptime_msec >> 56) & 0xff; 60 | buffer[ 8] = (send_count >> 0) & 0xff; 61 | buffer[ 9] = (send_count >> 8) & 0xff; 62 | buffer[10] = (send_count >> 16) & 0xff; 63 | buffer[11] = (send_count >> 24) & 0xff; 64 | buffer[12] = (send_count >> 32) & 0xff; 65 | buffer[13] = (send_count >> 40) & 0xff; 66 | buffer[14] = (send_count >> 48) & 0xff; 67 | buffer[15] = (send_count >> 56) & 0xff; 68 | 69 | Serial.printf("Sending uptime %lu [ms], count=%d\r\n", uptime_msec, send_count); 70 | client.write(buffer, sizeof(buffer)); 71 | client.endPacket(); 72 | 73 | send_count++; 74 | delay(UPDATE_INTERVAL_MS); 75 | } 76 | -------------------------------------------------------------------------------- /examples/uptime_post/uptime_post.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // WiFi configuration --- UPDATE this configuration for your WiFi AP 6 | char ssid[] = "ssid"; 7 | char password[] = "password"; 8 | 9 | // WireGuard configuration --- UPDATE this configuration from JSON 10 | char private_key[] = "(Private Key) "; // [Interface] PrivateKey 11 | IPAddress local_ip(1,2,3,4); // [Interface] Address 12 | char public_key[] = "(Public Key)"; // [Peer] PublicKey 13 | char endpoint_address[] = "link.arc.soracom.io"; // [Peer] Endpoint 14 | int endpoint_port = 11010; // [Peer] Endpoint 15 | 16 | static constexpr const uint32_t UPDATE_INTERVAL_MS = 5000; 17 | 18 | static WireGuard wg; 19 | static HTTPClient httpClient; 20 | 21 | void setup() 22 | { 23 | Serial.begin(115200); 24 | Serial.println("Connecting to the AP..."); 25 | WiFi.begin(ssid, password); 26 | while( !WiFi.isConnected() ) { 27 | delay(1000); 28 | } 29 | Serial.println("Adjusting system time..."); 30 | configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com"); 31 | 32 | Serial.println("Connected. Initializing WireGuard..."); 33 | wg.begin( 34 | local_ip, 35 | private_key, 36 | endpoint_address, 37 | public_key, 38 | endpoint_port); 39 | } 40 | 41 | void loop() 42 | { 43 | WiFiClient client; 44 | 45 | if( !client.connect("uni.soracom.io", 80) ) { 46 | Serial.println("Failed to connect..."); 47 | delay(5000); 48 | return; 49 | } 50 | 51 | uint64_t uptime_msec = millis(); 52 | Serial.printf("Sending uptime %lu [ms]\r\n", uptime_msec); 53 | String json; 54 | json += "{\"uptime_msec\":"; 55 | json.concat(static_cast(uptime_msec)); 56 | json += "}"; 57 | Serial.printf("payload: %s\r\n", json.c_str()); 58 | 59 | client.write("POST / HTTP/1.1\r\n"); 60 | client.write("Host: harvest.soracom.io\r\n"); 61 | client.write("Connection: Keep-Alive\r\n"); 62 | client.write("Keep-Alive: timeout=5, max=2\r\n"); 63 | client.write("Content-Type: application/json\r\n"); 64 | client.write("Content-Length: "); 65 | client.write(String(json.length(), 10).c_str()); 66 | client.write("\r\n\r\n"); 67 | client.write(json.c_str()); 68 | 69 | while(client.connected()) { 70 | auto line = client.readStringUntil('\n'); 71 | Serial.write(line.c_str()); 72 | Serial.write("\n"); 73 | if( line == "\r" ) break; 74 | } 75 | if(client.connected()) { 76 | uint8_t buffer[256]; 77 | size_t bytesToRead = 0; 78 | while((bytesToRead = client.available()) > 0) { 79 | bytesToRead = bytesToRead > sizeof(buffer) ? sizeof(buffer) : bytesToRead; 80 | auto bytesRead = client.readBytes(buffer, bytesToRead); 81 | Serial.write(buffer, bytesRead); 82 | } 83 | } 84 | delay(UPDATE_INTERVAL_MS); 85 | } 86 | -------------------------------------------------------------------------------- /src/crypto/refc/chacha20poly1305.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | * list of conditions and the following disclaimer in the documentation and/or 13 | * other materials provided with the distribution. 14 | * 15 | * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of 16 | * its contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | * Author: Daniel Hope 31 | */ 32 | 33 | #ifndef _CHACHA20POLY1305_H_ 34 | #define _CHACHA20POLY1305_H_ 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | // Aead(key, counter, plain text, auth text) ChaCha20Poly1305 AEAD, as specified in RFC7539 [17], with its nonce being composed of 32 bits of zeros followed by the 64-bit little-endian value of counter. 41 | // AEAD_CHACHA20_POLY1305 as described in https://tools.ietf.org/html/rfc7539 42 | void chacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key); 43 | bool chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key); 44 | 45 | // Xaead(key, nonce, plain text, auth text) XChaCha20Poly1305 AEAD, with a 24-byte random nonce, instantiated using HChaCha20 [6] and ChaCha20Poly1305. 46 | // AEAD_XChaCha20_Poly1305 as described in https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html 47 | void xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key); 48 | bool xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key); 49 | 50 | #endif /* _CHACHA20POLY1305_H_ */ 51 | -------------------------------------------------------------------------------- /src/wireguard-platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) 3 | * The original license is below: 4 | * 5 | * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without modification, 9 | * are permitted provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, this 12 | * list of conditions and the following disclaimer. 13 | * 14 | * 2. Redistributions in binary form must reproduce the above copyright notice, this 15 | * list of conditions and the following disclaimer in the documentation and/or 16 | * other materials provided with the distribution. 17 | * 18 | * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of 19 | * its contributors may be used to endorse or promote products derived from this 20 | * software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 26 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | * Author: Daniel Hope 34 | */ 35 | 36 | #ifndef _WIREGUARD_PLATFORM_H_ 37 | #define _WIREGUARD_PLATFORM_H_ 38 | 39 | #include 40 | #include 41 | #include 42 | 43 | // Peers are allocated statically inside the device structure to avoid malloc 44 | #define WIREGUARD_MAX_PEERS 1 45 | #define WIREGUARD_MAX_SRC_IPS 2 46 | 47 | // Per device limit on accepting (valid) initiation requests - per peer 48 | #define MAX_INITIATIONS_PER_SECOND (2) 49 | 50 | // 51 | // Your platform integration needs to provide implementations of these functions 52 | // 53 | 54 | void wireguard_platform_init(); 55 | 56 | // The number of milliseconds since system boot - for LwIP systems this could be sys_now() 57 | uint32_t wireguard_sys_now(); 58 | 59 | // Fill the supplied buffer with random data - random data is used for generating new session keys periodically 60 | void wireguard_random_bytes(void *bytes, size_t size); 61 | 62 | // Get the current time in tai64n format - 8 byte seconds, 4 byte nano sub-second - see https://cr.yp.to/libtai/tai64.html for details 63 | // Output buffer passed is 12 bytes 64 | // The Wireguard implementation doesn't strictly need this to be a time, but instead an increasing value 65 | // The remote end of the Wireguard tunnel will use this value in handshake replay detection 66 | void wireguard_tai64n_now(uint8_t *output); 67 | 68 | // Is the system under load - i.e. should we generate cookie reply message in response to initiation messages 69 | bool wireguard_is_under_load(); 70 | 71 | #endif /* _WIREGUARD_PLATFORM_H_ */ 72 | -------------------------------------------------------------------------------- /src/crypto.h: -------------------------------------------------------------------------------- 1 | #ifndef _CRYPTO_H_ 2 | #define _CRYPTO_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // BLAKE2S IMPLEMENTATION 9 | #include "crypto/refc/blake2s.h" 10 | #define wireguard_blake2s_ctx blake2s_ctx 11 | #define wireguard_blake2s_init(ctx,outlen,key,keylen) blake2s_init(ctx,outlen,key,keylen) 12 | #define wireguard_blake2s_update(ctx,in,inlen) blake2s_update(ctx,in,inlen) 13 | #define wireguard_blake2s_final(ctx,out) blake2s_final(ctx,out) 14 | #define wireguard_blake2s(out,outlen,key,keylen,in,inlen) blake2s(out,outlen,key,keylen,in,inlen) 15 | 16 | // X25519 IMPLEMENTATION 17 | #include "crypto/refc/x25519.h" 18 | #define wireguard_x25519(a,b,c) x25519(a,b,c,1) 19 | 20 | // CHACHA20POLY1305 IMPLEMENTATION 21 | #include "crypto/refc/chacha20poly1305.h" 22 | #define wireguard_aead_encrypt(dst,src,srclen,ad,adlen,nonce,key) chacha20poly1305_encrypt(dst,src,srclen,ad,adlen,nonce,key) 23 | #define wireguard_aead_decrypt(dst,src,srclen,ad,adlen,nonce,key) chacha20poly1305_decrypt(dst,src,srclen,ad,adlen,nonce,key) 24 | #define wireguard_xaead_encrypt(dst,src,srclen,ad,adlen,nonce,key) xchacha20poly1305_encrypt(dst,src,srclen,ad,adlen,nonce,key) 25 | #define wireguard_xaead_decrypt(dst,src,srclen,ad,adlen,nonce,key) xchacha20poly1305_decrypt(dst,src,srclen,ad,adlen,nonce,key) 26 | 27 | 28 | // Endian / unaligned helper macros 29 | #define U8C(v) (v##U) 30 | #define U32C(v) (v##U) 31 | 32 | #define U8V(v) ((uint8_t)(v) & U8C(0xFF)) 33 | #define U32V(v) ((uint32_t)(v) & U32C(0xFFFFFFFF)) 34 | 35 | #define U8TO32_LITTLE(p) \ 36 | (((uint32_t)((p)[0]) ) | \ 37 | ((uint32_t)((p)[1]) << 8) | \ 38 | ((uint32_t)((p)[2]) << 16) | \ 39 | ((uint32_t)((p)[3]) << 24)) 40 | 41 | #define U8TO64_LITTLE(p) \ 42 | (((uint64_t)((p)[0]) ) | \ 43 | ((uint64_t)((p)[1]) << 8) | \ 44 | ((uint64_t)((p)[2]) << 16) | \ 45 | ((uint64_t)((p)[3]) << 24) | \ 46 | ((uint64_t)((p)[4]) << 32) | \ 47 | ((uint64_t)((p)[5]) << 40) | \ 48 | ((uint64_t)((p)[6]) << 48) | \ 49 | ((uint64_t)((p)[7]) << 56)) 50 | 51 | #define U16TO8_BIG(p, v) \ 52 | do { \ 53 | (p)[1] = U8V((v) ); \ 54 | (p)[0] = U8V((v) >> 8); \ 55 | } while (0) 56 | 57 | #define U32TO8_LITTLE(p, v) \ 58 | do { \ 59 | (p)[0] = U8V((v) ); \ 60 | (p)[1] = U8V((v) >> 8); \ 61 | (p)[2] = U8V((v) >> 16); \ 62 | (p)[3] = U8V((v) >> 24); \ 63 | } while (0) 64 | 65 | #define U32TO8_BIG(p, v) \ 66 | do { \ 67 | (p)[3] = U8V((v) ); \ 68 | (p)[2] = U8V((v) >> 8); \ 69 | (p)[1] = U8V((v) >> 16); \ 70 | (p)[0] = U8V((v) >> 24); \ 71 | } while (0) 72 | 73 | #define U64TO8_LITTLE(p, v) \ 74 | do { \ 75 | (p)[0] = U8V((v) ); \ 76 | (p)[1] = U8V((v) >> 8); \ 77 | (p)[2] = U8V((v) >> 16); \ 78 | (p)[3] = U8V((v) >> 24); \ 79 | (p)[4] = U8V((v) >> 32); \ 80 | (p)[5] = U8V((v) >> 40); \ 81 | (p)[6] = U8V((v) >> 48); \ 82 | (p)[7] = U8V((v) >> 56); \ 83 | } while (0) 84 | 85 | #define U64TO8_BIG(p, v) \ 86 | do { \ 87 | (p)[7] = U8V((v) ); \ 88 | (p)[6] = U8V((v) >> 8); \ 89 | (p)[5] = U8V((v) >> 16); \ 90 | (p)[4] = U8V((v) >> 24); \ 91 | (p)[3] = U8V((v) >> 32); \ 92 | (p)[2] = U8V((v) >> 40); \ 93 | (p)[1] = U8V((v) >> 48); \ 94 | (p)[0] = U8V((v) >> 56); \ 95 | } while (0) 96 | 97 | 98 | void crypto_zero(void *dest, size_t len); 99 | bool crypto_equal(const void *a, const void *b, size_t size); 100 | 101 | #endif /* _CRYPTO_H_ */ 102 | 103 | -------------------------------------------------------------------------------- /examples/disconnect/disconnect.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // WiFi configuration --- UPDATE this configuration for your WiFi AP 6 | char ssid[] = "ssid"; 7 | char password[] = "password"; 8 | 9 | // WireGuard configuration --- UPDATE this configuration from JSON 10 | char private_key[] = "(Private Key) "; // [Interface] PrivateKey 11 | IPAddress local_ip(1,2,3,4); // [Interface] Address 12 | char public_key[] = "(Public Key)"; // [Peer] PublicKey 13 | char endpoint_address[] = "link.arc.soracom.io"; // [Peer] Endpoint 14 | int endpoint_port = 11010; // [Peer] Endpoint 15 | 16 | const char host_inside_vpn[] = "10.0.0.1"; 17 | const char host_outside_vpn[] = "192.168.2.1"; 18 | 19 | static constexpr const uint32_t UPDATE_INTERVAL_MS = 5000; 20 | 21 | static WireGuard wg; 22 | 23 | void setup() 24 | { 25 | esp_log_level_set("*", ESP_LOG_DEBUG); 26 | 27 | Serial.begin(115200); 28 | Serial.println("Connecting to the AP..."); 29 | WiFi.begin(ssid, password); 30 | while( !WiFi.isConnected() ) { 31 | delay(1000); 32 | } 33 | 34 | Serial.println("Adjusting system time..."); 35 | configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com"); 36 | 37 | Serial.println("WiFi Connected."); 38 | } 39 | 40 | void loop() 41 | { 42 | static uint64_t send_count = 0; 43 | static uint64_t loop_count = 0; 44 | if( loop_count % 5 == 0) { 45 | if( !wg.is_initialized() ) { 46 | Serial.println("Initializing WG interface..."); 47 | if( !wg.begin( 48 | local_ip, 49 | private_key, 50 | endpoint_address, 51 | public_key, 52 | endpoint_port) ) { 53 | Serial.println("Failed to initialize WG interface."); 54 | } 55 | } 56 | else { 57 | Serial.println("Shutting down WG interface..."); 58 | wg.end(); 59 | } 60 | } 61 | loop_count++; 62 | 63 | WiFiUDP client; 64 | const char* host = wg.is_initialized() ? host_inside_vpn : host_outside_vpn; 65 | if( !client.beginPacket(host, 23080) ) { 66 | Serial.println("Failed to begin packet..."); 67 | delay(5000); 68 | return; 69 | } 70 | 71 | uint64_t uptime_msec = millis(); 72 | uint8_t buffer[16]; 73 | buffer[ 0] = (uptime_msec >> 0) & 0xff; 74 | buffer[ 1] = (uptime_msec >> 8) & 0xff; 75 | buffer[ 2] = (uptime_msec >> 16) & 0xff; 76 | buffer[ 3] = (uptime_msec >> 24) & 0xff; 77 | buffer[ 4] = (uptime_msec >> 32) & 0xff; 78 | buffer[ 5] = (uptime_msec >> 40) & 0xff; 79 | buffer[ 6] = (uptime_msec >> 48) & 0xff; 80 | buffer[ 7] = (uptime_msec >> 56) & 0xff; 81 | buffer[ 8] = (send_count >> 0) & 0xff; 82 | buffer[ 9] = (send_count >> 8) & 0xff; 83 | buffer[10] = (send_count >> 16) & 0xff; 84 | buffer[11] = (send_count >> 24) & 0xff; 85 | buffer[12] = (send_count >> 32) & 0xff; 86 | buffer[13] = (send_count >> 40) & 0xff; 87 | buffer[14] = (send_count >> 48) & 0xff; 88 | buffer[15] = (send_count >> 56) & 0xff; 89 | 90 | Serial.printf("Sending uptime %lu [ms], count=%d\r\n", uptime_msec, send_count); 91 | client.write(buffer, sizeof(buffer)); 92 | client.endPacket(); 93 | 94 | send_count++; 95 | 96 | IPAddress result; 97 | if( WiFi.hostByName("www.google.com", result) ) { 98 | Serial.printf("hostByName: %s\r\n", result.toString().c_str()); 99 | } 100 | else { 101 | Serial.printf("hostByName failed\r\n"); 102 | } 103 | 104 | delay(UPDATE_INTERVAL_MS); 105 | } 106 | -------------------------------------------------------------------------------- /src/crypto/refc/x25519.h: -------------------------------------------------------------------------------- 1 | // Taken from https://sourceforge.net/p/strobe (MIT Licence) 2 | /** 3 | * @file x25519.h 4 | * @copyright 5 | * Copyright (c) 2016 Cryptography Research, Inc. \n 6 | * Released under the MIT License. See LICENSE.txt for license information. 7 | * @author Mike Hamburg 8 | * @brief X25519 key exchange and signatures. 9 | */ 10 | 11 | #ifndef __X25519_H__ 12 | #define __X25519_H__ 13 | 14 | #define X25519_BYTES (256/8) 15 | 16 | /* The base point (9) */ 17 | extern const unsigned char X25519_BASE_POINT[X25519_BYTES]; 18 | 19 | /** Number of bytes in an EC public key */ 20 | #define EC_PUBLIC_BYTES 32 21 | 22 | /** Number of bytes in an EC private key */ 23 | #define EC_PRIVATE_BYTES 32 24 | 25 | /** 26 | * Number of bytes in a Schnorr challenge. 27 | * Could be set to 16 in a pinch. (FUTURE?) 28 | */ 29 | #define EC_CHALLENGE_BYTES 32 30 | 31 | /** Enough bytes to get a uniform sample mod #E. For eg a Brainpool 32 | * curve this would need to be more than for a private key, but due 33 | * to the special prime used by Curve25519, the same size is enough. 34 | */ 35 | #define EC_UNIFORM_BYTES 32 36 | 37 | /* x25519 scalar multiplication. Sets out to scalar*base. 38 | * 39 | * If clamp is set (and supported by X25519_INTEROP_SUPPORT_CLAMP) 40 | * then the scalar will be "clamped" like a Curve25519 secret key. 41 | * This adds almost no security, but permits interop with other x25519 42 | * implementations without manually clamping the keys. 43 | * 44 | * Per RFC 7748, this function returns failure (-1) if the output 45 | * is zero and clamp is set. This indicates "non-contributory behavior", 46 | * meaning that one party might steer the key so that the other party's 47 | * contribution doesn't matter, or contributes only a little entropy. 48 | * 49 | * WARNING: however, this function differs from RFC 7748 in another way: 50 | * it pays attention to the high bit base[EC_PUBLIC_BYTES-1] & 0x80, but 51 | * RFC 7748 says to ignore this bit. For compatibility with RFC 7748, 52 | * you must also clear this bit by running base[EC_PUBLIC_BYTES-1] &= 0x7F. 53 | * This library won't clear it for you because it takes the base point as 54 | * const, and (depending on build flags) dosen't copy it. 55 | * 56 | * If clamp==0, or if X25519_INTEROP_SUPPORT_CLAMP==0, then this function 57 | * always returns 0. 58 | */ 59 | int x25519 ( 60 | unsigned char out[EC_PUBLIC_BYTES], 61 | const unsigned char scalar[EC_PRIVATE_BYTES], 62 | const unsigned char base[EC_PUBLIC_BYTES], 63 | int clamp 64 | ); 65 | 66 | /** 67 | * Returns 0 on success, -1 on failure. 68 | * 69 | * Per RFC 7748, this function returns failure if the output 70 | * is zero and clamp is set. This usually doesn't matter for 71 | * base scalarmuls. 72 | * 73 | * If clamp==0, or if X25519_INTEROP_SUPPORT_CLAMP==0, then this function 74 | * always returns 0. 75 | * 76 | * Same as x255(out,scalar,X255_BASE_POINT), except that 77 | * other implementations may optimize it. 78 | */ 79 | static inline int x25519_base ( 80 | unsigned char out[EC_PUBLIC_BYTES], 81 | const unsigned char scalar[EC_PRIVATE_BYTES], 82 | int clamp 83 | ) { 84 | return x25519(out,scalar,X25519_BASE_POINT,clamp); 85 | } 86 | 87 | /** 88 | * As x25519_base, but with a scalar that's EC_UNIFORM_BYTES long, 89 | * and clamp always 0 (and thus, no return value). 90 | * 91 | * This is used for signing. Implementors must replace it for 92 | * curves that require more bytes for uniformity (Brainpool). 93 | */ 94 | static inline void x25519_base_uniform ( 95 | unsigned char out[EC_PUBLIC_BYTES], 96 | const unsigned char scalar[EC_UNIFORM_BYTES] 97 | ) { 98 | (void)x25519_base(out,scalar,0); 99 | } 100 | 101 | /** 102 | * STROBE-compatible Schnorr signatures using curve25519 (not ed25519) 103 | * 104 | * The user will call x25519_base_uniform(eph,eph_secret) to schedule 105 | * a random ephemeral secret key. They then call a Schnorr oracle to 106 | * get a challenge, and compute the response using this function. 107 | */ 108 | void x25519_sign_p2 ( 109 | unsigned char response[EC_PRIVATE_BYTES], 110 | const unsigned char challenge[EC_CHALLENGE_BYTES], 111 | const unsigned char eph_secret[EC_UNIFORM_BYTES], 112 | const unsigned char secret[EC_PRIVATE_BYTES] 113 | ); 114 | 115 | /** 116 | * STROBE-compatible signature verification using curve25519 (not ed25519). 117 | * This function is the public equivalent x25519_sign_p2, taking the long-term 118 | * and ephemeral public keys instead of secret ones. 119 | * 120 | * Returns -1 on failure and 0 on success. 121 | */ 122 | int x25519_verify_p2 ( 123 | const unsigned char response[X25519_BYTES], 124 | const unsigned char challenge[X25519_BYTES], 125 | const unsigned char eph[X25519_BYTES], 126 | const unsigned char pub[X25519_BYTES] 127 | ); 128 | 129 | #endif /* __X25519_H__ */ 130 | -------------------------------------------------------------------------------- /src/crypto/refc/blake2s.c: -------------------------------------------------------------------------------- 1 | // Taken from RFC7693 - https://tools.ietf.org/html/rfc7693 2 | 3 | #include "blake2s.h" 4 | #include "../../crypto.h" 5 | 6 | // Cyclic right rotation. 7 | 8 | #ifndef ROTR32 9 | #define ROTR32(x, y) (((x) >> (y)) ^ ((x) << (32 - (y)))) 10 | #endif 11 | 12 | // Mixing function G. 13 | #define B2S_G(a, b, c, d, x, y) { \ 14 | v[a] = v[a] + v[b] + x; \ 15 | v[d] = ROTR32(v[d] ^ v[a], 16); \ 16 | v[c] = v[c] + v[d]; \ 17 | v[b] = ROTR32(v[b] ^ v[c], 12); \ 18 | v[a] = v[a] + v[b] + y; \ 19 | v[d] = ROTR32(v[d] ^ v[a], 8); \ 20 | v[c] = v[c] + v[d]; \ 21 | v[b] = ROTR32(v[b] ^ v[c], 7); } 22 | 23 | // Initialization Vector. 24 | static const uint32_t blake2s_iv[8] = 25 | { 26 | 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 27 | 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 28 | }; 29 | 30 | // Compression function. "last" flag indicates last block. 31 | static void blake2s_compress(blake2s_ctx *ctx, int last) 32 | { 33 | const uint8_t sigma[10][16] = { 34 | { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, 35 | { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }, 36 | { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, 37 | { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 }, 38 | { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, 39 | { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }, 40 | { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, 41 | { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 }, 42 | { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, 43 | { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 } 44 | }; 45 | int i; 46 | uint32_t v[16], m[16]; 47 | 48 | for (i = 0; i < 8; i++) { // init work variables 49 | v[i] = ctx->h[i]; 50 | v[i + 8] = blake2s_iv[i]; 51 | } 52 | 53 | v[12] ^= ctx->t[0]; // low 32 bits of offset 54 | v[13] ^= ctx->t[1]; // high 32 bits 55 | if (last) // last block flag set ? 56 | v[14] = ~v[14]; 57 | for (i = 0; i < 16; i++) // get little-endian words 58 | m[i] = U8TO32_LITTLE(&ctx->b[4 * i]); 59 | 60 | for (i = 0; i < 10; i++) { // ten rounds 61 | B2S_G( 0, 4, 8, 12, m[sigma[i][ 0]], m[sigma[i][ 1]]); 62 | B2S_G( 1, 5, 9, 13, m[sigma[i][ 2]], m[sigma[i][ 3]]); 63 | B2S_G( 2, 6, 10, 14, m[sigma[i][ 4]], m[sigma[i][ 5]]); 64 | B2S_G( 3, 7, 11, 15, m[sigma[i][ 6]], m[sigma[i][ 7]]); 65 | B2S_G( 0, 5, 10, 15, m[sigma[i][ 8]], m[sigma[i][ 9]]); 66 | B2S_G( 1, 6, 11, 12, m[sigma[i][10]], m[sigma[i][11]]); 67 | B2S_G( 2, 7, 8, 13, m[sigma[i][12]], m[sigma[i][13]]); 68 | B2S_G( 3, 4, 9, 14, m[sigma[i][14]], m[sigma[i][15]]); 69 | } 70 | 71 | for( i = 0; i < 8; ++i ) 72 | ctx->h[i] ^= v[i] ^ v[i + 8]; 73 | } 74 | 75 | // Initialize the hashing context "ctx" with optional key "key". 76 | // 1 <= outlen <= 32 gives the digest size in bytes. 77 | // Secret key (also <= 32 bytes) is optional (keylen = 0). 78 | int blake2s_init(blake2s_ctx *ctx, size_t outlen, 79 | const void *key, size_t keylen) // (keylen=0: no key) 80 | { 81 | size_t i; 82 | 83 | if (outlen == 0 || outlen > 32 || keylen > 32) 84 | return -1; // illegal parameters 85 | 86 | for (i = 0; i < 8; i++) // state, "param block" 87 | ctx->h[i] = blake2s_iv[i]; 88 | ctx->h[0] ^= 0x01010000 ^ (keylen << 8) ^ outlen; 89 | 90 | ctx->t[0] = 0; // input count low word 91 | ctx->t[1] = 0; // input count high word 92 | ctx->c = 0; // pointer within buffer 93 | ctx->outlen = outlen; 94 | 95 | for (i = keylen; i < 64; i++) // zero input block 96 | ctx->b[i] = 0; 97 | if (keylen > 0) { 98 | blake2s_update(ctx, key, keylen); 99 | ctx->c = 64; // at the end 100 | } 101 | 102 | return 0; 103 | } 104 | 105 | // Add "inlen" bytes from "in" into the hash. 106 | void blake2s_update(blake2s_ctx *ctx, 107 | const void *in, size_t inlen) // data bytes 108 | { 109 | size_t i; 110 | 111 | for (i = 0; i < inlen; i++) { 112 | if (ctx->c == 64) { // buffer full ? 113 | ctx->t[0] += ctx->c; // add counters 114 | if (ctx->t[0] < ctx->c) // carry overflow ? 115 | ctx->t[1]++; // high word 116 | blake2s_compress(ctx, 0); // compress (not last) 117 | ctx->c = 0; // counter to zero 118 | } 119 | ctx->b[ctx->c++] = ((const uint8_t *) in)[i]; 120 | } 121 | } 122 | 123 | // Generate the message digest (size given in init). 124 | // Result placed in "out". 125 | void blake2s_final(blake2s_ctx *ctx, void *out) 126 | { 127 | size_t i; 128 | 129 | ctx->t[0] += ctx->c; // mark last block offset 130 | if (ctx->t[0] < ctx->c) // carry overflow 131 | ctx->t[1]++; // high word 132 | 133 | while (ctx->c < 64) // fill up with zeros 134 | ctx->b[ctx->c++] = 0; 135 | blake2s_compress(ctx, 1); // final block flag = 1 136 | 137 | // little endian convert and store 138 | for (i = 0; i < ctx->outlen; i++) { 139 | ((uint8_t *) out)[i] = 140 | (ctx->h[i >> 2] >> (8 * (i & 3))) & 0xFF; 141 | } 142 | } 143 | 144 | // Convenience function for all-in-one computation. 145 | int blake2s(void *out, size_t outlen, 146 | const void *key, size_t keylen, 147 | const void *in, size_t inlen) 148 | { 149 | blake2s_ctx ctx; 150 | if (blake2s_init(&ctx, outlen, key, keylen)) 151 | return -1; 152 | blake2s_update(&ctx, in, inlen); 153 | blake2s_final(&ctx, out); 154 | 155 | return 0; 156 | } 157 | -------------------------------------------------------------------------------- /src/WireGuard.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * WireGuard implementation for ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) 3 | * SPDX-License-Identifier: BSD-3-Clause 4 | */ 5 | #include "WireGuard-ESP32.h" 6 | 7 | #include "freertos/FreeRTOS.h" 8 | #include "freertos/task.h" 9 | #include "freertos/event_groups.h" 10 | #include "esp_system.h" 11 | 12 | #include "lwip/err.h" 13 | #include "lwip/sys.h" 14 | #include "lwip/ip.h" 15 | #include "lwip/netdb.h" 16 | 17 | #include "esp32-hal-log.h" 18 | 19 | extern "C" { 20 | #include "wireguardif.h" 21 | #include "wireguard-platform.h" 22 | } 23 | 24 | // Wireguard instance 25 | static struct netif wg_netif_struct = {0}; 26 | static struct netif *wg_netif = NULL; 27 | static struct netif *previous_default_netif = NULL; 28 | static uint8_t wireguard_peer_index = WIREGUARDIF_INVALID_INDEX; 29 | 30 | #define TAG "[WireGuard] " 31 | 32 | bool WireGuard::begin(const IPAddress& localIP, const IPAddress& Subnet, const IPAddress& Gateway, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort) { 33 | struct wireguardif_init_data wg; 34 | struct wireguardif_peer peer; 35 | ip_addr_t ipaddr = IPADDR4_INIT(static_cast(localIP)); 36 | ip_addr_t netmask = IPADDR4_INIT(static_cast(Subnet)); 37 | ip_addr_t gateway = IPADDR4_INIT(static_cast(Gateway)); 38 | 39 | assert(privateKey != NULL); 40 | assert(remotePeerAddress != NULL); 41 | assert(remotePeerPublicKey != NULL); 42 | assert(remotePeerPort != 0); 43 | 44 | // Setup the WireGuard device structure 45 | wg.private_key = privateKey; 46 | wg.listen_port = remotePeerPort; 47 | 48 | wg.bind_netif = NULL; 49 | 50 | // Initialise the first WireGuard peer structure 51 | wireguardif_peer_init(&peer); 52 | // If we know the endpoint's address can add here 53 | bool success_get_endpoint_ip = false; 54 | for(int retry = 0; retry < 5; retry++) { 55 | ip_addr_t endpoint_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0); 56 | struct addrinfo *res = NULL; 57 | struct addrinfo hint; 58 | memset(&hint, 0, sizeof(hint)); 59 | memset(&endpoint_ip, 0, sizeof(endpoint_ip)); 60 | if( lwip_getaddrinfo(remotePeerAddress, NULL, &hint, &res) != 0 ) { 61 | vTaskDelay(pdMS_TO_TICKS(2000)); 62 | continue; 63 | } 64 | success_get_endpoint_ip = true; 65 | struct in_addr addr4 = ((struct sockaddr_in *) (res->ai_addr))->sin_addr; 66 | inet_addr_to_ip4addr(ip_2_ip4(&endpoint_ip), &addr4); 67 | lwip_freeaddrinfo(res); 68 | 69 | peer.endpoint_ip = endpoint_ip; 70 | log_i(TAG "%s is %3d.%3d.%3d.%3d" 71 | , remotePeerAddress 72 | , (endpoint_ip.u_addr.ip4.addr >> 0) & 0xff 73 | , (endpoint_ip.u_addr.ip4.addr >> 8) & 0xff 74 | , (endpoint_ip.u_addr.ip4.addr >> 16) & 0xff 75 | , (endpoint_ip.u_addr.ip4.addr >> 24) & 0xff 76 | ); 77 | break; 78 | } 79 | if( !success_get_endpoint_ip ) { 80 | log_e(TAG "failed to get endpoint ip."); 81 | return false; 82 | } 83 | // Register the new WireGuard network interface with lwIP 84 | wg_netif = netif_add(&wg_netif_struct, ip_2_ip4(&ipaddr), ip_2_ip4(&netmask), ip_2_ip4(&gateway), &wg, &wireguardif_init, &ip_input); 85 | if( wg_netif == nullptr ) { 86 | log_e(TAG "failed to initialize WG netif."); 87 | return false; 88 | } 89 | // Mark the interface as administratively up, link up flag is set automatically when peer connects 90 | netif_set_up(wg_netif); 91 | 92 | peer.public_key = remotePeerPublicKey; 93 | peer.preshared_key = NULL; 94 | // Allow all IPs through tunnel 95 | { 96 | ip_addr_t allowed_ip = IPADDR4_INIT_BYTES(0, 0, 0, 0); 97 | peer.allowed_ip = allowed_ip; 98 | ip_addr_t allowed_mask = IPADDR4_INIT_BYTES(0, 0, 0, 0); 99 | peer.allowed_mask = allowed_mask; 100 | } 101 | 102 | peer.endport_port = remotePeerPort; 103 | 104 | // Initialize the platform 105 | wireguard_platform_init(); 106 | // Register the new WireGuard peer with the netwok interface 107 | wireguardif_add_peer(wg_netif, &peer, &wireguard_peer_index); 108 | if ((wireguard_peer_index != WIREGUARDIF_INVALID_INDEX) && !ip_addr_isany(&peer.endpoint_ip)) { 109 | // Start outbound connection to peer 110 | log_i(TAG "connecting wireguard..."); 111 | wireguardif_connect(wg_netif, wireguard_peer_index); 112 | // Save the current default interface for restoring when shutting down the WG interface. 113 | previous_default_netif = netif_default; 114 | // Set default interface to WG device. 115 | netif_set_default(wg_netif); 116 | } 117 | 118 | this->_is_initialized = true; 119 | return true; 120 | } 121 | 122 | bool WireGuard::begin(const IPAddress& localIP, const char* privateKey, const char* remotePeerAddress, const char* remotePeerPublicKey, uint16_t remotePeerPort) { 123 | // Maintain compatiblity with old begin 124 | auto subnet = IPAddress(255,255,255,255); 125 | auto gateway = IPAddress(0,0,0,0); 126 | return WireGuard::begin(localIP, subnet, gateway, privateKey, remotePeerAddress, remotePeerPublicKey, remotePeerPort); 127 | } 128 | 129 | void WireGuard::end() { 130 | if( !this->_is_initialized ) return; 131 | 132 | // Restore the default interface. 133 | netif_set_default(previous_default_netif); 134 | previous_default_netif = nullptr; 135 | // Disconnect the WG interface. 136 | wireguardif_disconnect(wg_netif, wireguard_peer_index); 137 | // Remove peer from the WG interface 138 | wireguardif_remove_peer(wg_netif, wireguard_peer_index); 139 | wireguard_peer_index = WIREGUARDIF_INVALID_INDEX; 140 | // Shutdown the wireguard interface. 141 | wireguardif_shutdown(wg_netif); 142 | // Remove the WG interface; 143 | netif_remove(wg_netif); 144 | wg_netif = nullptr; 145 | 146 | this->_is_initialized = false; 147 | } -------------------------------------------------------------------------------- /src/wireguardif.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) 3 | * The original license is below: 4 | * 5 | * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without modification, 9 | * are permitted provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, this 12 | * list of conditions and the following disclaimer. 13 | * 14 | * 2. Redistributions in binary form must reproduce the above copyright notice, this 15 | * list of conditions and the following disclaimer in the documentation and/or 16 | * other materials provided with the distribution. 17 | * 18 | * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of 19 | * its contributors may be used to endorse or promote products derived from this 20 | * software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 26 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | * Author: Daniel Hope 34 | */ 35 | 36 | 37 | #ifndef _WIREGUARDIF_H_ 38 | #define _WIREGUARDIF_H_ 39 | 40 | #include "lwip/arch.h" 41 | #include "lwip/netif.h" 42 | #include "lwip/ip_addr.h" 43 | 44 | // Default MTU for WireGuard is 1420 bytes 45 | #define WIREGUARDIF_MTU (1420) 46 | 47 | #define WIREGUARDIF_DEFAULT_PORT (51820) 48 | #define WIREGUARDIF_KEEPALIVE_DEFAULT (0xFFFF) 49 | 50 | struct wireguardif_init_data { 51 | // Required: the private key of this WireGuard network interface 52 | const char *private_key; 53 | // Required: What UDP port to listen on 54 | u16_t listen_port; 55 | // Optional: restrict send/receive of encapsulated WireGuard traffic to this network interface only (NULL to use routing table) 56 | struct netif *bind_netif; 57 | }; 58 | 59 | struct wireguardif_peer { 60 | const char *public_key; 61 | // Optional pre-shared key (32 bytes) - make sure this is NULL if not to be used 62 | const uint8_t *preshared_key; 63 | // tai64n of largest timestamp we have seen during handshake to avoid replays 64 | uint8_t greatest_timestamp[12]; 65 | 66 | // Allowed ip/netmask (can add additional later but at least one is required) 67 | ip_addr_t allowed_ip; 68 | ip_addr_t allowed_mask; 69 | 70 | // End-point details (may be blank) 71 | ip_addr_t endpoint_ip; 72 | u16_t endport_port; 73 | u16_t keep_alive; 74 | }; 75 | 76 | #define WIREGUARDIF_INVALID_INDEX (0xFF) 77 | 78 | /* static struct netif wg_netif_struct = {0}; 79 | * struct wireguard_interface wg; 80 | * wg.private_key = "abcdefxxx..xxxxx="; 81 | * wg.listen_port = 51820; 82 | * wg.bind_netif = NULL; // Pass netif to listen on, NULL for all interfaces 83 | * 84 | * netif = netif_add(&netif_struct, &ipaddr, &netmask, &gateway, &wg, &wireguardif_init, &ip_input); 85 | * 86 | * netif_set_up(wg_net); 87 | * 88 | * struct wireguardif_peer peer; 89 | * wireguardif_peer_init(&peer); 90 | * peer.public_key = "apoehc...4322abcdfejg=; 91 | * peer.preshared_key = NULL; 92 | * peer.allowed_ip = allowed_ip; 93 | * peer.allowed_mask = allowed_mask; 94 | * 95 | * // If you want to enable output connection 96 | * peer.endpoint_ip = peer_ip; 97 | * peer.endport_port = 12345; 98 | * 99 | * uint8_t wireguard_peer_index; 100 | * wireguardif_add_peer(netif, &peer, &wireguard_peer_index); 101 | * 102 | * if ((wireguard_peer_index != WIREGUARDIF_INVALID_INDEX) && !ip_addr_isany(&peer.endpoint_ip)) { 103 | * // Start outbound connection to peer 104 | * wireguardif_connect(wg_net, wireguard_peer_index); 105 | * } 106 | * 107 | */ 108 | 109 | // Initialise a new WireGuard network interface (netif) 110 | err_t wireguardif_init(struct netif *netif); 111 | 112 | // Shutdown a WireGuard network interface (netif) 113 | void wireguardif_shutdown(struct netif *netif); 114 | 115 | // Helper to initialise the peer struct with defaults 116 | void wireguardif_peer_init(struct wireguardif_peer *peer); 117 | 118 | // Add a new peer to the specified interface - see wireguard.h for maximum number of peers allowed 119 | // On success the peer_index can be used to reference this peer in future function calls 120 | err_t wireguardif_add_peer(struct netif *netif, struct wireguardif_peer *peer, u8_t *peer_index); 121 | 122 | // Remove the given peer from the network interface 123 | err_t wireguardif_remove_peer(struct netif *netif, u8_t peer_index); 124 | 125 | // Update the "connect" IP of the given peer 126 | err_t wireguardif_update_endpoint(struct netif *netif, u8_t peer_index, const ip_addr_t *ip, u16_t port); 127 | 128 | // Try and connect to the given peer 129 | err_t wireguardif_connect(struct netif *netif, u8_t peer_index); 130 | 131 | // Stop trying to connect to the given peer 132 | err_t wireguardif_disconnect(struct netif *netif, u8_t peer_index); 133 | 134 | // Is the given peer "up"? A peer is up if it has a valid session key it can communicate with 135 | err_t wireguardif_peer_is_up(struct netif *netif, u8_t peer_index, ip_addr_t *current_ip, u16_t *current_port); 136 | 137 | #endif /* _WIREGUARDIF_H_ */ 138 | -------------------------------------------------------------------------------- /src/crypto/refc/poly1305-donna-32.h: -------------------------------------------------------------------------------- 1 | // Taken from https://github.com/floodyberry/poly1305-donna - public domain or MIT 2 | /* 3 | poly1305 implementation using 32 bit * 32 bit = 64 bit multiplication and 64 bit addition 4 | */ 5 | 6 | #if defined(_MSC_VER) 7 | #define POLY1305_NOINLINE __declspec(noinline) 8 | #elif defined(__GNUC__) 9 | #define POLY1305_NOINLINE __attribute__((noinline)) 10 | #else 11 | #define POLY1305_NOINLINE 12 | #endif 13 | 14 | #define poly1305_block_size 16 15 | 16 | /* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */ 17 | typedef struct poly1305_state_internal_t { 18 | unsigned long r[5]; 19 | unsigned long h[5]; 20 | unsigned long pad[4]; 21 | size_t leftover; 22 | unsigned char buffer[poly1305_block_size]; 23 | unsigned char final; 24 | } poly1305_state_internal_t; 25 | 26 | /* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in little endian */ 27 | static unsigned long 28 | U8TO32(const unsigned char *p) { 29 | return 30 | (((unsigned long)(p[0] & 0xff) ) | 31 | ((unsigned long)(p[1] & 0xff) << 8) | 32 | ((unsigned long)(p[2] & 0xff) << 16) | 33 | ((unsigned long)(p[3] & 0xff) << 24)); 34 | } 35 | 36 | /* store a 32 bit unsigned integer as four 8 bit unsigned integers in little endian */ 37 | static void 38 | U32TO8(unsigned char *p, unsigned long v) { 39 | p[0] = (v ) & 0xff; 40 | p[1] = (v >> 8) & 0xff; 41 | p[2] = (v >> 16) & 0xff; 42 | p[3] = (v >> 24) & 0xff; 43 | } 44 | 45 | void 46 | poly1305_init(poly1305_context *ctx, const unsigned char key[32]) { 47 | poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; 48 | 49 | /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ 50 | st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff; 51 | st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03; 52 | st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff; 53 | st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff; 54 | st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; 55 | 56 | /* h = 0 */ 57 | st->h[0] = 0; 58 | st->h[1] = 0; 59 | st->h[2] = 0; 60 | st->h[3] = 0; 61 | st->h[4] = 0; 62 | 63 | /* save pad for later */ 64 | st->pad[0] = U8TO32(&key[16]); 65 | st->pad[1] = U8TO32(&key[20]); 66 | st->pad[2] = U8TO32(&key[24]); 67 | st->pad[3] = U8TO32(&key[28]); 68 | 69 | st->leftover = 0; 70 | st->final = 0; 71 | } 72 | 73 | static void 74 | poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) { 75 | const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */ 76 | unsigned long r0,r1,r2,r3,r4; 77 | unsigned long s1,s2,s3,s4; 78 | unsigned long h0,h1,h2,h3,h4; 79 | unsigned long long d0,d1,d2,d3,d4; 80 | unsigned long c; 81 | 82 | r0 = st->r[0]; 83 | r1 = st->r[1]; 84 | r2 = st->r[2]; 85 | r3 = st->r[3]; 86 | r4 = st->r[4]; 87 | 88 | s1 = r1 * 5; 89 | s2 = r2 * 5; 90 | s3 = r3 * 5; 91 | s4 = r4 * 5; 92 | 93 | h0 = st->h[0]; 94 | h1 = st->h[1]; 95 | h2 = st->h[2]; 96 | h3 = st->h[3]; 97 | h4 = st->h[4]; 98 | 99 | while (bytes >= poly1305_block_size) { 100 | /* h += m[i] */ 101 | h0 += (U8TO32(m+ 0) ) & 0x3ffffff; 102 | h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; 103 | h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; 104 | h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; 105 | h4 += (U8TO32(m+12) >> 8) | hibit; 106 | 107 | /* h *= r */ 108 | d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); 109 | d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2); 110 | d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3); 111 | d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4); 112 | d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); 113 | 114 | /* (partial) h %= p */ 115 | c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; 116 | d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; 117 | d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; 118 | d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; 119 | d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; 120 | h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; 121 | h1 += c; 122 | 123 | m += poly1305_block_size; 124 | bytes -= poly1305_block_size; 125 | } 126 | 127 | st->h[0] = h0; 128 | st->h[1] = h1; 129 | st->h[2] = h2; 130 | st->h[3] = h3; 131 | st->h[4] = h4; 132 | } 133 | 134 | POLY1305_NOINLINE void 135 | poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) { 136 | poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; 137 | unsigned long h0,h1,h2,h3,h4,c; 138 | unsigned long g0,g1,g2,g3,g4; 139 | unsigned long long f; 140 | unsigned long mask; 141 | 142 | /* process the remaining block */ 143 | if (st->leftover) { 144 | size_t i = st->leftover; 145 | st->buffer[i++] = 1; 146 | for (; i < poly1305_block_size; i++) 147 | st->buffer[i] = 0; 148 | st->final = 1; 149 | poly1305_blocks(st, st->buffer, poly1305_block_size); 150 | } 151 | 152 | /* fully carry h */ 153 | h0 = st->h[0]; 154 | h1 = st->h[1]; 155 | h2 = st->h[2]; 156 | h3 = st->h[3]; 157 | h4 = st->h[4]; 158 | 159 | c = h1 >> 26; h1 = h1 & 0x3ffffff; 160 | h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; 161 | h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; 162 | h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; 163 | h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; 164 | h1 += c; 165 | 166 | /* compute h + -p */ 167 | g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; 168 | g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; 169 | g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; 170 | g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; 171 | g4 = h4 + c - (1UL << 26); 172 | 173 | /* select h if h < p, or h + -p if h >= p */ 174 | mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1; 175 | g0 &= mask; 176 | g1 &= mask; 177 | g2 &= mask; 178 | g3 &= mask; 179 | g4 &= mask; 180 | mask = ~mask; 181 | h0 = (h0 & mask) | g0; 182 | h1 = (h1 & mask) | g1; 183 | h2 = (h2 & mask) | g2; 184 | h3 = (h3 & mask) | g3; 185 | h4 = (h4 & mask) | g4; 186 | 187 | /* h = h % (2^128) */ 188 | h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; 189 | h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; 190 | h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; 191 | h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; 192 | 193 | /* mac = (h + pad) % (2^128) */ 194 | f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f; 195 | f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; 196 | f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; 197 | f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; 198 | 199 | U32TO8(mac + 0, h0); 200 | U32TO8(mac + 4, h1); 201 | U32TO8(mac + 8, h2); 202 | U32TO8(mac + 12, h3); 203 | 204 | /* zero out the state */ 205 | st->h[0] = 0; 206 | st->h[1] = 0; 207 | st->h[2] = 0; 208 | st->h[3] = 0; 209 | st->h[4] = 0; 210 | st->r[0] = 0; 211 | st->r[1] = 0; 212 | st->r[2] = 0; 213 | st->r[3] = 0; 214 | st->r[4] = 0; 215 | st->pad[0] = 0; 216 | st->pad[1] = 0; 217 | st->pad[2] = 0; 218 | st->pad[3] = 0; 219 | } 220 | 221 | -------------------------------------------------------------------------------- /src/crypto/refc/chacha20.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | * list of conditions and the following disclaimer in the documentation and/or 13 | * other materials provided with the distribution. 14 | * 15 | * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of 16 | * its contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | * Author: Daniel Hope 31 | */ 32 | 33 | // RFC7539 implementation of ChaCha20 with modified nonce size for WireGuard 34 | // https://tools.ietf.org/html/rfc7539 35 | // Adapted from https://cr.yp.to/streamciphers/timings/estreambench/submissions/salsa20/chacha8/ref/chacha.c by D. J. Bernstein (Public Domain) 36 | // HChaCha20 is described here: https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html 37 | 38 | #include "chacha20.h" 39 | 40 | #include 41 | #include 42 | #include "../../crypto.h" 43 | 44 | // 2.3. The ChaCha20 Block Function 45 | // The first four words (0-3) are constants: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 46 | static const uint32_t CHACHA20_CONSTANT_1 = 0x61707865; 47 | static const uint32_t CHACHA20_CONSTANT_2 = 0x3320646e; 48 | static const uint32_t CHACHA20_CONSTANT_3 = 0x79622d32; 49 | static const uint32_t CHACHA20_CONSTANT_4 = 0x6b206574; 50 | 51 | #define ROTL32(v, n) (U32V((v) << (n)) | ((v) >> (32 - (n)))) 52 | 53 | #define PLUS(v,w) (U32V((v) + (w))) 54 | #define PLUSONE(v) (PLUS((v),1)) 55 | 56 | // 2.1. The ChaCha Quarter Round 57 | // 1. a += b; d ^= a; d <<<= 16; 58 | // 2. c += d; b ^= c; b <<<= 12; 59 | // 3. a += b; d ^= a; d <<<= 8; 60 | // 4. c += d; b ^= c; b <<<= 7; 61 | 62 | #define QUARTERROUND(a, b, c, d) \ 63 | a += b; d ^= a; d = ROTL32(d, 16); \ 64 | c += d; b ^= c; b = ROTL32(b, 12); \ 65 | a += b; d ^= a; d = ROTL32(d, 8); \ 66 | c += d; b ^= c; b = ROTL32(b, 7) 67 | 68 | static inline void INNER_BLOCK(uint32_t *block) { 69 | QUARTERROUND(block[0], block[4], block[ 8], block[12]); // column 0 70 | QUARTERROUND(block[1], block[5], block[ 9], block[13]); // column 1 71 | QUARTERROUND(block[2], block[6], block[10], block[14]); // column 2 72 | QUARTERROUND(block[3], block[7], block[11], block[15]); // column 3 73 | QUARTERROUND(block[0], block[5], block[10], block[15]); // diagonal 1 74 | QUARTERROUND(block[1], block[6], block[11], block[12]); // diagonal 2 75 | QUARTERROUND(block[2], block[7], block[ 8], block[13]); // diagonal 3 76 | QUARTERROUND(block[3], block[4], block[ 9], block[14]); // diagonal 4 77 | } 78 | 79 | #define TWENTY_ROUNDS(x) ( \ 80 | INNER_BLOCK(x), \ 81 | INNER_BLOCK(x), \ 82 | INNER_BLOCK(x), \ 83 | INNER_BLOCK(x), \ 84 | INNER_BLOCK(x), \ 85 | INNER_BLOCK(x), \ 86 | INNER_BLOCK(x), \ 87 | INNER_BLOCK(x), \ 88 | INNER_BLOCK(x), \ 89 | INNER_BLOCK(x) \ 90 | ) 91 | 92 | // 2.3. The ChaCha20 Block Function 93 | // chacha20_block(key, counter, nonce): 94 | // state = constants | key | counter | nonce 95 | // working_state = state 96 | // for i=1 upto 10 97 | // inner_block(working_state) 98 | // end 99 | // state += working_state 100 | // return serialize(state) 101 | // end 102 | static void chacha20_block(struct chacha20_ctx *ctx, uint8_t *stream) { 103 | uint32_t working_state[16]; 104 | int i; 105 | 106 | for (i = 0; i < 16; ++i) { 107 | working_state[i] = ctx->state[i]; 108 | } 109 | 110 | TWENTY_ROUNDS(working_state); 111 | 112 | for (i = 0; i < 16; ++i) { 113 | U32TO8_LITTLE(stream + (4 * i), PLUS(working_state[i], ctx->state[i])); 114 | } 115 | } 116 | 117 | void chacha20(struct chacha20_ctx *ctx, uint8_t *out, const uint8_t *in, uint32_t len) { 118 | uint8_t output[CHACHA20_BLOCK_SIZE]; 119 | int i; 120 | 121 | if (len) { 122 | for (;;) { 123 | chacha20_block(ctx, output); 124 | // Word 12 is a block counter 125 | ctx->state[12] = PLUSONE(ctx->state[12]); 126 | if (len <= 64) { 127 | for (i = 0;i < len;++i) { 128 | out[i] = in[i] ^ output[i]; 129 | } 130 | return; 131 | } 132 | for (i = 0;i < 64;++i) { 133 | out[i] = in[i] ^ output[i]; 134 | } 135 | len -= 64; 136 | out += 64; 137 | in += 64; 138 | } 139 | } 140 | } 141 | 142 | 143 | // 2.3. The ChaCha20 Block Function 144 | // The first four words (0-3) are constants: 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 145 | // The next eight words (4-11) are taken from the 256-bit key by reading the bytes in little-endian order, in 4-byte chunks. 146 | // Word 12 is a block counter. Since each block is 64-byte, a 32-bit word is enough for 256 gigabytes of data. 147 | // Words 13-15 are a nonce, which should not be repeated for the same key. 148 | // For wireguard: "nonce being composed of 32 bits of zeros followed by the 64-bit little-endian value of counter." where counter comes from the Wireguard layer and is separate from the block counter in word 12 149 | void chacha20_init(struct chacha20_ctx *ctx, const uint8_t *key, const uint64_t nonce) { 150 | ctx->state[0] = CHACHA20_CONSTANT_1; 151 | ctx->state[1] = CHACHA20_CONSTANT_2; 152 | ctx->state[2] = CHACHA20_CONSTANT_3; 153 | ctx->state[3] = CHACHA20_CONSTANT_4; 154 | ctx->state[4] = U8TO32_LITTLE(key + 0); 155 | ctx->state[5] = U8TO32_LITTLE(key + 4); 156 | ctx->state[6] = U8TO32_LITTLE(key + 8); 157 | ctx->state[7] = U8TO32_LITTLE(key + 12); 158 | ctx->state[8] = U8TO32_LITTLE(key + 16); 159 | ctx->state[9] = U8TO32_LITTLE(key + 20); 160 | ctx->state[10] = U8TO32_LITTLE(key + 24); 161 | ctx->state[11] = U8TO32_LITTLE(key + 28); 162 | ctx->state[12] = 0; 163 | ctx->state[13] = 0; 164 | ctx->state[14] = nonce & 0xFFFFFFFF; 165 | ctx->state[15] = nonce >> 32; 166 | } 167 | 168 | // 2.2. HChaCha20 169 | // HChaCha20 is initialized the same way as the ChaCha cipher, except that HChaCha20 uses a 128-bit nonce and has no counter. 170 | // After initialization, proceed through the ChaCha rounds as usual. 171 | // Once the 20 ChaCha rounds have been completed, the first 128 bits and last 128 bits of the ChaCha state (both little-endian) are concatenated, and this 256-bit subkey is returned. 172 | void hchacha20(uint8_t *out, const uint8_t *nonce, const uint8_t *key) { 173 | uint32_t state[16]; 174 | state[0] = CHACHA20_CONSTANT_1; 175 | state[1] = CHACHA20_CONSTANT_2; 176 | state[2] = CHACHA20_CONSTANT_3; 177 | state[3] = CHACHA20_CONSTANT_4; 178 | state[4] = U8TO32_LITTLE(key + 0); 179 | state[5] = U8TO32_LITTLE(key + 4); 180 | state[6] = U8TO32_LITTLE(key + 8); 181 | state[7] = U8TO32_LITTLE(key + 12); 182 | state[8] = U8TO32_LITTLE(key + 16); 183 | state[9] = U8TO32_LITTLE(key + 20); 184 | state[10] = U8TO32_LITTLE(key + 24); 185 | state[11] = U8TO32_LITTLE(key + 28); 186 | state[12] = U8TO32_LITTLE(nonce + 0); 187 | state[13] = U8TO32_LITTLE(nonce + 4); 188 | state[14] = U8TO32_LITTLE(nonce + 8); 189 | state[15] = U8TO32_LITTLE(nonce + 12); 190 | 191 | TWENTY_ROUNDS(state); 192 | 193 | // Concatenate first/last 128 bits into 256bit output (as little endian) 194 | U32TO8_LITTLE(out + 0, state[0]); 195 | U32TO8_LITTLE(out + 4, state[1]); 196 | U32TO8_LITTLE(out + 8, state[2]); 197 | U32TO8_LITTLE(out + 12, state[3]); 198 | U32TO8_LITTLE(out + 16, state[12]); 199 | U32TO8_LITTLE(out + 20, state[13]); 200 | U32TO8_LITTLE(out + 24, state[14]); 201 | U32TO8_LITTLE(out + 28, state[15]); 202 | } 203 | -------------------------------------------------------------------------------- /src/crypto/refc/chacha20poly1305.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, this 12 | * list of conditions and the following disclaimer in the documentation and/or 13 | * other materials provided with the distribution. 14 | * 15 | * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of 16 | * its contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 23 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | * Author: Daniel Hope 31 | */ 32 | 33 | // AEAD_CHACHA20_POLY1305 as described in https://tools.ietf.org/html/rfc7539 34 | // AEAD_XChaCha20_Poly1305 as described in https://tools.ietf.org/id/draft-arciszewski-xchacha-02.html 35 | #include "chacha20poly1305.h" 36 | #include "chacha20.h" 37 | #include "poly1305-donna.h" 38 | 39 | #include 40 | #include 41 | #include "../../crypto.h" 42 | 43 | #define POLY1305_KEY_SIZE 32 44 | #define POLY1305_MAC_SIZE 16 45 | 46 | static const uint8_t zero[CHACHA20_BLOCK_SIZE] = { 0 }; 47 | 48 | // 2.6. Generating the Poly1305 Key Using ChaCha20 49 | static void generate_poly1305_key(struct poly1305_context *poly1305_state, struct chacha20_ctx *chacha20_state, const uint8_t *key, uint64_t nonce) { 50 | uint8_t block[POLY1305_KEY_SIZE] = {0}; 51 | 52 | // The method is to call the block function with the following parameters: 53 | // - The 256-bit session integrity key is used as the ChaCha20 key. 54 | // - The block counter is set to zero. 55 | // - The protocol will specify a 96-bit or 64-bit nonce 56 | chacha20_init(chacha20_state, key, nonce); 57 | 58 | // We take the first 256 bits or the serialized state, and use those as the one-time Poly1305 key 59 | chacha20(chacha20_state, block, block, sizeof(block)); 60 | 61 | poly1305_init(poly1305_state, block); 62 | 63 | crypto_zero(&block, sizeof(block)); 64 | } 65 | 66 | // 2.8. AEAD Construction (Encryption) 67 | void chacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key) { 68 | struct poly1305_context poly1305_state; 69 | struct chacha20_ctx chacha20_state; 70 | uint8_t block[8]; 71 | size_t padded_len; 72 | 73 | // First, a Poly1305 one-time key is generated from the 256-bit key and nonce using the procedure described in Section 2.6. 74 | generate_poly1305_key(&poly1305_state, &chacha20_state, key, nonce); 75 | 76 | // Next, the ChaCha20 encryption function is called to encrypt the plaintext, using the same key and nonce, and with the initial counter set to 1. 77 | chacha20(&chacha20_state, dst, src, src_len); 78 | 79 | // Finally, the Poly1305 function is called with the Poly1305 key calculated above, and a message constructed as a concatenation of the following: 80 | // - The AAD 81 | poly1305_update(&poly1305_state, ad, ad_len); 82 | // - padding1 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16 83 | padded_len = (ad_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes 84 | poly1305_update(&poly1305_state, zero, padded_len - ad_len); 85 | // - The ciphertext 86 | poly1305_update(&poly1305_state, dst, src_len); 87 | // - padding2 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16. 88 | padded_len = (src_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes 89 | poly1305_update(&poly1305_state, zero, padded_len - src_len); 90 | // - The length of the additional data in octets (as a 64-bit little-endian integer) 91 | U64TO8_LITTLE(block, (uint64_t)ad_len); 92 | poly1305_update(&poly1305_state, block, sizeof(block)); 93 | // - The length of the ciphertext in octets (as a 64-bit little-endian integer). 94 | U64TO8_LITTLE(block, (uint64_t)src_len); 95 | poly1305_update(&poly1305_state, block, sizeof(block)); 96 | 97 | // The output from the AEAD is twofold: 98 | // - A ciphertext of the same length as the plaintext. (above, output of chacha20 into dst) 99 | // - A 128-bit tag, which is the output of the Poly1305 function. (append to dst) 100 | poly1305_finish(&poly1305_state, dst + src_len); 101 | 102 | // Make sure we leave nothing sensitive on the stack 103 | crypto_zero(&chacha20_state, sizeof(chacha20_state)); 104 | crypto_zero(&block, sizeof(block)); 105 | } 106 | 107 | // 2.8. AEAD Construction (Decryption) 108 | bool chacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, uint64_t nonce, const uint8_t *key) { 109 | struct poly1305_context poly1305_state; 110 | struct chacha20_ctx chacha20_state; 111 | uint8_t block[8]; 112 | uint8_t mac[POLY1305_MAC_SIZE]; 113 | size_t padded_len; 114 | int dst_len; 115 | bool result = false; 116 | 117 | // Decryption is similar [to encryption] with the following differences: 118 | // - The roles of ciphertext and plaintext are reversed, so the ChaCha20 encryption function is applied to the ciphertext, producing the plaintext. 119 | // - The Poly1305 function is still run on the AAD and the ciphertext, not the plaintext. 120 | // - The calculated tag is bitwise compared to the received tag. The message is authenticated if and only if the tags match. 121 | 122 | if (src_len >= POLY1305_MAC_SIZE) { 123 | dst_len = src_len - POLY1305_MAC_SIZE; 124 | 125 | // First, a Poly1305 one-time key is generated from the 256-bit key and nonce using the procedure described in Section 2.6. 126 | generate_poly1305_key(&poly1305_state, &chacha20_state, key, nonce); 127 | 128 | // Calculate the MAC before attempting decryption 129 | 130 | // the Poly1305 function is called with the Poly1305 key calculated above, and a message constructed as a concatenation of the following: 131 | // - The AAD 132 | poly1305_update(&poly1305_state, ad, ad_len); 133 | // - padding1 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16 134 | padded_len = (ad_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes 135 | poly1305_update(&poly1305_state, zero, padded_len - ad_len); 136 | // - The ciphertext (note the Poly1305 function is still run on the AAD and the ciphertext, not the plaintext) 137 | poly1305_update(&poly1305_state, src, dst_len); 138 | // - padding2 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16. 139 | padded_len = (dst_len + 15) & 0xFFFFFFF0; // Round up to next 16 bytes 140 | poly1305_update(&poly1305_state, zero, padded_len - dst_len); 141 | // - The length of the additional data in octets (as a 64-bit little-endian integer) 142 | U64TO8_LITTLE(block, (uint64_t)ad_len); 143 | poly1305_update(&poly1305_state, block, sizeof(block)); 144 | // - The length of the ciphertext in octets (as a 64-bit little-endian integer). 145 | U64TO8_LITTLE(block, (uint64_t)dst_len); 146 | poly1305_update(&poly1305_state, block, sizeof(block)); 147 | 148 | // The output from the AEAD is twofold: 149 | // - A plaintext of the same length as the ciphertext. (below, output of chacha20 into dst) 150 | // - A 128-bit tag, which is the output of the Poly1305 function. (into mac for checking against passed mac) 151 | poly1305_finish(&poly1305_state, mac); 152 | 153 | 154 | if (crypto_equal(mac, src + dst_len, POLY1305_MAC_SIZE)) { 155 | // mac is correct - do the decryption 156 | // Next, the ChaCha20 encryption function is called to decrypt the ciphertext, using the same key and nonce, and with the initial counter set to 1. 157 | chacha20(&chacha20_state, dst, src, dst_len); 158 | result = true; 159 | } 160 | } 161 | return result; 162 | } 163 | 164 | // AEAD_XChaCha20_Poly1305 165 | // XChaCha20-Poly1305 is a variant of the ChaCha20-Poly1305 AEAD construction as defined in [RFC7539] that uses a 192-bit nonce instead of a 96-bit nonce. 166 | // The algorithm for XChaCha20-Poly1305 is as follows: 167 | // 1. Calculate a subkey from the first 16 bytes of the nonce and the key, using HChaCha20 (Section 2.2). 168 | // 2. Use the subkey and remaining 8 bytes of the nonce (prefixed with 4 NUL bytes) with AEAD_CHACHA20_POLY1305 from [RFC7539] as normal. The definition for XChaCha20 is given in Section 2.3. 169 | void xchacha20poly1305_encrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key) { 170 | uint8_t subkey[CHACHA20_KEY_SIZE]; 171 | uint64_t new_nonce; 172 | 173 | new_nonce = U8TO64_LITTLE(nonce + 16); 174 | 175 | hchacha20(subkey, nonce, key); 176 | chacha20poly1305_encrypt(dst, src, src_len, ad, ad_len, new_nonce, subkey); 177 | 178 | crypto_zero(subkey, sizeof(subkey)); 179 | } 180 | 181 | bool xchacha20poly1305_decrypt(uint8_t *dst, const uint8_t *src, size_t src_len, const uint8_t *ad, size_t ad_len, const uint8_t *nonce, const uint8_t *key) { 182 | uint8_t subkey[CHACHA20_KEY_SIZE]; 183 | uint64_t new_nonce; 184 | bool result; 185 | 186 | new_nonce = U8TO64_LITTLE(nonce + 16); 187 | 188 | hchacha20(subkey, nonce, key); 189 | result = chacha20poly1305_decrypt(dst, src, src_len, ad, ad_len, new_nonce, subkey); 190 | 191 | crypto_zero(subkey, sizeof(subkey)); 192 | return result; 193 | } 194 | -------------------------------------------------------------------------------- /src/wireguard.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) 3 | * The original license is below: 4 | * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without modification, 8 | * are permitted provided that the following conditions are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright notice, this 11 | * list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright notice, this 14 | * list of conditions and the following disclaimer in the documentation and/or 15 | * other materials provided with the distribution. 16 | * 17 | * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of 18 | * its contributors may be used to endorse or promote products derived from this 19 | * software without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 25 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | * 32 | * Author: Daniel Hope 33 | */ 34 | 35 | #ifndef _WIREGUARD_H_ 36 | #define _WIREGUARD_H_ 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | // Note: these are only required for definitions in device/peer for netif, udp_pcb, ip_addr_t and u16_t 43 | #include "lwip/netif.h" 44 | #include "lwip/udp.h" 45 | #include "lwip/ip_addr.h" 46 | #include "lwip/arch.h" 47 | 48 | // Platform-specific functions that need to be implemented per-platform 49 | #include "wireguard-platform.h" 50 | 51 | // tai64n contains 64-bit seconds and 32-bit nano offset (12 bytes) 52 | #define WIREGUARD_TAI64N_LEN (12) 53 | // Auth algorithm is chacha20pol1305 which is 128bit (16 byte) authenticator 54 | #define WIREGUARD_AUTHTAG_LEN (16) 55 | // Hash algorithm is blake2s which makes 32 byte hashes 56 | #define WIREGUARD_HASH_LEN (32) 57 | // Public key algo is curve22519 which uses 32 byte keys 58 | #define WIREGUARD_PUBLIC_KEY_LEN (32) 59 | // Public key algo is curve22519 which uses 32 byte keys 60 | #define WIREGUARD_PRIVATE_KEY_LEN (32) 61 | // Symmetric session keys are chacha20/poly1305 which uses 32 byte keys 62 | #define WIREGUARD_SESSION_KEY_LEN (32) 63 | 64 | // Timers / Limits 65 | #define WIREGUARD_COOKIE_LEN (16) 66 | #define COOKIE_SECRET_MAX_AGE (2 * 60) 67 | #define COOKIE_NONCE_LEN (24) 68 | 69 | #define REKEY_AFTER_MESSAGES (1ULL << 60) 70 | #define REJECT_AFTER_MESSAGES (0xFFFFFFFFFFFFFFFFULL - (1ULL << 13)) 71 | #define REKEY_AFTER_TIME (120) 72 | #define REJECT_AFTER_TIME (180) 73 | #define REKEY_TIMEOUT (5) 74 | #define KEEPALIVE_TIMEOUT (10) 75 | 76 | struct wireguard_keypair { 77 | bool valid; 78 | bool initiator; // Did we initiate this session (send the initiation packet rather than sending the response packet) 79 | uint32_t keypair_millis; 80 | 81 | uint8_t sending_key[WIREGUARD_SESSION_KEY_LEN]; 82 | bool sending_valid; 83 | uint64_t sending_counter; 84 | 85 | uint8_t receiving_key[WIREGUARD_SESSION_KEY_LEN]; 86 | bool receiving_valid; 87 | 88 | uint32_t last_tx; 89 | uint32_t last_rx; 90 | 91 | uint32_t replay_bitmap; 92 | uint64_t replay_counter; 93 | 94 | uint32_t local_index; // This is the index we generated for our end 95 | uint32_t remote_index; // This is the index on the other end 96 | }; 97 | 98 | struct wireguard_handshake { 99 | bool valid; 100 | bool initiator; 101 | uint32_t local_index; 102 | uint32_t remote_index; 103 | uint8_t ephemeral_private[WIREGUARD_PRIVATE_KEY_LEN]; 104 | uint8_t remote_ephemeral[WIREGUARD_PUBLIC_KEY_LEN]; 105 | uint8_t hash[WIREGUARD_HASH_LEN]; 106 | uint8_t chaining_key[WIREGUARD_HASH_LEN]; 107 | }; 108 | 109 | struct wireguard_allowed_ip { 110 | bool valid; 111 | ip_addr_t ip; 112 | ip_addr_t mask; 113 | }; 114 | 115 | struct wireguard_peer { 116 | bool valid; // Is this peer initialised? 117 | bool active; // Should we be actively trying to connect? 118 | 119 | // This is the configured IP of the peer (endpoint) 120 | ip_addr_t connect_ip; 121 | u16_t connect_port; 122 | // This is the latest received IP/port 123 | ip_addr_t ip; 124 | u16_t port; 125 | // keep-alive interval in seconds, 0 is disable 126 | uint16_t keepalive_interval; 127 | 128 | struct wireguard_allowed_ip allowed_source_ips[WIREGUARD_MAX_SRC_IPS]; 129 | 130 | uint8_t public_key[WIREGUARD_PUBLIC_KEY_LEN]; 131 | uint8_t preshared_key[WIREGUARD_SESSION_KEY_LEN]; 132 | 133 | // Precomputed DH(Sprivi,Spubr) with device private key, and peer public key 134 | uint8_t public_key_dh[WIREGUARD_PUBLIC_KEY_LEN]; 135 | 136 | // Session keypairs 137 | struct wireguard_keypair curr_keypair; 138 | struct wireguard_keypair prev_keypair; 139 | struct wireguard_keypair next_keypair; 140 | 141 | // 5.1 Silence is a Virtue: The responder keeps track of the greatest timestamp received per peer 142 | uint8_t greatest_timestamp[WIREGUARD_TAI64N_LEN]; 143 | 144 | // The active handshake that is happening 145 | struct wireguard_handshake handshake; 146 | 147 | // Decrypted cookie from the responder 148 | uint32_t cookie_millis; 149 | uint8_t cookie[WIREGUARD_COOKIE_LEN]; 150 | 151 | // The latest mac1 we sent with initiation 152 | bool handshake_mac1_valid; 153 | uint8_t handshake_mac1[WIREGUARD_COOKIE_LEN]; 154 | 155 | // Precomputed keys for use in mac validation 156 | uint8_t label_cookie_key[WIREGUARD_SESSION_KEY_LEN]; 157 | uint8_t label_mac1_key[WIREGUARD_SESSION_KEY_LEN]; 158 | 159 | // The last time we received a valid initiation message 160 | uint32_t last_initiation_rx; 161 | // The last time we sent an initiation message to this peer 162 | uint32_t last_initiation_tx; 163 | 164 | // last_tx and last_rx of data packets 165 | uint32_t last_tx; 166 | uint32_t last_rx; 167 | 168 | // We set this flag on RX/TX of packets if we think that we should initiate a new handshake 169 | bool send_handshake; 170 | }; 171 | 172 | struct wireguard_device { 173 | // Maybe have a "Device private" member to abstract these? 174 | struct netif *netif; 175 | struct udp_pcb *udp_pcb; 176 | 177 | struct netif *underlying_netif; 178 | 179 | uint8_t public_key[WIREGUARD_PUBLIC_KEY_LEN]; 180 | uint8_t private_key[WIREGUARD_PRIVATE_KEY_LEN]; 181 | 182 | uint8_t cookie_secret[WIREGUARD_HASH_LEN]; 183 | uint32_t cookie_secret_millis; 184 | 185 | // Precalculated 186 | uint8_t label_cookie_key[WIREGUARD_SESSION_KEY_LEN]; 187 | uint8_t label_mac1_key[WIREGUARD_SESSION_KEY_LEN]; 188 | 189 | // List of peers associated with this device 190 | struct wireguard_peer peers[WIREGUARD_MAX_PEERS]; 191 | 192 | bool valid; 193 | }; 194 | 195 | #define MESSAGE_INVALID 0 196 | #define MESSAGE_HANDSHAKE_INITIATION 1 197 | #define MESSAGE_HANDSHAKE_RESPONSE 2 198 | #define MESSAGE_COOKIE_REPLY 3 199 | #define MESSAGE_TRANSPORT_DATA 4 200 | 201 | 202 | // 5.4.2 First Message: Initiator to Responder 203 | struct message_handshake_initiation { 204 | uint8_t type; 205 | uint8_t reserved[3]; 206 | uint32_t sender; 207 | uint8_t ephemeral[32]; 208 | uint8_t enc_static[32 + WIREGUARD_AUTHTAG_LEN]; 209 | uint8_t enc_timestamp[WIREGUARD_TAI64N_LEN + WIREGUARD_AUTHTAG_LEN]; 210 | uint8_t mac1[WIREGUARD_COOKIE_LEN]; 211 | uint8_t mac2[WIREGUARD_COOKIE_LEN]; 212 | } __attribute__ ((__packed__)); 213 | 214 | // 5.4.3 Second Message: Responder to Initiator 215 | struct message_handshake_response { 216 | uint8_t type; 217 | uint8_t reserved[3]; 218 | uint32_t sender; 219 | uint32_t receiver; 220 | uint8_t ephemeral[32]; 221 | uint8_t enc_empty[0 + WIREGUARD_AUTHTAG_LEN]; 222 | uint8_t mac1[WIREGUARD_COOKIE_LEN]; 223 | uint8_t mac2[WIREGUARD_COOKIE_LEN]; 224 | } __attribute__ ((__packed__)); 225 | 226 | // 5.4.7 Under Load: Cookie Reply Message 227 | struct message_cookie_reply { 228 | uint8_t type; 229 | uint8_t reserved[3]; 230 | uint32_t receiver; 231 | uint8_t nonce[COOKIE_NONCE_LEN]; 232 | uint8_t enc_cookie[WIREGUARD_COOKIE_LEN + WIREGUARD_AUTHTAG_LEN]; 233 | } __attribute__ ((__packed__)); 234 | 235 | // 5.4.6 Subsequent Messages: Transport Data Messages 236 | struct message_transport_data { 237 | uint8_t type; 238 | uint8_t reserved[3]; 239 | uint32_t receiver; 240 | uint8_t counter[8]; 241 | // Followed by encrypted data 242 | uint8_t enc_packet[]; 243 | } __attribute__ ((__packed__)); 244 | 245 | // Initialise the WireGuard system - need to call this before anything else 246 | void wireguard_init(); 247 | bool wireguard_device_init(struct wireguard_device *device, const uint8_t *private_key); 248 | bool wireguard_peer_init(struct wireguard_device *device, struct wireguard_peer *peer, const uint8_t *public_key, const uint8_t *preshared_key); 249 | 250 | struct wireguard_peer *peer_alloc(struct wireguard_device *device); 251 | uint8_t wireguard_peer_index(struct wireguard_device *device, struct wireguard_peer *peer); 252 | struct wireguard_peer *peer_lookup_by_pubkey(struct wireguard_device *device, uint8_t *public_key); 253 | struct wireguard_peer *peer_lookup_by_peer_index(struct wireguard_device *device, uint8_t peer_index); 254 | struct wireguard_peer *peer_lookup_by_receiver(struct wireguard_device *device, uint32_t receiver); 255 | struct wireguard_peer *peer_lookup_by_handshake(struct wireguard_device *device, uint32_t receiver); 256 | 257 | void wireguard_start_session(struct wireguard_peer *peer, bool initiator); 258 | 259 | void keypair_update(struct wireguard_peer *peer, struct wireguard_keypair *received_keypair); 260 | void keypair_destroy(struct wireguard_keypair *keypair); 261 | 262 | struct wireguard_keypair *get_peer_keypair_for_idx(struct wireguard_peer *peer, uint32_t idx); 263 | bool wireguard_check_replay(struct wireguard_keypair *keypair, uint64_t seq); 264 | 265 | uint8_t wireguard_get_message_type(const uint8_t *data, size_t len); 266 | 267 | struct wireguard_peer *wireguard_process_initiation_message(struct wireguard_device *device, struct message_handshake_initiation *msg); 268 | bool wireguard_process_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *src); 269 | bool wireguard_process_cookie_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_cookie_reply *src); 270 | 271 | bool wireguard_create_handshake_initiation(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_initiation *dst); 272 | bool wireguard_create_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *dst); 273 | void wireguard_create_cookie_reply(struct wireguard_device *device, struct message_cookie_reply *dst, const uint8_t *mac1, uint32_t index, uint8_t *source_addr_port, size_t source_length); 274 | 275 | 276 | bool wireguard_check_mac1(struct wireguard_device *device, const uint8_t *data, size_t len, const uint8_t *mac1); 277 | bool wireguard_check_mac2(struct wireguard_device *device, const uint8_t *data, size_t len, uint8_t *source_addr_port, size_t source_length, const uint8_t *mac2); 278 | 279 | bool wireguard_expired(uint32_t created_millis, uint32_t valid_seconds); 280 | 281 | void wireguard_encrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, struct wireguard_keypair *keypair); 282 | bool wireguard_decrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, uint64_t counter, struct wireguard_keypair *keypair); 283 | 284 | bool wireguard_base64_decode(const char *str, uint8_t *out, size_t *outlen); 285 | bool wireguard_base64_encode(const uint8_t *in, size_t inlen, char *out, size_t *outlen); 286 | 287 | #endif /* _WIREGUARD_H_ */ 288 | -------------------------------------------------------------------------------- /src/crypto/refc/x25519.c: -------------------------------------------------------------------------------- 1 | // Taken from https://sourceforge.net/p/strobe (MIT Licence) 2 | /** 3 | * @cond internal 4 | * @file x25519.c 5 | * @copyright 6 | * Copyright (c) 2015-2016 Cryptography Research, Inc. \n 7 | * Released under the MIT License. See LICENSE.txt for license information. 8 | * @author Mike Hamburg 9 | * @brief Key exchange and signatures based on X25519. 10 | */ 11 | #include 12 | #include "x25519.h" 13 | //#include "strobe.h" 14 | //#include "strobe_config.h" 15 | // STROBE header replacement 16 | #include 17 | #define X25519_WBITS 32 18 | #define X25519_SUPPORT_SIGN 0 19 | #define X25519_MEMCPY_PARAMS 1 20 | #define X25519_USE_POWER_CHAIN 1 21 | #if BYTE_ORDER == LITTLE_ENDIAN 22 | static inline uint32_t eswap_letoh_32(uint32_t w) { return w; } 23 | #else 24 | #error "Fix eswap() on non-little-endian machine" 25 | #endif 26 | 27 | #if X25519_WBITS == 64 28 | typedef uint64_t limb_t; 29 | typedef __uint128_t dlimb_t; 30 | typedef __int128_t sdlimb_t; 31 | #define eswap_limb eswap_letoh_64 32 | #define LIMB(x) x##ull 33 | #elif X25519_WBITS == 32 34 | typedef uint32_t limb_t; 35 | typedef uint64_t dlimb_t; 36 | typedef int64_t sdlimb_t; 37 | #define eswap_limb eswap_letoh_32 38 | #define LIMB(x) (uint32_t)(x##ull),(uint32_t)((x##ull)>>32) 39 | #else 40 | #error "Need to know X25519_WBITS" 41 | #endif 42 | 43 | #define NLIMBS (256/X25519_WBITS) 44 | typedef limb_t fe[NLIMBS]; 45 | 46 | #if X25519_SUPPORT_SIGN 47 | typedef limb_t scalar_t[NLIMBS]; 48 | static const limb_t MONTGOMERY_FACTOR = (limb_t)0xd2b51da312547e1bull; 49 | static const scalar_t sc_p = { 50 | LIMB(0x5812631a5cf5d3ed), LIMB(0x14def9dea2f79cd6), 51 | LIMB(0x0000000000000000), LIMB(0x1000000000000000) 52 | }, sc_r2 = { 53 | LIMB(0xa40611e3449c0f01), LIMB(0xd00e1ba768859347), 54 | LIMB(0xceec73d217f5be65), LIMB(0x0399411b7c309a3d) 55 | }; 56 | #endif 57 | 58 | static inline limb_t umaal( 59 | limb_t *carry, limb_t acc, limb_t mand, limb_t mier 60 | ) { 61 | dlimb_t tmp = (dlimb_t) mand * mier + acc + *carry; 62 | *carry = tmp >> X25519_WBITS; 63 | return tmp; 64 | } 65 | 66 | /* These functions are implemented in terms of umaal on ARM */ 67 | static inline limb_t adc(limb_t *carry, limb_t acc, limb_t mand) { 68 | dlimb_t total = (dlimb_t)*carry + acc + mand; 69 | *carry = total>>X25519_WBITS; 70 | return total; 71 | } 72 | 73 | static inline limb_t adc0(limb_t *carry, limb_t acc) { 74 | dlimb_t total = (dlimb_t)*carry + acc; 75 | *carry = total>>X25519_WBITS; 76 | return total; 77 | } 78 | 79 | /* Precondition: carry is small. 80 | * Invariant: result of propagate is < 2^255 + 1 word 81 | * In particular, always less than 2p. 82 | * Also, output x >= min(x,19) 83 | */ 84 | static void propagate(fe x, limb_t over) { 85 | unsigned i; 86 | over = x[NLIMBS-1]>>(X25519_WBITS-1) | over<<1; 87 | x[NLIMBS-1] &= ~((limb_t)1<<(X25519_WBITS-1)); 88 | 89 | limb_t carry = over * 19; 90 | for (i=0; i>= X25519_WBITS; 110 | } 111 | propagate(out,1+carry); 112 | } 113 | 114 | static void __attribute__((unused)) 115 | swapin(limb_t *x, const uint8_t *in) { 116 | memcpy(x,in,sizeof(fe)); 117 | unsigned i; 118 | for (i=0; i>= X25519_WBITS; 199 | } 200 | return ((dlimb_t)res - 1) >> X25519_WBITS; 201 | } 202 | 203 | static const limb_t a24[1]={121665}; 204 | 205 | static void ladder_part1(fe xs[5]) { 206 | limb_t *x2 = xs[0], *z2=xs[1],*x3=xs[2],*z3=xs[3],*t1=xs[4]; 207 | add(t1,x2,z2); // t1 = A 208 | sub(z2,x2,z2); // z2 = B 209 | add(x2,x3,z3); // x2 = C 210 | sub(z3,x3,z3); // z3 = D 211 | mul1(z3,t1); // z3 = DA 212 | mul1(x2,z2); // x3 = BC 213 | add(x3,z3,x2); // x3 = DA+CB 214 | sub(z3,z3,x2); // z3 = DA-CB 215 | sqr1(t1); // t1 = AA 216 | sqr1(z2); // z2 = BB 217 | sub(x2,t1,z2); // x2 = E = AA-BB 218 | mul(z2,x2,a24,sizeof(a24)/sizeof(a24[0])); // z2 = E*a24 219 | add(z2,z2,t1); // z2 = E*a24 + AA 220 | } 221 | static void ladder_part2(fe xs[5], const fe x1) { 222 | limb_t *x2 = xs[0], *z2=xs[1],*x3=xs[2],*z3=xs[3],*t1=xs[4]; 223 | sqr1(z3); // z3 = (DA-CB)^2 224 | mul1(z3,x1); // z3 = x1 * (DA-CB)^2 225 | sqr1(x3); // x3 = (DA+CB)^2 226 | mul1(z2,x2); // z2 = AA*(E*a24+AA) 227 | sub(x2,t1,x2); // x2 = BB again 228 | mul1(x2,t1); // x2 = AA*BB 229 | } 230 | 231 | static void x25519_core(fe xs[5], const uint8_t scalar[X25519_BYTES], const uint8_t *x1, int clamp) { 232 | int i; 233 | #if X25519_MEMCPY_PARAMS 234 | fe x1i; 235 | swapin(x1i,x1); 236 | x1 = (const uint8_t *)x1; 237 | #endif 238 | limb_t swap = 0; 239 | limb_t *x2 = xs[0],*x3=xs[2],*z3=xs[3]; 240 | memset(xs,0,4*sizeof(fe)); 241 | x2[0] = z3[0] = 1; 242 | memcpy(x3,x1,sizeof(fe)); 243 | 244 | for (i=255; i>=0; i--) { 245 | uint8_t bytei = scalar[i/8]; 246 | if (clamp) { 247 | if (i/8 == 0) { 248 | bytei &= ~7; 249 | } else if (i/8 == X25519_BYTES-1) { 250 | bytei &= 0x7F; 251 | bytei |= 0x40; 252 | } 253 | } 254 | limb_t doswap = -(limb_t)((bytei>>(i%8)) & 1); 255 | condswap(x2,x3,swap^doswap); 256 | swap = doswap; 257 | 258 | ladder_part1(xs); 259 | ladder_part2(xs,(const limb_t *)x1); 260 | } 261 | condswap(x2,x3,swap); 262 | } 263 | 264 | int x25519(uint8_t out[X25519_BYTES], const uint8_t scalar[X25519_BYTES], const uint8_t x1[X25519_BYTES], int clamp) { 265 | fe xs[5]; 266 | x25519_core(xs,scalar,x1,clamp); 267 | 268 | /* Precomputed inversion chain */ 269 | limb_t *x2 = xs[0], *z2=xs[1], *z3=xs[3]; 270 | int i; 271 | 272 | limb_t *prev = z2; 273 | #if X25519_USE_POWER_CHAIN 274 | static const struct { uint8_t a,c,n; } steps[13] = { 275 | {2,1,1 }, 276 | {2,1,1 }, 277 | {4,2,3 }, 278 | {2,4,6 }, 279 | {3,1,1 }, 280 | {3,2,12 }, 281 | {4,3,25 }, 282 | {2,3,25 }, 283 | {2,4,50 }, 284 | {3,2,125}, 285 | {3,1,2 }, 286 | {3,1,2 }, 287 | {3,1,1 } 288 | }; 289 | for (i=0; i<13; i++) { 290 | int j; 291 | limb_t *a = xs[steps[i].a]; 292 | for (j=steps[i].n; j>0; j--) { 293 | sqr(a, prev); 294 | prev = a; 295 | } 296 | mul1(a,xs[steps[i].c]); 297 | } 298 | #else 299 | /* Raise to the p-2 = 0x7f..ffeb */ 300 | for (i=253; i>=0; i--) { 301 | sqr(z3,prev); 302 | prev = z3; 303 | if (i>=8 || (0xeb>>i & 1)) { 304 | mul1(z3,z2); 305 | } 306 | } 307 | #endif 308 | 309 | /* Here prev = z3 */ 310 | /* x2 /= z2 */ 311 | #if X25519_MEMCPY_PARAMS 312 | mul1(x2,z3); 313 | int ret = canon(x2); 314 | swapout(out,x2); 315 | #else 316 | mul((limb_t *)out, x2, z3, NLIMBS); 317 | int ret = canon((limb_t*)out); 318 | #endif 319 | if (clamp) return ret; 320 | else return 0; 321 | } 322 | 323 | const uint8_t X25519_BASE_POINT[X25519_BYTES] = {9}; 324 | 325 | #if X25519_SUPPORT_VERIFY 326 | static limb_t x25519_verify_core( 327 | fe xs[5], 328 | const limb_t *other1, 329 | const uint8_t other2[X25519_BYTES] 330 | ) { 331 | limb_t *z2=xs[1],*x3=xs[2],*z3=xs[3]; 332 | #if X25519_MEMCPY_PARAMS 333 | fe xo2; 334 | swapin(xo2,other2); 335 | #else 336 | const limb_t *xo2 = (const limb_t *)other2; 337 | #endif 338 | 339 | memcpy(x3, other1, 2*sizeof(fe)); 340 | 341 | ladder_part1(xs); 342 | 343 | /* Here z2 = t2^2 */ 344 | mul1(z2,other1); 345 | mul1(z2,other1+NLIMBS); 346 | mul1(z2,xo2); 347 | const limb_t sixteen = 16; 348 | mul (z2,z2,&sixteen,1); 349 | 350 | mul1(z3,xo2); 351 | sub(z3,z3,x3); 352 | sqr1(z3); 353 | 354 | /* check equality */ 355 | sub(z3,z3,z2); 356 | 357 | /* If canon(z2) then both sides are zero. 358 | * If canon(z3) then the two sides are equal. 359 | * 360 | * Reject sigs where both sides are zero, because 361 | * that can happen if an input causes the ladder to 362 | * return 0/0. 363 | */ 364 | return canon(z2) | ~canon(z3); 365 | } 366 | 367 | int x25519_verify_p2 ( 368 | const uint8_t response[X25519_BYTES], 369 | const uint8_t challenge[X25519_BYTES], 370 | const uint8_t eph[X25519_BYTES], 371 | const uint8_t pub[X25519_BYTES] 372 | ) { 373 | fe xs[7]; 374 | x25519_core(&xs[0],challenge,pub,0); 375 | x25519_core(&xs[2],response,X25519_BASE_POINT,0); 376 | return x25519_verify_core(&xs[2],xs[0],eph); 377 | } 378 | #endif // X25519_SUPPORT_VERIFY 379 | 380 | #if X25519_SUPPORT_SIGN 381 | static void sc_montmul ( 382 | scalar_t out, 383 | const scalar_t a, 384 | const scalar_t b 385 | ) { 386 | /** 387 | * OK, so carry bounding. We're using a high carry, so that the 388 | * inputs don't have to be reduced. 389 | * 390 | * First montmul: output < (M^2 + Mp)/M = M+p, subtract p, < M. This gets rid of high carry. 391 | * Second montmul, by r^2 mod p < p: output < (Mp + Mp)/M = 2p, subtract p, < p, done. 392 | */ 393 | unsigned i,j; 394 | limb_t hic = 0; 395 | for (i=0; i0) out[j-1] = acc; 404 | } 405 | 406 | /* Add two carry registers and high carry */ 407 | out[NLIMBS-1] = adc(&hic, carry, carry2); 408 | } 409 | 410 | /* Reduce */ 411 | sdlimb_t scarry = 0; 412 | for (i=0; i>= X25519_WBITS; 415 | } 416 | limb_t need_add = -(scarry + hic); 417 | 418 | limb_t carry = 0; 419 | for (i=0; i 34 | */ 35 | 36 | #include "wireguardif.h" 37 | 38 | #include 39 | #include 40 | 41 | #include "lwip/netif.h" 42 | #include "lwip/ip.h" 43 | #include "lwip/udp.h" 44 | #include "lwip/mem.h" 45 | #include "lwip/sys.h" 46 | #include "lwip/timeouts.h" 47 | 48 | #include "wireguard.h" 49 | #include "crypto.h" 50 | #include "esp_log.h" 51 | #include "tcpip_adapter.h" 52 | 53 | #include "esp32-hal-log.h" 54 | 55 | #define WIREGUARDIF_TIMER_MSECS 400 56 | 57 | #define TAG "[WireGuard] " 58 | 59 | static void update_peer_addr(struct wireguard_peer *peer, const ip_addr_t *addr, u16_t port) { 60 | peer->ip = *addr; 61 | peer->port = port; 62 | } 63 | 64 | static struct wireguard_peer *peer_lookup_by_allowed_ip(struct wireguard_device *device, const ip_addr_t *ipaddr) { 65 | struct wireguard_peer *result = NULL; 66 | struct wireguard_peer *tmp; 67 | int x; 68 | int y; 69 | for (x=0; (!result) && (x < WIREGUARD_MAX_PEERS); x++) { 70 | tmp = &device->peers[x]; 71 | if (tmp->valid) { 72 | for (y=0; y < WIREGUARD_MAX_SRC_IPS; y++) { 73 | if ((tmp->allowed_source_ips[y].valid) && ip_addr_netcmp(ipaddr, &tmp->allowed_source_ips[y].ip, ip_2_ip4(&tmp->allowed_source_ips[y].mask))) { 74 | result = tmp; 75 | break; 76 | } 77 | } 78 | } 79 | } 80 | return result; 81 | } 82 | 83 | static bool wireguardif_can_send_initiation(struct wireguard_peer *peer) { 84 | return ((peer->last_initiation_tx == 0) || (wireguard_expired(peer->last_initiation_tx, REKEY_TIMEOUT))); 85 | } 86 | 87 | static err_t wireguardif_peer_output(struct netif *netif, struct pbuf *q, struct wireguard_peer *peer) { 88 | struct wireguard_device *device = (struct wireguard_device *)netif->state; 89 | // Send to last know port, not the connect port 90 | //TODO: Support DSCP and ECN - lwip requires this set on PCB globally, not per packet 91 | return udp_sendto_if(device->udp_pcb, q, &peer->ip, peer->port, device->underlying_netif); 92 | } 93 | 94 | static err_t wireguardif_device_output(struct wireguard_device *device, struct pbuf *q, const ip_addr_t *ipaddr, u16_t port) { 95 | return udp_sendto_if(device->udp_pcb, q, ipaddr, port, device->underlying_netif); 96 | } 97 | 98 | static err_t wireguardif_output_to_peer(struct netif *netif, struct pbuf *q, const ip_addr_t *ipaddr, struct wireguard_peer *peer) { 99 | // The LWIP IP layer wants to send an IP packet out over the interface - we need to encrypt and send it to the peer 100 | struct message_transport_data *hdr; 101 | struct pbuf *pbuf; 102 | err_t result; 103 | size_t unpadded_len; 104 | size_t padded_len; 105 | size_t header_len = 16; 106 | uint8_t *dst; 107 | uint32_t now; 108 | struct wireguard_keypair *keypair = &peer->curr_keypair; 109 | 110 | // Note: We may not be able to use the current keypair if we haven't received data, may need to resort to using previous keypair 111 | if (keypair->valid && (!keypair->initiator) && (keypair->last_rx == 0)) { 112 | keypair = &peer->prev_keypair; 113 | } 114 | 115 | if (keypair->valid && (keypair->initiator || keypair->last_rx != 0)) { 116 | 117 | if ( 118 | !wireguard_expired(keypair->keypair_millis, REJECT_AFTER_TIME) && 119 | (keypair->sending_counter < REJECT_AFTER_MESSAGES) 120 | ) { 121 | 122 | // Calculate the outgoing packet size - round up to next 16 bytes, add 16 bytes for header 123 | if (q) { 124 | // This is actual transport data 125 | unpadded_len = q->tot_len; 126 | } else { 127 | // This is a keep-alive 128 | unpadded_len = 0; 129 | } 130 | padded_len = (unpadded_len + 15) & 0xFFFFFFF0; // Round up to next 16 byte boundary 131 | 132 | // The buffer needs to be allocated from "transport" pool to leave room for LwIP generated IP headers 133 | // The IP packet consists of 16 byte header (struct message_transport_data), data padded upto 16 byte boundary + encrypted auth tag (16 bytes) 134 | pbuf = pbuf_alloc(PBUF_TRANSPORT, header_len + padded_len + WIREGUARD_AUTHTAG_LEN, PBUF_RAM); 135 | if (pbuf) { 136 | log_v(TAG "preparing transport data..."); 137 | // Note: allocating pbuf from RAM above guarantees that the pbuf is in one section and not chained 138 | // - i.e payload points to the contiguous memory region 139 | memset(pbuf->payload, 0, pbuf->tot_len); 140 | 141 | hdr = (struct message_transport_data *)pbuf->payload; 142 | 143 | hdr->type = MESSAGE_TRANSPORT_DATA; 144 | hdr->receiver = keypair->remote_index; 145 | // Alignment required... pbuf_alloc has probably aligned data, but want to be sure 146 | U64TO8_LITTLE(hdr->counter, keypair->sending_counter); 147 | 148 | // Copy the encrypted (padded) data to the output packet - chacha20poly1305_encrypt() can encrypt data in-place which avoids call to mem_malloc 149 | dst = &hdr->enc_packet[0]; 150 | if ((padded_len > 0) && q) { 151 | // Note: before copying make sure we have inserted the IP header checksum 152 | // The IP header checksum (and other checksums in the IP packet - e.g. ICMP) need to be calculated by LWIP before calling 153 | // The Wireguard interface always needs checksums to be generated in software but the base netif may have some checksums generated by hardware 154 | 155 | // Copy pbuf to memory - handles case where pbuf is chained 156 | pbuf_copy_partial(q, dst, unpadded_len, 0); 157 | } 158 | 159 | // Then encrypt 160 | wireguard_encrypt_packet(dst, dst, padded_len, keypair); 161 | 162 | result = wireguardif_peer_output(netif, pbuf, peer); 163 | 164 | if (result == ERR_OK) { 165 | now = wireguard_sys_now(); 166 | peer->last_tx = now; 167 | keypair->last_tx = now; 168 | } 169 | 170 | pbuf_free(pbuf); 171 | 172 | // Check to see if we should rekey 173 | if (keypair->sending_counter >= REKEY_AFTER_MESSAGES) { 174 | peer->send_handshake = true; 175 | } else if (keypair->initiator && wireguard_expired(keypair->keypair_millis, REKEY_AFTER_TIME)) { 176 | peer->send_handshake = true; 177 | } 178 | 179 | } else { 180 | // Failed to allocate memory 181 | result = ERR_MEM; 182 | } 183 | } else { 184 | // key has expired... 185 | keypair_destroy(keypair); 186 | result = ERR_CONN; 187 | } 188 | } else { 189 | // No valid keys! 190 | result = ERR_CONN; 191 | } 192 | return result; 193 | } 194 | 195 | // This is used as the output function for the Wireguard netif 196 | // The ipaddr here is the one inside the VPN which we use to lookup the correct peer/endpoint 197 | static err_t wireguardif_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ip4addr) { 198 | struct wireguard_device *device = (struct wireguard_device *)netif->state; 199 | // Send to peer that matches dest IP 200 | ip_addr_t ipaddr; 201 | ip_addr_copy_from_ip4(ipaddr, *ip4addr); 202 | struct wireguard_peer *peer = peer_lookup_by_allowed_ip(device, &ipaddr); 203 | if (peer) { 204 | return wireguardif_output_to_peer(netif, q, &ipaddr, peer); 205 | } else { 206 | return ERR_RTE; 207 | } 208 | } 209 | 210 | static void wireguardif_send_keepalive(struct wireguard_device *device, struct wireguard_peer *peer) { 211 | // Send a NULL packet as a keep-alive 212 | wireguardif_output_to_peer(device->netif, NULL, NULL, peer); 213 | } 214 | 215 | static void wireguardif_process_response_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *response, const ip_addr_t *addr, u16_t port) { 216 | if (wireguard_process_handshake_response(device, peer, response)) { 217 | // Packet is good 218 | // Update the peer location 219 | log_i(TAG "good handshake from %08x:%d", addr->u_addr.ip4.addr, port); 220 | update_peer_addr(peer, addr, port); 221 | 222 | wireguard_start_session(peer, true); 223 | wireguardif_send_keepalive(device, peer); 224 | 225 | // Set the IF-UP flag on netif 226 | netif_set_link_up(device->netif); 227 | } else { 228 | // Packet bad 229 | log_i(TAG "bad handshake from %08x:%d", addr->u_addr.ip4.addr, port); 230 | } 231 | } 232 | 233 | static bool peer_add_ip(struct wireguard_peer *peer, ip_addr_t ip, ip_addr_t mask) { 234 | bool result = false; 235 | struct wireguard_allowed_ip *allowed; 236 | int x; 237 | // Look for existing match first 238 | for (x=0; x < WIREGUARD_MAX_SRC_IPS; x++) { 239 | allowed = &peer->allowed_source_ips[x]; 240 | if ((allowed->valid) && ip_addr_cmp(&allowed->ip, &ip) && ip_addr_cmp(&allowed->mask, &mask)) { 241 | result = true; 242 | break; 243 | } 244 | } 245 | if (!result) { 246 | // Look for a free slot 247 | for (x=0; x < WIREGUARD_MAX_SRC_IPS; x++) { 248 | allowed = &peer->allowed_source_ips[x]; 249 | if (!allowed->valid) { 250 | allowed->valid = true; 251 | allowed->ip = ip; 252 | allowed->mask = mask; 253 | result = true; 254 | break; 255 | } 256 | } 257 | } 258 | return result; 259 | } 260 | 261 | static void wireguardif_process_data_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_transport_data *data_hdr, size_t data_len, const ip_addr_t *addr, u16_t port) { 262 | struct wireguard_keypair *keypair; 263 | uint64_t nonce; 264 | uint8_t *src; 265 | size_t src_len; 266 | struct pbuf *pbuf; 267 | struct ip_hdr *iphdr; 268 | ip_addr_t dest; 269 | bool dest_ok = false; 270 | int x; 271 | uint32_t now; 272 | uint16_t header_len = 0xFFFF; 273 | uint32_t idx = data_hdr->receiver; 274 | 275 | keypair = get_peer_keypair_for_idx(peer, idx); 276 | 277 | if (keypair) { 278 | if ( 279 | (keypair->receiving_valid) && 280 | !wireguard_expired(keypair->keypair_millis, REJECT_AFTER_TIME) && 281 | (keypair->sending_counter < REJECT_AFTER_MESSAGES) 282 | 283 | ) { 284 | 285 | nonce = U8TO64_LITTLE(data_hdr->counter); 286 | src = &data_hdr->enc_packet[0]; 287 | src_len = data_len; 288 | 289 | // We don't know the unpadded size until we have decrypted the packet and validated/inspected the IP header 290 | pbuf = pbuf_alloc(PBUF_TRANSPORT, src_len - WIREGUARD_AUTHTAG_LEN, PBUF_RAM); 291 | if (pbuf) { 292 | // Decrypt the packet 293 | memset(pbuf->payload, 0, pbuf->tot_len); 294 | if (wireguard_decrypt_packet(pbuf->payload, src, src_len, nonce, keypair)) { 295 | 296 | // 3. Since the packet has authenticated correctly, the source IP of the outer UDP/IP packet is used to update the endpoint for peer TrMv...WXX0. 297 | // Update the peer location 298 | update_peer_addr(peer, addr, port); 299 | 300 | now = wireguard_sys_now(); 301 | keypair->last_rx = now; 302 | peer->last_rx = now; 303 | 304 | // Might need to shuffle next key --> current keypair 305 | keypair_update(peer, keypair); 306 | 307 | // Check to see if we should rekey 308 | if (keypair->initiator && wireguard_expired(keypair->keypair_millis, REJECT_AFTER_TIME - peer->keepalive_interval - REKEY_TIMEOUT)) { 309 | peer->send_handshake = true; 310 | } 311 | 312 | // Make sure that link is reported as up 313 | netif_set_link_up(device->netif); 314 | 315 | if (pbuf->tot_len > 0) { 316 | //4a. Once the packet payload is decrypted, the interface has a plaintext packet. If this is not an IP packet, it is dropped. 317 | iphdr = (struct ip_hdr *)pbuf->payload; 318 | // Check for packet replay / dupes 319 | if (wireguard_check_replay(keypair, nonce)) { 320 | 321 | // 4b. Otherwise, WireGuard checks to see if the source IP address of the plaintext inner-packet routes correspondingly in the cryptokey routing table 322 | // Also check packet length! 323 | #if LWIP_IPV4 324 | if (IPH_V(iphdr) == 4) { 325 | ip_addr_copy_from_ip4(dest, iphdr->dest); 326 | for (x=0; x < WIREGUARD_MAX_SRC_IPS; x++) { 327 | if (peer->allowed_source_ips[x].valid) { 328 | if (ip_addr_netcmp(&dest, &peer->allowed_source_ips[x].ip, ip_2_ip4(&peer->allowed_source_ips[x].mask))) { 329 | dest_ok = true; 330 | header_len = PP_NTOHS(IPH_LEN(iphdr)); 331 | break; 332 | } 333 | } 334 | } 335 | } 336 | #endif /* LWIP_IPV4 */ 337 | #if LWIP_IPV6 338 | if (IPH_V(iphdr) == 6) { 339 | // TODO: IPV6 support for route filtering 340 | header_len = PP_NTOHS(IPH_LEN(iphdr)); 341 | dest_ok = true; 342 | } 343 | #endif /* LWIP_IPV6 */ 344 | if (header_len <= pbuf->tot_len) { 345 | 346 | // 5. If the plaintext packet has not been dropped, it is inserted into the receive queue of the wg0 interface. 347 | if (dest_ok) { 348 | // Send packet to be process by LWIP 349 | ip_input(pbuf, device->netif); 350 | // pbuf is owned by IP layer now 351 | pbuf = NULL; 352 | } 353 | } else { 354 | // IP header is corrupt or lied about packet size 355 | } 356 | } else { 357 | // This is a duplicate packet / replayed / too far out of order 358 | } 359 | } else { 360 | // This was a keep-alive packet 361 | } 362 | } 363 | 364 | if (pbuf) { 365 | pbuf_free(pbuf); 366 | } 367 | } 368 | 369 | 370 | } else { 371 | //After Reject-After-Messages transport data messages or after the current secure session is Reject- After-Time seconds old, 372 | // whichever comes first, WireGuard will refuse to send or receive any more transport data messages using the current secure session, 373 | // until a new secure session is created through the 1-RTT handshake 374 | keypair_destroy(keypair); 375 | } 376 | 377 | } else { 378 | // Could not locate valid keypair for remote index 379 | } 380 | } 381 | 382 | static struct pbuf *wireguardif_initiate_handshake(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_initiation *msg, err_t *error) { 383 | struct pbuf *pbuf = NULL; 384 | err_t err = ERR_OK; 385 | if (wireguard_create_handshake_initiation(device, peer, msg)) { 386 | // Send this packet out! 387 | pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct message_handshake_initiation), PBUF_RAM); 388 | if (pbuf) { 389 | err = pbuf_take(pbuf, msg, sizeof(struct message_handshake_initiation)); 390 | if (err == ERR_OK) { 391 | // OK! 392 | } else { 393 | pbuf_free(pbuf); 394 | pbuf = NULL; 395 | } 396 | } else { 397 | err = ERR_MEM; 398 | } 399 | } else { 400 | err = ERR_ARG; 401 | } 402 | if (error) { 403 | *error = err; 404 | } 405 | return pbuf; 406 | } 407 | 408 | static void wireguardif_send_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer) { 409 | struct message_handshake_response packet; 410 | struct pbuf *pbuf = NULL; 411 | err_t err = ERR_OK; 412 | 413 | if (wireguard_create_handshake_response(device, peer, &packet)) { 414 | 415 | wireguard_start_session(peer, false); 416 | 417 | // Send this packet out! 418 | pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct message_handshake_response), PBUF_RAM); 419 | if (pbuf) { 420 | err = pbuf_take(pbuf, &packet, sizeof(struct message_handshake_response)); 421 | if (err == ERR_OK) { 422 | // OK! 423 | wireguardif_peer_output(device->netif, pbuf, peer); 424 | } 425 | pbuf_free(pbuf); 426 | } 427 | } 428 | } 429 | 430 | static size_t get_source_addr_port(const ip_addr_t *addr, u16_t port, uint8_t *buf, size_t buflen) { 431 | size_t result = 0; 432 | 433 | #if LWIP_IPV4 434 | if (IP_IS_V4(addr) && (buflen >= 4)) { 435 | U32TO8_BIG(buf + result, PP_NTOHL(ip4_addr_get_u32(ip_2_ip4(addr)))); 436 | result += 4; 437 | } 438 | #endif 439 | #if LWIP_IPV6 440 | if (IP_IS_V6(addr) && (buflen >= 16)) { 441 | U16TO8_BIG(buf + result + 0, IP6_ADDR_BLOCK1(ip_2_ip6(addr))); 442 | U16TO8_BIG(buf + result + 2, IP6_ADDR_BLOCK2(ip_2_ip6(addr))); 443 | U16TO8_BIG(buf + result + 4, IP6_ADDR_BLOCK3(ip_2_ip6(addr))); 444 | U16TO8_BIG(buf + result + 6, IP6_ADDR_BLOCK4(ip_2_ip6(addr))); 445 | U16TO8_BIG(buf + result + 8, IP6_ADDR_BLOCK5(ip_2_ip6(addr))); 446 | U16TO8_BIG(buf + result + 10, IP6_ADDR_BLOCK6(ip_2_ip6(addr))); 447 | U16TO8_BIG(buf + result + 12, IP6_ADDR_BLOCK7(ip_2_ip6(addr))); 448 | U16TO8_BIG(buf + result + 14, IP6_ADDR_BLOCK8(ip_2_ip6(addr))); 449 | result += 16; 450 | } 451 | #endif 452 | if (buflen >= result + 2) { 453 | U16TO8_BIG(buf + result, port); 454 | result += 2; 455 | } 456 | return result; 457 | } 458 | 459 | static void wireguardif_send_handshake_cookie(struct wireguard_device *device, const uint8_t *mac1, uint32_t index, const ip_addr_t *addr, u16_t port) { 460 | struct message_cookie_reply packet; 461 | struct pbuf *pbuf = NULL; 462 | err_t err = ERR_OK; 463 | uint8_t source_buf[18]; 464 | size_t source_len = get_source_addr_port(addr, port, source_buf, sizeof(source_buf)); 465 | 466 | wireguard_create_cookie_reply(device, &packet, mac1, index, source_buf, source_len); 467 | 468 | // Send this packet out! 469 | pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct message_cookie_reply), PBUF_RAM); 470 | if (pbuf) { 471 | err = pbuf_take(pbuf, &packet, sizeof(struct message_cookie_reply)); 472 | if (err == ERR_OK) { 473 | wireguardif_device_output(device, pbuf, addr, port); 474 | } 475 | pbuf_free(pbuf); 476 | } 477 | } 478 | 479 | static bool wireguardif_check_initiation_message(struct wireguard_device *device, struct message_handshake_initiation *msg, const ip_addr_t *addr, u16_t port) { 480 | bool result = false; 481 | uint8_t *data = (uint8_t *)msg; 482 | uint8_t source_buf[18]; 483 | size_t source_len; 484 | // We received an initiation packet check it is valid 485 | 486 | if (wireguard_check_mac1(device, data, sizeof(struct message_handshake_initiation) - (2 * WIREGUARD_COOKIE_LEN), msg->mac1)) { 487 | // mac1 is valid! 488 | if (!wireguard_is_under_load()) { 489 | // If we aren't under load we only need mac1 to be correct 490 | result = true; 491 | } else { 492 | // If we are under load then check mac2 493 | source_len = get_source_addr_port(addr, port, source_buf, sizeof(source_buf)); 494 | 495 | result = wireguard_check_mac2(device, data, sizeof(struct message_handshake_initiation) - (WIREGUARD_COOKIE_LEN), source_buf, source_len, msg->mac2); 496 | 497 | if (!result) { 498 | // mac2 is invalid (cookie may have expired) or not present 499 | // 5.3 Denial of Service Mitigation & Cookies 500 | // If the responder receives a message with a valid msg.mac1 yet with an invalid msg.mac2, and is under load, it may respond with a cookie reply message 501 | wireguardif_send_handshake_cookie(device, msg->mac1, msg->sender, addr, port); 502 | } 503 | } 504 | 505 | } else { 506 | // mac1 is invalid 507 | } 508 | return result; 509 | } 510 | 511 | static bool wireguardif_check_response_message(struct wireguard_device *device, struct message_handshake_response *msg, const ip_addr_t *addr, u16_t port) { 512 | bool result = false; 513 | uint8_t *data = (uint8_t *)msg; 514 | uint8_t source_buf[18]; 515 | size_t source_len; 516 | // We received an initiation packet check it is valid 517 | 518 | if (wireguard_check_mac1(device, data, sizeof(struct message_handshake_response) - (2 * WIREGUARD_COOKIE_LEN), msg->mac1)) { 519 | // mac1 is valid! 520 | if (!wireguard_is_under_load()) { 521 | // If we aren't under load we only need mac1 to be correct 522 | result = true; 523 | } else { 524 | // If we are under load then check mac2 525 | source_len = get_source_addr_port(addr, port, source_buf, sizeof(source_buf)); 526 | 527 | result = wireguard_check_mac2(device, data, sizeof(struct message_handshake_response) - (WIREGUARD_COOKIE_LEN), source_buf, source_len, msg->mac2); 528 | 529 | if (!result) { 530 | // mac2 is invalid (cookie may have expired) or not present 531 | // 5.3 Denial of Service Mitigation & Cookies 532 | // If the responder receives a message with a valid msg.mac1 yet with an invalid msg.mac2, and is under load, it may respond with a cookie reply message 533 | wireguardif_send_handshake_cookie(device, msg->mac1, msg->sender, addr, port); 534 | } 535 | } 536 | 537 | } else { 538 | // mac1 is invalid 539 | } 540 | return result; 541 | } 542 | 543 | 544 | void wireguardif_network_rx(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { 545 | LWIP_ASSERT("wireguardif_network_rx: invalid arg", arg != NULL); 546 | LWIP_ASSERT("wireguardif_network_rx: invalid pbuf", p != NULL); 547 | // We have received a packet from the base_netif to our UDP port - process this as a possible Wireguard packet 548 | struct wireguard_device *device = (struct wireguard_device *)arg; 549 | struct wireguard_peer *peer; 550 | uint8_t *data = p->payload; 551 | size_t len = p->len; // This buf, not chained ones 552 | 553 | struct message_handshake_initiation *msg_initiation; 554 | struct message_handshake_response *msg_response; 555 | struct message_cookie_reply *msg_cookie; 556 | struct message_transport_data *msg_data; 557 | 558 | uint8_t type = wireguard_get_message_type(data, len); 559 | ESP_LOGV(TAG, "network_rx: %08x:%d", addr->u_addr.ip4.addr, port); 560 | 561 | switch (type) { 562 | case MESSAGE_HANDSHAKE_INITIATION: 563 | msg_initiation = (struct message_handshake_initiation *)data; 564 | log_i(TAG "HANDSHAKE_INITIATION: %08x:%d", addr->u_addr.ip4.addr, port); 565 | // Check mac1 (and optionally mac2) are correct - note it may internally generate a cookie reply packet 566 | if (wireguardif_check_initiation_message(device, msg_initiation, addr, port)) { 567 | 568 | peer = wireguard_process_initiation_message(device, msg_initiation); 569 | if (peer) { 570 | // Update the peer location 571 | update_peer_addr(peer, addr, port); 572 | 573 | // Send back a handshake response 574 | wireguardif_send_handshake_response(device, peer); 575 | } 576 | } 577 | break; 578 | 579 | case MESSAGE_HANDSHAKE_RESPONSE: 580 | log_i(TAG "HANDSHAKE_RESPONSE: %08x:%d", addr->u_addr.ip4.addr, port); 581 | msg_response = (struct message_handshake_response *)data; 582 | 583 | // Check mac1 (and optionally mac2) are correct - note it may internally generate a cookie reply packet 584 | if (wireguardif_check_response_message(device, msg_response, addr, port)) { 585 | 586 | peer = peer_lookup_by_handshake(device, msg_response->receiver); 587 | if (peer) { 588 | // Process the handshake response 589 | wireguardif_process_response_message(device, peer, msg_response, addr, port); 590 | } 591 | } 592 | break; 593 | 594 | case MESSAGE_COOKIE_REPLY: 595 | log_i(TAG "COOKIE_REPLY: %08x:%d", addr->u_addr.ip4.addr, port); 596 | msg_cookie = (struct message_cookie_reply *)data; 597 | peer = peer_lookup_by_handshake(device, msg_cookie->receiver); 598 | if (peer) { 599 | if (wireguard_process_cookie_message(device, peer, msg_cookie)) { 600 | // Update the peer location 601 | update_peer_addr(peer, addr, port); 602 | 603 | // Don't send anything out - we stay quiet until the next initiation message 604 | } 605 | } 606 | break; 607 | 608 | case MESSAGE_TRANSPORT_DATA: 609 | ESP_LOGV(TAG, "TRANSPORT_DATA: %08x:%d", addr->u_addr.ip4.addr, port); 610 | 611 | msg_data = (struct message_transport_data *)data; 612 | peer = peer_lookup_by_receiver(device, msg_data->receiver); 613 | if (peer) { 614 | // header is 16 bytes long so take that off the length 615 | wireguardif_process_data_message(device, peer, msg_data, len - 16, addr, port); 616 | } 617 | break; 618 | 619 | default: 620 | // Unknown or bad packet header 621 | break; 622 | } 623 | // Release data! 624 | pbuf_free(p); 625 | } 626 | 627 | static err_t wireguard_start_handshake(struct netif *netif, struct wireguard_peer *peer) { 628 | struct wireguard_device *device = (struct wireguard_device *)netif->state; 629 | err_t result; 630 | struct pbuf *pbuf; 631 | struct message_handshake_initiation msg; 632 | 633 | pbuf = wireguardif_initiate_handshake(device, peer, &msg, &result); 634 | if (pbuf) { 635 | result = wireguardif_peer_output(netif, pbuf, peer); 636 | log_i(TAG "start handshake %08x,%d - %d", peer->ip.u_addr.ip4.addr, peer->port, result); 637 | pbuf_free(pbuf); 638 | peer->send_handshake = false; 639 | peer->last_initiation_tx = wireguard_sys_now(); 640 | memcpy(peer->handshake_mac1, msg.mac1, WIREGUARD_COOKIE_LEN); 641 | peer->handshake_mac1_valid = true; 642 | } 643 | return result; 644 | } 645 | 646 | static err_t wireguardif_lookup_peer(struct netif *netif, u8_t peer_index, struct wireguard_peer **out) { 647 | LWIP_ASSERT("netif != NULL", (netif != NULL)); 648 | LWIP_ASSERT("state != NULL", (netif->state != NULL)); 649 | struct wireguard_device *device = (struct wireguard_device *)netif->state; 650 | struct wireguard_peer *peer = NULL; 651 | err_t result; 652 | 653 | if (device->valid) { 654 | peer = peer_lookup_by_peer_index(device, peer_index); 655 | if (peer) { 656 | result = ERR_OK; 657 | } else { 658 | result = ERR_ARG; 659 | } 660 | } else { 661 | result = ERR_ARG; 662 | } 663 | *out = peer; 664 | return result; 665 | } 666 | 667 | err_t wireguardif_connect(struct netif *netif, u8_t peer_index) { 668 | struct wireguard_peer *peer; 669 | err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); 670 | if (result == ERR_OK) { 671 | // Check that a valid connect ip and port have been set 672 | if (!ip_addr_isany(&peer->connect_ip) && (peer->connect_port > 0)) { 673 | // Set the flag that we want to try connecting 674 | peer->active = true; 675 | peer->ip = peer->connect_ip; 676 | peer->port = peer->connect_port; 677 | result = ERR_OK; 678 | } else { 679 | result = ERR_ARG; 680 | } 681 | } 682 | return result; 683 | } 684 | 685 | err_t wireguardif_disconnect(struct netif *netif, u8_t peer_index) { 686 | struct wireguard_peer *peer; 687 | err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); 688 | if (result == ERR_OK) { 689 | // Set the flag that we want to try connecting 690 | peer->active = false; 691 | // Wipe out current keys 692 | keypair_destroy(&peer->next_keypair); 693 | keypair_destroy(&peer->curr_keypair); 694 | keypair_destroy(&peer->prev_keypair); 695 | result = ERR_OK; 696 | } 697 | return result; 698 | } 699 | 700 | err_t wireguardif_peer_is_up(struct netif *netif, u8_t peer_index, ip_addr_t *current_ip, u16_t *current_port) { 701 | struct wireguard_peer *peer; 702 | err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); 703 | if (result == ERR_OK) { 704 | if ((peer->curr_keypair.valid) || (peer->prev_keypair.valid)) { 705 | result = ERR_OK; 706 | } else { 707 | result = ERR_CONN; 708 | } 709 | if (current_ip) { 710 | *current_ip = peer->ip; 711 | } 712 | if (current_port) { 713 | *current_port = peer->port; 714 | } 715 | } 716 | return result; 717 | } 718 | 719 | err_t wireguardif_remove_peer(struct netif *netif, u8_t peer_index) { 720 | struct wireguard_peer *peer; 721 | err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); 722 | if (result == ERR_OK) { 723 | crypto_zero(peer, sizeof(struct wireguard_peer)); 724 | peer->valid = false; 725 | result = ERR_OK; 726 | } 727 | return result; 728 | } 729 | 730 | err_t wireguardif_update_endpoint(struct netif *netif, u8_t peer_index, const ip_addr_t *ip, u16_t port) { 731 | struct wireguard_peer *peer; 732 | err_t result = wireguardif_lookup_peer(netif, peer_index, &peer); 733 | if (result == ERR_OK) { 734 | peer->connect_ip = *ip; 735 | peer->connect_port = port; 736 | result = ERR_OK; 737 | } 738 | return result; 739 | } 740 | 741 | 742 | err_t wireguardif_add_peer(struct netif *netif, struct wireguardif_peer *p, u8_t *peer_index) { 743 | LWIP_ASSERT("netif != NULL", (netif != NULL)); 744 | LWIP_ASSERT("state != NULL", (netif->state != NULL)); 745 | LWIP_ASSERT("p != NULL", (p != NULL)); 746 | struct wireguard_device *device = (struct wireguard_device *)netif->state; 747 | err_t result; 748 | uint8_t public_key[WIREGUARD_PUBLIC_KEY_LEN]; 749 | size_t public_key_len = sizeof(public_key); 750 | struct wireguard_peer *peer = NULL; 751 | 752 | uint32_t t1 = wireguard_sys_now(); 753 | 754 | if (wireguard_base64_decode(p->public_key, public_key, &public_key_len) 755 | && (public_key_len == WIREGUARD_PUBLIC_KEY_LEN)) { 756 | 757 | // See if the peer is already registered 758 | peer = peer_lookup_by_pubkey(device, public_key); 759 | if (!peer) { 760 | // Not active - see if we have room to allocate a new one 761 | peer = peer_alloc(device); 762 | if (peer) { 763 | 764 | if (wireguard_peer_init(device, peer, public_key, p->preshared_key)) { 765 | 766 | peer->connect_ip = p->endpoint_ip; 767 | peer->connect_port = p->endport_port; 768 | peer->ip = peer->connect_ip; 769 | peer->port = peer->connect_port; 770 | if (p->keep_alive == WIREGUARDIF_KEEPALIVE_DEFAULT) { 771 | peer->keepalive_interval = KEEPALIVE_TIMEOUT; 772 | } else { 773 | peer->keepalive_interval = p->keep_alive; 774 | } 775 | peer_add_ip(peer, p->allowed_ip, p->allowed_mask); 776 | memcpy(peer->greatest_timestamp, p->greatest_timestamp, sizeof(peer->greatest_timestamp)); 777 | 778 | result = ERR_OK; 779 | } else { 780 | result = ERR_ARG; 781 | } 782 | } else { 783 | result = ERR_MEM; 784 | } 785 | } else { 786 | result = ERR_OK; 787 | } 788 | } else { 789 | result = ERR_ARG; 790 | } 791 | 792 | uint32_t t2 = wireguard_sys_now(); 793 | log_i(TAG "Adding peer took %ums\r\n", (t2-t1)); 794 | 795 | if (peer_index) { 796 | if (peer) { 797 | *peer_index = wireguard_peer_index(device, peer); 798 | } else { 799 | *peer_index = WIREGUARDIF_INVALID_INDEX; 800 | } 801 | } 802 | return result; 803 | } 804 | 805 | static bool should_send_initiation(struct wireguard_peer *peer) { 806 | bool result = false; 807 | if (wireguardif_can_send_initiation(peer)) { 808 | if (peer->send_handshake) { 809 | result = true; 810 | } else if (peer->curr_keypair.valid && !peer->curr_keypair.initiator && wireguard_expired(peer->curr_keypair.keypair_millis, REJECT_AFTER_TIME - peer->keepalive_interval)) { 811 | result = true; 812 | } else if (!peer->curr_keypair.valid && peer->active) { 813 | result = true; 814 | } 815 | } 816 | return result; 817 | } 818 | 819 | static bool should_send_keepalive(struct wireguard_peer *peer) { 820 | bool result = false; 821 | if (peer->keepalive_interval > 0) { 822 | if ((peer->curr_keypair.valid) || (peer->prev_keypair.valid)) { 823 | if (wireguard_expired(peer->last_tx, peer->keepalive_interval)) { 824 | result = true; 825 | } 826 | } 827 | } 828 | return result; 829 | } 830 | 831 | static bool should_destroy_current_keypair(struct wireguard_peer *peer) { 832 | bool result = false; 833 | if (peer->curr_keypair.valid && 834 | (wireguard_expired(peer->curr_keypair.keypair_millis, REJECT_AFTER_TIME) || 835 | (peer->curr_keypair.sending_counter >= REJECT_AFTER_MESSAGES)) 836 | ) { 837 | result = true; 838 | } 839 | return result; 840 | } 841 | 842 | static bool should_reset_peer(struct wireguard_peer *peer) { 843 | bool result = false; 844 | if (peer->curr_keypair.valid && (wireguard_expired(peer->curr_keypair.keypair_millis, REJECT_AFTER_TIME * 3))) { 845 | result = true; 846 | } 847 | return result; 848 | } 849 | 850 | static void wireguardif_tmr(void *arg) { 851 | struct wireguard_device *device = (struct wireguard_device *)arg; 852 | struct wireguard_peer *peer; 853 | int x; 854 | // Reschedule this timer 855 | sys_timeout(WIREGUARDIF_TIMER_MSECS, wireguardif_tmr, device); 856 | 857 | // Check periodic things 858 | bool link_up = false; 859 | for (x=0; x < WIREGUARD_MAX_PEERS; x++) { 860 | peer = &device->peers[x]; 861 | if (peer->valid) { 862 | // Do we need to rekey / send a handshake? 863 | if (should_reset_peer(peer)) { 864 | // Nothing back for too long - we should wipe out all crypto state 865 | keypair_destroy(&peer->next_keypair); 866 | keypair_destroy(&peer->curr_keypair); 867 | keypair_destroy(&peer->prev_keypair); 868 | handshake_destroy(&peer->handshake); 869 | 870 | // Revert back to default IP/port if these were altered 871 | peer->ip = peer->connect_ip; 872 | peer->port = peer->connect_port; 873 | } 874 | if (should_destroy_current_keypair(peer)) { 875 | // Destroy current keypair 876 | keypair_destroy(&peer->curr_keypair); 877 | } 878 | if (should_send_keepalive(peer)) { 879 | wireguardif_send_keepalive(device, peer); 880 | } 881 | if (should_send_initiation(peer)) { 882 | wireguard_start_handshake(device->netif, peer); 883 | } 884 | 885 | if ((peer->curr_keypair.valid) || (peer->prev_keypair.valid)) { 886 | link_up = true; 887 | } 888 | } 889 | } 890 | 891 | if (!link_up) { 892 | // Clear the IF-UP flag on netif 893 | netif_set_link_down(device->netif); 894 | } 895 | } 896 | 897 | void wireguardif_shutdown(struct netif *netif) { 898 | LWIP_ASSERT("netif != NULL", (netif != NULL)); 899 | LWIP_ASSERT("state != NULL", (netif->state != NULL)); 900 | 901 | struct wireguard_device * device = (struct wireguard_device *)netif->state; 902 | // Disable timer. 903 | sys_untimeout(wireguardif_tmr, device); 904 | // remove UDP context. 905 | if( device->udp_pcb ) { 906 | udp_disconnect(device->udp_pcb); 907 | udp_remove(device->udp_pcb); 908 | device->udp_pcb = NULL; 909 | } 910 | // remove device context. 911 | free(device); 912 | netif->state = NULL; 913 | } 914 | 915 | err_t wireguardif_init(struct netif *netif) { 916 | err_t result; 917 | struct wireguardif_init_data *init_data; 918 | struct wireguard_device *device; 919 | struct udp_pcb *udp; 920 | uint8_t private_key[WIREGUARD_PRIVATE_KEY_LEN]; 921 | size_t private_key_len = sizeof(private_key); 922 | 923 | struct netif* underlying_netif; 924 | tcpip_adapter_get_netif(TCPIP_ADAPTER_IF_STA, &underlying_netif); 925 | log_i(TAG "underlying_netif = %p", underlying_netif); 926 | 927 | LWIP_ASSERT("netif != NULL", (netif != NULL)); 928 | LWIP_ASSERT("state != NULL", (netif->state != NULL)); 929 | 930 | // We need to initialise the wireguard module 931 | wireguard_init(); 932 | log_i(TAG "wireguard module initialized."); 933 | 934 | if (netif && netif->state) { 935 | 936 | // The init data is passed into the netif_add call as the 'state' - we will replace this with our private state data 937 | init_data = (struct wireguardif_init_data *)netif->state; 938 | 939 | // Clear out and set if function is successful 940 | netif->state = NULL; 941 | 942 | if (wireguard_base64_decode(init_data->private_key, private_key, &private_key_len) 943 | && (private_key_len == WIREGUARD_PRIVATE_KEY_LEN)) { 944 | 945 | udp = udp_new(); 946 | 947 | if (udp) { 948 | result = udp_bind(udp, IP_ADDR_ANY, init_data->listen_port); // Note this listens on all interfaces! Really just want the passed netif 949 | if (result == ERR_OK) { 950 | device = (struct wireguard_device *)mem_calloc(1, sizeof(struct wireguard_device)); 951 | if (device) { 952 | device->netif = netif; 953 | device->underlying_netif = underlying_netif; 954 | //udp_bind_netif(udp, underlying_netif); 955 | 956 | device->udp_pcb = udp; 957 | log_d(TAG "start device initialization"); 958 | // Per-wireguard netif/device setup 959 | uint32_t t1 = wireguard_sys_now(); 960 | if (wireguard_device_init(device, private_key)) { 961 | uint32_t t2 = wireguard_sys_now(); 962 | log_d(TAG "Device init took %ums\r\n", (t2-t1)); 963 | 964 | #if LWIP_CHECKSUM_CTRL_PER_NETIF 965 | NETIF_SET_CHECKSUM_CTRL(netif, NETIF_CHECKSUM_ENABLE_ALL); 966 | #endif 967 | netif->state = device; 968 | netif->name[0] = 'w'; 969 | netif->name[1] = 'g'; 970 | netif->output = wireguardif_output; 971 | netif->linkoutput = NULL; 972 | netif->hwaddr_len = 0; 973 | netif->mtu = WIREGUARDIF_MTU; 974 | // We set up no state flags here - caller should set them 975 | // NETIF_FLAG_LINK_UP is automatically set/cleared when at least one peer is connected 976 | netif->flags = 0; 977 | 978 | udp_recv(udp, wireguardif_network_rx, device); 979 | 980 | // Start a periodic timer for this wireguard device 981 | sys_timeout(WIREGUARDIF_TIMER_MSECS, wireguardif_tmr, device); 982 | 983 | result = ERR_OK; 984 | } else { 985 | log_e(TAG "failed to initialize WireGuard device."); 986 | mem_free(device); 987 | device = NULL; 988 | udp_remove(udp); 989 | result = ERR_ARG; 990 | } 991 | } else { 992 | log_e(TAG "failed to allocate device context."); 993 | udp_remove(udp); 994 | result = ERR_MEM; 995 | } 996 | } else { 997 | log_e(TAG "failed to bind UDP err=%d", result); 998 | udp_remove(udp); 999 | } 1000 | 1001 | } else { 1002 | log_e(TAG "failed to allocate UDP"); 1003 | result = ERR_MEM; 1004 | } 1005 | } else { 1006 | log_e(TAG "invalid init_data private key"); 1007 | result = ERR_ARG; 1008 | } 1009 | } else { 1010 | log_e(TAG "netif or state is NULL: netif=%p, netif.state:%p", netif, netif ? netif->state : NULL); 1011 | result = ERR_ARG; 1012 | } 1013 | return result; 1014 | } 1015 | 1016 | void wireguardif_peer_init(struct wireguardif_peer *peer) { 1017 | LWIP_ASSERT("peer != NULL", (peer != NULL)); 1018 | memset(peer, 0, sizeof(struct wireguardif_peer)); 1019 | // Caller must provide 'public_key' 1020 | peer->public_key = NULL; 1021 | ip_addr_set_any(false, &peer->endpoint_ip); 1022 | peer->endport_port = WIREGUARDIF_DEFAULT_PORT; 1023 | peer->keep_alive = WIREGUARDIF_KEEPALIVE_DEFAULT; 1024 | ip_addr_set_any(false, &peer->allowed_ip); 1025 | ip_addr_set_any(false, &peer->allowed_mask); 1026 | memset(peer->greatest_timestamp, 0, sizeof(peer->greatest_timestamp)); 1027 | peer->preshared_key = NULL; 1028 | } 1029 | -------------------------------------------------------------------------------- /src/wireguard.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Ported to ESP32 Arduino by Kenta Ida (fuga@fugafuga.org) 3 | * The original license is below: 4 | * 5 | * Copyright (c) 2021 Daniel Hope (www.floorsense.nz) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without modification, 9 | * are permitted provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, this 12 | * list of conditions and the following disclaimer. 13 | * 14 | * 2. Redistributions in binary form must reproduce the above copyright notice, this 15 | * list of conditions and the following disclaimer in the documentation and/or 16 | * other materials provided with the distribution. 17 | * 18 | * 3. Neither the name of "Floorsense Ltd", "Agile Workspace Ltd" nor the names of 19 | * its contributors may be used to endorse or promote products derived from this 20 | * software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 26 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | * 33 | * Author: Daniel Hope 34 | */ 35 | 36 | #include "wireguard.h" 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | #include "crypto.h" 43 | 44 | // For HMAC calculation 45 | #define WIREGUARD_BLAKE2S_BLOCK_SIZE (64) 46 | 47 | // 5.4 Messages 48 | // Constants 49 | static const uint8_t CONSTRUCTION[37] = "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s"; // The UTF-8 string literal "Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s", 37 bytes of output 50 | static const uint8_t IDENTIFIER[34] = "WireGuard v1 zx2c4 Jason@zx2c4.com"; // The UTF-8 string literal "WireGuard v1 zx2c4 Jason@zx2c4.com", 34 bytes of output 51 | static const uint8_t LABEL_MAC1[8] = "mac1----"; // Label-Mac1 The UTF-8 string literal "mac1----", 8 bytes of output. 52 | static const uint8_t LABEL_COOKIE[8] = "cookie--"; // Label-Cookie The UTF-8 string literal "cookie--", 8 bytes of output 53 | 54 | static const char *base64_lookup = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 55 | 56 | static const uint8_t zero_key[WIREGUARD_PUBLIC_KEY_LEN] = { 0 }; 57 | 58 | // Calculated in wireguard_init 59 | static uint8_t construction_hash[WIREGUARD_HASH_LEN]; 60 | static uint8_t identifier_hash[WIREGUARD_HASH_LEN]; 61 | 62 | 63 | void wireguard_init() { 64 | wireguard_blake2s_ctx ctx; 65 | // Pre-calculate chaining key hash 66 | wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); 67 | wireguard_blake2s_update(&ctx, CONSTRUCTION, sizeof(CONSTRUCTION)); 68 | wireguard_blake2s_final(&ctx, construction_hash); 69 | // Pre-calculate initial handshake hash - uses construction_hash calculated above 70 | wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); 71 | wireguard_blake2s_update(&ctx, construction_hash, sizeof(construction_hash)); 72 | wireguard_blake2s_update(&ctx, IDENTIFIER, sizeof(IDENTIFIER)); 73 | wireguard_blake2s_final(&ctx, identifier_hash); 74 | } 75 | 76 | struct wireguard_peer *peer_alloc(struct wireguard_device *device) { 77 | struct wireguard_peer *result = NULL; 78 | struct wireguard_peer *tmp; 79 | int x; 80 | for (x=0; x < WIREGUARD_MAX_PEERS; x++) { 81 | tmp = &device->peers[x]; 82 | if (!tmp->valid) { 83 | result = tmp; 84 | break; 85 | } 86 | } 87 | return result; 88 | } 89 | 90 | struct wireguard_peer *peer_lookup_by_pubkey(struct wireguard_device *device, uint8_t *public_key) { 91 | struct wireguard_peer *result = NULL; 92 | struct wireguard_peer *tmp; 93 | int x; 94 | for (x=0; x < WIREGUARD_MAX_PEERS; x++) { 95 | tmp = &device->peers[x]; 96 | if (tmp->valid) { 97 | if (memcmp(tmp->public_key, public_key, WIREGUARD_PUBLIC_KEY_LEN) == 0) { 98 | result = tmp; 99 | break; 100 | } 101 | } 102 | } 103 | return result; 104 | } 105 | 106 | uint8_t wireguard_peer_index(struct wireguard_device *device, struct wireguard_peer *peer) { 107 | uint8_t result = 0xFF; 108 | uint8_t x; 109 | for (x=0; x < WIREGUARD_MAX_PEERS; x++) { 110 | if (peer == &device->peers[x]) { 111 | result = x; 112 | break; 113 | } 114 | } 115 | return result; 116 | } 117 | 118 | struct wireguard_peer *peer_lookup_by_peer_index(struct wireguard_device *device, uint8_t peer_index) { 119 | struct wireguard_peer *result = NULL; 120 | if (peer_index < WIREGUARD_MAX_PEERS) { 121 | if (device->peers[peer_index].valid) { 122 | result = &device->peers[peer_index]; 123 | } 124 | } 125 | return result; 126 | } 127 | 128 | struct wireguard_peer *peer_lookup_by_receiver(struct wireguard_device *device, uint32_t receiver) { 129 | struct wireguard_peer *result = NULL; 130 | struct wireguard_peer *tmp; 131 | int x; 132 | for (x=0; x < WIREGUARD_MAX_PEERS; x++) { 133 | tmp = &device->peers[x]; 134 | if (tmp->valid) { 135 | if ((tmp->curr_keypair.valid && (tmp->curr_keypair.local_index == receiver)) || 136 | (tmp->next_keypair.valid && (tmp->next_keypair.local_index == receiver)) || 137 | (tmp->prev_keypair.valid && (tmp->prev_keypair.local_index == receiver)) 138 | ) { 139 | result = tmp; 140 | break; 141 | } 142 | } 143 | } 144 | return result; 145 | } 146 | 147 | struct wireguard_peer *peer_lookup_by_handshake(struct wireguard_device *device, uint32_t receiver) { 148 | struct wireguard_peer *result = NULL; 149 | struct wireguard_peer *tmp; 150 | int x; 151 | for (x=0; x < WIREGUARD_MAX_PEERS; x++) { 152 | tmp = &device->peers[x]; 153 | if (tmp->valid) { 154 | if (tmp->handshake.valid && tmp->handshake.initiator && (tmp->handshake.local_index == receiver)) { 155 | result = tmp; 156 | break; 157 | } 158 | } 159 | } 160 | return result; 161 | } 162 | 163 | bool wireguard_expired(uint32_t created_millis, uint32_t valid_seconds) { 164 | uint32_t diff = wireguard_sys_now() - created_millis; 165 | return (diff >= (valid_seconds * 1000)); 166 | } 167 | 168 | 169 | static void generate_cookie_secret(struct wireguard_device *device) { 170 | wireguard_random_bytes(device->cookie_secret, WIREGUARD_HASH_LEN); 171 | device->cookie_secret_millis = wireguard_sys_now(); 172 | } 173 | 174 | static void generate_peer_cookie(struct wireguard_device *device, uint8_t *cookie, uint8_t *source_addr_port, size_t source_length) { 175 | wireguard_blake2s_ctx ctx; 176 | 177 | if (wireguard_expired(device->cookie_secret_millis, COOKIE_SECRET_MAX_AGE)) { 178 | // Generate new random bytes 179 | generate_cookie_secret(device); 180 | } 181 | 182 | // Mac(key, input) Keyed-Blake2s(key, input, 16), the keyed MAC variant of the BLAKE2s hash function, returning 16 bytes of output 183 | wireguard_blake2s_init(&ctx, WIREGUARD_COOKIE_LEN, device->cookie_secret, WIREGUARD_HASH_LEN); 184 | // 5.4.7 Under Load: Cookie Reply Message 185 | // Mix in the IP address and port - have the IP layer pass this in as byte array to avoid using Lwip specific APIs in this module 186 | if ((source_addr_port) && (source_length > 0)) { 187 | wireguard_blake2s_update(&ctx, source_addr_port, source_length); 188 | } 189 | wireguard_blake2s_final(&ctx, cookie); 190 | } 191 | 192 | static void wireguard_mac(uint8_t *dst, const void *message, size_t len, const uint8_t *key, size_t keylen) { 193 | wireguard_blake2s(dst, WIREGUARD_COOKIE_LEN, key, keylen, message, len); 194 | } 195 | 196 | static void wireguard_mac_key(uint8_t *key, const uint8_t *public_key, const uint8_t *label, size_t label_len) { 197 | blake2s_ctx ctx; 198 | blake2s_init(&ctx, WIREGUARD_SESSION_KEY_LEN, NULL, 0); 199 | blake2s_update(&ctx, label, label_len); 200 | blake2s_update(&ctx, public_key, WIREGUARD_PUBLIC_KEY_LEN); 201 | blake2s_final(&ctx, key); 202 | } 203 | 204 | static void wireguard_mix_hash(uint8_t *hash, const uint8_t *src, size_t src_len) { 205 | wireguard_blake2s_ctx ctx; 206 | wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); 207 | wireguard_blake2s_update(&ctx, hash, WIREGUARD_HASH_LEN); 208 | wireguard_blake2s_update(&ctx, src, src_len); 209 | wireguard_blake2s_final(&ctx, hash); 210 | } 211 | 212 | static void wireguard_hmac(uint8_t *digest, const uint8_t *key, size_t key_len, const uint8_t *text, size_t text_len) { 213 | // Adapted from appendix example in RFC2104 to use BLAKE2S instead of MD5 - https://tools.ietf.org/html/rfc2104 214 | wireguard_blake2s_ctx ctx; 215 | uint8_t k_ipad[WIREGUARD_BLAKE2S_BLOCK_SIZE]; // inner padding - key XORd with ipad 216 | uint8_t k_opad[WIREGUARD_BLAKE2S_BLOCK_SIZE]; // outer padding - key XORd with opad 217 | 218 | uint8_t tk[WIREGUARD_HASH_LEN]; 219 | int i; 220 | // if key is longer than BLAKE2S_BLOCK_SIZE bytes reset it to key=BLAKE2S(key) 221 | if (key_len > WIREGUARD_BLAKE2S_BLOCK_SIZE) { 222 | wireguard_blake2s_ctx tctx; 223 | wireguard_blake2s_init(&tctx, WIREGUARD_HASH_LEN, NULL, 0); 224 | wireguard_blake2s_update(&tctx, key, key_len); 225 | wireguard_blake2s_final(&tctx, tk); 226 | key = tk; 227 | key_len = WIREGUARD_HASH_LEN; 228 | } 229 | 230 | // the HMAC transform looks like: 231 | // HASH(K XOR opad, HASH(K XOR ipad, text)) 232 | // where K is an n byte key 233 | // ipad is the byte 0x36 repeated BLAKE2S_BLOCK_SIZE times 234 | // opad is the byte 0x5c repeated BLAKE2S_BLOCK_SIZE times 235 | // and text is the data being protected 236 | memset(k_ipad, 0, sizeof(k_ipad)); 237 | memset(k_opad, 0, sizeof(k_opad)); 238 | memcpy(k_ipad, key, key_len); 239 | memcpy(k_opad, key, key_len); 240 | 241 | // XOR key with ipad and opad values 242 | for (i=0; i < WIREGUARD_BLAKE2S_BLOCK_SIZE; i++) { 243 | k_ipad[i] ^= 0x36; 244 | k_opad[i] ^= 0x5c; 245 | } 246 | // perform inner HASH 247 | wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); // init context for 1st pass 248 | wireguard_blake2s_update(&ctx, k_ipad, WIREGUARD_BLAKE2S_BLOCK_SIZE); // start with inner pad 249 | wireguard_blake2s_update(&ctx, text, text_len); // then text of datagram 250 | wireguard_blake2s_final(&ctx, digest); // finish up 1st pass 251 | 252 | // perform outer HASH 253 | wireguard_blake2s_init(&ctx, WIREGUARD_HASH_LEN, NULL, 0); // init context for 2nd pass 254 | wireguard_blake2s_update(&ctx, k_opad, WIREGUARD_BLAKE2S_BLOCK_SIZE); // start with outer pad 255 | wireguard_blake2s_update(&ctx, digest, WIREGUARD_HASH_LEN); // then results of 1st hash 256 | wireguard_blake2s_final(&ctx, digest); // finish up 2nd pass 257 | } 258 | 259 | static void wireguard_kdf1(uint8_t *tau1, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) { 260 | uint8_t tau0[WIREGUARD_HASH_LEN]; 261 | uint8_t output[WIREGUARD_HASH_LEN + 1]; 262 | 263 | // tau0 = Hmac(key, input) 264 | wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len); 265 | // tau1 := Hmac(tau0, 0x1) 266 | output[0] = 1; 267 | wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1); 268 | memcpy(tau1, output, WIREGUARD_HASH_LEN); 269 | 270 | // Wipe intermediates 271 | crypto_zero(tau0, sizeof(tau0)); 272 | crypto_zero(output, sizeof(output)); 273 | } 274 | 275 | static void wireguard_kdf2(uint8_t *tau1, uint8_t *tau2, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) { 276 | uint8_t tau0[WIREGUARD_HASH_LEN]; 277 | uint8_t output[WIREGUARD_HASH_LEN + 1]; 278 | 279 | // tau0 = Hmac(key, input) 280 | wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len); 281 | // tau1 := Hmac(tau0, 0x1) 282 | output[0] = 1; 283 | wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1); 284 | memcpy(tau1, output, WIREGUARD_HASH_LEN); 285 | 286 | // tau2 := Hmac(tau0,tau1 || 0x2) 287 | output[WIREGUARD_HASH_LEN] = 2; 288 | wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1); 289 | memcpy(tau2, output, WIREGUARD_HASH_LEN); 290 | 291 | // Wipe intermediates 292 | crypto_zero(tau0, sizeof(tau0)); 293 | crypto_zero(output, sizeof(output)); 294 | } 295 | 296 | static void wireguard_kdf3(uint8_t *tau1, uint8_t *tau2, uint8_t *tau3, const uint8_t *chaining_key, const uint8_t *data, size_t data_len) { 297 | uint8_t tau0[WIREGUARD_HASH_LEN]; 298 | uint8_t output[WIREGUARD_HASH_LEN + 1]; 299 | 300 | // tau0 = Hmac(key, input) 301 | wireguard_hmac(tau0, chaining_key, WIREGUARD_HASH_LEN, data, data_len); 302 | // tau1 := Hmac(tau0, 0x1) 303 | output[0] = 1; 304 | wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, 1); 305 | memcpy(tau1, output, WIREGUARD_HASH_LEN); 306 | 307 | // tau2 := Hmac(tau0,tau1 || 0x2) 308 | output[WIREGUARD_HASH_LEN] = 2; 309 | wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1); 310 | memcpy(tau2, output, WIREGUARD_HASH_LEN); 311 | 312 | // tau3 := Hmac(tau0,tau1,tau2 || 0x3) 313 | output[WIREGUARD_HASH_LEN] = 3; 314 | wireguard_hmac(output, tau0, WIREGUARD_HASH_LEN, output, WIREGUARD_HASH_LEN + 1); 315 | memcpy(tau3, output, WIREGUARD_HASH_LEN); 316 | 317 | // Wipe intermediates 318 | crypto_zero(tau0, sizeof(tau0)); 319 | crypto_zero(output, sizeof(output)); 320 | } 321 | 322 | bool wireguard_check_replay(struct wireguard_keypair *keypair, uint64_t seq) { 323 | // Implementation of packet replay window - as per RFC2401 324 | // Adapted from code in Appendix C at https://tools.ietf.org/html/rfc2401 325 | uint32_t diff; 326 | bool result = false; 327 | size_t ReplayWindowSize = sizeof(keypair->replay_bitmap); // 32 bits 328 | 329 | if (seq != 0) { 330 | if (seq > keypair->replay_counter) { 331 | // new larger sequence number 332 | diff = seq - keypair->replay_counter; 333 | if (diff < ReplayWindowSize) { 334 | // In window 335 | keypair->replay_bitmap <<= diff; 336 | // set bit for this packet 337 | keypair->replay_bitmap |= 1; 338 | } else { 339 | // This packet has a "way larger" 340 | keypair->replay_bitmap = 1; 341 | } 342 | keypair->replay_counter = seq; 343 | // larger is good 344 | result = true; 345 | } else { 346 | diff = keypair->replay_counter - seq; 347 | if (diff < ReplayWindowSize) { 348 | if (keypair->replay_bitmap & ((uint32_t)1 << diff)) { 349 | // already seen 350 | } else { 351 | // mark as seen 352 | keypair->replay_bitmap |= ((uint32_t)1 << diff); 353 | // out of order but good 354 | result = true; 355 | } 356 | } else { 357 | // too old or wrapped 358 | } 359 | } 360 | } else { 361 | // first == 0 or wrapped 362 | } 363 | return result; 364 | } 365 | 366 | struct wireguard_keypair *get_peer_keypair_for_idx(struct wireguard_peer *peer, uint32_t idx) { 367 | if (peer->curr_keypair.valid && peer->curr_keypair.local_index == idx) { 368 | return &peer->curr_keypair; 369 | } else if (peer->next_keypair.valid && peer->next_keypair.local_index == idx) { 370 | return &peer->next_keypair; 371 | } else if (peer->prev_keypair.valid && peer->prev_keypair.local_index == idx) { 372 | return &peer->prev_keypair; 373 | } 374 | return NULL; 375 | } 376 | 377 | static uint32_t wireguard_generate_unique_index(struct wireguard_device *device) { 378 | // We need a random 32-bit number but make sure it's not already been used in the context of this device 379 | uint32_t result; 380 | uint8_t buf[4]; 381 | int x; 382 | struct wireguard_peer *peer; 383 | bool existing; 384 | do { 385 | do { 386 | wireguard_random_bytes(buf, 4); 387 | result = U8TO32_LITTLE(buf); 388 | } while ((result == 0) || (result == 0xFFFFFFFF)); // Don't allow 0 or 0xFFFFFFFF as valid values 389 | 390 | existing = false; 391 | for (x=0; x < WIREGUARD_MAX_PEERS; x++) { 392 | peer = &device->peers[x]; 393 | existing = (result == peer->curr_keypair.local_index) || 394 | (result == peer->prev_keypair.local_index) || 395 | (result == peer->next_keypair.local_index) || 396 | (result == peer->handshake.local_index); 397 | 398 | } 399 | } while (existing); 400 | 401 | return result; 402 | } 403 | 404 | static void wireguard_clamp_private_key(uint8_t *key) { 405 | key[0] &= 248; 406 | key[31] = (key[31] & 127) | 64; 407 | } 408 | 409 | static void wireguard_generate_private_key(uint8_t *key) { 410 | wireguard_random_bytes(key, WIREGUARD_PRIVATE_KEY_LEN); 411 | wireguard_clamp_private_key(key); 412 | } 413 | 414 | static bool wireguard_generate_public_key(uint8_t *public_key, const uint8_t *private_key) { 415 | static const uint8_t basepoint[WIREGUARD_PUBLIC_KEY_LEN] = { 9 }; 416 | bool result = false; 417 | if (memcmp(private_key, zero_key, WIREGUARD_PUBLIC_KEY_LEN) != 0) { 418 | result = (wireguard_x25519(public_key, private_key, basepoint) == 0); 419 | } 420 | return result; 421 | } 422 | 423 | bool wireguard_check_mac1(struct wireguard_device *device, const uint8_t *data, size_t len, const uint8_t *mac1) { 424 | bool result = false; 425 | uint8_t calculated[WIREGUARD_COOKIE_LEN]; 426 | wireguard_mac(calculated, data, len, device->label_mac1_key, WIREGUARD_SESSION_KEY_LEN); 427 | if (crypto_equal(calculated, mac1, WIREGUARD_COOKIE_LEN)) { 428 | result = true; 429 | } 430 | return result; 431 | } 432 | 433 | bool wireguard_check_mac2(struct wireguard_device *device, const uint8_t *data, size_t len, uint8_t *source_addr_port, size_t source_length, const uint8_t *mac2) { 434 | bool result = false; 435 | uint8_t cookie[WIREGUARD_COOKIE_LEN]; 436 | uint8_t calculated[WIREGUARD_COOKIE_LEN]; 437 | 438 | generate_peer_cookie(device, cookie, source_addr_port, source_length); 439 | 440 | wireguard_mac(calculated, data, len, cookie, WIREGUARD_COOKIE_LEN); 441 | if (crypto_equal(calculated, mac2, WIREGUARD_COOKIE_LEN)) { 442 | result = true; 443 | } 444 | return result; 445 | } 446 | 447 | void handshake_destroy(struct wireguard_handshake *handshake) { 448 | crypto_zero(handshake->ephemeral_private, WIREGUARD_PUBLIC_KEY_LEN); 449 | crypto_zero(handshake->remote_ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 450 | crypto_zero(handshake->hash, WIREGUARD_HASH_LEN); 451 | crypto_zero(handshake->chaining_key, WIREGUARD_HASH_LEN); 452 | handshake->remote_index = 0; 453 | handshake->local_index = 0; 454 | handshake->valid = false; 455 | } 456 | 457 | void keypair_destroy(struct wireguard_keypair *keypair) { 458 | crypto_zero(keypair, sizeof(struct wireguard_keypair)); 459 | keypair->valid = false; 460 | } 461 | 462 | void keypair_update(struct wireguard_peer *peer, struct wireguard_keypair *received_keypair) { 463 | bool key_is_next = (received_keypair == &peer->next_keypair); 464 | if (key_is_next) { 465 | peer->prev_keypair = peer->curr_keypair; 466 | peer->curr_keypair = peer->next_keypair; 467 | keypair_destroy(&peer->next_keypair); 468 | } 469 | } 470 | 471 | static void add_new_keypair(struct wireguard_peer *peer, struct wireguard_keypair new_keypair) { 472 | if (new_keypair.initiator) { 473 | if (peer->next_keypair.valid) { 474 | peer->prev_keypair = peer->next_keypair; 475 | keypair_destroy(&peer->next_keypair); 476 | } else { 477 | peer->prev_keypair = peer->curr_keypair; 478 | } 479 | peer->curr_keypair = new_keypair; 480 | } else { 481 | peer->next_keypair = new_keypair; 482 | keypair_destroy(&peer->prev_keypair); 483 | } 484 | } 485 | 486 | void wireguard_start_session(struct wireguard_peer *peer, bool initiator) { 487 | struct wireguard_handshake *handshake = &peer->handshake; 488 | struct wireguard_keypair new_keypair; 489 | 490 | crypto_zero(&new_keypair, sizeof(struct wireguard_keypair)); 491 | new_keypair.initiator = initiator; 492 | new_keypair.local_index = handshake->local_index; 493 | new_keypair.remote_index = handshake->remote_index; 494 | 495 | new_keypair.keypair_millis = wireguard_sys_now(); 496 | new_keypair.sending_valid = true; 497 | new_keypair.receiving_valid = true; 498 | 499 | // 5.4.5 Transport Data Key Derivation 500 | // (Tsendi = Trecvr, Trecvi = Tsendr) := Kdf2(Ci = Cr,E) 501 | if (new_keypair.initiator) { 502 | wireguard_kdf2(new_keypair.sending_key, new_keypair.receiving_key, handshake->chaining_key, NULL, 0); 503 | } else { 504 | wireguard_kdf2(new_keypair.receiving_key, new_keypair.sending_key, handshake->chaining_key, NULL, 0); 505 | } 506 | 507 | new_keypair.replay_bitmap = 0; 508 | new_keypair.replay_counter = 0; 509 | 510 | new_keypair.last_tx = 0; 511 | new_keypair.last_rx = 0; // No packets received yet 512 | 513 | new_keypair.valid = true; 514 | 515 | // Eprivi = Epubi = Eprivr = Epubr = Ci = Cr := E 516 | crypto_zero(handshake->ephemeral_private, WIREGUARD_PUBLIC_KEY_LEN); 517 | crypto_zero(handshake->remote_ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 518 | crypto_zero(handshake->hash, WIREGUARD_HASH_LEN); 519 | crypto_zero(handshake->chaining_key, WIREGUARD_HASH_LEN); 520 | handshake->remote_index = 0; 521 | handshake->local_index = 0; 522 | handshake->valid = false; 523 | 524 | add_new_keypair(peer, new_keypair); 525 | } 526 | 527 | uint8_t wireguard_get_message_type(const uint8_t *data, size_t len) { 528 | uint8_t result = MESSAGE_INVALID; 529 | if (len >= 4) { 530 | if ((data[1] == 0) && (data[2] == 0) && (data[3] == 0)) { 531 | switch (data[0]) { 532 | case MESSAGE_HANDSHAKE_INITIATION: 533 | if (len == sizeof(struct message_handshake_initiation)) { 534 | result = MESSAGE_HANDSHAKE_INITIATION; 535 | } 536 | break; 537 | case MESSAGE_HANDSHAKE_RESPONSE: 538 | if (len == sizeof(struct message_handshake_response)) { 539 | result = MESSAGE_HANDSHAKE_RESPONSE; 540 | } 541 | break; 542 | case MESSAGE_COOKIE_REPLY: 543 | if (len == sizeof(struct message_cookie_reply)) { 544 | result = MESSAGE_COOKIE_REPLY; 545 | } 546 | break; 547 | case MESSAGE_TRANSPORT_DATA: 548 | if (len >= sizeof(struct message_transport_data) + WIREGUARD_AUTHTAG_LEN) { 549 | result = MESSAGE_TRANSPORT_DATA; 550 | } 551 | break; 552 | default: 553 | break; 554 | } 555 | } 556 | } 557 | return result; 558 | } 559 | 560 | struct wireguard_peer *wireguard_process_initiation_message(struct wireguard_device *device, struct message_handshake_initiation *msg) { 561 | struct wireguard_peer *ret_peer = NULL; 562 | struct wireguard_peer *peer = NULL; 563 | struct wireguard_handshake *handshake; 564 | uint8_t key[WIREGUARD_SESSION_KEY_LEN]; 565 | uint8_t chaining_key[WIREGUARD_HASH_LEN]; 566 | uint8_t hash[WIREGUARD_HASH_LEN]; 567 | uint8_t s[WIREGUARD_PUBLIC_KEY_LEN]; 568 | uint8_t e[WIREGUARD_PUBLIC_KEY_LEN]; 569 | uint8_t t[WIREGUARD_TAI64N_LEN]; 570 | uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN]; 571 | uint32_t now; 572 | bool rate_limit; 573 | bool replay; 574 | 575 | // We are the responder, other end is the initiator 576 | 577 | // Ci := Hash(Construction) (precalculated hash) 578 | memcpy(chaining_key, construction_hash, WIREGUARD_HASH_LEN); 579 | 580 | // Hi := Hash(Ci || Identifier 581 | memcpy(hash, identifier_hash, WIREGUARD_HASH_LEN); 582 | 583 | // Hi := Hash(Hi || Spubr) 584 | wireguard_mix_hash(hash, device->public_key, WIREGUARD_PUBLIC_KEY_LEN); 585 | 586 | // Ci := Kdf1(Ci, Epubi) 587 | wireguard_kdf1(chaining_key, chaining_key, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 588 | 589 | // msg.ephemeral := Epubi 590 | memcpy(e, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 591 | 592 | // Hi := Hash(Hi || msg.ephemeral) 593 | wireguard_mix_hash(hash, msg->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 594 | 595 | // Calculate DH(Eprivi,Spubr) 596 | wireguard_x25519(dh_calculation, device->private_key, e); 597 | if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { 598 | 599 | // (Ci,k) := Kdf2(Ci,DH(Eprivi,Spubr)) 600 | wireguard_kdf2(chaining_key, key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); 601 | 602 | // msg.static := AEAD(k, 0, Spubi, Hi) 603 | if (wireguard_aead_decrypt(s, msg->enc_static, sizeof(msg->enc_static), hash, WIREGUARD_HASH_LEN, 0, key)) { 604 | // Hi := Hash(Hi || msg.static) 605 | wireguard_mix_hash(hash, msg->enc_static, sizeof(msg->enc_static)); 606 | 607 | peer = peer_lookup_by_pubkey(device, s); 608 | if (peer) { 609 | handshake = &peer->handshake; 610 | 611 | // (Ci,k) := Kdf2(Ci,DH(Sprivi,Spubr)) 612 | wireguard_kdf2(chaining_key, key, chaining_key, peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN); 613 | 614 | // msg.timestamp := AEAD(k, 0, Timestamp(), Hi) 615 | if (wireguard_aead_decrypt(t, msg->enc_timestamp, sizeof(msg->enc_timestamp), hash, WIREGUARD_HASH_LEN, 0, key)) { 616 | // Hi := Hash(Hi || msg.timestamp) 617 | wireguard_mix_hash(hash, msg->enc_timestamp, sizeof(msg->enc_timestamp)); 618 | 619 | now = wireguard_sys_now(); 620 | 621 | // Check that timestamp is increasing and we haven't had too many initiations (should only get one per peer every 5 seconds max?) 622 | replay = (memcmp(t, peer->greatest_timestamp, WIREGUARD_TAI64N_LEN) <= 0); // tai64n is big endian so we can use memcmp to compare 623 | rate_limit = (peer->last_initiation_rx - now) < (1000 / MAX_INITIATIONS_PER_SECOND); 624 | 625 | if (!replay && !rate_limit) { 626 | // Success! Copy everything to peer 627 | peer->last_initiation_rx = now; 628 | if (memcmp(t, peer->greatest_timestamp, WIREGUARD_TAI64N_LEN) > 0) { 629 | memcpy(peer->greatest_timestamp, t, WIREGUARD_TAI64N_LEN); 630 | // TODO: Need to notify if the higher layers want to persist latest timestamp/nonce somewhere 631 | } 632 | memcpy(handshake->remote_ephemeral, e, WIREGUARD_PUBLIC_KEY_LEN); 633 | memcpy(handshake->hash, hash, WIREGUARD_HASH_LEN); 634 | memcpy(handshake->chaining_key, chaining_key, WIREGUARD_HASH_LEN); 635 | handshake->remote_index = msg->sender; 636 | handshake->valid = true; 637 | handshake->initiator = false; 638 | ret_peer = peer; 639 | 640 | } else { 641 | // Ignore 642 | } 643 | } else { 644 | // Failed to decrypt 645 | } 646 | } else { 647 | // peer not found 648 | } 649 | } else { 650 | // Failed to decrypt 651 | } 652 | } else { 653 | // Bad X25519 654 | } 655 | 656 | crypto_zero(key, sizeof(key)); 657 | crypto_zero(hash, sizeof(hash)); 658 | crypto_zero(chaining_key, sizeof(chaining_key)); 659 | crypto_zero(dh_calculation, sizeof(dh_calculation)); 660 | 661 | return ret_peer; 662 | } 663 | 664 | bool wireguard_process_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *src) { 665 | struct wireguard_handshake *handshake = &peer->handshake; 666 | 667 | bool result = false; 668 | uint8_t key[WIREGUARD_SESSION_KEY_LEN]; 669 | uint8_t hash[WIREGUARD_HASH_LEN]; 670 | uint8_t chaining_key[WIREGUARD_HASH_LEN]; 671 | uint8_t e[WIREGUARD_PUBLIC_KEY_LEN]; 672 | uint8_t ephemeral_private[WIREGUARD_PUBLIC_KEY_LEN]; 673 | uint8_t static_private[WIREGUARD_PUBLIC_KEY_LEN]; 674 | uint8_t preshared_key[WIREGUARD_SESSION_KEY_LEN]; 675 | uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN]; 676 | uint8_t tau[WIREGUARD_PUBLIC_KEY_LEN]; 677 | 678 | if (handshake->valid && handshake->initiator) { 679 | 680 | memcpy(hash, handshake->hash, WIREGUARD_HASH_LEN); 681 | memcpy(chaining_key, handshake->chaining_key, WIREGUARD_HASH_LEN); 682 | memcpy(ephemeral_private, handshake->ephemeral_private, WIREGUARD_PUBLIC_KEY_LEN); 683 | memcpy(preshared_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN); 684 | 685 | // (Eprivr, Epubr) := DH-Generate() 686 | // Not required 687 | 688 | // Cr := Kdf1(Cr,Epubr) 689 | wireguard_kdf1(chaining_key, chaining_key, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 690 | 691 | // msg.ephemeral := Epubr 692 | memcpy(e, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 693 | 694 | // Hr := Hash(Hr || msg.ephemeral) 695 | wireguard_mix_hash(hash, src->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 696 | 697 | // Cr := Kdf1(Cr, DH(Eprivr, Epubi)) 698 | // Calculate DH(Eprivr, Epubi) 699 | wireguard_x25519(dh_calculation, ephemeral_private, e); 700 | if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { 701 | wireguard_kdf1(chaining_key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); 702 | 703 | // Cr := Kdf1(Cr, DH(Eprivr, Spubi)) 704 | // CalculateDH(Eprivr, Spubi) 705 | wireguard_x25519(dh_calculation, device->private_key, e); 706 | if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { 707 | wireguard_kdf1(chaining_key, chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); 708 | 709 | // (Cr, t, k) := Kdf3(Cr, Q) 710 | wireguard_kdf3(chaining_key, tau, key, chaining_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN); 711 | 712 | // Hr := Hash(Hr | t) 713 | wireguard_mix_hash(hash, tau, WIREGUARD_HASH_LEN); 714 | 715 | // msg.empty := AEAD(k, 0, E, Hr) 716 | if (wireguard_aead_decrypt(NULL, src->enc_empty, sizeof(src->enc_empty), hash, WIREGUARD_HASH_LEN, 0, key)) { 717 | // Hr := Hash(Hr | msg.empty) 718 | // Not required as discarded 719 | 720 | //Copy details to handshake 721 | memcpy(handshake->remote_ephemeral, e, WIREGUARD_HASH_LEN); 722 | memcpy(handshake->hash, hash, WIREGUARD_HASH_LEN); 723 | memcpy(handshake->chaining_key, chaining_key, WIREGUARD_HASH_LEN); 724 | handshake->remote_index = src->sender; 725 | 726 | result = true; 727 | } else { 728 | // Decrypt failed 729 | } 730 | 731 | } else { 732 | // X25519 fail 733 | } 734 | 735 | } else { 736 | // X25519 fail 737 | } 738 | 739 | } 740 | crypto_zero(key, sizeof(key)); 741 | crypto_zero(hash, sizeof(hash)); 742 | crypto_zero(chaining_key, sizeof(chaining_key)); 743 | crypto_zero(ephemeral_private, sizeof(ephemeral_private)); 744 | crypto_zero(static_private, sizeof(static_private)); 745 | crypto_zero(preshared_key, sizeof(preshared_key)); 746 | crypto_zero(tau, sizeof(tau)); 747 | 748 | return result; 749 | } 750 | 751 | bool wireguard_process_cookie_message(struct wireguard_device *device, struct wireguard_peer *peer, struct message_cookie_reply *src) { 752 | uint8_t cookie[WIREGUARD_COOKIE_LEN]; 753 | bool result = false; 754 | 755 | if (peer->handshake_mac1_valid) { 756 | 757 | result = wireguard_xaead_decrypt(cookie, src->enc_cookie, sizeof(src->enc_cookie), peer->handshake_mac1, WIREGUARD_COOKIE_LEN, src->nonce, peer->label_cookie_key); 758 | 759 | if (result) { 760 | // 5.4.7 Under Load: Cookie Reply Message 761 | // Upon receiving this message, if it is valid, the only thing the recipient of this message should do is store the cookie along with the time at which it was received 762 | memcpy(peer->cookie, cookie, WIREGUARD_COOKIE_LEN); 763 | peer->cookie_millis = wireguard_sys_now(); 764 | peer->handshake_mac1_valid = false; 765 | } 766 | } else { 767 | // We didn't send any initiation packet so we shouldn't be getting a cookie reply! 768 | } 769 | return result; 770 | } 771 | 772 | bool wireguard_create_handshake_initiation(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_initiation *dst) { 773 | uint8_t timestamp[WIREGUARD_TAI64N_LEN]; 774 | uint8_t key[WIREGUARD_SESSION_KEY_LEN]; 775 | uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN]; 776 | bool result = false; 777 | 778 | struct wireguard_handshake *handshake = &peer->handshake; 779 | 780 | memset(dst, 0, sizeof(struct message_handshake_initiation)); 781 | 782 | // Ci := Hash(Construction) (precalculated hash) 783 | memcpy(handshake->chaining_key, construction_hash, WIREGUARD_HASH_LEN); 784 | 785 | // Hi := Hash(Ci || Identifier) 786 | memcpy(handshake->hash, identifier_hash, WIREGUARD_HASH_LEN); 787 | 788 | // Hi := Hash(Hi || Spubr) 789 | wireguard_mix_hash(handshake->hash, peer->public_key, WIREGUARD_PUBLIC_KEY_LEN); 790 | 791 | // (Eprivi, Epubi) := DH-Generate() 792 | wireguard_generate_private_key(handshake->ephemeral_private); 793 | if (wireguard_generate_public_key(dst->ephemeral, handshake->ephemeral_private)) { 794 | 795 | // Ci := Kdf1(Ci, Epubi) 796 | wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 797 | 798 | // msg.ephemeral := Epubi 799 | // Done above - public keys is calculated into dst->ephemeral 800 | 801 | // Hi := Hash(Hi || msg.ephemeral) 802 | wireguard_mix_hash(handshake->hash, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 803 | 804 | // Calculate DH(Eprivi,Spubr) 805 | wireguard_x25519(dh_calculation, handshake->ephemeral_private, peer->public_key); 806 | if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { 807 | 808 | // (Ci,k) := Kdf2(Ci,DH(Eprivi,Spubr)) 809 | wireguard_kdf2(handshake->chaining_key, key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); 810 | 811 | // msg.static := AEAD(k,0,Spubi, Hi) 812 | wireguard_aead_encrypt(dst->enc_static, device->public_key, WIREGUARD_PUBLIC_KEY_LEN, handshake->hash, WIREGUARD_HASH_LEN, 0, key); 813 | 814 | // Hi := Hash(Hi || msg.static) 815 | wireguard_mix_hash(handshake->hash, dst->enc_static, sizeof(dst->enc_static)); 816 | 817 | // (Ci,k) := Kdf2(Ci,DH(Sprivi,Spubr)) 818 | // note DH(Sprivi,Spubr) is precomputed per peer 819 | wireguard_kdf2(handshake->chaining_key, key, handshake->chaining_key, peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN); 820 | 821 | // msg.timestamp := AEAD(k, 0, Timestamp(), Hi) 822 | wireguard_tai64n_now(timestamp); 823 | wireguard_aead_encrypt(dst->enc_timestamp, timestamp, WIREGUARD_TAI64N_LEN, handshake->hash, WIREGUARD_HASH_LEN, 0, key); 824 | 825 | // Hi := Hash(Hi || msg.timestamp) 826 | wireguard_mix_hash(handshake->hash, dst->enc_timestamp, sizeof(dst->enc_timestamp)); 827 | 828 | dst->type = MESSAGE_HANDSHAKE_INITIATION; 829 | dst->sender = wireguard_generate_unique_index(device); 830 | 831 | handshake->valid = true; 832 | handshake->initiator = true; 833 | handshake->local_index = dst->sender; 834 | 835 | result = true; 836 | } 837 | } 838 | 839 | if (result) { 840 | // 5.4.4 Cookie MACs 841 | // msg.mac1 := Mac(Hash(Label-Mac1 || Spubm' ), msgA) 842 | // The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed 843 | wireguard_mac(dst->mac1, dst, (sizeof(struct message_handshake_initiation)-(2*WIREGUARD_COOKIE_LEN)), peer->label_mac1_key, WIREGUARD_SESSION_KEY_LEN); 844 | 845 | // if Lm = E or Lm ≥ 120: 846 | if ((peer->cookie_millis == 0) || wireguard_expired(peer->cookie_millis, COOKIE_SECRET_MAX_AGE)) { 847 | // msg.mac2 := 0 848 | crypto_zero(dst->mac2, WIREGUARD_COOKIE_LEN); 849 | } else { 850 | // msg.mac2 := Mac(Lm, msgB) 851 | wireguard_mac(dst->mac2, dst, (sizeof(struct message_handshake_initiation)-(WIREGUARD_COOKIE_LEN)), peer->cookie, WIREGUARD_COOKIE_LEN); 852 | 853 | } 854 | } 855 | 856 | crypto_zero(key, sizeof(key)); 857 | crypto_zero(dh_calculation, sizeof(dh_calculation)); 858 | return result; 859 | } 860 | 861 | bool wireguard_create_handshake_response(struct wireguard_device *device, struct wireguard_peer *peer, struct message_handshake_response *dst) { 862 | struct wireguard_handshake *handshake = &peer->handshake; 863 | uint8_t key[WIREGUARD_SESSION_KEY_LEN]; 864 | uint8_t dh_calculation[WIREGUARD_PUBLIC_KEY_LEN]; 865 | uint8_t tau[WIREGUARD_HASH_LEN]; 866 | bool result = false; 867 | 868 | memset(dst, 0, sizeof(struct message_handshake_response)); 869 | 870 | if (handshake->valid && !handshake->initiator) { 871 | 872 | // (Eprivr, Epubr) := DH-Generate() 873 | wireguard_generate_private_key(handshake->ephemeral_private); 874 | if (wireguard_generate_public_key(dst->ephemeral, handshake->ephemeral_private)) { 875 | 876 | // Cr := Kdf1(Cr,Epubr) 877 | wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 878 | 879 | // msg.ephemeral := Epubr 880 | // Copied above when generated 881 | 882 | // Hr := Hash(Hr || msg.ephemeral) 883 | wireguard_mix_hash(handshake->hash, dst->ephemeral, WIREGUARD_PUBLIC_KEY_LEN); 884 | 885 | // Cr := Kdf1(Cr, DH(Eprivr, Epubi)) 886 | // Calculate DH(Eprivi,Spubr) 887 | wireguard_x25519(dh_calculation, handshake->ephemeral_private, handshake->remote_ephemeral); 888 | if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { 889 | wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); 890 | 891 | // Cr := Kdf1(Cr, DH(Eprivr, Spubi)) 892 | // Calculate DH(Eprivi,Spubr) 893 | wireguard_x25519(dh_calculation, handshake->ephemeral_private, peer->public_key); 894 | if (!crypto_equal(dh_calculation, zero_key, WIREGUARD_PUBLIC_KEY_LEN)) { 895 | wireguard_kdf1(handshake->chaining_key, handshake->chaining_key, dh_calculation, WIREGUARD_PUBLIC_KEY_LEN); 896 | 897 | // (Cr, t, k) := Kdf3(Cr, Q) 898 | wireguard_kdf3(handshake->chaining_key, tau, key, handshake->chaining_key, peer->preshared_key, WIREGUARD_SESSION_KEY_LEN); 899 | 900 | // Hr := Hash(Hr | t) 901 | wireguard_mix_hash(handshake->hash, tau, WIREGUARD_HASH_LEN); 902 | 903 | // msg.empty := AEAD(k, 0, E, Hr) 904 | wireguard_aead_encrypt(dst->enc_empty, NULL, 0, handshake->hash, WIREGUARD_HASH_LEN, 0, key); 905 | 906 | // Hr := Hash(Hr | msg.empty) 907 | wireguard_mix_hash(handshake->hash, dst->enc_empty, sizeof(dst->enc_empty)); 908 | 909 | dst->type = MESSAGE_HANDSHAKE_RESPONSE; 910 | dst->receiver = handshake->remote_index; 911 | dst->sender = wireguard_generate_unique_index(device); 912 | // Update handshake object too 913 | handshake->local_index = dst->sender; 914 | 915 | result = true; 916 | } else { 917 | // Bad x25519 918 | } 919 | } else { 920 | // Bad x25519 921 | } 922 | 923 | } else { 924 | // Failed to generate DH 925 | } 926 | } 927 | 928 | if (result) { 929 | // 5.4.4 Cookie MACs 930 | // msg.mac1 := Mac(Hash(Label-Mac1 || Spubm' ), msgA) 931 | // The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed 932 | wireguard_mac(dst->mac1, dst, (sizeof(struct message_handshake_response)-(2*WIREGUARD_COOKIE_LEN)), peer->label_mac1_key, WIREGUARD_SESSION_KEY_LEN); 933 | 934 | // if Lm = E or Lm ≥ 120: 935 | if ((peer->cookie_millis == 0) || wireguard_expired(peer->cookie_millis, COOKIE_SECRET_MAX_AGE)) { 936 | // msg.mac2 := 0 937 | crypto_zero(dst->mac2, WIREGUARD_COOKIE_LEN); 938 | } else { 939 | // msg.mac2 := Mac(Lm, msgB) 940 | wireguard_mac(dst->mac2, dst, (sizeof(struct message_handshake_response)-(WIREGUARD_COOKIE_LEN)), peer->cookie, WIREGUARD_COOKIE_LEN); 941 | } 942 | } 943 | 944 | crypto_zero(key, sizeof(key)); 945 | crypto_zero(dh_calculation, sizeof(dh_calculation)); 946 | crypto_zero(tau, sizeof(tau)); 947 | return result; 948 | } 949 | 950 | void wireguard_create_cookie_reply(struct wireguard_device *device, struct message_cookie_reply *dst, const uint8_t *mac1, uint32_t index, uint8_t *source_addr_port, size_t source_length) { 951 | uint8_t cookie[WIREGUARD_COOKIE_LEN]; 952 | crypto_zero(dst, sizeof(struct message_cookie_reply)); 953 | dst->type = MESSAGE_COOKIE_REPLY; 954 | dst->receiver = index; 955 | wireguard_random_bytes(dst->nonce, COOKIE_NONCE_LEN); 956 | generate_peer_cookie(device, cookie, source_addr_port, source_length); 957 | wireguard_xaead_encrypt(dst->enc_cookie, cookie, WIREGUARD_COOKIE_LEN, mac1, WIREGUARD_COOKIE_LEN, dst->nonce, device->label_cookie_key); 958 | } 959 | 960 | bool wireguard_peer_init(struct wireguard_device *device, struct wireguard_peer *peer, const uint8_t *public_key, const uint8_t *preshared_key) { 961 | // Clear out structure 962 | memset(peer, 0, sizeof(struct wireguard_peer)); 963 | 964 | if (device->valid) { 965 | // Copy across the public key into our peer structure 966 | memcpy(peer->public_key, public_key, WIREGUARD_PUBLIC_KEY_LEN); 967 | if (preshared_key) { 968 | memcpy(peer->preshared_key, preshared_key, WIREGUARD_SESSION_KEY_LEN); 969 | } else { 970 | crypto_zero(peer->preshared_key, WIREGUARD_SESSION_KEY_LEN); 971 | } 972 | 973 | if (wireguard_x25519(peer->public_key_dh, device->private_key, peer->public_key) == 0) { 974 | // Zero out handshake 975 | memset(&peer->handshake, 0, sizeof(struct wireguard_handshake)); 976 | peer->handshake.valid = false; 977 | 978 | // Zero out any cookie info - we haven't received one yet 979 | peer->cookie_millis = 0; 980 | memset(&peer->cookie, 0, WIREGUARD_COOKIE_LEN); 981 | 982 | // Precompute keys to deal with mac1/2 calculation 983 | wireguard_mac_key(peer->label_mac1_key, peer->public_key, LABEL_MAC1, sizeof(LABEL_MAC1)); 984 | wireguard_mac_key(peer->label_cookie_key, peer->public_key, LABEL_COOKIE, sizeof(LABEL_COOKIE)); 985 | 986 | peer->valid = true; 987 | } else { 988 | crypto_zero(peer->public_key_dh, WIREGUARD_PUBLIC_KEY_LEN); 989 | } 990 | } 991 | return peer->valid; 992 | } 993 | 994 | bool wireguard_device_init(struct wireguard_device *device, const uint8_t *private_key) { 995 | // Set the private key and calculate public key from it 996 | memcpy(device->private_key, private_key, WIREGUARD_PRIVATE_KEY_LEN); 997 | // Ensure private key is correctly "clamped" 998 | wireguard_clamp_private_key(device->private_key); 999 | device->valid = wireguard_generate_public_key(device->public_key, private_key); 1000 | if (device->valid) { 1001 | generate_cookie_secret(device); 1002 | // 5.4.4 Cookie MACs - The value Hash(Label-Mac1 || Spubm' ) above can be pre-computed. 1003 | wireguard_mac_key(device->label_mac1_key, device->public_key, LABEL_MAC1, sizeof(LABEL_MAC1)); 1004 | // 5.4.7 Under Load: Cookie Reply Message - The value Hash(Label-Cookie || Spubm) above can be pre-computed. 1005 | wireguard_mac_key(device->label_cookie_key, device->public_key, LABEL_COOKIE, sizeof(LABEL_COOKIE)); 1006 | 1007 | } else { 1008 | crypto_zero(device->private_key, WIREGUARD_PRIVATE_KEY_LEN); 1009 | } 1010 | return device->valid; 1011 | } 1012 | 1013 | void wireguard_encrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, struct wireguard_keypair *keypair) { 1014 | wireguard_aead_encrypt(dst, src, src_len, NULL, 0, keypair->sending_counter, keypair->sending_key); 1015 | keypair->sending_counter++; 1016 | } 1017 | 1018 | bool wireguard_decrypt_packet(uint8_t *dst, const uint8_t *src, size_t src_len, uint64_t counter, struct wireguard_keypair *keypair) { 1019 | return wireguard_aead_decrypt(dst, src, src_len, NULL, 0, counter, keypair->receiving_key); 1020 | } 1021 | 1022 | bool wireguard_base64_decode(const char *str, uint8_t *out, size_t *outlen) { 1023 | uint32_t accum = 0; // We accumulate upto four blocks of 6 bits into this to form 3 bytes output 1024 | uint8_t char_count = 0; // How many characters have we processed in this block 1025 | int byte_count = 3; // How many bytes are we expecting in current 4 char block 1026 | int len = 0; // result length in bytes 1027 | bool result = true; 1028 | uint8_t bits; 1029 | char c; 1030 | char *ptr; 1031 | int x; 1032 | size_t inlen; 1033 | 1034 | if (!str) { 1035 | return false; 1036 | } 1037 | 1038 | inlen = strlen(str); 1039 | 1040 | for (x = 0; x < inlen; x++) { 1041 | c = str[x]; 1042 | if (c == '=') { 1043 | // This is '=' padding at end of string - decrease the number of bytes to write 1044 | bits = 0; 1045 | byte_count--; 1046 | if (byte_count < 0) { 1047 | // Too much padding! 1048 | result = false; 1049 | break; 1050 | } 1051 | } else { 1052 | if (byte_count != 3) { 1053 | // Padding only allowed at end - this is a valid byte and we have already seen padding 1054 | result = false; 1055 | break; 1056 | } 1057 | ptr = strchr(base64_lookup, c); 1058 | if (ptr) { 1059 | bits = (uint8_t)((ptr - base64_lookup) & 0x3F); 1060 | } else { 1061 | // invalid character in input string 1062 | result = false; 1063 | break; 1064 | } 1065 | } 1066 | 1067 | accum = (accum << 6) | bits; 1068 | char_count++; 1069 | 1070 | if (char_count == 4) { 1071 | if (len + byte_count > *outlen) { 1072 | // Output buffer overflow 1073 | result = false; 1074 | break; 1075 | } 1076 | out[len++] = (uint8_t)((accum >> 16) & 0xFF); 1077 | if (byte_count > 1) { 1078 | out[len++] = (uint8_t)((accum >> 8) & 0xFF); 1079 | } 1080 | if (byte_count > 2) { 1081 | out[len++] = (uint8_t)(accum & 0xFF); 1082 | } 1083 | char_count = 0; 1084 | accum = 0; 1085 | } 1086 | } 1087 | if (char_count != 0) { 1088 | // We require padding to multiple of 3 input length - bytes are missing from output! 1089 | result = false; 1090 | } 1091 | *outlen = len; 1092 | return result; 1093 | } 1094 | 1095 | bool wireguard_base64_encode(const uint8_t *in, size_t inlen, char *out, size_t *outlen) { 1096 | bool result = false; 1097 | int read_offset = 0; 1098 | int write_offset = 0; 1099 | uint8_t byte1, byte2, byte3; 1100 | uint32_t tmp; 1101 | char c; 1102 | size_t len = 4 * ((inlen + 2) / 3); 1103 | int padding = (3 - (inlen % 3)); 1104 | if (padding > 2) padding = 0; 1105 | if (*outlen > len) { 1106 | 1107 | while (read_offset < inlen) { 1108 | // Read three bytes 1109 | byte1 = (read_offset < inlen) ? in[read_offset++] : 0; 1110 | byte2 = (read_offset < inlen) ? in[read_offset++] : 0; 1111 | byte3 = (read_offset < inlen) ? in[read_offset++] : 0; 1112 | // Turn into 24 bit intermediate 1113 | tmp = (byte1 << 16) | (byte2 << 8) | (byte3); 1114 | // Write out 4 characters each representing 6 bits of input 1115 | out[write_offset++] = base64_lookup[(tmp >> 18) & 0x3F]; 1116 | out[write_offset++] = base64_lookup[(tmp >> 12) & 0x3F]; 1117 | c = (write_offset < len - padding) ? base64_lookup[(tmp >> 6) & 0x3F] : '='; 1118 | out[write_offset++] = c; 1119 | c = (write_offset < len - padding) ? base64_lookup[(tmp) & 0x3F] : '='; 1120 | out[write_offset++] = c; 1121 | } 1122 | out[len] = '\0'; 1123 | *outlen = len; 1124 | result = true; 1125 | } else { 1126 | // Not enough data to put in base64 and null terminate 1127 | } 1128 | return result; 1129 | } 1130 | --------------------------------------------------------------------------------