0

Background information:

I am not a computer scientist. However, in a research project I am currently building a ESP32-based sensor. Multiple sensors of this type are going to be used by multiple users.

Every time a user wants to utilize a sensor, the sensor needs to get the WiFi credentials of this specific user so that the ESP32 can connect to the WiFi (for publishing the sensor data in a dashboard). In order to deliver these WiFi credentials, the ESP32 will be set up as a WiFi access point (AP) during configuration phase. Each user shall be able to use his/her smartphone to connect to the ESP, which runs a small HTTP server and delivers a login form to the user's smartphone. After entering the credentials, they are sent via HTTP to the ESP32, which then can use this to login to the WiFi of my institute. Obviously, transferring the WiFi credentials via HTTP is not safe and, thus, they need to be encrypted.

Although it would be possible with a few workarounds, I don't want to use HTTPS for the communication between smartphone and ESP32, since it seems to involve a lot of implementation inconveniences. I also don't want to use a separate smartphone app, but want to stay with the browser-based approach, if possible.

The idea:

I found the following blog post which demonstrate how one can achieve a Curve25519-based Diffie-Hellman (DH) key exchange between a Node-JS Server and an ESP8266. Additionally, I stumbled across WebCrypto yesterday. This led me to the following idea:

My ESP32 might deliver a WebCrypto code together with the login form, which it sends to the user's smartphone. Since WebCrypto seems to be supported by most of the modern smartphone browsers, the smartphone could locally generate a key pair via WebCrypto. The ESP32 could generate it's own key pair via the Crypto library mentioned in the link. Then both devices can do a Diffie-Hellman key exchange, the smartphone can encrypt the WiFi password, sent it to the ESP32, which can then decrypt it and use it.

Questions:

I have absolutely no experience with encryption, coding Diffie-Hellman key exchange, or using WebCrypto. Obviously, there is a lot that can be implemented in a wrong way and cause a false security feeling. Furthermore, WebCrypto seems to have no implementation of Curve25519. Therefore, I have a few questions:

  1. Is there a simpler approach to achieve a secure WiFi credential transfer from the smartphone to the ESP32?

  2. Is the proposed idea realistic and safe?

  3. What are the biggest security pitfalls which I need to consider during implementation of this idea?

  4. If you have experience with WebCrypto, what alternatives to the Curve25519 key generation would be the best?

  5. At the end of the aforementioned link, the author mentioned that ensuring device identity is a problem which is not solved in their example. What does that mean?

reg.cs
  • 101
  • The Web Crypto API does not support EC Curve25519. However, EC P256 is supported, which is probably fine for your application. Notwithstanding, WRT, "*I don't want to use HTTPS for the communication between smartphone and ESP32, since it seems to involve a lot of implementation inconveniences*" - I think what you are trying to do is going to involve a lot more implementation inconveniences. HTTPS is designed specifically for what you are trying to do (transfer information securely between a client and a server, with secrecy, integrity and authentication). Why reinvent the wheel? – mti2935 Apr 18 '21 at 14:47
  • Thanks for the hint to EC P256, I will look it up! The problem with HTTPS is all the handling of the certificates on a local area network without internet access (i.e., the connection between smartphone and ESP32). While it is possible to do that, handling and keeping the certificates up to date on multiple sensors manually seems a bit too time-consuming. A flexible key generation may take some time during implementation, but then I don't need to touch the system again. – reg.cs Apr 18 '21 at 14:53
  • OP, i understand. But, you are going to have the same problem if you build this from scratch with the web crypto API, because your client must have some way to authenticate that the public key that it receives from the server is authentic. The client can not just accept the public key on blind faith, otherwise this opens the door to a man-in-the-middle (MITM) attack. This is why *authenticity* is important. See https://security.stackexchange.com/questions/248175/self-signed-certificates-with-ssl/248186?noredirect=1#comment510419_248186 for more info and possible solutions. – mti2935 Apr 18 '21 at 15:02
  • You might want to consider creating a self-signed certificate for the server, with a very long expiration date (e.g. 50 years), and pinning this certificate on the client. This way, you can use tried and true HTTPS (instead of reinventing the wheel), your client authenticates the server (as it should in any secure system) using the pinned cert, and you don't have to worry about updating certificates (until 2071). – mti2935 Apr 18 '21 at 15:06
  • Ok, that seems to be connected to question (3) and (5) of my post. I understand that my approach is lacking the _authenticity_. But if I use a self-signed certificate and ask the user to dismiss the browser warning popping up, how does that prevent a MITM attack? I mean, couldn't the MITM also deliver a self-signed certificate to the client without the user noticing it? Or worse ... since the sensor/ESP32 containing the certificate could fall into the hands of an attacker, couldn't one extract the certificate? – reg.cs Apr 18 '21 at 15:20
  • The user would have to accept the cert the first time they connect, then the browser will recognize it automatically every time after that. So, it's trust on first use (TOFU), which is similar to how SSH works. If the cert changes (e.g. because of a MITM) attack, the browser will notice it, and warn the user. The problem with serving js crypto code over (unencrypted) HTTP is - what prevents an MITM from modifying the crypto code? – mti2935 Apr 18 '21 at 15:39
  • Ok, I see. Maybe a general question: We are talking about a local WiFi connection between a smartphone and a ESP32. The user first connects to the ESP32 WiFi (access point), then directly inputs the IP address of the ESP32 into their browser ... Can a MITM attack actually happen? – reg.cs Apr 18 '21 at 16:15
  • I'm not familiar with the ESP32 to answer in specific terms. But, generally speaking, if there are other devices connected to the same WiFi access point, it may be possible for one of these devices to pull off a MITM attack by way of an ARP spoofing attack or the like. But, I think I know where you are going with this. Maybe you are satisfied with a solution that protects the information from a passive eavesdropper, but not an active MITM attacker. If that's the case, a solution involving the Web Crypto API over (uinencrypted) HTTP might work for your use case. – mti2935 Apr 18 '21 at 18:29
  • Yeah, I was thinking exactly about that. Maybe I could restrict the access point to allow not more than one connection at a time (if that is possible). Another option I thought about was to attach a display to the ESP, generate a random password at runtime, display that on the display and ask the user to enter both his WiFi credentials and the displayed password. Anyway, have to think about that. Thanks for your helpful input, @mti2935! – reg.cs Apr 18 '21 at 20:28
  • Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/123123/discussion-between-mti2935-and-reg-cs). – mti2935 Apr 18 '21 at 20:29
  • Q: do you control the build of the ESP32? Have you considered storing a private key on it? eg. You may be able to use *Libsodium* (x25519 ECDH) .. from https://libsodium.gitbook.io/doc/public-key_cryptography/sealed_boxes: *"**Purpose:** Sealed boxes are designed to anonymously send messages to a recipient given its public key. Only the recipient can decrypt these messages, using its private key."* I don't know specifically if ESP32 supports *Libsodium* .. [maybe](https://hackaday.com/2019/01/03/compiling-nodemcu-for-the-esp32-with-support-for-public-private-key-encryption/)? – brynk Apr 19 '21 at 09:20
  • To clarify, your user would provide the encrypted credentials for the IoT device using some mechanism other than a web-page delivered by the device: rather, the device would provide a HTTP endpoint to which the user would `POST` their wifi credentials for use. Some other application running on the user's phone or computer would generate the encrypted payload, connect to the adhoc/ wifi-direct network, connect to the known end-point via the device's HTTP server, then deliver the encrypted payload that only the device would be able to decrypt (since it holds the private key). – brynk Apr 19 '21 at 09:41
  • @brynk, thanks four your comments! I am new to all this, so could you confirm that I understand this correctly: The ESP32 generates a public-private key pair during runtime, then sends the public key to the user's smartphone, which encrypts the user's WiFi credentials and sends it back to the ESP32? If that is correct, wouldn't that allow the man-in-the-middle attack again? Someone could fake itself as the access point, provide it's own public key, and then obtain the WiFi credentials of the user? – reg.cs Apr 19 '21 at 09:48
  • Yes if the device sends the public key to the client, however, since you've created the private key already and stored it on the IoT device, instead, your public key gets placed in a register "somewhere" for the client to find (probably on a secure website that the client can access). So instead of relying on the sensor to prove itself to your user, your user relies on a 3rd party server to obtain the corresponding public key for the device. (more comments to follow...) – brynk Apr 19 '21 at 09:53
  • Now your user can obtain the public key from the register, encrypt the payload using `crypto_sealed_box`, and then `POST` the payload to the device. The device will detect this and then use these cred's to connect to the wifi access-point. – brynk Apr 19 '21 at 09:54
  • Now that I think about it, you could even meet your earlier vision of providing the code to perform the encryption via the browser, using [*sodium.js*](https://github.com/jedisct1/libsodium.js/blob/master/dist/browsers/sodium.js) - though one downside I think is that (most?) modern browsers won't deliver a payload using XHR to a HTTP server after interacting with a HTTPS webpage – brynk Apr 19 '21 at 09:57
  • Unfortunately, I think that does not simplify things: The additional register would need to be managed. And I guess, one problem will also be that the smartphone will have no internet access during it is connected to the WiFi access point of the ESP32. So the user would have to do additional steps (first connect to internet, ask a server for the public key, connect to the ESP32 Wifi, post the key. – reg.cs Apr 19 '21 at 11:20
  • Yes I'm sure you're right! I'm envisiging your workflow as being something like: user signs takes "ownership" of device containing sensor, configures it to use enterprise wifi under their identity, and then carries it around with them to measure "how noisy it is"/ "how much ammonia vapour am I breathing" etc. There is a product called the *Wesp32* that includes an ethernet/ RJ45 jack, as well as bluetooth and wifi drivers. I'm sure there are others. Something like this might at least increase your options for provisioning? eg. a "kiosk" where the labra *participant* signs up! – brynk Apr 19 '21 at 22:24
  • Wow, the Wesp32 looks really interesting. Thanks for pointing me to that device! For my current use case, however, it would only shift the issue from phone to Wesp32. But based on your suggestions and another discussion with mti2935, I came to the conclusion, that the most simple and reasonable approach might be: Generate a fixed public-private key pair, encode the public key as a QR code, attach it to the device and store the private key on an encrypted ESP32. Then the user scans the code with the smartphone to obtain the public key for encryption of the wifi credentials. What do you think? – reg.cs Apr 20 '21 at 07:23

0 Answers0