| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
############################################################################### |
|
2
|
|
|
|
|
|
|
# Purpose : Substitution cipher based on a keyword alphabet |
|
3
|
|
|
|
|
|
|
# Author : John Alden |
|
4
|
|
|
|
|
|
|
# Created : Jan 2005 |
|
5
|
|
|
|
|
|
|
# CVS : $Id: KeywordAlphabet.pm,v 1.5 2005/03/20 20:02:11 aldenj20 Exp $ |
|
6
|
|
|
|
|
|
|
############################################################################### |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
package Text::Cipher::KeywordAlphabet; |
|
9
|
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
888
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
35
|
|
|
11
|
1
|
|
|
1
|
|
771
|
use Text::Cipher; |
|
|
1
|
|
|
|
|
2760
|
|
|
|
1
|
|
|
|
|
37
|
|
|
12
|
1
|
|
|
1
|
|
22
|
use Carp; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
72
|
|
|
13
|
1
|
|
|
1
|
|
6
|
use vars qw($VERSION $AUTOLOAD); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
775
|
|
|
14
|
|
|
|
|
|
|
$VERSION = sprintf "%d.%03d", (q$Revision: 1.5 $ =~ /: (\d+)\.(\d+)/); |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub new { |
|
17
|
7
|
|
|
7
|
1
|
11089
|
my ($class, $keywords, $offset) = @_; |
|
18
|
7
|
100
|
|
|
|
203
|
croak("offset must be an integer") unless($offset =~ /^\-?\d*$/); #Integer or blank |
|
19
|
6
|
|
|
|
|
8
|
my %seen; |
|
20
|
6
|
100
|
|
|
|
26
|
my $alphabet = join("", map {uc} grep {/^[a-z]$/i && !$seen{$_}++} (split //, $keywords), 'a'..'z'); |
|
|
156
|
|
|
|
|
231
|
|
|
|
186
|
|
|
|
|
1031
|
|
|
21
|
6
|
|
|
|
|
39
|
$alphabet = _rotate_alphabet($alphabet, $offset); |
|
22
|
6
|
|
|
|
|
33
|
my $self = { |
|
23
|
6
|
|
|
|
|
862
|
cipher => new Text::Cipher(join("", 'A'..'Z', 'a'..'z'), join("", $alphabet, map {lc} $alphabet)), |
|
24
|
6
|
|
|
|
|
29
|
decipher => new Text::Cipher(join("", $alphabet, map {lc} $alphabet), join("", 'A'..'Z', 'a'..'z')), |
|
25
|
|
|
|
|
|
|
alphabet => $alphabet |
|
26
|
|
|
|
|
|
|
}; |
|
27
|
6
|
|
|
|
|
574
|
return bless($self, $class); |
|
28
|
|
|
|
|
|
|
} |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub alphabet { |
|
31
|
6
|
|
|
6
|
1
|
2029
|
my ($self) = shift; |
|
32
|
6
|
|
|
|
|
49
|
return $self->{alphabet}; |
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub AUTOLOAD { |
|
36
|
2
|
|
|
2
|
|
1483
|
my ($self) = shift; |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# DESTROY messages should never be propagated |
|
39
|
2
|
50
|
|
|
|
8
|
return if $AUTOLOAD =~ /::DESTROY$/; |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# Remove the package name |
|
42
|
2
|
|
|
|
|
4
|
my $package = __PACKAGE__; |
|
43
|
2
|
|
|
|
|
33
|
$AUTOLOAD =~ s/^${package}:://; |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# Pass on to either the enciphering or deciphering object |
|
46
|
2
|
100
|
|
|
|
7
|
if($AUTOLOAD =~ /^decipher/) { |
|
47
|
1
|
|
|
|
|
3
|
$AUTOLOAD =~ s/^decipher/encipher/; |
|
48
|
1
|
|
|
|
|
5
|
$self->{decipher}->$AUTOLOAD(@_); |
|
49
|
|
|
|
|
|
|
} else { |
|
50
|
1
|
|
|
|
|
7
|
$self->{cipher}->$AUTOLOAD(@_); |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
} |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Based on routine in Text::Shift |
|
55
|
|
|
|
|
|
|
sub _rotate_alphabet { |
|
56
|
|
|
|
|
|
|
# Get parameters |
|
57
|
6
|
|
|
6
|
|
10
|
my($string,$mag) = @_; |
|
58
|
6
|
|
|
|
|
10
|
my $strlng = length($string); |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# Handle outliers |
|
61
|
6
|
100
|
100
|
|
|
41
|
$mag %= $strlng if(abs($mag) > $strlng or $mag < 0); |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# Return rotated string |
|
64
|
6
|
100
|
|
|
|
17
|
return $string if($mag == 0); |
|
65
|
4
|
|
|
|
|
12
|
$string .= substr($string,0,$mag, ""); |
|
66
|
4
|
|
|
|
|
8
|
return $string; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
1; |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=head1 NAME |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
Text::Cipher::KeywordAlphabet - Substitution cipher based on a keyword alphabet |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
#Create a keyword alphabet with a left shift of 5 |
|
78
|
|
|
|
|
|
|
$cipher = new Text::Cipher::KeywordAlphabet("the quick brown fox", -5); |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
#Fetch the generated alphabet |
|
81
|
|
|
|
|
|
|
$keyword_alphabet = $cipher->alphabet(); |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
#Encipher a string |
|
84
|
|
|
|
|
|
|
$ciphered = $cipher->encipher($message); |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
#Decipher an enciphered message |
|
87
|
|
|
|
|
|
|
$message = $cipher->decipher($ciphered); |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
#Some convenience methods |
|
90
|
|
|
|
|
|
|
$cipher->encipher_scalar(\$some_scalar); |
|
91
|
|
|
|
|
|
|
$cipher->decipher_scalar(\$some_scalar); |
|
92
|
|
|
|
|
|
|
@ciphered = $cipher->encipher_list(@list); |
|
93
|
|
|
|
|
|
|
@list = $cipher->decipher_list(@ciphered); |
|
94
|
|
|
|
|
|
|
$cipher->encipher_array(\@some_array); |
|
95
|
|
|
|
|
|
|
$cipher->decipher_array(\@some_array); |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
#Other uses |
|
98
|
|
|
|
|
|
|
$null_cipher = new Text::Cipher::KeywordAlphabet(); #no-op cipher |
|
99
|
|
|
|
|
|
|
$rot13_cipher = new Text::Cipher::KeywordAlphabet(undef, 13); #Caesar cipher |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
This module generates a monoalphabetic substitution cipher from a set of words, resulting in what's sometimes referred to as a "keyword (generated) alphabet". |
|
104
|
|
|
|
|
|
|
Here's a good definition, plagiarised from an anonymous source: |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
"A keyword alphabet is formed by taking a word or phrase, deleting the second and subsequent occurrence of each letter and then writing the remaining letters of the alphabet in order. |
|
107
|
|
|
|
|
|
|
Encipherment is achieved by replacing each plaintext letter by the letter that appears N letters later in the (cyclic) keyword alphabet." |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
The keyword alphabet is case-insensitive - both uppercase and lowercase characters will be transformed with the same mapping. |
|
110
|
|
|
|
|
|
|
The offset (N in the definition above) can be a positive or negative integer. |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
L is an introductory tutorial on how substitution ciphers can be broken. |
|
113
|
|
|
|
|
|
|
L contains a full worked example. |
|
114
|
|
|
|
|
|
|
L provides an online substitution cipher breaker. |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
At the risk of stating the obvious, since substitution ciphers are easy to break, it's advisable not to use them for protecting important data. |
|
117
|
|
|
|
|
|
|
Look at some of the more heavy-duty ciphers in the Crypt:: namespace which plug into Crypt::CBC if you want to protect data. |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=head1 METHODS |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=over 4 |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=item $obj = new Text::Cipher::KeywordAlphabet($keyword_phrase, $offset) |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
Create a new keyword alphabet |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
=item $keyword_alphabet = $obj->alphabet(); |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
Return the keyword alphabet created by the constructor |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=item $ciphered = $obj->encipher($message) |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
Enciphers a string using the keyword alphabet |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=item $message = $obj->decipher($ciphered) |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
Reverse of encipher() |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
=item $obj->encipher_scalar(\$some_scalar); |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
By-reference equivalent of encipher() |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=item $obj->decipher_scalar(\$some_scalar); |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
By-reference equivalent of decipher() |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=item @ciphered = $obj->encipher_list(@list); |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Convenience method provided by Text::Cipher |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=item @list = $obj->decipher_list(@ciphered); |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
Reverse of encipher_list(). |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=item $obj->encipher_array(\@some_array); |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Convenience method provided by Text::Cipher |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=item $obj->decipher_array(\@some_array); |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
Reverse of encipher_array(). |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=back |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=head1 VERSION |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
See $Text::Cipher::KeywordAlphabet::VERSION. |
|
168
|
|
|
|
|
|
|
Last edit: $Revision: 1.5 $ on $Date: 2005/03/20 20:02:11 $ |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=head1 BUGS |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
None known. This module has not been used heavily in production so it's not impossible a bug may have slipped through the unit tests. |
|
173
|
|
|
|
|
|
|
Bug reports are welcome, particularly with patches & test cases. |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head1 AUTHOR |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
John Alden |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=over 4 |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=item Text::Cipher and Regexp::Tr |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
Useful building blocks for substitution ciphers |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=item Text::Shift and Crypt::Rot13 |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
Caesar (aka shift or rot-N) ciphers (see L) |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=item Crypt::Caesar |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Crack Caesar ciphers using letter frequency (see L) |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=item Crypt::Vigenere |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Vigenere polyalphabetic cipher (see L) |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=item Crypt::Enigma and Crypt::OOEnigma |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
Implementations of Enigma ciphers (see L) |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
=back |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Copyright 2005 by John Alden |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=cut |