File Coverage

blib/lib/Mail/SRS.pm
Criterion Covered Total %
statement 97 102 95.1
branch 37 48 77.0
condition n/a
subroutine 16 19 84.2
pod 13 13 100.0
total 163 182 89.5


line stmt bran cond sub pod time code
1             package Mail::SRS;
2              
3 9     9   136743 use strict;
  9         24  
  9         365  
4 9     9   58 use warnings;
  9         27  
  9         407  
5 9         1592 use vars qw($VERSION @ISA @EXPORT_OK %EXPORT_TAGS
6             $SRS0TAG $SRS1TAG
7             $SRS0RE $SRS1RE
8             $SRSSEP
9             $SRSTAG $SRSWRAP
10             $SRSHASHLENGTH $SRSMAXAGE
11 9     9   51 );
  9         1767  
12 9     9   52 use Exporter;
  9         15  
  9         405  
13 9     9   59 use Carp;
  9         15  
  9         739  
14 9     9   9128 use Digest::HMAC_SHA1;
  9         77677  
  9         27435  
15              
16             $VERSION = "0.31";
17             @ISA = qw(Exporter);
18              
19             $SRS0TAG = "SRS0";
20             $SRS1TAG = "SRS1";
21             $SRS0RE = qr/^$SRS0TAG([-+=])/io;
22             $SRS1RE = qr/^$SRS1TAG([-+=])/io;
23             $SRSSEP = "=";
24              
25             # These are deprecated.
26             $SRSTAG = $SRS0TAG;
27             $SRSWRAP = $SRS1TAG;
28              
29             $SRSHASHLENGTH = 4;
30             $SRSMAXAGE = 21;
31              
32             @EXPORT_OK = qw($SRS0TAG $SRS1TAG
33             $SRS0RE $SRS1RE
34             $SRSSEP
35             $SRSTAG $SRSWRAP
36             $SRSHASHLENGTH $SRSMAXAGE
37             );
38             %EXPORT_TAGS = (
39             all => \@EXPORT_OK,
40             );
41              
42             =head1 NAME
43              
44             Mail::SRS - Interface to Sender Rewriting Scheme
45              
46             =head1 SYNOPSIS
47              
48             use Mail::SRS;
49             my $srs = new Mail::SRS(
50             Secret => [ .... ], # scalar or array
51             MaxAge => 49, # days
52             HashLength => 4, # base64 characters: 4 x 6bits
53             HashMin => 4, # base64 characters
54             );
55             my $srsaddress = $srs->forward($sender, $alias);
56             my $sender = $srs->reverse($srsaddress);
57              
58             =head1 DESCRIPTION
59              
60             The Sender Rewriting Scheme preserves .forward functionality in an
61             SPF-compliant world.
62              
63             SPF requires the SMTP client IP to match the envelope sender
64             (return-path). When a message is forwarded through an intermediate
65             server, that intermediate server may need to rewrite the return-path
66             to remain SPF compliant. If the message bounces, that intermediate
67             server needs to validate the bounce and forward the bounce to the
68             original sender.
69              
70             SRS provides a convention for return-path rewriting which allows
71             multiple forwarding servers to compact the return-path. SRS also
72             provides an authentication mechanism to ensure that purported bounces
73             are not arbitrarily forwarded.
74              
75             SRS is documented at http://spf.pobox.com/srs.html and many points
76             about the scheme are discussed at http://www.anarres.org/projects/srs/
77              
78             For a better understanding of this code and how it functions, please
79             read this document and run the interactive walkthrough in eg/simple.pl
80             in this distribution. To run this from the build directory, type
81             "make teach".
82              
83             =head1 METHODS
84              
85             =head2 $srs = new Mail::SRS(...)
86              
87             Construct a new Mail::SRS object and return it. Available parameters
88             are:
89              
90             =over 4
91              
92             =item Secret => $string
93              
94             A key for the cryptographic algorithms. This may be an array or a single
95             string. A string is promoted into an array of one element.
96              
97             =item MaxAge
98              
99             The maximum number of days for which a timestamp is considered
100             valid. After this time, the timestamp is invalid.
101              
102             =item HashLength => $integer
103              
104             The number of bytes of base64 encoded data to use for the cryptographic
105             hash. More is better, but makes for longer addresses which might
106             exceed the 64 character length suggested by RFC2821. This defaults to
107             4, which gives 4 x 6 = 24 bits of cryptographic information, which
108             means that a spammer will have to make 2^24 attempts to guarantee
109             forging an SRS address.
110              
111             =item HashMin => $integer
112              
113             The shortest hash which we will allow to pass authentication. Since we
114             allow any valid prefix of the full SHA1 HMAC to pass authentication,
115             a spammer might just suggest a hash of length 0. We require at least
116             HashMin characters, which must all be correct. Naturally, this must
117             be no greater than HashLength and will default to HashLength unless
118             otherwise specified.
119              
120             =item Separator => $character
121              
122             Specify the initial separator to use immediately after the SRS tag. SRS
123             uses the = separator throughout EXCEPT for the initial separator,
124             which may be any of + - or =.
125              
126             Some MTAs already have a feature by which text after a + or - is
127             ignored for the purpose of identifying a local recipient. If the
128             initial separator is set to + or -, then an administrator may process
129             all SRS mails by creating users SRS0 and SRS1, and using Mail::SRS
130             in the default delivery rule for these users.
131              
132             Some notes on the use and preservation of these separators are found
133             in the perldoc for L.
134              
135             =item AlwaysRewrite => $boolean
136              
137             SRS rewriting is not performed by default if the alias host matches
138             the sender host, since it would be unnecessary to do so, and it
139             interacts badly with ezmlm if we do. Set this to true if you want
140             always to rewrite when requested to do so.
141              
142             =item IgnoreTimestamp => $boolean
143              
144             Consider all timestamps to be valid. Defaults to false. It is STRONGLY
145             recommended that this remain false. This parameter is provided so that
146             timestamps may be ignored temporarily after a change in the timestamp
147             format or encoding, until all timestamps in the old encoding would
148             have become invalid. Note that timestamps still form a part of the
149             cryptographic data when this is enabled.
150              
151             =item AllowUnsafeSrs
152              
153             This is a backwards compatibility option for an older version of the
154             protocol where SRS1 was not hash-protected. The 'reverse' method
155             will detect such addresses, and handle them properly. Deployments
156             upgrading from version <=0.27 to any version >=0.28 should enable
157             this for MaxAge+1 days.
158              
159             When this option is enabled, all new addresses will be generated with
160             cryptographic protection.
161              
162             =back
163              
164             Some subclasses require other parameters. See their documentation for
165             details.
166              
167             =cut
168              
169             sub new {
170 35     35 1 4052 my $class = shift;
171              
172 35 100       112 if ($class eq 'Mail::SRS') {
173 10         2861 require Mail::SRS::Guarded;
174 10         71 return new Mail::SRS::Guarded(@_);
175             }
176              
177 25 100       152 my $self = ($#_ == 0) ? { %{ (shift) } } : { @_ };
  1         5  
178 25 100       145 $self->{Secret} = [ $self->{Secret} ]
179             unless ref($self->{Secret}) eq 'ARRAY';
180 25 50       94 $self->{MaxAge} = $SRSMAXAGE unless $self->{MaxAge};
181 25 50       81 $self->{HashLength} = $SRSHASHLENGTH unless $self->{HashLength};
182 25 50       81 $self->{HashMin} = $self->{HashLength} unless $self->{HashMin};
183 25 100       77 $self->{Separator} = '=' unless exists $self->{Separator};
184 25 100       114 unless ($self->{Separator} =~ m/^[-+=]$/) {
185 1         10 die "Initial separator must be = - or +, " .
186             "not $self->{Separator}";
187             }
188 24         96 return bless $self, $class;
189             }
190              
191             =head2 $srsaddress = $srs->forward($sender, $alias)
192              
193             Map a sender address into a new sender and a cryptographic cookie.
194             Returns an SRS address to use as the new sender.
195              
196             There are alternative subclasses, some of which will return SRS
197             compliant addresses, some will simply return non-SRS but valid RFC821
198             addresses. See the interactive walkthrough for more information on this
199             ("make teach").
200              
201             =cut
202              
203             sub forward {
204 137     137 1 55680 my ($self, $sender, $alias) = @_;
205              
206 137 50       717 $sender =~ m/^(.*)\@([^\@]+)$/
207             or die "Sender '$sender' contains no \@";
208 137         377 my ($senduser, $sendhost) = ($1, $2);
209 137 50       330 $senduser =~ m/\@/ and die 'Sender username may not contain an @';
210              
211             # We don't require alias to be a full address, just a domain will do
212 137 50       532 if ($alias =~ m/^(.*)\@([^@]+)$/) {
213 137         259 $alias = $2;
214             }
215 137         163 my $aliashost = $alias;
216              
217 137 100       319 if (lc $aliashost eq lc $sendhost) {
218 8 100       34 return "$senduser\@$sendhost" unless $self->{AlwaysRewrite};
219             }
220              
221             # Subclasses may override the compile() method.
222 133         411 my $srsdata = $self->compile($sendhost, $senduser);
223 133         430 return "$srsdata\@$aliashost";
224             }
225              
226             =head2 $sender = $srs->reverse($srsaddress)
227              
228             Reverse the mapping to get back the original address. Validates all
229             cryptographic and timestamp information. Returns the original sender
230             address. This method will die if the address cannot be reversed.
231              
232             =cut
233              
234             sub reverse {
235 136     136 1 22583 my ($self, $address) = @_;
236              
237 136 100       1000 $address =~ m/^(.*)\@([^@])+$/ or croak 'Address contains no @';
238 135         321 my ($user, $host) = ($1, $2);
239              
240 135         161 my ($sendhost, $senduser) = eval { $self->parse($user); };
  135         373  
241 135 100       294 die "Parse error in `$user': $@" if $@;
242              
243 134         422 return "$senduser\@$sendhost";
244             }
245              
246             =head2 $srs->compile($sendhost, $senduser)
247              
248             This method, designed to be overridden by subclasses, takes as
249             parameters the original host and user and must compile a new username
250             for the SRS transformed address. It is expected that this new username
251             will be joined on $SRSSEP, and will contain a hash generated from
252             $self->hash_create(...), and possibly a timestamp generated by
253             $self->timestamp_create().
254              
255             =cut
256              
257             sub compile {
258 0     0 1 0 croak "How did Mail::SRS::compile get called? " .
259             "All subclasses override it";
260             }
261              
262             =head2 $srs->parse($srsuser)
263              
264             This method, designed to be overridden by subclasses, takes an
265             SRS-transformed username as an argument, and must reverse the
266             transformation produced by compile(). It is required to verify any
267             hash and timestamp in the parsed data, using $self->hash_verify($hash,
268             ...) and $self->timestamp_check($timestamp).
269              
270             =cut
271              
272             sub parse {
273 0     0 1 0 croak "How did Mail::SRS::parse get called? " .
274             "All subclasses override it";
275             }
276              
277             =head2 $srs->timestamp_create([$time])
278              
279             Return a two character timestamp representing 'today', or $time if
280             given. $time is a Unix timestamp (seconds since the aeon).
281              
282             This Perl function has been designed to be agnostic as to base,
283             and in practice, base32 is used since it can be reversed even if a
284             remote MTA smashes case (in violation of RFC2821 section 2.4). The
285             agnosticism means that the Perl uses division instead of rightshift,
286             but in Perl that doesn't matter. C implementors should implement this
287             operation as a right shift by 5.
288              
289             =cut
290              
291             # We have two options. We can either encode an send date or an expiry
292             # date. If we encode a send date, we have the option of changing
293             # the expiry date later. If we encode an expiry date, we can send
294             # different expiry dates for different sources/targets, and we don't
295             # have to store them.
296              
297             # Do NOT use BASE64 since the timestamp_check routine now explicit
298             # smashes case in the timestamp just in case there was a problem.
299             # my @BASE64 = ('A'..'Z', 'a'..'z', '0'..'9', '+', '/');
300             my @BASE32 = ('A'..'Z', '2'..'7');
301              
302             my @BASE = @BASE32;
303             my %BASE = map { $BASE[$_] => $_ } (0..$#BASE);
304             # This checks for more than one bit set in the size.
305             # i.e. is the size a power of 2?
306             die "Invalid base array of size " . scalar(@BASE)
307             if scalar(@BASE) & (scalar(@BASE) - 1);
308             my $PRECISION = 60 * 60 * 24; # One day
309             my $TICKSLOTS = scalar(@BASE) * scalar(@BASE); # Two chars
310              
311             sub timestamp_create {
312 101     101 1 176 my ($self, $time) = @_;
313 101 100       268 $time = time() unless defined $time;
314             # Since we only mask in the bottom few bits anyway, we
315             # don't need to take this modulo anything (e.g. @BASE^2).
316 101         182 $time = int($time / $PRECISION); #% $TICKSLOTS;
317             # print "Time is $time\n";
318 101         204 my $out = $BASE[$time & $#BASE]; # $#BASE is 2^n -1
319 101         170 $time = int($time / scalar(@BASE)); # Use right shift.
320 101         363 return $BASE[$time & $#BASE] . $out;
321             }
322              
323             =head2 $srs->timestamp_check($timestamp)
324              
325             Return 1 if a timestamp is valid, undef otherwise. There are 4096
326             possible timestamps, used in a cycle. At any time, $srs->{MaxAge}
327             timestamps in this cycle are valid, the last one being today. A
328             timestamp from the future is not valid, neither is a timestamp from
329             too far into the past. Of course if you go far enough into the future,
330             the cycle wraps around, and there are valid timestamps again, but the
331             likelihood of a random timestamp being valid is 4096/$srs->{MaxAge},
332             which is usually quite small: 1 in 132 by default.
333              
334             =cut
335              
336             sub timestamp_check {
337 105     105 1 624 my ($self, $timestamp) = @_;
338 105 100       252 return 1 if $self->{IgnoreTimestamp};
339 100         175 $timestamp = uc $timestamp; # LOOK OUT - USE BASE32
340 100         121 my $time = 0;
341 100         340 foreach (split(//, $timestamp)) {
342 200         439 $time = $time * scalar(@BASE) + $BASE{$_};
343             }
344 100         247 my $now = int(time() / $PRECISION) % $TICKSLOTS;
345             # print "Time is $time, Now is $now\n";
346 100         225 $now += $TICKSLOTS while $now < $time;
347 100 100       466 return 1 if $now <= ($time + $self->{MaxAge});
348 3         10 return undef;
349             }
350              
351             =head2 $srs->time_check($time)
352              
353             Similar to $srs->timestamp_check($timestamp), but takes a Unix time, and
354             checks that an alias created at that Unix time is still valid. This is
355             designed for use by subclasses with storage backends.
356              
357             =cut
358              
359             sub time_check {
360 0     0 1 0 my ($self, $time) = @_;
361 0 0       0 return 1 if time() <= ($time + ($self->{MaxAge} * $PRECISION));
362 0         0 return undef;
363             }
364              
365             =head2 $srs->hash_create(@data)
366              
367             Returns a cryptographic hash of all data in @data. Any piece of data
368             encoded into an address which must remain inviolate should be hashed,
369             so that when the address is reversed, we can check that this data has
370             not been tampered with. You must provide at least one piece of data
371             to this method (otherwise this system is both cryptographically weak
372             and there may be collision problems with sender addresses).
373              
374             =cut
375              
376             sub hash_create {
377 134     134 1 1032 my ($self, @args) = @_;
378              
379 134         278 my @secret = $self->get_secret;
380 134 50       298 croak "Cannot create a cryptographic MAC without a secret"
381             unless @secret;
382 134         450 my $hmac = new Digest::HMAC_SHA1($secret[0]);
383 134         4502 foreach (@args) {
384 358         1929 $hmac->add(lc $_);
385             }
386 134         897 my $hash = $hmac->b64digest;
387 134         3279 return substr($hash, 0, $self->{HashLength});
388             }
389              
390             =head2 $srs->hash_verify($hash, @data)
391              
392             Verify that @data has not been tampered with, given the cryptographic
393             hash previously output by $srs->hash_create(); Returns 1 or undef.
394             All known secrets are tried in order to see if the hash was created
395             with an old secret.
396              
397             =cut
398              
399             sub hash_verify {
400 136     136 1 836 my ($self, $hash, @args) = @_;
401 136 50       335 return undef unless length $hash >= $self->{HashMin};
402 136         250 my @secret = $self->get_secret;
403 136 50       310 croak "Cannot verify a cryptographic MAC without a secret"
404             unless @secret;
405 136         169 my @valid = ();
406 136         204 foreach my $secret (@secret) {
407 138         403 my $hmac = new Digest::HMAC_SHA1($secret);
408 138         3846 foreach (@args) {
409 366         1873 $hmac->add(lc $_);
410             }
411 138         897 my $valid = substr($hmac->b64digest, 0, length($hash));
412             # We test all case sensitive matches before case insensitive
413             # matches. While the risk of a case insensitive collision is
414             # quite low, we might as well be careful.
415 138 100       3144 return 1 if $valid eq $hash;
416 26         99 push(@valid, $valid); # Lowercase it later.
417             }
418 24         203 $hash = lc($hash);
419 24         37 foreach (@valid) {
420 26 100       59 if ($hash eq lc($_)) {
421 22         200 warn "SRS: Case insensitive hash match detected. " .
422             "Someone smashed case in the local-part.";
423 22         161 return 1;
424             }
425             }
426 2         11 return undef;
427             }
428              
429             =head2 $srs->set_secret($new, @old)
430              
431             Add a new secret to the rewriter. When an address is returned, all
432             secrets are tried to see if the hash can be validated. Don't use "foo",
433             "secret", "password", "10downing", "god" or "wednesday" as your secret.
434              
435             =cut
436              
437             sub set_secret {
438 1     1 1 403 my $self = shift;
439 1         5 $self->{Secret} = [ @_ ];
440             }
441              
442             =head2 $srs->get_secret()
443              
444             Return the list of secrets. These are secret. Don't publish them.
445              
446             =cut
447              
448             sub get_secret {
449 275     275 1 6233 return @{$_[0]->{Secret}};
  275         840  
450             }
451              
452             =head2 $srs->separator()
453              
454             Return the initial separator, which follows the SRS tag. This is only
455             used as the initial separator, for the convenience of administrators
456             who wish to make srs0 and srs1 users on their mail servers and require
457             to use + or - as the user delimiter. All other separators in the SRS
458             address must be C<=>.
459              
460             =cut
461              
462             sub separator {
463 136     136 1 2049 return $_[0]->{Separator};
464             }
465              
466             =head1 EXPORTS
467              
468             Given :all, this module exports the following variables.
469              
470             =over 4
471              
472             =item $SRSSEP
473              
474             The SRS separator. The choice of C<=> as internal separator was fairly
475             arbitrary. It cannot be any of the following:
476              
477             =over 4
478              
479             =item / +
480              
481             Used in Base64.
482              
483             =item -
484              
485             Used in domains.
486              
487             =item ! %
488              
489             Used in bang paths and source routing.
490              
491             =item :
492              
493             Cannot be used in a Windows NT or Apple filename.
494              
495             =item ; | *
496              
497             Shell or regular expression metacharacters are probably to be avoided.
498              
499             =back
500              
501             =item $SRS0TAG
502              
503             The SRS0 tag.
504              
505             =item $SRS1TAG
506              
507             The SRS1 tag.
508              
509             =item $SRSTAG
510              
511             Deprecated, equal to $SRS0TAG.
512              
513             =item $SRSWRAP
514              
515             Deprecated, equal to $SRS1TAG.
516              
517             =item $SRSHASHLENGTH
518              
519             The default hash length for the SRS HMAC.
520              
521             =item $SRSMAXAGE
522              
523             The default expiry time for timestamps.
524              
525             =back
526              
527             =head1 EXAMPLES OF USAGE
528              
529             For people wanting boilerplate and those less familiar with using
530             Perl modules in larger applications.
531              
532             =head2 Forward Rewriting
533              
534             my $srs = new Mail::SRS(...);
535             my $address = ...
536             my $domain = ...
537             my $srsaddress = eval { $srs->forward($srsaddress, $domain); };
538             if ($@) {
539             # The rewrite failed
540             }
541             else {
542             # The rewrite succeeded
543             }
544              
545             =head2 Reverse Rewriting
546              
547             my $srs = new Mail::SRS(...);
548             my $srsaddress = ...
549             my $address = eval { $srs->reverse($srsaddress); };
550             if ($@) {
551             # The rewrite failed
552             }
553             else {
554             # The rewrite succeeded
555             }
556              
557             =head1 NOTES ON SRS
558              
559             =head2 Case Sensitivity
560              
561             RFC2821 states in section 2.4: "The local-part of a mailbox MUST BE
562             treated as case sensitive. Therefore, SMTP implementations MUST take
563             care to preserve the case of mailbox local-parts. [...] In particular,
564             for some hosts the user "smith" is different from the user "Smith".
565             However, exploiting the case sensitivity of mailbox local-parts
566             impedes interoperability and is discouraged."
567              
568             SRS does not rely on case sensitivity in the local part. It uses
569             base64 for encoding the hash, but allows a case insensitive match,
570             making this approximately equivalent to base36 at worst. It will
571             issue a warning if it detects that a remote MTA has smashed case. The
572             timestamp is encoded in base32.
573              
574             =head2 The 64 Billion Character Question
575              
576             RFC2821 section 4.5.3.1: Size limits and minimums:
577              
578             There are several objects that have required minimum/maximum
579             sizes. Every implementation MUST be able to receive objects
580             of at least these sizes. Objects larger than these sizes
581             SHOULD be avoided when possible. However, some Internet
582             mail constructs such as encoded X.400 addresses [16] will
583             often require larger objects: clients MAY attempt to transmit
584             these, but MUST be prepared for a server to reject them if
585             they cannot be handled by it. To the maximum extent possible,
586             implementation techniques which impose no limits on the length
587             of these objects should be used.
588              
589             local-part
590             The maximum total length of a user name or other
591             local-part is 64 characters.
592              
593             Clearly, by including 2 domain names and a local-part in the rewritten
594             address, there is no way in which SRS can guarantee to stay under
595             this limit. However, very few systems are known to actively enforce
596             this limit, and those which become known to the developers will be
597             listed here.
598              
599             =over 4
600              
601             =item Cisco: PIX MailGuard (firewall gimmick)
602              
603             =item WebShield [something] (firewall gimmick)
604              
605             =back
606              
607             =head2 Invalid SRS Addresses
608              
609             DO NOT MALFORMAT ADDRESSES. This is designed to be an interoperable
610             format. Certain things are allowed, such as changing the semantics
611             of the hash or the timestamp. However, both of these fields must
612             be present and separated by the SRS separator character C<=>. The
613             purpose of this section is to illustrate that if a malicious party
614             were to malformat an address, he would gain nothing by doing so,
615             nor would the network suffer.
616              
617             The SRS protocol is predicated on the fact that the first forwarder
618             provides a cryptographic wrapper on the forward chain for sending
619             mail to the original sender. So what happens if an SRS address is
620             invalid, or faked by a spammer?
621              
622             The minimum parsing of existing SRS addresses is done at each hop. If
623             an SRS0 address is not valid or badly formatted, it will not affect
624             the operation of the system: the mail will go out along the forwarder
625             chain, and return to the invalid or badly formatted address.
626              
627             If the spammer is not pretending to be the first hop, then he
628             must somehow construct an SRS0 address to embed within his SRS1
629             address. The cryptographic checks on this SRS0 address will fail at
630             the first forwarder and the mail will be dropped.
631              
632             If the spammer is pretending to be the first hop, then SPF should
633             require that any bounces coming back return to his mail server,
634             thus he wins nothing.
635              
636             =head2 Cryptographic Systems
637              
638             The hash in the address is designed to prevent the forging of reverse
639             addresses by a spammer, who might then use the SRS host as a forwarder.
640             It may only be constructed or validated by a party who knows the
641             secret key.
642              
643             The cryptographic system in the default implementation is not mandated.
644             Since nobody else ever needs to interpret the hash, it is reasonable
645             to put any binary data into this field (subject to the possible
646             constraint of case insensitive encoding).
647              
648             The SRS maintainers have attempted to provide a good system. It
649             satisfies a simple set of basic requirements: to provide unforgeability
650             of SRS addresses given that every MTA for a domain shares a secret key.
651             We prefer SHA1 over MD5 for political, rather than practical reasons.
652             (Anyone disputing this statement must include an example of a practical
653             weakness in their mail. We would love to see it.)
654              
655             If you find a weakness in our system, or you think you know of a
656             better system, please tell us. If your requirements are different,
657             you may override hash_create() and hash_verify() to implement a
658             different system without adversely impacting the network, as long as
659             your addresses still behave as SRS addresses.
660              
661             =head2 Extending Mail::SRS
662              
663             Write a subclass. You will probably want to override compile() and
664             parse(). If you are more familiar with the internals of SRS, you might
665             want to override hash_create(), hash_verify(), timestamp_create()
666             or timestamp_check().
667              
668             =head1 CHANGELOG
669              
670             =head2 MINOR CHANGES since v0.29
671              
672             =over 4
673              
674             =item timestamp_check now explicitly smashes case when verifying. This
675             means that the base used must be base32, NOT base64.
676              
677             =item hash_create and hash_verify now explicitly smash case when
678             creating and verifying hashes. This does not have a significant
679             cryptographic impact.
680              
681             =back
682              
683             =head2 MAJOR CHANGES since v0.27
684              
685             =over 4
686              
687             =item The SRS1 address format has changed to include cryptographic
688             information. Existing deployments should consider setting
689             AllowUnsafeSrs for MaxAge+1 days.
690              
691             =back
692              
693             =head2 MINOR CHANGES since v0.26
694              
695             =over 4
696              
697             =item parse() and compile() are explicitly specified to die() on error.
698              
699             =back
700              
701             =head2 MINOR CHANGES since v0.23
702              
703             =over 4
704              
705             =item Update BASE32 according to RFC3548.
706              
707             =back
708              
709             =head2 MINOR CHANGES since v0.21
710              
711             =over 4
712              
713             =item Dates are now encoded in base32.
714              
715             =item Case insensitive MAC validation is now allowed, but will issue
716             a warning.
717              
718             =back
719              
720             =head2 MINOR CHANGES since v0.18
721              
722             =over 4
723              
724             =item $SRSTAG and $SRSWRAP are deprecated.
725              
726             =item Mail::SRS::Reversable is now Mail::SRS::Reversible
727              
728             This should not be a problem since people should not be using it!
729              
730             =back
731              
732             You must use $SRS0RE and $SRS1RE to detect SRS addresses.
733              
734             =head2 MAJOR CHANGES since v0.15
735              
736             =over 4
737              
738             =item The separator character is now C<=>.
739              
740             =item The cryptographic scheme is now HMAC with SHA1.
741              
742             =item Only a prefix of the MAC is used.
743              
744             =back
745              
746             This API is still a release candidate and should remain relatively
747             stable.
748              
749             =head1 BUGS
750              
751             Email address parsing for quoted addresses is not yet done properly.
752              
753             Case insensitive MAC validation should become an option.
754              
755             =head1 TODO
756              
757             Write a testsuite for testing user-defined SRS implementations.
758              
759             =head1 SEE ALSO
760              
761             L, L, L,
762             "make teach", eg/*, http://www.anarres.org/projects/srs/
763              
764             =head1 AUTHOR
765              
766             Shevek
767             CPAN ID: SHEVEK
768             cpan@anarres.org
769             http://www.anarres.org/projects/
770              
771             =head1 COPYRIGHT
772              
773             Copyright (c) 2004 Shevek. All rights reserved.
774              
775             This program is free software; you can redistribute it and/or modify
776             it under the same terms as Perl itself.
777              
778             =cut
779              
780             1;