For a personal MMO game project I am implementing a homebrew reliable UDP-based protocol in java. Given my current setup I beleive it would be relatively simple for a snooper to hijack a session, so in order to prevent this I am taking the opportunity to learn a little cryptology. Its very interesting.
I can successfully create a shared secret key between the client and server using a Diffie-Hellman key exchange (a very clever concept), but now I need to use this to guarantee the authenticity of the packets. My preliminary testing so far has shown that the couple of different ciphers Ive tried bloat the amount of data a bit, but I would like to keep things as small and fast as possible.
Given that I am only trying to authenticate the packet and not nessecarily conceal the entire payload, I have the idea that I could put an 8 byte session ID generated from the secret key into the packet header, encrypt the whole packet, and hash it back down to 8 bytes. I take the unencrypted packet and put the 8 byte hash into the place of the session ID and then send it off.
Would this be secure? It feels a little inelegant to encrypt the whole packet only to send it unencrypted - is there a better/faster way to achieve my goal? Please note I would like to do this myself since its good experience so Im not so interested in 3rd party libraries or other protocol options.
If both peers have access to a shared secret (which they should, since you're talking about Diffie-Hellman), you could simply store a hash of the datagram in its header. The receiver checks to see if it matches.
As an added security measure, you could also add a "challenge" field to your datagram and use it somewhere in the hashing process to prevent replays.
So this hash should cover:
The shared secret
A challenge
The contents of the datagram
EDIT
The "challenge" is a strictly incrementing number. You add it to your datagram simply to change the hash every time you send a new message. If someone intercepts a message, it cannot resend it: the receiver makes sure it doesn't accept it.
Related
I'm developing a device on STM32L4x6. It is connected through BLE to a smartphone and it exchanges encrypted data with it.
Encryption is AES-GCM and I'm using the reference implementation provided by STMicro.
I have implemented a shared secret exchange mechanism using Diffie-Hellman protocol on Curve25519. Right now I am using this shared secret directly as AES key.
However I am confused on 2 points:
I think I have to derive a session key from the shared key however I don't really understand how.
about key storage on STM32, what is the common/best practice ? Is it enough to store the key in Flash and to set the Flash in Read Protected Level 1 ?
Thank you
As for deriving a session key - you may want to look into the topic of Key Derivation Function (KDF). Googling it returns a lot of useful informations related to establishing session keys. You may also ask your question on https://crypto.stackexchange.com/.
As for storing keys in STM32 - it depends what your requirements are. Do the keys need to persist between sessions or can you generate a new one each time a connection is established? Generating a new key each time a new connection is made will be safer due to two reasons:
It's different for each connection so even if someone manages to get the key for a session from the past, it may only be used to decrypt that session.
If you generate a new key for each new session, you don't have the need to store it anywhere such as Flash memory, as you may keep it in RAM only. Powering down the device will wipe the key. Enabling read protection prevents access to RAM as well as to internal Flash.
Regarding 2nd point however - STM32 is NOT considered a "Secure Microcontroller". It lacks hardware elements that prevent hardware attacks - power voltage glitch detection, side-channel prevention, secure mesh etc. With enough resources and determination an attacker will be able to obtain the cryptographic keys that you use, for example by grinding down the chip package and optically reading your data. That touches on the aspect of how secure does the device really have to be - development time cost, hardware security cost. With STM32 all you can do is to make it harder (keep the keys in RAM and only when you need it, then overwrite them with noise) and limit the scope of the attacker (change session keys as often as possible, e.g. each session).
I have been trying to find out exactly how SSL works, and have found descriptions of the packet sequence that starts the conversation, but not how requests are processed. Here is a link to an example showing the initial handshake:
https://www.eventhelix.com/RealtimeMantra/Networking/SSL.pdf
Once communication is established, both sides are sharing a private session key which is updated every so often. I would like to know details on:
I assume that an attacker cannot just replicate an observed packet and execute it multiple times? This is a so-called replay attack.
How is encryption done using AES-256? If both sides simply applied the algorithm, then a replay attack would work. So I assume there is some kind of chaining so that each packet uses different encryption.
The session key switches every interval (like once every 30 or 60 minutes. How does this exchange work? What messages are exchanged, and what happens if a method is sent before the exchange that arrives after the switch?
The underlying mechanism most recently is TLS 1.2. Is this the same for SSL and SSH, or are the two protocols different?
An explanation is always good but a link to relevant documentation would also be extremely helpful. If these interlocking parts are too much, I can split out into a separate question, but there is a lot of overlapping information in the above sections.
I assume that an attacker cannot just replicate an observed packet and execute it multiple times? This is a so-called replay attack.
Correct. TLS is immune from replay attacks.
How is encryption done using AES-256? If both sides simply applied the algorithm, then a replay attack would work. So I assume there is some kind of chaining so that each packet uses different encryption.
There is chaining, and sequence numbers, and also a MAC for each message.
The session key switches every interval (like once every 30 or 60 minutes. How does this exchange work? What messages are exchanged
Another ClientHello with the same sessionID, and an 'abbreviated handshake' after that, that changes the session key. Details in RFC 2246.
and what happens if a method is sent before the exchange that arrives after the switch?
The switch is by mutual agreement, and any message that arrives before the same sender's ChangeCipherSpec message is decrypted under the old parameters.
The underlying mechanism most recently is TLS 1.2. Is this the same for SSL and SSH, or are the two protocols different?
They are different.
I'm planning to use the crypto_box() functions of Nacl to encrypt messages as part of a client/server protocol. The server has to deal with multiple clients and each message from a client to the server is encrypted using the public key of the server and signed with the private key of the client.
The cypto_box() functions also require me to provide a nonce. The current message number could be used as a nonce–to my understanding, the nonce is necessarily known to an attacker who is capable of keeping track of how many messages were exchanged. Both, the client and server would then maintain a message counter and simply use the newest counter value as a nonce.
However, I must deal with the case where messages are reordered or lost. Therefore I'd send the nonce in plaintext alongside the encrypted message. As long as the same nonce is not used twice, I don't see any problems with this approach. Did I miss out on something?
No, nonce's and IV's may be considered public knowledge. I've just checked the NaCl site and I don't see any explicit remarks that contradict this.
CBC mode of operation has some additional requirements for the IV (non-predictability) but that's of course not an issue in NaCl.
You should make sure that you don't accept any nonces <= the last received nonce though, otherwise an attacker could probably resend or reorder messages.
Currently I am working on an embedded project. The client side is an 8bits MCU and the server side is computer.
As part of goal, I want to minimize the chance people copy our product. During the initialization phase, the server send its serial number to client and client do some simple calculation with its serial number then send result back to server. The server checks the result to a pre-calculated, hardcoded value, if match the client is authentic.
The problem is the calculated serial number that sent back to server is always fixed. Any copycat company can figure it out quite easily with a logic analyzer. I want to make the transmitting serial number seems random bits from time to time but still be able to decrypt back to its original value. A good example using AES encryption (notice every time you press the Encrypt It button a seemingly random text is generated, but as you decrypt it, then it reverts to the original text.)
Due to ROM/RAM and process power limitation in 8bits MCU I can’t fit a complete AES routine in it, so AES is out of a solution. Is there an easy and efficiency algorithm just to randomize the transmission?
Use a key pair. On initialization:
Client tells server "I am online"
Server encrypts a verification message, which only the client will be able to decode
Client sends back the decrypted message
There should be no need for the server's key to be hardcoded - it can be generated based on a timestamp (only an answer within an acceptable range is accepted) or the codes can be generated on an as-needed basis with a timeout to prevent them from being stored for a long term.
Have the server send either a monotonically-increasing counter or a timestamp to the client, alongside the serial number. The client then includes that in the calculation it performs.
Because the server always sends a different request, the response will always be different (of course, if the market is lucrative enough your competitors can always disassemble your MCU code and figure out how to replicate it, but there's really no stopping that).
A different idea might be to require the 8 bit controller to send a CRC of the date, time and serial number to the server. The server can verify it is a unique serial and send a CRC with date, time and authorization code.
You might also look into the rolling code algorythms used for garage doors openers to see if they could be applied to your application.
I want to secure the communication of a TCP-based program using a shared passphrase/key. The easiest way to do that without having to deal with block size, padding, ... is to directly use a stream cipher. Doing that way, the amount of data is not changed between clear and encrypted data and the modification is trivial.
Using only a stream cipher means that there is no authentication and I have always considered/heard that encryption without authentication is not secure enough and should not be used.
If adding authentication to a stream cipher is mandatory, we lose the simplicity that stream cipher has added because we must add an HMAC or use an authenticated encryption method (like crypto_secretbox from NaCl), there is a minimum message length, we must handle padding, ...
What would you recommend? Is it safe to only use stream cipher without authentication in some particular cases?
Using some kind of message authenticator is particularly important with stream ciphers, because the relationship between changes to the ciphertext and changes to the plaintext is so simple.
You can't just blindly go and apply the stream cipher without adding any extra information to the stream, anyway - remember the most important rule of stream ciphers:
NEVER RE-USE THE SAME KEYSTREAM
So unless you are only ever going to encrypt a single connection, and throw the passphrase away afterwards, you will need to generate a session key for each connection from the shared secret. This implies that you will need to send some extra information at the start of the connection, and since you're sending that anyway, sending a HMAC after each message should be no big deal.
Using a stream cipher because it seems simpler is usually a mistake, anyway. You mentioned crypto_secretbox from NaCl - I recommend using that, it will take care of the authentication and padding issues for you.
You could consider using AES in GCM-mode. That will give you a stream-cipher with built-in authentication.