Botan  1.11.15
src/lib/pubkey/dl_group/dl_group.cpp
Go to the documentation of this file.
00001 /*
00002 * Discrete Logarithm Parameters
00003 * (C) 1999-2008 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/dl_group.h>
00009 #include <botan/parsing.h>
00010 #include <botan/numthry.h>
00011 #include <botan/der_enc.h>
00012 #include <botan/ber_dec.h>
00013 #include <botan/pem.h>
00014 #include <botan/workfactor.h>
00015 
00016 namespace Botan {
00017 
00018 /*
00019 * DL_Group Constructor
00020 */
00021 DL_Group::DL_Group()
00022    {
00023    initialized = false;
00024    }
00025 
00026 /*
00027 * DL_Group Constructor
00028 */
00029 DL_Group::DL_Group(const std::string& name)
00030    {
00031    const char* pem = PEM_for_named_group(name);
00032 
00033    if(!pem)
00034       throw Invalid_Argument("DL_Group: Unknown group " + name);
00035 
00036    PEM_decode(pem);
00037    }
00038 
00039 /*
00040 * DL_Group Constructor
00041 */
00042 DL_Group::DL_Group(RandomNumberGenerator& rng,
00043                    PrimeType type, size_t pbits, size_t qbits)
00044    {
00045    if(pbits < 512)
00046       throw Invalid_Argument("DL_Group: prime size " + std::to_string(pbits) +
00047                              " is too small");
00048 
00049    if(type == Strong)
00050       {
00051       p = random_safe_prime(rng, pbits);
00052       q = (p - 1) / 2;
00053       g = 2;
00054       }
00055    else if(type == Prime_Subgroup)
00056       {
00057       if(!qbits)
00058          qbits = 2 * dl_work_factor(pbits);
00059 
00060       q = random_prime(rng, qbits);
00061       BigInt X;
00062       while(p.bits() != pbits || !is_prime(p, rng))
00063          {
00064          X.randomize(rng, pbits);
00065          p = X - (X % (2*q) - 1);
00066          }
00067 
00068       g = make_dsa_generator(p, q);
00069       }
00070    else if(type == DSA_Kosherizer)
00071       {
00072       qbits = qbits ? qbits : ((pbits <= 1024) ? 160 : 256);
00073 
00074       generate_dsa_primes(rng, p, q, pbits, qbits);
00075 
00076       g = make_dsa_generator(p, q);
00077       }
00078 
00079    initialized = true;
00080    }
00081 
00082 /*
00083 * DL_Group Constructor
00084 */
00085 DL_Group::DL_Group(RandomNumberGenerator& rng,
00086                    const std::vector<byte>& seed,
00087                    size_t pbits, size_t qbits)
00088    {
00089    if(!generate_dsa_primes(rng, p, q, pbits, qbits, seed))
00090       throw Invalid_Argument("DL_Group: The seed given does not "
00091                              "generate a DSA group");
00092 
00093    g = make_dsa_generator(p, q);
00094 
00095    initialized = true;
00096    }
00097 
00098 /*
00099 * DL_Group Constructor
00100 */
00101 DL_Group::DL_Group(const BigInt& p1, const BigInt& g1)
00102    {
00103    initialize(p1, 0, g1);
00104    }
00105 
00106 /*
00107 * DL_Group Constructor
00108 */
00109 DL_Group::DL_Group(const BigInt& p1, const BigInt& q1, const BigInt& g1)
00110    {
00111    initialize(p1, q1, g1);
00112    }
00113 
00114 /*
00115 * DL_Group Initializer
00116 */
00117 void DL_Group::initialize(const BigInt& p1, const BigInt& q1, const BigInt& g1)
00118    {
00119    if(p1 < 3)
00120       throw Invalid_Argument("DL_Group: Prime invalid");
00121    if(g1 < 2 || g1 >= p1)
00122       throw Invalid_Argument("DL_Group: Generator invalid");
00123    if(q1 < 0 || q1 >= p1)
00124       throw Invalid_Argument("DL_Group: Subgroup invalid");
00125 
00126    p = p1;
00127    g = g1;
00128    q = q1;
00129 
00130    initialized = true;
00131    }
00132 
00133 /*
00134 * Verify that the group has been set
00135 */
00136 void DL_Group::init_check() const
00137    {
00138    if(!initialized)
00139       throw Invalid_State("DLP group cannot be used uninitialized");
00140    }
00141 
00142 /*
00143 * Verify the parameters
00144 */
00145 bool DL_Group::verify_group(RandomNumberGenerator& rng,
00146                             bool strong) const
00147    {
00148    init_check();
00149 
00150    if(g < 2 || p < 3 || q < 0)
00151       return false;
00152    if((q != 0) && ((p - 1) % q != 0))
00153       return false;
00154 
00155    const size_t prob = (strong) ? 56 : 10;
00156 
00157    if(!is_prime(p, rng, prob))
00158       return false;
00159    if((q > 0) && !is_prime(q, rng, prob))
00160       return false;
00161    return true;
00162    }
00163 
00164 /*
00165 * Return the prime
00166 */
00167 const BigInt& DL_Group::get_p() const
00168    {
00169    init_check();
00170    return p;
00171    }
00172 
00173 /*
00174 * Return the generator
00175 */
00176 const BigInt& DL_Group::get_g() const
00177    {
00178    init_check();
00179    return g;
00180    }
00181 
00182 /*
00183 * Return the subgroup
00184 */
00185 const BigInt& DL_Group::get_q() const
00186    {
00187    init_check();
00188    if(q == 0)
00189       throw Invalid_State("DLP group has no q prime specified");
00190    return q;
00191    }
00192 
00193 /*
00194 * DER encode the parameters
00195 */
00196 std::vector<byte> DL_Group::DER_encode(Format format) const
00197    {
00198    init_check();
00199 
00200    if((q == 0) && (format != PKCS_3))
00201       throw Encoding_Error("The ANSI DL parameter formats require a subgroup");
00202 
00203    if(format == ANSI_X9_57)
00204       {
00205       return DER_Encoder()
00206          .start_cons(SEQUENCE)
00207             .encode(p)
00208             .encode(q)
00209             .encode(g)
00210          .end_cons()
00211       .get_contents_unlocked();
00212       }
00213    else if(format == ANSI_X9_42)
00214       {
00215       return DER_Encoder()
00216          .start_cons(SEQUENCE)
00217             .encode(p)
00218             .encode(g)
00219             .encode(q)
00220          .end_cons()
00221       .get_contents_unlocked();
00222       }
00223    else if(format == PKCS_3)
00224       {
00225       return DER_Encoder()
00226          .start_cons(SEQUENCE)
00227             .encode(p)
00228             .encode(g)
00229          .end_cons()
00230       .get_contents_unlocked();
00231       }
00232 
00233    throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format));
00234    }
00235 
00236 /*
00237 * PEM encode the parameters
00238 */
00239 std::string DL_Group::PEM_encode(Format format) const
00240    {
00241    const std::vector<byte> encoding = DER_encode(format);
00242 
00243    if(format == PKCS_3)
00244       return PEM_Code::encode(encoding, "DH PARAMETERS");
00245    else if(format == ANSI_X9_57)
00246       return PEM_Code::encode(encoding, "DSA PARAMETERS");
00247    else if(format == ANSI_X9_42)
00248       return PEM_Code::encode(encoding, "X942 DH PARAMETERS");
00249    else
00250       throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format));
00251    }
00252 
00253 /*
00254 * Decode BER encoded parameters
00255 */
00256 void DL_Group::BER_decode(const std::vector<byte>& data,
00257                           Format format)
00258    {
00259    BigInt new_p, new_q, new_g;
00260 
00261    BER_Decoder decoder(data);
00262    BER_Decoder ber = decoder.start_cons(SEQUENCE);
00263 
00264    if(format == ANSI_X9_57)
00265       {
00266       ber.decode(new_p)
00267          .decode(new_q)
00268          .decode(new_g)
00269          .verify_end();
00270       }
00271    else if(format == ANSI_X9_42)
00272       {
00273       ber.decode(new_p)
00274          .decode(new_g)
00275          .decode(new_q)
00276          .discard_remaining();
00277       }
00278    else if(format == PKCS_3)
00279       {
00280       ber.decode(new_p)
00281          .decode(new_g)
00282          .discard_remaining();
00283       }
00284    else
00285       throw Invalid_Argument("Unknown DL_Group encoding " + std::to_string(format));
00286 
00287    initialize(new_p, new_q, new_g);
00288    }
00289 
00290 /*
00291 * Decode PEM encoded parameters
00292 */
00293 void DL_Group::PEM_decode(const std::string& pem)
00294    {
00295    std::string label;
00296 
00297    auto ber = unlock(PEM_Code::decode(pem, label));
00298 
00299    if(label == "DH PARAMETERS")
00300       BER_decode(ber, PKCS_3);
00301    else if(label == "DSA PARAMETERS")
00302       BER_decode(ber, ANSI_X9_57);
00303    else if(label == "X942 DH PARAMETERS")
00304       BER_decode(ber, ANSI_X9_42);
00305    else
00306       throw Decoding_Error("DL_Group: Invalid PEM label " + label);
00307    }
00308 
00309 /*
00310 * Create generator of the q-sized subgroup (DSA style generator)
00311 */
00312 BigInt DL_Group::make_dsa_generator(const BigInt& p, const BigInt& q)
00313    {
00314    const BigInt e = (p - 1) / q;
00315 
00316    if(e == 0 || (p - 1) % q > 0)
00317       throw std::invalid_argument("make_dsa_generator q does not divide p-1");
00318 
00319    for(size_t i = 0; i != PRIME_TABLE_SIZE; ++i)
00320       {
00321       BigInt g = power_mod(PRIMES[i], e, p);
00322       if(g > 1)
00323          return g;
00324       }
00325 
00326    throw Internal_Error("DL_Group: Couldn't create a suitable generator");
00327    }
00328 
00329 }