Pascal Warrior's Journey

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Sunday, 24 June 2012

Encryption / Decryption and Asynchronous Socket Programming

Posted on 09:25 by Unknown

Back again, it's been a long time since my last post due to lack of free time and laziness :p

Recently, I've got some posts in Lazarus / Free Pascal forums asking for some incompletely documented features, namely the (en|de)cryption unit (blowfish) and asynchronous socket (from fcl-net). Free Pascal is shipped with huge powerful libraries which are mostly, unfortunately, undocumented. Through this post, I hope I can help document it a bit through examples (I'm still lazy for real documentation commit :p). Let's start, shall we?

Blowfish, the cryptography unit

current documentation: http://www.freepascal.org/docs-html/fcl/blowfish/index.html

This unit implements encryption / decryption classes with keys, and is able to apply it on any TStream descendant. For easiness, we'll use TStringStream for the example. On to the code:

{$mode objfpc}{$H+}

uses
Classes,
BlowFish;

var
en: TBlowFishEncryptStream;
de: TBlowFishDeCryptStream;
s1,s2: TStringStream;
key,value,temp: String;
begin
{ 1 }
key := 'testkey';
value := 'this is a string';
{ 2 }
s1 := TStringStream.Create('');
en := TBlowFishEncryptStream.Create(key,s1);
{ 3 }
en.WriteAnsiString(value);
en.Free;
WriteLn('encrypted: ' + s1.DataString);
{ 4 }
s2 := TStringStream.Create(s1.DataString);
s1.Free;
{ 5 }
de := TBlowFishDeCryptStream.Create(key,s2);
{ 6 }
temp := de.ReadAnsiString;
WriteLn('decrypted: ' + temp);

de.Free;
s2.Free;
end.

Explanations per curly brackets:

  1. First, we prepare the key (key) and data to be encrypted (value)
  2. Next, we create a TBlowFishEncryptStream instance, providing the key and stream to write the encrypted data into (s1)
  3. Now we write the unencrypted data. For testing, we output the encrypted data. You'll see that it would be a bunch of weird bytes
  4. Next, we will try to decrypt the data back to its original form. First, we create another TStringStream, this time we give the encrypted data as the stream data
  5. Then we create a TBlowFishDeCryptStream instance, providing the key that was used to encrypt the data and the stream from which the encrypted data would be read
  6. Next, read the data and output it. You'll see it's the original 'this is a string'
So easy, huh? On to the next one.

fcl-net, the undocumented treasure

current documentation: err.. none

This package offers a lot of networking things: asychronous socket, dns resolver, HTTP servlet, socket streams, etc. We would concentrate only on the asychronous socket (and implicitly, socket streams). At first glance, it looks uneasy to use. I have to dig in the sources to see how it works and guess how to use it. We will implement a server with multiple client support. To stay focus, the client will only connect, send a 'hello' message, then disconnects. The server would display notification for an incoming connection, the message sent by the client, and when the client disconnects. The server can only be terminated with Ctrl+C. Jump in to the server code:

{$mode objfpc}{$H+}

uses
{ 1 }
{$ifdef unix}cthreads,{$endif}
Classes,SysUtils,Sockets,fpAsync,fpSock;

type
{ 2 }
TClientHandlerThread = class(TThread)
private
FClientStream: TSocketStream;
public
constructor Create(AClientStream: TSocketStream);
procedure Execute; override;
end;
{ 3 }
TTestServer = class(TTCPServer)
private
procedure TestOnConnect(Sender: TConnectionBasedSocket; AStream: TSocketStream);
public
constructor Create(AOwner: TComponent); override;
end;
{ 4 }
function AddrToString(Addr: TSockAddr): String;
begin
Result := NetAddrToStr(Addr.sin_addr) + ':' + IntToStr(Addr.sin_port);
end;

{ TClientHandlerThread }
{ 5 }
constructor TClientHandlerThread.Create(AClientStream: TSocketStream);
begin
inherited Create(false);
FreeOnTerminate := true;
FClientStream := AClientStream;
end;
{ 6 }
procedure TClientHandlerThread.Execute;
var
Msg : String;
Done: Boolean;
begin
Done := false;
repeat
try
Msg := FClientStream.ReadAnsiString;
WriteLn(AddrToString(FClientStream.PeerAddress) + ': ' + Msg);
except
on e: EStreamError do begin
Done := true;
end;
end;
until Done;
WriteLn(AddrToString(FClientStream.PeerAddress) + ' disconnected');
end;

{ TTestServer }
{ 7 }
procedure TTestServer.TestOnConnect(Sender: TConnectionBasedSocket; AStream: TSocketStream);
begin
WriteLn('Incoming connection from ' + AddrToString(AStream.PeerAddress));
TClientHandlerThread.Create(AStream);
end;
{ 8 }
constructor TTestServer.Create(AOwner: TComponent);
begin
inherited;
OnConnect := @TestOnConnect;
end;

{ main }
{ 9 }
var
ServerEventLoop: TEventLoop;
begin
ServerEventLoop := TEventLoop.Create;
with TTestServer.Create(nil) do begin
EventLoop := ServerEventLoop;
Port := 12000;
WriteLn('Serving...');
Active := true;
EventLoop.Run;
end;
ServerEventLoop.Free;
end.

It's a bit long, so take a breath:

  1. We will need each client to be handled in its own thread, so we need cthreads unit for *nix OSes
  2. The client handler thread, it would work on the given client socket stream
  3. The server, we will create an override constructor to hook when a client connects
  4. Helper routine to get ip:port as string
  5. Overriden constructor for the thread, will call the inherited constructor (with false argument to indicate the thread shouldn't be in suspended state), setting the object to free itself whenever the execution has finished, and assign the socket stream to a private attribute
  6. The core of the thread. Will try to read what the client sends and output it in the server log until the client disconnects
  7. OnConnect handler, prints notification message whenever a client connects and create a handler thread for it
  8. Overriden constructor for the server, assigns the OnConnect handler
  9. Main program. Create event loop object for the server, creates the server, assigning event loop and port to listen, and ready to accept connections...
Phew, go on to the client. This time it's simpler:

{$mode objfpc}{$H+}

uses
Classes,SysUtils,Sockets,fpAsync,fpSock;

var
ClientEventLoop: TEventLoop;
begin
ClientEventLoop := TEventLoop.Create;
with TTCPClient.Create(nil) do begin
EventLoop := ClientEventLoop;
Host := '127.0.0.1';
Port := 12000;
Active := true;
EventLoop.Run;
Stream.WriteAnsiString('Hello');
Active := false;
end;
ClientEventLoop.Free;
end.

Not numbered since it's only a single main code block. First it creates event loop for the client, create the client, assigning event loop, host and port of the server to connect, activate the connection, send a 'Hello' message to the server and disconnects. Clear enough, eh?

OK, that's all for now. Got any questions? Just ask :)
Read More
Posted in | No comments
Newer Posts Older Posts Home
Subscribe to: Comments (Atom)

Popular Posts

  • Android Programming with Lazarus through Custom Drawn Interface
    OK, so you've read that it's possible to write Android applications with Lazarus and Free Pascal. You go straight to the  wiki , fol...
  • Encryption / Decryption and Asynchronous Socket Programming
    Back again, it's been a long time since my last post due to lack of free time and laziness :p Recently, I've got some posts in Lazar...
  • Brook Framework, a new web application framework for Free Pascal
    Recently, a new post in Lazarus forum surprised me. Somebody, OK, Silvio, announced his new web application framework for Free Pascal with o...
  • LLVM IR Builder in Object Pascal
    I'm about to graduate from my university (January 2011 if there's no more problems), and as a final assigment (though it's optio...
  • Using Google Maps service in a Pascal based Web Application
    My final team assignment of Information Retrieval (IR) class allows us to create any kind of IR system, and we decided to create a food ingr...
  • Big mistake: wrong process model
    This is a lesson learn for application developer. Remember my last post about compiler with LLVM backend? It doesn't end happily. I didn...
  • Top Down Agile Program Development
    This time I would like to post something out of coding world, but rather something about software engineering. Traditional agile program dev...

Blog Archive

  • ►  2013 (2)
    • ►  October (1)
    • ►  January (1)
  • ▼  2012 (2)
    • ►  December (1)
    • ▼  June (1)
      • Encryption / Decryption and Asynchronous Socket Pr...
  • ►  2011 (1)
    • ►  January (1)
  • ►  2010 (2)
    • ►  December (2)
Powered by Blogger.

About Me

Unknown
View my complete profile