How to protect against repeated attacks
I am trying to figure out a way to implement a decent cryptogram in a microcontroller project. I have an ARMv4 based MCU that will control my garage door and receive commands via the WiFi module.
The MCU will run a TCP / IP server that will listen for commands from Android clients that can connect from anywhere on the internet, so I need to implement crypto.
I understand how to use AES with a shared secret to encrypt traffic properly, but I am having a hard time dealing with Replay Attacks. All of the solutions I see so far have serious flaws.
There are two main problems that prevent me from using established methods such as session tokens, timestamps, or numbers:
-
The MCU has no reliable source of entropy, so I cannot generate quality random numbers.
-
The attacker can reset the MCU by cutting off the power in the garage, thus erasing any saved state at will and resetting the time counter to zero (or just wait 49 days for it to complete).
Given these limitations, I only see one approach that seems fine to me (i.e. I don't see how to break this). Unfortunately, this requires non-volatile storage, which means recording to an external flash, which is a major challenge due to various technical details.
I would like some feedback on the following solution. Better yet, do I have a missing solution that doesn't require non-volatile storage?
Please note that the main goal of this project is education. I understand that I could simplify this problem by setting up a secure relay inside my firewall and allowing internet traffic to be handled instead of directly exposing the MCU. But what would be funny about that?;)
= Suggested solution =
AES public key pair will be used. One key to enable Nonce in IV for CBC stage and another to encrypt messages themselves:
- General message
Key
- General
IV_Key
Here is a picture of what I am doing: https://www.youtube.com/watch?v=JNsUrOVQKpE#t=10m11s
1) Android takes the current time in milliseconds ( Ti
) (64-bit) and uses that as nonce input to the CBC stage to encrypt the command:
a) IV(i) = AES_ECB(IV_Key, Ti) b) Ci = AES_CBC(Key, IV(i), COMMAND)
2) Android uses /dev/random
to generate IV_Response
what the MCU will use to respond to the current request.
3) Android sends [<Ti, IV_Response, Ci>, <== HMAC(K)]
4) MCU receives and checks the integrity using HMAC, so an attacker cannot change the text Ti
.
5) MCU checks what Ti > T(i-1)
is stored in flash memory. This ensures that the recorded messages cannot be played back.
6) MCU computes IV(i) = AES_ECB(IV_Key, Ti)
and decrypts Ci
.
7) MCU responds with AES_CBC(Key, IV_Response, RESPONSE)
8) MCU stores Ti
in external flash memory.
It works? Is there an easier approach?
EDIT: It was shown in the comments that this approach is vulnerable to a delayed replay attack. If an attacker records and blocks message access to the MCU, the messages can be played back at any time and are still considered valid, so this algorithm is not suitable.
As suggested by @owlstead, a request / response system would probably be required. If I can't find a way, I think I need to do the following:
- Port or implement a decent PRGA. ( Any recommendations? )
- Pre-compute a set of random seed values ββfor PRGA. The new seed will be used for every MCU restart. Assuming 128 bit seeds, 16K storage units would be 1000 unique seeds, so the values ββwill not loop until the MCU successfully uses at least one PRGA output value and restarts 1000 times. It doesn't seem too bad.
- Use the PRGA output to create problems.
Does this sound right?
source to share
Not required IV_KEY
. IVs (and similar constructs like salts) do not need to be encrypted, and if you look at the image you linked to in a YouTube video, you can see that their payload description includes the IV in plain text. They are used so that the same plaintext does not encode the same ciphertext under the same key every time, which presents information to the attacker. The IV change protection is the HMAC message in the message, not the encryption. Thus, you can remove this requirement. EDIT: This paragraph is wrong, see discussion below. As noted, your approach above will work fine.
However, your system has a flaw, viz IV_Response
. From this I suppose you include it in your system that it serves some purpose. However, since it is not encoded in any way, it allows an attacker to answer yes to a device request without receiving the MCU. Let's say that your device instructed the MCU, which was controlling a small robot, to throw a ball. Your commands may look like.
1) Move to loc (x,y).
2) Lower anchor to secure bot table.
3) Throw ball
Our attacker can resolve messages 1 and 3 as expected, and block 2 to get to the MCU while still answering in the affirmative, causing our bot to be damaged when it throws the ball loose. This has an imperfect solution. Add a response to the command (which should fit into one block) so that it is encrypted, and respond to the MCU with a help AES_ECB(Key, Response)
that will check the device. This way, an attacker would not be able to spoof (if possible) a valid response. Note that since you deem it /dev/random
unreliable, this could provide an attacker with plaintext-ciphertext pairs that can be used for linear key cryptanalysis if the attacker has a large set of pairs to work with. Thus, you will need to change the key with some regularity.
Other than that, your approach looks good. Just remember that it is very important to use the saved one Ti
for re-attack protection, not the MCU clock. Otherwise, you will run into synchronization problems.
source to share