File Coverage

blib/lib/Crypt/Cipher/Vigenere.pm
Criterion Covered Total %
statement 53 53 100.0
branch 6 6 100.0
condition n/a
subroutine 10 10 100.0
pod 4 4 100.0
total 73 73 100.0


line stmt bran cond sub pod time code
1             package Crypt::Cipher::Vigenere;
2              
3             our $VERSION = '0.03';
4              
5 1     1   256203 use v5.20;
  1         3  
6 1     1   5 use strict;
  1         2  
  1         58  
7 1     1   8 use warnings;
  1         2  
  1         26  
8 1     1   1446 use experimental 'signatures';
  1         3800  
  1         8  
9              
10 4     4 1 1377 sub new ($class, $key) {
  4         11  
  4         8  
  4         8  
11 4         21 bless( { key => $key, pos => 0 }, $class )
12             }
13              
14             # return the current key character and advance the position
15             sub _next_key_letter ($self)
16 96     96   120 {
  96         122  
  96         108  
17 96         191 my $c = substr($self->{key}, $self->{pos}, 1);
18 96         124 $self->{pos}++;
19 96 100       180 $self->{pos} = 0 unless $self->{pos} < length($self->{key});
20 96         188 return $c;
21             }
22              
23             # enciphering/deciphering function; the only difference is the direction of the
24             # shifts
25 8         13 sub _cipher ($self, $plaintext, $direction)
  8         12  
26 8     8   10 {
  8         10  
  8         12  
27 8         13 my $ciphertext = '';
28              
29             # split into individual characters
30 8         39 my @pt = split(//, $plaintext);
31              
32             # process plaintext characters
33 8         18 foreach my $letter (@pt) {
34              
35             # we only operate on the 26 letters of the English alphabet, everything else
36             # is passed through unchanged
37 112 100       280 unless($letter =~ /[A-Z]/i) {
38 16         25 $ciphertext .= $letter;
39 16         24 next;
40             }
41              
42             # get number of shifts
43 96         171 my $shift = ord(uc $self->_next_key_letter) - ord('A');
44              
45             # shift the plaintext letter
46 96         214 my $cipherletter .= chr(
47             (
48             (
49             (
50             ord(uc $letter) - ord('A')
51             ) + $direction * $shift
52             ) % 26
53             ) + ord('A')
54             );
55              
56             # preserve case
57 96 100       225 $cipherletter = lc $cipherletter if $letter =~ /[a-z]/;
58              
59             # finish this iteration
60 96         170 $ciphertext .= $cipherletter;
61             }
62              
63 8         56 return $ciphertext;
64             }
65              
66             # encode/decode mapped to the internal _cipher() function
67 4     4 1 8261 sub encode ($self, $plaintext) { $self->_cipher($plaintext, 1) };
  4         6  
  4         8  
  4         4  
  4         13  
68 4     4 1 7 sub decode ($self, $ciphertext) { $self->_cipher($ciphertext, -1) };
  4         7  
  4         6  
  4         6  
  4         11  
69              
70             # reset key position
71 4     4 1 13 sub reset ($self) { $self->{pos} = 0 }
  4         7  
  4         7  
  4         10  
72              
73             1;
74              
75             __END__