Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Example of a encrypted client/server useing Crypt::Blowfish

by lindex (Friar)
on Aug 28, 2000 at 05:00 UTC ( [id://29945]=sourcecode: print w/replies, xml ) Need Help??
Category: Networking
Author/Contact Info Jason M. Mills <jason@gost.net>
or lindex
Description:

I am currently working on an open source project to produce a full featured administration package in perl for hlds (half-life server) geared twards the Counterstrike mod for the game. We wanted to provide a all in one script package to monitor user activity as well as provide a method for administrators to access the server and monitor/chat/admin without starting up the half-life game on a windows machine. We decided the best way to provide remote administration with these restrictions was to write a server and client to handle all the parsing and command sending. Now because this package is meant to be used by ISP's to admin there hlds gameservers security is an issue. Being as it is my job to write the client and server I had to deal with the issue of creating a encrypted session between the client and server, and that brings me to my point, This is a test(demo) of a server and client useing Crypt::Blowfish to encrypt the session between the client and server. So basicly its just a encrypted echo server & echo client :)

Use this to make a key:
perl -e 'print pack("H16",join("",map{$_=chr(int(rand(177)));}(1..56))
+);' >>keyfile.key
Here is the server:
#!/usr/bin/perl -w

#
# bleh bleh OO perl ownz j00
#
use strict;
use Crypt::Blowfish;
use IO::Socket;
use Fcntl qw(:flock);
use vars qw($sock $cipher $acpt_sock $key $pid $in);

#
# takes a string of any size and pads string with SOH char
# if the string does not split into $blocksize byte segments evenly
#
sub pad {
  my($string) = shift;
  my($blocksize) = shift;  
  my($strlen) = length($string);
  
  
  return($string) if ($strlen == $blocksize);
  return($string.chr(1)x($blocksize - $strlen)) if ($strlen < $blocksi
+ze);
  if ($strlen > $blocksize) {
    while($strlen = $strlen - $blocksize) {
      last if ($strlen < $blocksize);
    }
    return($string.chr(1)x($blocksize - $strlen));
  }

  return($string);
}

#
# takes a Crypt::Blowfish handle and a string of any size
# then uses pads string useing pad() function then chunks
# off 8 byte segments of string and encrypt's those and 
# assembles encrypted string in a scalar to be returned 
#
sub encrypt {
        my($handle) = shift || return(undef());
        my($string) = pad(shift,8) || return(undef());
        my($ret,$offset);
        
        $offset = 0;
        while(defined($_ = substr($string,$offset,8))) {
                $ret .= $handle->encrypt($_) unless(!$_);
                $offset = int($offset) + 8;
                last if ($offset >= length($string));
        }
        return($ret);
}

# 
# takes encrypted string (in binary of course).
# then decryptes string in 8 byte segments
# and assembles in scalar to be returned
#
sub decrypt {
        my($handle) = shift || return(undef());
        my($string) = shift || return(undef());
        my($ret,$offset);

        $offset = 0;
        while(defined($_ = substr($string,$offset,8))) {
                $ret .= $handle->decrypt($_) unless(!$_);
                $offset = int($offset) + 8;
                last if ($offset >= length($string));
        }
        return($ret);
}
        
#
# main code starts here (i.e. not sub routines)
#

#
# spout usage is less than or more than one argument
#
die "Usage: $0 <keyfile>\n" unless(@ARGV==1);

#
# read in key file for use with Crypt::Blowfish
# 
local(*KEY);
open(KEY,$ARGV[0]) || die "$!: \"$ARGV[0]\"\n";
flock(KEY,LOCK_EX);
$key = <KEY>;
close(KEY);

#
# build my Crypt::Blowfish handle useing $key
#
$cipher = new Crypt::Blowfish $key;

#
# build my IO::Socket handle for being a tcp server
#
$sock = IO::Socket::INET->new(
        LocalPort =>9200, # set port to listen on to 9200
        Listen    =>5, # Accept only 5 connections at once (pointless)
        Proto     =>'tcp', # use tcp proto
        Reuse     =>1 # my kernel happy by free ports immediatly
);

#
# loop to handle accepting connections as well as server 
# type mombo jumpo such as server codes, parsing, decryption
#
while($acpt_sock = $sock->accept()) {
        print "Connection from ",$acpt_sock->peerhost(),":",$acpt_sock
+->peerport(),"\n" unless(!$acpt_sock);
        unless($pid = fork() && $acpt_sock) {
                print $acpt_sock "-OK- Crypted Server\n\r" unless(!$ac
+pt_sock);
                while(<$acpt_sock>) {
                        s/(\r|\n)//g;
                        print $acpt_sock encrypt($cipher,decrypt($ciph
+er,$_)),"\r\n";
                }
                print "Connection closed by ",$acpt_sock->peerhost(),"
+:",$acpt_sock->peerport(),"\n" unless(!$acpt_sock);
                close($acpt_sock);
                exit(0);
        }
}
And here is the client:
#!/usr/bin/perl -w

#
# bleh bleh OO perl ownz j00
#
use strict;
use Crypt::Blowfish;
use IO::Socket;
use Term::ReadLine;
use Fcntl qw(:flock);
use vars qw($sock $cipher $acpt_sock $key $in $term);

#
# takes a string of any size and pads string with SOH char
# if the string does not split into $blocksize byte segments evenly
#
sub pad {
  my($string) = shift;
  my($blocksize) = shift;  
  my($strlen) = length($string);
  
  
  return($string) if ($strlen == $blocksize);
  return($string.chr(1)x($blocksize - $strlen)) if ($strlen < $blocksi
+ze);
  if ($strlen > $blocksize) {
    while($strlen = $strlen - $blocksize) {
      last if ($strlen < $blocksize);
    }
    return($string.chr(1)x($blocksize - $strlen));
  }

  return($string);
}

#
# takes a Crypt::Blowfish handle and a string of any size
# then uses pads string useing pad() function then chunks
# off 8 byte segments of string and encrypt's those and 
# assembles encrypted string in a scalar to be returned 
#
sub encrypt {
        my($handle) = shift || return(undef());
        my($string) = pad(shift,8) || return(undef());
        my($ret,$offset);
        
        $offset = 0;
        while(defined($_ = substr($string,$offset,8))) {
                $ret .= $handle->encrypt($_) unless(!$_);
                $offset = int($offset) + 8;
                last if ($offset >= length($string));
        }
        return($ret);
}

# 
# takes encrypted string (in binary of course)
# then decryptes string in 8 byte segments
# and assembles in scalar to be returned
#
sub decrypt {
        my($handle) = shift || return(undef());
        my($string) = shift || return(undef());
        my($ret,$offset);

        $offset = 0;
        while(defined($_ = substr($string,$offset,8))) {
                $ret .= $handle->decrypt($_) unless(!$_);
                $offset = int($offset) + 8;
                last if ($offset >= length($string));
        }
        return($ret);
}
        
#
# prompts user for data
#
sub prompt {
        my($handle) = shift;
        my($prompt) = shift;
        my($ret);
        while(!($ret = $handle->readline($prompt))) {};
        return($ret);
}

#
# main code starts here (i.e. not sub routines)
#

#
# spout usage is less than or more than two argument
#
die "Usage: $0 <hostname> <keyfile>\n" unless(@ARGV==2);

#
# read in key file for use with Crypt::Blowfish
# 
local(*KEY);
open(KEY,$ARGV[1]) || die "$!: \"$ARGV[0]\"\n";
flock(KEY,LOCK_EX);
$key = <KEY>;
close(KEY);

#
# buile my Crypt::Blowfish handle useing $key
#
$cipher = new Crypt::Blowfish $key;

#
# build my IO::Socket handle for being a tcp client
#
$sock = IO::Socket::INET->new(
        PeerAddr =>$ARGV[0], # set host to connect to from $ARGV[0]
        PeerPort =>9200, # connecting to port 9200 on PeerAddr
        Proto    =>'tcp' # we are using tcp proto       
);

die "Could not connect to $ARGV[0] !\n" unless($sock);
#
# build my Term::ReadLine handle;
#
$term = new Term::ReadLine undef;
$term->ornaments(0);

#
# check for server output dont do crap until gotten -ok-
#
while(<$sock>) {
        if (/-ok- crypted server/i) {
                print "*** Connected to server ***\n";
                last;
        }
}

#
# loop for server output and user input
#
while($_ = prompt($term,"> ")) {
        die "Lost connection to $ARGV[0]\n" unless($sock);
        print $sock encrypt($cipher,$_),"\r\n"; 
        $in = <$sock>;
        $in =~ s/(\r|\n)//g;
        print decrypt($cipher,$in),"\n";
        undef($in);
}
P.S. this is just test code, only a demonstration on how one
would write such a client/server :)
Replies are listed 'Best First'.
RE: Example of a encrypted client/server useing Crypt::Blowfish
by lindex (Friar) on Aug 28, 2000 at 15:34 UTC
    Note:
    turnstep mentioned that one may want to put an "or die" on the flock calls.
    With the method Iam calling flock, the program will "hang" or wait for the lock on the file.
    I prefer this, some ppl dont, so its up to you. Being as this is only example code I oped not to
    change the orignal version :)
    But do what you will.

    Note(2):
    turnstep yet agian mentioned my failing with flock, being
    that files are never a constent, so It is a very good thing to
    a an "or die" to each of the flock calls. for more information
    consult your systems man page on flock :)



    lindex
    /****************************/ jason@gost.net, wh@ckz.org http://jason.gost.net /*****************************/

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: sourcecode [id://29945]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2024-04-19 06:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found