1# easy en/decryption with DES/IDEA/Blowfish and some other ciphers
2# Mike Blazer <blazer@mail.nevalink.ru>
3
4package Crypt::CBCeasy;
5
6use 5.003;
7use Crypt::CBC;
8use Carp;
9use Symbol;
10
11use strict;
12no strict 'refs';
13use vars qw($VERSION @DEFAULT_CIPHERS $LastCipher);
14
15$VERSION = '0.24';
16@DEFAULT_CIPHERS = qw/DES IDEA Blowfish/;
17
18
19#--------------
20sub useCBC {
21#--------------
22# $from - handler (r), filename or just plain or encrypted text
23# $to   - handler (r), or filename. If '' or undef sub returns $to-string
24  my ($key, $from, $to) = @_;
25  my $sub               = (caller(1))[3]; # caller subroutine
26  my ($algorithm, $op)  = $sub =~ /^(.*)::(.*)$/;
27#print "$algorithm, $op\n";
28  $LastCipher = $algorithm;
29
30  my ($fhi, $fho, $fromFile, $INopened, $OUTopened,
31      $buffer, $fromStr, $toStr, $cipher);
32
33  croak "CBCeasy: source not defined\n"      unless defined $from;
34  croak "CBCeasy: key not defined\n"         unless defined $key;
35  croak "CBCeasy: I can do only `encipher' or `decipher'\n"
36     unless $op && $op =~ /^(encipher|decipher)$/i;
37
38  if ((UNIVERSAL::isa($from, 'GLOB') ||     # \*HANDLE
39       UNIVERSAL::isa(\$from,'GLOB')        # *HANDLE
40       ) &&  defined fileno $from
41     ) {
42
43     $fhi = $from;
44     $fromFile = 1;
45
46  } elsif (-e $from && -r _) {      # filename
47     $fhi = gensym;
48     $fromFile = 1;
49     $INopened = 1;
50     open ($fhi, $from) || croak "CBCeasy: file `$from' not found/readable\n";
51
52  } elsif (-e $from && !-r _) {     # filename
53     croak "CBCeasy: file `$from' not readable\n";
54
55  } else { # stream itself in $from
56  }
57
58  $cipher = new Crypt::CBC($key, $algorithm);
59  $cipher->start(lc $op);
60
61  if ($fromFile) {
62
63     binmode $fhi;
64     # fails with too long chains
65     while (read($fhi,$buffer,4096)) {
66	$toStr .= $cipher->crypt($buffer);
67     }
68     $toStr .= $cipher->finish;
69
70     close $fhi if $INopened;
71
72  } else {
73     # fails with too long chains
74     while ($from) {
75       $fromStr = substr($from, 0, 4096);
76       substr($from, 0, 4096) = '';
77       $toStr .= $cipher->crypt($fromStr);
78     }
79     $toStr .= $cipher->finish;
80  }
81
82  return $toStr unless $to;
83
84  if ((UNIVERSAL::isa($to, 'GLOB') ||     # \*HANDLE
85       UNIVERSAL::isa(\$to,'GLOB')        # *HANDLE
86      ) &&  defined fileno $to
87     ) {
88
89     $fho = $to;
90
91  } else {      # filename
92     $fho = gensym;
93     $OUTopened = 1;
94     open ($fho, ">$to") || croak "CBCeasy: can't write file `$to'\n";
95
96  }
97
98  binmode $fho;
99  print $fho $toStr;
100
101  close $fho if $OUTopened;
102
103}
104
105#--------------
106sub import {
107  my $pkg = shift;
108
109  for (@_ ? @_ : @DEFAULT_CIPHERS) {
110     eval <<"E_O_P" unless defined *{"$_\::encipher"}{CODE};
111
112	 sub $_\::encipher { useCBC(\@_) }
113	 sub $_\::decipher { useCBC(\@_) }
114E_O_P
115
116  }
117}
118
1191;
120__END__
121
122=head1 NAME
123
124Crypt::CBCeasy - Easy things make really easy with Crypt::CBC
125
126=head1 SYNOPSIS
127
128 use Crypt::CBCeasy; # !!! YOU can not 'require' this module !!!
129
130 IDEA::encipher($my_key, "plain-file", "crypted-file");
131
132 $plain_text = DES::decipher($my_key, \*CRYPTO_FILE);
133
134 $crypted = Blowfish::encipher($my_key, \*PLAIN_SOCKET);
135
136=head1 ABSTRACT
137
138This module is just a helper for Crypt::CBC to make simple and
139usual jobs just one-liners.
140
141The current version of the module is available at CPAN.
142
143=head1 DESCRIPTION
144
145After you call this module as
146
147  use Crypt::CBCeasy IMPORT-LIST;
148
149it creates the C<encipher()> and C<decipher()> functions in all
150namespaces (packages) listed in the C<IMPORT-LIST>.
151
152Without the C<IMPORT-LIST> it creates these 2 functions
153in the B<DES::>, B<IDEA::> and
154B<Blowfish::> namespaces by default
155to stay compatible with the previous versions
156that were capable to handle only these 3 ciphers.
157
158You have to install C<Crypt::CBC> v. 1.22 or later to work with C<Blowfish>.
159
160Sure IDEA:: functions will work only if you have Crypt::IDEA installed,
161DES:: - if you have Crypt::DES, Blowfish:: - if you have Crypt::Blowfish
162and Crypt::CBC is version 1.22 or above etc.
163
164Here's the list of the ciphers that could be called via the
165C<Crypt::CBCeasy> interface today (in fact the same modules
166that are C<Crypt::CBC> compatible):
167
168  Cipher          CPAN module
169
170  DES             Crypt::DES
171  IDEA            Crypt::IDEA
172  Blowfish        Crypt::Blowfish
173  Twofish2        Crypt::Twofish2
174  DES_PP          Crypt::DES_PP
175  Blowfish_PP     Crypt::Blowfish_PP
176  Rijndael        Crypt::Rijndael
177  TEA             Crypt::TEA
178
179Note that cipher names are case sensitive in the C<IMPORT-LIST>,
180so "blowfish" will give an error.
181Type them exactly as they are written in the correspondent
182underlying modules.
183
184Both C<encipher()> and C<decipher()> functions take 3 parameters:
185
186  1 - en/decryption key
187  2 - source
188  3 - destination
189
190The sources could be: an existing file, a scalar (just a string that would be
191encrypted), an opened filehandle, any other object that inherits from the
192filehandle, for example IO::File or FileHandle object, and socket.
193
194Destinations could be any of the above except scalar, because we can not
195distinguish between scalar and output file name here.
196
197Well, it's easier to look at the examples:
198
199(C<$fh> vars here are IO::Handle, IO::File or FileHandle objects,
200variables of type "GLOB", "GLOB" refs or sockets)
201
202B<IDEA::encipher(> $my_key, "in-file", "out-file" B<);>
203
204B<IDEA::encipher(> $my_key, *IN, "out-file" B<);>
205
206B<IDEA::encipher(> $my_key, \*IN, "out-file" B<);>
207
208B<IDEA::encipher(> $my_key, $fh_in, "out-file" B<);>
209
210B<IDEA::encipher(> $my_key, "in-file", *OUT B<);>
211
212B<IDEA::encipher(> $my_key, "in-file", \*OUT B<);>
213
214B<IDEA::encipher(> $my_key, "in-file", $fh_out B<);>
215
216B<IDEA::encipher(> $my_key, *IN, *OUT B<);>
217
218B<IDEA::encipher(> $my_key, \*IN, \*OUT B<);>
219
220B<IDEA::encipher(> $my_key, $fh_in, $fh_out B<);>
221
222B<IDEA::encipher(> $my_key, $plain_text, "out-file" B<);>
223
224B<IDEA::encipher(> $my_key, $plain_text, *OUT B<);>
225
226B<IDEA::encipher(> $my_key, $plain_text, \*OUT B<);>
227
228B<IDEA::encipher(> $my_key, $plain_text, $fh_out B<);>
229
230any of the above will work and do what was expected.
231
232In addition there is a 2-argument version that returns it's result
233as scalar:
234
235$crypted_text = B<IDEA::encipher(> $my_key, $plain_text B<);>
236
237$crypted_text = B<IDEA::encipher(> $my_key, "in-file" B<);>
238
239$crypted_text = B<IDEA::encipher(> $my_key, *IN B<);>
240
241$crypted_text = B<IDEA::encipher(> $my_key, \*IN B<);>
242
243$crypted_text = B<IDEA::encipher(> $my_key, $fh B<);>
244
245All the same is possible for any of the ciphers in the C<IMPORT-LIST>.
246
247All functions croak on errors (such as "input file not found"), so
248if you want to trap errors use them inside the C<eval{}> block
249and check the C<$@>.
250
251
252Note that all filehandles are used in C<binmode> whether you claimed them
253C<binmode> or not. On Win32 for example this will result in CRLF's in
254$plain_text after
255
256 $plain_text = DES::decipher($my_key, "crypted_file");
257
258if "crypted_file" was created by
259
260 DES::encipher($my_key, "text_file", "crypted_file");
261
262If the filehandle was used before - it's your job to rewind it
263to the beginning and/or close.
264
265=head1 INSTALLATION
266
267As this is just a plain module no special installation is needed. Put it
268into the /Crypt subdirectory somewhere in your @INC. The standard
269
270 Makefile.PL
271 make
272 make test
273 make install
274
275procedure is provided. In addition
276
277 make html
278
279will produce the HTML-docs.
280
281This module requires
282
283Crypt::CBC by Lincoln Stein, lstein@cshl.org
284v.1.20 or later.
285
286one or more of
287
288Crypt::IDEA, Crypt::DES, Crypt::Blowfish, Crypt::Blowfish_PP,
289Crypt::Twofish2, Crypt::DES_PP or other Crypt::CBC compatible modules.
290
291=head1 CAVEATS
292
293This module has been created and tested in a Win95/98/2000Pro environment
294with Perl 5.004_02 and ActiveState ActivePerl build 618.
295I expect it to function correctly on other systems too.
296
297=head1 CHANGES
298
299 0.21   Mon Mar  6 07:28:41 2000  -  first public release
300
301 0.22   Sun Feb 18 13:11:59 2001
302	A horrible BUG was found by Michael Drumheller <drumheller@alum.mit.edu>
303	In fact 0.21 was ALWAYS using DES despite of the desired cipher.
304	DAMN!
305	Fixed.
306	And the test is modified so that this will never happen again.
307
308	Now you can define the list of ciphers that are compatible
309	with Crypt::CBC in the import list.
310	You can not call this module with the "require" statement. This
311	is incompatible with the older versions.
312
313  0.23  Crypt::Rijndael 0.02 compatibility was approved.
314        Tests are some more complex now.
315
316  0.24  Crypt::TEA 1.01 by Abhijit Menon-Sen <ams@wiw.org> is checked
317	and approved.
318
319=head1 TODO
320
321Any suggestions are much appreciated.
322
323=head1 BUGS
324
325Please report.
326
327=head1 VERSION
328
329This man page documents "Crypt::CBCeasy" version 0.24
330
331February 18, 2001
332
333=head1 AUTHOR
334
335Mike Blazer, blazer@mail.nevalink.ru
336
337http://base.dux.ru/guest/fno/perl/
338
339=head1 SEE ALSO
340
341Crypt::CBC
342
343=head1 COPYRIGHT
344
345Copyright (C) 2000-2001 Mike Blazer.
346
347This package is free software; you can redistribute it and/or
348modify it under the same terms as Perl itself.
349
350=cut
351
352