We have 3 parts that will result in 3 projects – Client, Server and Common (common library for both the server and the client).

First, we take a quick look at the classes and I’ll explain what they do – though I think it is pretty obvious.

(Click on the diagram to enlarge)

Let’s start with the common part.The ServerInfo contains the date/time and the public key of the server.The Credentials contains UserName/Password/Expires properties that get serialized and sent to the server; the others (about date/time) are static properties initialized at the beginning from the server info and are used to set the Expires property just before the request.

Let’s move to the server at AppServerstatic class; its role is to create/start/stop the service that will serve to clients the ServerInfo.

Now on the client, we have AppClientstatic class; its role is to get the ServerInfo; it also hosts the client’s credentials.

This is followed by the encoding mechanism where encryption and compression occurs, but we’ll talk about this later.

Now on the server: we need to derive a class from ServiceAuthenticationManager and override the Authenticate method[3]; here if the CheckCredentials passes without any exception being thrown, then we authenticate the user from the credentials.

Encryption

Encryption/decryption is provided by common Cryptographer/ClientCryptographer/ServerCryptographer; a separate cryptographer for server and client is needed because they do different encryption/decryption.

Client - Encrypt Request

Get the id of the message, associate it with the key and keep them until the response from the server comes – we’ll need that key to decrypt the response from the server.

Get the element to encrypt (the Credentials element if only credentials are to be encrypted or the first node if the entire message will be encrypted) and encrypt that element.

Encrypt the AES key with the public key[2] of the server and add it to the encrypted node (using the name KeyElementName – which is a constant for both the server and the client).

Set the id of the encrypted element to the id of the message (to know the id of the message before decryption).

Get the key based of the id of the message (RelatesTo element) that was saved from the request.

Encrypt the message.

Set the id of the message to the encrypted data (so that on the client to know which key to use – if only synchronous requests would be sent, then we’ll need just to use the last key, but we have to take both situations under consideration).

Since we want to do this in a message encoder, we don’t have the message as an XML document, but as an array segment; therefore, for client and server we need to do encryption on array segments (actually convert the array segments to XML documents and then apply the above methods).

This might be not so easy to understand by just following the attached code; so I’ll present it with a few changes to make it easier to understand.

First, I’ll show only the encoding done for the client (there is no point in showing the server because it is similar); and second - I’m combining the common with the client (because actually all started this way – thinking at the client, then at the server and after that, at their identical parts and thus the “common” project came into being).

First, we have the ClientEncoder based on the abstract class MessageEncoder with the most important methods WriteMessage and ReadMessage; here we use the methods presented in the Encryption and Compression chapters; the ContentCompression and ContentEncryption properties are initialized by the class that creates the encoder and are actually a propagation of the contentCompression and contentEncryption attributes from the configuration file (a little later, we’ll see how this is retrieved from the App.config).

You may need to re-add some of the references: System.Configuration, System.ServiceModel, System.IdentityModel, System.Security, System.Runtime.Serialization, Ionic.Zip (the last is in the Common project; the others come with .NET 4).

The references are for both the parts of the article and for the attached code (comments with numbers).

You need administrative rights to start the server.

To use Microsoft’s implementation of zip and remove the need for Ionic.Zip.dll, just change in the Common Project, Encoding.cs the “using Ionic.Zlib;” with “using System.IO.Compression;”; then you can delete the reference and the DLL.

To avoid duplication, the code is attached only to the first part of the article.

If you want to test directly the server.exe and the client.exe from the attached zip, you need to unblock first server.exe.config and client.exe.config (right click, properties, unblock); otherwise you'll get a configuration error.