Crypt-IDA

 view release on metacpan or  search on metacpan

bin/SplitCombine.pl  view on Meta::CPAN

#use Gtk2::GladeXML;

package main;

my $dir=$0;
$dir=~s|(.*)/.*|$1|;
my $app="$dir/SplitCombine.xml";

#$gladexml = Gtk2::GladeXML->new($app);

#ui_callbacks::init($gladexml);

#$gladexml->signal_autoconnect_from_package("ui_callbacks" );

my $builder=Gtk2::Builder->new;

$builder->add_from_file($app);
ui_callbacks::init($builder);
$builder->connect_signals(undef, ui_callbacks);

warn "builder is $builder\n";

Gtk2->main;


1;


package ui_callbacks;

# The Gtk2::GladeXML module doesn't pass the user_data information
# from the glade file, so we have to have a separate callback for each
# widget. Which is a pity, because if it did, we could just implement
# one callback for each type of widget and use the user_data field to
# determine what name to store the new data under in the %split_opts
# or %combine_opts structures...

# One way of cutting down on the number of functions that need to be
# written is to use Perl's AUTOLOAD feature. By encoding the variable

lib/Crypt/IDA.pm  view on Meta::CPAN

  return $self->empty_to_fh($fh, $offset);
}

# ida_process_streams is the heart of the module. It's called from
# both ida_split and ida_combine, so it's capable of operating with
# just one or several fillers/emptiers. Its main purpose is to manage
# the input/output buffers, and it calls the external matrix multiply
# code to actually transform blocks of data in large chunks. For
# efficiency, it has some requirements on the organisation of
# input/output buffer matrices. It also delegates the task of
# reading/writing data to relatively simple user-supplied callbacks.
# This module isn't intended to be called by users directly, though,
# so it's not even documented in the POD section. Even though
# technically this could be useful if the user wanted to specify their
# own input/output matrices, there's so little error-checking of
# parameters here that it's probably best not to mention its
# existence/availability.

# the routine uses various tracking variables for each filler/emptier
# handle
use constant {

lib/Crypt/IDA.pm  view on Meta::CPAN

  unless ($nfillers == 1 or $nfillers==$IROWS) {
    carp "Fillers must be 1 or number of input rows";
    return undef;
  }
  unless ($nemptiers == 1 or $nemptiers == $OROWS) {
    carp "Emptiers must be 1 or number of output rows";
    return undef;
  }

  # Previously, I stashed vars inside the supplied fill/empty
  # callbacks, assuming that we might need them again if we were to be
  # called a second time. However, since the only way that this
  # routine can end is with an error or eof, neither is a condition
  # that we can continue on from.
  #
  # As a result, I'm changing to:
  # * only storing these vars locally
  # * storing them in an list of lists (rather than list of hashes)
  # (see constant definitions above)
  #
  my (@fillvars,@emptyvars);

lib/Crypt/IDA.pm  view on Meta::CPAN

  $align    null-pad input up a multiple of $align bytes
  $key      key parameter used to create transform matrix
  $mat      transform matrix/inverse transform matrix

=head2 Stream-processing design pattern

Rather than implement separate C<ida_split_string> or
C<ida_split_file> methods, a more flexible design which decouples the
details of the input and output streams from the actual processing is
used. In terms of design patterns, the C<ida_split> and C<ida_combine>
routines operate as stream processors, and use user-supplied callbacks
to read some bytes of input or write some bytes of output. Therefore,
the split and combine tasks break down into three steps:

=over

=item 1. Set up fill handler(s)

=item 2. Set up empty handler(s)

=item 3. Call processing routine (ida_split/ida_combine)

=back

For the C<ida_split> routine, a single "fill" handler is required,
while one or more "empty" handlers are required (one for each share to
be output). For the C<ida_combine> routine, the opposite is true: one
or more "fill" handlers are required (corresponding to the shares to
be combined), while a single "empty" handler (for the recombined
secret) is required.

The C<fill_from_*> and C<empty_to_*> routines create callbacks which
can be used by C<ida_split>/C<ida_combine>. Routines are provided for
creating callbacks given a string, filename or open file
handle. Custom callbacks (such as for reading/writing on a network
socket connection or an IPC message queue) can also be written quite
easily. See the section L<Writing Custom Callbacks> for more details.

=head2 Keys and transform matrices

Both the split and combine algorithms operate by performing matrix
multiplication over the input. In the case of the split operation, the
transform matrix has n rows (n=number of shares) and k columns
(k=quorum), while in the case of combine operation, the transform
matrix has k rows and k columns. Either operation is described simply

lib/Crypt/IDA.pm  view on Meta::CPAN

inverted. This inverted matrix is then used as the transform matrix
for the combine algorithm.

For more information, see the sections for L<KEY MANAGEMENT>, 
L<SPLIT OPERATION>, L<COMBINE OPERATION> and the L<SEE ALSO> section.

=head1 FILL/EMPTY CALLBACKS

=head2 "Fill" Callbacks

Fill callbacks are created by a call to one of:

 $source=fill_from_string ($string,$align);
 $source=fill_from_fh     ($fh,$align,$offset);
 $source=fill_from_file   ($filename,$align,$offset);

The C<$string>, C<$fh> and C<$filename> parameters should be
self-explanatory. The $offset parameter, where supplied, specifies an
offset to seek to in the file/file handle I<before> any reading takes
place. The C<$offset> parameter may be omitted, in which case it
defaults to 0, i.e., the start of the file.

lib/Crypt/IDA.pm  view on Meta::CPAN

those padding bytes after recovering the secret with C<ida_combine>.
This can be accomplished by removing null bytes from the end of the
secret (provided trailing nulls in the original secret are
prohibited), or (as is preferable for splitting/combining binary
files), by recording the original (unpadded) size of the secret and
truncating the reconstituted secret down to that size after calling
C<ida_combine>.

=head2 "Empty" Callbacks

The following routines are available for creating "empty" callbacks:

  $sink=empty_to_string    (\$string);
  $sink=empty_to_fh        ($fh,$offset);
  $sink=empty_to_file      ($filename,$perm,$offset);

All parameters with the same name are the same as in the "fill"
callbacks. Additionally, note that:

=over

=item * empty_to_string requires a I<reference> to a string variable
(to enable the callback to modify the string);

=item * empty handlers do not pad the output stream, so they don't
need an C<$align> parameter; and

=item * empty_to_file takes a C<$perm> (file permission) parameter,

lib/Crypt/IDA.pm  view on Meta::CPAN

=item * If the key and matrix parameters are unset, then a random
key/transform matrix will be generated and used to create the
shares. For a discussion of cases where you might want to override
this behaviour and supply your own values for these parameters, see
the L<Keys and transform matrices> and L<KEY MANAGEMENT> sections.

=item * sharelist is a reference to a list of rows to be operated on;
if specified, only shares corresponding to those rows in the transform
matrix will be created.

=item * emptiers is a reference to a list of empty callbacks. The list
should contain one empty callback for each share to be produced.

=item * rand can be set to "rand", in which case Perl's default
C<rand()> function will be used for generating keys. Otherwise, the
parameter is taken to be a file containing the random number to be
used (C</dev/urandom> and C</dev/random> are special devices on Linux
systems which generate different random numbers each time they are
read; see their man pages for details).

=item * bufsize specifies the size of the input and output buffer

lib/Crypt/IDA.pm  view on Meta::CPAN

calculated from k rows of the split transform matrix) to reconstruct
the original file.

Note that version 0.05 of Math::FastGF2 added a new C<new_vandermonde>
constructor methods to help with performing Reed-Solomon encoding.


=head2 Writing Custom Callbacks

The following code can be used as a template for writing routines
which create fill/empty callbacks which can be passed to C<ida_split>
and C<ida_combine>:

 sub create_my_ida_callback {
   my ($arg1, $arg2, ... ) = @_;

   # do some initialisation based on args, such as opening files,
   # connecting to a database, saving details of an IPC message queue,
   # etc.
 
   # for "fill" callbacks:
   return {
	   SUB => sub {
	     my $len=shift;
	     my $string;

             # some code to get/produce up to $len bytes of input and
             # place it in $string.  Since this is a closure, the
             # callback has access to the initial $arg1, $arg2 and any
             # other variables created in the enclosing routine.

	     if ($some_error_occurred) {
	       return undef;
	     } elsif ($no_more_input) {
	       return "";
	     } else {
	       return $string;
	     }
           },
	  };
 
   # for "empty" callbacks:
   return {
	   SUB => sub {
	     my $string=shift;

             # some code to save/consume new data bytes passed in
             # $string. The routine should return the number of bytes
             # actually processed, or undef if there was a (write)
             # error.

	     if ($some_error_occurred) {
	       # optionally set $! with error message
	       return undef;
	     } else {
	       return $number_of_bytes_actually_saved;
	     }
           },
	  };
 }

Note that callbacks are written using Perl's closure mechanism rather
than by passing simple code (subroutine) references. This is done to
allow the callback to be "customised" to use a particular file handle,
string, etc., as input or output. See the L<What's a closure?> section
in the Perl FAQ for more details on this construct. Also, a hashref is
used rather than a simple coderef since the processing routines use
that hash to store bookkeeping information such as buffer fill levels,
read/write pointers and so on.

The C<ida_split> and C<ida_combine> routines are written in such a way
that they handle most of the logic involved with buffering of input
and output and the details of reading/writing values in the
input/output matrices.  This means that callbacks can usually be kept
very simple and, for the most part, stateless. Specifically, if an
empty handler cannot process all bytes of input presented to it in one
call, it simply returns the number of bytes it actually
processed. There is no need for it to save any unprocessed part of the
input, and doing so will probably result in an error. Since the
calling routines know how many unprocessed bytes remain in the output
buffer, it will arrange so that the next time that particular empty
handler is called, it will receive those unprocessed bytes at the
start of its input string.

lib/Crypt/IDA/Algorithm.pm  view on Meta::CPAN

    inorder => 0, outorder => 0, # passed to getvals_str/setvals_str

    # Simplify transform/key specification. Either provide a transform
    # matrix or a key with optional sharelist. Don't support sharelist
    # with xform matrix or auto-generating a key.

    xform => undef,
    key => undef,		# [@xvals, @yvals]
    sharelist => undef,

    # add some callbacks below...
};

sub BUILD {
    my ($self, $args) = @_;
    for my $req ( qw(k w mode bufsize inorder outorder) ) {
	die "$req attribute required" unless defined $self->$req;
    }
    die "Bad mode!" unless $self->{mode} =~ /^(split|combine)$/;
    for my $plus ( qw(k w bufsize) ) {
	die "$plus attribute strictly positive" unless $self->$plus > 0;

lib/Crypt/IDA/Algorithm.pm  view on Meta::CPAN

when something "interesting" happens within the code (eg, new input
became available or space became available in the output buffer)

=back

=head2 NOTICE

This code has been tested to make sure that it replicates the
behaviour of the original C<Crypt::IDA> implementation. However, I
have not yet implemented any callback functionality that would make it
easier to integrate with an external event loop. I will add callbacks
in a later release.

=head1 CODE ORGANISATION

The internal organisation of the code has been improved. The main
C<Crypt::IDA> loops (C<ida_split> and C<ida_combine>) both call a
generic internal C<ida_process_streams> loop. It has very complicated
logic to enable it to handle different matrix layouts and circular
buffer reads/writes, as well as dealing with partial matrix columns.

lib/Crypt/IDA/Algorithm.pm  view on Meta::CPAN

flushed, so split/combine operations only block for as long as the
calculations take.

While I imagine that the above way of calling this class will be
typical, I also suspect that other people might have their own idea of
how this code should be called (or encapsulated) within their own
particular event framework. As with Perl, there's definitely more than
one way to do event-driven programming.

It seems that the easiest way to support arbitrary event loops is by
providing callbacks for when various "interesting" things happen
within the algorithm, such as an input matrix becoming full, or space
becoming available within the output matrix. This kind of approach is a
natural fit, since it's the dominant style of event-driven programming.

However, without untangling what the most common use cases are, it's
not really possible to determine in advance exactly I<which> callbacks
I should implement. I don't want to add unnecessary complexity or a
bunch of incompatible callbacks. As a result, I'm not going to tackle
that problem in this release.

As the code stands, there is I<partial> support for using callbacks.
The C<SlidingWindow> object (accessed via C<{sw}>) can be set up to
trigger a C<cb_write_bundle> or C<cb_read_bundle> callback when the
slowest stream in a substream advances.

=head1 AUTHOR

Declan Malone, E<lt>idablack@sourceforge.netE<gt>

=head1 COPYRIGHT AND LICENSE

lib/Crypt/IDA/SlidingWindow.pm  view on Meta::CPAN

    write_head => 0,		# } sis 
    write_tail => 0,		# start of window; last to advance
    # substream pointers (could be on read end or write end)
    # bundle => set up in BUILD
    
    # required
    mode => undef,		# 'split' or 'combine'
    rows => undef,		# how many substreams in bundle?
    window => undef,

    # optional callbacks (might move to Algorithm?)
    cb_error => undef,
    cb_read_bundle => undef,
    cb_wrote_bundle => undef,
    cb_processed => undef,
};

sub BUILD {
    my ($self, $args) = @_;
    for my $req ( qw(mode rows window) ) {
	die "$req attribute required" unless defined $self->$req;

lib/Crypt/IDA/SlidingWindow.pm  view on Meta::CPAN


    die "Use advance_write_substream instead" if $self->{splitting};
    my ($head,$tail) = ($self->{write_head}, $self->{write_tail});

    # Advance tail, but not past head.
    die "Write tail would overtake head" if $tail + $cols > $head;
    $self->{write_tail} += $cols;
}

# code for advancing read/write substreams is the same, apart from
# error messages, callbacks and overall pointer to possibly update
sub _advance_rw_substream;
sub advance_read_substream  { shift->_advance_rw_substream("read", @_) }
sub advance_write_substream { shift->_advance_rw_substream("write", @_)}


# Returns:
# * undef on error
# * 0 if OK and bundle pointer didn't advance
# * 1 if OK and bundle pointer did advance
sub _advance_rw_substream {

t/slide.t  view on Meta::CPAN

ok (0 == $c->advance_read_substream(0,1), "can advance row 0 by 1");
($rok,$pok,$wok,$subs) = $c->can_advance;

is ($rok, 10, "expect read one substream not to advance parent");
is ($pok, 0,  "expect read one substream not to allow processing");
is ($wok, 0,  "expect read independent of write");
is ($subs->[0], 9, "expect reduced read space in substream");
is ($c->bundle->[0]->{head}, 1, "advanced substream's head variable");
is ($c->yts, 2, "expect read substream to decrement 'yet to start'");

is ($read_cb_count, 0, "expect no read callbacks yet");

eval { $c->advance_read_substream(0,10) };
ok ($@, "expect error advancing substream past window");

# 2. advance row 1 by 4
ok (0 == $c->advance_read_substream(1,4), "can advance row 1 by 4");
($rok,$pok,$wok,$subs) = $c->can_advance;

is ($rok, 10, "expect read two substreams not to advance parent");
is ($pok, 0,  "expect read two substream not to allow processing");
is ($wok, 0,  "expect read still independent of write");
is ($subs->[1], 6, "expect reduced read space in substream");
is ($c->bundle->[1]->{head}, 4, "advanced substream's head variable");
is ($c->yts, 1, "expect read substream to decrement 'yet to start'");

is ($read_cb_count, 0, "expect no read callbacks yet");

# 3. advance row 2 by 6 (triggering update of parent)
ok(1 == $c->advance_read_substream(2,6), "can advance row 2 by 6");
($rok,$pok,$wok,$subs) = $c->can_advance;

is ($rok, 9,  "expect read 3 substreams advance parent by min");
is ($pok, 1,  "expect read 3 substreams to allow processing");
is ($wok, 0,  "expect read still independent of write");
is ($subs->[2], 4, "expect reduced read space in substream");
is ($c->bundle->[2]->{head}, 6, "advanced substream's head variable");



( run in 0.455 second using v1.01-cache-2.11-cpan-9b1e4054eb1 )