File Coverage

blib/lib/Crypt/OpenToken/KeyGenerator.pm
Criterion Covered Total %
statement 41 41 100.0
branch 2 2 100.0
condition n/a
subroutine 7 7 100.0
pod 1 1 100.0
total 51 51 100.0


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