File Coverage

blib/lib/Crypt/Lite.pm
Criterion Covered Total %
statement 84 94 89.3
branch 13 22 59.0
condition 3 7 42.8
subroutine 9 10 90.0
pod 0 9 0.0
total 109 142 76.7


line stmt bran cond sub pod time code
1             package Crypt::Lite;
2 1     1   23139 use strict;
  1         2  
  1         1345  
3             ############################################################
4             # Author : retoh@cpan.org
5             # Created : 07FEB2002
6             #
7             # Licencing:
8             # http://www.infocopter.com/perl/licencing-print.htm
9             #
10             # Usage:
11             # ----------------------------------------------------------
12             # See POD at the end or enter
13             # man Crypt::Lite
14             # after installation
15             # ----------------------------------------------------------
16             # http://www.infocopter.com/perl/modules/
17             ############################################################
18              
19             my $package = __PACKAGE__;
20             require MIME::Base64;
21             unless (eval "require MD5") {
22             print "No MD5 module.\n";
23             # skip remaining tests
24             exit;
25             }
26              
27             our $VERSION = '0.82.11';
28              
29             # GLOBAL VARIABLES
30             my $contentType = "";
31             my $priv = ""; # challenge key
32             my $debug = 0;
33              
34             #----- FORWARD DECLARATIONS & PROTOTYPING
35             sub iso2hex($);
36             sub hex2iso($);
37             sub Error($);
38             sub Debug($);
39              
40             sub new {
41 1     1 0 186 my $type = shift;
42 1         7 my %params = @_;
43 1         3 my $self = {};
44              
45 1   50     7 $params{'encoding'} ||= 'base64'; # base64 || hex8
46 1   50     9 $params{'debug' } ||= 0;
47              
48 1         3 $self->{'debug' } = $debug = $params{'debug'};
49 1         3 $self->{'encoding'} = $params{'encoding'};
50              
51 1         2 $debug = $params{'debug'};
52              
53 1         6 bless $self, $type;
54             }
55              
56             sub encrypt {
57 1     1 0 8 my $self = shift;
58              
59 1         3 my $text = shift;
60 1         3 $priv = shift;
61            
62             # Make sure to encrypt similar or equal text to different strings
63 1         106 my $scramble_left = sprintf("%04d", substr(1048576 * rand(), 0, 4));
64              
65 1         10 my $priv_md5 = MD5->hexhash($priv);
66              
67 1         44 my $text_scrambled = "$scramble_left\t$text\t$priv_md5";
68              
69 1         6 my $bin_text = &atob($text_scrambled);
70 1         4 my $bin_priv = &atob($priv);
71              
72 1         12 Debug "N1000: Scrambling '$text' with '$priv'...";
73            
74 1         5 my $encryp = &bin_add($bin_text, $bin_priv);
75            
76 1 50       13 if ($self->{'debug'}) {
77 0         0 Debug "$bin_text \t<- text";
78 0         0 Debug "$bin_priv \t<- challenge";
79 0         0 Debug "$encryp \t<- result";
80             }
81            
82 1         3 my $encryp_pack = "";
83 1         6 for (my $i = 0; $i < length($encryp); $i += 8) {
84 59         74 my $elem = substr($encryp, $i, 8);
85             # X my $elemp = pack('C', $elem); # cannot be used on RH8.0
86 59         143 $encryp_pack .= pack('B8', $elem);
87             }
88              
89 1         7 Debug "N1003: encryp_pack -----> '$encryp_pack'\n";
90              
91 1         2 my $encrypted = '';
92 1 50       7 if ($self->{'encoding'} eq 'hex8') {
93 1         4 $encrypted = iso2hex $encryp_pack;
94             }
95             else {
96             # base64
97 0         0 $encrypted = MIME::Base64::encode($encryp_pack);
98 0         0 chomp $encrypted;
99             }
100              
101 1         8 $encrypted;
102             }
103              
104             sub decrypt {
105 2     2 0 750 my $self = shift;
106              
107 2         4 my $encryp_base64 = shift;
108 2         4 $priv = shift;
109            
110 2         23 Debug 'N1002: Decrypting (' . $self->{'encoding'} . ") '$encryp_base64' with '$priv'...";
111            
112 2         6 my $bin_priv = &atob($priv);
113            
114 2         5 my $base64toplain = '';
115 2 50       8 if ($self->{'encoding'} eq 'hex8') {
116 2         8 $base64toplain = hex2iso $encryp_base64;
117 2 50       8 Debug "hex8 -> '$encryp_base64' = '$base64toplain'" if $self->{'debug'};
118             }
119 0         0 else { $base64toplain = MIME::Base64::decode($encryp_base64); }
120              
121 2         9 Debug "N1004: -> base64toplain = '$base64toplain'...";
122              
123 2         4 my $encryp_pack = "";
124 2         100 for (my $i = 0; $i < length($base64toplain); $i++) {
125 118         125 my $elem = substr($base64toplain, $i, 1);
126 118         184 my $bin = unpack('B8', $elem);
127 118         273 $encryp_pack .= $bin;
128             }
129              
130 2         7 my $bin_new = &bin_add($encryp_pack, $bin_priv);
131              
132 2         5 $encryp_pack = "";
133 2         9 for (my $i = 0; $i < length($bin_new); $i += 8) {
134 118         156 my $elem = substr($bin_new, $i, 8);
135 118 50       199 print "'$elem' = ", pack('B8', $elem), "...\n" if $debug;
136 118         321 $encryp_pack .= pack('B8', $elem);
137             }
138              
139 2         12 Debug "N1001: =====> '$encryp_pack' !!!";
140              
141 2         12 my ($rand1, $result, $priv_wrapped) = split /\t/, $encryp_pack;
142              
143 2         19 my $priv_md5 = MD5->hexhash($priv);
144              
145 2 100       188 return '' if $rand1 =~ /\D/;
146 1 50 33     28 return '' unless ($priv_md5 eq $priv_wrapped or $priv eq $priv_wrapped);
147             # -- Additional clause "$priv eq $priv_wrapped" for reasons of reverse compatibilty before rel. 0.82.07
148              
149 1         7 $result; # return middle element of array only
150             }
151              
152             ################################################
153             # LOCAL SUB ROUTINES
154             ################################################
155              
156             sub atob ($) {
157 4     4 0 8 my $str = shift;
158 4         7 my $bin = "";
159 4         14 for (my $i = 0; $i < length($str); $i++) { $bin .= unpack('B8', substr($str, $i, 1)); }
  88         285  
160 4         10 $bin;
161             }
162              
163             sub bin_add ($$) {
164 3     3 0 5 my $a = shift;
165 3         6 my $b = shift;
166              
167 3         5 my $i = my $j = 0;
168 3         11 for ($j = 0; $j < length($a); $j++) {
169 1416         3971 substr($a, $j, 1) += substr($b, $i, 1);
170 1416 100       4521 substr($a, $j, 1) = 0 if substr($a, $j, 1) == 2;
171 1416 100       5833 $i = 0 if ++$i > length($priv);
172             }
173 3         15 $a;
174             }
175              
176             sub iso2hex ($) {
177 1     1 0 3 my $string = $_[0];
178 1         2 my $hex_string = '';
179              
180 1         4 for (my $i = 0; $i < length($string); $i++) {
181             # print substr($string, $i, 1);
182 59         164 $hex_string .= unpack('H8', substr($string, $i, 1));
183             }
184 1         4 $hex_string;
185             }
186              
187             sub hex2iso ($) {
188 2     2 0 4 my $hex_string = $_[0];
189 2         3 my $iso_string = '';
190              
191 2         33 for (my $i = 0; $i < length($hex_string); $i += 2) {
192 118         190 my $char = substr(pack('H8', substr($hex_string, $i, 2)), 0, 1); # 1 char
193 118         341 $iso_string .= $char;
194             }
195 2         7 $iso_string;
196             }
197              
198             sub Error ($) {
199 0 0   0 0 0 print "Content-type: text/html\n\n" unless $contentType;
200 0         0 print "<b>ERROR</b> ($package): $_[0]\n";
201 0         0 exit(1);
202             }
203              
204 8 50   8 0 29 sub Debug ($) { return unless $debug; print "<b>[$package]</b> $_[0]<br>\n"; }
  0            
205              
206             1;
207              
208             #### Used Warning / Error Codes ##########################
209             # Next free W Code: 1000
210             # Next free E Code: 1000
211             # Next free N Code: 1005
212              
213             __END__
214              
215             =head1 NAME
216              
217             Crypt::Lite - Easy to use symmetric data encryption and decryption
218              
219             =head1 SYNOPSIS
220              
221             use Crypt::Lite;
222              
223             $crypt = Crypt::Lite->new( debug => 0 );
224              
225             [or]
226              
227             $crypt = Crypt::Lite->new( debug => 0, encoding => 'hex8' );
228              
229             =head2 Encryption
230              
231             $encrypted = $crypt->encrypt('plain text to encrypt', 'your_secret_string');
232              
233             =head2 Decryption
234              
235             $decrypted = $crypt->decrypt($encrypted, 'your_secret_string');
236              
237             Returns an empty string if the encrypted hash has been broken
238              
239             =head1 DESCRIPTION
240              
241             =head2 Important Notice
242              
243             Crypt::Lite does C<NOT> strong encryption - that's what the "Lite" stands for. It's very easy to install and use, anwhere where Perl runs. Please take a closer look on AES or Blowfish for strong encryption.
244              
245             =head2 What's Special
246              
247             Crypt::Lite returns an empty string if the passphrase does not exactly match. Especially block ciphers often return a partial plain text even if, let's say about 90 % of the passphrase was correct (this will not say it's more secure - it's a property ;-).
248              
249             =head2 Introduction
250              
251             Sometimes it's necessary to protect some certain data against plain reading or you intend to send information through the Internet. Another reason might be to assure users cannot modify their previously entered data in a follow-up step of a long Web transaction where you don't want to deal with server-side session data. The goal of Crypt::Lite was to have a pretty simple way to encrypt and decrypt data without the need to install and compile huge packages with lots of dependencies.
252              
253             Crypt::Lite has the property that it typically returns an empty string on a wrong passphrase instead of a partially decrpyted string. It generates every time a different encrypted hash when you re-encrypt the same data with the same secret string. In normal cases of XOR encryption, what Crypt::Lite is based on, double or tripple encryption does NOT increase the security. Because of the nature of Crypt::Lite I state (because of the shifting concept) double encryption *does* increase the challenge to decrypt it. Nevertheless I *don't* recommend it because at least it creates very large strings ;-) What I really suggest is to use good passphrases not shorter than 6 characters, or better 16 characters length to encrypt. A randomly generated passphrase that is used only once of the same length as the plain text will be the most secure encryption with Crypt::Lite.
254              
255             In general, decryption works also on hashes that have been encrypted on a foreign host (try this with an unpatched IDEA installation ;-).
256              
257             Since last time has grown a harshly thread about XOR encryption I suggest to take a look from time to time on this URL to get the latest news and documentation on
258              
259             http://www.infocopter.com/perl/modules/crypt-lite.html
260              
261             =head2 EXPORT
262              
263             None by default.
264              
265              
266              
267             =head1 SEE ALSO
268              
269             Please find a documentation and related news about this module on
270              
271             http://www.infocopter.com/perl/modules/
272              
273             There is currently no mailing list.
274              
275             =head1 AUTHOR
276              
277             Reto Schaer, E<lt>retoh@hatespam-cpan.orgE<gt>
278              
279             =head1 COPYRIGHT AND LICENSE
280              
281             Copyright (C) 2002-2006 by Reto Schaer
282              
283             This library is free software; you can redistribute it and/or modify
284             it under the same terms as Perl itself, either Perl version 5.8.3 or,
285             at your option, any later version of Perl 5 you may have available.
286              
287             Feel free to use it for commercial purposes or just for pleasure. You may change the code for your needs if you like. Redistribution and use in source and binary forms, with or without modification, are permitted.
288              
289             I ask you to leave the link to the related documentation anywhere at the the top of the module in case of redistribution my code.
290              
291             =head2 SEE ALSO
292              
293             http://www.infocopter.com/perl/licencing.html
294              
295             =cut