I’m trying to write a secure authentication method that’s going to be deployed on an embedded system. Once the system is deployed I won’t be able to do any additional programming on site. I won’t be able to change its stored secret password either. Users of the system will walk up to the terminal wherever it’s been placed and authenticate themselves. Who the users are won’t be known ahead of time before the system is deployed.
If I choose some well known hashing algorithm, such as MD5 or SHA, will this method of authenticating users work securely:
Concatenate the user’s name + date + a short string message (which is actually the command the user will be allowed to give to the system) + the sekrit password, and run it through the hashing algorithm to get a hashed string. Tell the user what date they’ll be allowed to use the terminal and the short string message and the hashed string, but keep the secret password to myself, the owner of the system.
Then the user will take that info they’ve been given, travel to the terminal and enter it. So then the deployed terminal will do the same calculation I did back at home base and check the resulting hash against the hash the user entered, and if it matches, everything’s good. Perform the command that’s in the message string. If not, try again, user, but only a few more times before the system says “I won’t let you try this hash any more today.”
I don’t want to have to care whether the user keeps the info they’ve been given secure. If somebody else grabs that paper the user wrote the data on and uses it at the terminal, great! The command will be executed in the user’s name anyway, which is what we wanted to happen. Once a command is accepted with a given hash, that hash will be stored for the rest of the calendar day and not be allowed to execute again.
Is this good enough to keep the secret password secure from prying eyes and prevent people who have observed many such messages with the same password from generating their own falsely authenticated messages? Will I need to use any salt? I thought adding the date might serve as a salt method, but I’m not sure.
I read that MD5 is a really poor choice of algorithm these days, but I don’t understand in which contexts it fails. I’d prefer to use MD5 because I happen to already have the source for an MD5 function in my language of choice available. I haven’t yet found any other hashing algorithm written in this language and I might have to do one from scratch, but I’m trying to avoid needing to do that work. I will if people here tell me MD5 is no good for this and can be easily broken.
I’m being a bit coy on the language and other details of how this system will be deployed because I do not want anybody to google and find this thread. I know, that’s “security through obscurity” but I’m also attempting to keep my Ponderoid online identity separate too.
If so the answer is no. No system is unhackable and a system you cannot change once in place is a good target for hackers (assuming there is something worth getting). Once they figure it out they can get in forever.
At the end of the day security is a trade-off between ease of use and…well…security.
You need to talk to the client and determine what is best for this particular application. If you are not protecting a lot of money or valuable secrets it is not hard to make security sufficient to make most hackers give you a pass. If you are protecting something of high value you need to work a lot harder at it.
To be clear, you at Home Base will know, when the time comes, what commands need to be entered when, but you don’t know which commands will be needed at the time you install the device. Is that correct?
And you want the right commands to be executed at the right time, but you don’t care who executes those commands (so, for instance, the device won’t respond to a command by outputting sensitive data to them). Is it possible to get a failure if the device is issued the same command multiple times in one day (when it was only supposed to be issued that command once)? What if a command is issued on the right date, but at the wrong time? What if a command that is supposed to be issued is never issued?
And of course, you don’t want anyone to ever be able to execute a command that you don’t want them to execute, or on a date you don’t want them to do it.
It seems to me that a failure can occur whenever anyone can predict the hash that will result from a given command being issued at a given time. One way to do this would be to determine the secret password. In principle, this could be brute-forced, but if you make the password sufficiently long and random (which is entirely practical, since no human ever needs to memorize it), this will be too difficult to worry about.
Does the system have a pre-installed list of authorized users, or does it recognize usernames only as part of the hashing protocol? If the latter, then an attacker could either brute-force the hash by changing the username on each attempt (if the daily limit is per-user), or prevent the legitimate user from being able to access the system by using up the attempts before the legitimate user gets there.
MD5 is pretty old and I’m told that it can be broken too easily to be considered adequate these days. I would try to find a SHA-1 alternative. Using a salt is a good idea. Generate some random 4 digit number and use that as a salt. The remote system will need to try all 10000 possibilities to recreate the salt. That is the main advantage of the salt, it increases the computations needed to do stuff. The other advantage, that identical inputs will probably generate different outputs, probably won’t help here.
I think your proposed system is reasonably secure.
I am actually working a somewhat related project - not as convoluted (I only need to verify that a password is valid, but I need to protect against replay attacks), but similar in principle.
The issue I see is the hash length - are you going to ask the user to key in some long, random string of characters? That’s going to be a huge source of frustration.
Can you not cryptographically sign the input? For example, something like the digital signature possible with PGP, where you have the secret key to sign the command, and the remote device has the public key to verify that you signed it. The benefits of this approach is that even if one device is completely compromised, an adversary will not be able to issue valid inputs to other devices.
You are basically recreating Time based one-time password scheme. Take a look at the references for the Wikipedia article. There are probably open source libraries to help you with this.
Thanks, everybody, for these well thought out responses. They are much appreciated.
This would be… unfortunate. If a hacker cracks the password and then starts entering validated commands they generated themselves, the most likely scenario is they will end up bricking the terminal intentionally or unintentionally. Too many otherwise-valid commands over the course of a single day is almost guaranteed to brick it. Perhaps I will ensure that happens in code, after it performs one final fail-safe stored command. The planned lifespan of this system is probably on the order of 30 days on site, perhaps a lot less. After the final purpose of the machine has been achieved on site, the current plan is to have the terminal brick itself. The program may or may not be installed again at a different site at a later time but if it gets reused the password can be changed at that time.
Correct.
Correct.
Yes. That’s why I want to store the hashes of completed commands and disallow them to be executed again once accepted. But the terminal has only so much memory I’m allowed to use; I want to limit how many used hashes it needs to store. Thus the idea that the valid-on date would be part of the hash and the system would automatically purge that part of the RAM daily.
How critical the actual timing is the user’s call. Under most circumstances, I expect the user will be wanting to enter that command ASAP after I generate it for them. I expect most times I’ll be on the phone or in skype with them and I’ll paste or email the command and hash to them while they’re standing at the terminal or shortly before they go there. The terminal will never be connected to any network; it won’t even have the hardware necessary.
Then the user who wanted it executed will have to come back to me for a new valid hash.
I definitely don’t want them to execute commands I didn’t authorize. The date part is not so critical. I came up with the date thing both as a way of limiting how much memory the authentication system would use, and also as a way of adding a bit of salt. I’ve read about rainbow tables and I think I understand how salting works against them, even when using known salt. At the time I issue the command for the user, I’ll know whether or not having it execute on that date will be important. Most of the time, I expect it won’t be, but sometimes it might.
I know who some of the intended authorized users will be now, but more are expected to be added after the system has been deployed. So the plan is to have the hashing validate the usernames.
Here you’ve brought up an issue I did not think of at all. Thank you. Perhaps there should be no limit on number of attempts, and instead the limit how fast the terminal will accept attempts? Say, if the user can only try once per minute, that’s 1440 tries they’ll get per day, period. If a legit user comes along while somebody is standing there trying to brute force the terminal, that will almost certainly end that [censored]'s attempts, but I can’t count on that happening. I can make the terminal sound a loud alarm if there are too many failed attempts, but I know most of the time there will be nobody within range to hear.
What it’s for… I can’t exactly say without entering enough info that somebody clever at googling could connect my Ponderoid identity with my workplace, sorry.
I hadn’t heard of Google Authenticator so I went and looked that up. From there I found links to time-based one-time password algorithms and hash-based message authentication codes. It seems my plan I’ve synthesized from my reading about hashes and crypto is much simpler than these, but more or less the same ideas. I’ll definitely have to do a close reading about two-pass hashes to see if that makes sense for my current application. Thanks.
Yes, it might be. Perhaps I might add some sort of error correcting code on top of the hash itself? I don’t know if I’ll get enough coding time to throw that in there… or if it will fit in the embedded authenticator’s memory once written.
I’ve been looking for sourcecode for any other hashing besides MD5, but haven’t found it yet. I’m limited in which language I can compile for this embedded hardware. If I have to sit down and implement some flavor of SHA in this language, I will, but that will involve a lot of brain sweat in actually understanding the algorithm well enough to code it. I’m a bit lazy.
I’ll have to test to see how long it takes to run the hash 10000 times on the embedded hardware. If it finishes in under a minute while the CPU is under load from other sources besides the authenticator, that will probably be acceptable. If that sounds like pitiful hardware performance… You’re right. It’s something we have to deal with though. Oh yeah, this embedded system will be doing other tasks almost nonstop besides just sitting there waiting for special authenticated commands from the terminal.
When a user who has been authenticated via other means comes to me or calls me and needs a command executed, I’ll use my desktop computer to generate a hash which includes their name. The embedded system will assume that any valid hash came from an authorized user. The authentication part of the system will store that hash for a limited time before it purges it to make room. The part of the system that will actually perform the validated command has a lot more room to store their name and the text of the command they wanted executed. Some day before the planned bricking somebody might look at those logs. Hopefully nothing will ever happen that makes that necessary. My job here is to reduce that possibility to almost nil if I can.
I swear I previewed before I posted… Pleonast’s and gazpacho’s posts weren’t showing.
I don’t have the source for PGP or any other public key cryptosystem available in this language. As it is, isn’t the hash I’m doing indeed a form of cryptographic signature? Just using the same secret key on both ends? If this system is ever deployed anywhere else, we will definitely use a different secret key each time.
This will depend entirely on your use-case, but f you want to make the process less annoying for users (typing long codes into an embedded keyboard is never fun) then maybe consider alternative methods of input?
If the device in question has a webcam, or can support one as an add-on module, then I’d maybe consider encoding the hash as a QR code and sending it to the users phone; have them hold the screen up to the webcam so your software can decode the hash. I’ve seen that work well in other applications which would otherwise require the user to input a long, awkward string of characters.
Of course that might be overkill if there aren’t many users or if ease-of-use is a low priority.
First, concerning salt characters, keep in mind that they don’t have to be together in the phrase. If you parse them into the command at positions 1,3,5,9 that will exponentially increase the number of attempts that will have to be made for each one since your attacker presumably won’t know the positions in addition to not knowing the salt or it’s length.
Second. How likely is it that someone will be motivated to compromise the system? Are you putting a bank vault door on the refrigerator?
Is it internet connected? SAML federation is the current best practice, but you will still need to expire the local keys at some point.
Look into how U2F does assertions, but as you are giving people physical access to the machine it will be at risk.
If security is a concern, having a way to roll credentials is the primary design choice I would make first, there are just too many attack surfaces to ensure any form of lasting security.
What CPU/MCU and what language are you using?
This doc is a few years old but fairly comprehensive and may help, but you probably don’t want to write your own, but use an existing library.
Always assume that an attacker knows everything about your method except for the secret keys, because everything that isn’t a secret key isn’t a secret key.
but not by much. And the final nail in that coffin is that no additional hardware has been authorized in the budget for this project. Not gonna happen. I woudn’t be surprised to find the necessary program to decode a QR code won’t fit in the available RAM either.
I’m concerned that the time domains that protocol is designed for might turn out to be way too short. I have to plan for a significant fraction of a day passing in between issuing a valid command and the user entering it. Also, I’m not sure if the protocol will support authentication of the command along with the time domain. Is this demonstrably more secure than just including the 8 digits of an ISO date in the hash?
There’s definitely no sourcecode for that already written in our language, so I’d have to port something. Our language is C-like, but with some maddening differences that can trip experienced C-coders up. The code has to compile to sufficiently small footprint to fit in the limited available RAM, along with whatever variables it uses when executing.
I’d say it’s something more akin to putting a bank vault door on the cash register or tip jar at a restaurant. I think the chances are fairly good a few users will be tempted to want to alter the issued commands to make the machine do something I didn’t authorize. The motives will be there. They might be willing to stand there for a long time entering commands and hashes hoping to find one that works.
That link didn’t work for me. I think I covered your other points elsewhere in this thread. The machine will have no internet connection, there will be no opportunity to change the secret key once deployed, and no additional hardware will be purchased. Also, I can’t assume all users will have a smartphone.
Darned skippy. Some of the authorized users will have access to the source code for this program.
The Initiative for Open Authentication has published both time- and counter-based one-time-password algorithms. The time-based version simply generates a counter value based on the current time, so you could tweak things so that a token is only valid for whatever period of time you want.
The 6- or 8- or however-many-digit password is ultimately derived from a hash-based message authentication code, so by adapting the algorithm I do not see why you could not authenticate any type of message in addition to a bare counter value.
Have you considered using public-key encryption? It’s more complicated to program, but certainly more secure.
If I’ve understood correctly, the weak point of your current method is that the secret key has to be kept both in the embedded system and externally to generate access keys. If that key is ever compromised, it’s game over. It can’t be changed.
However, if you have a private key embedded in the system, and a public key in the access generator, then you will avoid this vulnerability.
There is just a pad-file that is n-bytes long. You want to give a command? XOR the command with the pad-file.
So the data flow is <command + CRC-32> XOR <pad-bytes> = command, increment pad-pointer.
Command processor : if entered string is less than remaining bytes of the pad and command < max command length, XOR those bytes of the pad file with the command. Check against the CRC-32 to make sure the command came through correctly. If the CRC-32 passes, execute the command.
If you want to log the user’s name, have that in the encrypted message - just make sure you length check!
I’m an embedded systems engineer myself and I would do it this way unless I didn’t have enough space on the target.
Reasons : this algorithm is simple enough that I would have some hope that it would work reliably. And one-time-pad is completely uncrackable, so you don’t have to be concerned about using some really complex algorithm with nonces and sessions keys and all that tricky stuff (and then screw up in implementation and end up with a wide open system).
These days, the lowest end embedded flashes you could possibly put into a device are multiple megabytes, so it’s not like pad-file space is a problem. And I bet the device you are using, if it has a display and an input terminal, it probably uses an SD card reader which means you can trivially have multiple gigabytes of storage space.
On your end, just use a python script to generate the pad file using an RNG seeded from the Unix time when the script was run. Easy peasy. Same script would let you generate these commands.