diff options
Diffstat (limited to 'botan/src/pubkey')
88 files changed, 8590 insertions, 0 deletions
diff --git a/botan/src/pubkey/dh/dh.cpp b/botan/src/pubkey/dh/dh.cpp new file mode 100644 index 0000000..0c9d02f --- /dev/null +++ b/botan/src/pubkey/dh/dh.cpp @@ -0,0 +1,119 @@ +/* +* Diffie-Hellman +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/dh.h> +#include <botan/numthry.h> +#include <botan/util.h> + +namespace Botan { + +/* +* DH_PublicKey Constructor +*/ +DH_PublicKey::DH_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + X509_load_hook(); + } + +/* +* Algorithm Specific X.509 Initialization Code +*/ +void DH_PublicKey::X509_load_hook() + { + } + +/* +* Return the maximum input size in bits +*/ +u32bit DH_PublicKey::max_input_bits() const + { + return group_p().bits(); + } + +/* +* Return the public value for key agreement +*/ +MemoryVector<byte> DH_PublicKey::public_value() const + { + return BigInt::encode_1363(y, group_p().bytes()); + } + +/* +* Create a DH private key +*/ +DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + { + const BigInt& p = group_p(); + x.randomize(rng, 2 * dl_work_factor(p.bits())); + PKCS8_load_hook(rng, true); + } + else + PKCS8_load_hook(rng, false); + } + +/* +* Algorithm Specific PKCS #8 Initialization Code +*/ +void DH_PrivateKey::PKCS8_load_hook(RandomNumberGenerator& rng, + bool generated) + { + if(y == 0) + y = power_mod(group_g(), x, group_p()); + core = DH_Core(rng, group, x); + + if(generated) + gen_check(rng); + else + load_check(rng); + } + +/* +* Return the public value for key agreement +*/ +MemoryVector<byte> DH_PrivateKey::public_value() const + { + return DH_PublicKey::public_value(); + } + +/* +* Derive a key +*/ +SecureVector<byte> DH_PrivateKey::derive_key(const byte w[], + u32bit w_len) const + { + return derive_key(BigInt::decode(w, w_len)); + } + +/* +* Derive a key +*/ +SecureVector<byte> DH_PrivateKey::derive_key(const DH_PublicKey& key) const + { + return derive_key(key.get_y()); + } + +/* +* Derive a key +*/ +SecureVector<byte> DH_PrivateKey::derive_key(const BigInt& w) const + { + const BigInt& p = group_p(); + if(w <= 1 || w >= p-1) + throw Invalid_Argument(algo_name() + "::derive_key: Invalid key input"); + return BigInt::encode_1363(core.agree(w), p.bytes()); + } + +} diff --git a/botan/src/pubkey/dh/dh.h b/botan/src/pubkey/dh/dh.h new file mode 100644 index 0000000..fa558bc --- /dev/null +++ b/botan/src/pubkey/dh/dh.h @@ -0,0 +1,80 @@ +/* +* Diffie-Hellman +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DIFFIE_HELLMAN_H__ +#define BOTAN_DIFFIE_HELLMAN_H__ + +#include <botan/dl_algo.h> +#include <botan/dh_core.h> + +namespace Botan { + +/** +* This class represents Diffie-Hellman public keys. +*/ +class BOTAN_DLL DH_PublicKey : public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "DH"; } + + MemoryVector<byte> public_value() const; + u32bit max_input_bits() const; + + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_42; } + + /** + * Construct an uninitialized key. Use this constructor if you wish + * to decode an encoded key into the new instance. + */ + DH_PublicKey() {} + + /** + * Construct a public key with the specified parameters. + * @param grp the DL group to use in the key + * @param y the public value y + */ + DH_PublicKey(const DL_Group& grp, const BigInt& y); + private: + void X509_load_hook(); + }; + +/** +* This class represents Diffie-Hellman private keys. +*/ +class BOTAN_DLL DH_PrivateKey : public DH_PublicKey, + public PK_Key_Agreement_Key, + public virtual DL_Scheme_PrivateKey + { + public: + SecureVector<byte> derive_key(const byte other[], u32bit length) const; + SecureVector<byte> derive_key(const DH_PublicKey& other) const; + SecureVector<byte> derive_key(const BigInt& other) const; + + MemoryVector<byte> public_value() const; + + /** + * Construct an uninitialized key. Use this constructor if you wish + * to decode an encoded key into the new instance. + */ + DH_PrivateKey() {} + + /** + * Construct a private key with predetermined value. + * @param rng random number generator to use + * @param grp the group to be used in the key + * @param x the key's secret value (or if zero, generate a new key) + */ + DH_PrivateKey(RandomNumberGenerator& rng, const DL_Group& grp, + const BigInt& x = 0); + private: + void PKCS8_load_hook(RandomNumberGenerator& rng, bool = false); + DH_Core core; + }; + +} + +#endif diff --git a/botan/src/pubkey/dh/dh_core.cpp b/botan/src/pubkey/dh/dh_core.cpp new file mode 100644 index 0000000..78a26a8 --- /dev/null +++ b/botan/src/pubkey/dh/dh_core.cpp @@ -0,0 +1,69 @@ +/* +* PK Algorithm Core +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/dh_core.h> +#include <botan/numthry.h> +#include <botan/pk_engine.h> +#include <botan/parsing.h> +#include <algorithm> + +namespace Botan { + +namespace { + +const u32bit BLINDING_BITS = BOTAN_PRIVATE_KEY_OP_BLINDING_BITS; + +} + +/* +* DH_Core Constructor +*/ +DH_Core::DH_Core(RandomNumberGenerator& rng, + const DL_Group& group, const BigInt& x) + { + op = Engine_Core::dh_op(group, x); + + const BigInt& p = group.get_p(); + + BigInt k(rng, std::min(p.bits()-1, BLINDING_BITS)); + + if(k != 0) + blinder = Blinder(k, power_mod(inverse_mod(k, p), x, p), p); + } + +/* +* DH_Core Copy Constructor +*/ +DH_Core::DH_Core(const DH_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + } + +/* +* DH_Core Assignment Operator +*/ +DH_Core& DH_Core::operator=(const DH_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + return (*this); + } + +/* +* DH Operation +*/ +BigInt DH_Core::agree(const BigInt& i) const + { + return blinder.unblind(op->agree(blinder.blind(i))); + } + +} diff --git a/botan/src/pubkey/dh/dh_core.h b/botan/src/pubkey/dh/dh_core.h new file mode 100644 index 0000000..91b50a2 --- /dev/null +++ b/botan/src/pubkey/dh/dh_core.h @@ -0,0 +1,38 @@ +/* +* DH Core +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DH_CORE_H__ +#define BOTAN_DH_CORE_H__ + +#include <botan/dh_op.h> +#include <botan/blinding.h> + +namespace Botan { + +/* +* DH Core +*/ +class BOTAN_DLL DH_Core + { + public: + BigInt agree(const BigInt&) const; + + DH_Core& operator=(const DH_Core&); + + DH_Core() { op = 0; } + DH_Core(const DH_Core&); + DH_Core(RandomNumberGenerator& rng, + const DL_Group&, const BigInt&); + ~DH_Core() { delete op; } + private: + DH_Operation* op; + Blinder blinder; + }; + +} + +#endif diff --git a/botan/src/pubkey/dh/dh_op.h b/botan/src/pubkey/dh/dh_op.h new file mode 100644 index 0000000..50f3d78 --- /dev/null +++ b/botan/src/pubkey/dh/dh_op.h @@ -0,0 +1,45 @@ +/* +* DH Operations +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DH_OPS_H__ +#define BOTAN_DH_OPS_H__ + +#include <botan/dl_group.h> +#include <botan/reducer.h> +#include <botan/pow_mod.h> + +namespace Botan { + +/* +* DH Operation Interface +*/ +class BOTAN_DLL DH_Operation + { + public: + virtual BigInt agree(const BigInt&) const = 0; + virtual DH_Operation* clone() const = 0; + virtual ~DH_Operation() {} + }; + +/* +* Botan's Default DH Operation +*/ +class BOTAN_DLL Default_DH_Op : public DH_Operation + { + public: + BigInt agree(const BigInt& i) const { return powermod_x_p(i); } + DH_Operation* clone() const { return new Default_DH_Op(*this); } + + Default_DH_Op(const DL_Group& group, const BigInt& x) : + powermod_x_p(x, group.get_p()) {} + private: + Fixed_Exponent_Power_Mod powermod_x_p; + }; + +} + +#endif diff --git a/botan/src/pubkey/dh/info.txt b/botan/src/pubkey/dh/info.txt new file mode 100644 index 0000000..33af9a8 --- /dev/null +++ b/botan/src/pubkey/dh/info.txt @@ -0,0 +1,20 @@ +realname "Diffie-Hellman Key Agreement" + +define DIFFIE_HELLMAN + +load_on auto + +<add> +dh.cpp +dh.h +dh_core.cpp +dh_core.h +dh_op.h +</add> + +<requires> +dl_algo +dl_group +libstate +numbertheory +</requires> diff --git a/botan/src/pubkey/dl_algo/dl_algo.cpp b/botan/src/pubkey/dl_algo/dl_algo.cpp new file mode 100644 index 0000000..8ce3446 --- /dev/null +++ b/botan/src/pubkey/dl_algo/dl_algo.cpp @@ -0,0 +1,167 @@ +/* +* DL Scheme +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/dl_algo.h> +#include <botan/numthry.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> + +namespace Botan { + +/* +* Return the X.509 public key encoder +*/ +X509_Encoder* DL_Scheme_PublicKey::x509_encoder() const + { + class DL_Scheme_Encoder : public X509_Encoder + { + public: + AlgorithmIdentifier alg_id() const + { + MemoryVector<byte> group = + key->group.DER_encode(key->group_format()); + + return AlgorithmIdentifier(key->get_oid(), group); + } + + MemoryVector<byte> key_bits() const + { + return DER_Encoder().encode(key->y).get_contents(); + } + + DL_Scheme_Encoder(const DL_Scheme_PublicKey* k) : key(k) {} + private: + const DL_Scheme_PublicKey* key; + }; + + return new DL_Scheme_Encoder(this); + } + +/* +* Return the X.509 public key decoder +*/ +X509_Decoder* DL_Scheme_PublicKey::x509_decoder() + { + class DL_Scheme_Decoder : public X509_Decoder + { + public: + void alg_id(const AlgorithmIdentifier& alg_id) + { + DataSource_Memory source(alg_id.parameters); + key->group.BER_decode(source, key->group_format()); + } + + void key_bits(const MemoryRegion<byte>& bits) + { + BER_Decoder(bits).decode(key->y); + key->X509_load_hook(); + } + + DL_Scheme_Decoder(DL_Scheme_PublicKey* k) : key(k) {} + private: + DL_Scheme_PublicKey* key; + }; + + return new DL_Scheme_Decoder(this); + } + +/* +* Return the PKCS #8 private key encoder +*/ +PKCS8_Encoder* DL_Scheme_PrivateKey::pkcs8_encoder() const + { + class DL_Scheme_Encoder : public PKCS8_Encoder + { + public: + AlgorithmIdentifier alg_id() const + { + MemoryVector<byte> group = + key->group.DER_encode(key->group_format()); + + return AlgorithmIdentifier(key->get_oid(), group); + } + + MemoryVector<byte> key_bits() const + { + return DER_Encoder().encode(key->x).get_contents(); + } + + DL_Scheme_Encoder(const DL_Scheme_PrivateKey* k) : key(k) {} + private: + const DL_Scheme_PrivateKey* key; + }; + + return new DL_Scheme_Encoder(this); + } + +/* +* Return the PKCS #8 private key decoder +*/ +PKCS8_Decoder* DL_Scheme_PrivateKey::pkcs8_decoder(RandomNumberGenerator& rng) + { + class DL_Scheme_Decoder : public PKCS8_Decoder + { + public: + void alg_id(const AlgorithmIdentifier& alg_id) + { + DataSource_Memory source(alg_id.parameters); + key->group.BER_decode(source, key->group_format()); + } + + void key_bits(const MemoryRegion<byte>& bits) + { + BER_Decoder(bits).decode(key->x); + key->PKCS8_load_hook(rng); + } + + DL_Scheme_Decoder(DL_Scheme_PrivateKey* k, RandomNumberGenerator& r) : + key(k), rng(r) {} + private: + DL_Scheme_PrivateKey* key; + RandomNumberGenerator& rng; + }; + + return new DL_Scheme_Decoder(this, rng); + } + +/* +* Check Public DL Parameters +*/ +bool DL_Scheme_PublicKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(y < 2 || y >= group_p()) + return false; + if(!group.verify_group(rng, strong)) + return false; + return true; + } + +/* +* Check DL Scheme Private Parameters +*/ +bool DL_Scheme_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + const BigInt& p = group_p(); + const BigInt& g = group_g(); + + if(y < 2 || y >= p || x < 2 || x >= p) + return false; + if(!group.verify_group(rng, strong)) + return false; + + if(!strong) + return true; + + if(y != power_mod(g, x, p)) + return false; + + return true; + } + +} diff --git a/botan/src/pubkey/dl_algo/dl_algo.h b/botan/src/pubkey/dl_algo/dl_algo.h new file mode 100644 index 0000000..256ce96 --- /dev/null +++ b/botan/src/pubkey/dl_algo/dl_algo.h @@ -0,0 +1,116 @@ +/* +* DL Scheme +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DL_ALGO_H__ +#define BOTAN_DL_ALGO_H__ + +#include <botan/dl_group.h> +#include <botan/x509_key.h> +#include <botan/pkcs8.h> +#include <botan/rng.h> + +namespace Botan { + +/** +* This class represents discrete logarithm (DL) public keys. +*/ +class BOTAN_DLL DL_Scheme_PublicKey : public virtual Public_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + /** + * Get the DL domain parameters of this key. + * @return the DL domain parameters of this key + */ + const DL_Group& get_domain() const { return group; } + + /** + * Get the public value y with y = g^x mod p where x is the secret key. + */ + const BigInt& get_y() const { return y; } + + /** + * Get the prime p of the underlying DL group. + * @return the prime p + */ + const BigInt& group_p() const { return group.get_p(); } + + /** + * Get the prime q of the underlying DL group. + * @return the prime q + */ + const BigInt& group_q() const { return group.get_q(); } + + /** + * Get the generator g of the underlying DL group. + * @return the generator g + */ + const BigInt& group_g() const { return group.get_g(); } + + /** + * Get the underlying groups encoding format. + * @return the encoding format + */ + virtual DL_Group::Format group_format() const = 0; + + /** + * Get an X509 encoder for this key. + * @return an encoder usable to encode this key. + */ + X509_Encoder* x509_encoder() const; + + /** + * Get an X509 decoder for this key. + * @return an decoder usable to decode a DL key and store the + * values in this instance. + */ + X509_Decoder* x509_decoder(); + protected: + BigInt y; + DL_Group group; + private: + virtual void X509_load_hook() {} + }; + +/** +* This class represents discrete logarithm (DL) private keys. +*/ +class BOTAN_DLL DL_Scheme_PrivateKey : public virtual DL_Scheme_PublicKey, + public virtual Private_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + /** + * Get the secret key x. + * @return the secret key + */ + const BigInt& get_x() const { return x; } + + /** + * Get an PKCS#8 encoder for this key. + * @return an encoder usable to encode this key. + */ + PKCS8_Encoder* pkcs8_encoder() const; + + /** + * Get an PKCS#8 decoder for this key. + * @param rng the rng to use + * @return an decoder usable to decode a DL key and store the + * values in this instance. + */ + PKCS8_Decoder* pkcs8_decoder(RandomNumberGenerator& rng); + protected: + BigInt x; + private: + virtual void PKCS8_load_hook(RandomNumberGenerator&, bool = false) {} + }; + +} + +#endif diff --git a/botan/src/pubkey/dl_algo/info.txt b/botan/src/pubkey/dl_algo/info.txt new file mode 100644 index 0000000..15a7751 --- /dev/null +++ b/botan/src/pubkey/dl_algo/info.txt @@ -0,0 +1,18 @@ +realname "Discrete Logarithm PK Algorithms" + +define DL_PUBLIC_KEY_FAMILY + +load_on auto + +<add> +dl_algo.cpp +dl_algo.h +</add> + +<requires> +asn1 +dl_group +numbertheory +pk_codecs +rng +</requires> diff --git a/botan/src/pubkey/dl_group/dl_group.cpp b/botan/src/pubkey/dl_group/dl_group.cpp new file mode 100644 index 0000000..81c5d5e --- /dev/null +++ b/botan/src/pubkey/dl_group/dl_group.cpp @@ -0,0 +1,333 @@ +/* +* Discrete Logarithm Parameters +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#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, + global_state().algorithm_factory(), + 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, + global_state().algorithm_factory(), + 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; + } + +} diff --git a/botan/src/pubkey/dl_group/dl_group.h b/botan/src/pubkey/dl_group/dl_group.h new file mode 100644 index 0000000..a84a85f --- /dev/null +++ b/botan/src/pubkey/dl_group/dl_group.h @@ -0,0 +1,162 @@ +/* +* Discrete Logarithm Group +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DL_PARAM_H__ +#define BOTAN_DL_PARAM_H__ + +#include <botan/bigint.h> +#include <botan/data_src.h> + +namespace Botan { + +/** +* This class represents discrete logarithm groups. It holds a prime p, +* a prime q = (p-1)/2 and g = x^((p-1)/q) mod p. +*/ +class BOTAN_DLL DL_Group + { + public: + /** + * Get the prime p. + * @return the prime p + */ + const BigInt& get_p() const; + + /** + * Get the prime q. + * @return the prime q + */ + const BigInt& get_q() const; + + /** + * Get the base g. + * @return the base g + */ + const BigInt& get_g() const; + + /** + * The DL group encoding format variants. + */ + enum Format { + ANSI_X9_42, + ANSI_X9_57, + PKCS_3, + + DSA_PARAMETERS = ANSI_X9_57, + DH_PARAMETERS = ANSI_X9_42, + X942_DH_PARAMETERS = ANSI_X9_42, + PKCS3_DH_PARAMETERS = PKCS_3 + }; + + /** + * Determine the prime creation for DL groups. + */ + enum PrimeType { Strong, Prime_Subgroup, DSA_Kosherizer }; + + /** + * Perform validity checks on the group. + * @param rng the rng to use + * @param strong whether to perform stronger by lengthier tests + * @return true if the object is consistent, false otherwise + */ + bool verify_group(RandomNumberGenerator& rng, bool strong) const; + + /** + * Encode this group into a string using PEM encoding. + * @param format the encoding format + * @return the string holding the PEM encoded group + */ + std::string PEM_encode(Format format) const; + + /** + * Encode this group into a string using DER encoding. + * @param format the encoding format + * @return the string holding the DER encoded group + */ + SecureVector<byte> DER_encode(Format format) const; + + /** + * Decode a DER/BER encoded group into this instance. + * @param src a DataSource providing the encoded group + * @param format the format of the encoded group + */ + void BER_decode(DataSource& src, Format format); + + /** + * Decode a PEM encoded group into this instance. + * @param src a DataSource providing the encoded group + */ + void PEM_decode(DataSource& src); + + /** + * Construct a DL group with uninitialized internal value. + * Use this constructor is you wish to set the groups values + * from a DER or PEM encoded group. + */ + DL_Group(); + + /** + * Construct a DL group that is registered in the configuration. + * @param name the name that is configured in the global configuration + * for the desired group. If no configuration file is specified, + * the default values from the file policy.cpp will be used. For instance, + * use "modp/ietf/768" as name. + */ + DL_Group(const std::string& name); + + /** + * Create a new group randomly. + * @param rng the random number generator to use + * @param type specifies how the creation of primes p and q shall + * be performed. If type=Strong, then p will be determined as a + * safe prime, and q will be chosen as (p-1)/2. If + * type=Prime_Subgroup and qbits = 0, then the size of q will be + * determined according to the estimated difficulty of the DL + * problem. If type=DSA_Kosherizer, DSA primes will be created. + * @param pbits the number of bits of p + * @param qbits the number of bits of q. Leave it as 0 to have + * the value determined according to pbits. + */ + DL_Group(RandomNumberGenerator& rng, PrimeType type, + u32bit pbits, u32bit qbits = 0); + + /** + * Create a DSA group with a given seed. + * @param rng the random number generator to use + * @param seed the seed to use to create the random primes + * @param pbits the desired bit size of the prime p + * @param qbits the desired bit size of the prime q. + */ + DL_Group(RandomNumberGenerator& rng, const MemoryRegion<byte>& seed, + u32bit pbits = 1024, u32bit qbits = 0); + + /** + * Create a DL group. The prime q will be determined according to p. + * @param p the prime p + * @param g the base g + */ + DL_Group(const BigInt& p, const BigInt& g); + + /** + * Create a DL group. + * @param p the prime p + * @param q the prime q + * @param g the base g + */ + DL_Group(const BigInt& p, const BigInt& q, const BigInt& g); + private: + static BigInt make_dsa_generator(const BigInt&, const BigInt&); + + void init_check() const; + void initialize(const BigInt&, const BigInt&, const BigInt&); + bool initialized; + BigInt p, q, g; + }; + +} + +#endif diff --git a/botan/src/pubkey/dl_group/info.txt b/botan/src/pubkey/dl_group/info.txt new file mode 100644 index 0000000..6b9884a --- /dev/null +++ b/botan/src/pubkey/dl_group/info.txt @@ -0,0 +1,19 @@ +realname "DL Group" + +load_on auto + +define DL_GROUP + +<add> +dl_group.cpp +dl_group.h +</add> + +<requires> +asn1 +bigint +filters +libstate +numbertheory +pem +</requires> diff --git a/botan/src/pubkey/dlies/dlies.cpp b/botan/src/pubkey/dlies/dlies.cpp new file mode 100644 index 0000000..c441ed1 --- /dev/null +++ b/botan/src/pubkey/dlies/dlies.cpp @@ -0,0 +1,137 @@ +/* +* DLIES +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/dlies.h> +#include <botan/look_pk.h> +#include <botan/xor_buf.h> + +namespace Botan { + +/* +* DLIES_Encryptor Constructor +*/ +DLIES_Encryptor::DLIES_Encryptor(const PK_Key_Agreement_Key& k, + KDF* kdf_obj, + MessageAuthenticationCode* mac_obj, + u32bit mac_kl) : + key(k), kdf(kdf_obj), mac(mac_obj), mac_keylen(mac_kl) + { + } + +DLIES_Encryptor::~DLIES_Encryptor() + { + delete kdf; + delete mac; + } + +/* +* DLIES Encryption +*/ +SecureVector<byte> DLIES_Encryptor::enc(const byte in[], u32bit length, + RandomNumberGenerator&) const + { + if(length > maximum_input_size()) + throw Invalid_Argument("DLIES: Plaintext too large"); + if(other_key.is_empty()) + throw Invalid_State("DLIES: The other key was never set"); + + MemoryVector<byte> v = key.public_value(); + + SecureVector<byte> out(v.size() + length + mac->OUTPUT_LENGTH); + out.copy(v, v.size()); + out.copy(v.size(), in, length); + + SecureVector<byte> vz(v, key.derive_key(other_key, other_key.size())); + + const u32bit K_LENGTH = length + mac_keylen; + OctetString K = kdf->derive_key(K_LENGTH, vz, vz.size()); + if(K.length() != K_LENGTH) + throw Encoding_Error("DLIES: KDF did not provide sufficient output"); + byte* C = out + v.size(); + + xor_buf(C, K.begin() + mac_keylen, length); + mac->set_key(K.begin(), mac_keylen); + + mac->update(C, length); + for(u32bit j = 0; j != 8; ++j) + mac->update(0); + + mac->final(C + length); + + return out; + } + +/* +* Set the other parties public key +*/ +void DLIES_Encryptor::set_other_key(const MemoryRegion<byte>& ok) + { + other_key = ok; + } + +/* +* Return the max size, in bytes, of a message +*/ +u32bit DLIES_Encryptor::maximum_input_size() const + { + return 32; + } + +/* +* DLIES_Decryptor Constructor +*/ +DLIES_Decryptor::DLIES_Decryptor(const PK_Key_Agreement_Key& k, + KDF* kdf_obj, + MessageAuthenticationCode* mac_obj, + u32bit mac_kl) : + key(k), kdf(kdf_obj), mac(mac_obj), mac_keylen(mac_kl) + { + } + +DLIES_Decryptor::~DLIES_Decryptor() + { + delete kdf; + delete mac; + } + +/* +* DLIES Decryption +*/ +SecureVector<byte> DLIES_Decryptor::dec(const byte msg[], u32bit length) const + { + const u32bit public_len = key.public_value().size(); + + if(length < public_len + mac->OUTPUT_LENGTH) + throw Decoding_Error("DLIES decryption: ciphertext is too short"); + + const u32bit CIPHER_LEN = length - public_len - mac->OUTPUT_LENGTH; + + SecureVector<byte> v(msg, public_len); + SecureVector<byte> C(msg + public_len, CIPHER_LEN); + SecureVector<byte> T(msg + public_len + CIPHER_LEN, mac->OUTPUT_LENGTH); + + SecureVector<byte> vz(v, key.derive_key(v, v.size())); + + const u32bit K_LENGTH = C.size() + mac_keylen; + OctetString K = kdf->derive_key(K_LENGTH, vz, vz.size()); + if(K.length() != K_LENGTH) + throw Encoding_Error("DLIES: KDF did not provide sufficient output"); + + mac->set_key(K.begin(), mac_keylen); + mac->update(C); + for(u32bit j = 0; j != 8; ++j) + mac->update(0); + SecureVector<byte> T2 = mac->final(); + if(T != T2) + throw Integrity_Failure("DLIES: message authentication failed"); + + xor_buf(C, K.begin() + mac_keylen, C.size()); + + return C; + } + +} diff --git a/botan/src/pubkey/dlies/dlies.h b/botan/src/pubkey/dlies/dlies.h new file mode 100644 index 0000000..88a22b9 --- /dev/null +++ b/botan/src/pubkey/dlies/dlies.h @@ -0,0 +1,69 @@ +/* +* DLIES +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DLIES_H__ +#define BOTAN_DLIES_H__ + +#include <botan/pubkey.h> +#include <botan/mac.h> +#include <botan/kdf.h> + +namespace Botan { + +/* +* DLIES Encryption +*/ +class BOTAN_DLL DLIES_Encryptor : public PK_Encryptor + { + public: + DLIES_Encryptor(const PK_Key_Agreement_Key&, + KDF* kdf, + MessageAuthenticationCode* mac, + u32bit mac_key_len = 20); + + ~DLIES_Encryptor(); + + void set_other_key(const MemoryRegion<byte>&); + private: + SecureVector<byte> enc(const byte[], u32bit, + RandomNumberGenerator&) const; + u32bit maximum_input_size() const; + + const PK_Key_Agreement_Key& key; + SecureVector<byte> other_key; + + KDF* kdf; + MessageAuthenticationCode* mac; + u32bit mac_keylen; + }; + +/* +* DLIES Decryption +*/ +class BOTAN_DLL DLIES_Decryptor : public PK_Decryptor + { + public: + DLIES_Decryptor(const PK_Key_Agreement_Key&, + KDF* kdf, + MessageAuthenticationCode* mac, + u32bit mac_key_len = 20); + + ~DLIES_Decryptor(); + + private: + SecureVector<byte> dec(const byte[], u32bit) const; + + const PK_Key_Agreement_Key& key; + + KDF* kdf; + MessageAuthenticationCode* mac; + u32bit mac_keylen; + }; + +} + +#endif diff --git a/botan/src/pubkey/dlies/info.txt b/botan/src/pubkey/dlies/info.txt new file mode 100644 index 0000000..5138aaf --- /dev/null +++ b/botan/src/pubkey/dlies/info.txt @@ -0,0 +1,16 @@ +realname "DLIES" + +define DLIES + +load_on auto + +<add> +dlies.cpp +dlies.h +</add> + +<requires> +kdf +libstate +mac +</requires> diff --git a/botan/src/pubkey/dsa/dsa.cpp b/botan/src/pubkey/dsa/dsa.cpp new file mode 100644 index 0000000..b0688ae --- /dev/null +++ b/botan/src/pubkey/dsa/dsa.cpp @@ -0,0 +1,134 @@ +/* +* DSA +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/dsa.h> +#include <botan/numthry.h> +#include <botan/keypair.h> +#include <botan/look_pk.h> + +namespace Botan { + +/* +* DSA_PublicKey Constructor +*/ +DSA_PublicKey::DSA_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + X509_load_hook(); + } + +/* +* Algorithm Specific X.509 Initialization Code +*/ +void DSA_PublicKey::X509_load_hook() + { + core = DSA_Core(group, y); + } + +/* +* DSA Verification Function +*/ +bool DSA_PublicKey::verify(const byte msg[], u32bit msg_len, + const byte sig[], u32bit sig_len) const + { + return core.verify(msg, msg_len, sig, sig_len); + } + +/* +* Return the maximum input size in bits +*/ +u32bit DSA_PublicKey::max_input_bits() const + { + return group_q().bits(); + } + +/* +* Return the size of each portion of the sig +*/ +u32bit DSA_PublicKey::message_part_size() const + { + return group_q().bytes(); + } + +/* +* Create a DSA private key +*/ +DSA_PrivateKey::DSA_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + { + x = BigInt::random_integer(rng, 2, group_q() - 1); + PKCS8_load_hook(rng, true); + } + else + PKCS8_load_hook(rng, false); + } + +/* +* Algorithm Specific PKCS #8 Initialization Code +*/ +void DSA_PrivateKey::PKCS8_load_hook(RandomNumberGenerator& rng, + bool generated) + { + y = power_mod(group_g(), x, group_p()); + core = DSA_Core(group, y, x); + + if(generated) + gen_check(rng); + else + load_check(rng); + } + +/* +* DSA Signature Operation +*/ +SecureVector<byte> DSA_PrivateKey::sign(const byte in[], u32bit length, + RandomNumberGenerator& rng) const + { + const BigInt& q = group_q(); + + BigInt k; + do + k.randomize(rng, q.bits()); + while(k >= q); + + return core.sign(in, length, k); + } + +/* +* Check Private DSA Parameters +*/ +bool DSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong) || x >= group_q()) + return false; + + if(!strong) + return true; + + try + { + KeyPair::check_key(rng, + get_pk_signer(*this, "EMSA1(SHA-1)"), + get_pk_verifier(*this, "EMSA1(SHA-1)") + ); + } + catch(Self_Test_Failure) + { + return false; + } + + return true; + } + +} diff --git a/botan/src/pubkey/dsa/dsa.h b/botan/src/pubkey/dsa/dsa.h new file mode 100644 index 0000000..4c9b708 --- /dev/null +++ b/botan/src/pubkey/dsa/dsa.h @@ -0,0 +1,62 @@ +/* +* DSA +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DSA_H__ +#define BOTAN_DSA_H__ + +#include <botan/dl_algo.h> +#include <botan/dsa_core.h> + +namespace Botan { + +/* +* DSA Public Key +*/ +class BOTAN_DLL DSA_PublicKey : public PK_Verifying_wo_MR_Key, + public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "DSA"; } + + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_57; } + u32bit message_parts() const { return 2; } + u32bit message_part_size() const; + + bool verify(const byte[], u32bit, const byte[], u32bit) const; + u32bit max_input_bits() const; + + DSA_PublicKey() {} + DSA_PublicKey(const DL_Group&, const BigInt&); + protected: + DSA_Core core; + private: + void X509_load_hook(); + }; + +/* +* DSA Private Key +*/ +class BOTAN_DLL DSA_PrivateKey : public DSA_PublicKey, + public PK_Signing_Key, + public virtual DL_Scheme_PrivateKey + { + public: + SecureVector<byte> sign(const byte[], u32bit, + RandomNumberGenerator& rng) const; + + bool check_key(RandomNumberGenerator& rng, bool) const; + + DSA_PrivateKey() {} + DSA_PrivateKey(RandomNumberGenerator&, const DL_Group&, + const BigInt& = 0); + private: + void PKCS8_load_hook(RandomNumberGenerator& rng, bool = false); + }; + +} + +#endif diff --git a/botan/src/pubkey/dsa/dsa_core.cpp b/botan/src/pubkey/dsa/dsa_core.cpp new file mode 100644 index 0000000..e5a23a5 --- /dev/null +++ b/botan/src/pubkey/dsa/dsa_core.cpp @@ -0,0 +1,63 @@ +/* +* DSA Core +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/dsa_core.h> +#include <botan/numthry.h> +#include <botan/pk_engine.h> +#include <botan/parsing.h> +#include <algorithm> + +namespace Botan { + +/* +* DSA_Core Constructor +*/ +DSA_Core::DSA_Core(const DL_Group& group, const BigInt& y, const BigInt& x) + { + op = Engine_Core::dsa_op(group, y, x); + } + +/* +* DSA_Core Copy Constructor +*/ +DSA_Core::DSA_Core(const DSA_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + } + +/* +* DSA_Core Assignment Operator +*/ +DSA_Core& DSA_Core::operator=(const DSA_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + return (*this); + } + +/* +* DSA Verification Operation +*/ +bool DSA_Core::verify(const byte msg[], u32bit msg_length, + const byte sig[], u32bit sig_length) const + { + return op->verify(msg, msg_length, sig, sig_length); + } + +/* +* DSA Signature Operation +*/ +SecureVector<byte> DSA_Core::sign(const byte in[], u32bit length, + const BigInt& k) const + { + return op->sign(in, length, k); + } + +} diff --git a/botan/src/pubkey/dsa/dsa_core.h b/botan/src/pubkey/dsa/dsa_core.h new file mode 100644 index 0000000..8bb1621 --- /dev/null +++ b/botan/src/pubkey/dsa/dsa_core.h @@ -0,0 +1,37 @@ +/* +* DSA Core +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DSA_CORE_H__ +#define BOTAN_DSA_CORE_H__ + +#include <botan/dsa_op.h> +#include <botan/dl_group.h> + +namespace Botan { + +/* +* DSA Core +*/ +class BOTAN_DLL DSA_Core + { + public: + SecureVector<byte> sign(const byte[], u32bit, const BigInt&) const; + bool verify(const byte[], u32bit, const byte[], u32bit) const; + + DSA_Core& operator=(const DSA_Core&); + + DSA_Core() { op = 0; } + DSA_Core(const DSA_Core&); + DSA_Core(const DL_Group&, const BigInt&, const BigInt& = 0); + ~DSA_Core() { delete op; } + private: + DSA_Operation* op; + }; + +} + +#endif diff --git a/botan/src/pubkey/dsa/dsa_op.cpp b/botan/src/pubkey/dsa/dsa_op.cpp new file mode 100644 index 0000000..5b92144 --- /dev/null +++ b/botan/src/pubkey/dsa/dsa_op.cpp @@ -0,0 +1,73 @@ +/* +* DSA Operations +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/dsa_op.h> + +namespace Botan { + +/* +* Default_DSA_Op Constructor +*/ +Default_DSA_Op::Default_DSA_Op(const DL_Group& grp, const BigInt& y1, + const BigInt& x1) : x(x1), y(y1), group(grp) + { + powermod_g_p = Fixed_Base_Power_Mod(group.get_g(), group.get_p()); + powermod_y_p = Fixed_Base_Power_Mod(y, group.get_p()); + mod_p = Modular_Reducer(group.get_p()); + mod_q = Modular_Reducer(group.get_q()); + } + +/* +* Default DSA Verify Operation +*/ +bool Default_DSA_Op::verify(const byte msg[], u32bit msg_len, + const byte sig[], u32bit sig_len) const + { + const BigInt& q = group.get_q(); + + if(sig_len != 2*q.bytes() || msg_len > q.bytes()) + return false; + + BigInt r(sig, q.bytes()); + BigInt s(sig + q.bytes(), q.bytes()); + BigInt i(msg, msg_len); + + if(r <= 0 || r >= q || s <= 0 || s >= q) + return false; + + s = inverse_mod(s, q); + s = mod_p.multiply(powermod_g_p(mod_q.multiply(s, i)), + powermod_y_p(mod_q.multiply(s, r))); + + return (mod_q.reduce(s) == r); + } + +/* +* Default DSA Sign Operation +*/ +SecureVector<byte> Default_DSA_Op::sign(const byte in[], u32bit length, + const BigInt& k) const + { + if(x == 0) + throw Internal_Error("Default_DSA_Op::sign: No private key"); + + const BigInt& q = group.get_q(); + BigInt i(in, length); + + BigInt r = mod_q.reduce(powermod_g_p(k)); + BigInt s = mod_q.multiply(inverse_mod(k, q), mul_add(x, r, i)); + + if(r.is_zero() || s.is_zero()) + throw Internal_Error("Default_DSA_Op::sign: r or s was zero"); + + SecureVector<byte> output(2*q.bytes()); + r.binary_encode(output + (output.size() / 2 - r.bytes())); + s.binary_encode(output + (output.size() - s.bytes())); + return output; + } + +} diff --git a/botan/src/pubkey/dsa/dsa_op.h b/botan/src/pubkey/dsa/dsa_op.h new file mode 100644 index 0000000..0b112c6 --- /dev/null +++ b/botan/src/pubkey/dsa/dsa_op.h @@ -0,0 +1,53 @@ +/* +* DSA Operations +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DSA_OPS_H__ +#define BOTAN_DSA_OPS_H__ + +#include <botan/numthry.h> +#include <botan/pow_mod.h> +#include <botan/reducer.h> +#include <botan/dl_group.h> + +namespace Botan { + +/* +* DSA Operation +*/ +class BOTAN_DLL DSA_Operation + { + public: + virtual bool verify(const byte[], u32bit, + const byte[], u32bit) const = 0; + virtual SecureVector<byte> sign(const byte[], u32bit, + const BigInt&) const = 0; + virtual DSA_Operation* clone() const = 0; + virtual ~DSA_Operation() {} + }; + +/* +* Botan's Default DSA Operation +*/ +class BOTAN_DLL Default_DSA_Op : public DSA_Operation + { + public: + bool verify(const byte[], u32bit, const byte[], u32bit) const; + SecureVector<byte> sign(const byte[], u32bit, const BigInt&) const; + + DSA_Operation* clone() const { return new Default_DSA_Op(*this); } + + Default_DSA_Op(const DL_Group&, const BigInt&, const BigInt&); + private: + const BigInt x, y; + const DL_Group group; + Fixed_Base_Power_Mod powermod_g_p, powermod_y_p; + Modular_Reducer mod_p, mod_q; + }; + +} + +#endif diff --git a/botan/src/pubkey/dsa/info.txt b/botan/src/pubkey/dsa/info.txt new file mode 100644 index 0000000..c70e02d --- /dev/null +++ b/botan/src/pubkey/dsa/info.txt @@ -0,0 +1,22 @@ +realname "DSA" + +define DSA + +load_on auto + +<add> +dsa.cpp +dsa.h +dsa_core.cpp +dsa_core.h +dsa_op.cpp +dsa_op.h +</add> + +<requires> +dl_algo +dl_group +keypair +libstate +numbertheory +</requires> diff --git a/botan/src/pubkey/ec_dompar/ec_dompar.cpp b/botan/src/pubkey/ec_dompar/ec_dompar.cpp new file mode 100644 index 0000000..6cfcc06 --- /dev/null +++ b/botan/src/pubkey/ec_dompar/ec_dompar.cpp @@ -0,0 +1,573 @@ + +#include <botan/ec_dompar.h> +#include <botan/pubkey_enums.h> +#include <botan/parsing.h> +#include <botan/hex.h> +#include <botan/pipe.h> + +namespace Botan { + +namespace { + +std::vector<std::string> get_standard_domain_parameter(const std::string& oid) + { + // using a linear search here is pretty nasty... revisit + + /* SEC2 */ + + if(oid == "1.3.132.0.6") + { + /* secp112r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xdb7c2abf62e35e668076bead208b"); //p + dom_par.push_back("0xDB7C2ABF62E35E668076BEAD2088"); // a + dom_par.push_back("0x659EF8BA043916EEDE8911702B22"); // b + dom_par.push_back("0409487239995A5EE76B55F9C2F098A89CE5AF8724C0A23E0E0ff77500"); // G + dom_par.push_back("0xDB7C2ABF62E35E7628DFAC6561C5"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.7") + { + /* secp112r2; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xdb7c2abf62e35e668076bead208b"); //p + dom_par.push_back("0x6127C24C05F38A0AAAF65C0EF02C"); // a + dom_par.push_back("0x51DEF1815DB5ED74FCC34C85D709"); // b + dom_par.push_back("044BA30AB5E892B4E1649DD0928643ADCD46F5882E3747DEF36E956E97"); // G + dom_par.push_back("0x36DF0AAFD8B8D7597CA10520D04B"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.28") + { + /* secp128r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xfffffffdffffffffffffffffffffffff"); //p + dom_par.push_back("0xffffffFDffffffffffffffffffffffFC"); // a + dom_par.push_back("0xE87579C11079F43DD824993C2CEE5ED3"); // b + dom_par.push_back("04161ff7528B899B2D0C28607CA52C5B86CF5AC8395BAFEB13C02DA292DDED7A83"); // G + dom_par.push_back("0xffffffFE0000000075A30D1B9038A115"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.29") + { + /* secp128r2; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xfffffffdffffffffffffffffffffffff"); //p + dom_par.push_back("0xD6031998D1B3BBFEBF59CC9BBff9AEE1"); // a + dom_par.push_back("0x5EEEFCA380D02919DC2C6558BB6D8A5D"); // b + dom_par.push_back("047B6AA5D85E572983E6FB32A7CDEBC14027B6916A894D3AEE7106FE805FC34B44"); // G + dom_par.push_back("0x3ffffffF7ffffffFBE0024720613B5A3"); // order + dom_par.push_back("4"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.9") + { + /* secp160k1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xfffffffffffffffffffffffffffffffeffffac73"); //p + dom_par.push_back("0x0000000000000000000000000000000000000000"); // a + dom_par.push_back("0x0000000000000000000000000000000000000007"); // b + dom_par.push_back("043B4C382CE37AA192A4019E763036F4F5DD4D7EBB938CF935318FDCED6BC28286531733C3F03C4FEE"); // G + dom_par.push_back("0x0100000000000000000001B8FA16DFAB9ACA16B6B3"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.30") + { + /* secp160r2; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xfffffffffffffffffffffffffffffffeffffac73"); //p + dom_par.push_back("0xffffffffffffffffffffffffffffffFEffffAC70"); // a + dom_par.push_back("0xB4E134D3FB59EB8BAB57274904664D5AF50388BA"); // b + dom_par.push_back("0452DCB034293A117E1F4ff11B30F7199D3144CE6DFEAffEF2E331F296E071FA0DF9982CFEA7D43F2E"); // G + dom_par.push_back("0x0100000000000000000000351EE786A818F3A1A16B"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.31") + { + /* secp192k1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xfffffffffffffffffffffffffffffffffffffffeffffee37"); //p + dom_par.push_back("0x000000000000000000000000000000000000000000000000"); // a + dom_par.push_back("0x000000000000000000000000000000000000000000000003"); // b + dom_par.push_back("04DB4ff10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"); // G + dom_par.push_back("0xffffffffffffffffffffffFE26F2FC170F69466A74DEFD8D"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.32") + { + /* secp224k1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xfffffffffffffffffffffffffffffffffffffffffffffffeffffe56d"); //p + dom_par.push_back("0x00000000000000000000000000000000000000000000000000000000"); // a + dom_par.push_back("0x00000000000000000000000000000000000000000000000000000005"); // b + dom_par.push_back("04A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"); // G + dom_par.push_back("0x010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.33") + { + /* secp224r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xffffffffffffffffffffffffffffffff000000000000000000000001"); //p + dom_par.push_back("0xffffffffffffffffffffffffffffffFEffffffffffffffffffffffFE"); // a + dom_par.push_back("0xB4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355ffB4"); // b + dom_par.push_back("04B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"); // G + dom_par.push_back("0xffffffffffffffffffffffffffff16A2E0B8F03E13DD29455C5C2A3D"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.10") + { + /* secp256k1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"); //p + dom_par.push_back("0x0000000000000000000000000000000000000000000000000000000000000000"); // a + dom_par.push_back("0x0000000000000000000000000000000000000000000000000000000000000007"); // b + dom_par.push_back("0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"); // G + dom_par.push_back("0xffffffffffffffffffffffffffffffFEBAAEDCE6AF48A03BBFD25E8CD0364141"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.34") + { + /* secp384r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff"); //p + dom_par.push_back("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFEffffffff0000000000000000ffffffFC"); // a + dom_par.push_back("0xB3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"); // b + dom_par.push_back("04AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB73617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"); // G + dom_par.push_back("0xffffffffffffffffffffffffffffffffffffffffffffffffC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.35") + { + /* secp521r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); //p + dom_par.push_back("0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFC"); // a + dom_par.push_back("0x0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"); // b + dom_par.push_back("0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2ffA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"); // G + dom_par.push_back("0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + /* NIS */ + + if(oid == "1.3.6.1.4.1.8301.3.1.2.9.0.38") + { + /* NIST curve P-521; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); //p + dom_par.push_back("0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFC"); // a + dom_par.push_back("0x051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"); // b + dom_par.push_back("0400C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2ffA8DE3348B3C1856A429BF97E7E31C2E5BD66011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"); // G + dom_par.push_back("0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + /* BrainPool */ + + if(oid == "1.3.36.3.3.2.8.1.1.1") + { + /* brainpoolP160r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xE95E4A5F737059DC60DFC7AD95B3D8139515620F"); //p + dom_par.push_back("0x340E7BE2A280EB74E2BE61BADA745D97E8F7C300"); // a + dom_par.push_back("0x1E589A8595423412134FAA2DBDEC95C8D8675E58"); // b + dom_par.push_back("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321"); // G + dom_par.push_back("0xE95E4A5F737059DC60DF5991D45029409E60FC09"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.36.3.3.2.8.1.1.3") + { + /* brainpoolP192r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xC302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297"); //p + dom_par.push_back("0x6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF"); // a + dom_par.push_back("0x469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9"); // b + dom_par.push_back("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F"); // G + dom_par.push_back("0xC302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.36.3.3.2.8.1.1.5") + { + /* brainpoolP224r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xD7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF"); //p + dom_par.push_back("0x68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43"); // a + dom_par.push_back("0x2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B"); // b + dom_par.push_back("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD"); // G + dom_par.push_back("0xD7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.36.3.3.2.8.1.1.7") + { + /* brainpoolP256r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377"); //p + dom_par.push_back("0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9"); // a + dom_par.push_back("0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6"); // b + dom_par.push_back("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997"); // G + dom_par.push_back("0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.36.3.3.2.8.1.1.9") + { + /* brainpoolP320r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xD35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27"); //p + dom_par.push_back("0x3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4"); // a + dom_par.push_back("0x520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6"); // b + dom_par.push_back("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1"); // G + dom_par.push_back("0xD35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.36.3.3.2.8.1.1.11") + { + /* brainpoolP384r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53"); //p + dom_par.push_back("0x7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826"); // a + dom_par.push_back("0x4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11"); // b + dom_par.push_back("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315"); // G + dom_par.push_back("0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.36.3.3.2.8.1.1.13") + { + /* brainpoolP512r1; source: Flexiprovider */ + std::vector<std::string> dom_par; + dom_par.push_back("0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3"); //p + dom_par.push_back("0x7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA"); // a + dom_par.push_back("0x3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723"); // b + dom_par.push_back("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892"); // G + dom_par.push_back("0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069"); // order + dom_par.push_back("1"); // cofactor + + return dom_par; + } + + if(oid == "1.3.132.0.8") + { + std::vector<std::string> dom_par; + dom_par.push_back("0xffffffffffffffffffffffffffffffff7fffffff"); //p + dom_par.push_back("0xffffffffffffffffffffffffffffffff7ffffffc"); // a + dom_par.push_back("0x1c97befc54bd7a8b65acf89f81d4d4adc565fa45"); // b + dom_par.push_back("024a96b5688ef573284664698968c38bb913cbfc82"); // G + dom_par.push_back("0x0100000000000000000001f4c8f927aed3ca752257"); // order + dom_par.push_back("1"); // cofactor + return dom_par; + } + + if(oid == "1.2.840.10045.3.1.1") // prime192v1 Flexiprovider + { + std::vector<std::string> dom_par; + dom_par.push_back("0xfffffffffffffffffffffffffffffffeffffffffffffffff"); //p + dom_par.push_back("0xfffffffffffffffffffffffffffffffefffffffffffffffc"); // a + dom_par.push_back("0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1"); // b + dom_par.push_back("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"); // G + dom_par.push_back("0xffffffffffffffffffffffff99def836146bc9b1b4d22831"); // order + dom_par.push_back("1"); // cofactor + return dom_par; + } + + /* prime192v2; source: Flexiprovider */ + if(oid == "1.2.840.10045.3.1.2") + { + std::vector<std::string> dom_par; + dom_par.push_back("0xfffffffffffffffffffffffffffffffeffffffffffffffff"); //p + dom_par.push_back("0xffffffffffffffffffffffffffffffFeffffffffffffffFC"); // a + dom_par.push_back("0xcc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953"); // b + dom_par.push_back("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a"); // G + dom_par.push_back("0xfffffffffffffffffffffffe5fb1a724dc80418648d8dd31"); // order + dom_par.push_back("1"); // cofactor + return dom_par; + } + + /* prime192v3; source: Flexiprovider */ + if(oid == "1.2.840.10045.3.1.3") + { + std::vector<std::string> dom_par; + dom_par.push_back("0xfffffffffffffffffffffffffffffffeffffffffffffffff"); //p + dom_par.push_back("0xfffffffffffffffffffffffffffffffefffffffffffffffc"); // a + dom_par.push_back("0x22123dc2395a05caa7423daeccc94760a7d462256bd56916"); // b + dom_par.push_back("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896"); // G + dom_par.push_back("0xffffffffffffffffffffffff7a62d031c83f4294f640ec13"); // order + dom_par.push_back("1"); // cofactor + return dom_par; + } + + /* prime239v1; source: Flexiprovider */ + if(oid == "1.2.840.10045.3.1.4") + { + std::vector<std::string> dom_par; + dom_par.push_back("0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff"); //p + dom_par.push_back("0x7ffFffffffffffffffffffff7fffffffffff8000000000007ffffffffffc"); // a + dom_par.push_back("0x6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A"); // b + dom_par.push_back("020ffA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF"); // G + dom_par.push_back("0x7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b"); // order + dom_par.push_back("1"); // cofactor + return dom_par; + } + + /* prime239v2; source: Flexiprovider */ + if(oid == "1.2.840.10045.3.1.5") + { + std::vector<std::string> dom_par; + dom_par.push_back("0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff"); //p + dom_par.push_back("0x7ffFffffffffffffffffffff7ffFffffffff8000000000007ffFffffffFC"); // a + dom_par.push_back("0x617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C"); // b + dom_par.push_back("0238AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7"); // G + dom_par.push_back("0x7fffffffffffffffffffffff800000CFA7E8594377D414C03821BC582063"); // order + dom_par.push_back("1"); // cofactor + return dom_par; + } + + /* prime239v3; source: Flexiprovider */ + if(oid == "1.2.840.10045.3.1.6") + { + std::vector<std::string> dom_par; + dom_par.push_back("0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff"); //p + dom_par.push_back("0x7ffFffffffffffffffffffff7ffFffffffff8000000000007ffFffffffFC"); // a + dom_par.push_back("0x255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E"); // b + dom_par.push_back("036768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A"); // G + dom_par.push_back("0x7fffffffffffffffffffffff7fffff975DEB41B3A6057C3C432146526551"); // order + dom_par.push_back("1"); // cofactor + return dom_par; + } + + /* prime256v1; source: Flexiprovider */ + if(oid == "1.2.840.10045.3.1.7") + { + std::vector<std::string> dom_par; + dom_par.push_back("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"); //p + dom_par.push_back("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffFC"); // a + dom_par.push_back("0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"); // b + dom_par.push_back("036B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"); // G + dom_par.push_back("0xffffffff00000000ffffffffffffffffBCE6FAADA7179E84F3B9CAC2FC632551"); // order + dom_par.push_back("1"); // cofactor + return dom_par; + } + + throw Invalid_Argument("No such ECC curve " + oid); + } + +EC_Domain_Params get_ec_dompar(const std::string& oid) + { + std::vector<std::string> dom_par = get_standard_domain_parameter(oid); + + BigInt p(dom_par[0]); // give as 0x... + GFpElement a(p, BigInt(dom_par[1])); + GFpElement b(p, BigInt(dom_par[2])); + + Pipe pipe(new Hex_Decoder); + pipe.process_msg(dom_par[3]); + SecureVector<byte> sv_g = pipe.read_all(); + + CurveGFp curve(a, b, p); + PointGFp G = OS2ECP ( sv_g, curve ); + G.check_invariants(); + BigInt order(dom_par[4]); + BigInt cofactor(dom_par[5]); + EC_Domain_Params result(curve, G, order, cofactor); + return result; + } + +} + +EC_Domain_Params get_EC_Dom_Pars_by_oid(std::string oid) + { + EC_Domain_Params result = get_ec_dompar(oid); + result.m_oid = oid; + return result; + } + +EC_Domain_Params::EC_Domain_Params(const CurveGFp& curve, const PointGFp& base_point, + const BigInt& order, const BigInt& cofactor) + : m_curve(curve), + m_base_point(base_point), + m_order(order), + m_cofactor(cofactor), + m_oid("") + { } + +namespace { + +SecureVector<byte> encode_der_ec_dompar_explicit(EC_Domain_Params const& dom_pars) + { + u32bit ecpVers1 = 1; + OID curve_type_oid("1.2.840.10045.1.1"); + + DER_Encoder der; + + der.start_cons(SEQUENCE) + .encode(ecpVers1) + .start_cons(SEQUENCE) + .encode(curve_type_oid) + .encode(dom_pars.get_curve().get_p()) + .end_cons() + .start_cons(SEQUENCE) + .encode(FE2OSP ( dom_pars.get_curve().get_a() ), OCTET_STRING) + .encode(FE2OSP ( dom_pars.get_curve().get_b() ), OCTET_STRING) + .end_cons() + .encode(EC2OSP ( dom_pars.get_base_point(), PointGFp::UNCOMPRESSED), OCTET_STRING) + .encode(dom_pars.get_order()) + .encode(dom_pars.get_cofactor()) + .end_cons(); + + return der.get_contents(); + } + +EC_Domain_Params decode_ber_ec_dompar_explicit(SecureVector<byte> const& encoded) + { + BigInt ecpVers1(1); + OID curve_type_oid; + SecureVector<byte> sv_a; + SecureVector<byte> sv_b; + BigInt p; + SecureVector<byte> sv_base_point; + BigInt order; + BigInt cofactor; + BER_Decoder dec(encoded); + dec + .start_cons(SEQUENCE) + .decode(ecpVers1) + .start_cons(SEQUENCE) + .decode(curve_type_oid) + .decode(p) + .end_cons() + .start_cons(SEQUENCE) + .decode(sv_a, OCTET_STRING) + .decode(sv_b, OCTET_STRING) + .end_cons() + .decode(sv_base_point, OCTET_STRING) + .decode(order) + .decode(cofactor) + .verify_end() + .end_cons(); + if(ecpVers1 != 1) + { + throw Decoding_Error("wrong ecpVers"); + } + // Set the domain parameters + if(curve_type_oid.as_string() != "1.2.840.10045.1.1") // NOTE: hardcoded: prime field type + { + throw Decoding_Error("wrong curve type oid where prime field was expected"); + } + GFpElement a(p,BigInt::decode(sv_a, sv_a.size())); + GFpElement b(p,BigInt::decode(sv_b, sv_b.size())); + CurveGFp curve(a,b,p); + PointGFp G = OS2ECP ( sv_base_point, curve ); + G.check_invariants(); + return EC_Domain_Params(curve, G, order, cofactor); + } + +} // end anonymous namespace + +SecureVector<byte> encode_der_ec_dompar(EC_Domain_Params const& dom_pars, EC_dompar_enc enc_type) + { + SecureVector<byte> result; + + if(enc_type == ENC_EXPLICIT) + { + result = encode_der_ec_dompar_explicit(dom_pars); + } + else if(enc_type == ENC_OID) + { + OID dom_par_oid(dom_pars.get_oid()); + result = DER_Encoder().encode(dom_par_oid).get_contents(); + } + else if(enc_type == ENC_IMPLICITCA) + { + result = DER_Encoder().encode_null().get_contents(); + } + else + { + throw Internal_Error("encountered illegal value for ec parameter encoding type"); + } + return result; + } + +EC_Domain_Params decode_ber_ec_dompar(SecureVector<byte> const& encoded) + { + BER_Decoder dec(encoded); + BER_Object obj = dec.get_next_object(); + ASN1_Tag tag = obj.type_tag; + std::auto_ptr<EC_Domain_Params> p_result; + + if(tag == OBJECT_ID) + { + OID dom_par_oid; + BER_Decoder(encoded).decode(dom_par_oid); + return EC_Domain_Params(get_ec_dompar(dom_par_oid.as_string())); + } + else if(tag == SEQUENCE) + return EC_Domain_Params(decode_ber_ec_dompar_explicit(encoded)); + else if(tag == NULL_TAG) + throw Decoding_Error("cannot decode ECDSA parameters that are ImplicitCA"); + + throw Decoding_Error("encountered unexpected when trying to decode domain parameters"); + } + +bool operator==(EC_Domain_Params const& lhs, EC_Domain_Params const& rhs) + { + return ((lhs.get_curve() == rhs.get_curve()) && + (lhs.get_base_point() == rhs.get_base_point()) && + (lhs.get_order() == rhs.get_order()) && + (lhs.get_cofactor() == rhs.get_cofactor())); + } + +} + diff --git a/botan/src/pubkey/ec_dompar/ec_dompar.h b/botan/src/pubkey/ec_dompar/ec_dompar.h new file mode 100644 index 0000000..47971d8 --- /dev/null +++ b/botan/src/pubkey/ec_dompar/ec_dompar.h @@ -0,0 +1,121 @@ +/* +* ECDSA Domain Parameters +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECC_DOMAIN_PARAMETERS_H__ +#define BOTAN_ECC_DOMAIN_PARAMETERS_H__ + +#include <botan/point_gfp.h> +#include <botan/gfp_element.h> +#include <botan/curve_gfp.h> +#include <botan/bigint.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/alg_id.h> +#include <botan/pubkey_enums.h> + +namespace Botan { + +/** +* This class represents elliptic curce domain parameters +*/ +class BOTAN_DLL EC_Domain_Params + { + public: + + /** + * Construct Domain paramers from specified parameters + * @param curve elliptic curve + * @param base_point a base point + * @param order the order of the base point + * @param cofactor the cofactor + */ + EC_Domain_Params(const CurveGFp& curve, + const PointGFp& base_point, + const BigInt& order, + const BigInt& cofactor); + + /** + * Return domain parameter curve + * @result domain parameter curve + */ + const CurveGFp& get_curve() const + { + return m_curve; + } + + /** + * Return domain parameter curve + * @result domain parameter curve + */ + const PointGFp& get_base_point() const + { + return m_base_point; + } + + /** + * Return the order of the base point + * @result order of the base point + */ + const BigInt& get_order() const + { + return m_order; + } + + /** + * Return the cofactor + * @result the cofactor + */ + const BigInt& get_cofactor() const + { + return m_cofactor; + } + + /** + * Return the OID of these domain parameters + * @result the OID + */ + std::string get_oid() const { return m_oid; } + + private: + friend EC_Domain_Params get_EC_Dom_Pars_by_oid(std::string oid); + + CurveGFp m_curve; + PointGFp m_base_point; + BigInt m_order; + BigInt m_cofactor; + std::string m_oid; + }; + +bool operator==(EC_Domain_Params const& lhs, EC_Domain_Params const& rhs); + +inline bool operator!=(const EC_Domain_Params& lhs, + const EC_Domain_Params& rhs) + { + return !(lhs == rhs); + } + +enum EC_dompar_enc { ENC_EXPLICIT = 0, ENC_IMPLICITCA = 1, ENC_OID = 2 }; + +SecureVector<byte> encode_der_ec_dompar(EC_Domain_Params const& dom_pars, + EC_dompar_enc enc_type); + +EC_Domain_Params decode_ber_ec_dompar(SecureVector<byte> const& encoded); + +/** +* Factory function, the only way to obtain EC domain parameters with +* an OID. The demanded OID has to be registered in the InSiTo +* configuration. Consult the file ec_dompar.cpp for the default +* configuration. +* @param oid the oid of the demanded EC domain parameters +* @result the EC domain parameters associated with the OID +*/ +EC_Domain_Params get_EC_Dom_Pars_by_oid(std::string oid); + +} + +#endif diff --git a/botan/src/pubkey/ec_dompar/info.txt b/botan/src/pubkey/ec_dompar/info.txt new file mode 100644 index 0000000..2127837 --- /dev/null +++ b/botan/src/pubkey/ec_dompar/info.txt @@ -0,0 +1,18 @@ +realname "ECC Domain Parameters" + +define ECC_DOMAIN_PARAMATERS + +load_on auto + +<add> +ec_dompar.cpp +ec_dompar.h +</add> + +<requires> +asn1 +bigint +filters +gfpmath +hex +</requires> diff --git a/botan/src/pubkey/ecc_key/ecc_key.cpp b/botan/src/pubkey/ecc_key/ecc_key.cpp new file mode 100644 index 0000000..615efec --- /dev/null +++ b/botan/src/pubkey/ecc_key/ecc_key.cpp @@ -0,0 +1,269 @@ +/* +* ECC Key implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* Falko Strenzke, FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/ecc_key.h> +#include <botan/x509_key.h> +#include <botan/numthry.h> +#include <botan/util.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/secmem.h> +#include <botan/point_gfp.h> + +namespace Botan { + +/* +* EC_PublicKey +*/ +void EC_PublicKey::affirm_init() const // virtual + { + if((mp_dom_pars.get() == 0) || (mp_public_point.get() == 0)) + throw Invalid_State("cannot use uninitialized EC_Key"); + } + +const EC_Domain_Params& EC_PublicKey::domain_parameters() const + { + if(!mp_dom_pars.get()) + throw Invalid_State("EC_PublicKey::domain_parameters(): " + "ec domain parameters are not yet set"); + + return *mp_dom_pars; + } + +const PointGFp& EC_PublicKey::public_point() const + { + if(!mp_public_point.get()) + throw Invalid_State("EC_PublicKey::public_point(): public point not set"); + + return *mp_public_point; + } + +bool EC_PublicKey::domain_parameters_set() + { + return mp_dom_pars.get(); + } + +void EC_PublicKey::X509_load_hook() + { + try + { + // the base point is checked to be on curve already when decoding it + affirm_init(); + mp_public_point->check_invariants(); + } + catch(Illegal_Point) + { + throw Decoding_Error("decoded public point was found not to lie on curve"); + } + } + +X509_Encoder* EC_PublicKey::x509_encoder() const + { + class EC_Key_Encoder : public X509_Encoder + { + public: + AlgorithmIdentifier alg_id() const + { + key->affirm_init(); + + SecureVector<byte> params = + encode_der_ec_dompar(key->domain_parameters(), key->m_param_enc); + + return AlgorithmIdentifier(key->get_oid(), params); + } + + MemoryVector<byte> key_bits() const + { + key->affirm_init(); + return EC2OSP(*(key->mp_public_point), PointGFp::COMPRESSED); + } + + EC_Key_Encoder(const EC_PublicKey* k): key(k) {} + private: + const EC_PublicKey* key; + }; + + return new EC_Key_Encoder(this); + } + +X509_Decoder* EC_PublicKey::x509_decoder() + { + class EC_Key_Decoder : public X509_Decoder + { + public: + void alg_id(const AlgorithmIdentifier& alg_id) + { + key->mp_dom_pars.reset(new EC_Domain_Params(decode_ber_ec_dompar(alg_id.parameters))); + } + + void key_bits(const MemoryRegion<byte>& bits) + { + key->mp_public_point.reset( + new PointGFp( + OS2ECP(bits, key->domain_parameters().get_curve()) + )); + + key->X509_load_hook(); + } + + EC_Key_Decoder(EC_PublicKey* k): key(k) {} + private: + EC_PublicKey* key; + }; + + return new EC_Key_Decoder(this); + } + +void EC_PublicKey::set_parameter_encoding(EC_dompar_enc type) + { + if((type != ENC_EXPLICIT) && (type != ENC_IMPLICITCA) && (type != ENC_OID)) + throw Invalid_Argument("Invalid encoding type for EC-key object specified"); + + affirm_init(); + + if((type == ENC_OID) && (mp_dom_pars->get_oid() == "")) + throw Invalid_Argument("Invalid encoding type ENC_OID specified for " + "EC-key object whose corresponding domain " + "parameters are without oid"); + + m_param_enc = type; + } + +/******************************** +* EC_PrivateKey +********************************/ +void EC_PrivateKey::affirm_init() const // virtual + { + if(m_private_value == 0) + throw Invalid_State("cannot use EC_PrivateKey when private key is uninitialized"); + + EC_PublicKey::affirm_init(); + } + +const BigInt& EC_PrivateKey::private_value() const + { + if(m_private_value == 0) + throw Invalid_State("cannot use EC_PrivateKey when private key is uninitialized"); + + return m_private_value; + } + +/** +* EC_PrivateKey generator +**/ +void EC_PrivateKey::generate_private_key(RandomNumberGenerator& rng) + { + if(mp_dom_pars.get() == 0) + { + throw Invalid_State("cannot generate private key when domain parameters are not set"); + } + + BigInt tmp_private_value(0); + tmp_private_value = BigInt::random_integer(rng, 1, mp_dom_pars->get_order()); + mp_public_point = std::auto_ptr<PointGFp>( new PointGFp (mp_dom_pars->get_base_point())); + mp_public_point->mult_this_secure(tmp_private_value, + mp_dom_pars->get_order(), + mp_dom_pars->get_order()-1); + + //assert(mp_public_point.get() != 0); + tmp_private_value.swap(m_private_value); + } + +/** +* Return the PKCS #8 public key encoder +**/ +PKCS8_Encoder* EC_PrivateKey::pkcs8_encoder() const + { + class EC_Key_Encoder : public PKCS8_Encoder + { + public: + AlgorithmIdentifier alg_id() const + { + key->affirm_init(); + + SecureVector<byte> params = + encode_der_ec_dompar(key->domain_parameters(), ENC_EXPLICIT); + + return AlgorithmIdentifier(key->get_oid(), params); + } + + MemoryVector<byte> key_bits() const + { + key->affirm_init(); + SecureVector<byte> octstr_secret = + BigInt::encode_1363(key->m_private_value, key->m_private_value.bytes()); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(BigInt(1)) + .encode(octstr_secret, OCTET_STRING) + .end_cons() + .get_contents(); + } + + EC_Key_Encoder(const EC_PrivateKey* k): key(k) {} + private: + const EC_PrivateKey* key; + }; + + return new EC_Key_Encoder(this); + } + +/** +* Return the PKCS #8 public key decoder +*/ +PKCS8_Decoder* EC_PrivateKey::pkcs8_decoder(RandomNumberGenerator&) + { + class EC_Key_Decoder : public PKCS8_Decoder + { + public: + void alg_id(const AlgorithmIdentifier& alg_id) + { + key->mp_dom_pars.reset(new EC_Domain_Params(decode_ber_ec_dompar(alg_id.parameters))); + } + + void key_bits(const MemoryRegion<byte>& bits) + { + u32bit version; + SecureVector<byte> octstr_secret; + + BER_Decoder(bits) + .start_cons(SEQUENCE) + .decode(version) + .decode(octstr_secret, OCTET_STRING) + .verify_end() + .end_cons(); + + key->m_private_value = BigInt::decode(octstr_secret, octstr_secret.size()); + + if(version != 1) + throw Decoding_Error("Wrong PKCS #1 key format version for EC key"); + + key->PKCS8_load_hook(); + } + + EC_Key_Decoder(EC_PrivateKey* k): key(k) {} + private: + EC_PrivateKey* key; + }; + + return new EC_Key_Decoder(this); + } + +void EC_PrivateKey::PKCS8_load_hook(bool) + { + // we cannot use affirm_init() here because mp_public_point might still be null + if(mp_dom_pars.get() == 0) + throw Invalid_State("attempt to set public point for an uninitialized key"); + + mp_public_point.reset(new PointGFp(m_private_value * mp_dom_pars->get_base_point())); + mp_public_point->check_invariants(); + } + +} diff --git a/botan/src/pubkey/ecc_key/ecc_key.h b/botan/src/pubkey/ecc_key/ecc_key.h new file mode 100644 index 0000000..0ca9a0e --- /dev/null +++ b/botan/src/pubkey/ecc_key/ecc_key.h @@ -0,0 +1,154 @@ +/* +* ECDSA +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECC_PUBLIC_KEY_BASE_H__ +#define BOTAN_ECC_PUBLIC_KEY_BASE_H__ + +#include <botan/bigint.h> +#include <botan/curve_gfp.h> +#include <botan/pk_keys.h> +#include <botan/ec_dompar.h> +#include <botan/x509_key.h> +#include <botan/pkcs8.h> + +namespace Botan { + +/** +* This class represents abstract EC Public Keys. When encoding a key +* via an encoder that can be accessed via the corresponding member +* functions, the key will decide upon its internally stored encoding +* information whether to encode itself with or without domain +* parameters, or using the domain parameter oid. Furthermore, a public +* key without domain parameters can be decoded. In that case, it +* cannot be used for verification until its domain parameters are set +* by calling the corresponding member function. +*/ +class BOTAN_DLL EC_PublicKey : public virtual Public_Key + { + public: + + /** + * Tells whether this key knows his own domain parameters. + * @result true if the domain parameters are set, false otherwise + */ + bool domain_parameters_set(); + + /** + * Get the public point of this key. + * @throw Invalid_State is thrown if the + * domain parameters of this point are not set + * @result the public point of this key + */ + const PointGFp& public_point() const; + + /** + * Get the domain parameters of this key. + * @throw Invalid_State is thrown if the + * domain parameters of this point are not set + * @result the domain parameters of this key + */ + const EC_Domain_Params& domain_parameters() const; + + /** + * Set the domain parameter encoding to be used when encoding this key. + * @param enc the encoding to use + */ + void set_parameter_encoding(EC_dompar_enc enc); + + /** + * Get the domain parameter encoding to be used when encoding this key. + * @result the encoding to use + */ + inline int get_parameter_encoding() const + { + return m_param_enc; + } + + //ctors + EC_PublicKey() + : m_param_enc(ENC_EXPLICIT) + { + //assert(mp_dom_pars.get() == 0); + //assert(mp_public_point.get() == 0); + } + + /** + * Get an x509_encoder that can be used to encode this key. + * @result an x509_encoder for this key + */ + X509_Encoder* x509_encoder() const; + + /** + * Get an x509_decoder that can be used to decode a stored key into + * this key. + * @result an x509_decoder for this key + */ + X509_Decoder* x509_decoder(); + + /** + * Make sure that the public point and domain parameters of this key are set. + * @throw Invalid_State if either of the two data members is not set + */ + virtual void affirm_init() const; + + virtual ~EC_PublicKey() {} + protected: + virtual void X509_load_hook(); + + SecureVector<byte> m_enc_public_point; // stores the public point + + std::auto_ptr<EC_Domain_Params> mp_dom_pars; + std::auto_ptr<PointGFp> mp_public_point; + EC_dompar_enc m_param_enc; + }; + +/** +* This abstract class represents general EC Private Keys +*/ +class BOTAN_DLL EC_PrivateKey : public virtual EC_PublicKey, public virtual Private_Key + { + public: + + /** + * Get an PKCS#8 encoder that can be used to encoded this key. + * @result an PKCS#8 encoder for this key + */ + PKCS8_Encoder* pkcs8_encoder() const; + + /** + * Get an PKCS#8 decoder that can be used to decoded a stored key into + * this key. + * @result an PKCS#8 decoder for this key + */ + PKCS8_Decoder* pkcs8_decoder(RandomNumberGenerator&); + + /** + * Get the private key value of this key object. + * @result the private key value of this key object + */ + const BigInt& private_value() const; + + /** + * Make sure that the public key parts of this object are set + * (calls EC_PublicKey::affirm_init()) as well as the private key + * value. + * @throw Invalid_State if the above conditions are not satisfied + */ + virtual void affirm_init() const; + + virtual ~EC_PrivateKey() {} + protected: + virtual void PKCS8_load_hook(bool = false); + void generate_private_key(RandomNumberGenerator&); + BigInt m_private_value; + }; + +} + +#endif diff --git a/botan/src/pubkey/ecc_key/info.txt b/botan/src/pubkey/ecc_key/info.txt new file mode 100644 index 0000000..2a3c9a3 --- /dev/null +++ b/botan/src/pubkey/ecc_key/info.txt @@ -0,0 +1,20 @@ +realname "ECC Public Key" + +define ECC_PUBLIC_KEY_CRYPTO + +load_on auto + +<add> +ecc_key.cpp +ecc_key.h +</add> + +<requires> +alloc +asn1 +bigint +ec_dompar +gfpmath +numbertheory +pk_codecs +</requires> diff --git a/botan/src/pubkey/ecdsa/ecdsa.cpp b/botan/src/pubkey/ecdsa/ecdsa.cpp new file mode 100644 index 0000000..9640c63 --- /dev/null +++ b/botan/src/pubkey/ecdsa/ecdsa.cpp @@ -0,0 +1,230 @@ +/* +* ECDSA implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* 2007 Falko Strenzke, FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/ecdsa.h> +#include <botan/numthry.h> +#include <botan/util.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/secmem.h> +#include <botan/point_gfp.h> + +namespace Botan { + +ECDSA_PrivateKey::ECDSA_PrivateKey(RandomNumberGenerator& rng, + const EC_Domain_Params& dom_pars) + { + mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_pars)); + generate_private_key(rng); + + try + { + mp_public_point->check_invariants(); + } + catch(Illegal_Point& e) + { + throw Invalid_State("ECDSA key generation failed"); + } + + m_ecdsa_core = ECDSA_Core(*mp_dom_pars, m_private_value, *mp_public_point); + } + +/* +* ECDSA_PublicKey +*/ +void ECDSA_PublicKey::affirm_init() const // virtual + { + EC_PublicKey::affirm_init(); + } + +void ECDSA_PublicKey::set_domain_parameters(const EC_Domain_Params& dom_pars) + { + if(mp_dom_pars.get()) + { + // they are already set, we must ensure that they are equal to the arg + if(dom_pars != *mp_dom_pars.get()) + throw Invalid_Argument("EC_PublicKey::set_domain_parameters - cannot reset to a new value"); + + return; + } + + if(m_enc_public_point.size() == 0) + throw Invalid_State("EC_PublicKey::set_domain_parameters(): encoded public point isn't set"); + + // now try to decode the public key ... + PointGFp tmp_pp(OS2ECP(m_enc_public_point, dom_pars.get_curve())); + try + { + tmp_pp.check_invariants(); + } + catch(Illegal_Point e) + { + throw Invalid_State("EC_PublicKey::set_domain_parameters(): point does not lie on provided curve"); + } + + std::auto_ptr<EC_Domain_Params> p_tmp_pars(new EC_Domain_Params(dom_pars)); + ECDSA_Core tmp_ecdsa_core(*p_tmp_pars, BigInt(0), tmp_pp); + mp_public_point.reset(new PointGFp(tmp_pp)); + m_ecdsa_core = tmp_ecdsa_core; + mp_dom_pars = p_tmp_pars; + } + +void ECDSA_PublicKey::set_all_values(const ECDSA_PublicKey& other) + { + m_param_enc = other.m_param_enc; + m_ecdsa_core = other.m_ecdsa_core; + m_enc_public_point = other.m_enc_public_point; + if(other.mp_dom_pars.get()) + mp_dom_pars.reset(new EC_Domain_Params(other.domain_parameters())); + + if(other.mp_public_point.get()) + mp_public_point.reset(new PointGFp(other.public_point())); + } + +ECDSA_PublicKey::ECDSA_PublicKey(const ECDSA_PublicKey& other) + : Public_Key(), + EC_PublicKey(), + PK_Verifying_wo_MR_Key() + { + set_all_values(other); + } + +const ECDSA_PublicKey& ECDSA_PublicKey::operator=(const ECDSA_PublicKey& rhs) + { + set_all_values(rhs); + return *this; + } + +bool ECDSA_PublicKey::verify(const byte message[], + u32bit mess_len, + const byte signature[], + u32bit sig_len) const + { + affirm_init(); + + BigInt r, s; + + BER_Decoder(signature, sig_len) + .start_cons(SEQUENCE) + .decode(r) + .decode(s) + .end_cons() + .verify_end(); + + u32bit enc_len = std::max(r.bytes(), s.bytes()); + + SecureVector<byte> sv_plain_sig; + + sv_plain_sig.append(BigInt::encode_1363(r, enc_len)); + sv_plain_sig.append(BigInt::encode_1363(s, enc_len)); + + return m_ecdsa_core.verify(sv_plain_sig, sv_plain_sig.size(), + message, mess_len); + } + +ECDSA_PublicKey::ECDSA_PublicKey(const EC_Domain_Params& dom_par, + const PointGFp& public_point) + { + mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_par)); + mp_public_point = std::auto_ptr<PointGFp>(new PointGFp(public_point)); + m_param_enc = ENC_EXPLICIT; + m_ecdsa_core = ECDSA_Core(*mp_dom_pars, BigInt(0), *mp_public_point); + } + +void ECDSA_PublicKey::X509_load_hook() + { + EC_PublicKey::X509_load_hook(); + EC_PublicKey::affirm_init(); + m_ecdsa_core = ECDSA_Core ( *mp_dom_pars, BigInt ( 0 ), *mp_public_point ); + } + +u32bit ECDSA_PublicKey::max_input_bits() const + { + if(!mp_dom_pars.get()) + { + throw Invalid_State("ECDSA_PublicKey::max_input_bits(): domain parameters not set"); + } + return mp_dom_pars->get_order().bits(); + } + +/************************* +* ECDSA_PrivateKey +*************************/ +void ECDSA_PrivateKey::affirm_init() const // virtual + { + EC_PrivateKey::affirm_init(); + } + +void ECDSA_PrivateKey::PKCS8_load_hook(bool generated) + { + EC_PrivateKey::PKCS8_load_hook(generated); + EC_PrivateKey::affirm_init(); + m_ecdsa_core = ECDSA_Core(*mp_dom_pars, m_private_value, *mp_public_point); + } + +void ECDSA_PrivateKey::set_all_values(const ECDSA_PrivateKey& other) + { + m_private_value = other.m_private_value; + m_param_enc = other.m_param_enc; + m_ecdsa_core = other.m_ecdsa_core; + m_enc_public_point = other.m_enc_public_point; + + if(other.mp_dom_pars.get()) + mp_dom_pars.reset(new EC_Domain_Params(other.domain_parameters())); + + if(other.mp_public_point.get()) + mp_public_point.reset(new PointGFp(other.public_point())); + } + +ECDSA_PrivateKey::ECDSA_PrivateKey(ECDSA_PrivateKey const& other) + : Public_Key(), + EC_PublicKey(), + Private_Key(), + ECDSA_PublicKey(), + EC_PrivateKey(), + PK_Signing_Key() + { + set_all_values(other); + } + + +const ECDSA_PrivateKey& ECDSA_PrivateKey::operator=(const ECDSA_PrivateKey& rhs) + { + set_all_values(rhs); + return *this; + } + +SecureVector<byte> ECDSA_PrivateKey::sign(const byte message[], + u32bit mess_len, + RandomNumberGenerator& rng) const + { + affirm_init(); + + SecureVector<byte> sv_sig = m_ecdsa_core.sign(message, mess_len, rng); + + if(sv_sig.size() % 2 != 0) + throw Invalid_Argument("Erroneous length of signature"); + + u32bit rs_len = sv_sig.size() / 2; + SecureVector<byte> sv_r, sv_s; + sv_r.set(sv_sig.begin(), rs_len); + sv_s.set(&sv_sig[rs_len], rs_len); + + BigInt r = BigInt::decode(sv_r, sv_r.size()); + BigInt s = BigInt::decode(sv_s, sv_s.size()); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(r) + .encode(s) + .end_cons() + .get_contents(); + } + +} diff --git a/botan/src/pubkey/ecdsa/ecdsa.h b/botan/src/pubkey/ecdsa/ecdsa.h new file mode 100644 index 0000000..3794457 --- /dev/null +++ b/botan/src/pubkey/ecdsa/ecdsa.h @@ -0,0 +1,145 @@ +/* +* ECDSA +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECDSA_KEY_H__ +#define BOTAN_ECDSA_KEY_H__ + +#include <botan/ecc_key.h> +#include <botan/ecdsa_core.h> + +namespace Botan { + +/** +* This class represents ECDSA Public Keys. +*/ +class BOTAN_DLL ECDSA_PublicKey : public virtual EC_PublicKey, + public PK_Verifying_wo_MR_Key + { + public: + + /** + * Get this keys algorithm name. + * @result this keys algorithm name ("ECDSA") + */ + std::string algo_name() const { return "ECDSA"; } + + /** + * Get the maximum number of bits allowed to be fed to this key. + * This is the bitlength of the order of the base point. + + * @result the maximum number of input bits + */ + u32bit max_input_bits() const; + + /** + * Verify a message with this key. + * @param message the byte array containing the message + * @param mess_len the number of bytes in the message byte array + * @param signature the byte array containing the signature + * @param sig_len the number of bytes in the signature byte array + */ + bool verify(const byte message[], u32bit mess_len, + const byte signature[], u32bit sig_len) const; + + /** + * Default constructor. Use this one if you want to later fill + * this object with data from an encoded key. + */ + ECDSA_PublicKey() {} + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECDSA_PublicKey(const EC_Domain_Params& dom_par, + const PointGFp& public_point); // sets core + + ECDSA_PublicKey const& operator=(const ECDSA_PublicKey& rhs); + + ECDSA_PublicKey(const ECDSA_PublicKey& other); + + /** + * Set the domain parameters of this key. This function has to be + * used when a key encoded without domain parameters was decoded into + * this key. Otherwise it will not be able to verify a signature. + * @param dom_pars the domain_parameters associated with this key + * @throw Invalid_Argument if the point was found not to be satisfying the + * curve equation of the provided domain parameters + * or if this key already has domain parameters set + * and these are differing from those given as the parameter + */ + void set_domain_parameters(const EC_Domain_Params& dom_pars); + + /** + * Ensure that the public point and domain parameters of this key are set. + * @throw Invalid_State if either of the two data members is not set + */ + virtual void affirm_init() const; + + protected: + void X509_load_hook(); + virtual void set_all_values(const ECDSA_PublicKey& other); + + ECDSA_Core m_ecdsa_core; + }; + +/** +* This class represents ECDSA Private Keys +*/ +class BOTAN_DLL ECDSA_PrivateKey : public ECDSA_PublicKey, + public EC_PrivateKey, + public PK_Signing_Key + { + public: + //ctors + + /** + * Default constructor. Use this one if you want to later fill + * this object with data from an encoded key. + */ + ECDSA_PrivateKey() {} + + /** + * Generate a new private key + * @param the domain parameters to used for this key + */ + ECDSA_PrivateKey(RandomNumberGenerator& rng, + const EC_Domain_Params& domain); + + ECDSA_PrivateKey(const ECDSA_PrivateKey& other); + ECDSA_PrivateKey const& operator=(const ECDSA_PrivateKey& rhs); + + /** + * Sign a message with this key. + * @param message the byte array representing the message to be signed + * @param mess_len the length of the message byte array + * @result the signature + */ + + SecureVector<byte> sign(const byte message[], u32bit mess_len, + RandomNumberGenerator& rng) const; + + /** + * Make sure that the public key parts of this object are set + * (calls EC_PublicKey::affirm_init()) as well as the private key + * value. + * @throw Invalid_State if the above conditions are not satisfied + */ + virtual void affirm_init() const; + + protected: + virtual void set_all_values(const ECDSA_PrivateKey& other); + private: + void PKCS8_load_hook(bool = false); + }; + +} + +#endif diff --git a/botan/src/pubkey/ecdsa/ecdsa_core.cpp b/botan/src/pubkey/ecdsa/ecdsa_core.cpp new file mode 100644 index 0000000..93808cc --- /dev/null +++ b/botan/src/pubkey/ecdsa/ecdsa_core.cpp @@ -0,0 +1,55 @@ +/* +* ECDSA Core +* (C) 1999-2007 Jack Lloyd +* (C) 2007 FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/ecdsa_core.h> +#include <botan/numthry.h> +#include <botan/pk_engine.h> +#include <botan/parsing.h> +#include <algorithm> + +namespace Botan { + +/* +* ECDSA Operation +*/ +bool ECDSA_Core::verify(const byte signature[], u32bit sig_len, + const byte message[], u32bit mess_len) const + { + //assert(op.get()); + return op->verify(signature, sig_len, message, mess_len); + } + +SecureVector<byte> ECDSA_Core::sign(const byte message[], + u32bit mess_len, + RandomNumberGenerator& rng) const + { + //assert(op.get()); + return op->sign(message, mess_len, rng); + } + +ECDSA_Core& ECDSA_Core::operator=(const ECDSA_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + return (*this); + } + +ECDSA_Core::ECDSA_Core(const ECDSA_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + } + +ECDSA_Core::ECDSA_Core(EC_Domain_Params const& dom_pars, const BigInt& priv_key, PointGFp const& pub_key) + { + op = Engine_Core::ecdsa_op(dom_pars, priv_key, pub_key); + } + +} diff --git a/botan/src/pubkey/ecdsa/ecdsa_core.h b/botan/src/pubkey/ecdsa/ecdsa_core.h new file mode 100644 index 0000000..ceccc94 --- /dev/null +++ b/botan/src/pubkey/ecdsa/ecdsa_core.h @@ -0,0 +1,47 @@ +/* +* ECDSA Core +* (C) 1999-2007 Jack Lloyd +* (C) 2007 FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECDSA_CORE_H__ +#define BOTAN_ECDSA_CORE_H__ + +#include <botan/ecdsa_op.h> +#include <botan/blinding.h> +#include <botan/ec_dompar.h> + +namespace Botan { + +/* +* ECDSA Core +*/ +class BOTAN_DLL ECDSA_Core + { + public: + bool verify(const byte signature[], u32bit sig_len, + const byte message[], u32bit mess_len) const; + + SecureVector<byte> sign(const byte message[], u32bit mess_len, + RandomNumberGenerator& rng) const; + + ECDSA_Core& operator=(const ECDSA_Core&); + + ECDSA_Core() { op = 0; } + + ECDSA_Core(const ECDSA_Core&); + + ECDSA_Core(const EC_Domain_Params& dom_pars, + const BigInt& priv_key, + const PointGFp& pub_key); + + ~ECDSA_Core() { delete op; } + private: + ECDSA_Operation* op; + }; + +} + +#endif diff --git a/botan/src/pubkey/ecdsa/ecdsa_op.cpp b/botan/src/pubkey/ecdsa/ecdsa_op.cpp new file mode 100644 index 0000000..986043e --- /dev/null +++ b/botan/src/pubkey/ecdsa/ecdsa_op.cpp @@ -0,0 +1,129 @@ +/* +* ECDSA Operation +* (C) 2007 FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/ecdsa_op.h> +#include <botan/numthry.h> + +namespace Botan { + +bool Default_ECDSA_Op::verify(const byte signature[], u32bit sig_len, + const byte message[], u32bit mess_len) const + { + if(sig_len % 2 != 0) + throw Invalid_Argument("Erroneous length of signature"); + + //NOTE: it is not checked whether the public point is set + if(m_dom_pars.get_curve().get_p() == 0) + throw Internal_Error("domain parameters not set"); + + BigInt e(message, mess_len); + + u32bit rs_len = sig_len/2; + SecureVector<byte> sv_r; + SecureVector<byte> sv_s; + sv_r.set(signature, rs_len); + sv_s.set(signature+rs_len, rs_len); + BigInt r = BigInt::decode ( sv_r, sv_r.size()); + BigInt s = BigInt::decode (sv_s, sv_s.size()); + + if(r < 0 || r >= m_dom_pars.get_order()) + throw Invalid_Argument("r in ECDSA signature has an illegal value"); + + if(s < 0 || s >= m_dom_pars.get_order()) + throw Invalid_Argument("s in ECDSA signature has an illegal value"); + + BigInt w = inverse_mod(s, m_dom_pars.get_order()); + + PointGFp R = w*(e*m_dom_pars.get_base_point() + r*m_pub_key); + if(R.is_zero()) + return false; + + BigInt x = R.get_affine_x().get_value(); + bool result = (x % m_dom_pars.get_order() == r); + return result; + } + +SecureVector<byte> Default_ECDSA_Op::sign(const byte message[], + u32bit mess_len, + RandomNumberGenerator& rng) const + { + if(m_priv_key == 0) + throw Internal_Error("Default_ECDSA_Op::sign(): no private key"); + + if(m_dom_pars.get_curve().get_p() == 0) + throw Internal_Error("Default_ECDSA_Op::sign(): domain parameters not set"); + + BigInt e(message, mess_len); + + // generate k + BigInt k; + BigInt r(0); + const BigInt n(m_dom_pars.get_order()); + while(r == 0) + { + k = BigInt::random_integer(rng, 1, n); + + PointGFp k_times_P(m_dom_pars.get_base_point()); + k_times_P.mult_this_secure(k, n, n-1); + k_times_P.check_invariants(); + r = k_times_P.get_affine_x().get_value() % n; + } + BigInt k_inv = inverse_mod(k, n); + + // use randomization against attacks on s: + // a = k_inv * (r*(d + x) + e) mod n + // b = k_inv * r * x mod n + // s = a - b mod n + // where x is a random integer + +#if defined(CMS_RAND) + BigInt x = BigInt::random_integer(0, n); + BigInt s = m_priv_key + x; // obscure the secret from the beginning + // all following operations thus are randomized + s *= r; + s += e; + s *= k_inv; + s %= n; + + BigInt b = x; // again, start with the random number + b *= r; + b *= k_inv; + b %= n; + s -= b; // s = a - b + if(s <= 0) // s %= n + { + s += n; + } +#else // CMS_RAND + // no countermeasure here + BigInt s(r); + s *= m_priv_key; + s += e; + s *= k_inv; + s %= n; + +#endif // CMS_RAND + + SecureVector<byte> sv_r = BigInt::encode_1363 ( r, m_dom_pars.get_order().bytes() ); + SecureVector<byte> sv_s = BigInt::encode_1363 ( s, m_dom_pars.get_order().bytes() ); + + SecureVector<byte> result(sv_r); + result.append(sv_s); + return result; + } + +Default_ECDSA_Op::Default_ECDSA_Op(const EC_Domain_Params& dom_pars, const BigInt& priv_key, const PointGFp& pub_key) + : m_dom_pars(dom_pars), + m_pub_key(pub_key), + m_priv_key(priv_key) + { + + } + +} + diff --git a/botan/src/pubkey/ecdsa/ecdsa_op.h b/botan/src/pubkey/ecdsa/ecdsa_op.h new file mode 100644 index 0000000..25831a9 --- /dev/null +++ b/botan/src/pubkey/ecdsa/ecdsa_op.h @@ -0,0 +1,64 @@ +/* +* ECDSA Operations +* (C) 1999-2008 Jack Lloyd +* (C) 2007 FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECDSA_OPERATIONS_H__ +#define BOTAN_ECDSA_OPERATIONS_H__ + +#include <botan/ec_dompar.h> +#include <botan/rng.h> + +namespace Botan { + +/* +* ECDSA Operation +*/ +class BOTAN_DLL ECDSA_Operation + { + public: + virtual bool verify(const byte sig[], u32bit sig_len, + const byte msg[], u32bit msg_len) const = 0; + + virtual SecureVector<byte> sign(const byte message[], + u32bit mess_len, + RandomNumberGenerator&) const = 0; + + virtual ECDSA_Operation* clone() const = 0; + + virtual ~ECDSA_Operation() {} + }; + + +/* +* Default ECDSA operation +*/ +class BOTAN_DLL Default_ECDSA_Op : public ECDSA_Operation + { + public: + bool verify(const byte signature[], u32bit sig_len, + const byte message[], u32bit mess_len) const; + + SecureVector<byte> sign(const byte message[], u32bit mess_len, + RandomNumberGenerator& rng) const; + + ECDSA_Operation* clone() const + { + return new Default_ECDSA_Op(*this); + } + + Default_ECDSA_Op(const EC_Domain_Params& dom_pars, + const BigInt& priv_key, + const PointGFp& pub_key); + private: + EC_Domain_Params m_dom_pars; + PointGFp m_pub_key; + BigInt m_priv_key; + }; + +} + +#endif diff --git a/botan/src/pubkey/ecdsa/info.txt b/botan/src/pubkey/ecdsa/info.txt new file mode 100644 index 0000000..743440f --- /dev/null +++ b/botan/src/pubkey/ecdsa/info.txt @@ -0,0 +1,25 @@ +realname "ECDSA" + +define ECDSA + +load_on auto + +<add> +ecdsa.cpp +ecdsa.h +ecdsa_core.cpp +ecdsa_core.h +ecdsa_op.cpp +ecdsa_op.h +</add> + +<requires> +alloc +asn1 +ec_dompar +ecc_key +gfpmath +libstate +numbertheory +rng +</requires> diff --git a/botan/src/pubkey/eckaeg/eckaeg.cpp b/botan/src/pubkey/eckaeg/eckaeg.cpp new file mode 100644 index 0000000..b8ff75d --- /dev/null +++ b/botan/src/pubkey/eckaeg/eckaeg.cpp @@ -0,0 +1,152 @@ +/* +* ECKAEG implemenation +* (C) 2007 Manuel Hartl, FlexSecure GmbH +* 2007 Falko Strenzke, FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/eckaeg.h> +#include <botan/numthry.h> +#include <botan/util.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/secmem.h> +#include <botan/point_gfp.h> + +namespace Botan { + +/********************************* +* ECKAEG_PublicKey +*********************************/ + +void ECKAEG_PublicKey::affirm_init() const // virtual + { + EC_PublicKey::affirm_init(); + } + +void ECKAEG_PublicKey::set_all_values(ECKAEG_PublicKey const& other) + { + m_param_enc = other.m_param_enc; + m_eckaeg_core = other.m_eckaeg_core; + m_enc_public_point = other.m_enc_public_point; + if(other.mp_dom_pars.get()) + { + mp_dom_pars.reset(new EC_Domain_Params(*(other.mp_dom_pars))); + } + if(other.mp_public_point.get()) + { + mp_public_point.reset(new PointGFp(*(other.mp_public_point))); + } + } + +ECKAEG_PublicKey::ECKAEG_PublicKey(ECKAEG_PublicKey const& other) + : Public_Key(), + EC_PublicKey() + { + set_all_values(other); + } + +ECKAEG_PublicKey const& ECKAEG_PublicKey::operator=(ECKAEG_PublicKey const& rhs) + { + set_all_values(rhs); + return *this; + } + +void ECKAEG_PublicKey::X509_load_hook() + { + EC_PublicKey::X509_load_hook(); + EC_PublicKey::affirm_init(); + m_eckaeg_core = ECKAEG_Core(*mp_dom_pars, BigInt(0), *mp_public_point); + } + +ECKAEG_PublicKey::ECKAEG_PublicKey(EC_Domain_Params const& dom_par, PointGFp const& public_point) + { + mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_par)); + mp_public_point = std::auto_ptr<PointGFp>(new PointGFp(public_point)); + if(mp_public_point->get_curve() != mp_dom_pars->get_curve()) + { + throw Invalid_Argument("ECKAEG_PublicKey(): curve of arg. point and curve of arg. domain parameters are different"); + } + EC_PublicKey::affirm_init(); + m_eckaeg_core = ECKAEG_Core(*mp_dom_pars, BigInt(0), *mp_public_point); + } + +/********************************* +* ECKAEG_PrivateKey +*********************************/ +void ECKAEG_PrivateKey::affirm_init() const // virtual + { + EC_PrivateKey::affirm_init(); + } + +void ECKAEG_PrivateKey::PKCS8_load_hook(bool generated) + { + EC_PrivateKey::PKCS8_load_hook(generated); + EC_PrivateKey::affirm_init(); + m_eckaeg_core = ECKAEG_Core(*mp_dom_pars, m_private_value, *mp_public_point); + } + +void ECKAEG_PrivateKey::set_all_values(ECKAEG_PrivateKey const& other) + { + m_private_value = other.m_private_value; + m_param_enc = other.m_param_enc; + m_eckaeg_core = other.m_eckaeg_core; + m_enc_public_point = other.m_enc_public_point; + if(other.mp_dom_pars.get()) + { + mp_dom_pars.reset(new EC_Domain_Params(*(other.mp_dom_pars))); + } + if(other.mp_public_point.get()) + { + mp_public_point.reset(new PointGFp(*(other.mp_public_point))); + } + } + +ECKAEG_PrivateKey::ECKAEG_PrivateKey(ECKAEG_PrivateKey const& other) + : Public_Key(), + EC_PublicKey(), + Private_Key(), + ECKAEG_PublicKey(), + EC_PrivateKey(), + PK_Key_Agreement_Key() + { + set_all_values(other); + } + +ECKAEG_PrivateKey const& ECKAEG_PrivateKey::operator= (ECKAEG_PrivateKey const& rhs) + { + set_all_values(rhs); + return *this; + } + +MemoryVector<byte> ECKAEG_PrivateKey::public_value() const + { + return EC2OSP(public_point(), PointGFp::UNCOMPRESSED); + } + +/** +* Derive a key +*/ +SecureVector<byte> ECKAEG_PrivateKey::derive_key(const byte key[], + u32bit key_len) const + { + MemoryVector<byte> key_x(key, key_len); // FIXME: nasty/slow + PointGFp point = OS2ECP(key_x, public_point().get_curve()); + + return m_eckaeg_core.agree(point); + } + +/** +* Derive a key +*/ +SecureVector<byte> ECKAEG_PrivateKey::derive_key(const ECKAEG_PublicKey& key) const + { + affirm_init(); + key.affirm_init(); + + return m_eckaeg_core.agree(key.public_point()); + } + +} diff --git a/botan/src/pubkey/eckaeg/eckaeg.h b/botan/src/pubkey/eckaeg/eckaeg.h new file mode 100644 index 0000000..31b6574 --- /dev/null +++ b/botan/src/pubkey/eckaeg/eckaeg.h @@ -0,0 +1,137 @@ +/* +* ECKAEG +* (C) 2007 Falko Strenzke, FlexSecure GmbH +* Manuel Hartl, FlexSecure GmbH +* (C) 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECKAEG_KEY_H__ +#define BOTAN_ECKAEG_KEY_H__ + +#include <botan/ecc_key.h> +#include <botan/eckaeg_core.h> + +namespace Botan { + +/** +* This class represents ECKAEG Public Keys. +*/ +class BOTAN_DLL ECKAEG_PublicKey : public virtual EC_PublicKey + { + public: + + /** + * Default constructor. Use this one if you want to later fill + * this object with data from an encoded key. + */ + ECKAEG_PublicKey() {} + + /** + * Construct a public key from a given public point. + * @param dom_par the domain parameters associated with this key + * @param public_point the public point defining this key + */ + ECKAEG_PublicKey(const EC_Domain_Params& dom_par, + const PointGFp& public_point); + + /** + * Get this keys algorithm name. + * @result this keys algorithm name + */ + std::string algo_name() const { return "ECKAEG"; } + + /** + * Get the maximum number of bits allowed to be fed to this key. + * This is the bitlength of the order of the base point. + + * @result the maximum number of input bits + */ + u32bit max_input_bits() const + { + if(!mp_dom_pars.get()) + throw Invalid_State("ECKAEG_PublicKey::max_input_bits(): domain parameters not set"); + + return mp_dom_pars->get_order().bits(); + } + + ECKAEG_PublicKey(ECKAEG_PublicKey const& other); + ECKAEG_PublicKey const& operator= (ECKAEG_PublicKey const& rhs); + + /** + * Make sure that the public point and domain parameters of this + * key are set. + * @throw Invalid_State if either of the two data members is not set + */ + virtual void affirm_init() const; + + protected: + void X509_load_hook(); + virtual void set_all_values(const ECKAEG_PublicKey& other); + + ECKAEG_Core m_eckaeg_core; + }; + +/** +* This class represents ECKAEG Private Keys. +*/ +class BOTAN_DLL ECKAEG_PrivateKey : public ECKAEG_PublicKey, + public EC_PrivateKey, + public PK_Key_Agreement_Key + { + public: + + /** + * Generate a new private key + * @param the domain parameters to used for this key + */ + ECKAEG_PrivateKey(RandomNumberGenerator& rng, + const EC_Domain_Params& dom_pars) + { + mp_dom_pars = std::auto_ptr<EC_Domain_Params>(new EC_Domain_Params(dom_pars)); + generate_private_key(rng); + mp_public_point->check_invariants(); + m_eckaeg_core = ECKAEG_Core(*mp_dom_pars, m_private_value, *mp_public_point); + } + + /** + * Default constructor. Use this one if you want to later fill this object with data + * from an encoded key. + */ + ECKAEG_PrivateKey() {} + ECKAEG_PrivateKey(ECKAEG_PrivateKey const& other); + ECKAEG_PrivateKey const& operator=(ECKAEG_PrivateKey const& rhs); + + MemoryVector<byte> public_value() const; + + void PKCS8_load_hook(bool = false); + + /** + * Derive a shared key with the other partys public key. + * @param key the other partys public key + * @param key_len the other partys public key + */ + SecureVector<byte> derive_key(const byte key[], u32bit key_len) const; + + /** + * Derive a shared key with the other partys public key. + * @param other the other partys public key + */ + SecureVector<byte> derive_key(const ECKAEG_PublicKey& other) const; + + /** + * Make sure that the public key parts of this object are set + * (calls EC_PublicKey::affirm_init()) as well as the private key + * value. + * @throw Invalid_State if the above conditions are not satisfied + */ + virtual void affirm_init() const; + + protected: + virtual void set_all_values(const ECKAEG_PrivateKey& other); + }; + +} + +#endif diff --git a/botan/src/pubkey/eckaeg/eckaeg_core.cpp b/botan/src/pubkey/eckaeg/eckaeg_core.cpp new file mode 100644 index 0000000..dc89a87 --- /dev/null +++ b/botan/src/pubkey/eckaeg/eckaeg_core.cpp @@ -0,0 +1,59 @@ +/* +* ECKAEG Core +* (C) 1999-2007 Jack Lloyd +* (C) 2007 FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/eckaeg_core.h> +#include <botan/numthry.h> +#include <botan/pk_engine.h> +#include <botan/parsing.h> +#include <algorithm> + +namespace Botan { + +/* +* ECKAEG_Core Constructor +*/ +ECKAEG_Core::ECKAEG_Core(const EC_Domain_Params& dom_pars, + const BigInt& priv_key, + const PointGFp& pub_key) + { + op = Engine_Core::eckaeg_op(dom_pars, priv_key, pub_key); + } + +/* +* ECKAEG_Core Copy Constructor +*/ +ECKAEG_Core::ECKAEG_Core(const ECKAEG_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + } + +/* +* ECKAEG_Core Assignment Operator +*/ +ECKAEG_Core& ECKAEG_Core::operator=(const ECKAEG_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + return (*this); + } + +/* +* ECKAEG Operation +*/ +SecureVector<byte> ECKAEG_Core::agree(const PointGFp& otherKey) const + { + //assert(op.get()); + return op->agree(otherKey); + } + +} diff --git a/botan/src/pubkey/eckaeg/eckaeg_core.h b/botan/src/pubkey/eckaeg/eckaeg_core.h new file mode 100644 index 0000000..d632c94 --- /dev/null +++ b/botan/src/pubkey/eckaeg/eckaeg_core.h @@ -0,0 +1,44 @@ +/* +* ECKAEG Core +* (C) 1999-2007 Jack Lloyd +* (C) 2007 FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECKAEG_CORE_H__ +#define BOTAN_ECKAEG_CORE_H__ + +#include <botan/eckaeg_op.h> +#include <botan/blinding.h> +#include <botan/ec_dompar.h> + +namespace Botan { + +/* +* ECKAEG Core +*/ +class BOTAN_DLL ECKAEG_Core + { + public: + SecureVector<byte> agree(const PointGFp&) const; + + ECKAEG_Core& operator=(const ECKAEG_Core&); + + ECKAEG_Core() { op = 0; } + + ECKAEG_Core(const ECKAEG_Core&); + + ECKAEG_Core(const EC_Domain_Params& dom_pars, + const BigInt& priv_key, + PointGFp const& pub_key); + + ~ECKAEG_Core() { delete op; } + private: + ECKAEG_Operation* op; + Blinder blinder; + }; + +} + +#endif diff --git a/botan/src/pubkey/eckaeg/eckaeg_op.cpp b/botan/src/pubkey/eckaeg/eckaeg_op.cpp new file mode 100644 index 0000000..0cb5c3d --- /dev/null +++ b/botan/src/pubkey/eckaeg/eckaeg_op.cpp @@ -0,0 +1,36 @@ +/* +* ECKAEG Operation +* (C) 2007 FlexSecure GmbH +* 2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/eckaeg_op.h> +#include <botan/numthry.h> + +namespace Botan { + +Default_ECKAEG_Op::Default_ECKAEG_Op(const EC_Domain_Params& dom_pars, + const BigInt& priv_key, + const PointGFp& pub_key) + : m_dom_pars(dom_pars), + m_pub_key(pub_key), + m_priv_key(priv_key) + { + } + +SecureVector<byte> Default_ECKAEG_Op::agree(const PointGFp& i) const + { + BigInt cofactor(m_dom_pars.get_cofactor()); + BigInt n = m_dom_pars.get_order(); + BigInt l(inverse_mod(cofactor,n)); // l=h^-1 mod n + PointGFp Q(cofactor*i); // q = h*Pb + PointGFp S(Q); + BigInt group_order = m_dom_pars.get_cofactor() * n; + S.mult_this_secure((m_priv_key*l)%n, group_order, n-1); + S.check_invariants(); + return FE2OSP(S.get_affine_x()); // fe2os(xs) + } + +} diff --git a/botan/src/pubkey/eckaeg/eckaeg_op.h b/botan/src/pubkey/eckaeg/eckaeg_op.h new file mode 100644 index 0000000..27cf4f3 --- /dev/null +++ b/botan/src/pubkey/eckaeg/eckaeg_op.h @@ -0,0 +1,49 @@ +/* +* ECKAEG Operations +* (C) 1999-2008 Jack Lloyd +* 2007 FlexSecure GmbH +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ECKAEG_OPERATIONS_H__ +#define BOTAN_ECKAEG_OPERATIONS_H__ + +#include <botan/ec_dompar.h> + +namespace Botan { + +/* +* ECKAEG Operation +*/ +class BOTAN_DLL ECKAEG_Operation + { + public: + virtual SecureVector<byte> agree(const PointGFp&) const = 0; + virtual ECKAEG_Operation* clone() const = 0; + virtual ~ECKAEG_Operation() {} + }; + +/* +* Default ECKAEG operation +*/ +class BOTAN_DLL Default_ECKAEG_Op : public ECKAEG_Operation + { + public: + SecureVector<byte> agree(const PointGFp& i) const; + + ECKAEG_Operation* clone() const { return new Default_ECKAEG_Op(*this); } + + Default_ECKAEG_Op(const EC_Domain_Params& dom_pars, + const BigInt& priv_key, + const PointGFp& pub_key); + private: + EC_Domain_Params m_dom_pars; + PointGFp m_pub_key; + BigInt m_priv_key; + }; + + +} + +#endif diff --git a/botan/src/pubkey/eckaeg/info.txt b/botan/src/pubkey/eckaeg/info.txt new file mode 100644 index 0000000..6b78f7d --- /dev/null +++ b/botan/src/pubkey/eckaeg/info.txt @@ -0,0 +1,24 @@ +realname "ECKAEG" + +define ECKAEG + +load_on auto + +<add> +eckaeg.cpp +eckaeg.h +eckaeg_core.cpp +eckaeg_core.h +eckaeg_op.cpp +eckaeg_op.h +</add> + +<requires> +alloc +asn1 +ec_dompar +ecc_key +gfpmath +libstate +numbertheory +</requires> diff --git a/botan/src/pubkey/elgamal/elg_core.cpp b/botan/src/pubkey/elgamal/elg_core.cpp new file mode 100644 index 0000000..8b8c8f5 --- /dev/null +++ b/botan/src/pubkey/elgamal/elg_core.cpp @@ -0,0 +1,97 @@ +/* +* ElGamal Core +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/elg_core.h> +#include <botan/numthry.h> +#include <botan/pk_engine.h> +#include <botan/parsing.h> +#include <algorithm> + +namespace Botan { + +namespace { + +const u32bit BLINDING_BITS = BOTAN_PRIVATE_KEY_OP_BLINDING_BITS; + +} + +/* +* ELG_Core Constructor +*/ +ELG_Core::ELG_Core(const DL_Group& group, const BigInt& y) + { + op = Engine_Core::elg_op(group, y, 0); + p_bytes = 0; + } + +/* +* ELG_Core Constructor +*/ +ELG_Core::ELG_Core(RandomNumberGenerator& rng, + const DL_Group& group, const BigInt& y, const BigInt& x) + { + op = Engine_Core::elg_op(group, y, x); + + const BigInt& p = group.get_p(); + p_bytes = p.bytes(); + + if(BLINDING_BITS) + { + BigInt k(rng, std::min(p.bits()-1, BLINDING_BITS)); + blinder = Blinder(k, power_mod(k, x, p), p); + } + } + +/* +* ELG_Core Copy Constructor +*/ +ELG_Core::ELG_Core(const ELG_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + p_bytes = core.p_bytes; + } + +/* +* ELG_Core Assignment Operator +*/ +ELG_Core& ELG_Core::operator=(const ELG_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + p_bytes = core.p_bytes; + return (*this); + } + +/* +* ElGamal Encrypt Operation +*/ +SecureVector<byte> ELG_Core::encrypt(const byte in[], u32bit length, + const BigInt& k) const + { + return op->encrypt(in, length, k); + } + +/* +* ElGamal Decrypt Operation +*/ +SecureVector<byte> ELG_Core::decrypt(const byte in[], u32bit length) const + { + if(length != 2*p_bytes) + throw Invalid_Argument("ELG_Core::decrypt: Invalid message"); + + BigInt a(in, p_bytes); + BigInt b(in + p_bytes, p_bytes); + + return BigInt::encode(blinder.unblind(op->decrypt(blinder.blind(a), b))); + } + +} diff --git a/botan/src/pubkey/elgamal/elg_core.h b/botan/src/pubkey/elgamal/elg_core.h new file mode 100644 index 0000000..a7768a6 --- /dev/null +++ b/botan/src/pubkey/elgamal/elg_core.h @@ -0,0 +1,44 @@ +/* +* ElGamal Core +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ELGAMAL_CORE_H__ +#define BOTAN_ELGAMAL_CORE_H__ + +#include <botan/elg_op.h> +#include <botan/blinding.h> +#include <botan/dl_group.h> + +namespace Botan { + +/* +* ElGamal Core +*/ +class BOTAN_DLL ELG_Core + { + public: + SecureVector<byte> encrypt(const byte[], u32bit, const BigInt&) const; + SecureVector<byte> decrypt(const byte[], u32bit) const; + + ELG_Core& operator=(const ELG_Core&); + + ELG_Core() { op = 0; } + ELG_Core(const ELG_Core&); + + ELG_Core(const DL_Group&, const BigInt&); + ELG_Core(RandomNumberGenerator&, const DL_Group&, + const BigInt&, const BigInt&); + + ~ELG_Core() { delete op; } + private: + ELG_Operation* op; + Blinder blinder; + u32bit p_bytes; + }; + +} + +#endif diff --git a/botan/src/pubkey/elgamal/elg_op.cpp b/botan/src/pubkey/elgamal/elg_op.cpp new file mode 100644 index 0000000..1e476ab --- /dev/null +++ b/botan/src/pubkey/elgamal/elg_op.cpp @@ -0,0 +1,56 @@ +/* +* ElGamal Operations +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/elg_op.h> + +namespace Botan { + +/* +* Default_ELG_Op Constructor +*/ +Default_ELG_Op::Default_ELG_Op(const DL_Group& group, const BigInt& y, + const BigInt& x) : p(group.get_p()) + { + powermod_g_p = Fixed_Base_Power_Mod(group.get_g(), p); + powermod_y_p = Fixed_Base_Power_Mod(y, p); + mod_p = Modular_Reducer(p); + + if(x != 0) + powermod_x_p = Fixed_Exponent_Power_Mod(x, p); + } + +/* +* Default ElGamal Encrypt Operation +*/ +SecureVector<byte> Default_ELG_Op::encrypt(const byte in[], u32bit length, + const BigInt& k) const + { + BigInt m(in, length); + if(m >= p) + throw Invalid_Argument("Default_ELG_Op::encrypt: Input is too large"); + + BigInt a = powermod_g_p(k); + BigInt b = mod_p.multiply(m, powermod_y_p(k)); + + SecureVector<byte> output(2*p.bytes()); + a.binary_encode(output + (p.bytes() - a.bytes())); + b.binary_encode(output + output.size() / 2 + (p.bytes() - b.bytes())); + return output; + } + +/* +* Default ElGamal Decrypt Operation +*/ +BigInt Default_ELG_Op::decrypt(const BigInt& a, const BigInt& b) const + { + if(a >= p || b >= p) + throw Invalid_Argument("Default_ELG_Op: Invalid message"); + + return mod_p.multiply(b, inverse_mod(powermod_x_p(a), p)); + } + +} diff --git a/botan/src/pubkey/elgamal/elg_op.h b/botan/src/pubkey/elgamal/elg_op.h new file mode 100644 index 0000000..39ed897 --- /dev/null +++ b/botan/src/pubkey/elgamal/elg_op.h @@ -0,0 +1,52 @@ +/* +* ElGamal Operations +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ELGAMAL_OPS_H__ +#define BOTAN_ELGAMAL_OPS_H__ + +#include <botan/pow_mod.h> +#include <botan/numthry.h> +#include <botan/reducer.h> +#include <botan/dl_group.h> + +namespace Botan { + +/* +* ElGamal Operation +*/ +class BOTAN_DLL ELG_Operation + { + public: + virtual SecureVector<byte> encrypt(const byte[], u32bit, + const BigInt&) const = 0; + virtual BigInt decrypt(const BigInt&, const BigInt&) const = 0; + virtual ELG_Operation* clone() const = 0; + virtual ~ELG_Operation() {} + }; + +/* +* Botan's Default ElGamal Operation +*/ +class BOTAN_DLL Default_ELG_Op : public ELG_Operation + { + public: + SecureVector<byte> encrypt(const byte[], u32bit, const BigInt&) const; + BigInt decrypt(const BigInt&, const BigInt&) const; + + ELG_Operation* clone() const { return new Default_ELG_Op(*this); } + + Default_ELG_Op(const DL_Group&, const BigInt&, const BigInt&); + private: + const BigInt p; + Fixed_Base_Power_Mod powermod_g_p, powermod_y_p; + Fixed_Exponent_Power_Mod powermod_x_p; + Modular_Reducer mod_p; + }; + +} + +#endif diff --git a/botan/src/pubkey/elgamal/elgamal.cpp b/botan/src/pubkey/elgamal/elgamal.cpp new file mode 100644 index 0000000..1f79df5 --- /dev/null +++ b/botan/src/pubkey/elgamal/elgamal.cpp @@ -0,0 +1,124 @@ +/* +* ElGamal +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/elgamal.h> +#include <botan/numthry.h> +#include <botan/keypair.h> +#include <botan/look_pk.h> +#include <botan/util.h> + +namespace Botan { + +/* +* ElGamal_PublicKey Constructor +*/ +ElGamal_PublicKey::ElGamal_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + X509_load_hook(); + } + +/* +* Algorithm Specific X.509 Initialization Code +*/ +void ElGamal_PublicKey::X509_load_hook() + { + core = ELG_Core(group, y); + } + +/* +* ElGamal Encryption Function +*/ +SecureVector<byte> +ElGamal_PublicKey::encrypt(const byte in[], u32bit length, + RandomNumberGenerator& rng) const + { + BigInt k(rng, 2 * dl_work_factor(group_p().bits())); + return core.encrypt(in, length, k); + } + +/* +* Return the maximum input size in bits +*/ +u32bit ElGamal_PublicKey::max_input_bits() const + { + return (group_p().bits() - 1); + } + +/* +* ElGamal_PrivateKey Constructor +*/ +ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + { + x.randomize(rng, 2 * dl_work_factor(group_p().bits())); + PKCS8_load_hook(rng, true); + } + else + PKCS8_load_hook(rng, false); + } + +/* +* Algorithm Specific PKCS #8 Initialization Code +*/ +void ElGamal_PrivateKey::PKCS8_load_hook(RandomNumberGenerator& rng, + bool generated) + { + if(y == 0) + y = power_mod(group_g(), x, group_p()); + core = ELG_Core(rng, group, y, x); + + if(generated) + gen_check(rng); + else + load_check(rng); + } + +/* +* ElGamal Decryption Function +*/ +SecureVector<byte> ElGamal_PrivateKey::decrypt(const byte in[], + u32bit length) const + { + return core.decrypt(in, length); + } + +/* +* Check Private ElGamal Parameters +*/ +bool ElGamal_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong)) + return false; + + if(!strong) + return true; + + try + { + KeyPair::check_key(rng, + get_pk_encryptor(*this, "EME1(SHA-1)"), + get_pk_decryptor(*this, "EME1(SHA-1)") + ); + } + catch(Self_Test_Failure) + { + return false; + } + + return true; + } + +} diff --git a/botan/src/pubkey/elgamal/elgamal.h b/botan/src/pubkey/elgamal/elgamal.h new file mode 100644 index 0000000..93e640f --- /dev/null +++ b/botan/src/pubkey/elgamal/elgamal.h @@ -0,0 +1,59 @@ +/* +* ElGamal +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ELGAMAL_H__ +#define BOTAN_ELGAMAL_H__ + +#include <botan/dl_algo.h> +#include <botan/elg_core.h> + +namespace Botan { + +/* +* ElGamal Public Key +*/ +class BOTAN_DLL ElGamal_PublicKey : public PK_Encrypting_Key, + public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "ElGamal"; } + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_42; } + + SecureVector<byte> encrypt(const byte[], u32bit, + RandomNumberGenerator& rng) const; + u32bit max_input_bits() const; + + ElGamal_PublicKey() {} + ElGamal_PublicKey(const DL_Group&, const BigInt&); + protected: + ELG_Core core; + private: + void X509_load_hook(); + }; + +/* +* ElGamal Private Key +*/ +class BOTAN_DLL ElGamal_PrivateKey : public ElGamal_PublicKey, + public PK_Decrypting_Key, + public virtual DL_Scheme_PrivateKey + { + public: + SecureVector<byte> decrypt(const byte[], u32bit) const; + + bool check_key(RandomNumberGenerator& rng, bool) const; + + ElGamal_PrivateKey() {} + ElGamal_PrivateKey(RandomNumberGenerator&, const DL_Group&, + const BigInt& = 0); + private: + void PKCS8_load_hook(RandomNumberGenerator&, bool = false); + }; + +} + +#endif diff --git a/botan/src/pubkey/elgamal/info.txt b/botan/src/pubkey/elgamal/info.txt new file mode 100644 index 0000000..d7ae614 --- /dev/null +++ b/botan/src/pubkey/elgamal/info.txt @@ -0,0 +1,22 @@ +realname "ElGamal" + +define ELGAMAL + +load_on auto + +<add> +elgamal.cpp +elgamal.h +elg_core.cpp +elg_core.h +elg_op.cpp +elg_op.h +</add> + +<requires> +dl_algo +dl_group +keypair +libstate +numbertheory +</requires> diff --git a/botan/src/pubkey/if_algo/if_algo.cpp b/botan/src/pubkey/if_algo/if_algo.cpp new file mode 100644 index 0000000..556c86f --- /dev/null +++ b/botan/src/pubkey/if_algo/if_algo.cpp @@ -0,0 +1,215 @@ +/* +* IF Scheme +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/if_algo.h> +#include <botan/numthry.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> + +namespace Botan { + +/* +* Return the X.509 public key encoder +*/ +X509_Encoder* IF_Scheme_PublicKey::x509_encoder() const + { + class IF_Scheme_Encoder : public X509_Encoder + { + public: + AlgorithmIdentifier alg_id() const + { + return AlgorithmIdentifier(key->get_oid(), + AlgorithmIdentifier::USE_NULL_PARAM); + } + + MemoryVector<byte> key_bits() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(key->n) + .encode(key->e) + .end_cons() + .get_contents(); + } + + IF_Scheme_Encoder(const IF_Scheme_PublicKey* k) : key(k) {} + private: + const IF_Scheme_PublicKey* key; + }; + + return new IF_Scheme_Encoder(this); + } + +/* +* Return the X.509 public key decoder +*/ +X509_Decoder* IF_Scheme_PublicKey::x509_decoder() + { + class IF_Scheme_Decoder : public X509_Decoder + { + public: + void alg_id(const AlgorithmIdentifier&) {} + + void key_bits(const MemoryRegion<byte>& bits) + { + BER_Decoder(bits) + .start_cons(SEQUENCE) + .decode(key->n) + .decode(key->e) + .verify_end() + .end_cons(); + + key->X509_load_hook(); + } + + IF_Scheme_Decoder(IF_Scheme_PublicKey* k) : key(k) {} + private: + IF_Scheme_PublicKey* key; + }; + + return new IF_Scheme_Decoder(this); + } + +/* +* Return the PKCS #8 public key encoder +*/ +PKCS8_Encoder* IF_Scheme_PrivateKey::pkcs8_encoder() const + { + class IF_Scheme_Encoder : public PKCS8_Encoder + { + public: + AlgorithmIdentifier alg_id() const + { + return AlgorithmIdentifier(key->get_oid(), + AlgorithmIdentifier::USE_NULL_PARAM); + } + + MemoryVector<byte> key_bits() const + { + return DER_Encoder() + .start_cons(SEQUENCE) + .encode(static_cast<u32bit>(0)) + .encode(key->n) + .encode(key->e) + .encode(key->d) + .encode(key->p) + .encode(key->q) + .encode(key->d1) + .encode(key->d2) + .encode(key->c) + .end_cons() + .get_contents(); + } + + IF_Scheme_Encoder(const IF_Scheme_PrivateKey* k) : key(k) {} + private: + const IF_Scheme_PrivateKey* key; + }; + + return new IF_Scheme_Encoder(this); + } + +/* +* Return the PKCS #8 public key decoder +*/ +PKCS8_Decoder* IF_Scheme_PrivateKey::pkcs8_decoder(RandomNumberGenerator& rng) + { + class IF_Scheme_Decoder : public PKCS8_Decoder + { + public: + void alg_id(const AlgorithmIdentifier&) {} + + void key_bits(const MemoryRegion<byte>& bits) + { + u32bit version; + + BER_Decoder(bits) + .start_cons(SEQUENCE) + .decode(version) + .decode(key->n) + .decode(key->e) + .decode(key->d) + .decode(key->p) + .decode(key->q) + .decode(key->d1) + .decode(key->d2) + .decode(key->c) + .end_cons(); + + if(version != 0) + throw Decoding_Error("Unknown PKCS #1 key format version"); + + key->PKCS8_load_hook(rng); + } + + IF_Scheme_Decoder(IF_Scheme_PrivateKey* k, RandomNumberGenerator& r) : + key(k), rng(r) {} + private: + IF_Scheme_PrivateKey* key; + RandomNumberGenerator& rng; + }; + + return new IF_Scheme_Decoder(this, rng); + } + +/* +* Algorithm Specific X.509 Initialization Code +*/ +void IF_Scheme_PublicKey::X509_load_hook() + { + core = IF_Core(e, n); + } + +/* +* Algorithm Specific PKCS #8 Initialization Code +*/ +void IF_Scheme_PrivateKey::PKCS8_load_hook(RandomNumberGenerator& rng, + bool generated) + { + if(n == 0) n = p * q; + if(d1 == 0) d1 = d % (p - 1); + if(d2 == 0) d2 = d % (q - 1); + if(c == 0) c = inverse_mod(q, p); + + core = IF_Core(rng, e, n, d, p, q, d1, d2, c); + + if(generated) + gen_check(rng); + else + load_check(rng); + } + +/* +* Check IF Scheme Public Parameters +*/ +bool IF_Scheme_PublicKey::check_key(RandomNumberGenerator&, bool) const + { + if(n < 35 || n.is_even() || e < 2) + return false; + return true; + } + +/* +* Check IF Scheme Private Parameters +*/ +bool IF_Scheme_PrivateKey::check_key(RandomNumberGenerator& rng, + bool strong) const + { + if(n < 35 || n.is_even() || e < 2 || d < 2 || p < 3 || q < 3 || p*q != n) + return false; + + if(!strong) + return true; + + if(d1 != d % (p - 1) || d2 != d % (q - 1) || c != inverse_mod(q, p)) + return false; + if(!check_prime(p, rng) || !check_prime(q, rng)) + return false; + return true; + } + +} diff --git a/botan/src/pubkey/if_algo/if_algo.h b/botan/src/pubkey/if_algo/if_algo.h new file mode 100644 index 0000000..32a29be --- /dev/null +++ b/botan/src/pubkey/if_algo/if_algo.h @@ -0,0 +1,85 @@ +/* +* IF Scheme +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_IF_ALGO_H__ +#define BOTAN_IF_ALGO_H__ + +#include <botan/if_core.h> +#include <botan/x509_key.h> +#include <botan/pkcs8.h> + +namespace Botan { + +/** +* This class represents public keys +* of integer factorization based (IF) public key schemes. +*/ +class BOTAN_DLL IF_Scheme_PublicKey : public virtual Public_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + /** + * Get n = p * q. + * @return n + */ + const BigInt& get_n() const { return n; } + + /** + * Get the public exponent used by the key. + * @return the public exponent + */ + const BigInt& get_e() const { return e; } + + u32bit max_input_bits() const { return (n.bits() - 1); } + + X509_Encoder* x509_encoder() const; + X509_Decoder* x509_decoder(); + protected: + virtual void X509_load_hook(); + BigInt n, e; + IF_Core core; + }; + +/** +* This class represents public keys +* of integer factorization based (IF) public key schemes. +*/ +class BOTAN_DLL IF_Scheme_PrivateKey : public virtual IF_Scheme_PublicKey, + public virtual Private_Key + { + public: + bool check_key(RandomNumberGenerator& rng, bool) const; + + /** + * Get the first prime p. + * @return the prime p + */ + const BigInt& get_p() const { return p; } + + /** + * Get the second prime q. + * @return the prime q + */ + const BigInt& get_q() const { return q; } + + /** + * Get d with exp * d = 1 mod (p - 1, q - 1). + * @return d + */ + const BigInt& get_d() const { return d; } + + PKCS8_Encoder* pkcs8_encoder() const; + PKCS8_Decoder* pkcs8_decoder(RandomNumberGenerator&); + protected: + virtual void PKCS8_load_hook(RandomNumberGenerator&, bool = false); + BigInt d, p, q, d1, d2, c; + }; + +} + +#endif diff --git a/botan/src/pubkey/if_algo/if_core.cpp b/botan/src/pubkey/if_algo/if_core.cpp new file mode 100644 index 0000000..8cc6a81 --- /dev/null +++ b/botan/src/pubkey/if_algo/if_core.cpp @@ -0,0 +1,87 @@ +/* +* IF Algorithm Core +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/if_core.h> +#include <botan/numthry.h> +#include <botan/pk_engine.h> +#include <botan/parsing.h> +#include <algorithm> + +namespace Botan { + +namespace { + +const u32bit BLINDING_BITS = BOTAN_PRIVATE_KEY_OP_BLINDING_BITS; + +} + +/* +* IF_Core Constructor +*/ +IF_Core::IF_Core(const BigInt& e, const BigInt& n) + { + op = Engine_Core::if_op(e, n, 0, 0, 0, 0, 0, 0); + } + + +/* +* IF_Core Constructor +*/ +IF_Core::IF_Core(RandomNumberGenerator& rng, + const BigInt& e, const BigInt& n, const BigInt& d, + const BigInt& p, const BigInt& q, + const BigInt& d1, const BigInt& d2, const BigInt& c) + { + op = Engine_Core::if_op(e, n, d, p, q, d1, d2, c); + + if(BLINDING_BITS) + { + BigInt k(rng, std::min(n.bits()-1, BLINDING_BITS)); + blinder = Blinder(power_mod(k, e, n), inverse_mod(k, n), n); + } + } + +/* +* IF_Core Copy Constructor +*/ +IF_Core::IF_Core(const IF_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + } + +/* +* IF_Core Assignment Operator +*/ +IF_Core& IF_Core::operator=(const IF_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + blinder = core.blinder; + return (*this); + } + +/* +* IF Public Operation +*/ +BigInt IF_Core::public_op(const BigInt& i) const + { + return op->public_op(i); + } + +/* +* IF Private Operation +*/ +BigInt IF_Core::private_op(const BigInt& i) const + { + return blinder.unblind(op->private_op(blinder.blind(i))); + } + +} diff --git a/botan/src/pubkey/if_algo/if_core.h b/botan/src/pubkey/if_algo/if_core.h new file mode 100644 index 0000000..b7f4877 --- /dev/null +++ b/botan/src/pubkey/if_algo/if_core.h @@ -0,0 +1,45 @@ +/* +* IF Algorithm Core +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_IF_CORE_H__ +#define BOTAN_IF_CORE_H__ + +#include <botan/if_op.h> +#include <botan/blinding.h> + +namespace Botan { + +/* +* IF Core +*/ +class BOTAN_DLL IF_Core + { + public: + BigInt public_op(const BigInt&) const; + BigInt private_op(const BigInt&) const; + + IF_Core& operator=(const IF_Core&); + + IF_Core() { op = 0; } + IF_Core(const IF_Core&); + + IF_Core(const BigInt&, const BigInt&); + + IF_Core(RandomNumberGenerator& rng, + const BigInt&, const BigInt&, + const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&, const BigInt&); + + ~IF_Core() { delete op; } + private: + IF_Operation* op; + Blinder blinder; + }; + +} + +#endif diff --git a/botan/src/pubkey/if_algo/if_op.cpp b/botan/src/pubkey/if_algo/if_op.cpp new file mode 100644 index 0000000..27aef45 --- /dev/null +++ b/botan/src/pubkey/if_algo/if_op.cpp @@ -0,0 +1,47 @@ +/* +* IF (RSA/RW) Operation +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/if_op.h> +#include <botan/numthry.h> + +namespace Botan { + +/* +* Default_IF_Op Constructor +*/ +Default_IF_Op::Default_IF_Op(const BigInt& e, const BigInt& n, const BigInt&, + const BigInt& p, const BigInt& q, + const BigInt& d1, const BigInt& d2, + const BigInt& c) + { + powermod_e_n = Fixed_Exponent_Power_Mod(e, n); + + if(d1 != 0 && d2 != 0 && p != 0 && q != 0) + { + powermod_d1_p = Fixed_Exponent_Power_Mod(d1, p); + powermod_d2_q = Fixed_Exponent_Power_Mod(d2, q); + reducer = Modular_Reducer(p); + this->c = c; + this->q = q; + } + } + +/* +* Default IF Private Operation +*/ +BigInt Default_IF_Op::private_op(const BigInt& i) const + { + if(q == 0) + throw Internal_Error("Default_IF_Op::private_op: No private key"); + + BigInt j1 = powermod_d1_p(i); + BigInt j2 = powermod_d2_q(i); + j1 = reducer.reduce(sub_mul(j1, j2, c)); + return mul_add(j1, q, j2); + } + +} diff --git a/botan/src/pubkey/if_algo/if_op.h b/botan/src/pubkey/if_algo/if_op.h new file mode 100644 index 0000000..516902f --- /dev/null +++ b/botan/src/pubkey/if_algo/if_op.h @@ -0,0 +1,52 @@ +/* +* IF Operations +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_IF_OP_H__ +#define BOTAN_IF_OP_H__ + +#include <botan/bigint.h> +#include <botan/pow_mod.h> +#include <botan/reducer.h> + +namespace Botan { + +/* +* IF Operation +*/ +class BOTAN_DLL IF_Operation + { + public: + virtual BigInt public_op(const BigInt&) const = 0; + virtual BigInt private_op(const BigInt&) const = 0; + virtual IF_Operation* clone() const = 0; + virtual ~IF_Operation() {} + }; + +/* +* Default IF Operation +*/ +class BOTAN_DLL Default_IF_Op : public IF_Operation + { + public: + BigInt public_op(const BigInt& i) const + { return powermod_e_n(i); } + BigInt private_op(const BigInt&) const; + + IF_Operation* clone() const { return new Default_IF_Op(*this); } + + Default_IF_Op(const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&, const BigInt&, + const BigInt&, const BigInt&); + private: + Fixed_Exponent_Power_Mod powermod_e_n, powermod_d1_p, powermod_d2_q; + Modular_Reducer reducer; + BigInt c, q; + }; + +} + +#endif diff --git a/botan/src/pubkey/if_algo/info.txt b/botan/src/pubkey/if_algo/info.txt new file mode 100644 index 0000000..d2142f4 --- /dev/null +++ b/botan/src/pubkey/if_algo/info.txt @@ -0,0 +1,22 @@ +realname "Integer Factorization Algorithms" + +define IF_PUBLIC_KEY_FAMILY + +load_on dep + +<add> +if_algo.cpp +if_algo.h +if_core.cpp +if_core.h +if_op.cpp +if_op.h +</add> + +<requires> +asn1 +bigint +libstate +numbertheory +pk_codecs +</requires> diff --git a/botan/src/pubkey/info.txt b/botan/src/pubkey/info.txt new file mode 100644 index 0000000..ee8da5b --- /dev/null +++ b/botan/src/pubkey/info.txt @@ -0,0 +1,30 @@ +realname "Public Key Base" + +define PUBLIC_KEY_CRYPTO + +load_on auto + +<add> +pk_algs.cpp +pk_algs.h +pk_filts.cpp +pk_filts.h +pk_keys.cpp +pk_keys.h +pubkey.cpp +pubkey.h +pubkey_enums.cpp +pubkey_enums.h +</add> + +<requires> +alloc +asn1 +bigint +filters +kdf +oid_lookup +pk_pad +rng +sym_algo +</requires> diff --git a/botan/src/pubkey/keypair/info.txt b/botan/src/pubkey/keypair/info.txt new file mode 100644 index 0000000..9e75864 --- /dev/null +++ b/botan/src/pubkey/keypair/info.txt @@ -0,0 +1,14 @@ +realname "Keypair Testing" + +define KEYPAIR_TESTING + +load_on auto + +<add> +keypair.cpp +keypair.h +</add> + +<requires> +libstate +</requires> diff --git a/botan/src/pubkey/keypair/keypair.cpp b/botan/src/pubkey/keypair/keypair.cpp new file mode 100644 index 0000000..486577f --- /dev/null +++ b/botan/src/pubkey/keypair/keypair.cpp @@ -0,0 +1,73 @@ +/* +* Keypair Checks +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/keypair.h> +#include <botan/look_pk.h> +#include <memory> + +namespace Botan { + +namespace KeyPair { + +/* +* Check an encryption key pair for consistency +*/ +void check_key(RandomNumberGenerator& rng, + PK_Encryptor* encryptor, PK_Decryptor* decryptor) + { + if(encryptor->maximum_input_size() == 0) + return; + + std::auto_ptr<PK_Encryptor> enc(encryptor); + std::auto_ptr<PK_Decryptor> dec(decryptor); + + SecureVector<byte> message(enc->maximum_input_size() - 1); + rng.randomize(message, message.size()); + + SecureVector<byte> ciphertext = enc->encrypt(message, rng); + if(ciphertext == message) + throw Self_Test_Failure("Encryption key pair consistency failure"); + + SecureVector<byte> message2 = dec->decrypt(ciphertext); + if(message != message2) + throw Self_Test_Failure("Encryption key pair consistency failure"); + } + +/* +* Check a signature key pair for consistency +*/ +void check_key(RandomNumberGenerator& rng, + PK_Signer* signer, PK_Verifier* verifier) + { + std::auto_ptr<PK_Signer> sig(signer); + std::auto_ptr<PK_Verifier> ver(verifier); + + SecureVector<byte> message(16); + rng.randomize(message, message.size()); + + SecureVector<byte> signature; + + try + { + signature = sig->sign_message(message, rng); + } + catch(Encoding_Error) + { + return; + } + + if(!ver->verify_message(message, signature)) + throw Self_Test_Failure("Signature key pair consistency failure"); + + ++message[0]; + if(ver->verify_message(message, signature)) + throw Self_Test_Failure("Signature key pair consistency failure"); + } + +} + +} diff --git a/botan/src/pubkey/keypair/keypair.h b/botan/src/pubkey/keypair/keypair.h new file mode 100644 index 0000000..b1d5c2d --- /dev/null +++ b/botan/src/pubkey/keypair/keypair.h @@ -0,0 +1,47 @@ +/* +* Keypair Checks +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_KEYPAIR_H__ +#define BOTAN_KEYPAIR_H__ + +#include <botan/pubkey.h> + +namespace Botan { + +namespace KeyPair { + +/** +* Tests whether the specified encryptor and decryptor are related to each other, +* i.e. whether encrypting with the encryptor and consecutive decryption leads to +* the original plaintext. +* @param rng the rng to use +* @param enc the encryptor to test +* @param dec the decryptor to test +* @throw Self_Test_Failure if the arguments are not related to each other +*/ +BOTAN_DLL void check_key(RandomNumberGenerator& rng, + PK_Encryptor* enc, + PK_Decryptor* dec); + +/** +* Tests whether the specified signer and verifier are related to each other, +* i.e. whether a signature created with the signer and can be +* successfully verified with the verifier. +* @param rng the rng to use +* @param sig the signer to test +* @param ver the verifier to test +* @throw Self_Test_Failure if the arguments are not related to each other +*/ +BOTAN_DLL void check_key(RandomNumberGenerator& rng, + PK_Signer* sig, + PK_Verifier* ver); + +} + +} + +#endif diff --git a/botan/src/pubkey/nr/info.txt b/botan/src/pubkey/nr/info.txt new file mode 100644 index 0000000..c89820a --- /dev/null +++ b/botan/src/pubkey/nr/info.txt @@ -0,0 +1,22 @@ +realname "Nyberg-Rueppel" + +define NYBERG_RUEPPEL + +load_on auto + +<add> +nr.cpp +nr.h +nr_core.cpp +nr_core.h +nr_op.cpp +nr_op.h +</add> + +<requires> +dl_algo +dl_group +keypair +libstate +numbertheory +</requires> diff --git a/botan/src/pubkey/nr/nr.cpp b/botan/src/pubkey/nr/nr.cpp new file mode 100644 index 0000000..ad4ae78 --- /dev/null +++ b/botan/src/pubkey/nr/nr.cpp @@ -0,0 +1,134 @@ +/* +* Nyberg-Rueppel +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/nr.h> +#include <botan/numthry.h> +#include <botan/keypair.h> +#include <botan/look_pk.h> + +namespace Botan { + +/* +* NR_PublicKey Constructor +*/ +NR_PublicKey::NR_PublicKey(const DL_Group& grp, const BigInt& y1) + { + group = grp; + y = y1; + X509_load_hook(); + } + +/* +* Algorithm Specific X.509 Initialization Code +*/ +void NR_PublicKey::X509_load_hook() + { + core = NR_Core(group, y); + } + +/* +* Nyberg-Rueppel Verification Function +*/ +SecureVector<byte> NR_PublicKey::verify(const byte sig[], u32bit sig_len) const + { + return core.verify(sig, sig_len); + } + +/* +* Return the maximum input size in bits +*/ +u32bit NR_PublicKey::max_input_bits() const + { + return (group_q().bits() - 1); + } + +/* +* Return the size of each portion of the sig +*/ +u32bit NR_PublicKey::message_part_size() const + { + return group_q().bytes(); + } + +/* +* Create a NR private key +*/ +NR_PrivateKey::NR_PrivateKey(RandomNumberGenerator& rng, + const DL_Group& grp, + const BigInt& x_arg) + { + group = grp; + x = x_arg; + + if(x == 0) + { + x = BigInt::random_integer(rng, 2, group_q() - 1); + PKCS8_load_hook(rng, true); + } + else + PKCS8_load_hook(rng, false); + } + +/* +* Algorithm Specific PKCS #8 Initialization Code +*/ +void NR_PrivateKey::PKCS8_load_hook(RandomNumberGenerator& rng, + bool generated) + { + if(y == 0) + y = power_mod(group_g(), x, group_p()); + core = NR_Core(group, y, x); + + if(generated) + gen_check(rng); + else + load_check(rng); + } + +/* +* Nyberg-Rueppel Signature Operation +*/ +SecureVector<byte> NR_PrivateKey::sign(const byte in[], u32bit length, + RandomNumberGenerator& rng) const + { + const BigInt& q = group_q(); + + BigInt k; + do + k.randomize(rng, q.bits()); + while(k >= q); + + return core.sign(in, length, k); + } + +/* +* Check Private Nyberg-Rueppel Parameters +*/ +bool NR_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!DL_Scheme_PrivateKey::check_key(rng, strong) || x >= group_q()) + return false; + + if(!strong) + return true; + + try + { + KeyPair::check_key(rng, + get_pk_signer(*this, "EMSA1(SHA-1)"), + get_pk_verifier(*this, "EMSA1(SHA-1)") + ); + } + catch(Self_Test_Failure) + { + return false; + } + + return true; + } + +} diff --git a/botan/src/pubkey/nr/nr.h b/botan/src/pubkey/nr/nr.h new file mode 100644 index 0000000..144c5ec --- /dev/null +++ b/botan/src/pubkey/nr/nr.h @@ -0,0 +1,63 @@ +/* +* Nyberg-Rueppel +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_NYBERG_RUEPPEL_H__ +#define BOTAN_NYBERG_RUEPPEL_H__ + +#include <botan/dl_algo.h> +#include <botan/nr_core.h> + +namespace Botan { + +/* +* Nyberg-Rueppel Public Key +*/ +class BOTAN_DLL NR_PublicKey : public PK_Verifying_with_MR_Key, + public virtual DL_Scheme_PublicKey + { + public: + std::string algo_name() const { return "NR"; } + + SecureVector<byte> verify(const byte[], u32bit) const; + u32bit max_input_bits() const; + + DL_Group::Format group_format() const { return DL_Group::ANSI_X9_57; } + u32bit message_parts() const { return 2; } + u32bit message_part_size() const; + + NR_PublicKey() {} + NR_PublicKey(const DL_Group&, const BigInt&); + protected: + NR_Core core; + private: + void X509_load_hook(); + }; + +/* +* Nyberg-Rueppel Private Key +*/ +class BOTAN_DLL NR_PrivateKey : public NR_PublicKey, + public PK_Signing_Key, + public virtual DL_Scheme_PrivateKey + { + public: + SecureVector<byte> sign(const byte[], u32bit, + RandomNumberGenerator& rng) const; + + bool check_key(RandomNumberGenerator& rng, bool) const; + + NR_PrivateKey() {} + + NR_PrivateKey(RandomNumberGenerator&, const DL_Group&, + const BigInt& = 0); + private: + void PKCS8_load_hook(RandomNumberGenerator&, bool = false); + }; + +} + +#endif diff --git a/botan/src/pubkey/nr/nr_core.cpp b/botan/src/pubkey/nr/nr_core.cpp new file mode 100644 index 0000000..afa1115 --- /dev/null +++ b/botan/src/pubkey/nr/nr_core.cpp @@ -0,0 +1,62 @@ +/* +* NR Core +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/nr_core.h> +#include <botan/numthry.h> +#include <botan/pk_engine.h> +#include <botan/parsing.h> +#include <algorithm> + +namespace Botan { + +/* +* NR_Core Constructor +*/ +NR_Core::NR_Core(const DL_Group& group, const BigInt& y, const BigInt& x) + { + op = Engine_Core::nr_op(group, y, x); + } + +/* +* NR_Core Copy Constructor +*/ +NR_Core::NR_Core(const NR_Core& core) + { + op = 0; + if(core.op) + op = core.op->clone(); + } + +/* +* NR_Core Assignment Operator +*/ +NR_Core& NR_Core::operator=(const NR_Core& core) + { + delete op; + if(core.op) + op = core.op->clone(); + return (*this); + } + +/* +* NR Verification Operation +*/ +SecureVector<byte> NR_Core::verify(const byte in[], u32bit length) const + { + return op->verify(in, length); + } + +/* +* NR Signature Operation +*/ +SecureVector<byte> NR_Core::sign(const byte in[], u32bit length, + const BigInt& k) const + { + return op->sign(in, length, k); + } + +} diff --git a/botan/src/pubkey/nr/nr_core.h b/botan/src/pubkey/nr/nr_core.h new file mode 100644 index 0000000..4837736 --- /dev/null +++ b/botan/src/pubkey/nr/nr_core.h @@ -0,0 +1,37 @@ +/* +* NR Core +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_NR_CORE_H__ +#define BOTAN_NR_CORE_H__ + +#include <botan/nr_op.h> +#include <botan/dl_group.h> + +namespace Botan { + +/* +* NR Core +*/ +class BOTAN_DLL NR_Core + { + public: + SecureVector<byte> sign(const byte[], u32bit, const BigInt&) const; + SecureVector<byte> verify(const byte[], u32bit) const; + + NR_Core& operator=(const NR_Core&); + + NR_Core() { op = 0; } + NR_Core(const NR_Core&); + NR_Core(const DL_Group&, const BigInt&, const BigInt& = 0); + ~NR_Core() { delete op; } + private: + NR_Operation* op; + }; + +} + +#endif diff --git a/botan/src/pubkey/nr/nr_op.cpp b/botan/src/pubkey/nr/nr_op.cpp new file mode 100644 index 0000000..b5efa3d --- /dev/null +++ b/botan/src/pubkey/nr/nr_op.cpp @@ -0,0 +1,71 @@ +/* +* NR Operations +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/nr_op.h> + +namespace Botan { + +/* +* Default_NR_Op Constructor +*/ +Default_NR_Op::Default_NR_Op(const DL_Group& grp, const BigInt& y1, + const BigInt& x1) : x(x1), y(y1), group(grp) + { + powermod_g_p = Fixed_Base_Power_Mod(group.get_g(), group.get_p()); + powermod_y_p = Fixed_Base_Power_Mod(y, group.get_p()); + mod_p = Modular_Reducer(group.get_p()); + mod_q = Modular_Reducer(group.get_q()); + } + +/* +* Default NR Verify Operation +*/ +SecureVector<byte> Default_NR_Op::verify(const byte in[], u32bit length) const + { + const BigInt& q = group.get_q(); + + if(length != 2*q.bytes()) + return false; + + BigInt c(in, q.bytes()); + BigInt d(in + q.bytes(), q.bytes()); + + if(c.is_zero() || c >= q || d >= q) + throw Invalid_Argument("Default_NR_Op::verify: Invalid signature"); + + BigInt i = mod_p.multiply(powermod_g_p(d), powermod_y_p(c)); + return BigInt::encode(mod_q.reduce(c - i)); + } + +/* +* Default NR Sign Operation +*/ +SecureVector<byte> Default_NR_Op::sign(const byte in[], u32bit length, + const BigInt& k) const + { + if(x == 0) + throw Internal_Error("Default_NR_Op::sign: No private key"); + + const BigInt& q = group.get_q(); + + BigInt f(in, length); + + if(f >= q) + throw Invalid_Argument("Default_NR_Op::sign: Input is out of range"); + + BigInt c = mod_q.reduce(powermod_g_p(k) + f); + if(c.is_zero()) + throw Internal_Error("Default_NR_Op::sign: c was zero"); + BigInt d = mod_q.reduce(k - x * c); + + SecureVector<byte> output(2*q.bytes()); + c.binary_encode(output + (output.size() / 2 - c.bytes())); + d.binary_encode(output + (output.size() - d.bytes())); + return output; + } + +} diff --git a/botan/src/pubkey/nr/nr_op.h b/botan/src/pubkey/nr/nr_op.h new file mode 100644 index 0000000..cba1465 --- /dev/null +++ b/botan/src/pubkey/nr/nr_op.h @@ -0,0 +1,53 @@ +/* +* NR Operations +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_NR_OPS_H__ +#define BOTAN_NR_OPS_H__ + +#include <botan/pow_mod.h> +#include <botan/numthry.h> +#include <botan/reducer.h> +#include <botan/dl_group.h> + +namespace Botan { + +/* +* NR Operation +*/ +class BOTAN_DLL NR_Operation + { + public: + virtual SecureVector<byte> verify(const byte[], u32bit) const = 0; + virtual SecureVector<byte> sign(const byte[], u32bit, + const BigInt&) const = 0; + virtual NR_Operation* clone() const = 0; + virtual ~NR_Operation() {} + }; + +/* +* Botan's Default NR Operation +*/ +class BOTAN_DLL Default_NR_Op : public NR_Operation + { + public: + SecureVector<byte> verify(const byte[], u32bit) const; + SecureVector<byte> sign(const byte[], u32bit, const BigInt&) const; + + NR_Operation* clone() const { return new Default_NR_Op(*this); } + + Default_NR_Op(const DL_Group&, const BigInt&, const BigInt&); + private: + const BigInt x, y; + const DL_Group group; + Fixed_Base_Power_Mod powermod_g_p, powermod_y_p; + Modular_Reducer mod_p, mod_q; + }; + + +} + +#endif diff --git a/botan/src/pubkey/pk_algs.cpp b/botan/src/pubkey/pk_algs.cpp new file mode 100644 index 0000000..99d7294 --- /dev/null +++ b/botan/src/pubkey/pk_algs.cpp @@ -0,0 +1,112 @@ +/* +* PK Key +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/pk_algs.h> + +#if defined(BOTAN_HAS_RSA) + #include <botan/rsa.h> +#endif + +#if defined(BOTAN_HAS_DSA) + #include <botan/dsa.h> +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + #include <botan/dh.h> +#endif + +#if defined(BOTAN_HAS_ECDSA) + #include <botan/ecdsa.h> +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + #include <botan/nr.h> +#endif + +#if defined(BOTAN_HAS_RW) + #include <botan/rw.h> +#endif + +#if defined(BOTAN_HAS_ELGAMAL) + #include <botan/elgamal.h> +#endif + +namespace Botan { + +/* +* Get an PK public key object +*/ +Public_Key* get_public_key(const std::string& alg_name) + { +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") return new RSA_PublicKey; +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") return new DSA_PublicKey; +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") return new DH_PublicKey; +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(alg_name == "NR") return new NR_PublicKey; +#endif + +#if defined(BOTAN_HAS_RW) + if(alg_name == "RW") return new RW_PublicKey; +#endif + +#if defined(BOTAN_HAS_ELG) + if(alg_name == "ELG") return new ElGamal_PublicKey; +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") return new ECDSA_PublicKey; +#endif + + return 0; + } + +/* +* Get an PK private key object +*/ +Private_Key* get_private_key(const std::string& alg_name) + { +#if defined(BOTAN_HAS_RSA) + if(alg_name == "RSA") return new RSA_PrivateKey; +#endif + +#if defined(BOTAN_HAS_DSA) + if(alg_name == "DSA") return new DSA_PrivateKey; +#endif + +#if defined(BOTAN_HAS_DIFFIE_HELLMAN) + if(alg_name == "DH") return new DH_PrivateKey; +#endif + +#if defined(BOTAN_HAS_NYBERG_RUEPPEL) + if(alg_name == "NR") return new NR_PrivateKey; +#endif + +#if defined(BOTAN_HAS_RW) + if(alg_name == "RW") return new RW_PrivateKey; +#endif + +#if defined(BOTAN_HAS_ELG) + if(alg_name == "ELG") return new ElGamal_PrivateKey; +#endif + +#if defined(BOTAN_HAS_ECDSA) + if(alg_name == "ECDSA") return new ECDSA_PrivateKey; +#endif + + return 0; + } + +} diff --git a/botan/src/pubkey/pk_algs.h b/botan/src/pubkey/pk_algs.h new file mode 100644 index 0000000..c41bf1a --- /dev/null +++ b/botan/src/pubkey/pk_algs.h @@ -0,0 +1,31 @@ +/* +* PK Key Factory +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PK_KEY_FACTORY_H__ +#define BOTAN_PK_KEY_FACTORY_H__ + +#include <botan/pk_keys.h> + +namespace Botan { + +/** +* Get an empty public key object. +* @param name the name of the desired public key algorithm +* @return the public key object +*/ +BOTAN_DLL Public_Key* get_public_key(const std::string&); + +/** +* Get an empty private key object. +* @param name the name of the desired public key algorithm +* @return the private key object +*/ +BOTAN_DLL Private_Key* get_private_key(const std::string&); + +} + +#endif diff --git a/botan/src/pubkey/pk_codecs/info.txt b/botan/src/pubkey/pk_codecs/info.txt new file mode 100644 index 0000000..96511a6 --- /dev/null +++ b/botan/src/pubkey/pk_codecs/info.txt @@ -0,0 +1,18 @@ +realname "PK codecs (PKCS8, X.509)" + +load_on auto + +<add> +pkcs8.h +pkcs8.cpp +x509_key.h +x509_key.cpp +</add> + +<requires> +asn1 +filters +oid_lookup +pbe +pem +</requires> diff --git a/botan/src/pubkey/pk_codecs/pkcs8.cpp b/botan/src/pubkey/pk_codecs/pkcs8.cpp new file mode 100644 index 0000000..8a464ec --- /dev/null +++ b/botan/src/pubkey/pk_codecs/pkcs8.cpp @@ -0,0 +1,313 @@ +/* +* PKCS #8 +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/pkcs8.h> +#include <botan/get_pbe.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/asn1_obj.h> +#include <botan/pk_algs.h> +#include <botan/oids.h> +#include <botan/pem.h> +#include <memory> + +namespace Botan { + +namespace PKCS8 { + +namespace { + +/* +* Get info from an EncryptedPrivateKeyInfo +*/ +SecureVector<byte> PKCS8_extract(DataSource& source, + AlgorithmIdentifier& pbe_alg_id) + { + SecureVector<byte> key_data; + + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(pbe_alg_id) + .decode(key_data, OCTET_STRING) + .verify_end(); + + return key_data; + } + +/* +* PEM decode and/or decrypt a private key +*/ +SecureVector<byte> PKCS8_decode(DataSource& source, const User_Interface& ui, + AlgorithmIdentifier& pk_alg_id) + { + AlgorithmIdentifier pbe_alg_id; + SecureVector<byte> key_data, key; + bool is_encrypted = true; + + try { + if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) + key_data = PKCS8_extract(source, pbe_alg_id); + else + { + std::string label; + key_data = PEM_Code::decode(source, label); + if(label == "PRIVATE KEY") + is_encrypted = false; + else if(label == "ENCRYPTED PRIVATE KEY") + { + DataSource_Memory key_source(key_data); + key_data = PKCS8_extract(key_source, pbe_alg_id); + } + else + throw PKCS8_Exception("Unknown PEM label " + label); + } + + if(key_data.is_empty()) + throw PKCS8_Exception("No key data found"); + } + catch(Decoding_Error) + { + throw Decoding_Error("PKCS #8 private key decoding failed"); + } + + if(!is_encrypted) + key = key_data; + + const u32bit MAX_TRIES = 3; + + u32bit tries = 0; + while(true) + { + try { + if(MAX_TRIES && tries >= MAX_TRIES) + break; + + if(is_encrypted) + { + DataSource_Memory params(pbe_alg_id.parameters); + std::auto_ptr<PBE> pbe(get_pbe(pbe_alg_id.oid, params)); + + User_Interface::UI_Result result = User_Interface::OK; + const std::string passphrase = + ui.get_passphrase("PKCS #8 private key", source.id(), result); + + if(result == User_Interface::CANCEL_ACTION) + break; + + pbe->set_key(passphrase); + Pipe decryptor(pbe.release()); + + decryptor.process_msg(key_data, key_data.size()); + key = decryptor.read_all(); + } + + u32bit version; + + BER_Decoder(key) + .start_cons(SEQUENCE) + .decode(version) + .decode(pk_alg_id) + .decode(key, OCTET_STRING) + .discard_remaining() + .end_cons(); + + if(version != 0) + throw Decoding_Error("PKCS #8: Unknown version number"); + + break; + } + catch(Decoding_Error) + { + ++tries; + } + } + + if(key.is_empty()) + throw Decoding_Error("PKCS #8 private key decoding failed"); + return key; + } + +} + +/* +* DER or PEM encode a PKCS #8 private key +*/ +void encode(const Private_Key& key, Pipe& pipe, X509_Encoding encoding) + { + std::auto_ptr<PKCS8_Encoder> encoder(key.pkcs8_encoder()); + if(!encoder.get()) + throw Encoding_Error("PKCS8::encode: Key does not support encoding"); + + const u32bit PKCS8_VERSION = 0; + + SecureVector<byte> contents = + DER_Encoder() + .start_cons(SEQUENCE) + .encode(PKCS8_VERSION) + .encode(encoder->alg_id()) + .encode(encoder->key_bits(), OCTET_STRING) + .end_cons() + .get_contents(); + + if(encoding == PEM) + pipe.write(PEM_Code::encode(contents, "PRIVATE KEY")); + else + pipe.write(contents); + } + +/* +* Encode and encrypt a PKCS #8 private key +*/ +void encrypt_key(const Private_Key& key, + Pipe& pipe, + RandomNumberGenerator& rng, + const std::string& pass, const std::string& pbe_algo, + X509_Encoding encoding) + { + const std::string DEFAULT_PBE = "PBE-PKCS5v20(SHA-1,TripleDES/CBC)"; + + Pipe raw_key; + raw_key.start_msg(); + encode(key, raw_key, RAW_BER); + raw_key.end_msg(); + + std::auto_ptr<PBE> pbe(get_pbe(((pbe_algo != "") ? pbe_algo : DEFAULT_PBE))); + + pbe->new_params(rng); + pbe->set_key(pass); + + AlgorithmIdentifier pbe_algid(pbe->get_oid(), pbe->encode_params()); + + Pipe key_encrytor(pbe.release()); + key_encrytor.process_msg(raw_key); + + SecureVector<byte> enc_key = + DER_Encoder() + .start_cons(SEQUENCE) + .encode(pbe_algid) + .encode(key_encrytor.read_all(), OCTET_STRING) + .end_cons() + .get_contents(); + + if(encoding == PEM) + pipe.write(PEM_Code::encode(enc_key, "ENCRYPTED PRIVATE KEY")); + else + pipe.write(enc_key); + } + +/* +* PEM encode a PKCS #8 private key +*/ +std::string PEM_encode(const Private_Key& key) + { + Pipe pem; + pem.start_msg(); + encode(key, pem, PEM); + pem.end_msg(); + return pem.read_all_as_string(); + } + +/* +* Encrypt and PEM encode a PKCS #8 private key +*/ +std::string PEM_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + const std::string& pbe_algo) + { + if(pass == "") + return PEM_encode(key); + + Pipe pem; + pem.start_msg(); + encrypt_key(key, pem, rng, pass, pbe_algo, PEM); + pem.end_msg(); + return pem.read_all_as_string(); + } + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const User_Interface& ui) + { + AlgorithmIdentifier alg_id; + SecureVector<byte> pkcs8_key = PKCS8_decode(source, ui, alg_id); + + const std::string alg_name = OIDS::lookup(alg_id.oid); + if(alg_name == "" || alg_name == alg_id.oid.as_string()) + throw PKCS8_Exception("Unknown algorithm OID: " + + alg_id.oid.as_string()); + + std::auto_ptr<Private_Key> key(get_private_key(alg_name)); + + if(!key.get()) + throw PKCS8_Exception("Unknown PK algorithm/OID: " + alg_name + ", " + + alg_id.oid.as_string()); + + std::auto_ptr<PKCS8_Decoder> decoder(key->pkcs8_decoder(rng)); + + if(!decoder.get()) + throw Decoding_Error("Key does not support PKCS #8 decoding"); + + decoder->alg_id(alg_id); + decoder->key_bits(pkcs8_key); + + return key.release(); + } + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng, + const User_Interface& ui) + { + DataSource_Stream source(fsname, true); + return PKCS8::load_key(source, rng, ui); + } + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const std::string& pass) + { + return PKCS8::load_key(source, rng, User_Interface(pass)); + } + +/* +* Extract a private key and return it +*/ +Private_Key* load_key(const std::string& fsname, + RandomNumberGenerator& rng, + const std::string& pass) + { + return PKCS8::load_key(fsname, rng, User_Interface(pass)); + } + +/* +* Make a copy of this private key +*/ +Private_Key* copy_key(const Private_Key& key, + RandomNumberGenerator& rng) + { + Pipe bits; + + bits.start_msg(); + PKCS8::encode(key, bits); + bits.end_msg(); + + DataSource_Memory source(bits.read_all()); + return PKCS8::load_key(source, rng); + } + +} + +} diff --git a/botan/src/pubkey/pk_codecs/pkcs8.h b/botan/src/pubkey/pk_codecs/pkcs8.h new file mode 100644 index 0000000..28008bd --- /dev/null +++ b/botan/src/pubkey/pk_codecs/pkcs8.h @@ -0,0 +1,177 @@ +/* +* PKCS #8 +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PKCS8_H__ +#define BOTAN_PKCS8_H__ + +#include <botan/x509_key.h> +#include <botan/ui.h> + +namespace Botan { + +/** +* PKCS #8 Private Key Encoder. +*/ +class BOTAN_DLL PKCS8_Encoder + { + public: + /** + * Get the algorithm identifier associated with the scheme + * this encoders key is part of. + * @return the algorithm identifier + */ + virtual AlgorithmIdentifier alg_id() const = 0; + + /** + * Get the DER encoded key. + * @return the DER encoded key + */ + // FIXME: Why not SecureVector? + virtual MemoryVector<byte> key_bits() const = 0; + virtual ~PKCS8_Encoder() {} + }; + +/* +* PKCS #8 Private Key Decoder +*/ +class BOTAN_DLL PKCS8_Decoder + { + public: + /** + * Set the algorithm identifier associated with the scheme + * this decoders key is part of. + * @param alg_id the algorithm identifier + */ + virtual void alg_id(const AlgorithmIdentifier&) = 0; + + /** + * Set the DER encoded key. + * @param key the DER encoded key + */ + virtual void key_bits(const MemoryRegion<byte>&) = 0; + virtual ~PKCS8_Decoder() {} + }; + +/** +* PKCS #8 General Exception +*/ +struct BOTAN_DLL PKCS8_Exception : public Decoding_Error + { + PKCS8_Exception(const std::string& error) : + Decoding_Error("PKCS #8: " + error) {} + }; + +namespace PKCS8 { + +/** +* Encode a private key into a pipe. +* @param key the private key to encode +* @param pipe the pipe to feed the encoded key into +* @param enc the encoding type to use +*/ +BOTAN_DLL void encode(const Private_Key& key, Pipe& pipe, + X509_Encoding enc = PEM); + +/** +* Encode and encrypt a private key into a pipe. +* @param key the private key to encode +* @param pipe the pipe to feed the encoded key into +* @param pass the password to use for encryption +* @param rng the rng to use +* @param pbe_algo the name of the desired password-based encryption algorithm. +* Provide an empty string to use the default PBE defined in the configuration +* under base/default_pbe. +* @param enc the encoding type to use +*/ +BOTAN_DLL void encrypt_key(const Private_Key& key, + Pipe& pipe, + RandomNumberGenerator& rng, + const std::string& pass, + const std::string& pbe_algo = "", + X509_Encoding enc = PEM); + + +/** +* Get a string containing a PEM encoded private key. +* @param key the key to encode +* @return the encoded key +*/ +BOTAN_DLL std::string PEM_encode(const Private_Key& key); + +/** +* Get a string containing a PEM encoded private key, encrypting it with a +* password. +* @param key the key to encode +* @param rng the rng to use +* @param pass the password to use for encryption +* @param pbe_algo the name of the desired password-based encryption algorithm. +* Provide an empty string to use the default PBE defined in the configuration +* under base/default_pbe. +*/ +BOTAN_DLL std::string PEM_encode(const Private_Key& key, + RandomNumberGenerator& rng, + const std::string& pass, + const std::string& pbe_algo = ""); + +/** +* Load a key from a data source. +* @param source the data source providing the encoded key +* @param rng the rng to use +* @param ui the user interface to be used for passphrase dialog +* @return the loaded private key object +*/ +BOTAN_DLL Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const User_Interface& ui); + +/** Load a key from a data source. +* @param source the data source providing the encoded key +* @param rng the rng to use +* @param pass the passphrase to decrypt the key. Provide an empty +* string if the key is not encoded. +* @return the loaded private key object +*/ +BOTAN_DLL Private_Key* load_key(DataSource& source, + RandomNumberGenerator& rng, + const std::string& pass = ""); + +/** +* Load a key from a file. +* @param filename the path to the file containing the encoded key +* @param rng the rng to use +* @param ui the user interface to be used for passphrase dialog +* @return the loaded private key object +*/ +BOTAN_DLL Private_Key* load_key(const std::string& filename, + RandomNumberGenerator& rng, + const User_Interface& ui); + +/** Load a key from a file. +* @param filename the path to the file containing the encoded key +* @param rng the rng to use +* @param pass the passphrase to decrypt the key. Provide an empty +* string if the key is not encoded. +* @return the loaded private key object +*/ +BOTAN_DLL Private_Key* load_key(const std::string& filename, + RandomNumberGenerator& rng, + const std::string& pass = ""); + +/** +* Copy an existing encoded key object. +* @param key the key to copy +* @param rng the rng to use +* @return the new copy of the key +*/ +BOTAN_DLL Private_Key* copy_key(const Private_Key& key, + RandomNumberGenerator& rng); + +} + +} + +#endif diff --git a/botan/src/pubkey/pk_codecs/x509_key.cpp b/botan/src/pubkey/pk_codecs/x509_key.cpp new file mode 100644 index 0000000..455e627 --- /dev/null +++ b/botan/src/pubkey/pk_codecs/x509_key.cpp @@ -0,0 +1,176 @@ +/* +* X.509 Public Key +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/x509_key.h> +#include <botan/filters.h> +#include <botan/asn1_obj.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/pk_algs.h> +#include <botan/oids.h> +#include <botan/pem.h> +#include <memory> + +namespace Botan { + +namespace X509 { + +/* +* DER or PEM encode a X.509 public key +*/ +void encode(const Public_Key& key, Pipe& pipe, X509_Encoding encoding) + { + std::auto_ptr<X509_Encoder> encoder(key.x509_encoder()); + if(!encoder.get()) + throw Encoding_Error("X509::encode: Key does not support encoding"); + + MemoryVector<byte> der = + DER_Encoder() + .start_cons(SEQUENCE) + .encode(encoder->alg_id()) + .encode(encoder->key_bits(), BIT_STRING) + .end_cons() + .get_contents(); + + if(encoding == PEM) + pipe.write(PEM_Code::encode(der, "PUBLIC KEY")); + else + pipe.write(der); + } + +/* +* PEM encode a X.509 public key +*/ +std::string PEM_encode(const Public_Key& key) + { + Pipe pem; + pem.start_msg(); + encode(key, pem, PEM); + pem.end_msg(); + return pem.read_all_as_string(); + } + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(DataSource& source) + { + try { + AlgorithmIdentifier alg_id; + MemoryVector<byte> key_bits; + + if(ASN1::maybe_BER(source) && !PEM_Code::matches(source)) + { + BER_Decoder(source) + .start_cons(SEQUENCE) + .decode(alg_id) + .decode(key_bits, BIT_STRING) + .verify_end() + .end_cons(); + } + else + { + DataSource_Memory ber( + PEM_Code::decode_check_label(source, "PUBLIC KEY") + ); + + BER_Decoder(ber) + .start_cons(SEQUENCE) + .decode(alg_id) + .decode(key_bits, BIT_STRING) + .verify_end() + .end_cons(); + } + + if(key_bits.is_empty()) + throw Decoding_Error("X.509 public key decoding failed"); + + const std::string alg_name = OIDS::lookup(alg_id.oid); + if(alg_name == "") + throw Decoding_Error("Unknown algorithm OID: " + + alg_id.oid.as_string()); + + std::auto_ptr<Public_Key> key_obj(get_public_key(alg_name)); + if(!key_obj.get()) + throw Decoding_Error("Unknown PK algorithm/OID: " + alg_name + ", " + + alg_id.oid.as_string()); + + std::auto_ptr<X509_Decoder> decoder(key_obj->x509_decoder()); + + if(!decoder.get()) + throw Decoding_Error("Key does not support X.509 decoding"); + + decoder->alg_id(alg_id); + decoder->key_bits(key_bits); + + return key_obj.release(); + } + catch(Decoding_Error) + { + throw Decoding_Error("X.509 public key decoding failed"); + } + } + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(const std::string& fsname) + { + DataSource_Stream source(fsname, true); + return X509::load_key(source); + } + +/* +* Extract a public key and return it +*/ +Public_Key* load_key(const MemoryRegion<byte>& mem) + { + DataSource_Memory source(mem); + return X509::load_key(source); + } + +/* +* Make a copy of this public key +*/ +Public_Key* copy_key(const Public_Key& key) + { + Pipe bits; + bits.start_msg(); + X509::encode(key, bits, RAW_BER); + bits.end_msg(); + DataSource_Memory source(bits.read_all()); + return X509::load_key(source); + } + +/* +* Find the allowable key constraints +*/ +Key_Constraints find_constraints(const Public_Key& pub_key, + Key_Constraints limits) + { + const Public_Key* key = &pub_key; + u32bit constraints = 0; + + if(dynamic_cast<const PK_Encrypting_Key*>(key)) + constraints |= KEY_ENCIPHERMENT | DATA_ENCIPHERMENT; + + if(dynamic_cast<const PK_Key_Agreement_Key*>(key)) + constraints |= KEY_AGREEMENT; + + if(dynamic_cast<const PK_Verifying_wo_MR_Key*>(key) || + dynamic_cast<const PK_Verifying_with_MR_Key*>(key)) + constraints |= DIGITAL_SIGNATURE | NON_REPUDIATION; + + if(limits) + constraints &= limits; + + return Key_Constraints(constraints); + } + +} + +} diff --git a/botan/src/pubkey/pk_codecs/x509_key.h b/botan/src/pubkey/pk_codecs/x509_key.h new file mode 100644 index 0000000..9404b7e --- /dev/null +++ b/botan/src/pubkey/pk_codecs/x509_key.h @@ -0,0 +1,110 @@ +/* +* X.509 Public Key +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_X509_PUBLIC_KEY_H__ +#define BOTAN_X509_PUBLIC_KEY_H__ + +#include <botan/pipe.h> +#include <botan/pk_keys.h> +#include <botan/alg_id.h> +#include <botan/pubkey_enums.h> + +namespace Botan { + +/** +* This class represents abstract X.509 public key encoders. +*/ +class BOTAN_DLL X509_Encoder + { + public: + virtual AlgorithmIdentifier alg_id() const = 0; + virtual MemoryVector<byte> key_bits() const = 0; + virtual ~X509_Encoder() {} + }; + +/** +* This class represents abstract X.509 public key decoders. +*/ +class BOTAN_DLL X509_Decoder + { + public: + virtual void alg_id(const AlgorithmIdentifier&) = 0; + virtual void key_bits(const MemoryRegion<byte>&) = 0; + virtual ~X509_Decoder() {} + }; + +/** +* This namespace contains functions for handling X509 objects. +*/ +namespace X509 { + +/* +* X.509 Public Key Encoding/Decoding +*/ + +/** +* Encode a key into a pipe. +* @param key the public key to encode +* @param pipe the pipe to feed the encoded key into +* @param enc the encoding type to use +*/ +BOTAN_DLL void encode(const Public_Key& key, Pipe& pipe, + X509_Encoding enc = PEM); + +/** +* PEM encode a public key into a string. +* @param key the key to encode +* @return the PEM encoded key +*/ +BOTAN_DLL std::string PEM_encode(const Public_Key& key); + +/** +* Create a public key from a data source. +* @param source the source providing the DER or PEM encoded key +* @return the new public key object +*/ +BOTAN_DLL Public_Key* load_key(DataSource& source); + +/** +* Create a public key from a string. +* @param enc the string containing the PEM encoded key +* @return the new public key object +*/ +BOTAN_DLL Public_Key* load_key(const std::string& enc); + +/** +* Create a public key from a memory region. +* @param enc the memory region containing the DER or PEM encoded key +* @return the new public key object +*/ +BOTAN_DLL Public_Key* load_key(const MemoryRegion<byte>& enc); + +/** +* Copy a key. +* @param key the public key to copy +* @return the new public key object +*/ +BOTAN_DLL Public_Key* copy_key(const Public_Key& key); + +/** +* Create the key constraints for a specific public key. +* @param pub_key the public key from which the basic set of +* constraints to be placed in the return value is derived +* @param limits additional limits that will be incorporated into the +* return value +* @return the combination of key type specific constraints and +* additional limits +*/ + +BOTAN_DLL Key_Constraints find_constraints(const Public_Key& pub_key, + Key_Constraints limits); + +} + +} + +#endif diff --git a/botan/src/pubkey/pk_filts.cpp b/botan/src/pubkey/pk_filts.cpp new file mode 100644 index 0000000..18da9c1 --- /dev/null +++ b/botan/src/pubkey/pk_filts.cpp @@ -0,0 +1,115 @@ +/* +* PK Filters +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/pk_filts.h> + +namespace Botan { + +/* +* Append to the buffer +*/ +void PK_Encryptor_Filter::write(const byte input[], u32bit length) + { + buffer.append(input, length); + } + +/* +* Encrypt the message +*/ +void PK_Encryptor_Filter::end_msg() + { + send(cipher->encrypt(buffer, buffer.size(), rng)); + buffer.destroy(); + } + +/* +* Append to the buffer +*/ +void PK_Decryptor_Filter::write(const byte input[], u32bit length) + { + buffer.append(input, length); + } + +/* +* Decrypt the message +*/ +void PK_Decryptor_Filter::end_msg() + { + send(cipher->decrypt(buffer, buffer.size())); + buffer.destroy(); + } + +/* +* Add more data +*/ +void PK_Signer_Filter::write(const byte input[], u32bit length) + { + signer->update(input, length); + } + +/* +* Sign the message +*/ +void PK_Signer_Filter::end_msg() + { + send(signer->signature(rng)); + } + +/* +* Add more data +*/ +void PK_Verifier_Filter::write(const byte input[], u32bit length) + { + verifier->update(input, length); + } + +/* +* Verify the message +*/ +void PK_Verifier_Filter::end_msg() + { + if(signature.is_empty()) + throw Exception("PK_Verifier_Filter: No signature to check against"); + bool is_valid = verifier->check_signature(signature, signature.size()); + send((is_valid ? 1 : 0)); + } + +/* +* Set the signature to check +*/ +void PK_Verifier_Filter::set_signature(const byte sig[], u32bit length) + { + signature.set(sig, length); + } + +/* +* Set the signature to check +*/ +void PK_Verifier_Filter::set_signature(const MemoryRegion<byte>& sig) + { + signature = sig; + } + +/* +* PK_Verifier_Filter Constructor +*/ +PK_Verifier_Filter::PK_Verifier_Filter(PK_Verifier* v, const byte sig[], + u32bit length) : + verifier(v), signature(sig, length) + { + } + +/* +* PK_Verifier_Filter Constructor +*/ +PK_Verifier_Filter::PK_Verifier_Filter(PK_Verifier* v, + const MemoryRegion<byte>& sig) : + verifier(v), signature(sig) + { + } + +} diff --git a/botan/src/pubkey/pk_filts.h b/botan/src/pubkey/pk_filts.h new file mode 100644 index 0000000..8bf3fc2 --- /dev/null +++ b/botan/src/pubkey/pk_filts.h @@ -0,0 +1,91 @@ +/* +* PK Filters +* (C) 1999-2009 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PK_FILTERS_H__ +#define BOTAN_PK_FILTERS_H__ + +#include <botan/filter.h> +#include <botan/pubkey.h> + +namespace Botan { + +/* +* PK_Encryptor Filter +*/ +class BOTAN_DLL PK_Encryptor_Filter : public Filter + { + public: + void write(const byte[], u32bit); + void end_msg(); + PK_Encryptor_Filter(PK_Encryptor* c, + RandomNumberGenerator& rng_ref) : + cipher(c), rng(rng_ref) {} + ~PK_Encryptor_Filter() { delete cipher; } + private: + PK_Encryptor* cipher; + RandomNumberGenerator& rng; + SecureVector<byte> buffer; + }; + +/* +* PK_Decryptor Filter +*/ +class BOTAN_DLL PK_Decryptor_Filter : public Filter + { + public: + void write(const byte[], u32bit); + void end_msg(); + PK_Decryptor_Filter(PK_Decryptor* c) : cipher(c) {} + ~PK_Decryptor_Filter() { delete cipher; } + private: + PK_Decryptor* cipher; + SecureVector<byte> buffer; + }; + +/* +* PK_Signer Filter +*/ +class BOTAN_DLL PK_Signer_Filter : public Filter + { + public: + void write(const byte[], u32bit); + void end_msg(); + + PK_Signer_Filter(PK_Signer* s, + RandomNumberGenerator& rng_ref) : + signer(s), rng(rng_ref) {} + + ~PK_Signer_Filter() { delete signer; } + private: + PK_Signer* signer; + RandomNumberGenerator& rng; + }; + +/* +* PK_Verifier Filter +*/ +class BOTAN_DLL PK_Verifier_Filter : public Filter + { + public: + void write(const byte[], u32bit); + void end_msg(); + + void set_signature(const byte[], u32bit); + void set_signature(const MemoryRegion<byte>&); + + PK_Verifier_Filter(PK_Verifier* v) : verifier(v) {} + PK_Verifier_Filter(PK_Verifier*, const byte[], u32bit); + PK_Verifier_Filter(PK_Verifier*, const MemoryRegion<byte>&); + ~PK_Verifier_Filter() { delete verifier; } + private: + PK_Verifier* verifier; + SecureVector<byte> signature; + }; + +} + +#endif diff --git a/botan/src/pubkey/pk_keys.cpp b/botan/src/pubkey/pk_keys.cpp new file mode 100644 index 0000000..b931585 --- /dev/null +++ b/botan/src/pubkey/pk_keys.cpp @@ -0,0 +1,54 @@ +/* +* PK Key Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/pk_keys.h> +#include <botan/oids.h> + +namespace Botan { + +/* +* Default OID access +*/ +OID Public_Key::get_oid() const + { + try { + return OIDS::lookup(algo_name()); + } + catch(Lookup_Error) + { + throw Lookup_Error("PK algo " + algo_name() + " has no defined OIDs"); + } + } + +/* +* Run checks on a loaded public key +*/ +void Public_Key::load_check(RandomNumberGenerator& rng) const + { + if(!check_key(rng, BOTAN_PUBLIC_KEY_STRONG_CHECKS_ON_LOAD)) + throw Invalid_Argument(algo_name() + ": Invalid public key"); + } + +/* +* Run checks on a loaded private key +*/ +void Private_Key::load_check(RandomNumberGenerator& rng) const + { + if(!check_key(rng, BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_LOAD)) + throw Invalid_Argument(algo_name() + ": Invalid private key"); + } + +/* +* Run checks on a generated private key +*/ +void Private_Key::gen_check(RandomNumberGenerator& rng) const + { + if(!check_key(rng, BOTAN_PRIVATE_KEY_STRONG_CHECKS_ON_GENERATE)) + throw Self_Test_Failure(algo_name() + " private key generation failed"); + } + +} diff --git a/botan/src/pubkey/pk_keys.h b/botan/src/pubkey/pk_keys.h new file mode 100644 index 0000000..5b61257 --- /dev/null +++ b/botan/src/pubkey/pk_keys.h @@ -0,0 +1,180 @@ +/* +* PK Key Types +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PK_KEYS_H__ +#define BOTAN_PK_KEYS_H__ + +#include <botan/secmem.h> +#include <botan/asn1_oid.h> +#include <botan/rng.h> + +namespace Botan { + +/** +* Public Key Base Class. +*/ +class BOTAN_DLL Public_Key + { + public: + /** + * Get the name of the underlying public key scheme. + * @return the name of the public key scheme + */ + virtual std::string algo_name() const = 0; + + /** + * Get the OID of the underlying public key scheme. + * @return the OID of the public key scheme + */ + virtual OID get_oid() const; + + /** + * Test the key values for consistency. + * @param rng rng to use + * @param strong whether to perform strong and lengthy version + * of the test + * @return true if the test is passed + */ + virtual bool check_key(RandomNumberGenerator&, bool) const + { return true; } + + /** + * Find out the number of message parts supported by this scheme. + * @return the number of message parts + */ + virtual u32bit message_parts() const { return 1; } + + /** + * Find out the message part size supported by this scheme/key. + * @return the size of the message parts + */ + virtual u32bit message_part_size() const { return 0; } + + /** + * Get the maximum message size in bits supported by this public key. + * @return the maximum message in bits + */ + virtual u32bit max_input_bits() const = 0; + + /** + * Get an X509 encoder that can be used to encode this key in X509 format. + * @return an X509 encoder for this key + */ + virtual class X509_Encoder* x509_encoder() const = 0; + + /** + * Get an X509 decoder that can be used to set the values of this + * key based on an X509 encoded key object. + * @return an X509 decoder for this key + */ + virtual class X509_Decoder* x509_decoder() = 0; + + virtual ~Public_Key() {} + protected: + virtual void load_check(RandomNumberGenerator&) const; + }; + +/** +* Private Key Base Class +*/ +class BOTAN_DLL Private_Key : public virtual Public_Key + { + public: + /** + * Get a PKCS#8 encoder that can be used to encode this key in + * PKCS#8 format. + * @return an PKCS#8 encoder for this key + */ + virtual class PKCS8_Encoder* pkcs8_encoder() const + { return 0; } + + /** + * Get an PKCS#8 decoder that can be used to set the values of this key + * based on an PKCS#8 encoded key object. + * @return an PKCS#8 decoder for this key + */ + virtual class PKCS8_Decoder* pkcs8_decoder(RandomNumberGenerator&) + { return 0; } + protected: + void load_check(RandomNumberGenerator&) const; + void gen_check(RandomNumberGenerator&) const; + }; + +/** +* PK Encrypting Key. +*/ +class BOTAN_DLL PK_Encrypting_Key : public virtual Public_Key + { + public: + virtual SecureVector<byte> encrypt(const byte[], u32bit, + RandomNumberGenerator&) const = 0; + virtual ~PK_Encrypting_Key() {} + }; + +/** +* PK Decrypting Key +*/ +class BOTAN_DLL PK_Decrypting_Key : public virtual Private_Key + { + public: + virtual SecureVector<byte> decrypt(const byte[], u32bit) const = 0; + virtual ~PK_Decrypting_Key() {} + }; + +/** +* PK Signing Key +*/ +class BOTAN_DLL PK_Signing_Key : public virtual Private_Key + { + public: + virtual SecureVector<byte> sign(const byte[], u32bit, + RandomNumberGenerator& rng) const = 0; + virtual ~PK_Signing_Key() {} + }; + +/** +* PK Verifying Key, Message Recovery Version +*/ +class BOTAN_DLL PK_Verifying_with_MR_Key : public virtual Public_Key + { + public: + virtual SecureVector<byte> verify(const byte[], u32bit) const = 0; + virtual ~PK_Verifying_with_MR_Key() {} + }; + +/** +* PK Verifying Key, No Message Recovery Version +*/ +class BOTAN_DLL PK_Verifying_wo_MR_Key : public virtual Public_Key + { + public: + virtual bool verify(const byte[], u32bit, + const byte[], u32bit) const = 0; + virtual ~PK_Verifying_wo_MR_Key() {} + }; + +/** +* PK Secret Value Derivation Key +*/ +class BOTAN_DLL PK_Key_Agreement_Key : public virtual Private_Key + { + public: + virtual SecureVector<byte> derive_key(const byte[], u32bit) const = 0; + virtual MemoryVector<byte> public_value() const = 0; + virtual ~PK_Key_Agreement_Key() {} + }; + +/* +* Typedefs +*/ +typedef PK_Key_Agreement_Key PK_KA_Key; +typedef Public_Key X509_PublicKey; +typedef Private_Key PKCS8_PrivateKey; + +} + +#endif diff --git a/botan/src/pubkey/pubkey.cpp b/botan/src/pubkey/pubkey.cpp new file mode 100644 index 0000000..4ddaa6f --- /dev/null +++ b/botan/src/pubkey/pubkey.cpp @@ -0,0 +1,396 @@ +/* +* Public Key Base +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/pubkey.h> +#include <botan/der_enc.h> +#include <botan/ber_dec.h> +#include <botan/bigint.h> +#include <botan/parsing.h> +#include <botan/bit_ops.h> +#include <memory> + +namespace Botan { + +/* +* Encrypt a message +*/ +SecureVector<byte> PK_Encryptor::encrypt(const byte in[], u32bit len, + RandomNumberGenerator& rng) const + { + return enc(in, len, rng); + } + +/* +* Encrypt a message +*/ +SecureVector<byte> PK_Encryptor::encrypt(const MemoryRegion<byte>& in, + RandomNumberGenerator& rng) const + { + return enc(in.begin(), in.size(), rng); + } + +/* +* Decrypt a message +*/ +SecureVector<byte> PK_Decryptor::decrypt(const byte in[], u32bit len) const + { + return dec(in, len); + } + +/* +* Decrypt a message +*/ +SecureVector<byte> PK_Decryptor::decrypt(const MemoryRegion<byte>& in) const + { + return dec(in.begin(), in.size()); + } + +/* +* PK_Encryptor_MR_with_EME Constructor +*/ +PK_Encryptor_MR_with_EME::PK_Encryptor_MR_with_EME(const PK_Encrypting_Key& k, + EME* eme_obj) : + key(k), encoder(eme_obj) + { + } + +/* +* Encrypt a message +*/ +SecureVector<byte> +PK_Encryptor_MR_with_EME::enc(const byte msg[], + u32bit length, + RandomNumberGenerator& rng) const + { + SecureVector<byte> message; + if(encoder) + message = encoder->encode(msg, length, key.max_input_bits(), rng); + else + message.set(msg, length); + + if(8*(message.size() - 1) + high_bit(message[0]) > key.max_input_bits()) + throw Exception("PK_Encryptor_MR_with_EME: Input is too large"); + + return key.encrypt(message, message.size(), rng); + } + +/* +* Return the max size, in bytes, of a message +*/ +u32bit PK_Encryptor_MR_with_EME::maximum_input_size() const + { + if(!encoder) + return (key.max_input_bits() / 8); + else + return encoder->maximum_input_size(key.max_input_bits()); + } + +/* +* PK_Decryptor_MR_with_EME Constructor +*/ +PK_Decryptor_MR_with_EME::PK_Decryptor_MR_with_EME(const PK_Decrypting_Key& k, + EME* eme_obj) : + key(k), encoder(eme_obj) + { + } + +/* +* Decrypt a message +*/ +SecureVector<byte> PK_Decryptor_MR_with_EME::dec(const byte msg[], + u32bit length) const + { + try { + SecureVector<byte> decrypted = key.decrypt(msg, length); + if(encoder) + return encoder->decode(decrypted, key.max_input_bits()); + else + return decrypted; + } + catch(Invalid_Argument) + { + throw Exception("PK_Decryptor_MR_with_EME: Input is invalid"); + } + catch(Decoding_Error) + { + throw Exception("PK_Decryptor_MR_with_EME: Input is invalid"); + } + } + +/* +* PK_Signer Constructor +*/ +PK_Signer::PK_Signer(const PK_Signing_Key& k, EMSA* emsa_obj) : + key(k), emsa(emsa_obj) + { + sig_format = IEEE_1363; + } + +/* +* Set the signature format +*/ +void PK_Signer::set_output_format(Signature_Format format) + { + if(key.message_parts() == 1 && format != IEEE_1363) + throw Invalid_State("PK_Signer: Cannot set the output format for " + + key.algo_name() + " keys"); + sig_format = format; + } + +/* +* Sign a message +*/ +SecureVector<byte> PK_Signer::sign_message(const byte msg[], u32bit length, + RandomNumberGenerator& rng) + { + update(msg, length); + return signature(rng); + } + +/* +* Sign a message +*/ +SecureVector<byte> PK_Signer::sign_message(const MemoryRegion<byte>& msg, + RandomNumberGenerator& rng) + { + return sign_message(msg, msg.size(), rng); + } + +/* +* Add more to the message to be signed +*/ +void PK_Signer::update(const byte in[], u32bit length) + { + emsa->update(in, length); + } + +/* +* Add more to the message to be signed +*/ +void PK_Signer::update(byte in) + { + update(&in, 1); + } + +/* +* Add more to the message to be signed +*/ +void PK_Signer::update(const MemoryRegion<byte>& in) + { + update(in, in.size()); + } + +/* +* Create a signature +*/ +SecureVector<byte> PK_Signer::signature(RandomNumberGenerator& rng) + { + SecureVector<byte> encoded = emsa->encoding_of(emsa->raw_data(), + key.max_input_bits(), + rng); + + SecureVector<byte> plain_sig = key.sign(encoded, encoded.size(), rng); + + if(key.message_parts() == 1 || sig_format == IEEE_1363) + return plain_sig; + + if(sig_format == DER_SEQUENCE) + { + if(plain_sig.size() % key.message_parts()) + throw Encoding_Error("PK_Signer: strange signature size found"); + const u32bit SIZE_OF_PART = plain_sig.size() / key.message_parts(); + + std::vector<BigInt> sig_parts(key.message_parts()); + for(u32bit j = 0; j != sig_parts.size(); ++j) + sig_parts[j].binary_decode(plain_sig + SIZE_OF_PART*j, SIZE_OF_PART); + + return DER_Encoder() + .start_cons(SEQUENCE) + .encode_list(sig_parts) + .end_cons() + .get_contents(); + } + else + throw Encoding_Error("PK_Signer: Unknown signature format " + + to_string(sig_format)); + } + +/* +* PK_Verifier Constructor +*/ +PK_Verifier::PK_Verifier(EMSA* emsa_obj) + { + emsa = emsa_obj; + sig_format = IEEE_1363; + } + +/* +* PK_Verifier Destructor +*/ +PK_Verifier::~PK_Verifier() + { + delete emsa; + } + +/* +* Set the signature format +*/ +void PK_Verifier::set_input_format(Signature_Format format) + { + if(key_message_parts() == 1 && format != IEEE_1363) + throw Invalid_State("PK_Verifier: This algorithm always uses IEEE 1363"); + sig_format = format; + } + +/* +* Verify a message +*/ +bool PK_Verifier::verify_message(const MemoryRegion<byte>& msg, + const MemoryRegion<byte>& sig) + { + return verify_message(msg, msg.size(), sig, sig.size()); + } + +/* +* Verify a message +*/ +bool PK_Verifier::verify_message(const byte msg[], u32bit msg_length, + const byte sig[], u32bit sig_length) + { + update(msg, msg_length); + return check_signature(sig, sig_length); + } + +/* +* Append to the message +*/ +void PK_Verifier::update(const byte in[], u32bit length) + { + emsa->update(in, length); + } + +/* +* Append to the message +*/ +void PK_Verifier::update(byte in) + { + update(&in, 1); + } + +/* +* Append to the message +*/ +void PK_Verifier::update(const MemoryRegion<byte>& in) + { + update(in, in.size()); + } + +/* +* Check a signature +*/ +bool PK_Verifier::check_signature(const MemoryRegion<byte>& sig) + { + return check_signature(sig, sig.size()); + } + +/* +* Check a signature +*/ +bool PK_Verifier::check_signature(const byte sig[], u32bit length) + { + try { + if(sig_format == IEEE_1363) + return validate_signature(emsa->raw_data(), sig, length); + else if(sig_format == DER_SEQUENCE) + { + BER_Decoder decoder(sig, length); + BER_Decoder ber_sig = decoder.start_cons(SEQUENCE); + + u32bit count = 0; + SecureVector<byte> real_sig; + while(ber_sig.more_items()) + { + BigInt sig_part; + ber_sig.decode(sig_part); + real_sig.append(BigInt::encode_1363(sig_part, + key_message_part_size())); + ++count; + } + if(count != key_message_parts()) + throw Decoding_Error("PK_Verifier: signature size invalid"); + + return validate_signature(emsa->raw_data(), + real_sig, real_sig.size()); + } + else + throw Decoding_Error("PK_Verifier: Unknown signature format " + + to_string(sig_format)); + } + catch(Invalid_Argument) { return false; } + catch(Decoding_Error) { return false; } + } + +/* +* Verify a signature +*/ +bool PK_Verifier_with_MR::validate_signature(const MemoryRegion<byte>& msg, + const byte sig[], u32bit sig_len) + { + SecureVector<byte> output_of_key = key.verify(sig, sig_len); + return emsa->verify(output_of_key, msg, key.max_input_bits()); + } + +/* +* Verify a signature +*/ +bool PK_Verifier_wo_MR::validate_signature(const MemoryRegion<byte>& msg, + const byte sig[], u32bit sig_len) + { + Null_RNG rng; + + SecureVector<byte> encoded = + emsa->encoding_of(msg, key.max_input_bits(), rng); + + return key.verify(encoded, encoded.size(), sig, sig_len); + } + +/* +* PK_Key_Agreement Constructor +*/ +PK_Key_Agreement::PK_Key_Agreement(const PK_Key_Agreement_Key& k, + KDF* kdf_obj) : + key(k), kdf(kdf_obj) + { + } + +/* +* Perform Key Agreement Operation +*/ +SymmetricKey PK_Key_Agreement::derive_key(u32bit key_len, + const byte in[], u32bit in_len, + const std::string& params) const + { + return derive_key(key_len, in, in_len, + reinterpret_cast<const byte*>(params.data()), + params.length()); + } + +/* +* Perform Key Agreement Operation +*/ +SymmetricKey PK_Key_Agreement::derive_key(u32bit key_len, const byte in[], + u32bit in_len, const byte params[], + u32bit params_len) const + { + OctetString z = key.derive_key(in, in_len); + if(!kdf) + return z; + + return kdf->derive_key(key_len, z.bits_of(), params, params_len); + } + +} diff --git a/botan/src/pubkey/pubkey.h b/botan/src/pubkey/pubkey.h new file mode 100644 index 0000000..c73a54d --- /dev/null +++ b/botan/src/pubkey/pubkey.h @@ -0,0 +1,392 @@ +/* +* Public Key Interface +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PUBKEY_H__ +#define BOTAN_PUBKEY_H__ + +#include <botan/pk_keys.h> +#include <botan/symkey.h> +#include <botan/rng.h> +#include <botan/eme.h> +#include <botan/emsa.h> +#include <botan/kdf.h> + +namespace Botan { + +/** +* The two types of signature format supported by Botan. +*/ +enum Signature_Format { IEEE_1363, DER_SEQUENCE }; + +/** +* Public Key Encryptor +*/ +class BOTAN_DLL PK_Encryptor + { + public: + + /** + * Encrypt a message. + * @param in the message as a byte array + * @param length the length of the above byte array + * @param rng the random number source to use + * @return the encrypted message + */ + SecureVector<byte> encrypt(const byte in[], u32bit length, + RandomNumberGenerator& rng) const; + + /** + * Encrypt a message. + * @param in the message + * @param rng the random number source to use + * @return the encrypted message + */ + SecureVector<byte> encrypt(const MemoryRegion<byte>& in, + RandomNumberGenerator& rng) const; + + /** + * Return the maximum allowed message size in bytes. + * @return the maximum message size in bytes + */ + virtual u32bit maximum_input_size() const = 0; + + virtual ~PK_Encryptor() {} + private: + virtual SecureVector<byte> enc(const byte[], u32bit, + RandomNumberGenerator&) const = 0; + }; + +/** +* Public Key Decryptor +*/ +class BOTAN_DLL PK_Decryptor + { + public: + /** + * Decrypt a ciphertext. + * @param in the ciphertext as a byte array + * @param length the length of the above byte array + * @return the decrypted message + */ + SecureVector<byte> decrypt(const byte in[], u32bit length) const; + + /** + * Decrypt a ciphertext. + * @param in the ciphertext + * @return the decrypted message + */ + SecureVector<byte> decrypt(const MemoryRegion<byte>& in) const; + + virtual ~PK_Decryptor() {} + private: + virtual SecureVector<byte> dec(const byte[], u32bit) const = 0; + }; + +/** +* Public Key Signer. Use the sign_message() functions for small +* messages. Use multiple calls update() to process large messages and +* generate the signature by finally calling signature(). +*/ +class BOTAN_DLL PK_Signer + { + public: + /** + * Sign a message. + * @param in the message to sign as a byte array + * @param length the length of the above byte array + * @param rng the rng to use + * @return the signature + */ + SecureVector<byte> sign_message(const byte in[], u32bit length, + RandomNumberGenerator& rng); + + /** + * Sign a message. + * @param in the message to sign + * @param rng the rng to use + * @return the signature + */ + SecureVector<byte> sign_message(const MemoryRegion<byte>& in, + RandomNumberGenerator& rng); + + /** + * Add a message part (single byte). + * @param the byte to add + */ + void update(byte in); + + /** + * Add a message part. + * @param in the message part to add as a byte array + * @param length the length of the above byte array + */ + void update(const byte in[], u32bit length); + + /** + * Add a message part. + * @param in the message part to add + */ + void update(const MemoryRegion<byte>& in); + + /** + * Get the signature of the so far processed message (provided by the + * calls to update()). + * @param rng the rng to use + * @return the signature of the total message + */ + SecureVector<byte> signature(RandomNumberGenerator& rng); + + /** + * Set the output format of the signature. + * @param format the signature format to use + */ + void set_output_format(Signature_Format format); + + /** + * Construct a PK Signer. + * @param key the key to use inside this signer + * @param emsa the EMSA to use + * An example would be "EMSA1(SHA-224)". + */ + PK_Signer(const PK_Signing_Key& key, EMSA* emsa); + + ~PK_Signer() { delete emsa; } + private: + PK_Signer(const PK_Signer&); + PK_Signer& operator=(const PK_Signer&); + + const PK_Signing_Key& key; + Signature_Format sig_format; + EMSA* emsa; + }; + +/** +* Public Key Verifier. Use the verify_message() functions for small +* messages. Use multiple calls update() to process large messages and +* verify the signature by finally calling check_signature(). +*/ +class BOTAN_DLL PK_Verifier + { + public: + /** + * Verify a signature. + * @param msg the message that the signature belongs to, as a byte array + * @param msg_length the length of the above byte array msg + * @param sig the signature as a byte array + * @param sig_length the length of the above byte array sig + * @return true if the signature is valid + */ + bool verify_message(const byte msg[], u32bit msg_length, + const byte sig[], u32bit sig_length); + /** + * Verify a signature. + * @param msg the message that the signature belongs to + * @param sig the signature + * @return true if the signature is valid + */ + bool verify_message(const MemoryRegion<byte>& msg, + const MemoryRegion<byte>& sig); + + /** + * Add a message part (single byte) of the message corresponding to the + * signature to be verified. + * @param msg_part the byte to add + */ + void update(byte msg_part); + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + * @param msg_part the new message part as a byte array + * @param length the length of the above byte array + */ + void update(const byte msg_part[], u32bit length); + + /** + * Add a message part of the message corresponding to the + * signature to be verified. + * @param msg_part the new message part + */ + void update(const MemoryRegion<byte>& msg_part); + + /** + * Check the signature of the buffered message, i.e. the one build + * by successive calls to update. + * @param sig the signature to be verified as a byte array + * @param length the length of the above byte array + * @return true if the signature is valid, false otherwise + */ + bool check_signature(const byte sig[], u32bit length); + + /** + * Check the signature of the buffered message, i.e. the one build + * by successive calls to update. + * @param sig the signature to be verified + * @return true if the signature is valid, false otherwise + */ + bool check_signature(const MemoryRegion<byte>& sig); + + /** + * Set the format of the signatures fed to this verifier. + * @param format the signature format to use + */ + void set_input_format(Signature_Format format); + + /** + * Construct a PK Verifier. + * @param emsa the EMSA to use + * An example would be new EMSA1(new SHA_224) + */ + PK_Verifier(EMSA* emsa); + + virtual ~PK_Verifier(); + protected: + virtual bool validate_signature(const MemoryRegion<byte>&, + const byte[], u32bit) = 0; + virtual u32bit key_message_parts() const = 0; + virtual u32bit key_message_part_size() const = 0; + + Signature_Format sig_format; + EMSA* emsa; + private: + PK_Verifier(const PK_Verifier&); + PK_Verifier& operator=(const PK_Verifier&); + }; + +/* +* Key Agreement +*/ +class BOTAN_DLL PK_Key_Agreement + { + public: + SymmetricKey derive_key(u32bit, const byte[], u32bit, + const std::string& = "") const; + SymmetricKey derive_key(u32bit, const byte[], u32bit, + const byte[], u32bit) const; + + /** + * Construct a PK Key Agreement. + * @param key the key to use + * @param kdf the KDF to use + */ + PK_Key_Agreement(const PK_Key_Agreement_Key& key, KDF* kdf); + + ~PK_Key_Agreement() { delete kdf; } + private: + PK_Key_Agreement(const PK_Key_Agreement_Key&); + PK_Key_Agreement& operator=(const PK_Key_Agreement&); + + const PK_Key_Agreement_Key& key; + KDF* kdf; + }; + +/** +* Encryption with an MR algorithm and an EME. +*/ +class BOTAN_DLL PK_Encryptor_MR_with_EME : public PK_Encryptor + { + public: + u32bit maximum_input_size() const; + + /** + * Construct an instance. + * @param key the key to use inside the decryptor + * @param eme the EME to use + */ + PK_Encryptor_MR_with_EME(const PK_Encrypting_Key& key, + EME* eme); + + ~PK_Encryptor_MR_with_EME() { delete encoder; } + private: + PK_Encryptor_MR_with_EME(const PK_Encryptor_MR_with_EME&); + PK_Encryptor_MR_with_EME& operator=(const PK_Encryptor_MR_with_EME&); + + SecureVector<byte> enc(const byte[], u32bit, + RandomNumberGenerator& rng) const; + + const PK_Encrypting_Key& key; + const EME* encoder; + }; + +/** +* Decryption with an MR algorithm and an EME. +*/ +class BOTAN_DLL PK_Decryptor_MR_with_EME : public PK_Decryptor + { + public: + /** + * Construct an instance. + * @param key the key to use inside the encryptor + * @param eme the EME to use + */ + PK_Decryptor_MR_with_EME(const PK_Decrypting_Key& key, + EME* eme); + + ~PK_Decryptor_MR_with_EME() { delete encoder; } + private: + PK_Decryptor_MR_with_EME(const PK_Decryptor_MR_with_EME&); + PK_Decryptor_MR_with_EME& operator=(const PK_Decryptor_MR_with_EME&); + + SecureVector<byte> dec(const byte[], u32bit) const; + + const PK_Decrypting_Key& key; + const EME* encoder; + }; + +/** +* Public Key Verifier with Message Recovery. +*/ +class BOTAN_DLL PK_Verifier_with_MR : public PK_Verifier + { + public: + /** + * Construct an instance. + * @param key the key to use inside the verifier + * @param emsa_name the name of the EMSA to use + */ + PK_Verifier_with_MR(const PK_Verifying_with_MR_Key& k, + EMSA* emsa_obj) : PK_Verifier(emsa_obj), key(k) {} + + private: + PK_Verifier_with_MR(const PK_Verifying_with_MR_Key&); + PK_Verifier_with_MR& operator=(const PK_Verifier_with_MR&); + + bool validate_signature(const MemoryRegion<byte>&, const byte[], u32bit); + u32bit key_message_parts() const { return key.message_parts(); } + u32bit key_message_part_size() const { return key.message_part_size(); } + + const PK_Verifying_with_MR_Key& key; + }; + +/** +* Public Key Verifier without Message Recovery +*/ +class BOTAN_DLL PK_Verifier_wo_MR : public PK_Verifier + { + public: + /** + * Construct an instance. + * @param key the key to use inside the verifier + * @param emsa_name the name of the EMSA to use + */ + PK_Verifier_wo_MR(const PK_Verifying_wo_MR_Key& k, + EMSA* emsa_obj) : PK_Verifier(emsa_obj), key(k) {} + + private: + PK_Verifier_wo_MR(const PK_Verifying_wo_MR_Key&); + PK_Verifier_wo_MR& operator=(const PK_Verifier_wo_MR&); + + bool validate_signature(const MemoryRegion<byte>&, const byte[], u32bit); + u32bit key_message_parts() const { return key.message_parts(); } + u32bit key_message_part_size() const { return key.message_part_size(); } + + const PK_Verifying_wo_MR_Key& key; + }; + +} + +#endif diff --git a/botan/src/pubkey/pubkey_enums.cpp b/botan/src/pubkey/pubkey_enums.cpp new file mode 100644 index 0000000..327107d --- /dev/null +++ b/botan/src/pubkey/pubkey_enums.cpp @@ -0,0 +1,42 @@ +/* +* KeyUsage +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/pubkey_enums.h> +#include <botan/ber_dec.h> + +namespace Botan { + +namespace BER { + +/* +* Decode a BER encoded KeyUsage +*/ +void decode(BER_Decoder& source, Key_Constraints& key_usage) + { + BER_Object obj = source.get_next_object(); + + if(obj.type_tag != BIT_STRING || obj.class_tag != UNIVERSAL) + throw BER_Bad_Tag("Bad tag for usage constraint", + obj.type_tag, obj.class_tag); + if(obj.value.size() != 2 && obj.value.size() != 3) + throw BER_Decoding_Error("Bad size for BITSTRING in usage constraint"); + if(obj.value[0] >= 8) + throw BER_Decoding_Error("Invalid unused bits in usage constraint"); + + const byte mask = (0xFF << obj.value[0]); + obj.value[obj.value.size()-1] &= mask; + + u16bit usage = 0; + for(u32bit j = 1; j != obj.value.size(); ++j) + usage = (obj.value[j] << 8) | usage; + + key_usage = Key_Constraints(usage); + } + +} + +} diff --git a/botan/src/pubkey/pubkey_enums.h b/botan/src/pubkey/pubkey_enums.h new file mode 100644 index 0000000..53e319f --- /dev/null +++ b/botan/src/pubkey/pubkey_enums.h @@ -0,0 +1,77 @@ +/* +* Enumerations +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_ENUMS_H__ +#define BOTAN_ENUMS_H__ + +#include <botan/ber_dec.h> + +namespace Botan { + +/** +* X.509v3 Key Constraints. +*/ +enum Key_Constraints { + NO_CONSTRAINTS = 0, + DIGITAL_SIGNATURE = 32768, + NON_REPUDIATION = 16384, + KEY_ENCIPHERMENT = 8192, + DATA_ENCIPHERMENT = 4096, + KEY_AGREEMENT = 2048, + KEY_CERT_SIGN = 1024, + CRL_SIGN = 512, + ENCIPHER_ONLY = 256, + DECIPHER_ONLY = 128 +}; + +/** +* BER Decoding Function for key constraints +*/ +namespace BER { + +void BOTAN_DLL decode(BER_Decoder&, Key_Constraints&); + +} + +/** +* X.509v2 CRL Reason Code. +*/ +enum CRL_Code { + UNSPECIFIED = 0, + KEY_COMPROMISE = 1, + CA_COMPROMISE = 2, + AFFILIATION_CHANGED = 3, + SUPERSEDED = 4, + CESSATION_OF_OPERATION = 5, + CERTIFICATE_HOLD = 6, + REMOVE_FROM_CRL = 8, + PRIVLEDGE_WITHDRAWN = 9, + AA_COMPROMISE = 10, + + DELETE_CRL_ENTRY = 0xFF00, + OCSP_GOOD = 0xFF01, + OCSP_UNKNOWN = 0xFF02 +}; + +/* +* Various Other Enumerations +*/ + +/** +* The two types of X509 encoding supported by Botan. +*/ +enum X509_Encoding { RAW_BER, PEM }; + +/** +* Value to encode in case of no path limit in the X509 +* BasicConstraints extension. +*/ +static const u32bit NO_CERT_PATH_LIMIT = 0xFFFFFFF0; + +} + +#endif diff --git a/botan/src/pubkey/rsa/info.txt b/botan/src/pubkey/rsa/info.txt new file mode 100644 index 0000000..7729fd8 --- /dev/null +++ b/botan/src/pubkey/rsa/info.txt @@ -0,0 +1,17 @@ +realname "RSA" + +define RSA + +load_on auto + +<add> +rsa.cpp +rsa.h +</add> + +<requires> +if_algo +keypair +libstate +numbertheory +</requires> diff --git a/botan/src/pubkey/rsa/rsa.cpp b/botan/src/pubkey/rsa/rsa.cpp new file mode 100644 index 0000000..83e6e1b --- /dev/null +++ b/botan/src/pubkey/rsa/rsa.cpp @@ -0,0 +1,164 @@ +/* +* RSA +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/rsa.h> +#include <botan/parsing.h> +#include <botan/numthry.h> +#include <botan/keypair.h> +#include <botan/look_pk.h> + +namespace Botan { + +/* +* RSA_PublicKey Constructor +*/ +RSA_PublicKey::RSA_PublicKey(const BigInt& mod, const BigInt& exp) + { + n = mod; + e = exp; + X509_load_hook(); + } + +/* +* RSA Public Operation +*/ +BigInt RSA_PublicKey::public_op(const BigInt& i) const + { + if(i >= n) + throw Invalid_Argument(algo_name() + "::public_op: input is too large"); + return core.public_op(i); + } + +/* +* RSA Encryption Function +*/ +SecureVector<byte> RSA_PublicKey::encrypt(const byte in[], u32bit len, + RandomNumberGenerator&) const + { + BigInt i(in, len); + return BigInt::encode_1363(public_op(i), n.bytes()); + } + +/* +* RSA Verification Function +*/ +SecureVector<byte> RSA_PublicKey::verify(const byte in[], u32bit len) const + { + BigInt i(in, len); + return BigInt::encode(public_op(i)); + } + +/* +* Create a RSA private key +*/ +RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng, + u32bit bits, u32bit exp) + { + if(bits < 512) + throw Invalid_Argument(algo_name() + ": Can't make a key that is only " + + to_string(bits) + " bits long"); + if(exp < 3 || exp % 2 == 0) + throw Invalid_Argument(algo_name() + ": Invalid encryption exponent"); + + e = exp; + p = random_prime(rng, (bits + 1) / 2, e); + q = random_prime(rng, bits - p.bits(), e); + d = inverse_mod(e, lcm(p - 1, q - 1)); + + PKCS8_load_hook(rng, true); + + if(n.bits() != bits) + throw Self_Test_Failure(algo_name() + " private key generation failed"); + } + +/* +* RSA_PrivateKey Constructor +*/ +RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng, + const BigInt& prime1, const BigInt& prime2, + const BigInt& exp, const BigInt& d_exp, + const BigInt& mod) + { + p = prime1; + q = prime2; + e = exp; + d = d_exp; + n = mod; + + if(d == 0) + d = inverse_mod(e, lcm(p - 1, q - 1)); + + PKCS8_load_hook(rng); + } + +/* +* RSA Private Operation +*/ +BigInt RSA_PrivateKey::private_op(const byte in[], u32bit length) const + { + BigInt i(in, length); + if(i >= n) + throw Invalid_Argument(algo_name() + "::private_op: input is too large"); + + BigInt r = core.private_op(i); + if(i != public_op(r)) + throw Self_Test_Failure(algo_name() + " private operation check failed"); + return r; + } + +/* +* RSA Decryption Operation +*/ +SecureVector<byte> RSA_PrivateKey::decrypt(const byte in[], u32bit len) const + { + return BigInt::encode(private_op(in, len)); + } + +/* +* RSA Signature Operation +*/ +SecureVector<byte> RSA_PrivateKey::sign(const byte in[], u32bit len, + RandomNumberGenerator&) const + { + return BigInt::encode_1363(private_op(in, len), n.bytes()); + } + +/* +* Check Private RSA Parameters +*/ +bool RSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!IF_Scheme_PrivateKey::check_key(rng, strong)) + return false; + + if(!strong) + return true; + + if((e * d) % lcm(p - 1, q - 1) != 1) + return false; + + try + { + KeyPair::check_key(rng, + get_pk_encryptor(*this, "EME1(SHA-1)"), + get_pk_decryptor(*this, "EME1(SHA-1)") + ); + + KeyPair::check_key(rng, + get_pk_signer(*this, "EMSA4(SHA-1)"), + get_pk_verifier(*this, "EMSA4(SHA-1)") + ); + } + catch(Self_Test_Failure) + { + return false; + } + + return true; + } + +} diff --git a/botan/src/pubkey/rsa/rsa.h b/botan/src/pubkey/rsa/rsa.h new file mode 100644 index 0000000..f07533a --- /dev/null +++ b/botan/src/pubkey/rsa/rsa.h @@ -0,0 +1,88 @@ +/* +* RSA +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RSA_H__ +#define BOTAN_RSA_H__ + +#include <botan/if_algo.h> + +namespace Botan { + +/** +* RSA Public Key +*/ +class BOTAN_DLL RSA_PublicKey : public PK_Encrypting_Key, + public PK_Verifying_with_MR_Key, + public virtual IF_Scheme_PublicKey + { + public: + std::string algo_name() const { return "RSA"; } + + SecureVector<byte> encrypt(const byte[], u32bit, + RandomNumberGenerator& rng) const; + + SecureVector<byte> verify(const byte[], u32bit) const; + + RSA_PublicKey() {} + RSA_PublicKey(const BigInt&, const BigInt&); + protected: + BigInt public_op(const BigInt&) const; + }; + +/** +* RSA Private Key class. +*/ +class BOTAN_DLL RSA_PrivateKey : public RSA_PublicKey, + public PK_Decrypting_Key, + public PK_Signing_Key, + public IF_Scheme_PrivateKey + { + public: + SecureVector<byte> sign(const byte[], u32bit, + RandomNumberGenerator&) const; + + SecureVector<byte> decrypt(const byte[], u32bit) const; + + bool check_key(RandomNumberGenerator& rng, bool) const; + + /** + * Default constructor, does not set any internal values. Use this + * constructor if you wish to decode a DER or PEM encoded key. + */ + RSA_PrivateKey() {} + + /** + * Construct a private key from the specified parameters. + * @param rng the random number generator to use + * @param prime1 the first prime + * @param prime2 the second prime + * @param exp the exponent + * @param d_exp if specified, this has to be d with + * exp * d = 1 mod (p - 1, q - 1). Leave it as 0 if you wish to + * the constructor to calculate it. + * @param n if specified, this must be n = p * q. Leave it as 0 + * if you wish to the constructor to calculate it. + */ + RSA_PrivateKey(RandomNumberGenerator& rng, + const BigInt& p, const BigInt& q, const BigInt& e, + const BigInt& d = 0, const BigInt& n = 0); + + /** + * Create a new private key with the specified bit length + * @param rng the random number generator to use + * @param bits the desired bit length of the private key + * @param exp the public exponent to be used + */ + RSA_PrivateKey(RandomNumberGenerator& rng, + u32bit bits, u32bit exp = 65537); + private: + BigInt private_op(const byte[], u32bit) const; + }; + +} + +#endif diff --git a/botan/src/pubkey/rw/info.txt b/botan/src/pubkey/rw/info.txt new file mode 100644 index 0000000..ada6c37 --- /dev/null +++ b/botan/src/pubkey/rw/info.txt @@ -0,0 +1,17 @@ +realname "Rabin-Williams" + +define RW + +load_on auto + +<add> +rw.cpp +rw.h +</add> + +<requires> +if_algo +keypair +libstate +numbertheory +</requires> diff --git a/botan/src/pubkey/rw/rw.cpp b/botan/src/pubkey/rw/rw.cpp new file mode 100644 index 0000000..def0ae6 --- /dev/null +++ b/botan/src/pubkey/rw/rw.cpp @@ -0,0 +1,148 @@ +/* +* Rabin-Williams +* (C) 1999-2008 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/rw.h> +#include <botan/numthry.h> +#include <botan/keypair.h> +#include <botan/look_pk.h> +#include <botan/parsing.h> +#include <algorithm> + +namespace Botan { + +/* +* RW_PublicKey Constructor +*/ +RW_PublicKey::RW_PublicKey(const BigInt& mod, const BigInt& exp) + { + n = mod; + e = exp; + X509_load_hook(); + } + +/* +* Rabin-Williams Public Operation +*/ +BigInt RW_PublicKey::public_op(const BigInt& i) const + { + if((i > (n >> 1)) || i.is_negative()) + throw Invalid_Argument(algo_name() + "::public_op: i > n / 2 || i < 0"); + + BigInt r = core.public_op(i); + if(r % 16 == 12) return r; + if(r % 8 == 6) return 2*r; + + r = n - r; + if(r % 16 == 12) return r; + if(r % 8 == 6) return 2*r; + + throw Invalid_Argument(algo_name() + "::public_op: Invalid input"); + } + +/* +* Rabin-Williams Verification Function +*/ +SecureVector<byte> RW_PublicKey::verify(const byte in[], u32bit len) const + { + BigInt i(in, len); + return BigInt::encode(public_op(i)); + } + +/* +* Create a Rabin-Williams private key +*/ +RW_PrivateKey::RW_PrivateKey(RandomNumberGenerator& rng, + u32bit bits, u32bit exp) + { + if(bits < 512) + throw Invalid_Argument(algo_name() + ": Can't make a key that is only " + + to_string(bits) + " bits long"); + if(exp < 2 || exp % 2 == 1) + throw Invalid_Argument(algo_name() + ": Invalid encryption exponent"); + + e = exp; + p = random_prime(rng, (bits + 1) / 2, e / 2, 3, 4); + q = random_prime(rng, bits - p.bits(), e / 2, ((p % 8 == 3) ? 7 : 3), 8); + d = inverse_mod(e, lcm(p - 1, q - 1) >> 1); + + PKCS8_load_hook(rng, true); + + if(n.bits() != bits) + throw Self_Test_Failure(algo_name() + " private key generation failed"); + } + +/* +* RW_PrivateKey Constructor +*/ +RW_PrivateKey::RW_PrivateKey(RandomNumberGenerator& rng, + const BigInt& prime1, const BigInt& prime2, + const BigInt& exp, const BigInt& d_exp, + const BigInt& mod) + { + p = prime1; + q = prime2; + e = exp; + d = d_exp; + n = mod; + + if(d == 0) + d = inverse_mod(e, lcm(p - 1, q - 1) >> 1); + + PKCS8_load_hook(rng); + } + +/* +* Rabin-Williams Signature Operation +*/ +SecureVector<byte> RW_PrivateKey::sign(const byte in[], u32bit len, + RandomNumberGenerator&) const + { + BigInt i(in, len); + if(i >= n || i % 16 != 12) + throw Invalid_Argument(algo_name() + "::sign: Invalid input"); + + BigInt r; + if(jacobi(i, n) == 1) r = core.private_op(i); + else r = core.private_op(i >> 1); + + r = std::min(r, n - r); + if(i != public_op(r)) + throw Self_Test_Failure(algo_name() + " private operation check failed"); + + return BigInt::encode_1363(r, n.bytes()); + } + +/* +* Check Private Rabin-Williams Parameters +*/ +bool RW_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const + { + if(!IF_Scheme_PrivateKey::check_key(rng, strong)) + return false; + + if(!strong) + return true; + + if((e * d) % (lcm(p - 1, q - 1) / 2) != 1) + return false; + + try + { + KeyPair::check_key(rng, + get_pk_signer(*this, "EMSA2(SHA-1)"), + get_pk_verifier(*this, "EMSA2(SHA-1)") + ); + } + catch(Self_Test_Failure) + { + return false; + } + + return true; + } + +} diff --git a/botan/src/pubkey/rw/rw.h b/botan/src/pubkey/rw/rw.h new file mode 100644 index 0000000..900e5eb --- /dev/null +++ b/botan/src/pubkey/rw/rw.h @@ -0,0 +1,56 @@ +/* +* Rabin-Williams +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_RW_H__ +#define BOTAN_RW_H__ + +#include <botan/if_algo.h> + +namespace Botan { + +/* +* Rabin-Williams Public Key +*/ +class BOTAN_DLL RW_PublicKey : public PK_Verifying_with_MR_Key, + public virtual IF_Scheme_PublicKey + { + public: + std::string algo_name() const { return "RW"; } + + SecureVector<byte> verify(const byte[], u32bit) const; + + RW_PublicKey() {} + RW_PublicKey(const BigInt&, const BigInt&); + protected: + BigInt public_op(const BigInt&) const; + }; + +/* +* Rabin-Williams Private Key +*/ +class BOTAN_DLL RW_PrivateKey : public RW_PublicKey, + public PK_Signing_Key, + public IF_Scheme_PrivateKey + { + public: + SecureVector<byte> sign(const byte[], u32bit, + RandomNumberGenerator& rng) const; + + bool check_key(RandomNumberGenerator& rng, bool) const; + + RW_PrivateKey() {} + + RW_PrivateKey(RandomNumberGenerator&, + const BigInt&, const BigInt&, const BigInt&, + const BigInt& = 0, const BigInt& = 0); + + RW_PrivateKey(RandomNumberGenerator& rng, u32bit bits, u32bit = 2); + }; + +} + +#endif |