Click here to Skip to main content
15,867,686 members
Articles / Security

Encrypting Communication between C# and PHP

Rate me:
Please Sign up or sign in to vote.
4.91/5 (34 votes)
11 Oct 2011GPL344 min read 199.4K   4.4K   65   63
Set up encrypted secure communication between C# and PHP using the AES and RSA algorithms.

CS to PHP Encryption

Contents

Introduction

The first section of this article gives some background. The second section describes how to install and get the example scripts working for you so that you can verify that they work and have something to build off of. The third section discusses how to use the library I wrote for your own applications, giving you the guidance to utilize the library to its fullest. The fourth section describes the actual code of the library, how it works, and why I made the choices that I did.

If you are like me, you will probably want to know more about how I make C# and PHP work together in code and not just blindly use my library. However, I have included detailed usage instructions just in case you only want to copy, paste, and make it work.

Background

Several weeks ago, I was writing a proof of concept program in C# that, in part, required connecting to a PHP script securely. I did not have the option of using SSL, so I opted to use something more customized. Figuring that a specific encryption algorithm will work exactly the same regardless of the language that is implementing it, I simply used the built-in algorithms provided in C# and PHP. This assumption is true, for the most part; however, I was having a surprisingly difficult time getting the encryption to actually work between Microsoft's library and PHP's Mcrypt library. After several hours of failure, I eventually broke down and Googled a quick solution. Normally, I find an example close to what I need in a few minutes, but I looked for a long time and could not find a suitable solution. Nobody seemed to quite have a complete answer to the many people out there who were asking for help trying to do exactly what I was trying to do. Many questions were answered unsatisfactorily, none answered the full topic, others did not get any response at all, and an occasional person would eventually respond to his own question saying nothing more than "I got it to work," but would not help out the rest of us by posting his solution. I had already spent enough time trying to find a "quick" solution, so at this point, I went ahead and wrote my own. It took me a full Saturday, but I got it working. This article details what I did to get it working, provides a library that you can use, and should hopefully help out others who are in the same dilemma that I was.

The AES Algorithm

The Advanced Encryption Standard is a widely used block cipher based on the Rinjdael encryption algorithm. And by based, I mean that AES is a subset of Rinjdael in that it has a fixed block size of 128 bits, whereas Rinjdael supports variable block lengths of 128, 192, or 256 bits. Do not confuse block length with key length. AES supports key lengths of 128, 192, or 256 bits (when you see references to AES-128, AES-192, or AES-256, the number indicates the key size and not the block size).

AES is a symmetric algorithm, meaning that the same key must be used both to encrypt and decrypt a message. Although the algorithm is strong, you must have a secure way of getting the key to both parties without anybody intercepting the key along the way and using it to read your messages. This is where we need an asymmetric encryption algorithm.

The RSA Algorithm

The RSA algorithm is an asymmetric, public key encryption method. This means that two different keys are involved: an encryption key and a decryption key. These keys are referred to as public and private keys, respectively. The private key is kept on the server away from prying eyes, while the public key can be sent to as many people as you desire--even your enemies. Anything encrypted with one of the keys can only be decrypted with the other--you can not even decrypt a message with the same key you encrypted it with. In this way, a server (say, a PHP script) can send you a public RSA key which you can then use to encrypt something that only the server can decrypt. This is how you can securely transmit your symmetric AES key to a remote host for use in the AES algorithm.

But why transmit and use an AES key when you already have RSA keys that you can use? Because, RSA is very slow. In fact, it is slow enough that we only want to use it long enough to transmit a single key for use in our symmetric algorithm. This is basically what is happening behind the scenes when you request a website on an HTTPS site. The server sends you the public key, you use the public key to encrypt a random key you generate, and then you send that encrypted key to the server to establish a session through which you can securely communicate via AES encrypted messages. This is exactly the way that my implementation works.

Please be aware that in real word applications, there is another step where your computer verifies that the public key you got from a web site is valid by verifying that it is signed by a certificate authority. Without this step, it is possible for a determined individual to pretend to be the web site you are trying to access by issuing you a public key that he himself made. This attacker could then intercept your messages half way by pretending to be the website you are trying to access, read the messages in plain text, then encrypt them with the real site's public key, and send them to the real site. Note that this attack is not prevented in this article, so you should not use this encryption here for anything that is too sensitive--for an application like this, you should buy a signed certificate for use with an SSL encrypted web site.

For the purpose of this article, we will be using a self singed RSA certificate. There is no need to buy a certificate for this application, as we are not going to check the signature anyway. We are not going to be having browser notifications in our application warning us that the issuer is not trusted. The keys we generate ourselves are far more secure than we really need them to be.

Encryption by Obscurity

This is a good time for me to warn you about the dangers of writing your own encryption algorithm. While it may be fun to write your own encryption scheme (and I have done so many times), it is not a good idea to use it for anything. I can't seem to stress this point enough. Many people (including myself at one point) think that by creating your own algorithm, your attackers will not know the algorithm or the keys, making it twice as difficult to break.

The flaw in this reasoning is two fold. One is that to decrypt something, you have to have the algorithm. If you have the algorithm, even if it's compiled into an obfuscated assembly, it can be decompiled and studied for flaws. If the strength of your algorithm relies at all, even a little bit, on someone not knowing your algorithm, then it's not a secure algorithm. All of the strength of the algorithm should rest in the strength of the chosen keys. Two, if you have a compromised key, then you only lose the information secured by that key, and anyone who was using a different key is still safe. If you have a compromised algorithm, then every bit of information, regardless of the key it was encrypted with, may be compromised. If the algorithm is found to be bad, then your scheme's 1024 bit keys may turn out to be worthless.

"But the entire world knows how the AES algorithm works! The algorithm is readily available and explained to anyone interested, so how can it be more secure than my own algorithm?" Simply put, AES and RSA have undergone extensive testing and have been scrutinized by experts. Really smart people all over the world spend a lot of time trying to break it, and have still failed. They have proven its strength by their failure. Always use an algorithm that has been proven to be secure, because you have no idea how many flaws you are overlooking when you make your own.

I think a comment by Garth J. Lancaster says it best when he states that even though people think that being obscure about security concerns is the best way, he would trust them less than an open solution he can verify. He says (and I definitely agree) that the only thing that should be private in an encryption scheme is the certificate or key. [Read Comment] If the encryption method is known, it should not weaken the encrypted information at all. In fact, if the attacker knows that you used AES, he might give up trying to break the algorithm from the start. All you have to do is generate cryptographically secure keys, and keep them safe.

Then there are the legal issues of writing your own algorithm. I'll forgo the details, so just suffice it to say that if you intend to use your own encryption scheme to store other people's sensitive information (credit cards or such like) and use a faulty method to do so, you could be in a lot of trouble. Always use an approved encryption scheme when you are dealing with other people's information. Have a look at the FIPS 140-2 standard at NIST.gov or see all the documents here. FIPS 140-3 is due to come out shortly, so keep an eye on it. You are required to adhere to these standards if you run a business. Stay away form DES, since it has been shown that a 56 bit DES key can be broken in under a day (a 64 bit DES key is actually only 56 bits, since the other 8 bits are just for parity).

Security risks aside, making your own algorithm (that's worth anything) takes a lot of time. Why not simply call the built-in encryption functions that are most likely provided by the language you are using? Experts created, tested, and optimized it just for you, so simply drop it in and use it.

Getting the Example to Work

Generating an RSA Key Pair using OpenSSL

For legal reasons, OpenSSL is not included in the download for this article. You can download it manually from here and follow the instructions below to install it. (Optionally, you can get it from the developer of OpenSSL, but then you would have to compile the source code yourself.)

Download the latest Light installer from the list. For me, this was v1.0.0d (32-bit). Run the installer and if you get a popup like the one below (see picture), click OK--we only need access to 3 files in this package so nothing bad is going to happen.

Image 2

When you get to the following "Copy OpenSSL DLLs to:" screen (see picture), select the "The OpenSSL binaries (/bin) directory" option.

Image 3

Now that OpenSSL is installed, navigate to the folder you installed it to in an Explorer window. I installed mine into the default location of C:\OpenSSL-Win32\bin. Once you are there, open a command window and CD to that directory (e.g., type "cd C:\OpenSSL-Win32\bin"). You are now ready to generate public and private RSA keys.

To generate your own RSA keys, type the following commands at the prompt.

Let's generate a 1024 bit RSA private key and store it as temp.key:

openssl genrsa -aes256 -out temp.key 1024

You can optionally change the 1024 above to 2048 if you want a more secure key (it's unnecessary though--even web sites mostly use 1024 bit keys); just know that it will be a bit slower when encrypting and decrypting. Now, to convert the private key to the format we will use:

openssl rsa -in temp.key -out private.key

During the next step, OpenSSL will ask you to enter some information about your web site. You can make this up however you want. Create the public certificate (for distribution to clients) like this:

openssl req -new -x509 -nodes -sha1 -key private.key -out public.crt -days 3650

If you prefer, included in the download is a .bat file that I wrote which you can simply copy into the bin folder of OpenSSL and run to generate an SSL key pair for you. It will pause to ask you for information such as a password and country information, so just give it what it wants and it will generate an RSA key pair for you.

A key pair that I made is included in the download for you to play with (in case you can't get it to work yourself or just want to skip this step). Please note that the whole world has access to that private key since it is available for download, so do not use it for anything important.

Now you have both the public and private keys necessary for RSA encryption. There is one more step we must take to keep our private key secure on the server. You will notice that the private key is saved in a .key file in plain text. If we upload this to our web site as-is, then anybody can view it by simply going to yoursite.com/private.key and downloading it. You can either set up your web server to disallow people from downloading .key files (the harder way and the way we won't do it), or you can store it in a variable in a PHP script. If you try to open the PHP file, you will just get a blank page instead of the key. To do this, we are just going to copy the contents of private.key into a PHP variable named $PrivateRSAKey, like this:

PHP
<?php $PrivateRSAKey = "-----BEGIN RSA PRIVATE KEY----- 
                        MIIEowIBAAKCAQE...0FgBdzxrcF0b
                        -----END RSA PRIVATE KEY-----"; ?>

Now we can just use the PHP include() function to load our private key into our PHP script. To use the functions in my encryption library, the variable must have the name given above ($PrivateRSAKey) or it will not be recognized. Also, make sure you do not upload the private.key file to your web server! That would be a big security mistake. Once you generate a good .php file for your private key, you might as well delete private.key so that it's not floating around. In the download, I have provided a simple tool (made from 5 lines of C#) to automatically convert a .key file to a variable in a .php file. You may use it if you are having problems copying and pasting the string and messing up the format or line ending characters.

You now have a public key in the format of a certificate (public.crt) and a private key stored in a PHP variable (private.php).

Setting up the PHP Scripts on the Server Side

The next step is to upload the PHP portion of this script to a web server that has PHP. I uploaded the PHP scripts to another computer on my local network that is running WAMP (Windows, Apache, MySQL, and PHP). Upload everything in the PHP folder of the download for this article to a folder on your web server that you want to access securely. I uploaded mine to my other computer's web root in a folder named "enc," so the scripts will be at http://skot2/enc/ for me. Next, add the public.crt and private.php files (created in step 1 above) in to this folder as well, overwriting the included sample keys. (If you would rather use my keys temporarily until you get things working, then skip copying the keys over until later.) Note that in the few seconds that it takes you to upload your private key to your web server, it is vulnerable to interception. If this is a problem, then you should either upload it via an HTTPS link to the web server or find a way to generate it on the server itself. This is the only time the private key will travel across the network.

The PHP encryption library this article uses is PHP Sec Lib. This library is an excellent pure PHP implementation of the common encryption algorithms that we will be using. The code for PHP Sec Lib is included in this download for your convenience, but can also be downloaded from SourceForge.

You now have the necessary files uploaded to your web site, and should have a working PHP script on the Internet that you can access from the C# side of the connection.

Setting up the C# Library on the Client Side

This is the easy part, as far as setting up a working example is concerned. Simply open up the solution file from the download in Visual Studio and hit Compile.

Running the Example

When the program runs, in the third box, type in the full URL to the example.php that you uploaded to your site (for me, this is http://skot2/enc/example.php), and click "Establish Connection". Give it a moment. When it says that the connection has been established (the "Send Message" button will become available), type in a message and hit "Send Message". If all works correctly, then you will get back a meaningful response from PHP (as opposed to garbage characters or a bomb-out).

The C# code example takes care of retrieving the public key from the server and using it to send a symmetric key it generates. If you want, you can also test out the HTTP asynchronous POST functionality if you enter the correct URL to test.php, or the RSA encryption (without transmitting an AES key) by entering the correct URL to rsa.php.

The example defaults to http://skot2/ because that is the name of the test computer on my home network.

Using the Code -- A walkthrough

Using the PHP Library

I'm going to show you how to use this library by walking you through the creation of a simple application: a high score submitter! We are going to make a lame game in C# (all you do is type in what you want your score to be). The game will post a user's high score to our secure PHP script which will return his ranking amongst all gamers. We are going to encrypt this transmission because we do not want sore losers to use HTTP interception software to capture the posted data (the score), modify their score, and then resend the package so that they can feel warm inside for cheating to the top of a score list.

Let's get started. Before we write our own, we will look at an example. If you have uploaded the entire examples folder, then you will have uploaded example.php also. As its name suggests, this is the example page that we will build off of. Its contents are displayed below:

PHP
<?php

// Set the location to the public and private keys
$PrivateKeyFile = "private.php";
$PublicKeyFile  = "public.crt";

include("secure.php");

if ($AESMessage != "")
{
   SendEncryptedResponse("Got: " . $AESMessage . ", GOOD!");
}

?>

As you can see, we simply set the location of the private key (in PHP format) and the public key, include the encryption library, and then write our own code to do whatever. Here are a few things to note...

  • No data can be output by your script except what is output by the SendEncryptedResponse() function.
  • The <?php tag must be the first thing in the file. If there is a space or new line before the opening <?php tag, then the script will crash. This is partly due to the fact that we are starting a Session, but also because we are outputting encrypted data, and a space before the message could mess up our C# application.
  • You must set both of the key file variables ($PrivateKeyFile and $PublicKeyFile), and you must set them before the include statement. $PrivateKeyFile should be set to the name of the PHP file containing your private key (generated above in section one) and $PublicKeyFile should be set to the location of the public certificate file.
  • The include statement, obviously, is also required to use the library.
  • Anything below the include() and above the ?> closing tag is your logic: how you will process the securely transmitted messages.

Here is how you process an encrypted incoming message:

Any time this script receives a valid encrypted message, it will automatically be decrypted with the AES decryption key in the currently established session (you will establish this from the C# side later). After it is decrypted, the message will be stored in the variable $AESMessage. If this variable is not empty (thus the check for != ""), then there is a plain text message in the variable that you can process however you want. In the example, I am just sending it back to the sender plus a little extra. We are going to change this a bit by first parsing out the winner's name and his score. Since we are going to eventually send these from the C# side in the format name(comma)score, let's parse out those two strings using PHP's explode(delimiter, string) function:

PHP
if ($AESMessage != "")
{
   // Get the username and high score from the message that was sent
   $split = explode(",", $AESMessage);
   $username = $split[0];
   $score = $split[1];
}

How about we add a little ranking code:

PHP
$rank = "";
if ($score < 100)
   $rank = "Loser!";
else if ($score < 1000)
   $rank = "Not bad...";
else if ($score < 10000)
   $rank = "Pretty Good.";
else if ($score < 100000)
   $rank = "Amazing!";
else if ($score < 1000000)
   $rank = "~YOU DA BOMB~";
else
   $rank = "YOU ARE A GRAND MASTER!";

Now that we have done what we wanted with the data sent to us, we can send an encrypted response back to the client that accessed this page by using the SendEncryptedResponse() function. This function automatically encrypts the text you give it and returns it to the client. Note that you can only call this function once, and once you call it, the script exits. Nothing will be processed after a call to this function. As a reminder, do not use any echo commands in your script anywhere, as this will mess up the response to the client. Here is how we respond:

PHP
SendEncryptedResponse("Name: " . $username . " Rank: " . $rank);

With the call of this function, you are done. The message you pass it will be encrypted and sent to the C# program that called this page in the first place. Here is the full source code for the PHP script:

PHP
<?php

// Set the location to the public and private keys
$PrivateKeyFile = "private.php";
$PublicKeyFile  = "public.crt";
include("secure.php");

if ($AESMessage != "")
{
   // Get the username and high score from the message that was sent
   $split = explode(",", $AESMessage);
   $username = $split[0];
   $score = $split[1];

   $rank = "";
   if ($score < 100)
      $rank = "Loser!";
   else if ($score < 1000)
      $rank = "Not bad...";
   else if ($score < 10000)
      $rank = "Pretty Good.";
   else if ($score < 100000)
      $rank = "Amazing!";
   else if ($score < 1000000)
      $rank = "~YOU DA BOMB~";
   else
      $rank = "YOU ARE A GRAND MASTER!";
      
   SendEncryptedResponse("Name: " . $username . " Rank: " . $rank);
}

?>

That is it for the PHP side of things. Let us move on to the C# library...

Using the C# Library

We got the pseudo-high-score-board all set up, now all we need to do is write a pseudo-game to send it some data. First, open up Visual Studio and start a new Windows Forms application. Once you are there, go ahead and drag a Textbox, a NumericUpDown, and a Button on to the form. Make it look pretty, add some Labels, and be sure to set the NumericUpDown's Maximum property to something really high, like a hundred million. Here is what I made my "game" interface look like:

Image 4

Now add an OnClick event to the button (double click the button in the Designer view). In the Solution Explorer pane, right click on References and click "Add Reference". Browse until you find the cs2phpCryptography.dll library and add it (you can find this in the Library folder of the download). Also make sure that you add a reference to the library at the top of your code-behind, like this:

C#
using CS2PHPCryptography;

Hopefully, you are not stuck. I am trying to be extra clear in case the people that are reading this article are mainly PHP developers and are not too familiar with C#.

Next, we are going to create a SecurePHPConnection object within the Form class, and instantiate it as follows:

C#
SecurePHPConnection secure;

public Form1()
{
    InitializeComponent();

    secure = new SecurePHPConnection();
}

Right below the instantiation statement, we are going to subscribe to two of the events in the class: OnConnectionEstablished and OnResponseReceived. OnConnectionEstablished will be raised when, as my self-documenting naming suggests, a secure connection has been established with a remote PHP script. OnResponseReceived will be raised whenever we get a response from the remote script (this only happens after we send a message). Here is how you subscribe:

C#
public Form1()
{
    InitializeComponent();

    secure = new SecurePHPConnection();
    secure.OnConnectionEstablished += 
      new SecurePHPConnection.ConnectionEstablishedHandler(
      secure_OnConnectionEstablished);
    secure.OnResponseReceived += 
      new SecurePHPConnection.ResponseReceivedHandler(
      secure_OnResponseReceived);
}

void secure_OnResponseReceived(object sender, ResponseReceivedEventArgs e)
{
    throw new NotImplementedException();
}

void secure_OnConnectionEstablished(object sender, 
            OnConnectionEstablishedArgs e)
{
    throw new NotImplementedException();
}

We are almost there. Now we need to give the class the location of the PHP script that it will be posting its information to. Here is how we can do it (substituting my URL for the location you uploaded your PHP script to):

C#
secure.SetRemotePhpScriptLocation("http://skot2/enc/score.php");

Now we can finally start the request for a secure connection. It takes a while since we are using RSA (and some of you are probably going to use 2048 bit keys and make it even slower), so I set it up to do all of its stuff in the background and call back via the aforementioned event when it succeeds. Here is what you do to start the call:

C#
secure.EstablishSecureConnectionAsync();

You may also wish to set the button's Enabled property to false so that the user cannot click the Send button until a connection has been established. Just add the following code:

C#
button1.Enabled = false;

Good! We have the connection being started when the program runs. Now in the event code for OnConnectionEstablished, we can enable the button to let the user know that it is OK to submit his high score now.

C#
void secure_OnConnectionEstablished(object sender, OnConnectionEstablishedArgs e)
{
    button1.Enabled = true;
}

The next thing we will add is the code to send the actual high score to the PHP script. We can add this in the button click event code. First, we will get the username and score and put them into a single string separated by a comma, just like we set up our PHP script to expect:

C#
private void button1_Click(object sender, EventArgs e)
{
    string name = textBox1.Text;
    decimal score = (int)numericUpDown1.Value;
    string message = name + "," + score.ToString();
}

Now we can send the message. After we check to make sure that it is OK to send a message in the first place, we can simply call the SendMessageSecureAsync() function to have our message automatically encrypted with a 256 bit AES key and sent to the PHP script.

C#
if (secure.OKToSendMessage)
{
    secure.SendMessageSecureAsync(message);
}

Once PHP processes the request and sends a response, we can process its response in the OnResponseReceived event. The variable e passed into the event contains the response from the remote server. I chose to use a MessageBox to display the response:

C#
void secure_OnResponseReceived(object sender, ResponseReceivedEventArgs e)
{
    MessageBox.Show(e.Response);
}

Now it is time to hit F5 to compile and test it out! Once the application starts, the button will be grayed out for a while until the connection is established. Once it is enabled, type in a name and a score, send it off, and see what happens.

Image 5

It works for me. Hopefully it worked for you as well. Here is the complete C# code listing for Lame Game:

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CS2PHPCryptography;

namespace Lame_Game
{
    public partial class Form1 : Form
    {
        SecurePHPConnection secure;

        public Form1()
        {
            InitializeComponent();

            secure = new SecurePHPConnection();
            secure.OnConnectionEstablished += 
              new SecurePHPConnection.ConnectionEstablishedHandler(
              secure_OnConnectionEstablished);
            secure.OnResponseReceived += 
              new SecurePHPConnection.ResponseReceivedHandler(
              secure_OnResponseReceived);

            secure.SetRemotePhpScriptLocation("http://skot2/enc/score.php");
            secure.EstablishSecureConnectionAsync();

            button1.Enabled = false;
        }

        void secure_OnResponseReceived(object sender, ResponseReceivedEventArgs e)
        {
            MessageBox.Show(e.Response);
        }

        void secure_OnConnectionEstablished(object sender, 
                    OnConnectionEstablishedArgs e)
        {
            button1.Enabled = true;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string name = textBox1.Text;
            decimal score = (int)numericUpDown1.Value;
            string message = name + "," + score.ToString();

            if (secure.OKToSendMessage)
            {
                secure.SendMessageSecureAsync(message);
            }
        }
    }
}

Pretty simple code considering that we are communicating with a remote server in AES encrypted messages. OK. Now on to the cool stuff...

How the Code Works

What Actually Goes Over the Internet?

I put together this diagram to visually demonstrate what is actually happening across the Internet:

Image 6

First, the C# program (from here on referred to as the client) posts to the PHP script (the server) the following plain text request: "getkey=y".

Second, the server sees that the client wants the public RSA key, so it gives it to him in plain text by returning it in the response to the web page request.

Third, the client generates a 256 bit AES key and a 128 bit initialization vector using a cryptographically secure random number generator. The key and the initialization vector (IV) make up the symmetric key that we need to have on both sides of the connection to correctly encrypt and decrypt using the AES algorithm. Both the key and the IV are encrypted separately using the public RSA key (provided by the server) and placed into the data section of a POST request which is then sent off to the server.

Fourth, the server uses its private RSA key to decrypt both the AES key and IV which it stores in a session variable on the server for use exclusively with this one client. If multiple clients are connected to the same server, they will each have a different AES key. The server now has the proper key it needs and uses it to send the string "AES OK", encrypted with the AES key, back to the client.

Fifth, the client gets the response from the server, decrypts it using the AES key that was just established for this session, then verifies that it says "AES OK". If not, then there is a problem. At this point, a secure connection has been established. Each time this initialization process takes place, a new AES key is made, used for just that session, and then discarded when done.

The last "stage" is more of a loop. The client sends any message it wants to the server, the server processes the request and sends a message back, and then the client processes the server's response. In the diagram above, the black arrows represent plain text travelling through the Internet, the blue line represents an RSA encrypted package, and the red lines represent AES encrypted messages.

When the client is done, he (optionally) sends the AES encrypted message "CLOSE CONNECTION" to the server who then destroys the session variables containing the AES keys and returns "DISCONNECTED".

Doing It In PHP

Getting RSA to Work

Keeping with the pattern I have made, we will first look at the PHP code. Since it is a lot shorter than the C# code, this works out well. Since the full code is way too long to print here, I will just present the code segments applicable to what I am currently talking about.

Let us start with RSA. Right off the bat, I want to let you know that the libraries I have written do not allow the server to encrypt with RSA nor the client to decrypt with RSA--you can only encrypt on the client side and decrypt on the server side (this only applies to RSA and not AES, which we have working both ways). This is not because I could not do it, but because for this implementation, I am only using RSA to transmit a symmetric key and thus do not need it to work both ways. Also, since the algorithm is slow, there is no reason why you would want to use RSA bidirectional unless you were using it for some sort of signature verification, and that is currently beyond the scope of this article.

First of all, the client will post to the server the variable "getkey=y". When the server sees this, it will simply spit out the entire public key file for the client and then exit.

PHP
//
// The remote user is requesting a public certificate.
//
if (isset($_POST['getkey']))
{
   echo file_get_contents($PublicKeyFile);
   exit;
}

Since we are using the pure PHP implementation of RSA from PHP Sec Lib, encryption in RSA is actually quite easy. I start out with a code example to initialize the engine for decryption:

PHP
$rsa = new Crypt_RSA();
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$rsa->loadKey($PrivateRSAKey);

Not too hard. Notice that the encryption mode is set to PKCS1 (v2.1), this is simply the encryption standard that we are using. The alternative to PKCS1 is OAEP (Optimal Asymmetric Encryption Padding), which is supposedly a little more secure, but we are not going to use it for this application. The PHP variable $PrivateRSAKey comes from the private.php file we generated earlier and included above. If you did not read that section, then just know that the private key file was copied in its plain text entirety from the .key file and in to a variable in a .php file so that people could not download it by typing the direct address to it in their browser. The private key itself is in the PKCS1 unencrypted format. And by unencrypted, I mean that the private key itself is not encrypted--it is totally capable of being used for encrypting.

When the client sends us the AES key he has chosen for us to use in this session, it will come encrypted with the public key the server gave him. Now is a good time to introduce the special URL Safe Base64 encoding I utilize throughout both the client and server code. Here is what it looks like in PHP:

PHP
function Base64UrlDecode($x)
{
   return base64_decode(str_replace(array('_','-'), array('/','+'), $x));
}

function Base64UrlEncode($x)
{
   return str_replace(array('/','+'), array('_','-'), base64_encode($x));
}

It is just standard base64 encoding with all the "/" characters replaced with "_" and all the "+" characters replaced with "-". This is the standard way of making a base64 encoded string URL friendly. We do not necessarily need to do this from the server side, but I chose to do it for all the transmissions just to make sure all messages use the same formatting.

Getting AES to Work

Going back to decrypting the AES keys that were sent to us encrypted with a public RSA key, let's look at how it is done:

PHP
$_SESSION['key'] = Base64UrlEncode($rsa->decrypt(Base64UrlDecode($_POST['key'])));
$_SESSION['iv']  = Base64UrlEncode($rsa->decrypt(Base64UrlDecode($_POST['iv'])));

Notice that the key and the initializing vector are sent separately and that they are base64 encoded. We decode the posted base64 encoded string to a byte array, decrypt it with the private RSA key we just loaded, re-base64 encode the byte array into a string, and then store it in a session variable for later use. Now we have a securely transmitted AES key that we can use for the rest of this session. The RSA decryption part runs slowly (a few seconds), but fortunately, this is the only place we need it--AES is set up now and it is really fast.

Here is how we get the AES portion working. Once again, initialization of the AES engine is pretty straightforward:

PHP
$aes = new Crypt_AES(CRYPT_AES_MODE_CBC);

$aes->setKeyLength(256);
$aes->setKey(Base64UrlDecode($_SESSION['key']));
$aes->setIV(Base64UrlDecode($_SESSION['iv']));
$aes->enablePadding(); // This is PKCS7

As you can see, we are setting the key length to 256 bits, the strongest allowed by AES. Next, we are setting the key itself to the AES key previously stored in $_SESSION['key'], and setting the initialization vector to the value stored in the current session as well. The padding that we are enabling is PKCS7 padding. The AES we are using requires that we pad our message to a multiple of the block size (a fixed 128 bits, or 16 bytes). There are several types of padding formats that can be used, and this is where some people cannot get their PHP encrypted messages to decrypt correctly in another language. PKCS7 pads the message to the correct length by adding bytes whose value is equal to the number of bytes that are added. Here is an example:

The string: T  H  I  S  I  S  A  T  E  S  T
In Hex:     54 48 49 53 49 53 41 54 45 53 54

Since the message is not in a multiple of 16 bytes (it's 11 bytes), we must add 5 (16 - 11 = 5) bytes to pad it out to length. With PKCS7 padding, each of the 5 bytes will have the hexadecimal value 05, the value coming from the number of bytes we are adding:

54 48 49 53 49 53 41 54 45 53 54 05 05 05 05 05

This padded message can then be sent through the AES cipher. Do not get this confused with zero padding where messages are just padded with zeroes, or with one of the many other padding schemes out there. We are choosing to use this one to get it to work with C#.

The CBC mode you see above is setting the AES block cipher's mode to use Cipher Block Chaining. This is what uses the initialization vector we are setting. The basic idea behind CBC is that each block is encrypted with some information obtained from the previous block in a message. This means that if you have any problem decrypting one block in a message, all subsequent blocks will be unreadable as well. An interesting aside is that the initialization vector does not necessarily need to be kept private (like the key does); however, it is a good idea to keep it safe anyway for extra security.

Next, to decrypt a message, we do as follows:

PHP
$AESMessage = $aes->decrypt(Base64UrlDecode($_POST['data']));

Noting again how we first get the bytes from the base64 encoded string before running it through the cipher. This line of code is where the $AESMessage variable is set that you can use to access whatever the client sent to you. Once the server processes what is in this variable, it will send back a response to the client using the SendEncryptedResponse() function. This function initializes the AES block cipher in the same manner as it was initialized above, and then does this:

PHP
echo Base64UrlEncode($aes->encrypt($message));

printing out the base64 encoded string containing an encrypted message. This is the message that the client will receive as a response to his encrypted HTTP request. After this, we call the PHP exit command to prevent the server from outputting any more text. If anything is output but one single encrypted message, then the client will get confused and explode (or at least give a notification that there was a problem).

The only aspect of the server side yet to discuss is where we destroy the session at the request of the client.

PHP
if ($AESMessage == "CLOSE CONNECTION")
{
   echo Base64UrlEncode($aes->encrypt("DISCONNECTED"));

   $_SESSION['key'] = "llama";
   $_SESSION['iv']  = "llama";
   unset($_SESSION['key']);
   unset($_SESSION['iv']);
   session_destroy();
   exit;
}

It may not be necessary to change the variable contents, then unset them, and then destroy the session, but it doesn't hurt. llama represents my bogus data, plus I hear they are good at destroying data. Just before we kill the session, we are going to send one last encrypted message to the client letting him know that we got his request to curl up and die. The downside to sending these commands in plain text like this is that if the client wants to send the string "CLOSE CONNECTION" for something he is doing unrelated to our protocol, it will close the connection on him.

That is it for the PHP code. Now we can delve into the client side C#.

Doing It In C#

Overview of the Helper Classes

There are quite a few aspects to the client side of this library that are not related directly to encryption. We will quickly browse over them just so you know what is happening when we call the functions later on.

Image 7 Image 8

First we will look at the HttpControl class which deals with sending the actual data across the Internet to the server.

C#
public string Post(string url, string data, ProxySettings settings)
{
    try
    {
        byte[] buffer = Encoding.ASCII.GetBytes(data);
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

        // Use a proxy
        if (settings.UseProxy)
        {
            IWebProxy proxy = request.Proxy;
            WebProxy myProxy = new WebProxy();

            Uri newUri = new Uri(settings.ProxyAddress);
            myProxy.Address = newUri;

            myProxy.Credentials = new NetworkCredential(
              settings.ProxyUsername, settings.ProxyPassword);
            request.Proxy = myProxy;
        }

        // Send request
        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = buffer.Length;
        request.CookieContainer = cookies;
        Stream postData = request.GetRequestStream();
        postData.Write(buffer, 0, buffer.Length);
        postData.Close();

        // Get and return response
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        Stream Answer = response.GetResponseStream();
        StreamReader answer = new StreamReader(Answer);
        return answer.ReadToEnd();
    }
    catch (Exception ex)
    {
        return "ERROR: " + ex.Message;
    }
}

This is pretty much the standard way to POST data to a website from C#. This class is provided in the library in addition to the cryptography stuff in case you ever need to use it. Notice the following important line of code:

C#
request.CookieContainer = cookies; 

This is where we make sure that we send back the cookie information which identifies our session. Without this line of code, we could not have PHP save our key and IV for use throughout the whole session, meaning each request we would make could not be linked with all of our other requests and we would have to resend a key with every transaction. When we explicitly send back the cookie that the server gives us (containing the SESSIONID of our connection), the server can look up our key and IV in its list of connected clients and resume our session.

Since I am often behind a proxy, I have added the necessary overloads to the POST and GET functions in case you ever need to send information through one. Ignore the fact that I am catching all errors and returning the error message in a string. Once in a while, you will not be able to access a page, and instead of getting an encrypted response, you will get an HTML formatted error which could break some stuff in the code.

There is also an AsyncHttpControl class that does exactly the same thing as the HttpControl, except all the calls to POST or GET will run in the background and raise an OnHttpResponse event with the response text when a response is received. This is nice in a UI environment where you do not want the UI to freeze up on the user.

Image 9

There is also a class called PostPackageBuilder that makes it a little more straightforward for creating POST data. You simply add an identifier and value pair to the collection through the AddVariable(varName, varValue) method and send it to the HttpControl class. If you do not want to manually concatenate your variables into a form of "x=1&y=2&z=llama", then this class will make things work smoother for you.

Image 10

The final helper class we will look at before we get to the encryption stuff is the static Utility class. This class currently only contains functions to encode and decode in our special URL friendly base64 format (already introduced in the PHP code above).

Image 11

Getting RSA to work

Let's get down to business. First I'm going to throw a class diagram of the RSA class at you, then we will discuss it.

Image 12

To use the classes that we are going to use to do the RSA encryption, we need two using statements:

C#
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

The certificate we have generated and are going to load is an X509 certificate, meaning that it contains, among other things, the public key, the name of the person who the certificate is made for, and how long the certificate is good for. For our purposes, we are going to ignore everything but the public key, since that is all we need for the moment. Verifying signatures and expiration dates is beyond the scope of this article.

This class contains a function to load a certificate from either a string or a file. The certificate in string format is simply the entire contents of the certificate file loaded in to a string; we can use this function to directly load a certificate from the server's response to our request for the public key. Here is what our sample 1024 bit public RSA certificate looks like:

-----BEGIN CERTIFICATE-----
MIID2jCCA0OgAwIBAgIJAPEru6Ch9es0MA0GCSqGSIb3DQEBBQUAMIGlMQswCQYD
VQQGEwJVUzEQMA4GA1UECBMHRmxvcmlkYTESMBAGA1UEBxMJUGVuc2Fjb2xhMRsw
GQYDVQQKExJTY290dCBUZXN0IENvbXBhbnkxGTAXBgNVBAsTEFNlY3VyaXR5IFNl
Y3Rpb24xFjAUBgNVBAMTDVNjb3R0IENsYXl0b24xIDAeBgkqhkiG9w0BCQEWEXNz
bEBzcGFya2hpdHouY29tMB4XDTExMDcwNDEzMDczM1oXDTIxMDcwMTEzMDczNFow
gaUxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdGbG9yaWRhMRIwEAYDVQQHEwlQZW5z
YWNvbGExGzAZBgNVBAoTElNjb3R0IFRlc3QgQ29tcGFueTEZMBcGA1UECxMQU2Vj
dXJpdHkgU2VjdGlvbjEWMBQGA1UEAxMNU2NvdHQgQ2xheXRvbjEgMB4GCSqGSIb3
DQEJARYRc3NsQHNwYXJraGl0ei5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
AoGBAKLEwtnhSD3sUMidycowAhupy59PMh8FYX6ebKy4NYqEiFONzrujkGtAZgmU
aCAQBEmGcfBUDVd4ew72Xjikq0WhBUju+wmrIcgnQcIMAXMkZ2gBV12SkvCzRrJf
5zqO0rC0x/tBli/46KGrzyYLl7K3QFx3MQPNvVO+w/b0coatAgMBAAGjggEOMIIB
CjAdBgNVHQ4EFgQU+6E6OauoEUohJOAgC8OXU3xaHn4wgdoGA1UdIwSB0jCBz4AU
+6E6OauoEUohJOAgC8OXU3xaHn6hgaukgagwgaUxCzAJBgNVBAYTAlVTMRAwDgYD
VQQIEwdGbG9yaWRhMRIwEAYDVQQHEwlQZW5zYWNvbGExGzAZBgNVBAoTElNjb3R0
IFRlc3QgQ29tcGFueTEZMBcGA1UECxMQU2VjdXJpdHkgU2VjdGlvbjEWMBQGA1UE
AxMNU2NvdHQgQ2xheXRvbjEgMB4GCSqGSIb3DQEJARYRc3NsQHNwYXJraGl0ei5j
b22CCQDxK7ugofXrNDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAJ8l
RVFiLgfxiHsrPvhY+i05FYnDskit9QTnBv2ScM7rfK+EKfOswjxv9sGdGqKaTYE6
84XCmrwxCx42hNOSgMGDiZAlNoBJdJbF/bw2Qr5HUmZ8G3L3UlB1+qyM0+JkXMqk
VcoIR7Ia5AGZHe9/QAwD3nA9rf3diH2LWATtgWNB
-----END CERTIFICATE-----

As you can see, it is a base64 encoded string sandwiched between a header and footer. The constructor for the X509Certificate2 class that we are going to use to load the certificate expects a string containing just the base64 part of this certificate, so we need to parse it out:

C#
key = key.Split(new string[] { "-----" }, StringSplitOptions.RemoveEmptyEntries)[1];
key.Replace("\n", "");

This will split the certificate into an array of three strings ["BEGIN CERTIFICATE", "MIID2jCC...ATtgWNB", "END CERTIFICATE"] of which we want the second element: the base64 encoded certificate. We also need to remove the line ending characters to reconstruct the base64 string into one long string since it is stored in the file in separate lines of 64 characters each.

Correctly reading in the certificate is one of the areas that might have been confusing for some of you trying to get this to work on your own, since one of the X509Certificate2 class' constructors expects an XML formatted certificate file, but you have a key generated by OpenSSL in a different format. You also may not have known exactly what to send to the constructor for a certificate in the format of a byte array. Now that we have the base64 encoded certificate string, we can decode it to a byte array and send it to the constructor:

C#
return new X509Certificate2(Convert.FromBase64String(key));

If any of the above statements fail while loading a key, we catch the general Exception and throw a FormatException because the only thing that should cause this code to fail is if the certificate entered was not in the expected format (for example, missing the "-----BEGIN CERTIFICATE-----" tag at the top).

Now that we have a public certificate, we can use it to encrypt stuff (later we will encrypt an AES key). Here is how we encrypt with the public key:

C#
RSACryptoServiceProvider publicprovider = (RSACryptoServiceProvider)cert.PublicKey.Key;
return publicprovider.Encrypt(message, false);

Remember that data encrypted with the public key can only be decrypted with the private key, and that you should only encrypt small messages with RSA because it's slow. Now we can look at the AES algorithm.

Getting AES to Work

Image 13

Take a look at the class diagram for the AEStoPHPCryptography class and then we will set up the AES engine. First, we are going to need to add a using statement for the following namespace:

C#
using System.Security.Cryptography;

Remember from the network model above that the client is responsible for generating the AES key and the initialization vector needed for encryption. We are going to do that first, like this:

C#
Key = new byte[256 / 8];
IV = new byte[128 / 8];

RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
random.GetBytes(Key);
random.GetBytes(IV);

The RNGCryptoServiceProvider class provides a pretty secure pseudorandom number generator which we are going to use to generate a new AES key each time we start a new connection to the server. Remember that each client will generate and use a different AES key, and that the server will keep track of which key to use with which client on the server side. Notice that the Key is a byte array 32 bytes (256 bits) long, and that the IV is a byte array of 16 bytes (128 bits) long. We fill both of the arrays with random bytes to use for our key. If the bytes are not random (say we type in a password instead), then we will severely reduce the security of our system. This is why we will just automatically generate the keys using a cryptographically secure random number generator.

Now that we have the keys, we can use them to both encrypt and decrypt (we will send them to the server in a different class, so hold on). First we are going to encrypt something. Let's initialize the AES engine:

C#
RijndaelManaged aes = new RijndaelManaged();
aes.Padding = PaddingMode.PKCS7;

You might be wondering why we are using the RinjdaelManaged class and not some AES class. This is because AES is essentially Rinjdael with a fixed key size (see the introduction at the top of this article for more information on this). Notice again that we are setting the padding to PKCS7. You will remember from the PHP section what this is (and if not, you can scroll up and look at it). Now we set the cipher to use CBC, a key size of 256 bits, and then give it the key and IV that we just generated.

C#
aes.Mode = CipherMode.CBC;
aes.KeySize = 256;
aes.Key = Key;
aes.IV = IV;

Here is where the actual magic happens. We create an ICryptoTransform object which will do the actual encryption for us:

C#
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

We are going to need a place to save the encrypted data too, so go create a MemoryStream:

C#
MemoryStream msEncrypt = new MemoryStream();

The CryptoStream is what we will write out the message into. It will use the specified encryption algorithm (AES) and write the data after it has been encrypted to whatever stream we give it, which in our case is a memory stream.

C#
CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);

We have a stream to write the encrypted data to, we have a stream to write plain text to that will encrypt the data, now we just need a StreamWriter to actually allow us to write to the encryption stream:

C#
StreamWriter swEncrypt = new StreamWriter(csEncrypt);

Here is where we write to the stream that encrypts the message and in turn writes the encrypted message to the MemoryStream:

C#
swEncrypt.Write(plainText);

Free up the resources that we were using:

C#
swEncrypt.Close();
csEncrypt.Close();
aes.Clear();

Finally, we return the encrypted data held in the MemoryStream in the form of a byte array. This is the data that we will then encode into a base64 string and send to the server.

C#
return msEncrypt.ToArray();

Decryption works in much the same way, except we create a Decryptor from the AES object instead of an Encryptor:

C#
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

And we read the bytes from the CryptoStream instead of writing to it:

C#
string plaintext = srDecrypt.ReadToEnd();

For your convenience, here is the complete code for the encryption function:

C#
/// <summary>
/// Encrypt a message and get the encrypted message in a URL safe form of base64.
/// </summary>
/// <param name="plainText">The message to encrypt.</param>
public string Encrypt(string plainText)
{
    return Utility.ToUrlSafeBase64(Encrypt2(plainText));
}

/// <summary>
/// Encrypt a message using AES.
/// </summary>
/// <param name="plainText">The message to encrypt.</param>
private byte[] Encrypt2(string plainText)
{
    try
    {
        RijndaelManaged aes = new RijndaelManaged();
        aes.Padding = PaddingMode.PKCS7;
        aes.Mode = CipherMode.CBC;
        aes.KeySize = 256;
        aes.Key = Key;
        aes.IV = IV;
        
        ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

        MemoryStream msEncrypt = new MemoryStream();
        CryptoStream csEncrypt = 
          new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
        StreamWriter swEncrypt = new StreamWriter(csEncrypt);

        swEncrypt.Write(plainText);

        swEncrypt.Close();
        csEncrypt.Close();
        aes.Clear();

        return msEncrypt.ToArray();
    } 
    catch (Exception ex)
    {
        throw new CryptographicException("Problem trying to encrypt.", ex);
    }
}

You should be able to get this particular function working in an application that does not use my library by just copying and pasting it in there, changing Utility.ToUrlSafeBase64 to Convert.ToBase64String, and making sure that you have a 32 byte long key array and a 16 byte long IV array created somewhere. But we are all using my library, right?

Making AES and RSA work between C# and PHP

At last, we arrive at the meat of the C# client library that this whole article has been leading up to: the SecurePHPConnection class! This class does everything for you. It will, in a background thread, do the following and then raise an event when it has established a secure connection:

  1. Ask the server for a public key
  2. Generate an AES key
  3. Use the public key to encrypt the AES key
  4. Send the encrypted AES key to the server
  5. Wait for a response and then raise the event that a secure connection is established

Once the connection is established, the rest (as the first) is abstracted away from you. You simply call a function to send a message and wait for a response by either blocking until you get a response or waiting for an event to be raised saying that you got a response.

Here is what we set up in the constructor:

C#
http = new HttpControl();
rsa = new RSAtoPHPCryptography();
aes = new AEStoPHPCryptography();

background = new BackgroundWorker();
background.DoWork += new DoWorkEventHandler(background_DoWork);
background.RunWorkerCompleted += 
  new RunWorkerCompletedEventHandler(background_RunWorkerCompleted);

sender = new BackgroundWorker();
sender.DoWork += new DoWorkEventHandler(sender_DoWork);
sender.RunWorkerCompleted += 
  new RunWorkerCompletedEventHandler(sender_RunWorkerCompleted);

As you can see, we are using the HttpControl for communication, the RSA class for the key exchange, and the AES class for general communication (all three of these classes have been previously discussed). We set up two background workers to handle the time consuming stuff without tying up the UI. The class defines two events that anyone can subscribe to:

C#
/// <summary>
/// Event raised when a secure connection
/// has been established with the remote PHP script.
/// </summary>
public event ConnectionEstablishedHandler OnConnectionEstablished;
public delegate void ConnectionEstablishedHandler(object sender, 
                     OnConnectionEstablishedEventArgs e);

/// <summary>
/// Event raised when an encrypted transmission
/// is received as a response to something you sent.
/// </summary>
public event ResponseReceivedHandler OnResponseReceived;
public delegate void ResponseReceivedHandler(object sender, 
                     ResponseReceivedEventArgs e);

The first one we will raise whenever we successfully complete our background connection routine of getting an RSA key, sending the AES key, and verifying that all is good. The second one we will raise whenever we receive a response to an asynchronous message that we had previously sent (we will not raise this event when the blocking SendMessageSecure() function is called, only for SendMessageSecureAsync()).

We are going to need to save the URL of the server's PHP script that we are going to contact, so we can write a simple set function like this:

C#
public void SetRemotePhpScriptLocation(string phpScriptLocation)
{
    address = phpScriptLocation;
    ...
}

And when the client is ready to start the secure connection, he calls this function to start the connection request in the background:

C#
public void EstablishSecureConnectionAsync()
{
    if (!background.IsBusy)
        background.RunWorkerAsync();
}

Here is the code to establish the actual connection. First we are going to send the request for the public certificate:

C#
string cert = http.Post(address, "getkey=y");

Once we get the certificate (in cert), we can use it to initialize our RSA cipher:

C#
rsa.LoadCertificateFromString(cert);

Next we tell out AES class to go ahead and generate a secure AES key and IV:

C#
aes.GenerateRandomKeys();

And encrypt them with the public RSA key we just got from the server:

C#
string key = Utility.ToUrlSafeBase64(rsa.Encrypt(aes.EncryptionKey));
string iv = Utility.ToUrlSafeBase64(rsa.Encrypt(aes.EncryptionIV));

Now we can securely send the key and the IV to the server for use in our secure session using the HttpControl:

C#
string result = http.Post(address, "key=" + key + "&iv=" + iv);

If all went well up to here, we should get the encrypted response from the server of "AES OK" indicating that all is well on both his side and our side. A secure tunnel (of sorts) has been created! We can now notify the client by raising the OnConnectionEstablished event:

C#
if (OnConnectionEstablished != null)
{
    OnConnectionEstablished(this, new OnConnectionEstablishedEventArgs());
}

Once the client knows that everything has been successfully set up to allow encrypted communication with the server, he can send as many messages as he wants using the SendMessageSecure() function. Here is what the code looks like:

C#
string encrypted = aes.Encrypt(message);
string response = http.Post(address, "data=" + encrypted);
return aes.Decrypt(response);

As you can see, the message is encrypted and sent in a regular POST request to the server. The response from the server is decrypted and returned to whomever called the function. This repeats until the client quits or sends a disconnection request.

And that is all there is to it! If you copy over the XML documentation with the .dll for this library, you should have access to enough documentation to help you use all of the features it provides to the fullest.

Summary

Hopefully this article was a help to those of you who either are having problems getting encryption to work between C# and PHP, or are just interested in anything encryption related. Either way, if you create anything really cool with this library, drop me a message--I would love to see it.

Links

License

All code included in the download to this article is released under the GPL v3. My library allows you to encrypt in C# and decrypt in PHP, and to encrypt in PHP and decrypt in C#, using either RSA or AES.

PHP Sec Lib, which is included in the download, is an Open Source project from SourceForge. (See links above.)

History

  • May 9, 2015
  • October 8, 2011
    • Fixed the SendMessageSecure() function
    • Fixed some broken header links
    • Added generate.bat and PhpSafeKey.exe to the download package
    • Added a rant section about encryption by obscurity
  • July 8, 2011
    • First posting of this article

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer
United States United States
Scott enjoys working on proof-of-concept projects for the sake of learning new and interesting ways to solve problems.

Comments and Discussions

 
QuestionLame Game and PHP Encryption (3rd Form) Not Working Pin
Eric Remigino23-Jun-13 16:40
Eric Remigino23-Jun-13 16:40 
AnswerRe: Lame Game and PHP Encryption (3rd Form) Not Working Pin
Eric Remigino24-Jun-13 10:12
Eric Remigino24-Jun-13 10:12 
GeneralRe: Lame Game and PHP Encryption (3rd Form) Not Working Pin
Scott Clayton25-Jun-13 14:57
Scott Clayton25-Jun-13 14:57 
QuestionWhat if... Pin
jfriedman15-Apr-13 17:37
jfriedman15-Apr-13 17:37 
AnswerRe: What if... Pin
Scott Clayton15-Apr-13 17:47
Scott Clayton15-Apr-13 17:47 
GeneralRe: What if... Pin
jfriedman15-Apr-13 18:01
jfriedman15-Apr-13 18:01 
GeneralRe: What if... Pin
Scott Clayton15-Apr-13 18:07
Scott Clayton15-Apr-13 18:07 
QuestionError when build keys Pin
PrgTools9-Feb-13 6:24
PrgTools9-Feb-13 6:24 
AnswerRe: Error when build keys Pin
Scott Clayton10-Feb-13 17:36
Scott Clayton10-Feb-13 17:36 
GeneralRe: Error when build keys Pin
PrgTools22-Feb-13 4:56
PrgTools22-Feb-13 4:56 
QuestionRe: Error when build keys Pin
PrgTools28-Feb-13 1:14
PrgTools28-Feb-13 1:14 
AnswerRe: Error when build keys Pin
Scott Clayton28-Feb-13 15:41
Scott Clayton28-Feb-13 15:41 
GeneralRe: Error when build keys Pin
PrgTools28-Feb-13 21:31
PrgTools28-Feb-13 21:31 
GeneralRe: Error when build keys Pin
PrgTools13-Mar-13 3:12
PrgTools13-Mar-13 3:12 
QuestionEncoding Pin
agira10-Dec-12 6:10
agira10-Dec-12 6:10 
AnswerRe: Encoding Pin
agira10-Dec-12 6:44
agira10-Dec-12 6:44 
GeneralRe: Encoding Pin
Scott Clayton10-Dec-12 17:28
Scott Clayton10-Dec-12 17:28 
QuestionSetting up Multi-Level CAs Pin
David Leedom31-Oct-12 6:45
David Leedom31-Oct-12 6:45 
AnswerRe: Setting up Multi-Level CAs Pin
Scott Clayton31-Oct-12 15:34
Scott Clayton31-Oct-12 15:34 
Generalproblem in communication Pin
Member 847013819-Jul-12 19:55
Member 847013819-Jul-12 19:55 
GeneralRe: problem in communication Pin
Scott Clayton20-Jul-12 1:24
Scott Clayton20-Jul-12 1:24 
GeneralRe: problem in communication Pin
Member 847013820-Jul-12 20:45
Member 847013820-Jul-12 20:45 
GeneralRe: problem in communication Pin
Scott Clayton21-Jul-12 4:16
Scott Clayton21-Jul-12 4:16 
QuestionHaving a problem with the Decrypt() function in C# Pin
WhitW17-May-12 2:15
WhitW17-May-12 2:15 
SuggestionRe: Having a problem with the Decrypt() function in C# Pin
Scott Clayton18-May-12 13:41
Scott Clayton18-May-12 13:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.