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 |