File Coverage

blib/lib/Crypt/OpenToken/KeyGenerator.pm
Criterion Covered Total %
statement 38 38 100.0
branch 2 2 100.0
condition n/a
subroutine 6 6 100.0
pod 1 1 100.0
total 47 47 100.0


line stmt bran cond sub pod time code
1             package Crypt::OpenToken::KeyGenerator;
2              
3 7     7   109341 use strict;
  7         27  
  7         556  
4 7     7   42 use warnings;
  7         26  
  7         194  
5 7     7   41 use POSIX qw();
  7         19  
  7         130  
6 7     7   501 use Digest::HMAC_SHA1 qw(hmac_sha1);
  7         5230  
  7         2459  
7              
8             sub generate {
9 16     16 1 184 my ($password, $keysize) = @_;
10 16         32 my $key = '';
11 16         32 my $offset = 0;
12 16         28 my $salt = "\0" x 8;
13 16         30 my $iters = 1000;
14 16         26 my $blocksize = 20;
15              
16 16         90 my $num_blocks = POSIX::ceil($keysize / $blocksize);
17 16         102 my $digest = Digest::HMAC_SHA1->new($password);
18 16         761 foreach my $idx (1 .. $num_blocks) {
19 18         75 $digest->reset();
20 18         357 $digest->add($salt);
21 18         184 $digest->add(pack('N', $idx));
22 18         136 my $sha = $digest->digest;
23              
24             # generate the next block, and grab up to "$blocksize" chars out of it
25 18         431 my $block = _generate_block($password, $sha, $iters, $idx);
26 18         39 my $need = $keysize - $offset;
27 18 100       61 my $grabbing = $need < $blocksize ? $need : $blocksize;
28 18         59 $key .= substr($block, 0, $grabbing);
29 18         63 $offset += $grabbing;
30             }
31 16         193 return $key;
32             }
33              
34             sub _generate_block {
35 18     18   50 my ($password, $sha, $iters, $idx) = @_;
36 18         30 my $result = $sha;
37 18         31 my $current = $sha;
38              
39 18         46 for (2 .. $iters) {
40 17982         31119 $current = hmac_sha1($current, $password);
41 17982         263027 $result = $result ^ $current;
42             }
43 18         53 return $result;
44             }
45              
46             1;
47              
48             =head1 NAME
49              
50             Crypt::OpenToken::KeyGenerator - Generates keys based on shared passwords
51              
52             =head1 SYNOPSIS
53              
54             use Crypt::OpenToken::KeyGenerator;
55              
56             $key = Crypt::OpenToken::KeyGenerator::generate($password, $keysize);
57              
58             =head1 DESCRIPTION
59              
60             This module implements a key generation function.
61              
62             =head1 METHODS
63              
64             =over
65              
66             =item generate($password, $keysize)
67              
68             Generates an OpenToken key using the provided C<$password>. They generated
69             key will C<$keysize> bytes in length.
70              
71             =back
72              
73             =head1 AUTHOR
74              
75             Graham TerMarsch (cpan@howlingfrog.com)
76              
77             =head1 COPYRIGHT & LICENSE
78              
79             C<Crypt::OpenToken> is Copyright (C) 2010, Socialtext, and is released under
80             the Artistic-2.0 license.
81              
82             =cut