Establishing a secure communication channel over HTTP

Introduction

This article provides an introduction to how to make encrypted communications between two endpoints over HTTP. The goal is to transmit data securely from one endpoint to another without the need for SSL/HTTPS .

To establish an encrypted communication channel, we will take advantage of the RSA and AES algorithms. RSA & AES are the world’s most widely cryptography algorithms.

You might be wondering, WHY not just use simply the HTTPS? The answer to this question is another question: what if HTTPS was unavailable? or if the SSL/TLS are being intercepted by third parties like the local Internet service provider ISP?

There are multiple reasons for using HTTP. As a Security Specialist, I needed to stay under the Intrusion Detection Systems radar and avoid SSL/TLS inspection by enterprise security solutions.

The scenario in this article is that we have a desktop application that communicates with a web server on the internet. We want to ensure the information is securely exchanged, even if HTTPS is not present.

Core keywords: RSA, AES, Public Key, Private Key, Symmetric Key, C#, PHP

Before diving into the technical details, let’s have an overview on the RSA and AES algorithms.

RSA Algorithm

The acronym “RSA” comes from the surnames of Ron Rivest, Adi Shamir and Leonard Adleman, who publicly described the algorithm in 1977.

RSA Cryptography is the world’s most widely used public-key cryptography method for securing communication on the Internet. The RSA algorithm is an asymmetric cryptography algorithm; this means that it uses a public key and a private key (i.e two different, mathematically linked keys). As their names suggest, a public key is shared publicly, while a private key is secret and must not be shared with anyone.

The following illustration highlights how asymmetric cryptography works:

Basically, the public key: Used to encrypt information while the private key is used to decrypt the information.

AES Algorithm

Unlike the RSA algorithm, which uses two cryptographic keys for encryption and decryption, the Advanced Encryption Standard (AES) uses a single key for encryption and decryption shared between the sender and the receiver.

The following illustration highlights how symmetric cryptography works:

RSA or AES?

We now have a basic idea of how asymmetric & symmetric encryption works, but which one should be used?

Depending on the application design or the project you’re working on, you can choose the algorithm that suits your project.

RSA is reliable; AES is not. RSA provides confidentiality, authenticity and integrity. On the other hand, AES ensures only the confidentiality of the data.

Combining RSA & AES – Hybrid Encryption

The size of the data can be encrypted with RSA is limited to the key size; So simply, if the public key size is 2048 bit then the maximum length of the message should be 2048.

In addition, exchanging the RSA keys every time a message is exchanged between two parties will increase the delivery time.

To address these issues, we can use the RSA for exchanging the AES key securely and then use AES for data encryption.

The following illustration highlights how symmetric and asymmetric cryptography works:

  1. The client requests the public key from the recipient, which is, in this case, the web server.
  2. The client generates an AES key (session key), encrypts it with the server public key.
  3. The client sends the encrypted session key to the server.
  4. The server stores the session key in their session management database.
  5. At this point, both parties have the same encryption key, and they can exchange data securely.

Using RSA & AES in our Application

The scenario here is that we have a desktop application that communicates with a web server on the internet. We want to ensure the information is securely exchanged.

I made a very simple application using C# and PHP, which implement the following session key generation and exchange. The idea is to provide you with insight to help you build a more complex version. The full source code of both client and server application are available the GitHub link:

https://github.com/iomoath/RSA_AES_Test_Client_Server

The client: Desktop Application (Written in .NET C# language)

The server: Web application (Written in PHP language)

The process:

  1. The client generates a shared key (AES key).
  2. The client uses the server public key to encrypt the shared key.
  3. The client sends the encrypted AES key to the server.
  4. The server decrypts the messages using it’s RSA private key.
  5. The server generates a unique client identifier so it can identify the client next time.
  6. The server stores the AES key and the client’s unique identifier in its session management database.
  7. The server responds with the unique client identifier to tell the key exchange is complete.
  8. At this point, the key exchange is complete. The client can now communicate with the server using the shared key. The client must include its unique identifier in any future communications so the server can identify the client AES keys from its session management database and be able to decrypt the data.

Server Application

The web application composed of two main files:

key_exchange.php: Responsible for handling session key exchange (AES Key)

api.php: This is where the client will exchange information with the server after exchanging the session key through key_exchange.php

Web Application files:

key_exchange.php

The exchange_key.php expects the HTTP header “query”, this header value coming from the client contains the AES key, and it’s encrypted with the server public key. It implements the steps from 4 to 7 described above. Content of key_exchange.php:

key_exchange.php contents

api.php

The api.php script expects the HTTP header “HTTP_CLIENTID”, which contains the unique client identifier provided by the server during the key exchange process, and it’s encrypted using the server public key.

api.php expects the HTTP POST parameter “data” which contains the message and it’s encrypted with the shared AES key.

api.php contents

RSA key generation

You can use the script “rsa_test.php” to generate key pair. The private key should be added in config.php

The XML format will be used by the client application.

RSA Key generation using phpseclib library

At this point we should have our PHP application available to serve requests.

Client Application

The client application will attempt to establish a secure channel with the server and exchange some secret information.

The following code snippets are from the client application show key exchange function and information exchange:

Settings.cs, stores the server public key and URL
AES_Keys_Exchanger.ExchangeAesKeys() function responsible for exchanging session keys with the web server

The function ExchangeAesKeys() performs the following:

  1. Generate an AES key
  2. Encrypt the key using the server public key.
  3. Send an HTTP request to the web application at http://10.9.8.10/bank_app/key_exchange.php
  4. Decrypt the web server response using the keys generated in step 1
  5. Verify the server signature embedded with the response
  6. Read the client’s unique identifier value from the response and store it to be used across the session.

Program.SendTestMessage(), Simulate a test by sending some information to the server and read server response

The following screenshot is the output of the client application:

Inspecting HTTP Traffic

Let’s have a look on how the traffic generated by the client and server applications:

mitmproxy flows
Key Exchange request – originated by the client application
Key Exchange response – Server response
Encrypted Information exchange – Originated by the client application
Server Response

Considerations

In the demo application, the server public key is hard-coded in the client application, which eliminates the need to request the server public key over the network.

However, if we request the server public key over the internet, how do we know this key is authentic and the correct key?

There are multiple ways; one is by verifying the server key hash by the client application.

The hash of the server key must be hard-coded in the client application, so when it requests the server key, it calculates its hash and compares it with the one it has.

Read more about hashing and data integrity at the following links:

https://subscription.packtpub.com/book/cloud_and_networking/9781789348019/1/ch01lvl1sec04/hashing-and-data-integrity

https://www.c-sharpcorner.com/article/compute-sha256-hash-in-c-sharp/

Leave a Reply

Your email address will not be published. Required fields are marked *