Botan  1.11.15
src/lib/pubkey/elgamal/elgamal.cpp
Go to the documentation of this file.
00001 /*
00002 * ElGamal
00003 * (C) 1999-2007 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/internal/pk_utils.h>
00009 #include <botan/elgamal.h>
00010 #include <botan/keypair.h>
00011 #include <botan/reducer.h>
00012 #include <botan/blinding.h>
00013 #include <botan/workfactor.h>
00014 
00015 namespace Botan {
00016 
00017 /*
00018 * ElGamal_PublicKey Constructor
00019 */
00020 ElGamal_PublicKey::ElGamal_PublicKey(const DL_Group& grp, const BigInt& y1)
00021    {
00022    group = grp;
00023    y = y1;
00024    }
00025 
00026 /*
00027 * ElGamal_PrivateKey Constructor
00028 */
00029 ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng,
00030                                        const DL_Group& grp,
00031                                        const BigInt& x_arg)
00032    {
00033    group = grp;
00034    x = x_arg;
00035 
00036    if(x == 0)
00037       x.randomize(rng, 2 * dl_work_factor(group_p().bits()));
00038 
00039    y = power_mod(group_g(), x, group_p());
00040 
00041    if(x_arg == 0)
00042       gen_check(rng);
00043    else
00044       load_check(rng);
00045    }
00046 
00047 ElGamal_PrivateKey::ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id,
00048                                        const secure_vector<byte>& key_bits,
00049                                        RandomNumberGenerator& rng) :
00050    DL_Scheme_PrivateKey(alg_id, key_bits, DL_Group::ANSI_X9_42)
00051    {
00052    y = power_mod(group_g(), x, group_p());
00053    load_check(rng);
00054    }
00055 
00056 /*
00057 * Check Private ElGamal Parameters
00058 */
00059 bool ElGamal_PrivateKey::check_key(RandomNumberGenerator& rng,
00060                                    bool strong) const
00061    {
00062    if(!DL_Scheme_PrivateKey::check_key(rng, strong))
00063       return false;
00064 
00065    if(!strong)
00066       return true;
00067 
00068    return KeyPair::encryption_consistency_check(rng, *this, "EME1(SHA-1)");
00069    }
00070 
00071 namespace {
00072 
00073 /**
00074 * ElGamal encryption operation
00075 */
00076 class ElGamal_Encryption_Operation : public PK_Ops::Encryption
00077    {
00078    public:
00079       typedef ElGamal_PublicKey Key_Type;
00080 
00081       size_t max_input_bits() const { return mod_p.get_modulus().bits() - 1; }
00082 
00083       ElGamal_Encryption_Operation(const ElGamal_PublicKey& key, const std::string&);
00084 
00085       secure_vector<byte> encrypt(const byte msg[], size_t msg_len,
00086                                  RandomNumberGenerator& rng);
00087 
00088    private:
00089       Fixed_Base_Power_Mod powermod_g_p, powermod_y_p;
00090       Modular_Reducer mod_p;
00091    };
00092 
00093 ElGamal_Encryption_Operation::ElGamal_Encryption_Operation(const ElGamal_PublicKey& key,
00094                                                            const std::string&)
00095    {
00096    const BigInt& p = key.group_p();
00097 
00098    powermod_g_p = Fixed_Base_Power_Mod(key.group_g(), p);
00099    powermod_y_p = Fixed_Base_Power_Mod(key.get_y(), p);
00100    mod_p = Modular_Reducer(p);
00101    }
00102 
00103 secure_vector<byte>
00104 ElGamal_Encryption_Operation::encrypt(const byte msg[], size_t msg_len,
00105                                       RandomNumberGenerator& rng)
00106    {
00107    const BigInt& p = mod_p.get_modulus();
00108 
00109    BigInt m(msg, msg_len);
00110 
00111    if(m >= p)
00112       throw Invalid_Argument("ElGamal encryption: Input is too large");
00113 
00114    BigInt k(rng, 2 * dl_work_factor(p.bits()));
00115 
00116    BigInt a = powermod_g_p(k);
00117    BigInt b = mod_p.multiply(m, powermod_y_p(k));
00118 
00119    secure_vector<byte> output(2*p.bytes());
00120    a.binary_encode(&output[p.bytes() - a.bytes()]);
00121    b.binary_encode(&output[output.size() / 2 + (p.bytes() - b.bytes())]);
00122    return output;
00123    }
00124 
00125 /**
00126 * ElGamal decryption operation
00127 */
00128 class ElGamal_Decryption_Operation : public PK_Ops::Decryption
00129    {
00130    public:
00131       typedef ElGamal_PrivateKey Key_Type;
00132 
00133       size_t max_input_bits() const { return mod_p.get_modulus().bits() - 1; }
00134 
00135       ElGamal_Decryption_Operation(const ElGamal_PrivateKey& key, const std::string& emsa);
00136 
00137       secure_vector<byte> decrypt(const byte msg[], size_t msg_len);
00138    private:
00139       Fixed_Exponent_Power_Mod powermod_x_p;
00140       Modular_Reducer mod_p;
00141       Blinder blinder;
00142    };
00143 
00144 ElGamal_Decryption_Operation::ElGamal_Decryption_Operation(const ElGamal_PrivateKey& key,
00145                                                            const std::string&)
00146    {
00147    const BigInt& p = key.group_p();
00148 
00149    powermod_x_p = Fixed_Exponent_Power_Mod(key.get_x(), p);
00150    mod_p = Modular_Reducer(p);
00151 
00152    blinder = Blinder(p,
00153                      [](const BigInt& k) { return k; },
00154                      [this](const BigInt& k) { return powermod_x_p(k); });
00155    }
00156 
00157 secure_vector<byte>
00158 ElGamal_Decryption_Operation::decrypt(const byte msg[], size_t msg_len)
00159    {
00160    const BigInt& p = mod_p.get_modulus();
00161 
00162    const size_t p_bytes = p.bytes();
00163 
00164    if(msg_len != 2 * p_bytes)
00165       throw Invalid_Argument("ElGamal decryption: Invalid message");
00166 
00167    BigInt a(msg, p_bytes);
00168    BigInt b(msg + p_bytes, p_bytes);
00169 
00170    if(a >= p || b >= p)
00171       throw Invalid_Argument("ElGamal decryption: Invalid message");
00172 
00173    a = blinder.blind(a);
00174 
00175    BigInt r = mod_p.multiply(b, inverse_mod(powermod_x_p(a), p));
00176 
00177    return BigInt::encode_locked(blinder.unblind(r));
00178    }
00179 
00180 BOTAN_REGISTER_PK_ENCRYPTION_OP("ElGamal", ElGamal_Encryption_Operation);
00181 BOTAN_REGISTER_PK_DECRYPTION_OP("ElGamal", ElGamal_Decryption_Operation);
00182 
00183 }
00184 
00185 }