I am implementing a heartbeat protocol so that a server can send notifications to clients. The notifications are not occurring so often, so I don't want to keep an open TCP+TLS session for each client, since the overhead would be too high. Likewise, I don't want to use DTLS heartbeat (see RFC 6520), since I don't need a payload (and the heartbleed attack makes me think that common implementations are not mature enough).
I thought of the following protocol :
First, the client contacts the server over TCP+TLS, and they agree upon an ephemeral key $K$ and a sequence number $S$. The server also attributes an ephemeral session id $Id$ to the client (for faster lookup later). The TCP connection is then closed.
Second, the client sends heartbeat messages over UDP, containing $Id || E_K(padding || S)$, where $E$ is a block cipher (e.g. AES), $padding$ is enough zeros so that $padding || S$ has the length of a block, and the sequence number $S$ is increasing between two messages (to avoid replay attacks). Likewise, the server sends $E_K(padding||status||S)$, where $status$ is a bit indicating if a notification is available.
If no message is received after some timeout (a few minutes), the server removes the heartbeat session. Also, the session is timed-out after 1 day.
The role of the padding is to ensure that the peer knows the key $K$ (i.e. an attacker should not be able to forge ciphertexts with a valid padding). For example, $S$ could be a $32$-bit number and $padding$ would be $128 - 32 - 1 = 95$ bits (from server to client) if $E$ is AES128.
I am aware that an active attacker (or simply network congestion) can prevent packets from arriving, but apart from that is the scheme secure ? In particular :
Is it possible for an attacker to forge a packet with the correct padding (by only seeing the heartbeat packets) ?
Is it OK to pad with zeros or is does it induce some weakness ? Likewise, can I use deterministic sequence numbers, starting e.g. at $S = 0$ ?
Is the $95$-bit padding long enough (given that the session only lasts a day) ? I could use AES256, but the key is longer, which implies more memory per client on server size. Alternatively, I thought of sending $S$ in clear in the message (i.e. $Id || S || E_K(padding || S)$), which should increase the complexity of a forgery.
Is there something else I missed ? Is there a means to improve the protocol in terms of performance ?
Note : the $Id$ that I mentioned would contain $E_k(padding || i)$ with $k$ a key only known of the server and $i$ the index of the client in the table of sessions. This is mainly for performance to avoid using a hash table on the client's IP address and UDP port, and to avoid an attacker to forge valid $Id$s (which could be the basis of a DoS attack with useless lookups in the server's memory). Is this $Id$ implementation secure ?