# $Id: ElGamal.pm,v 1.8 2002/10/12 18:49:30 btrott Exp $ package Crypt::OpenPGP::Key::Public::ElGamal; use strict; use Crypt::OpenPGP::Util qw( bitsize); use Crypt::OpenPGP::Key::Public; use Crypt::OpenPGP::ErrorHandler; use base qw( Crypt::OpenPGP::Key::Public Crypt::OpenPGP::ErrorHandler ); sub can_encrypt { 1 } sub abbrev { 'g' } sub public_props { qw( p g y ) } sub crypt_props { qw( a b ) } sub sig_props { qw( a b ) } sub size { bitsize($_[0]->p) } sub init { my $key = shift; $key->{key_data} = shift || Crypt::OpenPGP::ElGamal::Public->new; $key; } sub keygen { return $_[0]->error("ElGamal key generation is not supported"); } sub encrypt { my $key = shift; my($M) = @_; $key->{key_data}->encrypt($M); } package Crypt::OpenPGP::ElGamal::Public; use strict; use Crypt::OpenPGP::Util qw( mod_exp ); use Math::Pari qw( Mod lift gcd ); sub new { bless {}, $_[0] } sub encrypt { my $key = shift; my($M) = @_; my $k = gen_k($key->p); my $a = mod_exp($key->g, $k, $key->p); my $b = mod_exp($key->y, $k, $key->p); $b = Mod($b, $key->p); $b = lift($b * $M); { a => $a, b => $b }; } sub gen_k { my($p) = @_; ## XXX choose bitsize based on bitsize of $p my $bits = 198; my $p_minus1 = $p - 1; require Crypt::Random; my $k = Crypt::Random::makerandom( Size => $bits, Strength => 0 ); while (1) { last if gcd($k, $p_minus1) == 1; $k++; } $k; } sub _getset { my $e = shift; sub { my $key = shift; $key->{$e} = shift if @_; $key->{$e}; } } *p = _getset('p'); *g = _getset('g'); *y = _getset('y'); 1;