File Coverage

blib/lib/Algorithm/IRCSRP2/Alice.pm
Criterion Covered Total %
statement 2 4 50.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 4 6 66.6


line stmt bran cond sub pod time code
1             package Algorithm::IRCSRP2::Alice;
2              
3             BEGIN {
4 1     1   4529 $Algorithm::IRCSRP2::Alice::VERSION = '0.501';
5             }
6              
7             # ABSTRACT: Alice interface
8              
9 1     1   441 use Moose;
  0            
  0            
10              
11             extends 'Algorithm::IRCSRP2';
12              
13             with 'Algorithm::IRCSRP2::Exchange';
14              
15             # core
16             use MIME::Base64;
17             use Digest::SHA;
18              
19             # CPAN
20             use Crypt::OpenSSL::AES;
21             use Moose::Util::TypeConstraints qw(enum);
22              
23             # local
24             use Algorithm::IRCSRP2::Utils qw(:all);
25              
26             has '+am_i_dave' => ('default' => 0, 'is' => 'ro');
27              
28             has 'state' => (
29             'isa' => enum([qw(null error init srpa0 srpa1 srpa2 srpa3 authenticated)]),
30             'is' => 'rw',
31             'default' => 'null',
32             'trigger' => sub {
33             my ($self, $new, $old) = @_;
34              
35             $self->debug_cb->("State change $old -> $new");
36              
37             if ($new eq 'error') {
38             $self->debug_cb->('Fatal error: ', $self->error);
39             }
40             }
41             );
42              
43             sub srpa0 {
44             my ($self) = @_;
45              
46             $self->state('srpa0');
47              
48             return '+srpa0 ' . $self->I();
49             }
50              
51             sub verify_srpa1 {
52             my ($self, $msg) = @_;
53              
54             $msg =~ s/^\+srpa1 //;
55              
56             my $decoded = MIME::Base64::decode_base64($msg);
57              
58             my $s = substr($decoded, 0, 32, '');
59             $self->s($s);
60              
61             my $B = $self->B(bytes2int($decoded));
62              
63             if ($B->copy->bmod(N()) != 0) {
64             $self->state('srpa1');
65              
66             return $self->srpa2();
67             }
68             else {
69             $self->error('srpa1');
70             $self->state('error');
71             return 0;
72             }
73             }
74              
75             sub srpa2 {
76             my ($self) = @_;
77              
78             # a = random integer with 1 < a < N.
79             my $a = Math::BigInt->new(gen_a());
80             $self->a($a);
81              
82             # A = g^a (mod N)
83             my $A = Math::BigInt->new(g());
84             $A->bmodpow($a->bstr, N());
85             $self->A($A);
86              
87             # x = H(s || I || P)
88             my $x = bytes2int(H($self->s . $self->I . $self->P));
89             $self->x($x);
90              
91             # u = H(A || B)
92             my $u = bytes2int(H(int2bytes($A) . int2bytes($self->B)));
93             $self->u($u);
94              
95             # S = (B - 3g^x)^(a + ux) (mod N)
96             my $t = Math::BigInt->new(g());
97             $t->bmodpow($x->bstr, N());
98             $t->bmul(3);
99              
100             my $q = $self->B->copy;
101             $q->bsub($t);
102              
103             $t = $q->copy;
104              
105             my $t2 = $u->copy;
106             $t2->bmul($x->bstr);
107             $t2->badd($a->bstr);
108             $t2->bmod(N());
109              
110             my $S = $t->copy;
111              
112             $S->bmodpow($t2->bstr, N());
113             $self->debug_cb->('h' x 20 . $S->bstr);
114             $self->S($S);
115              
116             # K1 = H(S || "enc")
117             my $K1 = Digest::SHA::sha256(int2bytes($S) . 'enc');
118             $self->K1($K1);
119              
120             # K2 = H(S || "auth")
121             my $K2 = Digest::SHA::sha256(int2bytes($S) . 'auth');
122             $self->K2($K2);
123              
124             # M1 = H(A || B || S)
125             my $M1 = H(int2bytes($A) . int2bytes($self->B) . int2bytes($S));
126             $self->M1($M1);
127              
128             # ircmessage = "+srpa2 " || Base64(M1 || IntAsBytes(A))
129             my $msg = MIME::Base64::encode_base64($M1 . int2bytes($A), '');
130              
131             $self->state('srpa2');
132              
133             return '+srpa2 ' . $msg;
134             }
135              
136             sub verify_srpa3 {
137             my ($self, $msg) = @_;
138              
139             $msg =~ s/^\+srpa3 //;
140              
141             my $cipher = MIME::Base64::decode_base64($msg);
142              
143             my $cmac = substr($cipher, 0, 16);
144              
145             if (hmac_sha256_128($self->K2(), substr($cipher, 16)) ne $cmac) {
146             $self->error('incorrect mac');
147             $self->state('error');
148             }
149              
150             $self->state('srpa3');
151              
152             $self->cipher(Crypt::OpenSSL::AES->new($self->K1()));
153              
154             my $plain = $self->cbc_decrypt(substr($cipher, 16));
155              
156             my $sessionkey = substr($plain, 0, 32);
157             my $mackey = substr($plain, 32, 32);
158             my $M2 = substr($plain, 64, 32);
159              
160             $self->debug_cb->('sessionkey ' . bytes2int($sessionkey));
161             $self->debug_cb->('mackey ' . bytes2int($mackey));
162              
163             my $M2ver = H(join('', int2bytes($self->A), $self->M1, int2bytes($self->S)));
164              
165             $self->debug_cb->('M2 ' . bytes2int($M2));
166             $self->debug_cb->('M2ver ' . bytes2int($M2ver));
167              
168             if ($M2 ne $M2ver) {
169             $self->error('M2 != M2ver');
170             $self->state('error');
171             }
172              
173             $self->session_key($sessionkey);
174             $self->cipher(Crypt::OpenSSL::AES->new($sessionkey));
175             $self->mac_key($mackey);
176              
177             $self->state('authenticated');
178              
179             return 1;
180             }
181              
182             no Moose::Util::TypeConstraints;
183             no Moose;
184              
185             __PACKAGE__->meta->make_immutable;
186              
187             1;
188              
189             __END__
190              
191             =pod
192              
193             =head1 NAME
194              
195             Algorithm::IRCSRP2::Alice - Alice interface
196              
197             =head1 VERSION
198              
199             version 0.501
200              
201             =head1 DESCRIPTION
202              
203             Implements the "Alice" side to the IRCSRP version 2 protocol. See how to use in
204             the Pidgin plugin implementation at L<https://gitorious.org/ircsrp/ircsrp>.
205              
206             =head1 BASE CLASS
207              
208             L<Algorithm::IRCSRP2>
209              
210             =head1 ROLES
211              
212             L<Algorithm::IRCSRP2::Exchange>
213              
214             =head1 ATTRIBUTES
215              
216             =head2 Optional Attributes
217              
218             =over
219              
220             =item * B<am_i_dave> (ro, Bool) - Defaults to '0'.
221              
222             =item * B<state> (rw, Str) - Defaults to 'null'.
223              
224             =back
225              
226             =head1 PUBLIC API METHODS
227              
228             See also L<Algorithm::IRCSRP2> (base class).
229              
230             =over
231              
232             =item * B<srpa0()> - Generate C<+spr0> string.
233              
234             =item * B<srpa2()> - Generates C<+srpa2> string.
235              
236             =item * B<verify_srpa1($msg)> - Verifies Dave's C<+srpa1> message.
237              
238             =item * B<verify_srpa3($msg)> - Verifies Dave's C<+srpa3> message. Once this is
239             done. Authentication is complete.
240              
241             =back
242              
243             =head1 AUTHOR
244              
245             Adam Flott <adam@npjh.com>
246              
247             =head1 COPYRIGHT AND LICENSE
248              
249             This software is copyright (c) 2011 by Adam Flott.
250              
251             This is free software; you can redistribute it and/or modify it under
252             the same terms as the Perl 5 programming language system itself.
253              
254             =cut