# Is what i'm trying to do safe?

What both parties have:

Server
Master Secret (MS)
Server supported versions (Svers)
Agreed upon version (ver)

Client
Master Secret (MS)
Client supported versions (Cvers)
Agreed upon version (Ver)

What I am planning on doing:

Client sends Cvers to Server.
Server checks what version to use (the highest version the 2 share will be selected)

then computes

Rand = Generate crypto random number
SessionID = SHA256(MS, ver, Rand) "<- though the hash will most likely be dependable on the selected version"
SessionKey = KDF(MS, SessionID)
EncryptionKey = KDF(SessionKey, Rand)
IV/nonce = Generate crypto random number


Server sends message to client: SessionID, Ver, Rand, IV/nonce
Client checks if the returned version he got from the server is actually a version he has (just to be sure). Then the client computes:

SessionKey = KDF(MS, SessionID)
EncryptionKey = KDF(SessionKey, Rand)


If we were to need an extra key (for HMAC) we would simply send over an other random number.

Then finally the client would create a random message and encrypt this message in the propper way according to the selected version. It would send this random message and the ciphertext to the server, the server will either decrypt it or do the same as the client and compare the results. If the results match it will send an OK message back to the client and the communication can commence.

I have a few questions regarding this:

• Obviously, is this secure?
• Do i need the session key or can i derive the encryption key directly from the MS? (provided the Rand is different each time)
• Is the generation of the SessionID ok this way or should a simple random number suffice?
• Should the client create a random message and send this over in plain text or should both the server and the client have a message which is 'hard coded' and always use that (it will be the same every session).

I hope it is ok to ask these kind of questions here.

Disclaimer
Lets start of by saying, yes i know making an own protocol is bad mkay. I have discussed this (at length) with my supervisors but (they made a 'fair' point) there is no TLS implementation small enough that can fit on our devices (not much remaining code space). So here I am implementing (it hurts saying this) my own small TLS-ish protocol.

Also, the versions do not correspond to TLS, version 1 might be AES-CBC version 2 might be AES-GCM version 3 might met TDES-CBC (etc.)

This is a very difficult question. But first the standard information:

1. Don't roll your own crypto if anyhow possible. (which isn't the case here)
2. No protocol should be considered secure until formally proven secure. (TLSv1.2 is)

That being said I can still provide "ad-hoc" security argumentations why it's likely that your handshake is (in)secure.
I can't prove protocols secure. For this need you have to consult special companies or cryptographers who have actually published such proofs.

1. If a protocol downgrade (which is trivial here) doesn't hurt you you should be safe.
2. Your encryption key currently is $EK=KDF(KDF(MS||SHA_{256}(MS||Ver||Rand))||Rand)$. I think that just deriving this key like $EK=KDF(MS||Rand)$ is equally secure and a bit faster and you can expand it to $(EK||AK)=KDF(MS||Rand)$ with $AK$ being the authentication key.
3. The generation of the session ID like this is a nice idea to authenticate the random value at the same time (maybe using the suggestion below).
4. I'm not fully sure what you mean by this question. But the Rand value is essential to be different each time to get different session keys (what your protocol tries to achieve), so hardcoding them would be a very bad idea.

Some other notes:

• You mentioned HMAC for authentication. Please use a standard AEAD construction (->GCM,EAX,...) if anyhow possible.
• You may want to consider, if sending the SessionID, that you check the SessionID on the client side, as it is an "authentication tag"
• You may also want to consider using a different IV/Nonce for each message and exclude it from the handshake as it doesn't seem to provide any purpose. However, after the handshake it's an interesting idea to exchange random messages to check the key exchange worked.
• You may further want to consider replacing the SHA-256(MS||Ver||Rand) by $HMAC_{MS}(Ver||Rand)$ and thus "authenticate" the random value and the version to defend against tampering, this means you also need to actually transmit the tag (which you were already doing).
• You may want to consider using a TLS-PSK cipher suite, like TLS_PSK_WITH_AES_256_GCM_SHA384, but then you'd loose the session key property of having different keys as all session keys will be equal (somewhat defeating the purpose of your protocol), but you could use the "other_secret" field to insert some random negotiated data (using your above protocol) and be confident that you use "fully" TLSv1.2 and have key-freshness.
• Without some kind of asymmetric key exchange I struggle to see the basis of the security. Are you relying on synchronized random number generators at each end? – user9070 May 13 '15 at 9:45
• @TruthSerum, security lies in the master secret. You don't need synced RNGs or asymmetric crypto. Each session key is fully independent from each other. It only depends on the random value and on the master secret, which are both used to derive fresh "master-keys" for each session. – SEJPM May 13 '15 at 16:01
• So essentially you hardcode the symmetric key at the endpoints and then negotiate an IV? – user9070 May 13 '15 at 19:44
• @TruthSerum Speaking in TLS words: We hardcode the master secret at all endpoints (more than 2 I guess) and derive temporary keys from that master keys using exchanged random data. IVs will be defined (I suggested) in context of a packet, just like in TLSv1.2. – SEJPM May 13 '15 at 19:50
• Well i'm going to use TLS, we were able to free up some space on the device and i now have 2KB to spare xD haha. anyway i still have to go through one insecure part to keep the code backwards compatible with the previous version. I still have to agree on a crypto method first, 0 being what we use currently and 01 going to be TLS, could you perhaps look at my follow up question: crypto.stackexchange.com/questions/25745/… on how to do this safely? – Vincent May 19 '15 at 7:34

Your scheme is not a good approach -- it is not safe. Your scheme is vulnerable to rollback attacks.

Ideally, the security property we'd like is that this will select the best (highest) version that both client and server support. However, that security property is not achieved.

A man-in-the-middle can force both parties to end up using the worst (lowest, weakest) version that they both support, simply by editing the values of Cvers and Svers as they are sent over the wire. For instance, suppose the client supports versions 3,4,5 and the server supports versions 2,3,4,5,6. The man-in-the-middle edits the messages so that the value of Cvers received by the server is 3 and the value of Svers received by the client is 3; now they'll both end up deciding to use version 3, the key exchange will succeed, and neither endpoint will notice that they're under attack.

That's not a desirable property for a protocol to have, which is why I say that your scheme is not a good approach.

A standard defense is to make the negotiated key depend upon the entire contents of everything sent during the handshake (all messages sent by both endpoints). This way, if a man-in-the-middle edits those messages, then the two parties will end up with different session keys, and eventually verification of the MACs will fail. This requires some assumptions but can be made to work acceptably well, with sufficient care.

More generally, you are trying to roll your own crypto, which is tricky and error-prone. Rollback attacks are a thing that has been studied. Rather than trying to invent your own protocol, it's better to use an established protocol, if that's possible.

Alternatively, if you must roll your own, you should study what other protocols has done. For instance, modern versions of TLS include some defenses against rollback attacks, so you'd be better off using TLS if possible -- close study of how TLS defends against rollback attacks would be a good idea. (You can also look at rollback attacks on older versions of TLS.) This might require more cryptographic knowledge than you already have, so you might need to hire a crypto-expert as a consultant. I realize that's expensive; rolling your own crypto and doing it right is, unfortunately, an expensive endeavour.

To help you avoid the need to re-invent the wheel: have you looked at pre-shared keys for TLS? at DTLS?

I would be worried about the absence of any key-exchange process to establish symmetric keys. The whole problem of safe communication seems to come down to safe key exchange, and this is what TLS addresses.

Some people on this site might disagree with me here, but if you are rolling your own protocol anyway, I'd imagine you would have better security (and compatibility) than what you would otherwise have if you made an attempt at implementing a standard protocol from it's specification.

I'm not suggesting you implement the primitives themselves (which I expect you already have at your disposal), just the handshake and application layer framing. Whether or not you claim TLS compatibility is up to you.

• Also, if you implement TLS yourself, you can just implement one version and one cipher suite, reducing code size significantly. Much of the size of a TLS implementation is because TLS offers lots and lots of options, and generally available ones have to support a lot of those. Since either way it's rolling his own crypto, I don't see why reimplementing TLS would be worse than designing and implementing an alternative from a security standpoint. – cpast May 12 '15 at 17:30
• Yes well I am making the handshake my self but what i tried to say is i take a lot of inspiration for that handshake from TLS. I might have worded some things wrongly. I have been trying some different approaches with TLS and i got it down to 38kb (wihich is 18 to much) but I will see if i can get it down further but if not, I will do my own handshake, that's what this post is for, to see if what i'm doing is kinda right. I'm not sure about the sha-256 part. – Vincent May 12 '15 at 19:42
• The handshake itself only mandates SHA and MD5 I think. But I think the exact hash functions used for the KDF are variable in the latest specification. In any case, the actual handshake logic adds minimal overhead to your implementation. As @cpast was saying, the main overhead that a full TLS implementation adds will be in it's support for a wide variety of cipher suites, and there's no reason, even formally, that you are required to support any more than one of those permutations. – user9070 May 12 '15 at 20:14
• @TruthSerum I think the reason why the OP doesn't use the "standard" TLS handshake (which allows "custom" PRFs in TLSv1.2, like SHA-256 or SHA-384, no MD5!) is that all TLS handshakes use some sort of asymmetric crypto which isn't possible for him (as he'd just use standard handshake then) due to performance restrictions. This "handshake" here has the aim to provide a temporary data encryption key using symmetric methods only. – SEJPM May 13 '15 at 8:44
• @SOJPM, pre-shared keys for TLS seem like a counterexample to the claim that TLS handshakes always require asymmetric crypto -- no? – D.W. May 15 '15 at 8:00