Skip to content
Go to file

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Project 04: Building a secure messaging system

In this project, I've extended the set of features for the secure login website to include messaging.

The website is being hosted on

The website supports single-recipient messages between users. All messages are sent over an SSL connection between the client and the server. Messages are also encrypted before they are stored in the database.

Database schema

To create the application's database, messages table, users table, and initial users we can run

php app\database\init.php

in the application directory.

The database initialization script in this project will create a messages table. The scheme of the messages table is as follows:

Field Type Null Key Default Extra
id int(10) unsigned NO PRI NULL auto_increment
message text NO NULL none
sender_id int(10) unsigned NO MUL NULL none
receiver_id int(10) unsigned NO MUL NULL none
enc_keys varchar(64) NO NULL none
keys_iv varchar(24) NO NULL none
message_iv varchar(24) NO NULL none

This project makes use of the MVC design pattern and new messages are inserted into the database as follows:

$m = new SecureMessage;
$m->message = "Hello, world!";
$m->sender_id = 1;
$m->receiver_id = 2;

It's important to notice that the SecureMessage::save() method will encrypt the message prior to inserting into the messages table;

The SecureMessage class also supports several static methods for retrieving users from the users table in the form of a User object.

Protecting the contents of the messages table

The goal of this project is to devise a strategy for securely storing messages on the server. This is done by encrypting the messages before storing them in the messages table. I have adopted the following strategy. When a user submits a message to be "sent" to another user, two 16-byte keys are generated:

$integrity_key = openssl_random_pseudo_bytes(16);
$encryption_key = openssl_random_pseudo_bytes(16);

A 64-byte keyed hash is generated using the SHA256 hashing algorithm:

$message_hash = hash_hmac(Config::hash_algo, $this->message, $integrity_key);

This hash is stored in the database to protect the integrity of the message. That is, any unauthorized changes to the message itself can be easily detected. Next, we generate a random 16-byte IV and encrypt the message and its hash using the AES-128-CBC encryption algorithm.

$message_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(Config::encr_algo));
$ciphertext = openssl_encrypt($this->message . $message_hash, Config::encr_algo, $encryption_key, 0, $message_iv);

Lastly, the keys are encrypted using a secret 16-byte key stored on the server.

$keys_iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length(Config::encr_algo));
$enc_keys = openssl_encrypt($integrity_key . $encryption_key, Config::encr_algo, Config::secret_key, 0, $keys_iv);

To retrieve a message from the database, its keys are decrypted using the system key. Then the message itself is decrypted using its own key.

Detecting changes to the contents of a message

When retrieving entries from the messages table, the hash is recomputed by hashing the message content using the integrity key, the produced hash is then compared with the hash that is stored in the database. If the hashes differ, the message has been altered and is thus discarded.

Protection against man-in-the-middle attacks

To ensure that the communication between the client and the server is protected, apache has been configured to used HTTPS (with the SSL protocol) for all communication. Using HTTPS requires the exchange of an SSL certificate. For the purpose of this project, a self-signed certificate was generated and stored on the server. This will ensure that all communication between the user's browser and the server is securely encrypted using public key encryption.

The downside of using a self-signed certificate is that the HTTPS connection, although encrypted, does not appear as a secure connection to the user's browser. This is because the certificate is not signed by a trusted authority. Although this still prevents against man-in-the-middle attacks with exchanging sensitive user-related information after the SSL handshake, this still opens the possibility of a man-in-the-middle attack during the handshake. There is no way for the user's browser to prevent attackers from providing their own certificate and tricking the user into giving the attacker their account login information. The solution to this problem is to purchase a signed certificate from a trusted authority.


No description, website, or topics provided.



No releases published
You can’t perform that action at this time.