#!/usr/bin/perl -w use strict; # BlowJob 0.8.5, a crypto plugin for XChat # was based on rodney mulraney's crypt # changed crypting method to Blowfish+Base64+randomness+Z-compression # needs : # Crypt::CBC, # Crypt::Blowfish, # MIME::Base64, # Compress::Zlib # # crypted format is : # HEX(Base64((paranoia-factor)*(blowfish(RANDOM+Zcomp(string))+RANDOM))) # # 06-12-2001 Added default umask for blowjob.keys # 05-12-2001 Added paranoia support for each key # 05-12-2001 Added conf file support # 05-12-2001 Added delkey and now can handle multi-server/channel keys # 05-12-2001 permanent crypting to a channel added # 05-12-2001 Can now handle multi-channel keys # just /setkey on the channel you are to associate a channel with a key # # --- conf file format --- # # # the generic key ( when /setkey has not been used ) # key: generic key value # # header that marks a crypted sentance # header: {header} # # do you wan't to see crypted lines [yes|no] # showcrypt: yes # # enable wildcards for multiserver entries ( useful for OPN for example ) # wildcardserver: yes # # --- end of conf file --- # # iMil # skid # Thomas Reifferscheid # oliv3 # Speuler use Crypt::CBC; use Crypt::Blowfish; use MIME::Base64; use Compress::Zlib; use vars qw($cipher); my $key = 'very poor key' ; my $header = "{blow}"; # Crypt loops, 1 should be enough for everyone imho ;) # please note with a value of 4, a single 4-letter word can generate # a 4 line crypted sentance my $paranoia = 1; # set this to "no" if you don't want to see crypted lines my $seecrypt = "no"; # add a server mask by default ? my $enableWildcard="yes"; my $version="0.8.5"; my $alnum = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; my $channel = IRC::get_info(2); if (!$channel) { IRC::print("\00305not in a channel\n"); return 1; } my $gkey; sub loadconf { my $fconf="$ENV{HOME}/.xchat2/blowjob.conf"; my @conf; open (CONF, "<$fconf"); if (!( -f CONF)) { IRC::print("\00305> $fconf not found, setting to defaults\n"); IRC::print("\00305> creating $fconf with default values\n\n"); close(CONF); open(CONF,">$fconf"); print CONF "key: $key\n"; print CONF "header: $header\n"; print CONF "seecrypt: $seecrypt\n"; print CONF "wildcardserver: $enableWildcard\n"; close(CONF); return 1; } @conf=; close(CONF); my $current; foreach(@conf) { $current = $_; $current =~ s/\n//g; if ($current =~ m/key/) { $current =~ s/.*\:[\ \t]*//; $key = $current; $gkey = $key; } if ($current =~ m/header/) { $current =~ s/.*\:[\s\t]*\{(.*)\}.*/{$1}/; $header = $current; } if ($current =~ m/seecrypt/) { $current =~ s/.*\:[\ \t]*//; $seecrypt = $current; } if ($current =~ m/wildcardserver/) { $current =~ s/.*\:[\ \t]*//; $enableWildcard = $current; } } IRC::print("\00314- configuration file loaded\n"); return 1; } loadconf; my $kfile ="$ENV{HOME}/.xchat2/blowjob.keys"; my @keys; $gkey=$key; my $gparanoia=$paranoia; sub loadkeys { if ( -e "$kfile" ) { open (KEYF, "<$kfile"); @keys = ; close (KEYF); } IRC::print("\00314- keys reloaded (Total:\00315 ".scalar @keys."\00314)\n"); return 1; } loadkeys; sub getkey { my ($curserv,$curchan) = @_; my $gotkey=0; my $serv; my $chan; my $fkey; foreach(@keys) { chomp; # keys can contain ":" now. Note: my ($serv,$chan,$fparanoia,$fkey)=split /:/,$_,4; # place of paranoia has changed! if ( $curserv =~ /$serv/ and $curchan =~ /^$chan$/ ) { $key= $fkey; $paranoia=$fparanoia; $gotkey=1; } } if (!$gotkey) { $key=$gkey; $paranoia=$gparanoia; } $cipher=new Crypt::CBC($key,'Blowfish',undef); } sub setkey { my $fparanoia; my $curserv = IRC::get_info(3); my $curchan = IRC::get_info(2); my $newchan=1; umask(0077); unless ($_[0] =~ /( +\d$)/) { $_[0].= " $gparanoia"; } ($key, $fparanoia) = ($_[0] =~ /(.*) +(\d)/); if($enableWildcard =~ /[Yy][Ee][Ss]/) { $curserv =~ s/(.*?)\./(.*?)\./; IRC::print("\00314IRC server wildcards enabled\n"); } # Note, place of paranoia has changed! my $line="$curserv:$curchan:$fparanoia:$key"; open (KEYF, ">$kfile"); foreach(@keys) { s/\n//g; if (/^$curserv\:$curchan\:/) { print KEYF "$line\n"; $newchan=0; } else { print KEYF "$_\n"; } } if ($newchan) { print KEYF "$line\n"; } close (KEYF); loadkeys; IRC::print("\00314key set to \00315$key\00314 for channel \00315$curchan"); return 1 ; } sub delkey { my $curchan = IRC::get_info(2); my $curserv = IRC::get_info(3); my $serv; my $chan; open (KEYF, ">$kfile"); foreach(@keys) { s/\n//g; ($serv,$chan)=/^(.*?)\:(.*?)\:/; unless ($curserv =~ /$serv/ and $curchan=~/^$chan$/) { print KEYF "$_\n"; } } close (KEYF); IRC::print("\00314key for channel \00315$curchan\00314 deleted\n"); loadkeys; return 1 ; } sub showkey { getkey(IRC::get_info(3),IRC::get_info(2)); IRC::print("\00314current key is : \00315$key\00314 (paranoia \00315$paranoia\00314)") ; return 1 ; } sub blow { my $in = shift ; my $nick = IRC::get_info(1); my $curchan = IRC::get_info(2); my $curserv = IRC::get_info(3); my $prng1=""; my $prng2=""; for (my $i=0;$i<4;$i++) { $prng1.=substr($alnum,int(rand(61)),1); $prng2.=substr($alnum,int(rand(61)),1); } getkey(IRC::get_info(3),IRC::get_info(2)); IRC::print("<$nick|{crypted}> \00310$in\n") ; $cipher->start('encrypting'); $in = compress($in); my $i; for ($i=0;$i<$paranoia;$i++) { $in = $prng1.$in; $in = $cipher->encrypt($in); $in .= $prng2; # don't wan't to see "RandomIV" $in =~ s/^.{8}//; } $in = encode_base64($in); $in = unpack("H*",$in); $in = $header." ".$in; $in =~ s/=+$//; IRC::send_raw("PRIVMSG $curchan :$in\n"); if ($seecrypt =~ m/[Yy][Ee][Ss]/) { IRC::print("\00315$in\n"); } $cipher->finish; return 1 ; } sub infoline { my $mynick = IRC::get_info(1); my $curchan = IRC::get_info(2); my $curserv = IRC::get_info(3); my $line = shift(@_); $line =~ m/\:(.*?)\!(.*?)\sPRIVMSG\s(.*?)\s\:(.*)?/; my $msgnick = $1; my $hmsender = $2; my $msgtype = $3; my $msgline = $4; if ($msgline =~ m/^$header/) { my $out = $msgline; $out =~ s/\0030[0-9]//g; $out =~ s/^$header\s*(.*)/$1/; if ($msgtype ne $curchan) { $curchan = $msgnick; } getkey($curserv,$curchan); $cipher->start('decrypting'); $out = pack("H*",$out); $out = decode_base64($out); my $i; for ($i=0;$i<$paranoia;$i++) { $out = substr($out,0,(length($out)-4)); # restore RandomIV $out = 'RandomIV'.$out; $out = $cipher->decrypt($out); $out = substr($out,4); } $out = uncompress($out); $cipher->finish; if(length($out)) { IRC::print_with_channel("<$msgnick|{uncrypted}> \00311$out\n",$curchan,$curserv); if ($seecrypt =~ m/[Yy][Ee][Ss]/) { IRC::print("\00315<$msgnick> $msgline"); } return 1; } } return 0 ; } my %permchans={}; sub perm { my $curchan = IRC::get_info(2); my $curserv = IRC::get_info(3); if ( exists($permchans{$curserv}{$curchan}) && $permchans{$curserv}{$curchan} == 1) { delete $permchans{$curserv}{$curchan}; IRC::print("\00314not crypting to \00315$curchan\00314 on \00315$curserv\00314 anymore"); } else { $permchans{$curserv}{$curchan} = 1; IRC::print("\00314crypting to \00315$curchan on \00315$curserv"); } return 1; } sub myline { my $curchan = IRC::get_info(2); my $curserv = IRC::get_info(3); my $line = shift; chomp($line); if (length($line) == 0) { return; } my $gotchan = 0; foreach(@keys) { s/\n//g; my ($serv,$chan,undef,undef)=split /:/; if ( ($curserv =~ /$serv/ && $curchan =~ /^$chan$/ && exists($permchans{$curserv}{$curchan}) && $permchans{$curserv}{$curchan} == 1) || (exists($permchans{$curserv}{$curchan}) && $permchans{$curserv}{$curchan} == 1)) { $gotchan = 1; } } if ($gotchan) { blow($line); return 1; } } sub reloadconf { loadconf; loadkeys; } sub help { IRC::print("\00314[\00303bl\003090\00303wjob\00314]\00315 script :\n"); IRC::print("\00315/setkey [] :\00314 new key for current channel\n") ; IRC::print("\00315/delkey :\00314 delete key for current channel"); IRC::print("\00315/showkey :\00314 show your current key\n") ; IRC::print("\00315/blow :\00314 send crypted line\n") ; IRC::print("\00315/perm :\00314 flag current channel as permanently crypted\n") ; IRC::print("\00315/bconf :\00314 reload blowjob.conf\n") ; return 1 ; } IRC::register("blowjob script",$version,"","") ; IRC::print("\n\00314[\00303bl\003090\00303wjob\00314] v$version\00315 script loaded\n\n"); IRC::print("\00314- type \00315/blowhelp\00314 for options\n") ; IRC::print("\00314- paranoia level is : \00315$paranoia\n") ; IRC::print("\00314- generic key is : \00315$key\n") ; IRC::print("\n\00314* please read script itself for documentation\n"); IRC::add_message_handler("PRIVMSG","infoline") ; IRC::add_command_handler("blowhelp","help") ; IRC::add_command_handler("setkey","setkey") ; IRC::add_command_handler("delkey","delkey"); IRC::add_command_handler("blow","blow") ; IRC::add_command_handler("showkey","showkey") ; IRC::add_command_handler("perm","perm") ; IRC::add_command_handler("bconf","reloadconf") ; IRC::add_command_handler("","myline") ;