Password Protection

Is there any way to make the opening screen password protected (Using a 3.5 enhanced screen) without using a control board?

Plenty of ways one could do that. Have the device start on page 0 with a text input and OK button. On OK, check text field for your desired password, then send the user to page 1 or whatever.

Just for fun I mocked up a quick and dirty example for you. Download the HMI here.

Here’s what that looks like:

t0 is our password field so I set pw to Password and key to full qwerty\keybdA.

b0 is the reset button. On the touch press event I have the following:

// Clear the password entry field
t0.txt=""
t2.txt=""

This clears any password entered from t0, then clears the password entry failure message in t2 (more on that below).

b1 is the Login button which has the following touch press event script:

// Check to see if the password is "12345"
if(t0.txt=="12345")
{
  page 2
}
// If we're still here, password was wrong so clear the text field
t0.txt=""
t2.txt="Login failed!\r Try again..."

First, we check to see if the password entered in t0 matches 12345. If so, we take the user to page 2. If not, we once again clear out the password entry field t0 and then display a “Login failed!” message to the user in t2.

Here’s what the demo looks like in action:

1 Like

Thank you ever so much. You ser are a star, just what im looking for.

I have downloaded the hmi file, everything works as you are showing but the Event box’s are all clear.
I know I will need to add the code to the box’s when I do my own design but why aint it there with your demo?

Sorry my bad I forgot to click on the buttons to high lite them

1 Like

Where may I find the keyboard that you used? of do I just make one? keybdA on the page list, how to create this?
Sorry for all the questions, i’m new to this

Thanks
Should make some time to play around in the software and see what all the settings do

If I want to reset the password then what can I do? When I reset my password it shows the message like password change successfully, but it does not accept the new password when I try again

Not a very secure password implementation.
Can be quickly skipped by simply sending ‘dp++’ over the serial line. At 57600 baud that’s password bypass in under 1 millisecond.

Also, your password is stored as static plain text (“12345”) so it can be pulled from the compiled HMI file and is unchangeable. If you switch to using a variable that can allow the password to be changed (non-static) then you can simply pull the password with “get password.txt” over serial.

Nextion is inherently insecure because you can always dump, patch, reupload its firmware. Applications that need software security against malicious serial activity simply cannot use Nextion.

So yes, you’re kinda right, it is “insecure” but it is likely good enough for a Nextion based solution.

Kind regards,
Max

I think you can make it decently secure if you get creative…

I put together a quick, “proof-of-concept” showing a pretty secure Nextion login PIN setup. Download links are below for 3.2" and 3.5" Enhanced .tft files.

The first time you run the new firmware, it will ask you to setup your 4-digit PIN code and will then restart. From this point on it will prompt for the user to enter a valid, matching 4-digit login PIN in order to move beyond the power-up security page. If the PIN is invalid you will get a message and the screen will restart after 5 seconds. If the PIN is valid then it move to a confirmation page that includes a yellow button which will allow setting a new login PIN.

No codes are stored as plain-text or in the firmware image(s) for security. The screen will also lock out any attempts to bypass the login PIN code screen through serial comms or other methods.

See what you think.

Download for Nextion 3.2" Enhanced

Download for Nextion 3.5" Enhanced

Edit: mimimi I’m an idiot
Reason for edit: see reply below.

Edit: mimimi I’m an idiot
Reason for deleting parts of the reply: see reply below.

Nonetheless I can describe the patch that should always work and enable serial commands. I simply run a search and replace in the TFT file for all occurences of com_stop and replace them by com_star. Next I replace all occurences of recmod by some unused variable. From there on I have serial access while the code still thinks it’s disabled. Any further periodic checks (f.ex. if nothing has been modified etc) can now be disabled by disabling all timers.
I cannot think of an effective way to harden a TFT file against this sort of patch.

Another idea: find out where the password has been stored and write a simple TFT file that reads that source and prints it to serial. Unless you implemented an actual cryptographic hash function this immediately gives you the password or the option to create a password that will be accepted. Even if it was hashed, it still allows you to brute force it on a decent computer.

Let me repeat: Nextion cannot be secured against malicious attackers that have access to Nextions serial lines. Such an attacker can always reflash the device with whatever he wants.
Also, if the attacker is able to desolder the flash chip he can easily dump the TFT file from it. The flash contains it without modifications. Alternatively, at least parts of the content can be dumped by sniffing the flash chip pins during operation (same is true for the EEPROM). Every address that’s read or written can be captured with a logic analyzer (or a small microcontroller with a microSD card as datalogger). I have successfully done this on my Nextion screen without desoldering the flash chip.

Regards,
Max

tl;dr: the added “security” of @ratnin s version is based on hashing the password and disabling the serial port. Hashing is usually the way to go for storing passwords but completely pointless here because a 4-digit code can always be brute forced no matter how good the hash is. And disabling the serial port… well I can’t see how that would be a sensible option for pretty much any Nextion application.
In other words: If a 4-digit code offers enough security for your application, @luma s version is perfectly fine!


long version with example files

Update, again. I completely forgot that the download links to almost all editor versions are available in the Nextion Forum. Idiot me. That finally allowed me to have a more thorough look at what @ratnin has written.

First of all, the use of appid to store the password is quite annoying because it totally breaks compatibility with the Nextion Editor (where appid is always zero) and that in turns means that only people with the particular screen you decided to compile it for can actually test it. It doesn’t really add any safety either (or does it?).

Anyways, here’s what @ratnin did:

  • Disable the serial interface using com_stop, recmod=1 and clearing the serial buffer u. Apparently under some condition it is also reenabled but I wasn’t bothered about finding out when.
  • User enters 4 digits which are stored as integer (code = code * 10 + 1 f.ex. - source)
  • Code is “hashed”. I haven’t analyzed the algorithm too much. I only verified that there are no collisions for any of the possible 0000 - 9999 codes. If you’re interested, here it is, copied straight from the decompiled TFT file. local:0x68 is the variable that contains the code the user entered.
    thc=local:0x68+0x146f
    thc=thc>>1
    thc--
    sys2=local:0x68<<1
    sys2=sys2+0x1012f8
    sys1=thc+sys2
    sys1=sys1>>1
    sys1+=3
    sys1=sys1^0x1b303b0b
    
  • This is used to store the code but also to verify if it matches the stored code (as one would expect)
  • If the “hashes” (I’m using quotes because I don’t know that algorithm actually qualifies as hash function) match, then the user is granted access to the unlocked page where he can set a new code.
  • If the “hashes” don’t match, there’s a delay of a few seconds and the thing resets to the page for entereing the code.

Possible attacks

I’ve tried and verified 3 different attacks. They’re all based on very simple search-and-replace modifications of the original TFT file and then flashing that file to the device. This is always possible if you have physical access to the serial port and/or the sd card slot. If using serial upload, it might not even take that long if Upload Protocol v1.2 is used.

Now some may say that requiring physical access and the option to reflash are rarely given, making it a pretty good solution. Not wrong, but physical access is required to break @luma s original “unsafe” implementation, too. Now think about what’s required for that sort of access (unscrewing a frontpanel f.ex.) and ask yourself if let’s say 10 more seconds for reflashing the thing would really make any difference in safety. If your answer is no, then just stick with @luma s version

Serial Access

TFT File
Decompiled Source

What makes this and the two attacks below so effective is that they’re hard to notice for a legitimate operator. Meaning, access can be established and potentially remain undetected for a long time.
Note: the other two attacks also contain this one, so you have serial access in all cases to play around with the file.

As described in my previous post, I replaced com_stop with com_star and recmod=1 with recmod=0. Serial access enabled. We can now send prints appid,0 and obtain the “hashed” password. Once again, with only 10k password to try, even a decent hash function wouldn’t offer any security.

Unlock with Any Code

TFT File
Decompiled Source

This one modifies the crucial check whether the “hashes” match such that it always acts as if the password was correct. This might be the easiest one to detect because even legit operators sometimes enter a wrong code.

Code stored unhashed

TFT File
Decompiled Source

The hash function is not really an obstacle in this case as described above. But let’s assume the user could enter a longer code and that the “hash” function was actually secure. Brute force may not be the best solution in that case.
Therefore this attack simply replaces

appid=hashed_code

with

appid=unhashed_code

(That’s of course pseudo-code, in the TFT file I actually replaced the pointers).

This of course only makes sense to do before a code is set or you need a good reason for resetting the code. But then it’s quite a severe vulnerability.

Conclusion

I hope these examples get across my point: the fact that you cannot secure Nextion against dumping and reflashing the firmware makes it inherently and unfixably unsafe. The only way to create a safe system is to restrict access to this unsafe device - both from the software side through the MCU connected to it as well as from the physical side.

That aside, as I said in the intro, even if we ignore the patching issue for a moment, the changes proposed here don’t add any security because the measures are either pointless (hashing a 4-digit code) or unpractical (disabling Nextions serial port).

Longer passwords with a secure hash function would add some security (though the patches above remain possible), but not every human-machine-interface needs a 16 digits alphanumeric upper, lower case and special characters password. 4 digit-codes are completely fine for many applications and in that case physical access and all the other things mentioned here don’t matter, really.

Finally… remember that TFTTool is a thing. Decompiling TFT files leads to quite readable files as you could see above. So if you got some super secret algorithm you might want to use something different than Nextion.

Kind regards,
Max

First off, this Nextion password protection code is just a simple example I put together for this specific post to show a reasonably secure login pin implementation. My company uses a Nextion display in a production product so I don’t want to post any of the specific security measures we implemented ourselves. In our product the pin code system is handled on both the MCU and Nextion side together. Our Nextion firmware is essentially “locked” to our displays only - it won’t operate on a Nextion screen that hasn’t come from us. The Nextion firmware image verifies that it’s installed on one of our displays and that it’s connected to one of our MCU’s. The MCU and it’s seperate firmware image does the same - verifying the Nextion’s source and firmware image along with several other installed semi components. I bunch of the components have unique hashes and keys allowing them all to authenticate themselves as well as the other components and all components have to pass authentication then generate there own one-time keys which are all hashed together in order to yield a valid unlock key for the device itself.

Regarding some of the points you listed:
Yes, the 4-digit PIN in the example could be brute forced. It’s only 4-digits. But it enforces a delay between pin code attempts (intentionally short in the sample) and any pin code attempts would need to be manually entered via the touchscreen because serial comms are locked down until verification. You could optionally insert short delays between entry of each digit to increase the time required to submit a new pin code attempt. A 10 second delay between digits would take almost 5 days to brute force the entire range of 4-digit pins.

Regarding usage of “appid”, I simply used it because I recently posted about it and it makes a good option - non-volatile, obscure, 32-bits, compatible with actual Nextion displays only (not the debug simulator), etc

Yes, the serial interface is disabled at boot up and is later re-enabled once the pin code entry has been validated. This is more secure and prevents attempts to bypass the pin code system over the serial connection.

In regards to “search and replace” and flashing the device over serial using the faster Upload Protocol v1.2 - it won’t work. Neither will the normal serial upload protocol. Serial flashing is disabled until pin code verification. The uploader will just hang up. This actually made building and testing the example firmware a real pain - it won’t run in the simulator (device only), any changes to the sample firmware can’t be uploaded over USB/serial and SD updates require copy files over to card, manually removing power from the display (‘rest’ command cannot be issued"), inserting the card, toggling power back on, waiting for the update to complete, breaking power again, removing the SD card and manually toggling the power back on the Nextion. That’s a bunch of disconnecting/reconnecting power, removing/inserting cards, etc to make a quick change to the code. It was so frustrating that I ended up adding a Yellow button in the bottom left corner of the pin code entry screen that would enable serial uploads for 5 seconds when pressed. I removed that asset when I completed testing out the sample code.

@luma’s implementation is unsecure because you can literally send “dp++” and jump right past it.

In regards to replacing “com_stop with com_star and recmod=1 with recmod=0…Serial access enabled”. I’ll go ahead and say that this method will not work on our more secure firmware used in our product. Why? Several reasons I’ll list -
recmod isn’t set with a constant (0 or 1) which is easily swapped out. It’s set with a calculation that includes several different variables including some system variables that have values that are hard to determine because they themselves where based off of previous calculations. So instead of constants you have calculates and pointers to multiple variables that themselves calculates based on pointers. Not as simple as swapping a 1 for a 0.
Another aspect I’ll mention, the com_stop, recmod=1 and all the stuff that disables serial connections is handled by a network of timers that continiously and automatically keep serials comms locked down for the duration of verification. Disabled timers are re-enabled by others automatically. The timer .en and .tim values are again based on calculations/outside variables rather than constants (no simple replacement). And lastly, the secure hash used to authorize the firmware/device actually uses the values of the timers, recmod, etc in the hash calculation itself. Basically, if you mess with any of them, you’ll generate invalid hashes. You can’t get a valid hash calculation without every one of the serial lock down components functioning as designed.

And finally, regarding the “appid=hashed_code to appid=unhashed_code” swap - I’m not going to going to detail our specific countermeasure to this in our product but it’s not a simple if/then/else == != type branching check. The checking process branches differently each time and is not pre-determined. One of the things utilized is a system of pages that each branch and redirect to other pages based on a hash calculation. So when it’s checking “keys” it bounces around between dozens of different pages that all make different calculations based to determine what page to redirect too. Think of each page as a branch that makes calculations based on hash values to determine where to proceed next. The page branching chain is tranversed differently every time through the use of PRNG values. If the pages are tranversed correctly each power up then you eventually end up at the “startup” page ready to run with serial comms enabled. Once again, the branches are traversed differently EVERY power up.

The simple work around to every bypass method of the example code you listed is to make assignments and branching checks based on calculations rather than constants and use the Nextions CRC features to verify that recmod, timers, values, etc have not been tampered with. Any attempts to modify any of these components will result in different (invalid) CRC calculations and prevent pin code verification.

A lot of effort your company put into this. I wonder if at the end you haven‘t spent more time trying to secure Nextion than Nextion saved you originally…

A few comments:
First of all, brute force was always meant to happen on a separate computer/device once the „hash“ has been extracted. For someone just using the touch interface the way it was meant to be used it‘s perfectly fine. As I said, 4 digit pin code is likely enough security for many applications but it makes hashing nonetheless pointless. Because by the time you get access to the hash, that hash doesn‘t offer any protection anymore.
An application that‘s fine with 4 digit security is likely not at all concerned about someone dumping the TFT file, analyzing it, finding out they can do dp=something, gaining physical access and doing a man-in-the-middle serial attack. And if this is actually a concern I still think that Nextion is the wrong product.

Secondly, you can check recmod as much as you want, if I run a search and replace, that doesn‘t change the value assigned to it but recmod itself, any checking code is defeated because it now checks some other variable. I did mention this attack previously btw.
Same thing for the timer.en variables. What if I replace all of them by something else?
You don‘t have secure code execution or pointer verification or whatever so you can‘t verify - once the firmware is flashed and runs - that the variable you wrote in the editor is the variable whose address is contained in the TFT file.
Edit: You can of course involve the MCU in these checks, too. But now effort is really skyrocketing and it’s still possible to defeat by a man-in-the-middle attack on the serial bus. Even if you’d go through the efforts of implementing certificates and public key cryptography, it’d still remain breakable because there’s no TPM or any sort of secure storage on Nextion. Meaning, an attacker could always dump the private key and do a man-in-the-middle attack anyways. Can’t say it often enough, there are chips and solutions out there that implement secure boot, signed firmware updates, etc in an actually secure way. Deploying some graphics library to those seems IMO like the way more sensible idea than using Nextion.

Lastly, the only thing that kinda saves you, is that I haven‘t been bothered adding more features to TFTTool. I‘m pretty sure you can reconstruct about 90% of the original HMI file - simply because of the interpreted nature of Nextion and the fact that no matter what you do or use, it‘s always meant to give you full control over all components at runtime.
The memory maps aren‘t random nor are the commands generated by the editor for various components. Meaning, variables as well as components could be reconstructed by TFTTool. Assuming serial access has been established, I have btw. already shared a tool that dumps all component properties over serial. It’s been used to analyze the NSPanel firmware. That was easier to do because you just write get b[i].type until you get an error.
I‘m not a fan of security by obscurity because it‘s a paradox in my eyes. If not seeing the code/what it does is essential to the security then you must be assuming that nobody wants to look at it (a.k.a. use something like TFTTool) - but if you assume there‘s nobody that would be willing to look at it, who are you securing it against? And, even more important, what if somebody looks at it anyways?

Kind regards,
Max

1 Like