diff --git a/.gitignore b/.gitignore index e17e9a5..4c60841 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ .vscode/ipch include/WLAN_Logins.h +include/Crypto_Config.h diff --git a/README.md b/README.md index 8d2bb2c..1ac9059 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,7 @@ ## Setup notes -Copy `include/WLAN_Logins.h.example` to `include/WLAN_Logins.h` and modify as you need. +On the files below, remove the `.example` part of the name and adjust to your needs: + +- `include/WLAN_Logins.h.example` +- `include/Crypto_Config.h.example` diff --git a/include/WebServer.h b/include/WebServer.h index 8256050..63e3779 100644 --- a/include/WebServer.h +++ b/include/WebServer.h @@ -4,27 +4,30 @@ #include #include +#include "ChallengeResponse.h" + class Fader; -class HTTPServer +class WebServer { public: bool start(void); void setFader(Fader *fader) { m_fader = fader;} - static HTTPServer &instance(void) + static WebServer &instance(void) { - static HTTPServer theInstance; + static WebServer theInstance; return theInstance; } private: httpsserver::HTTPServer *m_server; + ChallengeResponse m_cr; Fader *m_fader; - HTTPServer(void); + WebServer(void); static void serverTask(void *arg); @@ -33,5 +36,8 @@ class HTTPServer // handlers static void handleRoot(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); static void handleColor(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); + static void handleChallenge(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); + static void handleAuthTest(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); + static void handleUpdate(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); static void handle404(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res); }; \ No newline at end of file diff --git a/scripts/authtest.py b/scripts/authtest.py new file mode 100755 index 0000000..3f9918e --- /dev/null +++ b/scripts/authtest.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +import requests +import sys +import hashlib +import time +import re + +IP = sys.argv[1] + +# read the salt from the header file +with open("../include/Crypto_Config.h", "r") as header: + for line in header: + if "SALT" in line: + mo = re.search(r'"(.*)"', line) + SALT = mo.groups()[0] + +print(f'SALT = "{SALT}"') + +# read and store the password from the user +pwd = input("Enter password: ") + +# request and parse a challenge from the server +challenge = requests.get(f"http://{IP}/challenge").json() + +nonce = int(challenge['nonce']) + +print(f"Nonce: {nonce}") + +# build response string +responsestr = pwd + ":" + str(nonce) + ":" + SALT + +m = hashlib.sha256() +m.update(responsestr.encode('utf-8')) +response = m.hexdigest() + +result = requests.get(f"http://{IP}/authtest", {"response": response}) +print(result.text) \ No newline at end of file diff --git a/src/WebServer.cpp b/src/WebServer.cpp index 8fc5354..e722ffc 100644 --- a/src/WebServer.cpp +++ b/src/WebServer.cpp @@ -1,18 +1,21 @@ /* HTTP Server setup and handler functions */ #include +#include -#include "HTTPServer.h" +#include "WebServer.h" + +#include "Crypto_Config.h" #include "Fader.h" -HTTPServer::HTTPServer(void) - : m_fader(NULL) +WebServer::WebServer(void) + : m_cr(crypto::HTTP_PASSWORD), m_fader(NULL) { m_server = new httpsserver::HTTPServer(); } -void HTTPServer::serveFile(String filename, httpsserver::HTTPResponse *res) +void WebServer::serveFile(String filename, httpsserver::HTTPResponse *res) { uint8_t buf[1024]; File f = SPIFFS.open(filename.c_str(), "r"); @@ -30,7 +33,7 @@ void HTTPServer::serveFile(String filename, httpsserver::HTTPResponse *res) f.close(); } -void HTTPServer::handleRoot(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) +void WebServer::handleRoot(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) { serveFile("/index.html", res); res->setHeader("Content-Type", "text/html"); @@ -44,7 +47,7 @@ static void error400(httpsserver::HTTPResponse *res, const std::string &reason) res->setStatusCode(400); } -void HTTPServer::handleColor(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) +void WebServer::handleColor(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) { res->setHeader("Content-Type", "text/plain"); @@ -94,10 +97,84 @@ void HTTPServer::handleColor(httpsserver::HTTPRequest *req, httpsserver::HTTPRes res->print(" w:"); res->println(w); - HTTPServer::instance().m_fader->fade_color({r,g,b,w}); + WebServer::instance().m_fader->fade_color({r,g,b,w}); } -void HTTPServer::handle404(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) +void WebServer::handleUpdate(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) +{ + res->setHeader("Content-Type", "text/plain"); + + httpsserver::ResourceParameters * params = req->getParams(); + + if(!params->isRequestParameterSet("content")) { + error400(res, "Send update image as 'content'."); + } + + res->print("Content length: "); + res->println(req->getContentLength()); + + res->println("Content:"); + res->println("--------------------------------------------------------------------------------"); + + uint8_t buf[128]; + while(!req->requestComplete()) { + size_t bytes_processed = req->readBytes(buf, 128); + res->write(buf, bytes_processed); + } + res->println("--------------------------------------------------------------------------------"); + + std::vector d; + d.push_back(1); + d.push_back(2); + d.push_back(3); + + uint8_t sha256sum[32]; + mbedtls_sha256_ret(d.data(), d.size(), sha256sum, 0); + + for(size_t i = 0; i < 32; i++) { + static const char *conv = "0123456789abcdef"; + + uint8_t b = sha256sum[i]; + + res->print(conv[(b >> 4)]); + res->print(conv[(b &0x0F)]); + } + + res->println(); +} + +void WebServer::handleChallenge(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) +{ + res->setHeader("Content-Type", "application/json"); + + std::ostringstream responseBuilder; + responseBuilder << "{ \"nonce\": " << WebServer::instance().m_cr.nonce() << "}"; + + res->println(responseBuilder.str().c_str()); +} + +void WebServer::handleAuthTest(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) +{ + res->setHeader("Content-Type", "text/plain"); + + httpsserver::ResourceParameters * params = req->getParams(); + + if(!params->isRequestParameterSet("response")) { + error400(res, "Parameter 'response' not set."); + return; + } + + std::string response = params->getRequestParameter("response"); + bool result = WebServer::instance().m_cr.verify(response); + + if(result) { + res->println("Authentication test successful!"); + } else { + res->println("Authentication test failed (invalid response)"); + } +} + +void WebServer::handle404(httpsserver::HTTPRequest *req, httpsserver::HTTPResponse *res) { req->discardRequestBody(); @@ -107,19 +184,28 @@ void HTTPServer::handle404(httpsserver::HTTPRequest *req, httpsserver::HTTPRespo res->println("Error 404: Not found"); } -void HTTPServer::serverTask(void *arg) +void WebServer::serverTask(void *arg) { httpsserver::ResourceNode *nodeRoot = new httpsserver::ResourceNode("/", "GET", - HTTPServer::handleRoot); + WebServer::handleRoot); httpsserver::ResourceNode *nodeColor = new httpsserver::ResourceNode("/color", "GET", - HTTPServer::handleColor); + WebServer::handleColor); + httpsserver::ResourceNode *nodeUpdate = new httpsserver::ResourceNode("/update", "POST", + WebServer::handleUpdate); + httpsserver::ResourceNode *nodeChallenge = new httpsserver::ResourceNode("/challenge", "GET", + WebServer::handleChallenge); + httpsserver::ResourceNode *nodeAuthTest = new httpsserver::ResourceNode("/authtest", "GET", + WebServer::handleAuthTest); httpsserver::ResourceNode *node404 = new httpsserver::ResourceNode("", "GET", - HTTPServer::handle404); + WebServer::handle404); - HTTPServer &server = HTTPServer::instance(); + WebServer &server = WebServer::instance(); server.m_server->registerNode(nodeRoot); server.m_server->registerNode(nodeColor); + server.m_server->registerNode(nodeUpdate); + server.m_server->registerNode(nodeChallenge); + server.m_server->registerNode(nodeAuthTest); server.m_server->setDefaultNode(node404); Serial.println("[server] Starting HTTP Server..."); @@ -137,10 +223,10 @@ void HTTPServer::serverTask(void *arg) Serial.println("[server] Server died?! This should never happen."); } -bool HTTPServer::start(void) +bool WebServer::start(void) { xTaskCreate( - HTTPServer::serverTask, /* Task function. */ + WebServer::serverTask, /* Task function. */ "HTTP Server Task", /* name of task. */ 6144, /* Stack size of task */ NULL, /* parameter of the task */ diff --git a/src/main.cpp b/src/main.cpp index efe0889..96ae08a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,7 +6,7 @@ #include #include "WLAN_Logins.h" -#include "HTTPServer.h" +#include "WebServer.h" #include "Fader.h" #include "UDPProto.h" @@ -223,8 +223,8 @@ void setup() udpProto.start(2703); // start the web server - HTTPServer::instance().setFader(&ledFader); - HTTPServer::instance().start(); + WebServer::instance().setFader(&ledFader); + WebServer::instance().start(); } void loop() {