Skip to content

Fix WiFi password corruption when a stored value cannot be decrypted - #481

Open
fermintm wants to merge 1 commit into
bmorcelli:mainfrom
fermintm:wifi-credential-fix
Open

fermintm wants to merge 1 commit into
bmorcelli:mainfrom
fermintm:wifi-credential-fix

Conversation

@fermintm

Copy link
Copy Markdown

Follow-up to #477, split out as requested: this PR only touches the WiFi credential handling in shared code (src/settings.cpp, src/settings.h, src/wifi_crypto.cpp, src/wifi_crypto.h). No board files, and the cipher itself is not changed.

The bug

wifiPwdDecrypt() returns its input unchanged when it cannot decrypt it:

  • not valid base64, or not a whole number of AES blocks, or
  • the PKCS7 padding byte is outside 1..16.

applySettingsFromRoot() (config.conf) and getWifiFromNVS() (NVS) took that return value as the plaintext password. The next saveConfigs() / saveWifiIntoNVS() then encrypted it again, so every boot wrapped another layer around a ciphertext nobody could read, and the real password was gone.

That happens whenever the stored value was written with a different WIFI_ENC_KEY: an SD card moved from another device, a config.conf copied between boards, or the key changing between releases. It is silent — the network stays in the list, looks saved, and only fails when connecting.

The fix

  • wifiPwdDecryptStored() reports whether the value was actually readable, and unwraps values that earlier builds encrypted more than once.
  • When a value is unreadable, the caller keeps a good password already loaded from config.conf (NVS no longer overwrites it with garbage); otherwise it stores the SSID with an empty password so it can be entered again.
  • saveConfigs() no longer seeds the myNetSSID/myNetPwd placeholder into an empty list. That placeholder showed up as a saved network and came back after every reset.
  • Duplicate SSIDs are collapsed when NVS is merged with config.conf, preferring the entry that still has a password.

Compatibility

The cipher is untouched: same AES-128-CBC, same WIFI_ENC_KEY, same IV, same base64 + PKCS7 format. Values written by this build, and readable by the old code, decrypt exactly as before. wifiPwdDecrypt() keeps its signature and its old behaviour for existing callers.

How it was observed

On an ESP32-P4 board with a config.conf/NVS carried over from a build using a different key, wifi list showed the same SSID twice plus myNetSSID, all with unreadable passwords, and wifi connect failed on the stored value. After the fix there is one entry per SSID with the real password, it survives reboots, and wifi connect succeeds.

wifiPwdDecrypt() returns the input unchanged when it cannot decrypt it (not base64, not whole AES blocks, or bad PKCS7 padding). applySettingsFromRoot() and getWifiFromNVS() treated that return value as a plaintext password, so saveConfigs()/saveWifiIntoNVS() encrypted the ciphertext again: every boot nested another layer and the real password was lost.

That happens when config.conf or NVS was written by a build with a different WIFI_ENC_KEY, which is normal when an SD card moves between devices or the key changes between releases.

wifiPwdDecryptStored() now reports whether the value was readable. When it was not, the caller keeps a good password already loaded from config.conf, or stores the SSID without one, instead of re-encrypting garbage. Values this build can read are handled exactly as before; the cipher, key, IV and stored format are unchanged.

Also stop seeding config.conf with the myNetSSID/myNetPwd placeholder, which showed up as a saved network and came back after every reset, and collapse duplicate SSIDs when NVS is merged with config.conf.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant