Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Creating a secure channel

4.90/5 (33 votes)
24 May 2008CDDL13 min read 1   2.9K  
The purpose of this article is to explain how a secure channel is built. The article will explain the structure of a Very Simple Secured Protocol (VSSP) that sits above the TCP/IP layer.

Sample Image

Introduction

The purpose of this article is to explain how a secure channel is built. The article will explain the structure of a Very Simple Secured Protocol (VSSP) that sits above the TCP/IP layer. This article is based on lectures given by Prof' Amir Herzberg [1] and the book "SSL and TLS" by Eric Rescorla (chapters 1-3) [2]. I assume that you know and understand the basic building blocks of cryptography, i.e., symmetric and asymmetric encryption and message digest. For more information on those subjects, you can read "Cryptography 101 for the .NET Framework" by Toby Emden [3].

What is a secure channel?

People sometimes are mistaken to think that a secure channel means a channel where data is encrypted. However, encryption is only part of the equation. A good example can be a treasure map that Alice sent to her best friend Bob the pirate. This map describes the steps needed in order to reach the treasure.

Treasure map
StepsSteps (encrypted)
Go to the water towerR28gdGhlIHRoZSB3YXRlciB0b3dlci4=
Turn right and walk 100 stepsVHVybiByaWdodCBhbmQgd2FsayAxMDAgc3RlcHM=
Turn left and walk 90 stepsVHVybiBsZWZ0IGFuZCB3YWxrIDkwIHN0ZXBz
Dig 2 metersRGlnIDIgbWV0ZXJz

Eve the evil hates Bob, and does not want to see him become rich. Since the map is encrypted, Eve can not read the instructions, but she does not have to. All she needs to do is to change the map. She does not care how the changes will affect it, e.g.:

Treasure map
StepsSteps (encrypted)
Go to the water towerR28gdGhlIHRoZSB3YXRlciB0b3dlci4=
Turn right and walk 100 stepsVHVybiByaWdodCBhbmQgd2FsayAxMDAgc3RlcHM=
Turn left and walk 90 stepsVHVybiBsZWZ0IGFuZCB3YWxrIDkwIHN0ZXBz
Turn left and walk 90 stepsVHVybiBsZWZ0IGFuZCB3YWxrIDkwIHN0ZXBz
Dig 2 metersRGlnIDIgbWV0ZXJz

All she did was to duplicate the third instruction, and by doing so, she destroyed the map. If Bob can not tell that the map was altered, all the encryptions in the world will not help him find the treasure.

As you can see, Bob needs a way to check that no one altered the message.

Let us change the example. Eve wants to send Bob to a goose chase. She fabricates a treasure map, and sends it to him. Bob has no way to know that Eve sent him the map and not Alice. If Bob can authenticate somehow the origin of the map, then he can dismiss it as fake the moment he discovers that it did not come from Alice.

So, in summary, a secure channel needs to have a least three properties:

  1. Encryption
  2. Message validation
  3. Message authentication

Building a basic secure channel

Alice and Bob share a private key (it does not matter how they did it for now), and they want to create a secure channel in order to send a message.

Alice:
e = encrypt (k, t)
d = digest (k, e)
m = e + d
send to Bob (m)

Bob:
(e, d) = m
if (digest (k, e) == d)
    t = decrypt (k, e)
else
    error

Does this basic secure channel achieve the three properties that we have defined?

  1. Encryption – Yes. Bob and Alice share a private key. They use a symmetric encryption algorithm.
  2. Message validation – Yes. Bob and Alice use a digest algorithm (HMAC).
  3. Message authentication – Yes. Because Bob and Alice share a private key, no one else can use this key to forge a message. The underlying assumption here is that both Alice and Bob's machines are secure and no one else has access to this key.

There is one basic flaw in the above algorithm, the assumption that Alice and Bob manage to share a private key. It is not always possible, so is there a way to remove this assumption? Asymmetric encryption comes to the rescue.

Alice:
initiate connection to Bob over TCP/IP
// as_k stands for asymmetric public key
as_k = gets from Bob 
k = create a random key
encrypted_key = as_encrypt (as_k, k)
send to Bob (encrypted_key)

e = encrypt (k, t)
d = digest (k, e)
m = e + d
send to Bob (m)

Bob:
initiate connection with Alice over TCP/IP
send to Alice (as_k)
encrypted_key = gets from Alice
// as_pk stand for asymmetric private key.
k = as_decrypt(encrypted_key, as_pk) 

(e, d) = m
if (digest (k, e) == d)
    t = decrypt (k, e)
else
    error

By using asymmetric encryption, Bob can now send his public key to Alice. She, in turn, will use it to encrypt the shared secret (marked as k in the pseudo code above), which will be used as the key for the symmetric encryption and digest algorithms.

Does this basic secure channel achieve the properties that we defined?

  1. Encryption – Yes. Bob and Alice share a private secret. They use a symmetric encryption algorithm.
  2. Message validation – Yes. Bob and Alice use a digest algorithm (HMAC).
  3. Message authentication – No. What will happen if Eve intercepts the public key and instead sends her own? Thus, Alice can not be sure who actually sent her the public key. Without knowing it, Alice can accidently share the private secret with Eve. In consequence, when the private secret is compromised, the entire channel is broken.

Certificate and Certificate Authorities (CA) can help us to authenticate the public key. As a substitute for the public key, Bob sends a certificate. The certificate is signed by a trusted party (usually the CA). It binds the public key to a DNS name. Now, Alice can authenticate the public key.

TCP/IP

The above algorithm is using TCP/IP as the underlying transport layer. It has a significant influence on how the secured channel manages its connection. TCP/IP is responsible for ensuring that data packets are sent to the endpoint and assembled in the correct order when they arrive. This assumption removes a lot of overhead from our proposed secured channel.

The following paragraphs will demonstrate a real secured channel called VSSP (Very Simple Secured Protocol), which is a simplified version of SSL/TLS.

Top view

Image 2

The entire session between a client and a server can be divided into three parts:

  1. Handshake - Where the client and the server agree on cryptographic algorithms that will be used, and authenticate each other.
  2. Data transfer - Where the real data is transferred, i.e., files, text, etc.
  3. Closure - Ending the connection in a secured manner.

Handshake

In the above algorithms, the assumption is that encrypt, as_encrypt, decrypt, and as_decrypt are known to the client and server but it is not always true. Both client and server need to agree on a set of algorithms that will be used during the entire connection. Try to imagine that not all clients and servers are running the same version of our protocol. Newer versions will include more powerful instances of cryptographic algorithms, stronger keys, or totally different algorithms. We have to ensure that both the client and the server talk in the same language. The handshake phase assures that.

The authentication occurs during the handshake. There are two types of authentication: server authentication and client authentication. Server authentication happens when the client asks from the server to authenticate itself, and vice versa for client authentication. Authentication in VSSP uses Public Key Infrastructure (PKI), i.e., certificates and only supports server authentication.

Handshake protocol phases

Image 3

Phase 1

The Hello Client message initiates the connection. It contains two parameters. The first is a random value (nonce) that is used as a seed to the Key Derivation Function (KDF). The purpose of the random value is to stop an attack known as a replay attack [5]. In a replay attack, the attacker can retransmit all of the client's messages and cause the server to think that the client is sending the message again. By using the random value, the client and the server can be sure that each new session will be unique.

The second is a list of supported suites. A suite is a collection of cryptographic algorithms that will be used during a session. Each suite is composed of four algorithms: asymmetric key algorithm, symmetric algorithm, digest algorithm, and a compression algorithm. When the server receives the Hello Client message and it is willing to accept the connection, it replies with its own Hello Server message.

The Hello Server message contains three parameters. The first one is a random value (nonce) that has the same role as the random value that the client sends. The second is the chosen suite. The server chooses the most powerful suite that it supports out of the list of suites sent by the client. Note that the server does not necessarily support all of those suites. Powerful, usually, means better encryption algorithms (3DES over DES) or stronger keys (2048 over 1024).

Pay attention to the fact that an attacker that wants to intercept the session can change the list of suites sent to the server and remove all powerful algorithms so that the server will choose the weaker one. That weakness is something that the secured channel protocol must deal with, and it will be reviewed later on.

The third parameter is a certificate. The certificate contains the public key that will be used during the key exchange, but it also allows the client to validate the server. The current implementation sends an X509 certificate [6].

Phase 2

Image 4

Asymmetric encryption is slow compared to symmetric encryption, so instead of encrypting everything using asymmetric encryption, just encrypt a shared secret (private key). The private key will be used as the key for the symmetric encryption. In this phase, the client encrypts a shared secret using the public key (that was transmitted as part of the certificate in the former phase) and sends it to the server. The shared secret is used not only as a private key for a single algorithm, but as a mold from which the client and the server derive other private keys.

preMaster = Create premaster 
keysalt = random server bits + random client bits
masterKey = prf(preMaster, salt)
send masterKey to server 
iv = empty array
key = empty array
hmackKey = empty array
kdf (masterKey, iv, key, hmacKey)

The pseudo code describes how to create the final keys that will be used to initialize the algorithms that were defined in the chosen suite.

The preMaster is a long randomly generated array of bits. The salt is a concatenation of the random values generated by the server and the client in phase 1. Both of these values are parameters of prf (Pseudo Random Function) [7]. The prf expands the preMaster into a new random value called the masterKey, and from it, we can now derive our various keys. The VSSP uses the Rfc2898DeriveBytes class which implements password-based key derivation functionality.

The IV is the initialization vector used for CBC symmetric encryption algorithms, and the hmacKey is the key used for HMAC digest algorithms. kdf (Key Derivation Function) takes the master key, and creates from it the various keys. In VSSP, kdf is simplified, it just "cuts" the appropriate byes (see illustration). The server side does exactly the same except for the fact that it does not create the premaster key but receives it from the client.

Phase 3

The entire handshake process does not use any cryptographic or digest algorithm in order to encrypt the messages or validate their integrity. Only after the second phase the cryptographic algorithms are initialized, therefore it is impossible to use them before.

The messages were sent so it is quite useless to encrypt then, but it is perfectly reasonable to validate their integrity. In order to do so, we need to check if any of them where changed by an attacker. Both the client and the server save all the messages that they received and sent. They can run a digest algorithm (created in the last phase) on the sent messages and send it to the other side. The other side compares the digest that it received to the digest that it just calculated on the received messages. If the two digests are equal, then the entire process is valid, otherwise something interfered and there is a need to break the connection.

After the handshake is done, the real data can now be sent.

Data transfer

Image 5

Data is segmented into VSSP packets. Each packet has a header, payload, and a digest. The header consists of the following values:

  • VSSP magic number.
  • VSSP version – the version of the current protocol.
  • Message type - has several values that indicate what the content of the message is.
  • Data size – the size of the payload and the digest.

In order to send and receive data, the following pseudo algorithms are used:

send (t)
header = create_header (t)
comp = compress (t)
e = encrypt (comp, k)
d = digest (k, header + e + sent_counter)
m = header + e + d
sent_counter++
tcpSend (m)

receive (m)
header = extract_header (m)
if header is valid
    receive_counter++
    (k, d) = m
    if (digest (k, header + e + receive_counter) == d)
    comp = decrypt (k, e)
    t = decompress (comp)
    else
    error
else
    error

Compression

Compression is used in order to reduce the total size of the packet. Compression is being done before encryption for the sole reason that encryption (a good one) creates a totally random data, and totally random data can not be compressed.

Counters

As said in the previous paragraphs, VSSP uses TCP/IP as the underlying transport layer. Keeping packet order is done by the transport layer; however, a clever adversary can retransmit the same VSSP packet. In order to avoid such a situation, a counter is used. Both the client and the server keep track of send and receive counters. Whenever a message is received, the receive counter is increased by 1, and whenever a message is sent, the sent counter is increased by 1.

Closure

Closure is a special type of message that is sent by either side to indicate the termination of the session. The purpose of closure is to avoid a situation where an adversary closes a connection in the middle – truncation attack. Alice wants to send Bob a message about how many steps to take in order to reach the treasure. The number of steps needed is 1000, and each digit is encapsulated in a single packet. Eve intercepts the message and closes the connection just before the last 0. Bob will think that the number of steps is 100 and not 1000.

Code overview

The code is based on seven main packages:

  1. Data Layer – Encapsulates the entire data transfer code.
  2. Exceptions – Exceptions used.
  3. Messages – Messages that are sent during the handshake.
  4. Session – Session management and creation.
  5. States – The states that are used during the handshake. The handshake is a state machine.
  6. Users – Server and client implementation of the protocol.
  7. Utils – Various utility classes used.

In addition to the VSSP library, a chat application that utilizes the library is provided. We will concentrate on the most important packages.

Data Layer and Messages

Image 6

The DataLayerService class encapsulates the data transfer protocol. It exposes two main methods of send and receive. The DataLayerService is used by the data transfer part and by the handshake part; the only difference between the two parts is that the handshake does not use any cryptographic algorithms because none were set yet.

The messages are all based on a single class called DataPacket. The DataPacket encapsulates the payload and the message type.

Session

Image 7

The Session package defines the type of suites that can be created and the means to create them. ISession defines a session interface that all sessions must conform to, the interface encapsulates the main algorithms that are used by VSSP. Each session object can define its own set of algorithms.

Both the client and the server must agree on a chosen suite, therefore an enum is defined that includes all the available suites. Currently, only one suite is implemented; in order to implement more suites, you must add its name to the enum, implement a class that inherits from ISession, and add the creation code to the SessionFactory class.

Certificate validation

IsCertificateTrusted is a delegate defined under the HelloClientState class which the HelloClientState accepts as a parameter to its constructor. When the hello client state receives the certificate from the server, it needs to validate if the certificate is legal/valid. Each client needs to supply a method that does exactly that. The current implementation in the chat application uses a very crude method for such validation. It checks if the received certificate is located in a trusted certificate library (just like IE and Firefox do); however, it does not do any other checks.

Conclusion

In the current article, we demonstrated a simple implementation of a secured channel and explained the theory behind it.

Bibliography

  1. Introduction to secure communication and commerce 89-690
  2. SSL and TLS by Eric Rescorla
  3. Cryptography 101 for the .NET Framework
  4. Diagrams where created using Gliffy
  5. Replay attack
  6. X509 certificate
  7. prf

History

  • [24.05.2008] - Version 1.0.0.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)