1: ############################################################
2: # Here's a module I'm packaging up for the CPAN.
3: # It implements the simple-yet-effective CipherSaber
4: # encryption scheme, levels one and two. Instructions are
5: # in the POD.
6: #
7: # If you have time, I'd appreciate a review and any
8: # recommendations. Thanks in advance.
9: ############################################################
10: package Crypt::CipherSaber;
11:
12: use strict;
13: use vars qw($VERSION);
14:
15: $VERSION = '0.02';
16:
17: sub new {
18: my $class = shift;
19: my $key = shift;
20:
21: # CS-2 shuffles the state array N times, CS-1 once
22: my $N = shift;
23: if (!(defined $N) or ($N < 1)) {
24: $N = 1;
25: }
26: my $self = [ $key, [ 0 .. 255 ], $N ];
27: bless($self, $class);
28: }
29:
30: sub crypt {
31: my $self = shift;
32: my $iv = shift;
33: $self->_setup_key($iv);
34: my $message = shift;
35: my $state = $self->[1];
36: my ($i, $j, $n) = (0, 0, 0);
37: my $output;
38: for (0 .. (length($message) -1 )) {
39: $i++;
40: $i %= 256;
41: $j += $state->[$i];
42: $j %= 256;
43: @$state[$i, $j] = @$state[$j, $i];
44: $n = $state->[$i] + $state->[$j];
45: $n %= 256;
46: $output .= chr( $state->[$n] ^ ord(substr($message, $_, 1)) );
47: }
48: $self->[1] = [ 0 .. 255 ];
49: return $output;
50: }
51:
52: sub encrypt {
53: my $self = shift;
54: my $iv = $self->_gen_iv();
55: return $iv . $self->crypt($iv, @_);
56: }
57:
58: sub decrypt {
59: my $self = shift;
60: my $message = shift;
61: my $iv = substr($message, 0, 10, '');
62: return $self->crypt($iv, $message);
63: }
64:
65: ###################
66: #
67: # PRIVATE METHODS
68: #
69: ###################
70: sub _gen_iv {
71: my $iv;
72: $iv .= chr(int(rand(255))) for (1 .. 10);
73: return $iv;
74: }
75:
76: sub _setup_key {
77: my $self = shift;
78: my $key = $self->[0] . shift;
79: my @key = map { ord } split(//, $key);
80: my $state = $self->[1];
81: my $j = 0;
82: my $length = @key;
83:
84: # repeat N times, for CS-2
85: for (1 .. $self->[2]) {
86: for my $i (0 .. 255) {
87: $j += ($state->[$i] + ($key[$i % $length]));
88: $j %= 256;
89: (@$state[$i, $j]) = (@$state[$j, $i]);
90: }
91: }
92: }
93:
94: 1;
95:
96: __END__
97:
98: =head1 NAME
99:
100: Crypt::CipherSaber - Perl module implementing CipherSaber encryption.
101:
102: =head1 SYNOPSIS
103:
104: use Crypt::CipherSaber;
105: my $cs = Crypt::CipherSaber->new('my pathetic secret key');
106:
107: my $coded = $cs->encrypt('Here is a secret message for you');
108: my $decoded = $cs->decrypt($coded);
109:
110: =head1 DESCRIPTION
111:
112: The Crypt::CipherSaber module implements CipherSaber encryption, described at
113: http://ciphersaber.gurus.com. It is simple, fairly speedy, and relatively
114: secure algorithm based on RC4.
115:
116: Encryption and decryption are done based on a secret key, which must be shared
117: with all intended recipients of a message.
118:
119: =head1 METHODS
120:
121: =item new($key, $N)
122:
123: Initialize a new Crypt::CipherSaber object. $key, the key used to encrypt or to
124: decrypt messages is required. $N is optional. If provided and greater than
125: one, it will implement CipherSaber-2 encryption (slightly slower but more
126: secure). If not specified, or equal to 1, the module defaults to CipherSaber-1
127: encryption. $N must be a positive integer greater than one.
128:
129: =item encrypt($message)
130:
131: Encrypt a message. This uses the key stored in the current Crypt::CipherSaber
132: object. It will generate a 10-byte random IV (Initialization Vector)
133: automatically, as defined in the RC4 specification. This returns a string
134: containing the encrypted message.
135:
136: Note that the encrypted message may contain unprintable characters, as it uses
137: the extended ASCII character set (valid numbers 0 through 255).
138:
139: =item decrypt($message)
140:
141: Decrypt a message. For the curious, the first ten bytes of an encrypted
142: message are the IV, so this must strip it off first. This returns a string
143: containing the decrypted message.
144:
145: The decrypted message may also contain unprintable characters, as the
146: CipherSaber encryption scheme can handle binary files with fair ease. If this
147: is important to you, be sure to treat the results correctly.
148:
149: =item crypt($iv, $message)
150:
151: If you wish to generate the IV with a more cryptographically secure random
152: string (at least compared to Perl's builtin rand() function), you may do so
153: separately, passing it to this method directly. The IV must be a ten-byte
154: string consisting of characters from the extended ASCII set.
155:
156: This is generally only useful for encryption, although you may extract the
157: first ten characters of an encrypted message and pass them in yourself. You
158: might as well call B<decrypt()>, though.
159:
160: =head1 AUTHOR
161:
162: chromatic <chromatic@wgz.org>
163:
164: thanks to jlp for testing and moral support, and to the fine
165: folks at http://perlmonks.org
166:
167: =head1 SEE ALSO
168:
169: the CipherSaber home page at http://ciphersaber.gurus.com
170:
171: perl(1), rand().
172:
173: =cut