Hi,
Thank you for visiting my blog and especially having interest for this post.
I hope you understand It is written in the year of 2008, when it was the beginning of the Flex and the SSL socket is not provided yet so it was for the quick solution.
If Flex now supports SSL/TLS socket or if you just can use https, then use it simply. I hope you understand what I am saying.
----------------------------------------------------------
*Change log*
Feb-13-2009 : you can get the test.cpp file mentioned in this post, HERE .
Nov-18-2008 :
Changed the HTML for test.cpp codes. (Some characters were not visible before).
Preface
I think the IRC client is the most prefect start point for beginners who want to start making their own network client S/W.
Even though the IRC server itself is somewhat complex, the IRC client is basically comprised of 'string parsing' and the 'Socket send/receive'.
And basically IRC system is very useful and well designed one -at least, enough- and used by many online game services too.
On the google code pages, we can find somebody did excellent job of 'Flex IRC client', which is the IRC client written in Adobe's Flex.
http://code.google.com/p/
But as you can see, it does not support SSL connection. I bet you will need some secure channel on your C/S communication. There are many servers and clients which support SSL connetion, but for Flex side, SSL socket is not supported yet.
But hey, look at here. Another nice guy made us great Encryption library for Flex!!
http://code.google.com/p/
Even though that 'as3crypto' library does not support SSL Socket itself, but it does support for Assymetric/Symetric encryption/decryption functions and Digital certificate manipulations.
With this great library, we can make *Somewhat strong* connection between the Client (Our Flex socket application) and the Server.
The basic idea is very similar to the application level gateways like 'stunnel' (http://www.stunnel.org/).
The 'stunnel' acts as a SSL Wrapper for client and server. Your client connects to the 'stunnel' deamon (not directly to the Server), and the 'stunnel' deamon forwards the packets from client side to the Server, and vice versa.
And whe the 'stunnel' deamon makes a channel between the client and server, it negotiates some security informations (Some secure Key Exchanges, Authentications) and finally establishes the SSL channel between the 'stunnel' deamon and the client.
For simplicity, let say we have following network relation.
* Client<-(internet)->stunnel<->
In this, the SSL channel can be made between the client and the 'stunnel' deamon like this. (<= and => means the secure-encrypted- connection)
* Client<=(internet)=>stunnel<->
(OF COURSE, YOU CAN DO MUCH MORE COMPLEX THINGS USING stunnel. I am just telling you the concept of stunnel I am trying to immitate for our Flex application)
But you can not use 'stunnel' directly for Flex, because we don't have SSL connection support from the Flex, yet. (Officially)
Ok, so what we are going to do now is the make another *Application gateway* acts simliarily to the 'stunnel', understanding the Flex's situation.
Stream Cipher and the Key Exchange
Because Flex is using 'ActionScript' which is somewhat SLOW compared to the speed of other compiled languages, we can not use strong 'Block cipher algorithms' in Flex. Yeah, we can use but your customers will encounter the heavy slow down on their system.
So, I recommend to use 'Stream Cipher'. There are many 'Stream Cipher' algorithms but if I explain very simply, it is like using XOR bitwise operator.
In XOR operation, this is possible.
A XOR B -> C.
C XOR B -> A.
If we encrypt and decrypt this way, our Flex application will *FLY*
Anyway, if we want to encrypt and decrypt data, the both ends should know about the 'key' they are using. For example, our client wants to encrypt and decrypt data by using the key "0abb23c". Then the server should also use nothing but and only but the key "0abb23c".
Then how can our both ends (C/S) know that key? Of course any one end can send the key information to the other at the beginning. But we also know that anybody who have packet sniffing tool and can access your subnet or in the way between the C/S can see all those information clearly.
Then how can we exchange that 'key' information more securely? For that need, we can use PKI encryption by using our fancy library 'as3crypto'.
The basic idea for this secure key exchange is similar to 'Diffie Hellman' (http://en.wikipedia.org/wiki/
In this article, I am going to use following simple model.
1. Server has it's own Private key and Public key pair.
2. Client only knows the Server's Public key.
3. Client generates random key for encryption/decryption (stream cipher).
4. And the Client encrypts that stream cipher Key *with Server's public key*
5. Now the Client sends that encrypted stream cipher key to the server.
6. The Server, and only the server, can decrypt that information, because only the owner of the Private key (matching the public key the client used for encryption) can decrypt it.
7. Now the Server decrypt, and finally the server knows the Actual stream cipher key both the client and the server will use.
8. The Key negoiation is finished. Now whenever both ends send/recive data, they will use the 'shared' stream cipher key and encrypt/dacrypt data.
Our Application Gateway
As I explained before, our Application gateway is very simple. Basically,
1. The application gateway listens on the connection from the client.
2. If the connection from client is accpted, the the application gateway negotiatte the key with the client.
3. Now the application gateway connets to the Server and remember which server connection is for the connection from which client.
4. Whenever the client sends the data, the application gateway decrypts and forward it to the server.
5. Whenever the server sends the data to the application gateway, it encrypts the data and forward to the client.
6. If the client close the connection, the application gateway also close the connection for the server, and vice versa.
Because our application gateway will have bunch of client connection simultaneously, you better make it with 'epoll'(http://www.
Anyway, I am not going to give you the server side Listen/Accpet/Close sample code. I think you can make your own simple one.
Instead, I am going to give you my ugly test code for the Key exchange steps.
Some code for the Flex client
1. First of all, you have check out the source code of 'as3crypto' library.
Add it to your own Flex project.
2. Now you need to import following name spaces
import com.hurlant.crypto.cert.
import com.hurlant.crypto.rsa.RSAKey;
import com.hurlant.util.Hex;
3. Define variable for the 'stream cipher key'.
private var _enckey:ByteArray = new ByteArray();
4. Generate key for the 'stream cipher'
I simply used 16 byte key for the stream cipher, so simply loop this line 16 times....
_enckey.writeByte( (Math.random()*int.MIN_VALUE) as int );
5. Encrypt the stream cipher key with the Server's public key.
I this example, I hardcoded the server's 'Digital certificate' information.
For more information how you can generate your own certificate, please refer to the following URL.
http://sial.org/howto/openssl/
1 // I removed some part of the certificate.. 2 var strCert:String = new String("-----BEGIN CERTIFICATE-----MIICXTCCAcagAwIBAgIJAIkFiuBR2Dr1MA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNVBAYTAmpwMQ4wDAYDV...................mPRFCNRkrwaJVRWrhMBVKUX6eC9i3dsIAYdp+x9GbQq+8Bm0SnlNEZzgb2wCTbg-----END CERTIFICATE-----"); 3 var cert:X509Certificate = new X509Certificate(strCert); 4 var rsa:RSAKey = cert.getPublicKey(); 5 var ex1dst:ByteArray = new ByteArray; 6 rsa.encrypt(_enckey, ex1dst, _enckey.length);
6. Send the encrypted key, RIGHT AFTER you are connected to the server
_socket.writeBytes(ex1dst);
_socket.flush();
** '_socket' is the Socket type variable, for our connection.
5. Now, whenever you receive and send data, encrypt(for send) and decrypt(for receive) it.
For example, this code is from the 'flexircclient' but you can see how you can encrypt when you send and receive.
We just do XOR....
6. That's all :)
Some code for the Application gateway
First of all, please refer to my sample CPP file. *This is just a little modification and combination of codes from Apache*
You can compile it like this in Linux environment.
g++ test.cpp -lssl
you can get this file HERE .
--
You can use some of the functions in the code above like this in your Application gateway side.
* If new connection is accepted
2 if( NEW CONNECTION FROM THE CLIENT IS MADE ) 3 { 4 // 1. Read the Encryption key from the client 5 // In my Flex client sample, the client will send 128 byte.. 6 char szPubEncKey[1024]; 7 _readDataFromSocket(hClientSock, (char*)szPubEncKey, 128); 8 9 // 2. Decrypt the Encryption key. 10 char enckey[1024]; 11 int iDstLen = 1024; 12 DecryptBinaryFromClient(g_RsaPrivateKey,szPubEncKey, 128, enckey, &iDstLen); 13 14 // 3. Set the Encryption key for this session. 15 //unsigned char enckey[KEYLENGTH]; 16 memcpy( g_SockTbl_Client[hClientSock].enckey, enckey, KEYLENGTH); 17 18 // 4. Connect to the server 19 //... 20 21 // 5. Save client/server socket pair and the key. 22 //........ 23 //........ 24 }
* Whenever we need to send and receive..
1. We just do XOR
1 #define KEYLENGTH 16 2 for( int k=0; k<iRead; k++) 3 { 4 Databuffer[k] ^= enckeyForASocket[k%KEYLENGTH]; 5 }
Remarks..
I will try to revise this article continuously. I also think it will be more understandable if I add some pictures here.. But Today, I don't have much time. It's already time to go home. +)
If you have any questions, please write some comments. I will try to follow up.
Best..
hey bruce, i like ur work. i'm surprised how little discussion there is on the web for ways to create a secure channel between a flex 3 / air client and server?? i'll give it a go and let you know how i get on.
ReplyDeleteThank you, Matso. (松雄さん?)
ReplyDeleteThank you very much for your interest and help. :)
I wish you have sweet new year!
Best regards.,
Hello,
ReplyDeleteThanks :)
Dear Bruce,
ReplyDeleteJust so you know, your algorithm is not TSL. Its not bad. But you should know that it is susceptible to both a man-in-the-middle attack and a reflect attack (Attacker spoofs the client resending the first message). Adding a nounce after the first message would fix it; however, SSL/TSL are already invented. Why reinvent the wheel?
Hi, someone with no name.
ReplyDeleteAre you asking why I implemented this? It is written clear that at the time of 2008,
> "but for Flex side, SSL socket is not supported yet."
And sure, this is one way so MTM is possible. But I don't think adding a nonce after first message is not enough. More cleary, at the first messge from client, the server should verify, and the server should send another message for establishing a 'final' key what both sides know.
So, are you asking 'why I didn't implemented it perfect like TLS?' another my point is written in the post clearly saying that
> "Because Flex is using 'ActionScript' which is somewhat SLOW compared to the speed of other compiled languages, we can not use strong 'Block cipher algorithms' in Flex. Yeah, we can use but your customers will encounter the heavy slow down on their system."
I wonder, did you ever read my post once and the date it is written?
And if you were me, would you just wait or give up your project if there is no proper solution at the moment? (till Adobe or somebody implement?), or would you spend very much of your time for implementing a single funtion for just make it perfect like standard one? and postpone your release date?