diff options
Diffstat (limited to 'Master/tlpkg/tlperl0/lib/Crypt/DH.pm')
-rwxr-xr-x | Master/tlpkg/tlperl0/lib/Crypt/DH.pm | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/Master/tlpkg/tlperl0/lib/Crypt/DH.pm b/Master/tlpkg/tlperl0/lib/Crypt/DH.pm new file mode 100755 index 00000000000..b9f3ecf0d80 --- /dev/null +++ b/Master/tlpkg/tlperl0/lib/Crypt/DH.pm @@ -0,0 +1,250 @@ +# $Id: DH.pm 1860 2005-06-11 06:15:44Z btrott $ + +package Crypt::DH; +use strict; + +use Math::BigInt lib => "GMP,Pari"; +our $VERSION = '0.06'; + +sub new { + my $class = shift; + my $dh = bless {}, $class; + + my %param = @_; + for my $w (qw( p g priv_key )) { + next unless exists $param{$w}; + $dh->$w(delete $param{$w}); + } + die "Unknown parameters to constructor: " . join(", ", keys %param) if %param; + + $dh; +} + +BEGIN { + no strict 'refs'; + for my $meth (qw( p g pub_key priv_key )) { + *$meth = sub { + my $key = shift; + if (@_) { + $key->{$meth} = _any2bigint(shift); + } + my $ret = $key->{$meth} || ""; + $ret; + }; + } +} + +sub _any2bigint { + my($value) = @_; + if (ref $value eq 'Math::BigInt') { + return $value; + } + elsif (ref $value eq 'Math::Pari') { + return Math::BigInt->new(Math::Pari::pari2pv($value)); + } + elsif (defined $value && !(ref $value)) { + return Math::BigInt->new($value); + } + elsif (defined $value) { + die "Unknown parameter type: $value\n"; + } +} + +sub generate_keys { + my $dh = shift; + + unless (defined $dh->{priv_key}) { + my $i = _bitsize($dh->{p}) - 1; + $dh->{priv_key} = + $Crypt::Random::VERSION ? + Crypt::Random::makerandom_itv(Strength => 0, Uniform => 1, + Lower => 1, Upper => $dh->{p} - 1) : + _makerandom_itv($i, 1, $dh->{p} - 1); + } + + $dh->{pub_key} = $dh->{g}->copy->bmodpow($dh->{priv_key}, $dh->{p}); +} + +sub compute_key { + my $dh = shift; + my $pub_key = _any2bigint(shift); + $pub_key->copy->bmodpow($dh->{priv_key}, $dh->{p}); +} +*compute_secret = \&compute_key; + +sub _bitsize { + return length($_[0]->as_bin) - 2; +} + +sub _makerandom_itv { + my ($size, $min_inc, $max_exc) = @_; + + while (1) { + my $r = _makerandom($size); + return $r if $r >= $min_inc && $r < $max_exc; + } +} + +sub _makerandom { + my $size = shift; + + my $bytes = int($size / 8) + ($size % 8 ? 1 : 0); + + my $rand; + if (-e "/dev/urandom") { + my $fh; + open($fh, '/dev/urandom') + or die "Couldn't open /dev/urandom"; + my $got = sysread $fh, $rand, $bytes; + die "Didn't read all bytes from urandom" unless $got == $bytes; + close $fh; + } else { + for (1..$bytes) { + $rand .= chr(int(rand(256))); + } + } + + my $bits = unpack("b*", $rand); + die unless length($bits) >= $size; + + Math::BigInt->new('0b' . substr($bits, 0, $size)); +} + +1; +__END__ + +=head1 NAME + +Crypt::DH - Diffie-Hellman key exchange system + +=head1 SYNOPSIS + + use Crypt::DH; + my $dh = Crypt::DH->new; + $dh->g($g); + $dh->p($p); + + ## Generate public and private keys. + $dh->generate_keys; + + $my_pub_key = $dh->pub_key; + + ## Send $my_pub_key to "other" party, and receive "other" + ## public key in return. + + ## Now compute shared secret from "other" public key. + my $shared_secret = $dh->compute_secret( $other_pub_key ); + +=head1 DESCRIPTION + +I<Crypt::DH> is a Perl implementation of the Diffie-Hellman key +exchange system. Diffie-Hellman is an algorithm by which two +parties can agree on a shared secret key, known only to them. +The secret is negotiated over an insecure network without the +two parties ever passing the actual shared secret, or their +private keys, between them. + +=head1 THE ALGORITHM + +The algorithm generally works as follows: Party A and Party B +choose a property I<p> and a property I<g>; these properties are +shared by both parties. Each party then computes a random private +key integer I<priv_key>, where the length of I<priv_key> is at +most (number of bits in I<p>) - 1. Each party then computes a +public key based on I<g>, I<priv_key>, and I<p>; the exact value +is + + g ^ priv_key mod p + +The parties exchange these public keys. + +The shared secret key is generated based on the exchanged public +key, the private key, and I<p>. If the public key of Party B is +denoted I<pub_key_B>, then the shared secret is equal to + + pub_key_B ^ priv_key mod p + +The mathematical principles involved insure that both parties will +generate the same shared secret key. + +More information can be found in PKCS #3 (Diffie-Hellman Key +Agreement Standard): + + http://www.rsasecurity.com/rsalabs/pkcs/pkcs-3/ + +=head1 USAGE + +I<Crypt::DH> implements the core routines needed to use +Diffie-Hellman key exchange. To actually use the algorithm, +you'll need to start with values for I<p> and I<g>; I<p> is a +large prime, and I<g> is a base which must be larger than 0 +and less than I<p>. + +I<Crypt::DH> uses I<Math::BigInt> internally for big-integer +calculations. All accessor methods (I<p>, I<g>, I<priv_key>, and +I<pub_key>) thus return I<Math::BigInt> objects, as does the +I<compute_secret> method. The accessors, however, allow setting with a +scalar decimal string, hex string (^0x), Math::BigInt object, or +Math::Pari object (for backwards compatibility). + +=head2 $dh = Crypt::DH->new([ %param ]). + +Constructs a new I<Crypt::DH> object and returns the object. +I<%param> may include none, some, or all of the keys I<p>, I<g>, and +I<priv_key>. + +=head2 $dh->p([ $p ]) + +Given an argument I<$p>, sets the I<p> parameter (large prime) for +this I<Crypt::DH> object. + +Returns the current value of I<p>. (as a Math::BigInt object) + +=head2 $dh->g([ $g ]) + +Given an argument I<$g>, sets the I<g> parameter (base) for +this I<Crypt::DH> object. + +Returns the current value of I<g>. + +=head2 $dh->generate_keys + +Generates the public and private key portions of the I<Crypt::DH> +object, assuming that you've already filled I<p> and I<g> with +appropriate values. + +If you've provided a priv_key, it's used, otherwise a random priv_key +is created using either Crypt::Random (if already loaded), or +/dev/urandom, or Perl's rand, in that order. + +=head2 $dh->compute_secret( $public_key ) + +Given the public key I<$public_key> of Party B (the party with which +you're performing key negotiation and exchange), computes the shared +secret key, based on that public key, your own private key, and your +own large prime value (I<p>). + +The historical method name "compute_key" is aliased to this for +compatibility. + +=head2 $dh->priv_key([ $priv_key ]) + +Returns the private key. Given an argument I<$priv_key>, sets the +I<priv_key> parameter for this I<Crypt::DH> object. + +=head2 $dh->pub_key + +Returns the public key. + +=head1 AUTHOR & COPYRIGHT + +Benjamin Trott, ben@rhumba.pair.com + +Brad Fitzpatrick, brad@danga.com + +Except where otherwise noted, Crypt::DH is Copyright 2001 +Benjamin Trott. All rights reserved. Crypt::DH is free +software; you may redistribute it and/or modify it under +the same terms as Perl itself. + +=cut |