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   131092 use strict;
  7         31  
  7         213  
4 7     7   37 use warnings;
  7         19  
  7         176  
5 7     7   38 use POSIX qw();
  7         19  
  7         137  
6 7     7   533 use Digest::HMAC_SHA1 qw(hmac_sha1);
  7         5467  
  7         353  
7 7     7   3556 use namespace::autoclean;
  7         69193  
  7         28  
8              
9             sub generate {
10 16     16 1 176 my ($password, $keysize) = @_;
11 16         37 my $key = '';
12 16         28 my $offset = 0;
13 16         32 my $salt = "\0" x 8;
14 16         30 my $iters = 1000;
15 16         28 my $blocksize = 20;
16              
17 16         93 my $num_blocks = POSIX::ceil($keysize / $blocksize);
18 16         96 my $digest = Digest::HMAC_SHA1->new($password);
19 16         1127 foreach my $idx (1 .. $num_blocks) {
20 18         81 $digest->reset();
21 18         388 $digest->add($salt);
22 18         188 $digest->add(pack('N', $idx));
23 18         140 my $sha = $digest->digest;
24              
25             # generate the next block, and grab up to "$blocksize" chars out of it
26 18         457 my $block = _generate_block($password, $sha, $iters);
27 18         59 my $need = $keysize - $offset;
28 18 100       80 my $grabbing = $need < $blocksize ? $need : $blocksize;
29 18         71 $key .= substr($block, 0, $grabbing);
30 18         63 $offset += $grabbing;
31             }
32 16         222 return $key;
33             }
34              
35             sub _generate_block {
36 18     18   53 my ($password, $sha, $iters) = @_;
37 18         34 my $result = $sha;
38 18         36 my $current = $sha;
39              
40 18         45 for (2 .. $iters) {
41 17982         31580 $current = hmac_sha1($current, $password);
42 17982         272668 $result = $result ^ $current;
43             }
44 18         63 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