diff options
Diffstat (limited to 'scripts/ircsec.pl')
-rw-r--r-- | scripts/ircsec.pl | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/scripts/ircsec.pl b/scripts/ircsec.pl new file mode 100644 index 0000000..00dea4c --- /dev/null +++ b/scripts/ircsec.pl @@ -0,0 +1,205 @@ +# by Stefan 'tommie' Tomanek + +use strict; + +use Irssi 20020324; +use Irssi::TextUI; +use Crypt::CBC; +use Digest::MD5 qw(md5 md5_hex md5_base64);; + +use vars qw($VERSION %IRSSI); +$VERSION = '20190114'; +%IRSSI = ( + authors => 'Stefan \'tommie\' Tomanek', + contact => 'stefan@pico.ruhr.de', + name => 'IRCSec', + description => 'secures your conversation', + license => 'GPLv2', + changed => $VERSION, + modules => 'Crypt::CBC Digest::MD5', + sbitems => 'ircsec', + commands => "ircsec", + +); + +use vars qw(%channels); + +sub draw_box ($$$$) { + my ($title, $text, $footer, $colour) = @_; + my $box = ''; + $box .= '%R,--[%n%9%U'.$title.'%U%9%R]%n'."\n"; + foreach (split(/\n/, $text)) { + $box .= '%R|%n '.$_."\n"; + } + $box .= '%R`--<%n'.$footer.'%R>->%n'; + $box =~ s/%.//g unless $colour; + return $box; +} + +sub show_help() { + my $help=$IRSSI{name}." ".$VERSION." +/ircsec secure <key> + Encrypt and decrypt conversation in current channel/query with <key> +/ircsec unlock + Disable de/encryption +/ircsec toggle + Temporary dis- or enable security +"; + my $text = ''; + foreach (split(/\n/, $help)) { + $_ =~ s/^\/(.*)$/%9\/$1%9/; + $text .= $_."\n"; + } + print CLIENTCRAP &draw_box($IRSSI{name}." help", $text, "help", 1) ; +} + + +sub encrypt ($$$) { + my ($text, $key, $algo) = @_; + my $cipher; + $cipher = Crypt::CBC->new( -key => $key, + -cipher => $algo, + -iv => '$KJh#(}q', + -literal_key => 0, + -padding => 'space', + -header => 'randomiv' + ); + return unless $cipher; + my $checksum = md5_base64($text); + my $ciphertext = $cipher->encrypt_hex($text." ".$checksum); + return $ciphertext; +} + +sub decrypt ($$$) { + my ($data, $key, $algo) = @_; + my $cipher; + $cipher = Crypt::CBC->new( -key => $key, + -cipher => $algo, + -iv => '$KJh#(}q', + -literal_key => 0, + -padding => 'space', + -header => 'randomiv' + ); + + return unless $cipher; + my $plaintext = $cipher->decrypt_hex($data); + my ($text, $checksum) = $plaintext =~ /^(.*) (.*?)$/; + if ($checksum eq md5_base64($text)) { + return $text; + } else { + return undef; + } +} + +sub sig_send_text ($$$) { + my ($line, $server, $witem) = @_; + return unless ref $witem; + my $tag = $witem->{server}->{tag}; + if (defined $channels{$tag}{$witem->{name}} && $channels{$tag}{$witem->{name}}{active}) { + my $key = $channels{$tag}{$witem->{name}}{key}; + Irssi::signal_stop(); + my $cipher = Irssi::settings_get_str('ircsec_default_cipher'); + my $crypt = encrypt($line, $key, $cipher); +# if (defined $crypt) { + Irssi::signal_continue("[IRCSec:".$cipher."] ".$crypt, $server, $witem); +# } else { +# $witem->print("%R[IRCSec]>%n Unknown cipher method '".$cipher."'", MSGLEVEL_CLIENTCRAP); +# } + } +} + +sub decode ($$$) { + my ($server, $text, $target) = @_; + return unless ($text =~ /^\[IRCSec(:(.*?))?\] ([\d\w]+)/); + my $string = $3; + my $cipher = $2; + $cipher = Irssi::settings_get_str('ircsec_default_cipher') unless $cipher; + my $witem = $server->window_item_find($target); + return unless ref $witem; + return unless defined $channels{$server->{tag}}{$target}; + my $key = $channels{$server->{tag}}{$target}{key}; + my $plain = decrypt($string, $key, $cipher); + if (defined $plain) { + $witem->print("%B[IRCSec:".$cipher."]>%n $plain", MSGLEVEL_CLIENTCRAP); + } else { + $witem->print("%R[IRCSec]>%n Unknown cipher method '".$cipher."' or wrong key", MSGLEVEL_CLIENTCRAP); + } +} + +sub sb_ircsec ($$) { + my ($item, $get_size_only) = @_; + my $win = !Irssi::active_win() ? undef : Irssi::active_win()->{active}; + my $line; + if (ref $win && ($win->{type} eq "CHANNEL" || $win->{type} eq "QUERY")){ + my $name = $win->{name}; + my $tag = $win->{server}->{tag}; + if ($channels{$tag}{$name} && $channels{$tag}{$name}{active}) { + $line = "%G%Uo-m%U%n"; + } elsif ($channels{$tag}{$name}){ + $line = "%Ro-m%n"; + } + } + my $format = "{sb ".$line."}"; + $item->{min_size} = $item->{max_size} = length($line); + $item->default_handler($get_size_only, $format, 0, 1); + $item->default_handler($get_size_only, $format, 0, 1); +} + +sub cmd_ircsec ($$$) { + my ($args, $server, $witem) = @_; + my @arg = split(/ /, $args); + if (@arg == 0 || $arg[0] eq 'help') { + # do some stuff + show_help(); + } elsif ($arg[0] eq 'secure') { + shift @arg; + return unless ref $witem; + if (@arg) { + my $key = join(' ', @arg); + if (length($key) < 8) { + $witem->print("%R>>%n Key must be a minimum of 8 characters", MSGLEVEL_CLIENTCRAP); + } else { + $channels{$server->{tag}}{$witem->{name}}{key} = join(' ', @arg); + $channels{$server->{tag}}{$witem->{name}}{active} = 1; + $witem->print("%B>>%n %Go-m%n Conversation secured", MSGLEVEL_CLIENTCRAP); + } + } else { + $witem->print("%R>>%n Please specify a key", MSGLEVEL_CLIENTCRAP); + } + Irssi::statusbar_items_redraw('ircsec'); + } elsif ($arg[0] eq 'unlock') { + delete $channels{$server->{tag}}{$witem->{name}}; + $witem->print("%B>>%n %Ro-m%n Security disabled", MSGLEVEL_CLIENTCRAP); + Irssi::statusbar_items_redraw('ircsec'); + } elsif ($arg[0] eq 'toggle') { + return unless ref $witem; + if ($channels{$server->{tag}}{$witem->{name}}) { + $channels{$server->{tag}}{$witem->{name}}{active} = not $channels{$server->{tag}}{$witem->{name}}{active}; + Irssi::statusbar_items_redraw('ircsec'); + } + } +} + +Irssi::signal_add('message private', sub { decode($_[0], $_[1], $_[2]); }); +Irssi::signal_add('message public', sub { decode($_[0], $_[1], $_[4]); }); +Irssi::signal_add('message own_private', sub { decode($_[0], $_[1], $_[2]); }); +Irssi::signal_add('message own_public', sub { decode($_[0], $_[1], $_[2]); }); + +Irssi::signal_add_first('send text', "sig_send_text"); +Irssi::signal_add('window changed', sub { Irssi::statusbar_items_redraw('ircsec'); }); +Irssi::signal_add('window item changed', sub { Irssi::statusbar_items_redraw('ircsec'); }); + +Irssi::statusbar_item_register('ircsec', 0, 'sb_ircsec'); + +Irssi::settings_add_str($IRSSI{name}, 'ircsec_default_cipher', 'Blowfish'); + +Irssi::command_bind('ircsec', \&cmd_ircsec); + +foreach my $cmd ('unlock', 'secure', 'toggle') { + Irssi::command_bind('ircsec '.$cmd => sub { + cmd_ircsec("$cmd ".$_[0], $_[1], $_[2]); }); +} + +print CLIENTCRAP "%B>>%n ".$IRSSI{name}." ".$VERSION." loaded: /ircsec help for help"; + +# vim:set ts=8 sw=4: |