File Coverage

blib/lib/Crypt/CipherSaber.pm
Criterion Covered Total %
statement 79 79 100.0
branch 12 12 100.0
condition 5 5 100.0
subroutine 12 12 100.0
pod 5 5 100.0
total 113 113 100.0


line stmt bran cond sub pod time code
1             package Crypt::CipherSaber;
2              
3 7     7   25342 use strict;
  7         18  
  7         298  
4              
5 7     7   34 use Carp;
  7         11  
  7         555  
6 7     7   42 use Scalar::Util 'reftype';
  7         12  
  7         537  
7              
8 7     7   29 use vars '$VERSION';
  7         14  
  7         6332  
9              
10             $VERSION = '1.01';
11              
12             sub new
13             {
14 8     8 1 5645 my ($class, $key, $N) = @_;
15              
16             # CS-2 shuffles the state array N times, CS-1 once
17 8 100 100     52 if ( !( defined $N ) or ( $N < 1 ) )
18             {
19 7         12 $N = 1;
20             }
21 8         135 bless [ $key, [ 0 .. 255 ], $N ], $class;
22             }
23              
24             sub crypt
25             {
26 6     6 1 11 my ($self, $iv, $message) = @_;
27 6         15 $self->_setup_key($iv);
28              
29 6         14 my $state = $self->[1];
30 6         19 my $output = _do_crypt( $state, $message );
31 6         99 $self->[1] = [ 0 .. 255 ];
32 6         58 return $output;
33             }
34              
35             sub encrypt
36             {
37 2     2 1 56 my $self = shift;
38 2         8 my $iv = $self->_gen_iv();
39 2         8 return $iv . $self->crypt( $iv, @_ );
40             }
41              
42             sub decrypt
43             {
44 3     3 1 499 my $self = shift;
45 3         21 my ( $iv, $message ) = unpack( "a10a*", +shift );
46 3         15 return $self->crypt( $iv, $message );
47             }
48              
49             sub fh_crypt
50             {
51 7     7 1 3693 my ( $self, $in, $out, $iv ) = @_;
52              
53 7         18 for my $glob ($in, $out)
54             {
55 13   100     60 my $reftype = reftype( $glob ) || '';
56 13 100       35 unless ($reftype eq 'GLOB')
57             {
58 2         13 require Carp;
59 2         31 Carp::carp( 'Non-filehandle passed to fh_crypt()' );
60 2         833 return;
61             }
62             }
63              
64 5         18 local *OUT = $out;
65 5 100       14 if ( defined($iv) )
66             {
67 2 100       9 $iv = $self->_gen_iv() if length($iv) == 1;
68 2         6 $self->_setup_key($iv);
69 2         19 print OUT $iv;
70             }
71              
72 5         12 my $state = $self->[1];
73              
74 5         6 my ( $buf, @vars );
75              
76 5         61 while (<$in>)
77             {
78 32 100       62 unless ($iv)
79             {
80 3         16 ( $iv, $_ ) = unpack( "a10a*", $_ );
81 3         8 $self->_setup_key($iv);
82             }
83 32         26 my $line;
84 32         66 ( $line, $state, @vars ) = _do_crypt( $state, $_, @vars );
85 32         270 print OUT $line;
86             }
87 5         129 $self->[1] = [ 0 .. 255 ];
88 5         73 return 1;
89             }
90              
91             ###################
92             #
93             # PRIVATE METHODS
94             #
95             ###################
96             sub _gen_iv
97             {
98 3     3   5 my $iv;
99 3         11 for ( 1 .. 10 )
100             {
101 30         162 $iv .= chr( int( rand(256) ) );
102             }
103 3         419 return $iv;
104             }
105              
106             sub _setup_key
107             {
108 11     11   18 my $self = shift;
109 11         40 my $key = $self->[0] . shift;
110 11         61 my @key = map { ord } split( //, $key );
  239         222  
111 11         34 my $state = $self->[1];
112 11         12 my $j = 0;
113 11         20 my $length = @key;
114              
115             # repeat N times, for CS-2
116 11         28 for ( 1 .. $self->[2] )
117             {
118 19         30 for my $i ( 0 .. 255 )
119             {
120 4864         4789 $j += ( $state->[$i] + ( $key[ $i % $length ] ) );
121 4864         3560 $j %= 256;
122 4864         5766 ( @$state[ $i, $j ] ) = ( @$state[ $j, $i ] );
123             }
124             }
125             }
126              
127             sub _do_crypt
128             {
129 38     38   66 my ( $state, $message, $i, $j, $n ) = @_;
130              
131 38         46 my $output = '';
132              
133 38         81 for ( 0 .. ( length($message) - 1 ) )
134             {
135 8269         5458 $i++;
136 8269         5950 $i %= 256;
137 8269         6592 $j += $state->[$i];
138 8269         5793 $j %= 256;
139 8269         9311 @$state[ $i, $j ] = @$state[ $j, $i ];
140 8269         7538 $n = $state->[$i] + $state->[$j];
141 8269         5840 $n %= 256;
142 8269         9976 $output .= chr( $state->[$n] ^ ord( substr( $message, $_, 1 ) ) );
143             }
144              
145 38 100       246 return wantarray ? ( $output, $state, $i, $j, $n ) : $output;
146             }
147              
148             1;
149              
150             __END__