root/feedmelinks/lib/Crypt/DH.pm

Revision 1448, 6.6 kB (checked in by jm3, 2 years ago)

new spammer blacklist, perl libs, and better splinker hunting tools

Line 
1 # $Id: DH.pm 1860 2005-06-11 06:15:44Z btrott $
2
3 package Crypt::DH;
4 use strict;
5
6 use Math::BigInt lib => "GMP,Pari";
7 our $VERSION = '0.06';
8
9 sub new {
10     my $class = shift;
11     my $dh = bless {}, $class;
12
13     my %param = @_;
14     for my $w (qw( p g priv_key )) {
15         next unless exists $param{$w};
16         $dh->$w(delete $param{$w});
17     }
18     die "Unknown parameters to constructor: " . join(", ", keys %param) if %param;
19
20     $dh;
21 }
22
23 BEGIN {
24     no strict 'refs';
25     for my $meth (qw( p g pub_key priv_key )) {
26         *$meth = sub {
27             my $key = shift;
28             if (@_) {
29                 $key->{$meth} = _any2bigint(shift);
30             }
31             my $ret = $key->{$meth} || "";
32             $ret;
33         };
34     }
35 }
36
37 sub _any2bigint {
38     my($value) = @_;
39     if (ref $value eq 'Math::BigInt') {
40         return $value;
41     }
42     elsif (ref $value eq 'Math::Pari') {
43         return Math::BigInt->new(Math::Pari::pari2pv($value));
44     }
45     elsif (defined $value && !(ref $value)) {
46         return Math::BigInt->new($value);
47     }
48     elsif (defined $value) {
49         die "Unknown parameter type: $value\n";
50     }
51 }
52
53 sub generate_keys {
54     my $dh = shift;
55
56     unless (defined $dh->{priv_key}) {
57         my $i = _bitsize($dh->{p}) - 1;
58         $dh->{priv_key} =
59             $Crypt::Random::VERSION ?
60             Crypt::Random::makerandom_itv(Strength => 0, Uniform => 1,
61                                           Lower => 1, Upper => $dh->{p} - 1) :
62             _makerandom_itv($i, 1, $dh->{p} - 1);
63     }
64
65     $dh->{pub_key} = $dh->{g}->copy->bmodpow($dh->{priv_key}, $dh->{p});
66 }
67
68 sub compute_key {
69     my $dh = shift;
70     my $pub_key = _any2bigint(shift);
71     $pub_key->copy->bmodpow($dh->{priv_key}, $dh->{p});
72 }
73 *compute_secret = \&compute_key;
74
75 sub _bitsize {
76     return length($_[0]->as_bin) - 2;
77 }
78
79 sub _makerandom_itv {
80     my ($size, $min_inc, $max_exc) = @_;
81
82     while (1) {
83         my $r = _makerandom($size);
84         return $r if $r >= $min_inc && $r < $max_exc;
85     }
86 }
87
88 sub _makerandom {
89     my $size = shift;
90
91     my $bytes = int($size / 8) + ($size % 8 ? 1 : 0);
92
93     my $rand;
94     if (-e "/dev/urandom") {
95         my $fh;
96         open($fh, '/dev/urandom')
97             or die "Couldn't open /dev/urandom";
98         my $got = sysread $fh, $rand, $bytes;
99         die "Didn't read all bytes from urandom" unless $got == $bytes;
100         close $fh;
101     } else {
102         for (1..$bytes) {
103             $rand .= chr(int(rand(256)));
104         }
105     }
106
107     my $bits = unpack("b*", $rand);
108     die unless length($bits) >= $size;
109
110     Math::BigInt->new('0b' . substr($bits, 0, $size));
111 }
112
113 1;
114 __END__
115
116 =head1 NAME
117
118 Crypt::DH - Diffie-Hellman key exchange system
119
120 =head1 SYNOPSIS
121
122     use Crypt::DH;
123     my $dh = Crypt::DH->new;
124     $dh->g($g);
125     $dh->p($p);
126
127     ## Generate public and private keys.
128     $dh->generate_keys;
129
130     $my_pub_key = $dh->pub_key;
131
132     ## Send $my_pub_key to "other" party, and receive "other"
133     ## public key in return.
134
135     ## Now compute shared secret from "other" public key.
136     my $shared_secret = $dh->compute_secret( $other_pub_key );
137
138 =head1 DESCRIPTION
139
140 I<Crypt::DH> is a Perl implementation of the Diffie-Hellman key
141 exchange system. Diffie-Hellman is an algorithm by which two
142 parties can agree on a shared secret key, known only to them.
143 The secret is negotiated over an insecure network without the
144 two parties ever passing the actual shared secret, or their
145 private keys, between them.
146
147 =head1 THE ALGORITHM
148
149 The algorithm generally works as follows: Party A and Party B
150 choose a property I<p> and a property I<g>; these properties are
151 shared by both parties. Each party then computes a random private
152 key integer I<priv_key>, where the length of I<priv_key> is at
153 most (number of bits in I<p>) - 1. Each party then computes a
154 public key based on I<g>, I<priv_key>, and I<p>; the exact value
155 is
156
157     g ^ priv_key mod p
158
159 The parties exchange these public keys.
160
161 The shared secret key is generated based on the exchanged public
162 key, the private key, and I<p>. If the public key of Party B is
163 denoted I<pub_key_B>, then the shared secret is equal to
164
165     pub_key_B ^ priv_key mod p
166
167 The mathematical principles involved insure that both parties will
168 generate the same shared secret key.
169
170 More information can be found in PKCS #3 (Diffie-Hellman Key
171 Agreement Standard):
172
173     http://www.rsasecurity.com/rsalabs/pkcs/pkcs-3/
174
175 =head1 USAGE
176
177 I<Crypt::DH> implements the core routines needed to use
178 Diffie-Hellman key exchange. To actually use the algorithm,
179 you'll need to start with values for I<p> and I<g>; I<p> is a
180 large prime, and I<g> is a base which must be larger than 0
181 and less than I<p>.
182
183 I<Crypt::DH> uses I<Math::BigInt> internally for big-integer
184 calculations. All accessor methods (I<p>, I<g>, I<priv_key>, and
185 I<pub_key>) thus return I<Math::BigInt> objects, as does the
186 I<compute_secret> method.  The accessors, however, allow setting with a
187 scalar decimal string, hex string (^0x), Math::BigInt object, or
188 Math::Pari object (for backwards compatibility).
189
190 =head2 $dh = Crypt::DH->new([ %param ]).
191
192 Constructs a new I<Crypt::DH> object and returns the object.
193 I<%param> may include none, some, or all of the keys I<p>, I<g>, and
194 I<priv_key>.
195
196 =head2 $dh->p([ $p ])
197
198 Given an argument I<$p>, sets the I<p> parameter (large prime) for
199 this I<Crypt::DH> object.
200
201 Returns the current value of I<p>.  (as a Math::BigInt object)
202
203 =head2 $dh->g([ $g ])
204
205 Given an argument I<$g>, sets the I<g> parameter (base) for
206 this I<Crypt::DH> object.
207
208 Returns the current value of I<g>.
209
210 =head2 $dh->generate_keys
211
212 Generates the public and private key portions of the I<Crypt::DH>
213 object, assuming that you've already filled I<p> and I<g> with
214 appropriate values.
215
216 If you've provided a priv_key, it's used, otherwise a random priv_key
217 is created using either Crypt::Random (if already loaded), or
218 /dev/urandom, or Perl's rand, in that order.
219
220 =head2 $dh->compute_secret( $public_key )
221
222 Given the public key I<$public_key> of Party B (the party with which
223 you're performing key negotiation and exchange), computes the shared
224 secret key, based on that public key, your own private key, and your
225 own large prime value (I<p>).
226
227 The historical method name "compute_key" is aliased to this for
228 compatibility.
229
230 =head2 $dh->priv_key([ $priv_key ])
231
232 Returns the private key.  Given an argument I<$priv_key>, sets the
233 I<priv_key> parameter for this I<Crypt::DH> object.
234
235 =head2 $dh->pub_key
236
237 Returns the public key.
238
239 =head1 AUTHOR & COPYRIGHT
240
241 Benjamin Trott, ben@rhumba.pair.com
242
243 Brad Fitzpatrick, brad@danga.com
244
245 Except where otherwise noted, Crypt::DH is Copyright 2001
246 Benjamin Trott. All rights reserved. Crypt::DH is free
247 software; you may redistribute it and/or modify it under
248 the same terms as Perl itself.
249
250 =cut
251
Note: See TracBrowser for help on using the browser.