In this post we built a test application where we mixed asymmetric and symmetric encryption with HMAC hash verification. The message sender gets the asymmetric public key of the receiver and uses it to encrypt a symmetric public key. The message is encrypted with a one-time symmetric public key. The symmetric key is also used to calculate the HMAC of the cipher text. The receiver decrypts the symmetric key with her asymmetric private key and calculates the HMAC. If the hashes match then it’s safe to assume that the message hasn’t been tampered with on its way to the sender.

The communication flow is quite secure but we can tighten security even more. In this post we learnt about digital signatures. A digital signature is used to sign the hash of a message with the sender’s private key. The public key that matches the private signature key is sent along all other information to the sender. The sender can then check the validity of the signature using the provided public key. The trust is based on the fact that the public and private keys go hand in hand, therefore signature verification doesn’t need the private key.

The goal of this post is to extend the demo application with digital signatures. The sender will sign the message and the receiver will verify the validity of the signature.

Up to now the code is very similar to what we saw in the post on digital signatures. If you’re not sure about the details and what the above code does then you’ll find the explanation in the referred blog post.

Extending the EncryptedMessage object

We need to extend the EncryptedMessage object of the demo application to give room for the sign message result:

The SecretMessageReceiver and SecretMessageSender will both need to handle asymmetric and symmetric encryption, HMACs and digital signatures. These are 4 interface dependencies that both constructors will need. It’s better to factor these out to a common base class:

We’ve added an extra step to the message receiver class. It will verify the signature of the message. If there’s a mismatch then an exception is thrown. Otherwise code execution continues like before and the encrypted message is decrypted.

Putting it all together

Here’s an example how the above components can be put together to test the flow: