diff options
Diffstat (limited to 'src/pk/dl_group/dl_group.cpp')
-rw-r--r-- | src/pk/dl_group/dl_group.cpp | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/src/pk/dl_group/dl_group.cpp b/src/pk/dl_group/dl_group.cpp new file mode 100644 index 000000000..b37bc238c --- /dev/null +++ b/src/pk/dl_group/dl_group.cpp @@ -0,0 +1,327 @@ +/************************************************* +* Discrete Logarithm Parameters Source File * +* (C) 1999-2008 Jack Lloyd * +*************************************************/ + +#include <botan/dl_group.h> +#include <botan/libstate.h> +#include <botan/parsing.h> +#include <botan/numthry.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/pipe.h> +#include <botan/util.h> +#include <botan/pem.h> + +namespace Botan { + +/************************************************* +* DL_Group Constructor * +*************************************************/ +DL_Group::DL_Group() + { + initialized = false; + } + +/************************************************* +* DL_Group Constructor * +*************************************************/ +DL_Group::DL_Group(const std::string& type) + { + std::string grp_contents = global_state().get("dl", type); + + if(grp_contents == "") + throw Invalid_Argument("DL_Group: Unknown group " + type); + + DataSource_Memory pem(grp_contents); + PEM_decode(pem); + } + +/************************************************* +* DL_Group Constructor * +*************************************************/ +DL_Group::DL_Group(RandomNumberGenerator& rng, + PrimeType type, u32bit pbits, u32bit qbits) + { + if(pbits < 512) + throw Invalid_Argument("DL_Group: prime size " + to_string(pbits) + + " is too small"); + + if(type == Strong) + { + p = random_safe_prime(rng, pbits); + q = (p - 1) / 2; + g = 2; + } + else if(type == Prime_Subgroup || type == DSA_Kosherizer) + { + if(type == Prime_Subgroup) + { + if(!qbits) + qbits = 2 * dl_work_factor(pbits); + + q = random_prime(rng, qbits); + BigInt X; + while(p.bits() != pbits || !is_prime(p, rng)) + { + X.randomize(rng, pbits); + p = X - (X % (2*q) - 1); + } + } + else + { + qbits = qbits ? qbits : ((pbits == 1024) ? 160 : 256); + generate_dsa_primes(rng, p, q, pbits, qbits); + } + + g = make_dsa_generator(p, q); + } + + initialized = true; + } + +/************************************************* +* DL_Group Constructor * +*************************************************/ +DL_Group::DL_Group(RandomNumberGenerator& rng, + const MemoryRegion<byte>& seed, u32bit pbits, u32bit qbits) + { + if(!generate_dsa_primes(rng, p, q, pbits, qbits, seed)) + throw Invalid_Argument("DL_Group: The seed given does not " + "generate a DSA group"); + + g = make_dsa_generator(p, q); + + initialized = true; + } + +/************************************************* +* DL_Group Constructor * +*************************************************/ +DL_Group::DL_Group(const BigInt& p1, const BigInt& g1) + { + initialize(p1, 0, g1); + } + +/************************************************* +* DL_Group Constructor * +*************************************************/ +DL_Group::DL_Group(const BigInt& p1, const BigInt& q1, const BigInt& g1) + { + initialize(p1, q1, g1); + } + +/************************************************* +* DL_Group Initializer * +*************************************************/ +void DL_Group::initialize(const BigInt& p1, const BigInt& q1, const BigInt& g1) + { + if(p1 < 3) + throw Invalid_Argument("DL_Group: Prime invalid"); + if(g1 < 2 || g1 >= p1) + throw Invalid_Argument("DL_Group: Generator invalid"); + if(q1 < 0 || q1 >= p1) + throw Invalid_Argument("DL_Group: Subgroup invalid"); + + p = p1; + g = g1; + q = q1; + + initialized = true; + } + +/************************************************* +* Verify that the group has been set * +*************************************************/ +void DL_Group::init_check() const + { + if(!initialized) + throw Invalid_State("DLP group cannot be used uninitialized"); + } + +/************************************************* +* Verify the parameters * +*************************************************/ +bool DL_Group::verify_group(RandomNumberGenerator& rng, + bool strong) const + { + init_check(); + + if(g < 2 || p < 3 || q < 0) + return false; + if((q != 0) && ((p - 1) % q != 0)) + return false; + + if(!strong) + return true; + + if(!check_prime(p, rng)) + return false; + if((q > 0) && !check_prime(q, rng)) + return false; + return true; + } + +/************************************************* +* Return the prime * +*************************************************/ +const BigInt& DL_Group::get_p() const + { + init_check(); + return p; + } + +/************************************************* +* Return the generator * +*************************************************/ +const BigInt& DL_Group::get_g() const + { + init_check(); + return g; + } + +/************************************************* +* Return the subgroup * +*************************************************/ +const BigInt& DL_Group::get_q() const + { + init_check(); + if(q == 0) + throw Format_Error("DLP group has no q prime specified"); + return q; + } + +/************************************************* +* DER encode the parameters * +*************************************************/ +SecureVector<byte> DL_Group::DER_encode(Format format) const + { + init_check(); + + if((q == 0) && (format != PKCS_3)) + throw Encoding_Error("The ANSI DL parameter formats require a subgroup"); + + if(format == ANSI_X9_57) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(p) + .encode(q) + .encode(g) + .end_cons() + .get_contents(); + } + else if(format == ANSI_X9_42) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(p) + .encode(g) + .encode(q) + .end_cons() + .get_contents(); + } + else if(format == PKCS_3) + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(p) + .encode(g) + .end_cons() + .get_contents(); + } + + throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format)); + } + +/************************************************* +* PEM encode the parameters * +*************************************************/ +std::string DL_Group::PEM_encode(Format format) const + { + SecureVector<byte> encoding = DER_encode(format); + if(format == PKCS_3) + return PEM_Code::encode(encoding, "DH PARAMETERS"); + else if(format == ANSI_X9_57) + return PEM_Code::encode(encoding, "DSA PARAMETERS"); + else if(format == ANSI_X9_42) + return PEM_Code::encode(encoding, "X942 DH PARAMETERS"); + else + throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format)); + } + +/************************************************* +* Decode BER encoded parameters * +*************************************************/ +void DL_Group::BER_decode(DataSource& source, Format format) + { + BigInt new_p, new_q, new_g; + + BER_Decoder decoder(source); + BER_Decoder ber = decoder.start_cons(SEQUENCE); + + if(format == ANSI_X9_57) + { + ber.decode(new_p) + .decode(new_q) + .decode(new_g) + .verify_end(); + } + else if(format == ANSI_X9_42) + { + ber.decode(new_p) + .decode(new_g) + .decode(new_q) + .discard_remaining(); + } + else if(format == PKCS_3) + { + ber.decode(new_p) + .decode(new_g) + .discard_remaining(); + } + else + throw Invalid_Argument("Unknown DL_Group encoding " + to_string(format)); + + initialize(new_p, new_q, new_g); + } + +/************************************************* +* Decode PEM encoded parameters * +*************************************************/ +void DL_Group::PEM_decode(DataSource& source) + { + std::string label; + DataSource_Memory ber(PEM_Code::decode(source, label)); + + if(label == "DH PARAMETERS") + BER_decode(ber, PKCS_3); + else if(label == "DSA PARAMETERS") + BER_decode(ber, ANSI_X9_57); + else if(label == "X942 DH PARAMETERS") + BER_decode(ber, ANSI_X9_42); + else + throw Decoding_Error("DL_Group: Invalid PEM label " + label); + } + +/************************************************* +* Create a random DSA-style generator * +*************************************************/ +BigInt DL_Group::make_dsa_generator(const BigInt& p, const BigInt& q) + { + BigInt g, e = (p - 1) / q; + + for(u32bit j = 0; j != PRIME_TABLE_SIZE; ++j) + { + g = power_mod(PRIMES[j], e, p); + if(g != 1) + break; + } + + if(g == 1) + throw Exception("DL_Group: Couldn't create a suitable generator"); + + return g; + } + +} |