correct usage of keys and nonce I've being studying up on AES, GCM, CBC, HMAC and a lot of other primitives and am somewhat ( a little bit, perhaps) familiar with them however I am still a bit weary on the use of the keys and nonce.

Background:
I have got multiple (embedded) devices (sometimes hundreds) all of which are connect to a server. These devices are to communicate with either AES-CBC HMAC or AES-GCM. when using HMAC I know first to encrypt then MAC. Further more these devices have a pre-installed key on them.

Here is what i think i know:
1. You can have 1 master key but AES and HMAC never use the master key directly
2. You should use a KDF like PBKDF2 to create a session
3. Every so often you should change the master key

Now say we start connecting a device to the server. Both the device and the server have the same master key but they must agree upon a session key. I cannot do this in any other way than to use Diffie hellman? simply sending over a salt for the PBKDF2 won't do since an attacker might alter it.

Then, when using CBC, we create a random number as IV, we encrypt the message, add the IV and then use the HMAC with the session key, append the result and send it over.

When using GCM we create a nonce, encrypt the text, append the nonce to the cipher text and send it over, we either keep sending the nonce over or we keep a counter on both sides either way we always +1 the nonce.

So my question:
is diffie hellman a must have? or is there an other way to do? keep in mind I am very restricted in processor power and memory so using a PKI with RSA is not an option.

is everything else i described correct?

1 final remark, It is often said it's better to use 2 separate keys (1 for encryption 1 for HMAC) this simply means using DH twice
PBKDF2 is an acronym for Password Based Key Derivation Function, #2. As you already have a key you need a Key Based Key Derivation Function or KBKDF instead. Currently the most up to date one is probably HKDF, which was - very quickly - also recognized by NIST. There are other KDF's such as KDF1 and KDF2 which are easier to construct (not many libraries contain KBKDF's by default).



You don't require Diffie-Hellman if you already have a shared secret, unless you also require Forward Secrecy.

What you can do is store device keys on the device, send over some device ID to the server that uses that to calculate the device keys from a master key. That way, if one device is compromised, you don't loose the master key (the device is fitted with the device key upon creation using the same algorithm).

Similarly you can use a key derivation from the device key using some unique session based information or large enough random to establish session keys. I would create 2 to 3 session keys:


for explicit authentication using a MAC (you don't want to use your secure channel for implicit authentication - trust me on this)
for encryption of the secure channel
for authentication of the secure channel (unless you use one key for encryption and authentication as in GCM)


It's best to use different session keys for client and server (e.g. by reordering the client ID and server ID) otherwise you may run into nonce reuse, replay attacks etc.



Note that the authentication data used for explicit authentication should contain as much data as possible, including one or more randoms, client ID, server ID and something to identify the session with.



So basically you don't require asymmetric primitives for such a scheme, although you may gain additional benefits from it. Forward secrecy is one, but you might also want to achieve anonymity to name just one other (I presume this is less important for your use case though).