File Coverage

blib/lib/Crypt/VERPString.pm
Criterion Covered Total %
statement 19 41 46.3
branch 0 16 0.0
condition 0 8 0.0
subroutine 6 9 66.6
pod 3 3 100.0
total 28 77 36.3


line stmt bran cond sub pod time code
1             package Crypt::VERPString;
2              
3 2     2   49968 use warnings FATAL => 'all';
  2         5  
  2         102  
4 2     2   9 use strict;
  2         4  
  2         196  
5              
6 2     2   11 use Carp qw(croak);
  2         7  
  2         148  
7             #use MIME::Base32 qw(rfc);
8 2     2   5360 use MIME::Base32 qw(crockford);
  2         2415  
  2         15  
9 2     2   2733 use Crypt::CBC ();
  2         14876  
  2         1437  
10              
11             =head1 NAME
12              
13             Crypt::VERPString - Encrypt and encode fixed-length records for VERP
14              
15             =head1 VERSION
16              
17             Version 0.02
18              
19             =cut
20              
21             our $VERSION = '0.02';
22              
23             =head1 SYNOPSIS
24              
25             use Crypt::VERPString;
26             use MIME::Base64;
27              
28             my $cv = Crypt::VERPString->new(
29             cipher => 'IDEA', # defaults to blowfish
30             key => 'HAHGLUBHAL!@#$!%', # anything, really
31             format => 'Na*', # defaults to a*
32             separator => '!', # defaults to -
33             encoder => \&MIME::Base64::encode_base64,# defaults to base32
34             decoder => \&MIME::Base64::decode_base64,# ditto
35             );
36              
37             my $iv = 31337;
38             my $verp = $cv->encrypt($iv, 12345, 'hi i am a payload');
39              
40             # $verp eq '00007a69!+BT8d1wzW12YSFP5v7AnKVipYZ8rkQIT';
41              
42             # do stuff with this value, send to a friend...
43              
44             # oops, your friend doesn't exist, the message bounces and you
45             # retrieve the envelope.
46              
47             my ($bouncedverp) = ($header =~ /(?:[0-9a-fA-F]{8}!.*)/);
48              
49             my ($number, $string) = $cv->decrypt($bouncedverp);
50              
51             # now you can do something with this info.
52              
53             =head1 DESCRIPTION
54              
55             VERP stands for Variable Envelope Return Path. It is the act of inserting
56             some sort of identifying string into the local part of the envelope
57             address of an email, in order to match it to a distinct sending, should
58             the message bounce. This module prepares a string suitable for travel
59             in the deep jungle of SMTP, making it possible to store and retrieve
60             unique envelope data from a bounced message.
61              
62             This module is also useful for other small payloads that require the
63             same kind of escaping.
64              
65             =head1 METHODS
66              
67             =head2 new PARAMS
68              
69             =over 1
70              
71             =item cipher
72              
73             The block cipher to use. Defaults to Blowfish.
74              
75             =item key
76              
77             The secret key.
78              
79             =item format
80              
81             The pack() format. Defaults to "a*".
82              
83             =item separator
84              
85             The separation character between the initialization vector and the payload.
86             Defaults to "-".
87              
88             =item encoder
89              
90             A Subroutine reference to encode the payload. Defaults to MIME::Base32::encode
91              
92             =item decoder
93              
94             A Subroutine reference to decode the payload. Defaults to MIME::Base32::decode
95              
96             =back
97              
98             =cut
99              
100             sub new {
101             # mwa ha ha.
102 1     1 1 919 my $class = shift;
103 1         11 my $self = bless {map {lc($_[$_])=>$_[$_+1]} map {$_*2} (0..@_/2)}, $class;
  2         228  
  2         7  
104 0   0       $self->{cipher} ||= 'Blowfish';
105             # how i weep for no // operator
106             #defined $self->{iv} && $self->{iv} =~ /^\d+$/ or croak 'IV not a number';
107 0 0         defined $self->{key} or croak 'Key must be defined';
108 0 0         defined $self->{format} or $self->{format} = 'a*';
109 0 0         defined $self->{separator} or $self->{separator} = '-';
110 0 0         defined $self->{encoder} or $self->{encoder} = \&MIME::Base32::encode;
111 0 0         defined $self->{decoder} or $self->{decoder} = \&MIME::Base32::decode;
112 0           $self;
113             }
114              
115             sub _get_cipher {
116 0     0     my ($self, $iv) = @_;
117 0           Crypt::CBC->new({
118             key => $self->{key},
119             cipher => $self->{cipher},
120             iv => pack('NN', $iv, 0), # we could use more entropy...
121             regenerate_key => 0,
122             prepend_iv => 0,
123             });
124             }
125              
126             #=head2 set_iv NUMBER
127              
128             #Set a new initialization vector. Returns old initialization vector.
129              
130             #=cut
131              
132             #sub set_iv {
133             # my ($self, $iv) = @_;
134             # croak 'IV not a number' unless $iv =~ /^\d+$/;
135             # my $oldiv = $self->{iv};
136             # $self->{iv} = $iv;
137             # $self->{crypto}->set_initialization_vector(pack 'NN', ($self->{iv}));
138             # $oldiv;
139             #}
140              
141             =head2 encrypt IV, LIST
142              
143             Pass in the list and retrieve the unique, encrypted VERP string.
144              
145             =cut
146              
147             sub encrypt {
148 0     0 1   my ($self, $iv, @args) = @_;
149 0           my $cv = $self->_get_cipher($iv);
150 0           return join $self->{separator}, unpack('H*', pack 'N', $iv),
151             $self->{encoder}->($cv->encrypt(pack $self->{format}, @args));
152             }
153              
154             =head2 decrypt STRING
155              
156             Pass in the VERP string and retrieve the original unencrypted list.
157              
158             =cut
159              
160             sub decrypt {
161 0     0 1   my ($self, $str) = @_;
162 0           my ($iv, $payload) = ($str =~ /^([0-9a-fA-F]{8})$self->{separator}(.*)/o);
163 0 0 0       croak 'Malformed input string' unless $iv and $payload;
164 0           $iv = unpack("N", pack "H*", $iv);
165 0           my $cv = $self->_get_cipher($iv);
166 0           my $ciphertext = eval { $self->{decoder}->($payload) };
  0            
167 0 0 0       croak 'Could not decode payload using supplied decode sub'
168             if $@ or !$ciphertext;
169 0           my @payload = unpack $self->{format}, $cv->decrypt($ciphertext);
170 0 0         return wantarray ? @payload : $payload[0];
171             }
172              
173             =head1 AUTHOR
174              
175             dorian taylor, C<< >>
176              
177             =head1 SEE ALSO
178              
179             L
180              
181             L
182              
183             L
184              
185             =head1 BUGS
186              
187             The true IV is just the given number and zero, packed into two network longs.
188             I wouldn't recommend really using this for extremely sensitive data, I mean,
189             it's initially designed to fit in the local-part of an email. Ideas and
190             patches are welcome.
191              
192             Please report any bugs or feature requests to
193             C, or through the web interface at
194             L. I will be notified, and then you'll automatically
195             be notified of progress on your bug as I make changes.
196              
197             =head1 COPYRIGHT & LICENSE
198              
199             Copyright 2005 iCrystal Software, Inc., All Rights Reserved.
200              
201             This program is free software; you can redistribute it and/or modify it
202             under the same terms as Perl itself.
203              
204             =cut
205              
206             1; # End of Crypt::VERPString