added aes-128-cbc encryption testing
authorHeiko Schlittermann (JUMPER) <hs@schlittermann.de>
Sun, 31 Jul 2011 15:03:06 +0200
branchtesting
changeset 37 cb50d6c57439
parent 36 f361d688365c
child 38 fac6d76d06e8
added aes-128-cbc encryption
bin/imager.check
bin/imager.restore
bin/imager.save
scratch/x.pl
--- a/bin/imager.check	Fri Jul 29 16:06:55 2011 +0200
+++ b/bin/imager.check	Sun Jul 31 15:03:06 2011 +0200
@@ -133,6 +133,9 @@
             # we don't need uncompressed files if an compressed version
             # exists
             unlink $_ and return if -f "$_.gz";
+	    unlink "$_.x" and return if -f "$_.x.gz";
+
+	    # FIXME: do we need a compressed version?
 
             # cut away the first part of the filename and
             # some optional extension
@@ -201,7 +204,10 @@
 
         next
           if -f "$dir/data/$k"
-              or -f "$dir/data/$k.gz";
+              or -f "$dir/data/$k.gz"
+	      or -f "$dir/data/$k.x"
+	      or -f "$dir/data/$k.x.gz"
+	      or -f "$dir/data/$k.gz.x";
         say "missing $k @$i";
         @invalid{@$i} = ();
     }
--- a/bin/imager.restore	Fri Jul 29 16:06:55 2011 +0200
+++ b/bin/imager.restore	Sun Jul 31 15:03:06 2011 +0200
@@ -16,12 +16,17 @@
 use autodie qw(:all);
 use Pod::Usage;
 use Getopt::Long;
+use Hash::Util qw(lock_keys);
 use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
 
 use constant KiB => 1024;
 use constant MiB => 1024 * KiB;
 use constant GiB => 1024 * MiB;
 use constant ME  => basename $0;
+use constant CIPHER => "aes-128-cbc";
+
+my %o = (pass => "stdin");
+lock_keys(%o);
 
 sub find_data_dir;
 
@@ -29,8 +34,9 @@
 
     Getopt::Long::Configure(qw(Bundling));
     GetOptions(
-        "h|help" => sub { pod2usage(-verbose => 1, -exit => 0) },
-        "m|man"  => sub {
+        "p|pass=s" => \$o{pass},
+        "h|help"   => sub { pod2usage(-verbose => 1, -exit => 0) },
+        "m|man"    => sub {
             pod2usage(
                 -verbose   => 2,
                 -exit      => 0,
@@ -66,7 +72,7 @@
         if (-f "$data/$path") {
             open($in => "$data/$path");
             binmode($in);
-            local $/ = \$blocksize;
+            local $/ = undef;
             $buffer = <$in>;
         }
         elsif (-f "$data/$path.gz") {
@@ -75,6 +81,26 @@
             gunzip($in => \$buffer)
               or die $GunzipError;
         }
+        elsif (-f "$data/$path.x") {
+            open($in, "openssl @{[CIPHER]} -d -pass $o{pass} -in '$data/$path.x'|");
+            binmode($in);
+            local $/ = undef;
+            $buffer = <$in>;
+        }
+        elsif (-f "$data/$path.x.gz") {
+            warn "$data/$path.x.gz: depreciated!\n";
+            open($in,
+                "gzip -d -c $data/$path.x.gz | openssl bf -d -pass $o{pass}|");
+            binmode($in);
+            local $/ = undef;
+            $buffer = <$in>;
+        }
+        elsif (-f "$data/$path.gz.x") {
+            open($in, "openssl bf -d -pass $o{pass} -in $data/$path.gz.x|");
+            binmode($in);
+            gunzip($in => \$buffer)
+              or die $GunzipError;
+        }
         else {
             die ME . ": Can't open $data/$path: $!\n";
         }
@@ -100,7 +126,7 @@
 
 =head1 SYNOPSIS
 
-    imager.restore {idx} {destination}
+    imager.restore [options] {idx} {destination}
 
 =head1 DESCRIPTION
 
@@ -108,5 +134,22 @@
 cats them as one data stream. The destination can be any block device,
 a file name or even B<-> (STDOUT).
 
+=head1 OPTIONS
+
+=over
+
+=item B<-p> I<pass> | B<--pass=>I<pass>
+
+In case you expect encrypted data, this option takes the argument for
+B<openssl>'s C<-pass> option. See L<openssl(3)> for mor information.
+(default: stdin)
+
+=item B<-h>|B<--help>
+
+=item B<-m>|B<--man>
+
+The standard help options.
+
+=back
 
 =cut
--- a/bin/imager.save	Fri Jul 29 16:06:55 2011 +0200
+++ b/bin/imager.save	Sun Jul 31 15:03:06 2011 +0200
@@ -20,6 +20,7 @@
 use constant GiB      => 1024 * MiB;
 use constant NOW      => time();
 use constant DATETIME => strftime("%Y-%m-%dT%H:%M:%SZ" => gmtime(NOW));
+use constant CIPHER   => "aes-128-cbc";
 
 sub get_devsize;
 sub get_devname;
@@ -31,6 +32,7 @@
     compress  => undef,
     verbose   => undef,
     blocksize => 4 * MiB,
+    pass      => undef,
 );
 lock_keys(%o);
 
@@ -47,6 +49,7 @@
             );
         },
         "z|compress:i" => sub { $o{compress} = $_[1] ? $_[1] : Z_BEST_SPEED },
+	"p|pass=s"  => \$o{pass},
         "b|blocksize=s" => sub {
             given ($_[1]) {
                 when (/(\d+)G/i) { $o{blocksize} = $1 * GiB };
@@ -137,17 +140,27 @@
         my ($file, $ext, $cs);
         $file = $cs = md5_hex($buffer);
         $file =~ s/(?<fn>(?<prefix>...).*)/$+{prefix}\/$+{fn}/g;
-        $ext = $o{compress} ? ".gz" : "";
+	$ext = "";
+        $ext .= $o{compress} ? ".gz" : "";
+	$ext .= $o{pass} ? ".x" : "";
 
         # the extension we do not put into the index
         my $log = sprintf "%12d %s %s" => ($. - 1), $cs, $file;
 
-        if (not(-e "$data/$file" or -e "$data/$file.gz")) {
-            mkpath dirname("$data/$file.gz");
-            my $out = File::Temp->new(
+        if (not(-e "$data/$file" 
+	    or -e "$data/$file.gz"
+	    or -e "$data/$file.x"
+	    or -e "$data/$file.gz.x"
+	    or -e "$data/$file.x.gz")) {
+            mkpath dirname("$data/$file");
+	    my $out = File::Temp->new(
                 TEMPLATE => ".XXXXXXX",
                 DIR      => dirname("$data/$file")
             );
+
+	    if ($o{pass}) {
+		open($out, "|openssl @{[CIPHER]} -pass $o{pass} -out $out");
+	    }
             binmode($out);
             if ($o{compress}) {
                 gzip(
@@ -227,14 +240,18 @@
 
 =over
 
+=item B<-b> I<blocksize>|B<--blocksize>=I<blocksize>
+
+The blocksize used. (may be suffixed with K, M, G). (default: 4 MiB)
+
+=item B<-p> I<pass> | B<--pass>=I<pass>
+
+Use symmetric encryption for writing the data blocks.
+
 =item B<-z> [I<level>]|B<--compress>[=I<level>]
 
 Use compression when writing the blocks to disk. (default: off)
 
-=item B<-b> I<blocksize>|B<--blocksize>=I<blocksize>
-
-The blocksize used. (may be suffixed with K, M, G). (default: 4 MiB)
-
 =item B<-h>|B<--help>
 
 =item B<-m>|B<--man>
@@ -243,4 +260,12 @@
 
 =back
 
+=head1 PERFORMANCE
+
+Some experiments have shown that if compression and encryption is used,
+about 1/3 of the time is consumed by the encryption, and 2/3 are used
+for compression. The compression is done before(!) encrypting the file,
+since otherwise there is almost no benefit in compressing an encrypted
+file!
+
 =cut
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scratch/x.pl	Sun Jul 31 15:03:06 2011 +0200
@@ -0,0 +1,61 @@
+#!/usr/bin/perl
+use 5.010;
+use strict;
+use warnings;
+use Crypt::CBC;
+use autodie qw(:all);
+use Benchmark qw(:all);
+use IO::Compress::Gzip qw(gzip $GzipError);
+use File::Temp;
+
+my $tmp = File::Temp->new();
+warn "<< $tmp >>\n";
+
+my $cipher0 = Crypt::CBC->new(
+    -key => "x",
+    -keysize => 16,
+    -cipher => 'Blowfish',
+) or die;
+$ENV{X} = "x";
+
+@ARGV = qw(/boot/vmlinuz-2.6.32-5-amd64);
+my $text = join "" => <>;
+
+say length $text;
+
+cmpthese(30 => {
+    'openssl' => sub { openssl($text) },
+    'perlssl' => sub { perlssl($text) },
+    }
+);
+
+cmpthese(30 => {
+    'gzip' => sub { bingzip($text) },
+    'perlzip' => sub { perlzip($text) },
+    }
+);
+
+sub openssl {
+    open(my $out, "|openssl bf -pass env:X -out $tmp") or die;
+    print $out $_[0];
+    close $out;
+    die $? if $?;
+}
+
+sub perlssl {
+    open(my $out, ">$tmp");
+    print $out $cipher0->encrypt($_[0]);
+    close $out;
+}
+
+sub perlzip {
+    open(my $out, ">$tmp");
+    gzip($_[0] => $out);
+}
+
+sub bingzip {
+    open(my $out, "|gzip -1 >$tmp");
+    print $out $_[0];
+    close $out;
+    die $? if $?
+}