summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl.straw/lib/Crypt/OpenPGP/Key/Public/ElGamal.pm
blob: a6f589c0f8291625ffa12321f246f9b84fc3ae5a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
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;