added the ability to encrypt fwknop client plaintext data with openssl
This commit is contained in:
+271
-104
@@ -1,10 +1,33 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Author: Michael Rash <mbr@cipherdyne.org>
|
||||
#
|
||||
|
||||
use MIME::Base64;
|
||||
use IPC::Open2;
|
||||
use Data::Password::Entropy;
|
||||
use Getopt::Long 'GetOptions';
|
||||
use strict;
|
||||
|
||||
my $use_ent = 1;
|
||||
my $use_pw_entropy = 0;
|
||||
my $base64_decode = 1;
|
||||
my $no_base64_decode = 0;
|
||||
my $packets = 0;
|
||||
my $prefix = 'entropy';
|
||||
my $file_to_measure = '';
|
||||
my $run_fwknop_client = 0;
|
||||
my $min_len = 0;
|
||||
my $lib_dir = '../../lib/.libs';
|
||||
my $fwknop_client_path = '../../client/.libs/fwknop';
|
||||
my $enc_mode = 'ecb';
|
||||
my $spa_key_file = 'local_spa.key';
|
||||
my $help = 0;
|
||||
|
||||
my $use_openssl = 0;
|
||||
my $openssl_salt = '0000000000000000';
|
||||
my $openssl_mode = '-aes-256-cbc';
|
||||
|
||||
my %min_max_entropy = (
|
||||
'min' => {
|
||||
'val' => 0,
|
||||
@@ -15,61 +38,50 @@ my %min_max_entropy = (
|
||||
'pos' => 0,
|
||||
}
|
||||
);
|
||||
|
||||
my @encrypted_data = ();
|
||||
my @plaintext_data = ();
|
||||
my @cross_pkt_data = ();
|
||||
|
||||
while (<STDIN>) {
|
||||
next unless $_ =~ /\S/;
|
||||
chomp;
|
||||
Getopt::Long::Configure('no_ignore_case');
|
||||
die "[*] See '$0 -h' for usage information" unless (GetOptions(
|
||||
'file-to-measure=s' => \$file_to_measure,
|
||||
'no-base64-decode' => \$no_base64_decode,
|
||||
'count=i' => \$packets,
|
||||
'prefix=s' => \$prefix,
|
||||
'run-fwknop-client' => \$run_fwknop_client,
|
||||
'enc-mode=s' => \$enc_mode,
|
||||
'lib-dir=s' => \$lib_dir,
|
||||
'Client-path=s' => \$fwknop_client_path,
|
||||
'use-pw-entropy' => \$use_pw_entropy,
|
||||
'use-openssl' => \$use_openssl,
|
||||
'openssl-salt=s' => \$openssl_salt,
|
||||
'openssl-mode=s' => \$openssl_mode,
|
||||
'help' => \$help,
|
||||
));
|
||||
&usage() if $help;
|
||||
|
||||
push @encrypted_data, $_;
|
||||
next;
|
||||
$base64_decode = 0 if $no_base64_decode;
|
||||
$use_ent = 0 if $use_pw_entropy;
|
||||
die "[*] Must execute --run-fwknop-client in --use-openssl mode"
|
||||
if $use_openssl and not $run_fwknop_client;
|
||||
|
||||
my $base64_str = $_;
|
||||
unless ($base64_str =~ /^U2FsdGVkX1/) {
|
||||
$base64_str = 'U2FsdGVkX1' . $base64_str;
|
||||
}
|
||||
my ($equals_rv, $equals_padding) = &base64_equals_padding($base64_str);
|
||||
if ($equals_padding) {
|
||||
$base64_str .= $equals_padding;
|
||||
}
|
||||
push @encrypted_data, decode_base64($base64_str);
|
||||
}
|
||||
&run_fwknop_client() if $run_fwknop_client;
|
||||
|
||||
### calculate minimum length
|
||||
my $min_len = 0;
|
||||
for my $line (@encrypted_data) {
|
||||
chomp $line;
|
||||
next unless $line =~ /\S/;
|
||||
my $len = length($line);
|
||||
if ($min_len == 0) {
|
||||
$min_len = $len;
|
||||
} else {
|
||||
if ($len < $min_len) {
|
||||
$min_len = $len;
|
||||
}
|
||||
}
|
||||
}
|
||||
&read_data();
|
||||
|
||||
my $l_ctr = 0;
|
||||
for my $line (@encrypted_data) {
|
||||
my @chars = split //, $line;
|
||||
my $c_ctr = 0;
|
||||
for my $char (@chars) {
|
||||
$cross_pkt_data[$c_ctr] .= $char;
|
||||
last if $c_ctr == $min_len;
|
||||
$c_ctr++;
|
||||
}
|
||||
$l_ctr++;
|
||||
}
|
||||
&get_min_len();
|
||||
|
||||
open F, "> entropy.dat" or die $!;
|
||||
&build_data_slices();
|
||||
|
||||
open F, "> $prefix.dat" or die $!;
|
||||
my $pos = 0;
|
||||
for my $str (@cross_pkt_data) {
|
||||
|
||||
my $entropy = &get_entropy($str);
|
||||
|
||||
print F "$pos $entropy\n";
|
||||
# print F "$pos $entropy\n";
|
||||
print F "$pos $entropy ### " . &hex_dump($str) . "\n";
|
||||
|
||||
if ($min_max_entropy{'min'}{'val'} == 0
|
||||
and $min_max_entropy{'max'}{'val'} == 0) {
|
||||
@@ -93,57 +105,210 @@ close F;
|
||||
|
||||
my $min = $min_max_entropy{'min'}{'val'};
|
||||
my $max = $min_max_entropy{'max'}{'val'};
|
||||
print "Min entropy: $min at position: $min_max_entropy{'min'}{'pos'}\n";
|
||||
print "Max entropy: $max at position: $min_max_entropy{'max'}{'pos'}\n";
|
||||
|
||||
open F, "> entropy.gnu" or die $!;
|
||||
print F <<_GNUPLOT_;
|
||||
set title "entropy measurement"
|
||||
set terminal gif nocrop enhanced
|
||||
set output "entropy.gif"
|
||||
set grid
|
||||
plot 'entropy.dat' using 1:2 with lines title 'min: $min, max: $max'
|
||||
_GNUPLOT_
|
||||
close F;
|
||||
print "[+] Min entropy: $min at byte: $min_max_entropy{'min'}{'pos'}\n";
|
||||
print "[+] Max entropy: $max at byte: $min_max_entropy{'max'}{'pos'}\n";
|
||||
|
||||
system "gnuplot entropy.gnu";
|
||||
&run_gnuplot();
|
||||
|
||||
exit 0;
|
||||
|
||||
sub read_data() {
|
||||
|
||||
if ($use_openssl) {
|
||||
|
||||
### we've already gotten plaintext information from the fwknop client,
|
||||
### so encrypt this data with openssl and use it to re-write the
|
||||
### $file_to_measure
|
||||
unlink $file_to_measure if -e $file_to_measure;
|
||||
|
||||
my @openssl_encrypted_data = ();
|
||||
|
||||
### encrypt the plaintext and use it to re-write the -f file
|
||||
for my $line (@plaintext_data) {
|
||||
|
||||
my $ptext_file = 'ptext.tmp';
|
||||
my $enc_file = 'ptext.enc';
|
||||
|
||||
open F, "> $ptext_file" or die $!;
|
||||
print F $line;
|
||||
close F;
|
||||
|
||||
unlink $enc_file if -e $enc_file;
|
||||
|
||||
system "openssl enc $openssl_mode -a -S $openssl_salt " .
|
||||
"-in ptext.tmp -out ptext.enc -k fwknoptest000000";
|
||||
|
||||
my $base64_enc_data = '';
|
||||
open F, "< $enc_file" or die $!;
|
||||
while (<F>) {
|
||||
chomp;
|
||||
$base64_enc_data .= $_;
|
||||
}
|
||||
close F;
|
||||
|
||||
push @openssl_encrypted_data, $base64_enc_data;
|
||||
|
||||
}
|
||||
|
||||
open F, "> $file_to_measure" or die $!;
|
||||
for my $line (@openssl_encrypted_data) {
|
||||
print F $line, "\n";
|
||||
}
|
||||
close F;
|
||||
}
|
||||
|
||||
my $fh = *STDIN;
|
||||
if ($file_to_measure) {
|
||||
open IN, "< $file_to_measure" or die "[*] Could not open $file_to_measure: $!";
|
||||
$fh = *IN;
|
||||
}
|
||||
|
||||
my $l_ctr = 0;
|
||||
while (<$fh>) {
|
||||
next unless $_ =~ /\S/;
|
||||
chomp;
|
||||
|
||||
if ($base64_decode) {
|
||||
if (&is_base64($_)) {
|
||||
my $base64_str = $_;
|
||||
### base64-encoded "Salted__" prefix
|
||||
unless ($base64_str =~ /^U2FsdGVkX1/) {
|
||||
$base64_str = 'U2FsdGVkX1' . $base64_str;
|
||||
}
|
||||
my ($equals_rv, $equals_padding) = &base64_equals_padding($base64_str);
|
||||
if ($equals_padding) {
|
||||
$base64_str .= $equals_padding;
|
||||
}
|
||||
push @encrypted_data, decode_base64($base64_str);
|
||||
} else {
|
||||
push @encrypted_data, $_;
|
||||
}
|
||||
} else {
|
||||
push @encrypted_data, $_;
|
||||
}
|
||||
|
||||
$l_ctr++;
|
||||
if ($packets > 0) {
|
||||
last if $l_ctr == $packets;
|
||||
}
|
||||
}
|
||||
|
||||
### hex dump encrypted data
|
||||
open HEX, "> hex_dump.data" or die $!;
|
||||
for my $line (@encrypted_data) {
|
||||
print HEX &hex_dump($line), "\n";
|
||||
}
|
||||
close HEX;
|
||||
|
||||
print "[+] Read in $l_ctr SPA packets...\n";
|
||||
return;
|
||||
}
|
||||
|
||||
sub run_fwknop_client() {
|
||||
die "[*] Must set packets file with -f <file>" unless $file_to_measure;
|
||||
die "[*] Must set packet count with -c <count>" unless $packets;
|
||||
|
||||
if (-e $file_to_measure) {
|
||||
unlink $file_to_measure or die $!;
|
||||
}
|
||||
|
||||
my $cmd = "LD_LIBRARY_PATH=$lib_dir $fwknop_client_path -A tcp/22 " .
|
||||
"-a 127.0.0.2 -D 127.0.0.1 --get-key $spa_key_file -M $enc_mode " .
|
||||
"-B $file_to_measure -b -v --test 2> /dev/null";
|
||||
|
||||
print "[+] Running fwknop client via the following command:\n\n$cmd\n\n";
|
||||
|
||||
for (my $i=0; $i < $packets; $i++) {
|
||||
open C, "$cmd |" or die $!;
|
||||
while (<C>) {
|
||||
if (/Plaintext\:\s+(\S+)/) {
|
||||
push @plaintext_data, $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close C;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub get_min_len() {
|
||||
|
||||
### calculate minimum length
|
||||
for my $line (@encrypted_data) {
|
||||
chomp $line;
|
||||
next unless $line =~ /\S/;
|
||||
my $len = length($line);
|
||||
if ($min_len == 0) {
|
||||
$min_len = $len;
|
||||
} else {
|
||||
if ($len < $min_len) {
|
||||
$min_len = $len;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub build_data_slices() {
|
||||
for my $line (@encrypted_data) {
|
||||
my @chars = split //, $line;
|
||||
my $c_ctr = 0;
|
||||
for my $char (@chars) {
|
||||
$cross_pkt_data[$c_ctr] .= $char;
|
||||
last if $c_ctr == $min_len;
|
||||
$c_ctr++;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub run_gnuplot() {
|
||||
open F, "> $prefix.gnu" or die $!;
|
||||
print F <<_GNUPLOT_;
|
||||
set title "entropy measurement"
|
||||
set terminal gif nocrop enhanced
|
||||
set output "$prefix.gif"
|
||||
set grid
|
||||
plot '$prefix.dat' using 1:2 with lines title 'min: $min, max: $max'
|
||||
_GNUPLOT_
|
||||
close F;
|
||||
|
||||
print "[+] Creating $prefix.gif gnuplot graph...\n\n";
|
||||
system "gnuplot $prefix.gnu";
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub get_entropy() {
|
||||
my $data = shift;
|
||||
|
||||
#return password_entropy($data);
|
||||
|
||||
my $entropy = '';
|
||||
|
||||
### Entropy = 5.637677 bits per byte.
|
||||
# system "echo -n $data | ent | grep Entropy > tmp.ent";
|
||||
# open ENT, "< tmp.ent" or die $!;
|
||||
# my $line = <ENT>;
|
||||
# if ($line =~ /\s=\s(\d\S+)/) {
|
||||
# $entropy = $1;
|
||||
# }
|
||||
# close ENT;
|
||||
# return $entropy;
|
||||
if ($use_ent) {
|
||||
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'ent');
|
||||
|
||||
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'ent');
|
||||
print CHLD_IN $data;
|
||||
close CHLD_IN;
|
||||
|
||||
print CHLD_IN $data;
|
||||
close CHLD_IN;
|
||||
|
||||
while (<CHLD_OUT>) {
|
||||
if (/Entropy\s=\s(\d\S+)/) {
|
||||
$entropy = $1;
|
||||
last;
|
||||
while (<CHLD_OUT>) {
|
||||
### Entropy = 5.637677 bits per byte.
|
||||
if (/Entropy\s=\s(\d\S+)/) {
|
||||
$entropy = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
close CHLD_OUT;
|
||||
|
||||
waitpid( $pid, 0 );
|
||||
my $child_exit_status = $? >> 8;
|
||||
|
||||
} else {
|
||||
$entropy = password_entropy($data);
|
||||
}
|
||||
|
||||
close CHLD_OUT;
|
||||
|
||||
waitpid( $pid, 0 );
|
||||
my $child_exit_status = $? >> 8;
|
||||
|
||||
return $entropy;
|
||||
}
|
||||
|
||||
@@ -172,38 +337,40 @@ sub hex_dump() {
|
||||
|
||||
my @chars = split //, $data;
|
||||
my $ctr = 0;
|
||||
my $ascii_str = '';
|
||||
for my $char (@chars) {
|
||||
if ($ctr % 16 == 0) {
|
||||
print STDOUT " $ascii_str\n" if $ascii_str;
|
||||
printf STDOUT " 0x%.4x: ", $ctr;
|
||||
$ascii_str = '';
|
||||
}
|
||||
printf STDOUT "%.2x", ord($char);
|
||||
|
||||
if ((($ctr+1) % 2 == 0) and ($ctr % 16 != 0)) {
|
||||
print STDOUT ' ';
|
||||
}
|
||||
my $hex_part = '';
|
||||
my $ascii_part = '';
|
||||
|
||||
for my $char (@chars) {
|
||||
|
||||
$hex_part .= sprintf "%.2x", ord($char);
|
||||
|
||||
if ($char =~ /[^\x20-\x7e]/) {
|
||||
$ascii_str .= '.';
|
||||
$ascii_part .= '.';
|
||||
} else {
|
||||
$ascii_str .= $char;
|
||||
$ascii_part .= $char;
|
||||
}
|
||||
$ctr++;
|
||||
}
|
||||
if ($ascii_str) {
|
||||
my $remainder = 1;
|
||||
if ($ctr % 16 != 0) {
|
||||
$remainder = 16 - $ctr % 16;
|
||||
if ($remainder % 2 == 0) {
|
||||
$remainder = 2*$remainder + int($remainder/2) + 1;
|
||||
} else {
|
||||
$remainder = 2*$remainder + int($remainder/2) + 2;
|
||||
}
|
||||
}
|
||||
print STDOUT ' 'x$remainder, $ascii_str;
|
||||
return "$hex_part $ascii_part";
|
||||
# return "$ascii_part";
|
||||
}
|
||||
|
||||
sub is_base64() {
|
||||
my $data = shift;
|
||||
|
||||
### check to make sure the packet data only contains base64 encoded
|
||||
### characters per RFC 3548: 0-9, A-Z, a-z, +, /, =
|
||||
if ($data =~ /[^\x30-\x39\x41-\x5a\x61-\x7a\x2b\x2f\x3d]/) {
|
||||
return 0;
|
||||
}
|
||||
print STDOUT "\n";
|
||||
return;
|
||||
if ($data =~ /=[^=]/) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub usage() {
|
||||
print "$0 [options]\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user