Crypt-Unsnoopable
view release on metacpan or search on metacpan
bin/unsnoopable.pl view on Meta::CPAN
#!/usr/bin/perl
# -*-cperl-*-
#
# unsnoopable.pl - Completely unsnoopable messaging
# Copyright (c) Ashish Gulhati <crypt-unsnoopable at hash.neo.tc>
#
# $Id: bin/unsnoopable.pl v1.010 Tue Oct 16 21:04:28 PDT 2018 $
use warnings;
use Wx qw (:everything);
use Wx::Event qw (EVT_BUTTON);
use Crypt::Unsnoopable qw(dec heX);
use GD::Barcode::QRcode;
use File::HomeDir;
my $NOODLEPI;
if ($ARGV[0] and $ARGV[0] eq '--noodlepi') {
my $uname = `uname -a`; my $cpu;
if ($uname =~ /armv6l GNU\/Linux/) {
$cpu = `grep Hardware /proc/cpuinfo`;
}
$NOODLEPI = 1 if $cpu =~ /BCM2708/;
}
my $UNSNOOPABLE = $ENV{UNSNOOPABLEDIR} || File::HomeDir->my_home . '/.unsnoopable';
unless (-d $UNSNOOPABLE) {
die "Directory $UNSNOOPABLE doesn't exist and couldn't be created.\n" unless mkdir($UNSNOOPABLE, 0700);
}
my $u = new Crypt::Unsnoopable (DB => $UNSNOOPABLE);
my $pads = $u->otps;
# Initialize l8n
my ($lang, %lang) = initl8n();
# Initialize UI
my ($app, $frame, $padsel, $topSizer, $boxSizer, $statusBar, %button) = initui();
# Actions for all the buttons
my %action;
$action{Generate} = sub { # Generate new OTP
my $dialog = Wx::TextEntryDialog->new( $frame, "Enter a name for this pad:", "Generate One-Time Pad");
return if $dialog->ShowModal == wxID_CANCEL;
my $name = $dialog->GetValue(); return unless $name =~ /^[\w\d\s]+$/; return if exists $pads->{$name};
my $pad = $u->otpgen(2935, $name);
$pads = $u->otps;
$padsel->Insert("$name (2935)", 0);
show();
};
$action{Import} = sub { # Import OTP
my ($dialog, $pad);
if ($NOODLEPI) {
system ('v4l2-ctl --overlay=1');
open (ZBAR, "zbarcam --nodisplay --prescale=640x480 /dev/video0 |");
$pad = <ZBAR>; chomp $pad; $pad =~ s/^QR-Code://;
system ('killall -9 zbarcam');
close ZBAR;
system ('v4l2-ctl --overlay=0');
print "$pad\n";
}
else {
$dialog = Wx::TextEntryDialog->new( $frame, "Paste pad below", "Import One-Time Pad");
return if($dialog->ShowModal == wxID_CANCEL);
$pad = $dialog->GetValue();
}
return if $pad =~ /\D/;
$dialog = Wx::TextEntryDialog->new( $frame, "Enter a name for this pad:", "Import One-Time Pad");
return if $dialog->ShowModal == wxID_CANCEL;
my $name = $dialog->GetValue(); return unless $name =~ /^[\w\d\s]+$/; return if exists $pads->{$name};
return unless $pad = $u->add($pad, $name);
$pads = $u->otps; my $len = length($pads->{$name}->{pad})/2;
$padsel->Insert("$name ($len)", 0);
show();
};
$action{Export} = sub { # Export OTP
my $pad_name = $padsel->GetString($padsel->GetSelection); $pad_name =~ s/\s*\(\d+\)//;
local $SIG{'__WARN__'} = sub { };
my $pad = dec(heX($pads->{$pad_name}->{id}) . $pads->{$pad_name}->{pad});
my $dialog = qrdialog($pad, 'Scan the QR code or copy pad from below', 'Export One-Time Pad');
$dialog->ShowModal;
};
$action{Send} = sub { # Send a message
my $dialog = Wx::TextEntryDialog->new( $frame, "Enter message:", "Send message");
return if $dialog->ShowModal == wxID_CANCEL;
my $msg = $dialog->GetValue(); return unless $msg;
my $selnum = $padsel->GetSelection;
my $pad_name = $padsel->GetString($selnum); $pad_name =~ s/\s*\(\d+\)//;
return unless my $encrypted = $u->encrypt($pad_name, $msg);
my $len = length($u->otps->{$pad_name}->{pad})/2;
$padsel->SetString($selnum, "$pad_name ($len)");
$dialog = qrdialog($encrypted, 'Scan the QR code or copy message from below', 'Send message');
$dialog->ShowModal;
};
$action{Receive} = sub { # Receive a message
my ($dialog, $msg);
if ($NOODLEPI) {
system ('v4l2-ctl --overlay=1');
open (ZBAR, "zbarcam --nodisplay --prescale=640x480 /dev/video0 |");
$msg = <ZBAR>; chomp $msg; $msg =~ s/^QR-Code://;
system ('killall -9 zbarcam');
close ZBAR;
system ('v4l2-ctl --overlay=0');
print "$msg\n";
}
else {
$dialog = Wx::TextEntryDialog->new( $frame, "Enter message:", "Receive message");
return if $dialog->ShowModal == wxID_CANCEL;
$msg = $dialog->GetValue();
}
return unless $msg;
return unless my ($decrypted, $pad, $oldlen) = $u->decrypt($msg);
my $padlen = length($pad->{pad})/2;
my $pad_name = pack('H*',$pad->{name});
my $selnum = $padsel->FindString("$pad_name ($oldlen)");
$padsel->SetString($selnum, "$pad_name ($padlen)");
$dialog = Wx::MessageDialog->new( $frame, "Received message:\n\n$decrypted", "Receive message");
$dialog->ShowModal;
};
$action{Exit} = sub { # Exit
$statusBar->SetStatusText("Exit", 0);
my $dialog = Wx::MessageDialog->new( $frame, "Do you really want to exit?", "Confirm", wxOK|wxCANCEL);
return if $dialog->ShowModal == wxID_CANCEL;
$app->ExitMainLoop;
};
EVT_BUTTON($frame, $button{$_}, $action{$_}) for (qw(Generate Import Export Send Receive Exit));
# Start the UI
show();
$statusBar->SetStatusText(_('Unsnoopable Ready'), 0);
$frame->Show; $frame->Centre(wxBOTH); $frame->Refresh;
$app->MainLoop;
# Helper functions
sub qrdialog {
my ($text, $msgtxt, $title) = @_;
my $len = length($text); my ($msg, $qr, $dialog, $version);
if ($len < 7090 ) {
my $qrfh; my $level;
my @version = qw( 0 41 77 127 187 255 322 370 461 552 652 772 883 1022 1101 1250 1408 1548 1725 1903 2061 2232
2409 2620 2812 3057 3283 3517 3669 3909 4158 4417 4686 4965 5253 5529 5836 6153 6479 6743 7089 );
for (1..40) { next if $len > $version[$_]; $version = $_; last; }
my $qrxpm = GD::Barcode::QRcode->new($text, { Version => $version, Ecc => L, ModuleSize => 4 })->barcode;
$qrxpm =~ /^(.*)$/m; my $qrsize = length($1);
$qr = Wx::Bitmap->newFromXPM([ split /\n/, "$qrsize $qrsize 2 1\n0 c #FFFFFF\n1 c #000000\n$qrxpm" ]);
}
if (defined $qr) {
my $fontheight = $frame->GetCharHeight;
$msg = "\n" x ($qr->GetHeight / $fontheight) . "\n\n$msgtxt";
$dialog = Wx::TextEntryDialog->new($frame, $msg , $title, $text);
my $dialog_height = $dialog->GetSize->GetHeight;
my $dialogwidth = $dialog->GetSize->GetWidth;
my $qrheight = $qr->GetHeight; my $width = $qrheight + 20 > $dialogwidth ? $qrheight + 20 : $dialogwidth;
my $adjust = 10 unless $^O eq 'MSWin32' or $^O eq 'darwin';
my $qrpos = ($width-$qrheight)/2 + ($width == 300 ? $adjust : 0);
$dialog->SetSize([$width,$dialog_height]);
$dialog->SetMinSize([$width,$dialog_height]);
$dialog->SetMaxSize([$width,$dialog_height]);
Wx::StaticBitmap->new( $dialog, -1, $qr, [$qrpos,10] );
( run in 1.640 second using v1.01-cache-2.11-cpan-7fcb06a456a )