~ubuntu-branches/ubuntu/maverick/ciphersaber/maverick

« back to all changes in this revision

Viewing changes to lib/Crypt/CipherSaber.pm

  • Committer: Bazaar Package Importer
  • Author(s): Jerome Marant
  • Date: 2002-03-27 07:23:42 UTC
  • Revision ID: james.westby@ubuntu.com-20020327072342-zcvplihmsszct2ok
Tags: upstream-0.60
ImportĀ upstreamĀ versionĀ 0.60

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
################################################################################
 
2
#       Crypt::CipherSaber
 
3
#
 
4
#               an object oriented module implementing CipherSaber-1 and CS-2
 
5
#               encryption
 
6
#
 
7
#       copyright (c) 2001 chromatic.  All rights reserved.
 
8
#       This program is free software; you can distribute and modify it under the
 
9
#       same terms as Perl itself.
 
10
################################################################################
 
11
 
 
12
package Crypt::CipherSaber;
 
13
 
 
14
use strict;
 
15
use Carp;
 
16
use vars qw($VERSION);
 
17
 
 
18
$VERSION = '0.60';
 
19
 
 
20
sub new {
 
21
        my $class = shift;
 
22
        my $key = shift;
 
23
 
 
24
        # CS-2 shuffles the state array N times, CS-1 once
 
25
        my $N = shift;
 
26
        if (!(defined $N) or ($N < 1)) {
 
27
                $N = 1;
 
28
        }
 
29
        my $self = [ $key, [ 0 .. 255 ], $N ];
 
30
        bless($self, $class);
 
31
}
 
32
 
 
33
sub crypt {
 
34
        my $self = shift;
 
35
        my $iv = shift;
 
36
        $self->_setup_key($iv);
 
37
        my $message = shift;
 
38
        my $state = $self->[1];
 
39
        my $output = _do_crypt($state, $message);
 
40
        $self->[1] = [ 0 .. 255 ];
 
41
        return $output;
 
42
}
 
43
 
 
44
sub encrypt {
 
45
        my $self = shift;
 
46
        my $iv = $self->_gen_iv();
 
47
        return $iv . $self->crypt($iv, @_);
 
48
}
 
49
 
 
50
sub decrypt {
 
51
        my $self = shift;
 
52
        my ($iv, $message) = unpack("a10a*", +shift);
 
53
        return $self->crypt($iv, $message);
 
54
}
 
55
 
 
56
sub fh_crypt {
 
57
        my $self = shift;
 
58
        my ($in, $out, $iv) = @_;
 
59
 
 
60
        unless(UNIVERSAL::isa($in, 'GLOB') and UNIVERSAL::isa($out, 'GLOB')) {
 
61
                carp "I need filehandles!";
 
62
                return;
 
63
        }
 
64
 
 
65
        local *OUT = $out;
 
66
        if (defined($iv)) {
 
67
                unless (length($iv) > 1) {
 
68
                        $iv = $self->_gen_iv();
 
69
                }
 
70
                $self->_setup_key($iv);
 
71
                print OUT $iv;
 
72
        }
 
73
 
 
74
        my $state = $self->[1];
 
75
 
 
76
        my ($buf, @vars);
 
77
 
 
78
        while (<$in>) {
 
79
                unless ($iv) {
 
80
                        ($iv, $_) = unpack("a10a*", $_);
 
81
                        $self->_setup_key($iv);
 
82
                }
 
83
                my $line;
 
84
                ($line, $state, @vars) = _do_crypt($state, $_, @vars);
 
85
                print OUT $line;
 
86
        }
 
87
        $self->[1] = [ 0 .. 255 ];
 
88
        return 1;
 
89
}
 
90
 
 
91
###################
 
92
#
 
93
# PRIVATE METHODS
 
94
#
 
95
###################
 
96
sub _gen_iv {
 
97
        my $iv;
 
98
        for (1 .. 10) {
 
99
                $iv .= chr(int(rand(255)));
 
100
        }
 
101
        return $iv;
 
102
}
 
103
 
 
104
sub _setup_key {
 
105
        my $self = shift;
 
106
        my $key = $self->[0] . shift;
 
107
        my @key = map { ord } split(//, $key);
 
108
        my $state = $self->[1];
 
109
        my $j = 0;
 
110
        my $length = @key;
 
111
 
 
112
        # repeat N times, for CS-2
 
113
        for (1 .. $self->[2]) {
 
114
                for my $i (0 .. 255) {
 
115
                        $j += ($state->[$i] + ($key[$i % $length]));
 
116
                        $j %= 256;
 
117
                        (@$state[$i, $j]) = (@$state[$j, $i]);
 
118
                }
 
119
        }
 
120
}
 
121
 
 
122
sub _do_crypt {
 
123
        my ($state, $message, $i, $j, $n) = @_;
 
124
 
 
125
        my $output;
 
126
 
 
127
        for (0 .. (length($message) - 1 )) {
 
128
                $i++;
 
129
                $i %= 256;
 
130
                $j += $state->[$i];
 
131
                $j %= 256;
 
132
                @$state[$i, $j] = @$state[$j, $i];
 
133
                $n = $state->[$i] + $state->[$j];
 
134
                $n %= 256;
 
135
                $output .= chr( $state->[$n] ^ ord(substr($message, $_, 1)) );
 
136
        }
 
137
 
 
138
        return wantarray ? ($output, $state, $i, $j, $n) : $output;
 
139
}
 
140
 
 
141
1;
 
142
 
 
143
__END__
 
144
 
 
145
=head1 NAME
 
146
 
 
147
Crypt::CipherSaber - Perl module implementing CipherSaber encryption.
 
148
 
 
149
=head1 SYNOPSIS
 
150
 
 
151
  use Crypt::CipherSaber;
 
152
  my $cs = Crypt::CipherSaber->new('my pathetic secret key');
 
153
 
 
154
  my $coded = $cs->encrypt('Here is a secret message for you');
 
155
  my $decoded = $cs->decrypt($coded);
 
156
 
 
157
  # encrypt from and to a file
 
158
  open(INFILE, 'secretletter.txt') or die "Can't open infile: $!";
 
159
  open(OUTFILE, '>secretletter.cs1') or die "Can't open outfile: $!";
 
160
  binmode(INFILE);
 
161
  binmode(OUTFILE);
 
162
  $cs->fh_crypt(\*INFILE, \*OUTFILE, 1);
 
163
 
 
164
  # decrypt from and to a file
 
165
  open(INFILE, 'secretletter.cs1') or die "Can't open infile: $!";
 
166
  open(OUTFILE, '>secretletter.txt') or die "Can't open outfile: $!";
 
167
  binmode(INFILE);
 
168
  binmode(OUTFILE);
 
169
  $cs->fh_crypt(\*INFILE, \*OUTFILE);
 
170
 
 
171
=head1 DESCRIPTION
 
172
 
 
173
The Crypt::CipherSaber module implements CipherSaber encryption, described at
 
174
http://ciphersaber.gurus.com.  It is simple, fairly speedy, and relatively
 
175
secure algorithm based on RC4.
 
176
 
 
177
Encryption and decryption are done based on a secret key, which must be shared
 
178
with all intended recipients of a message.
 
179
 
 
180
=head1 METHODS
 
181
 
 
182
=over
 
183
 
 
184
=item B<new($key, $N)>
 
185
 
 
186
Initialize a new Crypt::CipherSaber object.  $key, the key used to encrypt or to
 
187
decrypt messages is required.  $N is optional.  If provided and greater than
 
188
one, it will implement CipherSaber-2 encryption (slightly slower but more
 
189
secure).  If not specified, or equal to 1, the module defaults to CipherSaber-1
 
190
encryption.  $N must be a positive integer greater than one.
 
191
 
 
192
=item B<encrypt($message)>
 
193
 
 
194
Encrypt a message.  This uses the key stored in the current Crypt::CipherSaber 
 
195
object.  It will generate a 10-byte random IV (Initialization Vector) 
 
196
automatically, as defined in the RC4 specification.  This returns a string 
 
197
containing the encrypted message.
 
198
 
 
199
Note that the encrypted message may contain unprintable characters, as it uses
 
200
the extended ASCII character set (valid numbers 0 through 255).
 
201
 
 
202
=item B<decrypt($message)>
 
203
 
 
204
Decrypt a message.  For the curious, the first ten bytes of an encrypted
 
205
message are the IV, so this must strip it off first.  This returns a string
 
206
containing the decrypted message.
 
207
 
 
208
The decrypted message may also contain unprintable characters, as the
 
209
CipherSaber encryption scheme can handle binary files with fair ease.  If this
 
210
is important to you, be sure to treat the results correctly.
 
211
 
 
212
=item B<crypt($iv, $message)>
 
213
 
 
214
If you wish to generate the IV with a more cryptographically secure random
 
215
string (at least compared to Perl's builtin rand() function), you may do so
 
216
separately, passing it to this method directly.  The IV must be a ten-byte
 
217
string consisting of characters from the extended ASCII set.
 
218
 
 
219
This is generally only useful for encryption, although you may extract the
 
220
first ten characters of an encrypted message and pass them in yourself.  You
 
221
might as well call B<decrypt()>, though.  The more random the IV, the stronger
 
222
the encryption tends to be.  On some operating systems, you can read from
 
223
/dev/random.  Other approaches are the Math::TrulyRandom module, or compressing
 
224
a file, removing the headers, and compressing it again.
 
225
 
 
226
=item B<fh_crypt(\*INPUT, \*OUTPUT, ($iv))>
 
227
 
 
228
For the sake of efficiency, Crypt::CipherSaber can now operate on filehandles.
 
229
It's not super brilliant, but it's relatively fast and sane.  Pass in a
 
230
reference to the input file handle and the output filehandle.  If your platform
 
231
needs to use C<binmode()>, this is your responsibility.  It is also your
 
232
responsibility to close the files.
 
233
 
 
234
You may also pass in an optional third parameter, an IV.  There are three
 
235
possibilities here.  If you pass no IV, C<fh_crypt()> will pull the first ten
 
236
bytes from *INPUT and use that as an IV.  This corresponds to decryption.  If 
 
237
you pass in an IV of your own (generally ten digits, but more than one digits 
 
238
as the code is now), it will use your own IV when encrypting the file.  If you
 
239
pass in the value '1', it will generate a new, random IV for you.  This
 
240
corresponds to an encryption.
 
241
 
 
242
=back
 
243
 
 
244
=head1 AUTHOR
 
245
 
 
246
chromatic <chromatic@wgz.org>
 
247
 
 
248
thanks to jlp for testing, moral support, and never fearing the icky details and to the fine folks at http://perlmonks.org
 
249
 
 
250
Additional thanks to Olivier Salaun and the Sympa project (http://www.sympa.org)
 
251
for testing.
 
252
 
 
253
=head1 SEE ALSO
 
254
 
 
255
the CipherSaber home page at http://ciphersaber.gurus.com
 
256
 
 
257
perl(1), rand().
 
258
 
 
259
=cut