Crypt-HCE_SHA-0.75/0000755000175000017500000000000012677541517012303 5ustar ericericCrypt-HCE_SHA-0.75/META.yml0000644000175000017500000000073312677541517013557 0ustar ericeric--- abstract: unknown author: - unknown build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150001' license: unknown meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Crypt-HCE_SHA no_index: directory: - t - inc requires: Digest::SHA: '0' MIME::Base64: '2' version: '0.75' Crypt-HCE_SHA-0.75/examples/0000755000175000017500000000000012677541517014121 5ustar ericericCrypt-HCE_SHA-0.75/examples/Server.pm0000644000175000017500000000705612677541277015740 0ustar ericericpackage Server; use IO::Select; use IO::Socket; use strict; use Carp; use Sys::Syslog; use Crypt::HCE_SHA; my @response; my $data; sub new { my $class = shift; my $self = {}; bless $self, $class; if ((scalar(@_) % 2) != 0) { croak "incorrect number of parameters"; } while (@_) { my $key = shift(@_); my $value = shift(@_); $self->{$key} = $value; } $self->_initialize; return $self; } sub _initialize { my $self = shift; if (!defined($self->{'Server'})) { croak "Server not initialized properly : Server parameter missing"; } if (!defined($self->{'Port'})) { croak "Server not initialized properly : Port parameter missing"; } if (!defined($self->{'Queue'})) { croak "Server not initialized properly : Queue parameter missing"; } if (!eval {$self->{'Socket'} = IO::Socket::INET->new(LocalAddr => $self->{'Server'}, LocalPort => $self->{'Port'}, Proto => 'tcp', Reuse => 1, Listen => $self->{'Queue'} ); }) { croak "Server couldn't establish a port on $self->{'Server'}"; } $self->{'Socket'}->autoflush(1); delete $self->{'HCE'}; $self->{'Select'} = IO::Select->new($self->{'Socket'}); } sub accept { my $self = shift; my ($time) = @_; # how long to wait my (@ready_to_read, $size); @ready_to_read = $self->{'Select'}->can_read($time); $size = scalar(@ready_to_read); if ($size == 1) { $self->{'Connect'} = $self->{'Socket'}->accept; $self->{'Connect'}->autoflush(1); # don't buffer return messages } else { delete $self->{'Connect'}; } return $size; } sub close { my $self = shift; $self->{'Connect'}->close; delete $self->{'Connect'}; delete $self->{'HCE'}; return 0; } sub send { my $self = shift; my @items = @_; my ($item, $enc_item); if (!defined($self->{'Connect'})) { croak "No Connection established: did you accept?"; } if (defined($self->{'HCE'})) { foreach $item (@items) { # syslog('debug','Server encode: %s',$item); $enc_item = $self->{'HCE'}->hce_block_encode_mime($item); # syslog('debug','Server sending: %s', $enc_item); print { $self->{'Connect'} } "$enc_item\n"; } $enc_item = $self->{'HCE'}->hce_block_encode_mime("+END_OF_LIST"); print { $self->{'Connect'} } "$enc_item\n"; } else { foreach $item (@items) { # syslog('debug','Server sending: %s',$item); print { $self->{'Connect'} } "$item\n"; } } return 0; } sub recv { my $self = shift; my ($data, $dec_data, $fh); if (!defined($self->{'Connect'})) { croak "No Connection established: did you accept?"; } $fh = $self->{'Connect'}; undef(@response); if (!defined($self->{'SKey'})) { while (<$fh>) { chomp; # syslog('debug','Server recv: %s', $_); tr/\n\r\t//d; last if ($_ eq '+END_OF_LIST'); push @response, $_; }; if (!defined(@response)) { return; } else { return @response; } } if (defined($self->{'HCE'})) { while (<$fh>) { chomp; # syslog('debug','Server recv: %s',$_); $dec_data = $self->{'HCE'}->hce_block_decode_mime($_); $dec_data =~ tr/\n\r\t//d; # syslog('debug','Server decode: %s', $dec_data); last if ($dec_data eq "+END_OF_LIST"); push @response, $dec_data; }; if (!defined(@response)) { return; } else { return @response; }; } else { $_ = <$fh>; # get RKey chomp; $self->{'RKey'} = $_; $self->{'HCE'} = Crypt::HCE_SHA->new($self->{'SKey'}, $self->{'RKey'}); return $self->recv(); } } 1; __END__ #------- POD ------ Crypt-HCE_SHA-0.75/examples/HOW_TO_USE0000644000175000017500000000273207754540476015626 0ustar ericericServer side (who you are sending your request to) use Server; $server = Server->new(Server => name_of_host_to_bind_too, Port => port_number, Queue => size_of_queue, SKey => 'shaReDSEcrET'); LOOP: while ($ready_to_read = $server->accept()) { # wait for next connection @info = $server->recv(); # @info now contains all of the data sent from the client # already de-crypted # to send info back to the client $server->send("information", "to send", "back", "to" "client"); $server->close(); } additional notes: name_of_host_to_bind_too is usually the dns name assigned to the local box or ip address port_number for port's under 1024 you must be root to open size_of_queue is the amount of backlog before a requested connection is rejected Client Side (who you are sending your request from) use Client; $client = Client->new(Server => name_of_server_to_connect_to, Port => port_number, SKey => 'shaReDSEcrET'); $client->send("information", "to", "send", "to" "the server"); @response = $client->recv(); print "response = @response\n"; additional notes: the Client module closes the connection after doing a recv. So to have more than one exchange you need to issue a Client->new for each pair, or you can modify the Client->recv code } else { close ($self->{'Socket'}); # remove this line return @response; } if you modify the code you must close the socket yourself somewhere else close ($client->{'Socket'}); Crypt-HCE_SHA-0.75/examples/Client.pm0000644000175000017500000000555712677541244015706 0ustar ericericpackage Client; use IO::Select; use IO::Socket; use strict; use Carp; use Sys::Syslog; use Crypt::HCE_SHA; my @response; my $data; sub new { my $class = shift; my $self = {}; bless $self, $class; if ((scalar(@_) % 2) != 0) { croak "incorrect number of parameters"; } while (@_) { my $key = shift(@_); my $value = shift(@_); $self->{$key} = $value; } $self->_initialize; return $self; } sub _initialize { my $self = shift; my $timeout; if (!defined($self->{'Server'})) { croak "Client not initialized properly : Server parameter missing"; } if (!defined($self->{'Port'})) { croak "Client not initialized properly : Port parameter missing"; } if (!defined($self->{'SKey'})) { croak "Client not initialized properly : SKey parameter missing"; } if (!eval {$self->{'Socket'} = IO::Socket::INET->new(PeerAddr => $self->{'Server'}, PeerPort => $self->{'Port'}, Proto => 'tcp', Reuse => 1); }) { croak "Client couldn't establish a connection to $self->{'Server'}"; } $self->{'Socket'}->autoflush(1); srand($$|time()); # poor random generator should be replaced $self->{'RKey'} = rand(100000000)+1000000; $self->{'HCE'} = Crypt::HCE_SHA->new($self->{'SKey'}, $self->{'RKey'}); print { $self->{'Socket'} } "$self->{'RKey'}\n"; } sub send { my $self = shift; my @items = @_; my ($item, $enc_item); if (defined($self->{'HCE'})) { foreach $item (@items) { # syslog('debug','Client encode: %s',$item); $enc_item = $self->{'HCE'}->hce_block_encode_mime($item); # syslog('debug','Client sending: %s', $enc_item); print { $self->{'Socket'} } "$enc_item\n; } $enc_item = $self->{'HCE'}->hce_block_encode_mime("+END_OF_LIST"); print { $self->{'Socket'} } "$enc_item\n"; } else { foreach $item (@items) { # syslog('debug','Client sending: %s',$item); print { $self->{'Socket'} } "$item\n"; } print { $self->{'Socket'} } "+END_OF_LIST\n"; } return 0; } sub recv { my $self = shift; my $fh = $self->{'Socket'}; my ($data, $dec_data); if (defined($self->{'HCE'})) { $data = ""; undef(@response); while (<$fh>) { chomp; $data = 1; # syslog('debug','Client recv: %s', $_); $dec_data = $self->{'HCE'}->hce_block_decode_mime($_); # syslog('debug','Client decode: %s', $dec_data); last if ($dec_data eq "+END_OF_LIST"); push @response, $dec_data; }; if (!defined $data) { close ($self->{'Socket'}); return $data; } else { close ($self->{'Socket'}); return @response; }; } else { $data = ""; undef(@response); while (<$fh>) { chomp; $data = 1; push @response, $_; }; if (!defined $data) { close ($self->{'Socket'}); return $data; } else { close ($self->{'Socket'}); return @response; }; } } 1; __END__ #------- POD ------ Crypt-HCE_SHA-0.75/MANIFEST0000644000175000017500000000042412677541517013434 0ustar ericericChanges HCE_SHA.pm MANIFEST Makefile.PL test.pl README examples/Client.pm examples/Server.pm examples/HOW_TO_USE META.yml Module meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Crypt-HCE_SHA-0.75/README0000644000175000017500000000134312677540755013167 0ustar ericeric This module implements a chaining block cipher using a one way hash. This method of encryption is the same that is used by radius (RFC2138) and is also described in Applied Cryptography. Two interfaces are provided in the module. The first is straight block encryption/decryption the second does base64 mime encoding/decoding of the encrypted/decrypted blocks. The idea is the the two sides have a shared secret that supplies one of the keys and a randomly generated block of bytes provides the second key. The random key is passed in cleartext between the two sides. An example client and server are packaged as modules with this module. They are used in the tests. Crypt-HCE_SHA-0.75/Changes0000644000175000017500000000167512677541167013610 0ustar ericericRevision history for Perl extension Crypt::HCE_SHA. 0.01 Wed Oct 14 16:23:57 1998 - original version; created by h2xs 1.18 0.02 - implementation 0.03 Fri Oct 16 14:41:33 1998 - moved example modules to the examples directory 0.40 Tue Apr 06 1999 - updated man documentation - updated to use Digest::SHA1 by Gisle Aas 0.45 Tue Aug 17 1999 - bug fix on chaining key selection - bug report submitted by Jake Angerman (Thanks Jake!) 0.60 Fri Feb 18 2000 - fixed length issue caused by mime inserting returns - updated Client.pm and Server.pm to reflect the changes 0.65 Fri Mar 26 2004 - removed syslog from test.pl to support ActiveState 0.70 Fri Mar 26 2004 - removed the other syslogs from test.pl 0.75 Fri Apr 01 2016 - fix defined deprecations - cleanup whitespace - switch to more general Digest::SHA allowing use of other sizes 224, 256, 384, and 512 SHA1 remains the default so it should remain compatible Crypt-HCE_SHA-0.75/test.pl0000644000175000017500000001765312677540667013640 0ustar ericeric# Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl test.pl' ######################### We start with some black magic to print on failure. # Change 1..1 below to 1..last_test_to_print . # (It may become useful if the test is moved to ./t subdirectory.) BEGIN { $| = 1; print "1..4\n"; } END {print "not ok 1\n" unless $loaded;} use Crypt::HCE_SHA; $loaded = 1; print "ok 1\n"; ######################### End of black magic. # Insert your test code below (better if it prints "ok 13" # (correspondingly "not ok 13") depending on the success of chunk 13 # of the test code): $text = "This is an example of some text that is long enough to verify that the bug was fixed. So if you see this message in its entirety then I guess it worked"; $hce_sha = Crypt::HCE_SHA->new("SharedSecret", "Random01,39j309ad"); $crypted = $hce_sha->hce_block_encrypt("Encrypt this information"); $info = $hce_sha->hce_block_decrypt($crypted); if ($info eq "Encrypt this information") { print "ok 2\n"; } else { print "not ok 2\n"; } $mime_crypted = $hce_sha->hce_block_encode_mime("Encrypt and Base64 this information"); $info = $hce_sha->hce_block_decode_mime($mime_crypted); if ($info eq "Encrypt and Base64 this information") { print "ok 3\n"; } else { print "not ok 3\n"; } $pid = fork(); if ($pid < 0) { die "Couldn't fork"; } if ($pid != 0) { $server = Server->new(Server => 0, Port => 5050, SKey => "SharedSecret", Queue => 1); $cons = $server->accept(5); if ($cons == 0) { die "accept timed out"; } @info = $server->recv(); $server->send(@info); wait; } else { sleep 3; $client = Client->new(Server => localhost, Port => 5050, SKey => "SharedSecret"); $client->send($text); @info_back = $client->recv(); if ($info_back[0] eq $text) { print "ok 4\n"; } else { print "not ok 4\n"; } exit 0; } package Server; use IO::Select; use IO::Socket; use strict; use Carp; #use HCE_SHA; my @response; my $data; sub new { my $class = shift; my $self = {}; bless $self, $class; if ((scalar(@_) % 2) != 0) { croak "incorrect number of parameters"; } while (@_) { my $key = shift(@_); my $value = shift(@_); $self->{$key} = $value; } $self->_initialize; return $self; } sub _initialize { my $self = shift; if (!defined($self->{'Server'})) { croak "Server not initialized properly : Server parameter missing"; } if (!defined($self->{'Port'})) { croak "Server not initialized properly : Port parameter missing"; } if (!defined($self->{'Queue'})) { croak "Server not initialized properly : Queue parameter missing"; } if (!eval {$self->{'Socket'} = IO::Socket::INET->new(LocalAddr => $self->{'Server'}, LocalPort => $self->{'Port'}, Proto => 'tcp', Reuse => 1, Listen => $self->{'Queue'} ); }) { croak "Server couldn't establish a port on $self->{'Server'}"; } $self->{'Socket'}->autoflush(1); delete $self->{'HCE'}; $self->{'Select'} = IO::Select->new($self->{'Socket'}); } sub accept { my $self = shift; my ($time) = @_; # how long to wait my (@ready_to_read, $size); @ready_to_read = $self->{'Select'}->can_read($time); $size = scalar(@ready_to_read); if ($size == 1) { $self->{'Connect'} = $self->{'Socket'}->accept; $self->{'Connect'}->autoflush(1); # don't buffer return messages } else { delete $self->{'Connect'}; } return $size; } sub close { my $self = shift; $self->{'Connect'}->close; delete $self->{'Connect'}; delete $self->{'HCE'}; return 0; } sub send { my $self = shift; my @items = @_; my ($item, $enc_item); if (!defined($self->{'Connect'})) { croak "No Connection established: did you accept?"; } if (defined($self->{'HCE'})) { foreach $item (@items) { print "Server encode: $item\n"; $enc_item = $self->{'HCE'}->hce_block_encode_mime($item); print "Server sending: $enc_item\n"; print { $self->{'Connect'} } "$enc_item\n"; } $enc_item = $self->{'HCE'}->hce_block_encode_mime("+END_OF_LIST"); print { $self->{'Connect'} } "$enc_item\n"; } else { foreach $item (@items) { print { $self->{'Connect'} } "$item\n"; } } return 0; } sub recv { my $self = shift; my ($data, $dec_data, $fh); if (!defined($self->{'Connect'})) { croak "No Connection established: did you accept?"; } $fh = $self->{'Connect'}; undef(@response); if (!defined($self->{'SKey'})) { while (<$fh>) { chomp; print "Server recv: $_\n"; tr/\n\r\t//d; last if ($_ eq '+END_OF_LIST'); push @response, $_; }; if (!(@response)) { return; } else { return @response; } } if (defined($self->{'HCE'})) { while (<$fh>) { chomp; print "Server recv: $_\n"; $dec_data = $self->{'HCE'}->hce_block_decode_mime($_); $dec_data =~ tr/\n\r\t//d; print "Server decode: $dec_data\n"; last if ($dec_data eq "+END_OF_LIST"); push @response, $dec_data; }; if (!(@response)) { return; } else { return @response; }; } else { $_ = <$fh>; # get RKey chomp; $self->{'RKey'} = $_; $self->{'HCE'} = Crypt::HCE_SHA->new($self->{'SKey'}, $self->{'RKey'}); return $self->recv(); } } package Client; use IO::Select; use IO::Socket; use strict; use Carp; #use HCE_SHA; my @response; my $data; sub new { my $class = shift; my $self = {}; bless $self, $class; if ((scalar(@_) % 2) != 0) { croak "incorrect number of parameters"; } while (@_) { my $key = shift(@_); my $value = shift(@_); $self->{$key} = $value; } $self->_initialize; return $self; } sub _initialize { my $self = shift; my $timeout; if (!defined($self->{'Server'})) { croak "Client not initialized properly : Server parameter missing"; } if (!defined($self->{'Port'})) { croak "Client not initialized properly : Port parameter missing"; } if (!defined($self->{'SKey'})) { croak "Client not initialized properly : SKey parameter missing"; } if (!eval {$self->{'Socket'} = IO::Socket::INET->new(PeerAddr => $self->{'Server'}, PeerPort => $self->{'Port'}, Proto => 'tcp', Reuse => 1); }) { croak "Client couldn't establish a connection to $self->{'Server'}"; } $self->{'Socket'}->autoflush(1); srand($$|time()); # poor random generator should be replaced $self->{'RKey'} = rand(100000000)+1000000; $self->{'HCE'} = Crypt::HCE_SHA->new($self->{'SKey'}, $self->{'RKey'}); print { $self->{'Socket'} } "$self->{'RKey'}\n"; } sub send { my $self = shift; my @items = @_; my ($item, $enc_item); if (defined($self->{'HCE'})) { foreach $item (@items) { $enc_item = $self->{'HCE'}->hce_block_encode_mime($item); print { $self->{'Socket'} } "$enc_item\n"; } $enc_item = $self->{'HCE'}->hce_block_encode_mime("+END_OF_LIST"); print { $self->{'Socket'} } "$enc_item\n"; } else { foreach $item (@items) { print { $self->{'Socket'} } "$item\n"; } print { $self->{'Socket'} } "+END_OF_LIST\n"; } return 0; } sub recv { my $self = shift; my $fh = $self->{'Socket'}; my ($data, $dec_data); if (defined($self->{'HCE'})) { $data = ""; undef(@response); while (<$fh>) { chomp; $data = 1; print "Client recv: $_\n"; $dec_data = $self->{'HCE'}->hce_block_decode_mime($_); print "Client decode: $dec_data\n"; last if ($dec_data eq "+END_OF_LIST"); push @response, $dec_data; }; if (!defined $data) { close ($self->{'Socket'}); return $data; } else { close ($self->{'Socket'}); return @response; }; } else { $data = ""; undef(@response); while (<$fh>) { chomp; $data = 1; push @response, $_; }; if (!defined $data) { close ($self->{'Socket'}); return $data; } else { close ($self->{'Socket'}); return @response; }; } } 1; __END__ Crypt-HCE_SHA-0.75/Makefile.PL0000644000175000017500000000046312677541407014256 0ustar ericericuse ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( 'NAME' => 'Crypt::HCE_SHA', 'VERSION_FROM' => 'HCE_SHA.pm', # finds $VERSION 'PREREQ_PM' => {'Digest::SHA' => 0, 'MIME::Base64' => 2} ); Crypt-HCE_SHA-0.75/META.json0000644000175000017500000000154512677541517013731 0ustar ericeric{ "abstract" : "unknown", "author" : [ "unknown" ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.0401, CPAN::Meta::Converter version 2.150001", "license" : [ "unknown" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Crypt-HCE_SHA", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Digest::SHA" : "0", "MIME::Base64" : "2" } } }, "release_status" : "stable", "version" : "0.75" } Crypt-HCE_SHA-0.75/HCE_SHA.pm0000644000175000017500000001054012677541077013734 0ustar ericeric# # Crypt::HCE_SHA # implements one way hash chaining encryption using SHA # # $Id: HCE_SHA.pm,v 1.3 2000/02/19 03:47:11 eric Exp $ # package Crypt::HCE_SHA; use strict; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); use Digest::SHA; use MIME::Base64; use Carp; require Exporter; require AutoLoader; @ISA = qw(Exporter AutoLoader); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. @EXPORT = qw( ); $VERSION = '0.75'; sub new { my $class = shift; my $self = {}; bless $self, $class; if ((@_ != 2) && (@_ != 3)) { croak "Error: must be invoked HCE_SHA->new(key, random_thing, [algorithm to use (1, 224, 256, 384, 512)])"; } $self->{SKEY} = shift(@_); $self->{RKEY} = shift(@_); if (@_ > 0) { $self->{BITS} = shift(@_); } else { $self->{BITS} = 1; } return $self; } sub _new_key { my $self = shift; my ($rnd) = @_; my $context = new Digest::SHA->new($self->{BITS}); $context->add($self->{SKEY}, $rnd); my $digest = $context->digest(); my @e_block = unpack('C*', $digest); return @e_block; } sub hce_block_encrypt { my $self = shift; my ($data) = @_; my ($i, $key, $data_size, $ans, $mod, @e_block, @data, @key, @ans); @key = unpack ('C*', $self->{SKEY}); @data = unpack ('C*', $data); undef @ans; @e_block = $self->_new_key($self->{RKEY}); $data_size = scalar(@data); for($i=0; $i < $data_size; $i++) { $mod = $i % 20; if (($mod == 0) && ($i > 19)) { @e_block = $self->_new_key(pack 'C*', (@ans)[($i-20)..($i-1)]); } $ans[$i] = $e_block[$mod] ^ $data[$i]; } $ans = pack 'C*', @ans; return $ans; } sub hce_block_decrypt { my $self = shift; my ($data) = @_; my ($i, $key, $data_size, $ans, $mod, @e_block, @data, @key, @ans); @key = unpack ('C*', $self->{SKEY}); @data = unpack ('C*', $data); undef @ans; @e_block = $self->_new_key($self->{RKEY}); $data_size = scalar(@data); for($i=0; $i < $data_size; $i++) { $mod = $i % 20; if (($mod == 0) && ($i > 19)) { @e_block = $self->_new_key(pack 'C*', (@data)[($i-20)..($i-1)]); } $ans[$i] = $e_block[$mod] ^ $data[$i]; } $ans = pack 'C*', @ans; return $ans; } sub hce_block_encode_mime { my $self = shift; my ($data) = @_; my $new_data = $self->hce_block_encrypt($data); my $encode = encode_base64($new_data, ""); return $encode; } sub hce_block_decode_mime { my $self = shift; my ($data) = @_; my $decode = decode_base64($data); my $new_data = $self->hce_block_decrypt($decode); return $new_data; } # Autoload methods go after =cut, and are processed by the autosplit program. 1; __END__ =head1 NAME Crypt::HCE_SHA - Perl extension implementing one way hash chaining encryption using SHA =head1 SYNOPSIS use Crypt::HCE_SHA; $hce_sha = Crypt::HCE_SHA->new("SharedSecret", "Random01,39j309ad"); $crypted = $hce_sha->hce_block_encrypt("Encrypt this information"); $info = $hce_sha->hce_block_decrypt($crypted); $mime_crypted = $hce_sha->hce_block_encode_mime("Encrypt and Base64 this information"); $info = $hce_sha->hce_block_decode_mime($mime_crypted); $hce_sha = Crypt::HCE_SHA->new("key", "random", 256); # use SHA256 instead of SHA1 =head1 DESCRIPTION This module implements a chaining block cipher using a one way hash. This method of encryption is the same that is used by radius (RFC2138) and is also described in Applied Cryptography. Two interfaces are provided in the module. The first is straight block encryption/decryption the second does base64 mime encoding/decoding of the encrypted/decrypted blocks. The idea is the the two sides have a shared secret that supplies one of the keys and a randomly generated block of bytes provides the second key. The random key is passed in cleartext between the two sides. An example client and server are packaged as modules with this module. They are used in the tests. They can be found in the examples directory. Thanks to Jake Angerman for the bug report on the bug in key generation for the chaining portion of the algorithm =head1 AUTHOR Eric Estabrooks, eric@urbanrage.com =head1 SEE ALSO perl(1). =cut