aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/pubkey
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-08-31 12:58:58 -0400
committerJack Lloyd <[email protected]>2016-08-31 12:58:58 -0400
commitdfab07a7bc00dc00f98ab86c70d536306073f34f (patch)
treed3dbb140764f259c932171d6f229d033dee685ca /src/lib/pubkey
parente29024608fca1b811aa72a7aafd930a42740b968 (diff)
parent1b9cf39063194fe91dc8e5d78f73d7251c5d16fc (diff)
Merge master into this branch, resolving conflicts with #457/#576
which recently landed on master.
Diffstat (limited to 'src/lib/pubkey')
-rw-r--r--src/lib/pubkey/curve25519/donna.cpp76
-rw-r--r--src/lib/pubkey/dh/dh.cpp9
-rw-r--r--src/lib/pubkey/dlies/dlies.cpp257
-rw-r--r--src/lib/pubkey/dlies/dlies.h101
-rw-r--r--src/lib/pubkey/dlies/info.txt3
-rw-r--r--src/lib/pubkey/dsa/dsa.cpp26
-rw-r--r--src/lib/pubkey/dsa/info.txt3
-rw-r--r--src/lib/pubkey/ec_group/named.cpp10
-rw-r--r--src/lib/pubkey/ecdsa/ecdsa.cpp23
-rw-r--r--src/lib/pubkey/ecdsa/info.txt3
-rw-r--r--src/lib/pubkey/ecgdsa/ecgdsa.cpp7
-rw-r--r--src/lib/pubkey/ecgdsa/info.txt2
-rw-r--r--src/lib/pubkey/ecies/ecies.cpp398
-rw-r--r--src/lib/pubkey/ecies/ecies.h293
-rw-r--r--src/lib/pubkey/ecies/info.txt8
-rw-r--r--src/lib/pubkey/eckcdsa/eckcdsa.cpp200
-rw-r--r--src/lib/pubkey/eckcdsa/eckcdsa.h91
-rw-r--r--src/lib/pubkey/eckcdsa/info.txt13
-rw-r--r--src/lib/pubkey/pk_algs.cpp14
-rw-r--r--src/lib/pubkey/pk_ops.cpp28
-rw-r--r--src/lib/pubkey/pk_ops_impl.h37
-rw-r--r--src/lib/pubkey/pubkey.cpp6
-rw-r--r--src/lib/pubkey/rfc6979/rfc6979.cpp23
-rw-r--r--src/lib/pubkey/rfc6979/rfc6979.h8
-rw-r--r--src/lib/pubkey/rsa/info.txt2
-rw-r--r--src/lib/pubkey/rsa/rsa.cpp2
26 files changed, 1456 insertions, 187 deletions
diff --git a/src/lib/pubkey/curve25519/donna.cpp b/src/lib/pubkey/curve25519/donna.cpp
index 9b28e412c..a0e4d249f 100644
--- a/src/lib/pubkey/curve25519/donna.cpp
+++ b/src/lib/pubkey/curve25519/donna.cpp
@@ -39,6 +39,26 @@ typedef byte u8;
typedef u64bit limb;
typedef limb felem[5];
+typedef struct
+ {
+ limb* x;
+ limb* z;
+ } fmonty_pair_t;
+
+typedef struct
+ {
+ fmonty_pair_t q;
+ fmonty_pair_t q_dash;
+ const limb* q_minus_q_dash;
+ } fmonty_in_t;
+
+typedef struct
+ {
+ fmonty_pair_t two_q;
+ fmonty_pair_t q_plus_q_dash;
+ } fmonty_out_t;
+
+
#if !defined(BOTAN_TARGET_HAS_NATIVE_UINT128)
typedef donna128 uint128_t;
#endif
@@ -273,44 +293,41 @@ fcontract(u8 *output, const felem input) {
/* Input: Q, Q', Q-Q'
* Output: 2Q, Q+Q'
*
- * x2 z3: long form
- * x3 z3: long form
- * x z: short form, destroyed
- * xprime zprime: short form, destroyed
- * qmqp: short form, preserved
+ * result.two_q (2*Q): long form
+ * result.q_plus_q_dash (Q + Q): long form
+ * in.q: short form, destroyed
+ * in.q_dash: short form, destroyed
+ * in.q_minus_q_dash: short form, preserved
*/
static void
-fmonty(limb *x2, limb *z2, /* output 2Q */
- limb *x3, limb *z3, /* output Q + Q' */
- limb *x, limb *z, /* input Q */
- limb *xprime, limb *zprime, /* input Q' */
- const limb *qmqp /* input Q - Q' */) {
+fmonty(fmonty_out_t& result, fmonty_in_t& in)
+{
limb origx[5], origxprime[5], zzz[5], xx[5], zz[5], xxprime[5],
- zzprime[5], zzzprime[5];
+ zzprime[5], zzzprime[5];
- copy_mem(origx, x, 5);
- fsum(x, z);
- fdifference_backwards(z, origx); // does x - z
+ copy_mem(origx, in.q.x, 5);
+ fsum(in.q.x, in.q.z);
+ fdifference_backwards(in.q.z, origx); // does x - z
- copy_mem(origxprime, xprime, 5);
- fsum(xprime, zprime);
- fdifference_backwards(zprime, origxprime);
- fmul(xxprime, xprime, z);
- fmul(zzprime, x, zprime);
+ copy_mem(origxprime, in.q_dash.x, 5);
+ fsum(in.q_dash.x, in.q_dash.z);
+ fdifference_backwards(in.q_dash.z, origxprime);
+ fmul(xxprime, in.q_dash.x, in.q.z);
+ fmul(zzprime, in.q.x, in.q_dash.z);
copy_mem(origxprime, xxprime, 5);
fsum(xxprime, zzprime);
fdifference_backwards(zzprime, origxprime);
- fsquare_times(x3, xxprime, 1);
+ fsquare_times(result.q_plus_q_dash.x, xxprime, 1);
fsquare_times(zzzprime, zzprime, 1);
- fmul(z3, zzzprime, qmqp);
+ fmul(result.q_plus_q_dash.z, zzzprime, in.q_minus_q_dash);
- fsquare_times(xx, x, 1);
- fsquare_times(zz, z, 1);
- fmul(x2, xx, zz);
+ fsquare_times(xx, in.q.x, 1);
+ fsquare_times(zz, in.q.z, 1);
+ fmul(result.two_q.x, xx, zz);
fdifference_backwards(zz, xx); // does zz = xx - zz
fscalar_product(zzz, zz, 121665);
fsum(zzz, xx);
- fmul(z2, zz, zzz);
+ fmul(result.two_q.z, zz, zzz);
}
// -----------------------------------------------------------------------------
@@ -356,11 +373,10 @@ cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
swap_conditional(nqx, nqpqx, bit);
swap_conditional(nqz, nqpqz, bit);
- fmonty(nqx2, nqz2,
- nqpqx2, nqpqz2,
- nqx, nqz,
- nqpqx, nqpqz,
- q);
+
+ fmonty_out_t result { nqx2, nqz2, nqpqx2, nqpqz2 };
+ fmonty_in_t in { nqx, nqz, nqpqx, nqpqz, q };
+ fmonty(result, in);
swap_conditional(nqx2, nqpqx2, bit);
swap_conditional(nqz2, nqpqz2, bit);
diff --git a/src/lib/pubkey/dh/dh.cpp b/src/lib/pubkey/dh/dh.cpp
index 9eb4e5cd0..8ed79aa3d 100644
--- a/src/lib/pubkey/dh/dh.cpp
+++ b/src/lib/pubkey/dh/dh.cpp
@@ -37,6 +37,7 @@ DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng,
const DL_Group& grp,
const BigInt& x_arg)
{
+ const bool generate = (x_arg == 0) ? true : false;
m_group = grp;
m_x = x_arg;
@@ -47,12 +48,18 @@ DH_PrivateKey::DH_PrivateKey(RandomNumberGenerator& rng,
}
if(m_y == 0)
+ {
m_y = power_mod(group_g(), m_x, group_p());
+ }
- if(m_x == 0)
+ if(generate)
+ {
gen_check(rng);
+ }
else
+ {
load_check(rng);
+ }
}
/*
diff --git a/src/lib/pubkey/dlies/dlies.cpp b/src/lib/pubkey/dlies/dlies.cpp
index 2c98966b0..9666a1c23 100644
--- a/src/lib/pubkey/dlies/dlies.cpp
+++ b/src/lib/pubkey/dlies/dlies.cpp
@@ -1,6 +1,7 @@
/*
* DLIES
* (C) 1999-2007 Jack Lloyd
+* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -10,128 +11,204 @@
namespace Botan {
-/*
-* DLIES_Encryptor Constructor
-*/
-DLIES_Encryptor::DLIES_Encryptor(const PK_Key_Agreement_Key& key,
- KDF* kdf_obj,
- MessageAuthenticationCode* mac_obj,
- size_t mac_kl) :
- m_ka(key, "Raw"),
- m_kdf(kdf_obj),
- m_mac(mac_obj),
- m_mac_keylen(mac_kl)
+DLIES_Encryptor::DLIES_Encryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_length) :
+ DLIES_Encryptor(own_priv_key, kdf, nullptr, 0, mac, mac_key_length)
{
- BOTAN_ASSERT_NONNULL(kdf_obj);
- BOTAN_ASSERT_NONNULL(mac_obj);
- m_my_key = key.public_value();
}
-/*
-* DLIES Encryption
-*/
+DLIES_Encryptor::DLIES_Encryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ Cipher_Mode* cipher,
+ size_t cipher_key_len,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_length) :
+ m_other_pub_key(),
+ m_own_pub_key(own_priv_key.public_value()),
+ m_ka(own_priv_key, "Raw"),
+ m_kdf(kdf),
+ m_cipher(cipher),
+ m_cipher_key_len(cipher_key_len),
+ m_mac(mac),
+ m_mac_keylen(mac_key_length),
+ m_iv()
+ {
+ BOTAN_ASSERT_NONNULL(kdf);
+ BOTAN_ASSERT_NONNULL(mac);
+ }
+
std::vector<byte> DLIES_Encryptor::enc(const byte in[], size_t length,
RandomNumberGenerator&) const
{
- if(length > maximum_input_size())
- throw Invalid_Argument("DLIES: Plaintext too large");
- if(m_other_key.empty())
+ if(m_other_pub_key.empty())
+ {
throw Invalid_State("DLIES: The other key was never set");
+ }
- secure_vector<byte> out(m_my_key.size() + length + m_mac->output_length());
- buffer_insert(out, 0, m_my_key);
- buffer_insert(out, m_my_key.size(), in, length);
+ // calculate secret value
+ const SymmetricKey secret_value = m_ka.derive_key(0, m_other_pub_key);
- secure_vector<byte> vz(m_my_key.begin(), m_my_key.end());
- vz += m_ka.derive_key(0, m_other_key).bits_of();
+ // derive secret key from secret value
+ const size_t required_key_length = m_cipher ? m_cipher_key_len + m_mac_keylen : length + m_mac_keylen;
+ const secure_vector<byte> secret_keys = m_kdf->derive_key(required_key_length, secret_value.bits_of());
- const size_t K_LENGTH = length + m_mac_keylen;
- secure_vector<byte> K = m_kdf->derive_key(K_LENGTH, vz);
-
- if(K.size() != K_LENGTH)
+ if(secret_keys.size() != required_key_length)
+ {
throw Encoding_Error("DLIES: KDF did not provide sufficient output");
- byte* C = &out[m_my_key.size()];
-
- m_mac->set_key(K.data(), m_mac_keylen);
- xor_buf(C, &K[m_mac_keylen], length);
-
- m_mac->update(C, length);
- for(size_t j = 0; j != 8; ++j)
- m_mac->update(0);
-
- m_mac->final(C + length);
+ }
+
+ secure_vector<byte> ciphertext(in, in + length);
+ const size_t cipher_key_len = m_cipher ? m_cipher_key_len : length;
+
+ if(m_cipher)
+ {
+ SymmetricKey enc_key(secret_keys.data(), cipher_key_len);
+ m_cipher->set_key(enc_key);
+
+ if(m_iv.size())
+ {
+ m_cipher->start(m_iv.bits_of());
+ }
+
+ m_cipher->finish(ciphertext);
+ }
+ else
+ {
+ xor_buf(ciphertext, secret_keys, cipher_key_len);
+ }
+
+ // calculate MAC
+ m_mac->set_key(secret_keys.data() + cipher_key_len, m_mac_keylen);
+ secure_vector<byte> tag = m_mac->process(ciphertext);
+
+ // out = (ephemeral) public key + ciphertext + tag
+ secure_vector<byte> out(m_own_pub_key.size() + ciphertext.size() + tag.size());
+ buffer_insert(out, 0, m_own_pub_key);
+ buffer_insert(out, 0 + m_own_pub_key.size(), ciphertext);
+ buffer_insert(out, 0 + m_own_pub_key.size() + ciphertext.size(), tag);
return unlock(out);
}
-/*
-* Set the other parties public key
-*/
-void DLIES_Encryptor::set_other_key(const std::vector<byte>& ok)
- {
- m_other_key = ok;
- }
-
-/*
+/**
* Return the max size, in bytes, of a message
+* Not_Implemented if DLIES is used in XOR encryption mode
*/
size_t DLIES_Encryptor::maximum_input_size() const
{
- return 32;
+ if(m_cipher)
+ {
+ // no limit in block cipher mode
+ return std::numeric_limits<size_t>::max();
+ }
+ else
+ {
+ // No way to determine if the KDF will output enough bits for XORing with the plaintext?!
+ throw Not_Implemented("Not implemented for XOR encryption mode");
+ }
}
-/*
-* DLIES_Decryptor Constructor
-*/
-DLIES_Decryptor::DLIES_Decryptor(const PK_Key_Agreement_Key& key,
- KDF* kdf_obj,
- MessageAuthenticationCode* mac_obj,
- size_t mac_kl) :
- m_ka(key, "Raw"),
- m_kdf(kdf_obj),
- m_mac(mac_obj),
- m_mac_keylen(mac_kl)
+DLIES_Decryptor::DLIES_Decryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ Cipher_Mode* cipher,
+ size_t cipher_key_len,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_length) :
+ m_pub_key_size(own_priv_key.public_value().size()),
+ m_ka(own_priv_key, "Raw"),
+ m_kdf(kdf),
+ m_cipher(cipher),
+ m_cipher_key_len(cipher_key_len),
+ m_mac(mac),
+ m_mac_keylen(mac_key_length),
+ m_iv()
{
- m_my_key = key.public_value();
+ BOTAN_ASSERT_NONNULL(kdf);
+ BOTAN_ASSERT_NONNULL(mac);
}
-/*
-* DLIES Decryption
-*/
+DLIES_Decryptor::DLIES_Decryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_length) :
+ DLIES_Decryptor(own_priv_key, kdf, nullptr, 0, mac, mac_key_length)
+ {}
+
secure_vector<byte> DLIES_Decryptor::do_decrypt(byte& valid_mask,
- const byte msg[], size_t length) const
+ const byte msg[], size_t length) const
{
- if(length < m_my_key.size() + m_mac->output_length())
+ if(length < m_pub_key_size + m_mac->output_length())
+ {
throw Decoding_Error("DLIES decryption: ciphertext is too short");
+ }
- const size_t CIPHER_LEN = length - m_my_key.size() - m_mac->output_length();
-
- std::vector<byte> v(msg, msg + m_my_key.size());
+ // calculate secret value
+ std::vector<byte> other_pub_key(msg, msg + m_pub_key_size);
+ const SymmetricKey secret_value = m_ka.derive_key(0, other_pub_key);
- secure_vector<byte> C(msg + m_my_key.size(), msg + m_my_key.size() + CIPHER_LEN);
+ const size_t ciphertext_len = length - m_pub_key_size - m_mac->output_length();
+ size_t cipher_key_len = m_cipher ? m_cipher_key_len : ciphertext_len;
- secure_vector<byte> T(msg + m_my_key.size() + CIPHER_LEN,
- msg + m_my_key.size() + CIPHER_LEN + m_mac->output_length());
+ // derive secret key from secret value
+ const size_t required_key_length = cipher_key_len + m_mac_keylen;
+ secure_vector<byte> secret_keys = m_kdf->derive_key(required_key_length, secret_value.bits_of());
- secure_vector<byte> vz(msg, msg + m_my_key.size());
- vz += m_ka.derive_key(0, v).bits_of();
-
- const size_t K_LENGTH = C.size() + m_mac_keylen;
- secure_vector<byte> K = m_kdf->derive_key(K_LENGTH, vz);
- if(K.size() != K_LENGTH)
+ if(secret_keys.size() != required_key_length)
+ {
throw Encoding_Error("DLIES: KDF did not provide sufficient output");
-
- m_mac->set_key(K.data(), m_mac_keylen);
- m_mac->update(C);
- for(size_t j = 0; j != 8; ++j)
- m_mac->update(0);
- secure_vector<byte> T2 = m_mac->final();
-
- valid_mask = CT::expand_mask<byte>(same_mem(T.data(), T2.data(), T.size()));
-
- xor_buf(C, K.data() + m_mac_keylen, C.size());
-
- return C;
+ }
+
+ secure_vector<byte> ciphertext(msg + m_pub_key_size, msg + m_pub_key_size + ciphertext_len);
+
+ // calculate MAC
+ m_mac->set_key(secret_keys.data() + cipher_key_len, m_mac_keylen);
+ secure_vector<byte> calculated_tag = m_mac->process(ciphertext);
+
+ // calculated tag == received tag ?
+ secure_vector<byte> tag(msg + m_pub_key_size + ciphertext_len,
+ msg + m_pub_key_size + ciphertext_len + m_mac->output_length());
+
+ valid_mask = CT::expand_mask<byte>(same_mem(tag.data(), calculated_tag.data(), tag.size()));
+
+ // decrypt
+ if(m_cipher)
+ {
+ if(valid_mask)
+ {
+ SymmetricKey dec_key(secret_keys.data(), cipher_key_len);
+ m_cipher->set_key(dec_key);
+
+ try
+ {
+ // the decryption can fail:
+ // e.g. Integrity_Failure is thrown if GCM is used and the message does not have a valid tag
+
+ if(m_iv.size())
+ {
+ m_cipher->start(m_iv.bits_of());
+ }
+
+ m_cipher->finish(ciphertext);
+ }
+ catch(...)
+ {
+ valid_mask = 0;
+ }
+
+ }
+ else
+ {
+ return secure_vector<byte>();
+ }
+ }
+ else
+ {
+ xor_buf(ciphertext, secret_keys.data(), cipher_key_len);
+ }
+
+ return ciphertext;
}
}
diff --git a/src/lib/pubkey/dlies/dlies.h b/src/lib/pubkey/dlies/dlies.h
index 10471048d..5f7251d03 100644
--- a/src/lib/pubkey/dlies/dlies.h
+++ b/src/lib/pubkey/dlies/dlies.h
@@ -1,6 +1,7 @@
/*
* DLIES
* (C) 1999-2007 Jack Lloyd
+* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -11,6 +12,8 @@
#include <botan/pubkey.h>
#include <botan/mac.h>
#include <botan/kdf.h>
+#include <botan/dh.h>
+#include <botan/cipher_mode.h>
namespace Botan {
@@ -20,24 +23,67 @@ namespace Botan {
class BOTAN_DLL DLIES_Encryptor : public PK_Encryptor
{
public:
- DLIES_Encryptor(const PK_Key_Agreement_Key&,
+ /**
+ * Stream mode: use KDF to provide a stream of bytes to xor with the message
+ *
+ * @param own_priv_key own (ephemeral) DH private key
+ * @param kdf the KDF that should be used
+ * @param mac the MAC function that should be used
+ * @param mac_key_len key length of the MAC function. Default = 20 bytes
+ *
+ * output = (ephemeral) public key + ciphertext + tag
+ */
+ DLIES_Encryptor(const DH_PrivateKey& own_priv_key,
KDF* kdf,
MessageAuthenticationCode* mac,
size_t mac_key_len = 20);
- void set_other_key(const std::vector<byte>&);
+ /**
+ * Block cipher mode
+ *
+ * @param own_priv_key own (ephemeral) DH private key
+ * @param kdf the KDF that should be used
+ * @param cipher the block cipher that should be used
+ * @param cipher_key_len the key length of the block cipher
+ * @param mac the MAC function that should be used
+ * @param mac_key_len key length of the MAC function. Default = 20 bytes
+ *
+ * output = (ephemeral) public key + ciphertext + tag
+ */
+ DLIES_Encryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ Cipher_Mode* cipher,
+ size_t cipher_key_len,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_len = 20);
+
+ // Set the other parties public key
+ inline void set_other_key(const std::vector<byte>& other_pub_key)
+ {
+ m_other_pub_key = other_pub_key;
+ }
+
+ /// Set the initialization vector for the data encryption method
+ inline void set_initialization_vector(const InitializationVector& iv)
+ {
+ m_iv = iv;
+ }
+
private:
std::vector<byte> enc(const byte[], size_t,
RandomNumberGenerator&) const override;
size_t maximum_input_size() const override;
- std::vector<byte> m_other_key, m_my_key;
-
+ std::vector<byte> m_other_pub_key;
+ std::vector<byte> m_own_pub_key;
PK_Key_Agreement m_ka;
std::unique_ptr<KDF> m_kdf;
+ std::unique_ptr<Cipher_Mode> m_cipher;
+ const size_t m_cipher_key_len;
std::unique_ptr<MessageAuthenticationCode> m_mac;
- size_t m_mac_keylen;
+ const size_t m_mac_keylen;
+ InitializationVector m_iv;
};
/**
@@ -46,21 +92,58 @@ class BOTAN_DLL DLIES_Encryptor : public PK_Encryptor
class BOTAN_DLL DLIES_Decryptor : public PK_Decryptor
{
public:
- DLIES_Decryptor(const PK_Key_Agreement_Key&,
+ /**
+ * Stream mode: use KDF to provide a stream of bytes to xor with the message
+ *
+ * @param own_priv_key own (ephemeral) DH private key
+ * @param kdf the KDF that should be used
+ * @param mac the MAC function that should be used
+ * @param mac_key_len key length of the MAC function. Default = 20 bytes
+ *
+ * input = (ephemeral) public key + ciphertext + tag
+ */
+ DLIES_Decryptor(const DH_PrivateKey& own_priv_key,
KDF* kdf,
MessageAuthenticationCode* mac,
size_t mac_key_len = 20);
+ /**
+ * Block cipher mode
+ *
+ * @param own_priv_key own (ephemeral) DH private key
+ * @param kdf the KDF that should be used
+ * @param cipher the block cipher that should be used
+ * @param cipher_key_len the key length of the block cipher
+ * @param mac the MAC function that should be used
+ * @param mac_key_len key length of the MAC function. Default = 20 bytes
+ *
+ * input = (ephemeral) public key + ciphertext + tag
+ */
+ DLIES_Decryptor(const DH_PrivateKey& own_priv_key,
+ KDF* kdf,
+ Cipher_Mode* cipher,
+ size_t cipher_key_len,
+ MessageAuthenticationCode* mac,
+ size_t mac_key_len = 20);
+
+ /// Set the initialization vector for the data decryption method
+ inline void set_initialization_vector(const InitializationVector& iv)
+ {
+ m_iv = iv;
+ }
+
private:
secure_vector<byte> do_decrypt(byte& valid_mask,
const byte in[], size_t in_len) const override;
- std::vector<byte> m_my_key;
-
+ const size_t m_pub_key_size;
PK_Key_Agreement m_ka;
std::unique_ptr<KDF> m_kdf;
+ std::unique_ptr<Cipher_Mode> m_cipher;
+ const size_t m_cipher_key_len;
std::unique_ptr<MessageAuthenticationCode> m_mac;
- size_t m_mac_keylen;
+ const size_t m_mac_keylen;
+ InitializationVector m_iv;
};
}
diff --git a/src/lib/pubkey/dlies/info.txt b/src/lib/pubkey/dlies/info.txt
index ec1bac803..30362ad78 100644
--- a/src/lib/pubkey/dlies/info.txt
+++ b/src/lib/pubkey/dlies/info.txt
@@ -1,6 +1,7 @@
-define DLIES 20131128
+define DLIES 20160713
<requires>
kdf
mac
+block
</requires>
diff --git a/src/lib/pubkey/dsa/dsa.cpp b/src/lib/pubkey/dsa/dsa.cpp
index 471189cd8..399756b1a 100644
--- a/src/lib/pubkey/dsa/dsa.cpp
+++ b/src/lib/pubkey/dsa/dsa.cpp
@@ -1,6 +1,7 @@
/*
* DSA
* (C) 1999-2010,2014 Jack Lloyd
+* (C) 2016 René Korthaus
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -10,7 +11,10 @@
#include <botan/keypair.h>
#include <botan/pow_mod.h>
#include <botan/reducer.h>
-#include <botan/rfc6979.h>
+#if defined(BOTAN_HAS_RFC6979_GENERATOR)
+ #include <botan/rfc6979.h>
+ #include <botan/emsa.h>
+#endif
#include <future>
namespace Botan {
@@ -66,7 +70,7 @@ bool DSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const
if(!strong)
return true;
- return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)");
}
namespace {
@@ -84,7 +88,7 @@ class DSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
m_x(dsa.get_x()),
m_powermod_g_p(dsa.group_g(), dsa.group_p()),
m_mod_q(dsa.group_q()),
- m_hash(hash_for_deterministic_signature(emsa))
+ m_emsa(emsa)
{
}
@@ -99,19 +103,24 @@ class DSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
const BigInt& m_x;
Fixed_Base_Power_Mod m_powermod_g_p;
Modular_Reducer m_mod_q;
- std::string m_hash;
+ std::string m_emsa;
};
secure_vector<byte>
DSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
- RandomNumberGenerator&)
+ RandomNumberGenerator& rng)
{
BigInt i(msg, msg_len);
while(i >= m_q)
i -= m_q;
- const BigInt k = generate_rfc6979_nonce(m_x, m_q, i, m_hash);
+#if defined(BOTAN_HAS_RFC6979_GENERATOR)
+ BOTAN_UNUSED(rng);
+ const BigInt k = generate_rfc6979_nonce(m_x, m_q, i, hash_for_emsa(m_emsa));
+#else
+ const BigInt k = BigInt::random_integer(rng, 1, m_q);
+#endif
auto future_r = std::async(std::launch::async,
[&]() { return m_mod_q.reduce(m_powermod_g_p(k)); });
@@ -124,10 +133,7 @@ DSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
BOTAN_ASSERT(s != 0, "invalid s");
BOTAN_ASSERT(r != 0, "invalid r");
- secure_vector<byte> output(2*m_q.bytes());
- r.binary_encode(&output[output.size() / 2 - r.bytes()]);
- s.binary_encode(&output[output.size() - s.bytes()]);
- return output;
+ return BigInt::encode_fixed_length_int_pair(r, s, m_q.bytes());
}
/**
diff --git a/src/lib/pubkey/dsa/info.txt b/src/lib/pubkey/dsa/info.txt
index 6e0259ce2..855363789 100644
--- a/src/lib/pubkey/dsa/info.txt
+++ b/src/lib/pubkey/dsa/info.txt
@@ -5,5 +5,6 @@ dl_algo
dl_group
keypair
numbertheory
-rfc6979
+emsa1
+sha2_32
</requires>
diff --git a/src/lib/pubkey/ec_group/named.cpp b/src/lib/pubkey/ec_group/named.cpp
index 3ee791053..6df8a3169 100644
--- a/src/lib/pubkey/ec_group/named.cpp
+++ b/src/lib/pubkey/ec_group/named.cpp
@@ -255,6 +255,16 @@ const char* EC_Group::PEM_for_named_group(const std::string& name)
"/////////////////////2xhEHCZWtEARYQbCbdhuJMCAQE="
"-----END EC PARAMETERS-----";
+ if(name == "frp256v1")
+ return
+ "-----BEGIN EC PARAMETERS-----"
+ "MIHgAgEBMCwGByqGSM49AQECIQDx/ReMCzrVjxASbejOQkNbOWGtvKvIym3o/PNT"
+ "2G6cAzBEBCDx/ReMCzrVjxASbejOQkNbOWGtvKvIym3o/PNT2G6cAAQg7jU/ylQo"
+ "qTANSrp1SkTAD9/sDJrksaGAMHXtlnt7tz8EQQS2s9TDVsE56zEYPUdJ1COVjCfS"
+ "3K+YtwFkyXot2Y9c/2FC4PfIsgSRH5Jx8PPs74wnAcMH6OTJ4YMRWhVUBiz7AiEA"
+ "8f0XjAs61Y8QEm3ozkJDW1PcZ+FA0r+UH/3UWcbWVeECAQE="
+ "-----END EC PARAMETERS-----";
+
return nullptr;
}
diff --git a/src/lib/pubkey/ecdsa/ecdsa.cpp b/src/lib/pubkey/ecdsa/ecdsa.cpp
index 4a4b0c037..264a36963 100644
--- a/src/lib/pubkey/ecdsa/ecdsa.cpp
+++ b/src/lib/pubkey/ecdsa/ecdsa.cpp
@@ -3,6 +3,7 @@
* (C) 2007 Manuel Hartl, FlexSecure GmbH
* 2007 Falko Strenzke, FlexSecure GmbH
* 2008-2010,2015 Jack Lloyd
+* 2016 René Korthaus
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -10,7 +11,10 @@
#include <botan/internal/pk_utils.h>
#include <botan/ecdsa.h>
#include <botan/keypair.h>
-#include <botan/rfc6979.h>
+#if defined(BOTAN_HAS_RFC6979_GENERATOR)
+ #include <botan/rfc6979.h>
+ #include <botan/emsa.h>
+#endif
namespace Botan {
@@ -23,7 +27,7 @@ bool ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
if(!strong)
return true;
- return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)");
}
namespace {
@@ -43,7 +47,7 @@ class ECDSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
m_base_point(ecdsa.domain().get_base_point(), m_order),
m_x(ecdsa.private_value()),
m_mod_order(m_order),
- m_hash(hash_for_deterministic_signature(emsa))
+ m_emsa(emsa)
{
}
@@ -59,7 +63,7 @@ class ECDSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
Blinded_Point_Multiply m_base_point;
const BigInt& m_x;
Modular_Reducer m_mod_order;
- std::string m_hash;
+ std::string m_emsa;
};
secure_vector<byte>
@@ -68,7 +72,11 @@ ECDSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
{
const BigInt m(msg, msg_len);
- const BigInt k = generate_rfc6979_nonce(m_x, m_order, m, m_hash);
+#if defined(BOTAN_HAS_RFC6979_GENERATOR)
+ const BigInt k = generate_rfc6979_nonce(m_x, m_order, m, hash_for_emsa(m_emsa));
+#else
+ const BigInt k = BigInt::random_integer(rng, 1, m_order);
+#endif
const PointGFp k_times_P = m_base_point.blinded_multiply(k, rng);
const BigInt r = m_mod_order.reduce(k_times_P.get_affine_x());
@@ -78,10 +86,7 @@ ECDSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
BOTAN_ASSERT(s != 0, "invalid s");
BOTAN_ASSERT(r != 0, "invalid r");
- secure_vector<byte> output(2*m_order.bytes());
- r.binary_encode(&output[output.size() / 2 - r.bytes()]);
- s.binary_encode(&output[output.size() - s.bytes()]);
- return output;
+ return BigInt::encode_fixed_length_int_pair(r, s, m_order.bytes());
}
/**
diff --git a/src/lib/pubkey/ecdsa/info.txt b/src/lib/pubkey/ecdsa/info.txt
index e7941d53d..3b12bff0d 100644
--- a/src/lib/pubkey/ecdsa/info.txt
+++ b/src/lib/pubkey/ecdsa/info.txt
@@ -7,5 +7,6 @@ ecc_key
keypair
numbertheory
rng
-rfc6979
+emsa1
+sha2_32
</requires>
diff --git a/src/lib/pubkey/ecgdsa/ecgdsa.cpp b/src/lib/pubkey/ecgdsa/ecgdsa.cpp
index b28e3fe96..30ea32817 100644
--- a/src/lib/pubkey/ecgdsa/ecgdsa.cpp
+++ b/src/lib/pubkey/ecgdsa/ecgdsa.cpp
@@ -20,7 +20,7 @@ bool ECGDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
if(!strong)
return true;
- return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)");
}
namespace {
@@ -73,10 +73,7 @@ ECGDSA_Signature_Operation::raw_sign(const byte msg[], size_t msg_len,
BOTAN_ASSERT(s != 0, "invalid s");
BOTAN_ASSERT(r != 0, "invalid r");
- secure_vector<byte> output(2*m_order.bytes());
- r.binary_encode(&output[output.size() / 2 - r.bytes()]);
- s.binary_encode(&output[output.size() - s.bytes()]);
- return output;
+ return BigInt::encode_fixed_length_int_pair(r, s, m_order.bytes());
}
/**
diff --git a/src/lib/pubkey/ecgdsa/info.txt b/src/lib/pubkey/ecgdsa/info.txt
index 6c18a1440..79dec3199 100644
--- a/src/lib/pubkey/ecgdsa/info.txt
+++ b/src/lib/pubkey/ecgdsa/info.txt
@@ -8,4 +8,6 @@ ecc_key
keypair
numbertheory
rng
+emsa1
+sha2_32
</requires>
diff --git a/src/lib/pubkey/ecies/ecies.cpp b/src/lib/pubkey/ecies/ecies.cpp
new file mode 100644
index 000000000..d44d14803
--- /dev/null
+++ b/src/lib/pubkey/ecies/ecies.cpp
@@ -0,0 +1,398 @@
+/*
+* ECIES
+* (C) 2016 Philipp Weber
+* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/ecies.h>
+#include <botan/cipher_mode.h>
+
+#include <botan/internal/ct_utils.h>
+#include <botan/internal/pk_utils.h>
+
+namespace Botan {
+
+namespace {
+
+/**
+* Private key type for ECIES_ECDH_KA_Operation
+*/
+class ECIES_PrivateKey : public EC_PrivateKey, public PK_Key_Agreement_Key
+ {
+ public:
+ explicit ECIES_PrivateKey(const ECDH_PrivateKey& private_key) :
+ EC_PublicKey(private_key),
+ EC_PrivateKey(private_key),
+ PK_Key_Agreement_Key(),
+ m_key(private_key)
+ {
+ }
+
+ std::vector<byte> public_value() const override
+ {
+ return m_key.public_value();
+ }
+
+ std::string algo_name() const override
+ {
+ return "ECIES";
+ }
+
+ size_t max_input_bits() const override
+ {
+ return m_key.max_input_bits();
+ }
+
+ private:
+ ECDH_PrivateKey m_key;
+ };
+
+/**
+* Implements ECDH key agreement without using the cofactor mode
+*/
+class ECIES_ECDH_KA_Operation : public PK_Ops::Key_Agreement_with_KDF
+ {
+ public:
+ typedef ECIES_PrivateKey Key_Type;
+
+ ECIES_ECDH_KA_Operation(const ECIES_PrivateKey& private_key, const std::string&) :
+ PK_Ops::Key_Agreement_with_KDF("Raw"),
+ m_key(private_key)
+ {
+ }
+
+ secure_vector<byte> raw_agree(const byte w[], size_t w_len) override
+ {
+ const CurveGFp& curve = m_key.domain().get_curve();
+ PointGFp point = OS2ECP(w, w_len, curve);
+ PointGFp S = point * m_key.private_value();
+ BOTAN_ASSERT(S.on_the_curve(), "ECDH agreed value was on the curve");
+ return BigInt::encode_1363(S.get_affine_x(), curve.get_p().bytes());
+ }
+
+ private:
+ ECIES_PrivateKey m_key;
+ };
+
+/**
+* Creates a PK_Key_Agreement instance for the given key and ecies_params
+* Returns either ECIES_ECDH_KA_Operation or the default implementation for the given key,
+* depending on the key and ecies_params
+* @param private_key the private key used for the key agreement
+* @param ecies_params settings for ecies
+* @param for_encryption disable cofactor mode if the secret will be used for encryption
+* (according to ISO 18033 cofactor mode is only used during decryption)
+*/
+PK_Key_Agreement create_key_agreement(const PK_Key_Agreement_Key& private_key, const ECIES_KA_Params& ecies_params,
+ bool for_encryption)
+ {
+ const ECDH_PrivateKey* ecdh_key = dynamic_cast<const ECDH_PrivateKey*>(&private_key);
+
+ if(ecdh_key == nullptr && (ecies_params.cofactor_mode() || ecies_params.old_cofactor_mode()
+ || ecies_params.check_mode()))
+ {
+ // assume we have a private key from an external provider (e.g. pkcs#11):
+ // there is no way to determine or control whether the provider uses cofactor mode or not.
+ // ISO 18033 does not allow cofactor mode in combination with old cofactor mode or check mode
+ // => disable cofactor mode, old cofactor mode and check mode for unknown keys/providers (as a precaution).
+ throw Invalid_Argument("ECIES: cofactor, old cofactor and check mode are only supported for ECDH_PrivateKey");
+ }
+
+ if(ecdh_key && (for_encryption || !ecies_params.cofactor_mode()))
+ {
+ // ECDH_KA_Operation uses cofactor mode: use own key agreement method if cofactor should not be used.
+ return PK_Key_Agreement(ECIES_PrivateKey(*ecdh_key), "Raw");
+ }
+
+ return PK_Key_Agreement(private_key, "Raw"); // use default implementation
+ }
+}
+
+BOTAN_REGISTER_PK_KEY_AGREE_OP("ECIES", ECIES_ECDH_KA_Operation);
+
+ECIES_KA_Operation::ECIES_KA_Operation(const PK_Key_Agreement_Key& private_key, const ECIES_KA_Params& ecies_params,
+ bool for_encryption) :
+ m_ka(create_key_agreement(private_key, ecies_params, for_encryption)),
+ m_params(ecies_params)
+ {
+ }
+
+/**
+* ECIES secret derivation according to ISO 18033-2
+*/
+SymmetricKey ECIES_KA_Operation::derive_secret(const std::vector<byte>& eph_public_key_bin,
+ const PointGFp& other_public_key_point) const
+ {
+ if(other_public_key_point.is_zero())
+ {
+ throw Invalid_Argument("ECIES: other public key point is zero");
+ }
+
+ std::unique_ptr<KDF> kdf = m_params.create_kdf();
+ BOTAN_ASSERT(kdf != nullptr, "KDF is found");
+
+ PointGFp other_point = other_public_key_point;
+
+ // ISO 18033: step b
+ if(m_params.old_cofactor_mode())
+ {
+ other_point *= m_params.domain().get_cofactor();
+ }
+
+ secure_vector<byte> derivation_input;
+
+ // ISO 18033: encryption step e / decryption step g
+ if(!m_params.single_hash_mode())
+ {
+ derivation_input += eph_public_key_bin;
+ }
+
+ // ISO 18033: encryption step f / decryption step h
+ secure_vector<byte> other_public_key_bin = EC2OSP(other_point, static_cast<byte>(m_params.compression_type()));
+ // Note: the argument `m_params.secret_length()` passed for `key_len` will only be used by providers because
+ // "Raw" is passed to the `PK_Key_Agreement` if the implementation of botan is used.
+ const SymmetricKey peh = m_ka.derive_key(m_params.domain().get_order().bytes(), other_public_key_bin.data(), other_public_key_bin.size());
+ derivation_input.insert(derivation_input.end(), peh.begin(), peh.end());
+
+ // ISO 18033: encryption step g / decryption step i
+ return kdf->derive_key(m_params.secret_length(), derivation_input);
+ }
+
+
+ECIES_KA_Params::ECIES_KA_Params(const EC_Group& domain, const std::string& kdf_spec, size_t length,
+ PointGFp::Compression_Type compression_type, ECIES_Flags flags) :
+ m_domain(domain),
+ m_kdf_spec(kdf_spec),
+ m_length(length),
+ m_compression_mode(compression_type),
+ m_flags(flags)
+ {
+ }
+
+std::unique_ptr<KDF> ECIES_KA_Params::create_kdf() const
+ {
+ std::unique_ptr<KDF> kdf = Botan::KDF::create(m_kdf_spec);
+ if(kdf == nullptr)
+ {
+ throw Algorithm_Not_Found(m_kdf_spec);
+ }
+ return kdf;
+ }
+
+
+ECIES_System_Params::ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec,
+ const std::string& dem_algo_spec, size_t dem_key_len,
+ const std::string& mac_spec, size_t mac_key_len,
+ PointGFp::Compression_Type compression_type, ECIES_Flags flags) :
+ ECIES_KA_Params(domain, kdf_spec, dem_key_len + mac_key_len, compression_type, flags),
+ m_dem_spec(dem_algo_spec),
+ m_dem_keylen(dem_key_len),
+ m_mac_spec(mac_spec),
+ m_mac_keylen(mac_key_len)
+ {
+ // ISO 18033: "At most one of CofactorMode, OldCofactorMode, and CheckMode may be 1."
+ if(cofactor_mode() + old_cofactor_mode() + check_mode() > 1)
+ {
+ throw Invalid_Argument("ECIES: only one of cofactor_mode, old_cofactor_mode and check_mode can be set");
+ }
+ }
+
+ECIES_System_Params::ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec,
+ const std::string& dem_algo_spec, size_t dem_key_len,
+ const std::string& mac_spec, size_t mac_key_len) :
+ ECIES_System_Params(domain, kdf_spec, dem_algo_spec, dem_key_len, mac_spec, mac_key_len, PointGFp::UNCOMPRESSED,
+ ECIES_Flags::NONE)
+ {
+ }
+
+std::unique_ptr<MessageAuthenticationCode> ECIES_System_Params::create_mac() const
+ {
+ std::unique_ptr<MessageAuthenticationCode> mac = Botan::MessageAuthenticationCode::create(m_mac_spec);
+ if(mac == nullptr)
+ {
+ throw Algorithm_Not_Found(m_mac_spec);
+ }
+ return mac;
+ }
+
+std::unique_ptr<Cipher_Mode> ECIES_System_Params::create_cipher(Botan::Cipher_Dir direction) const
+ {
+ Cipher_Mode* cipher = get_cipher_mode(m_dem_spec, direction);
+ if(cipher == nullptr)
+ {
+ throw Algorithm_Not_Found(m_dem_spec);
+ }
+ return std::unique_ptr<Cipher_Mode>(cipher);
+ }
+
+
+/*
+* ECIES_Encryptor Constructor
+*/
+ECIES_Encryptor::ECIES_Encryptor(const PK_Key_Agreement_Key& private_key, const ECIES_System_Params& ecies_params) :
+ m_ka(private_key, ecies_params, true),
+ m_params(ecies_params),
+ m_eph_public_key_bin(private_key.public_value()), // returns the uncompressed public key, see conversion below
+ m_iv(),
+ m_other_point(),
+ m_label()
+ {
+ if(ecies_params.compression_type() != PointGFp::UNCOMPRESSED)
+ {
+ // ISO 18033: step d
+ // convert only if necessary; m_eph_public_key_bin has been initialized with the uncompressed format
+ m_eph_public_key_bin = unlock(EC2OSP(OS2ECP(m_eph_public_key_bin, m_params.domain().get_curve()),
+ static_cast<byte>(ecies_params.compression_type())));
+ }
+ }
+
+/*
+* ECIES_Encryptor Constructor
+*/
+ECIES_Encryptor::ECIES_Encryptor(RandomNumberGenerator& rng, const ECIES_System_Params& ecies_params) :
+ ECIES_Encryptor(ECDH_PrivateKey(rng, ecies_params.domain()), ecies_params)
+ {
+ }
+
+
+/*
+* ECIES Encryption according to ISO 18033-2
+*/
+std::vector<byte> ECIES_Encryptor::enc(const byte data[], size_t length, RandomNumberGenerator&) const
+ {
+ if(m_other_point.is_zero())
+ {
+ throw Invalid_State("ECIES: the other key is zero");
+ }
+
+ const SymmetricKey secret_key = m_ka.derive_secret(m_eph_public_key_bin, m_other_point);
+
+ // encryption
+ std::unique_ptr<Cipher_Mode> cipher = m_params.create_cipher(ENCRYPTION);
+ BOTAN_ASSERT(cipher != nullptr, "Cipher is found");
+
+ cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen()));
+ if(m_iv.size() != 0)
+ {
+ cipher->start(m_iv.bits_of());
+ }
+ secure_vector<byte> encrypted_data(data, data + length);
+ cipher->finish(encrypted_data);
+
+ // concat elements
+ std::unique_ptr<MessageAuthenticationCode> mac = m_params.create_mac();
+ BOTAN_ASSERT(mac != nullptr, "MAC is found");
+
+ secure_vector<byte> out(m_eph_public_key_bin.size() + encrypted_data.size() + mac->output_length());
+ buffer_insert(out, 0, m_eph_public_key_bin);
+ buffer_insert(out, m_eph_public_key_bin.size(), encrypted_data);
+
+ // mac
+ mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen());
+ mac->update(encrypted_data);
+ if(!m_label.empty())
+ {
+ mac->update(m_label);
+ }
+ mac->final(out.data() + m_eph_public_key_bin.size() + encrypted_data.size());
+
+ return unlock(out);
+ }
+
+
+ECIES_Decryptor::ECIES_Decryptor(const PK_Key_Agreement_Key& key, const ECIES_System_Params& ecies_params) :
+ m_ka(key, ecies_params, false),
+ m_params(ecies_params),
+ m_iv(),
+ m_label()
+ {
+ // ISO 18033: "If v > 1 and CheckMode = 0, then we must have gcd(u, v) = 1." (v = index, u= order)
+ if(!ecies_params.check_mode())
+ {
+ Botan::BigInt cofactor = m_params.domain().get_cofactor();
+ if(cofactor > 1 && Botan::gcd(cofactor, m_params.domain().get_order()) != 1)
+ {
+ throw Invalid_Argument("ECIES: gcd of cofactor and order must be 1 if check_mode is 0");
+ }
+ }
+ }
+
+/**
+* ECIES Decryption according to ISO 18033-2
+*/
+secure_vector<byte> ECIES_Decryptor::do_decrypt(byte& valid_mask, const byte in[], size_t in_len) const
+ {
+ size_t point_size = m_params.domain().get_curve().get_p().bytes();
+ if(m_params.compression_type() != PointGFp::COMPRESSED)
+ {
+ point_size *= 2; // uncompressed and hybrid contains x AND y
+ }
+ point_size += 1; // format byte
+
+ std::unique_ptr<MessageAuthenticationCode> mac = m_params.create_mac();
+ BOTAN_ASSERT(mac != nullptr, "MAC is found");
+
+ if(in_len < point_size + mac->output_length())
+ {
+ throw Decoding_Error("ECIES decryption: ciphertext is too short");
+ }
+
+ // extract data
+ const std::vector<byte> other_public_key_bin(in, in + point_size); // the received (ephemeral) public key
+ const std::vector<byte> encrypted_data(in + point_size, in + in_len - mac->output_length());
+ const std::vector<byte> mac_data(in + in_len - mac->output_length(), in + in_len);
+
+ // ISO 18033: step a
+ PointGFp other_public_key = OS2ECP(other_public_key_bin, m_params.domain().get_curve());
+
+ // ISO 18033: step b
+ if(m_params.check_mode() && !other_public_key.on_the_curve())
+ {
+ throw Decoding_Error("ECIES decryption: received public key is not on the curve");
+ }
+
+ // ISO 18033: step e (and step f because get_affine_x (called by ECDH_KA_Operation::raw_agree)
+ // throws Illegal_Transformation if the point is zero)
+ const SymmetricKey secret_key = m_ka.derive_secret(other_public_key_bin, other_public_key);
+
+ // validate mac
+ mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen());
+ mac->update(encrypted_data);
+ if(!m_label.empty())
+ {
+ mac->update(m_label);
+ }
+ const secure_vector<byte> calculated_mac = mac->final();
+ valid_mask = CT::expand_mask<byte>(same_mem(mac_data.data(), calculated_mac.data(), mac_data.size()));
+
+ if(valid_mask)
+ {
+ // decrypt data
+ std::unique_ptr<Cipher_Mode> cipher = m_params.create_cipher(DECRYPTION);
+ BOTAN_ASSERT(cipher != nullptr, "Cipher is found");
+
+ cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen()));
+ if(m_iv.size() != 0)
+ {
+ cipher->start(m_iv.bits_of());
+ }
+
+ try
+ {
+ // the decryption can fail:
+ // e.g. Integrity_Failure is thrown if GCM is used and the message does not have a valid tag
+ secure_vector<byte> decrypted_data(encrypted_data.begin(), encrypted_data.end());
+ cipher->finish(decrypted_data);
+ return decrypted_data;
+ }
+ catch(...)
+ {
+ valid_mask = 0;
+ }
+ }
+ return secure_vector<byte>();
+ }
+
+}
diff --git a/src/lib/pubkey/ecies/ecies.h b/src/lib/pubkey/ecies/ecies.h
new file mode 100644
index 000000000..0bc0bf76e
--- /dev/null
+++ b/src/lib/pubkey/ecies/ecies.h
@@ -0,0 +1,293 @@
+/*
+* ECIES
+* (C) 2016 Philipp Weber
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ECIES_H__
+#define BOTAN_ECIES_H__
+
+#include <botan/ecdh.h>
+#include <botan/ec_group.h>
+#include <botan/kdf.h>
+#include <botan/cipher_mode.h>
+#include <botan/mac.h>
+#include <botan/point_gfp.h>
+#include <botan/pubkey.h>
+#include <botan/secmem.h>
+#include <botan/symkey.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace Botan {
+
+class RandomNumberGenerator;
+
+enum class ECIES_Flags : uint32_t
+ {
+ NONE = 0,
+
+ /// if set: prefix the input of the (ecdh) key agreement with the encoded (ephemeral) public key
+ SINGLE_HASH_MODE = 1,
+
+ /// (decryption only) if set: use cofactor multiplication during (ecdh) key agreement
+ COFACTOR_MODE = 2,
+
+ /// if set: use ecdhc instead of ecdh
+ OLD_COFACTOR_MODE = 4,
+
+ /// (decryption only) if set: test if the (ephemeral) public key is on the curve
+ CHECK_MODE = 8
+ };
+
+inline ECIES_Flags operator |(ECIES_Flags a, ECIES_Flags b)
+ {
+ return static_cast<ECIES_Flags>(static_cast<uint32_t>(a) | static_cast<uint32_t>(b));
+ }
+
+inline ECIES_Flags operator &(ECIES_Flags a, ECIES_Flags b)
+ {
+ return static_cast<ECIES_Flags>(static_cast<uint32_t>(a) & static_cast<uint32_t>(b));
+ }
+
+/**
+* Parameters for ecies secret derivation
+*/
+class BOTAN_DLL ECIES_KA_Params
+ {
+ public:
+ /**
+ * @param domain ec domain parameters of the involved ec keys
+ * @param kdf_spec name of the key derivation function
+ * @param length length of the secret to be derived
+ * @param compression_type format of encoded keys (affects the secret derivation if single_hash_mode is used)
+ * @param flags options, see documentation of ECIES_Flags
+ */
+ ECIES_KA_Params(const EC_Group& domain, const std::string& kdf_spec, size_t length,
+ PointGFp::Compression_Type compression_type, ECIES_Flags flags);
+
+ virtual ~ECIES_KA_Params() = default;
+
+ std::unique_ptr<KDF> create_kdf() const;
+
+ inline const EC_Group& domain() const
+ {
+ return m_domain;
+ }
+
+ inline size_t secret_length() const
+ {
+ return m_length;
+ }
+
+ inline bool single_hash_mode() const
+ {
+ return (m_flags & ECIES_Flags::SINGLE_HASH_MODE) == ECIES_Flags::SINGLE_HASH_MODE;
+ }
+
+ inline bool cofactor_mode() const
+ {
+ return (m_flags & ECIES_Flags::COFACTOR_MODE) == ECIES_Flags::COFACTOR_MODE;
+ }
+
+ inline bool old_cofactor_mode() const
+ {
+ return (m_flags & ECIES_Flags::OLD_COFACTOR_MODE) == ECIES_Flags::OLD_COFACTOR_MODE;
+ }
+
+ inline bool check_mode() const
+ {
+ return (m_flags & ECIES_Flags::CHECK_MODE) == ECIES_Flags::CHECK_MODE;
+ }
+
+ inline PointGFp::Compression_Type compression_type() const
+ {
+ return m_compression_mode;
+ }
+
+ private:
+ const EC_Group m_domain;
+ const std::string m_kdf_spec;
+ const size_t m_length;
+ const PointGFp::Compression_Type m_compression_mode;
+ const ECIES_Flags m_flags;
+ };
+
+
+class BOTAN_DLL ECIES_System_Params : public ECIES_KA_Params
+ {
+ public:
+ /**
+ * @param domain ec domain parameters of the involved ec keys
+ * @param kdf_spec name of the key derivation function
+ * @param dem_algo_spec name of the data encryption method
+ * @param dem_key_len length of the key used for the data encryption method
+ * @param mac_spec name of the message authentication code
+ * @param mac_key_len length of the key used for the message authentication code
+ */
+ ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec, const std::string& dem_algo_spec,
+ size_t dem_key_len, const std::string& mac_spec, size_t mac_key_len);
+
+ /**
+ * @param domain ec domain parameters of the involved ec keys
+ * @param kdf_spec name of the key derivation function
+ * @param dem_algo_spec name of the data encryption method
+ * @param dem_key_len length of the key used for the data encryption method
+ * @param mac_spec name of the message authentication code
+ * @param mac_key_len length of the key used for the message authentication code
+ * @param compression_type format of encoded keys (affects the secret derivation if single_hash_mode is used)
+ * @param flags options, see documentation of ECIES_Flags
+ */
+ ECIES_System_Params(const EC_Group& domain, const std::string& kdf_spec, const std::string& dem_algo_spec,
+ size_t dem_key_len, const std::string& mac_spec, size_t mac_key_len,
+ PointGFp::Compression_Type compression_type, ECIES_Flags flags);
+
+ virtual ~ECIES_System_Params() = default;
+
+ /// creates an instance of the message authentication code
+ std::unique_ptr<MessageAuthenticationCode> create_mac() const;
+
+ /// creates an instance of the data encryption method
+ std::unique_ptr<Cipher_Mode> create_cipher(Botan::Cipher_Dir direction) const;
+
+ /// returns the length of the key used by the data encryption method
+ inline size_t dem_keylen() const
+ {
+ return m_dem_keylen;
+ }
+
+ /// returns the length of the key used by the message authentication code
+ inline size_t mac_keylen() const
+ {
+ return m_mac_keylen;
+ }
+
+ private:
+ const std::string m_dem_spec;
+ const size_t m_dem_keylen;
+ const std::string m_mac_spec;
+ const size_t m_mac_keylen;
+ };
+
+
+/**
+* ECIES secret derivation according to ISO 18033-2
+*/
+class BOTAN_DLL ECIES_KA_Operation
+ {
+ public:
+ /**
+ * @param private_key the (ephemeral) private key which is used to derive the secret
+ * @param ecies_params settings for ecies
+ * @param for_encryption disable cofactor mode if the secret will be used for encryption
+ * (according to ISO 18033 cofactor mode is only used during decryption)
+ */
+ ECIES_KA_Operation(const PK_Key_Agreement_Key& private_key, const ECIES_KA_Params& ecies_params,
+ bool for_encryption);
+
+ /**
+ * Performs a key agreement with the provided keys and derives the secret from the result
+ * @param eph_public_key_bin the encoded (ephemeral) public key which belongs to the used (ephemeral) private key
+ * @param other_public_key_point public key point of the other party
+ */
+ SymmetricKey derive_secret(const std::vector<byte>& eph_public_key_bin,
+ const PointGFp& other_public_key_point) const;
+
+ private:
+ const PK_Key_Agreement m_ka;
+ const ECIES_KA_Params m_params;
+ };
+
+
+/**
+* ECIES Encryption according to ISO 18033-2
+*/
+class BOTAN_DLL ECIES_Encryptor : public PK_Encryptor
+ {
+ public:
+ /**
+ * @param private_key the (ephemeral) private key which is used for the key agreement
+ * @param ecies_params settings for ecies
+ */
+ ECIES_Encryptor(const PK_Key_Agreement_Key& private_key, const ECIES_System_Params& ecies_params);
+
+ /**
+ * Creates an ephemeral private key which is used for the key agreement
+ * @param rng random generator used during private key generation
+ * @param ecies_params settings for ecies
+ */
+ ECIES_Encryptor(RandomNumberGenerator& rng, const ECIES_System_Params& ecies_params);
+
+ /// Set the public key of the other party
+ inline void set_other_key(const Botan::PointGFp& public_point)
+ {
+ m_other_point = public_point;
+ }
+
+ /// Set the initialization vector for the data encryption method
+ inline void set_initialization_vector(const InitializationVector& iv)
+ {
+ m_iv = iv;
+ }
+
+ /// Set the label which is appended to the input for the message authentication code
+ inline void set_label(const std::string& label)
+ {
+ m_label = std::vector<byte>(label.begin(), label.end());
+ }
+
+ private:
+ std::vector<byte> enc(const byte data[], size_t length, RandomNumberGenerator&) const override;
+
+ inline size_t maximum_input_size() const override
+ {
+ return std::numeric_limits<size_t>::max();
+ }
+
+ const ECIES_KA_Operation m_ka;
+ const ECIES_System_Params m_params;
+ std::vector<byte> m_eph_public_key_bin;
+ InitializationVector m_iv;
+ PointGFp m_other_point;
+ std::vector<byte> m_label;
+ };
+
+
+/**
+* ECIES Decryption according to ISO 18033-2
+*/
+class BOTAN_DLL ECIES_Decryptor : public PK_Decryptor
+ {
+ public:
+ /**
+ * @param private_key the private key which is used for the key agreement
+ * @param ecies_params settings for ecies
+ */
+ ECIES_Decryptor(const PK_Key_Agreement_Key& private_key, const ECIES_System_Params& ecies_params);
+
+ /// Set the initialization vector for the data encryption method
+ inline void set_initialization_vector(const InitializationVector& iv)
+ {
+ m_iv = iv;
+ }
+
+ /// Set the label which is appended to the input for the message authentication code
+ inline void set_label(const std::string& label)
+ {
+ m_label = std::vector<byte>(label.begin(), label.end());
+ }
+
+ private:
+ secure_vector<byte> do_decrypt(byte& valid_mask, const byte in[], size_t in_len) const override;
+
+ const ECIES_KA_Operation m_ka;
+ const ECIES_System_Params m_params;
+ InitializationVector m_iv;
+ std::vector<byte> m_label;
+ };
+
+}
+
+#endif
diff --git a/src/lib/pubkey/ecies/info.txt b/src/lib/pubkey/ecies/info.txt
new file mode 100644
index 000000000..12776f8c2
--- /dev/null
+++ b/src/lib/pubkey/ecies/info.txt
@@ -0,0 +1,8 @@
+define ECIES 20160128
+
+<requires>
+kdf
+mac
+ecdh
+modes
+</requires> \ No newline at end of file
diff --git a/src/lib/pubkey/eckcdsa/eckcdsa.cpp b/src/lib/pubkey/eckcdsa/eckcdsa.cpp
new file mode 100644
index 000000000..5ca89675c
--- /dev/null
+++ b/src/lib/pubkey/eckcdsa/eckcdsa.cpp
@@ -0,0 +1,200 @@
+/*
+* ECKCDSA (ISO/IEC 14888-3:2006/Cor.2:2009)
+* (C) 2016 René Korthaus, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/internal/pk_utils.h>
+#include <botan/eckcdsa.h>
+#include <botan/keypair.h>
+#include <botan/emsa.h>
+#include <botan/hash.h>
+
+namespace Botan {
+
+bool ECKCDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
+ bool strong) const
+ {
+ if(!public_point().on_the_curve())
+ {
+ return false;
+ }
+
+ if(!strong)
+ {
+ return true;
+ }
+
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-1)");
+ }
+
+namespace {
+
+/**
+* ECKCDSA signature operation
+*/
+class ECKCDSA_Signature_Operation : public PK_Ops::Signature_with_EMSA
+ {
+ public:
+ typedef ECKCDSA_PrivateKey Key_Type;
+
+ ECKCDSA_Signature_Operation(const ECKCDSA_PrivateKey& eckcdsa,
+ const std::string& emsa) :
+ PK_Ops::Signature_with_EMSA(emsa),
+ m_order(eckcdsa.domain().get_order()),
+ m_base_point(eckcdsa.domain().get_base_point(), m_order),
+ m_x(eckcdsa.private_value()),
+ m_mod_order(m_order),
+ m_prefix()
+ {
+ const BigInt public_point_x = eckcdsa.public_point().get_affine_x();
+ const BigInt public_point_y = eckcdsa.public_point().get_affine_y();
+
+ m_prefix.resize(public_point_x.bytes() + public_point_y.bytes());
+ public_point_x.binary_encode(m_prefix.data());
+ public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]);
+ m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits
+ }
+
+ secure_vector<byte> raw_sign(const byte msg[], size_t msg_len,
+ RandomNumberGenerator& rng) override;
+
+ size_t message_parts() const override { return 2; }
+ size_t message_part_size() const override { return m_order.bytes(); }
+ size_t max_input_bits() const override { return m_order.bits(); }
+
+ bool has_prefix() override { return true; }
+ secure_vector<byte> message_prefix() const override { return m_prefix; }
+
+ private:
+ const BigInt& m_order;
+ Blinded_Point_Multiply m_base_point;
+ const BigInt& m_x;
+ Modular_Reducer m_mod_order;
+ secure_vector<byte> m_prefix;
+ };
+
+secure_vector<byte>
+ECKCDSA_Signature_Operation::raw_sign(const byte msg[], size_t,
+ RandomNumberGenerator& rng)
+ {
+ const BigInt k = BigInt::random_integer(rng, 1, m_order);
+ const PointGFp k_times_P = m_base_point.blinded_multiply(k, rng);
+ const BigInt k_times_P_x = k_times_P.get_affine_x();
+
+ secure_vector<byte> to_be_hashed(k_times_P_x.bytes());
+ k_times_P_x.binary_encode(to_be_hashed.data());
+
+ std::unique_ptr<EMSA> emsa(m_emsa->clone());
+ emsa->update(to_be_hashed.data(), to_be_hashed.size());
+ secure_vector<byte> c = emsa->raw_data();
+ c = emsa->encoding_of(c, max_input_bits(), rng);
+
+ const BigInt r(c.data(), c.size());
+
+ xor_buf(c, msg, c.size());
+ BigInt w(c.data(), c.size());
+ w = m_mod_order.reduce(w);
+
+ const BigInt s = m_mod_order.multiply(m_x, k - w);
+ BOTAN_ASSERT(s != 0, "invalid s");
+
+ secure_vector<byte> output = BigInt::encode_1363(r, c.size());
+ output += BigInt::encode_1363(s, m_mod_order.get_modulus().bytes());
+ return output;
+ }
+
+/**
+* ECKCDSA verification operation
+*/
+class ECKCDSA_Verification_Operation : public PK_Ops::Verification_with_EMSA
+ {
+ public:
+ typedef ECKCDSA_PublicKey Key_Type;
+
+ ECKCDSA_Verification_Operation(const ECKCDSA_PublicKey& eckcdsa,
+ const std::string& emsa) :
+ PK_Ops::Verification_with_EMSA(emsa),
+ m_base_point(eckcdsa.domain().get_base_point()),
+ m_public_point(eckcdsa.public_point()),
+ m_order(eckcdsa.domain().get_order()),
+ m_mod_order(m_order),
+ m_prefix()
+ {
+ const BigInt public_point_x = m_public_point.get_affine_x();
+ const BigInt public_point_y = m_public_point.get_affine_y();
+
+ m_prefix.resize(public_point_x.bytes() + public_point_y.bytes());
+ public_point_x.binary_encode(&m_prefix[0]);
+ public_point_y.binary_encode(&m_prefix[public_point_x.bytes()]);
+ m_prefix.resize(HashFunction::create(hash_for_signature())->hash_block_size()); // use only the "hash input block size" leftmost bits
+ }
+
+ bool has_prefix() override { return true; }
+ secure_vector<byte> message_prefix() const override { return m_prefix; }
+
+ size_t message_parts() const override { return 2; }
+ size_t message_part_size() const override { return m_order.bytes(); }
+ size_t max_input_bits() const override { return m_order.bits(); }
+
+ bool with_recovery() const override { return false; }
+
+ bool verify(const byte msg[], size_t msg_len,
+ const byte sig[], size_t sig_len) override;
+ private:
+ const PointGFp& m_base_point;
+ const PointGFp& m_public_point;
+ const BigInt& m_order;
+ // FIXME: should be offered by curve
+ Modular_Reducer m_mod_order;
+ secure_vector<byte> m_prefix;
+ };
+
+bool ECKCDSA_Verification_Operation::verify(const byte msg[], size_t,
+ const byte sig[], size_t sig_len)
+ {
+ // check that bit length of r is equal to output bit length of employed hash function h
+ const std::unique_ptr<HashFunction> hash = HashFunction::create(hash_for_signature());
+
+ // no way to know size of r in sig, so check that we have at least hash->output_length()+1
+ // bytes in sig, enough for r and an arbitrary size s
+ if(sig_len <= hash->output_length())
+ {
+ return false;
+ }
+
+ secure_vector<byte> r(sig, sig + hash->output_length());
+
+ // check that 0 < s < q
+ const BigInt s(sig + hash->output_length(), sig_len - hash->output_length());
+
+ if(s <= 0 || s >= m_order)
+ {
+ return false;
+ }
+
+ secure_vector<byte> r_xor_e(r);
+ xor_buf(r_xor_e, msg, r.size());
+ BigInt w(r_xor_e.data(), r_xor_e.size());
+ w = m_mod_order.reduce(w);
+
+ const PointGFp q = (m_base_point * w) + (m_public_point * s);
+ const BigInt q_x = q.get_affine_x();
+ secure_vector<byte> c(q_x.bytes());
+ q_x.binary_encode(c.data());
+ std::unique_ptr<EMSA> emsa(m_emsa->clone());
+ emsa->update(c.data(), c.size());
+ secure_vector<byte> v = emsa->raw_data();
+ Null_RNG rng;
+ v = emsa->encoding_of(v, max_input_bits(), rng);
+
+ return (v == r);
+ }
+
+BOTAN_REGISTER_PK_SIGNATURE_OP("ECKCDSA", ECKCDSA_Signature_Operation);
+BOTAN_REGISTER_PK_VERIFY_OP("ECKCDSA", ECKCDSA_Verification_Operation);
+
+}
+
+}
diff --git a/src/lib/pubkey/eckcdsa/eckcdsa.h b/src/lib/pubkey/eckcdsa/eckcdsa.h
new file mode 100644
index 000000000..b85c4025e
--- /dev/null
+++ b/src/lib/pubkey/eckcdsa/eckcdsa.h
@@ -0,0 +1,91 @@
+/*
+* ECKCDSA (ISO/IEC 14888-3:2006/Cor.2:2009)
+* (C) 2016 René Korthaus, Sirrix AG
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ECKCDSA_KEY_H__
+#define BOTAN_ECKCDSA_KEY_H__
+
+#include <botan/ecc_key.h>
+
+namespace Botan {
+
+/**
+* This class represents ECKCDSA public keys.
+*/
+class BOTAN_DLL ECKCDSA_PublicKey : public virtual EC_PublicKey
+ {
+ public:
+
+ /**
+ * 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
+ */
+ ECKCDSA_PublicKey(const EC_Group& dom_par,
+ const PointGFp& public_point) :
+ EC_PublicKey(dom_par, public_point) {}
+
+ ECKCDSA_PublicKey(const AlgorithmIdentifier& alg_id,
+ const secure_vector<byte>& key_bits) :
+ EC_PublicKey(alg_id, key_bits) {}
+
+ /**
+ * Get this keys algorithm name.
+ * @result this keys algorithm name ("ECGDSA")
+ */
+ std::string algo_name() const override { return "ECKCDSA"; }
+
+ /**
+ * 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
+ */
+ size_t max_input_bits() const override
+ { return domain().get_order().bits(); }
+
+ size_t message_parts() const override { return 2; }
+
+ size_t message_part_size() const override
+ { return domain().get_order().bytes(); }
+
+ protected:
+ ECKCDSA_PublicKey() {}
+ };
+
+/**
+* This class represents ECKCDSA private keys.
+*/
+class BOTAN_DLL ECKCDSA_PrivateKey : public ECKCDSA_PublicKey,
+ public EC_PrivateKey
+ {
+ public:
+
+ /**
+ * Load a private key
+ * @param alg_id the X.509 algorithm identifier
+ * @param key_bits PKCS #8 structure
+ */
+ ECKCDSA_PrivateKey(const AlgorithmIdentifier& alg_id,
+ const secure_vector<byte>& key_bits) :
+ EC_PrivateKey(alg_id, key_bits, true) {}
+
+ /**
+ * Generate a new private key
+ * @param rng a random number generator
+ * @param domain parameters to used for this key
+ * @param x the private key (if zero, generate a new random key)
+ */
+ ECKCDSA_PrivateKey(RandomNumberGenerator& rng,
+ const EC_Group& domain,
+ const BigInt& x = 0) :
+ EC_PrivateKey(rng, domain, x, true) {}
+
+ bool check_key(RandomNumberGenerator& rng, bool) const override;
+ };
+
+}
+
+#endif
diff --git a/src/lib/pubkey/eckcdsa/info.txt b/src/lib/pubkey/eckcdsa/info.txt
new file mode 100644
index 000000000..d3df354b1
--- /dev/null
+++ b/src/lib/pubkey/eckcdsa/info.txt
@@ -0,0 +1,13 @@
+define ECKCDSA 20160413
+
+<requires>
+asn1
+bigint
+ec_group
+ecc_key
+hash
+keypair
+numbertheory
+pk_pad
+rng
+</requires>
diff --git a/src/lib/pubkey/pk_algs.cpp b/src/lib/pubkey/pk_algs.cpp
index d2947b0c0..9dbde28af 100644
--- a/src/lib/pubkey/pk_algs.cpp
+++ b/src/lib/pubkey/pk_algs.cpp
@@ -28,6 +28,10 @@
#include <botan/ecgdsa.h>
#endif
+#if defined(BOTAN_HAS_ECKCDSA)
+ #include <botan/eckcdsa.h>
+#endif
+
#if defined(BOTAN_HAS_GOST_34_10_2001)
#include <botan/gost_3410.h>
#endif
@@ -105,6 +109,11 @@ Public_Key* make_public_key(const AlgorithmIdentifier& alg_id,
return new ECGDSA_PublicKey(alg_id, key_bits);
#endif
+#if defined(BOTAN_HAS_ECKCDSA)
+ if(alg_name == "ECKCDSA")
+ return new ECKCDSA_PublicKey(alg_id, key_bits);
+#endif
+
#if defined(BOTAN_HAS_GOST_34_10_2001)
if(alg_name == "GOST-34.10")
return new GOST_3410_PublicKey(alg_id, key_bits);
@@ -176,6 +185,11 @@ Private_Key* make_private_key(const AlgorithmIdentifier& alg_id,
return new ECGDSA_PrivateKey(alg_id, key_bits);
#endif
+#if defined(BOTAN_HAS_ECKCDSA)
+ if(alg_name == "ECKCDSA")
+ return new ECKCDSA_PrivateKey(alg_id, key_bits);
+#endif
+
#if defined(BOTAN_HAS_GOST_34_10_2001)
if(alg_name == "GOST-34.10")
return new GOST_3410_PrivateKey(alg_id, key_bits);
diff --git a/src/lib/pubkey/pk_ops.cpp b/src/lib/pubkey/pk_ops.cpp
index 654b68255..1017518a7 100644
--- a/src/lib/pubkey/pk_ops.cpp
+++ b/src/lib/pubkey/pk_ops.cpp
@@ -76,9 +76,12 @@ secure_vector<byte> PK_Ops::Key_Agreement_with_KDF::agree(size_t key_len,
return z;
}
-PK_Ops::Signature_with_EMSA::Signature_with_EMSA(const std::string& emsa)
+PK_Ops::Signature_with_EMSA::Signature_with_EMSA(const std::string& emsa) :
+ Signature(),
+ m_emsa(get_emsa(emsa)),
+ m_hash(hash_for_emsa(emsa)),
+ m_prefix_used(false)
{
- m_emsa.reset(get_emsa(emsa));
if(!m_emsa)
throw Algorithm_Not_Found(emsa);
}
@@ -87,19 +90,29 @@ PK_Ops::Signature_with_EMSA::~Signature_with_EMSA() {}
void PK_Ops::Signature_with_EMSA::update(const byte msg[], size_t msg_len)
{
+ if(has_prefix() && !m_prefix_used)
+ {
+ m_prefix_used = true;
+ secure_vector<byte> prefix = message_prefix();
+ m_emsa->update(prefix.data(), prefix.size());
+ }
m_emsa->update(msg, msg_len);
}
secure_vector<byte> PK_Ops::Signature_with_EMSA::sign(RandomNumberGenerator& rng)
{
+ m_prefix_used = false;
const secure_vector<byte> msg = m_emsa->raw_data();
const auto padded = m_emsa->encoding_of(msg, this->max_input_bits(), rng);
return raw_sign(padded.data(), padded.size(), rng);
}
-PK_Ops::Verification_with_EMSA::Verification_with_EMSA(const std::string& emsa)
+PK_Ops::Verification_with_EMSA::Verification_with_EMSA(const std::string& emsa) :
+ Verification(),
+ m_emsa(get_emsa(emsa)),
+ m_hash(hash_for_emsa(emsa)),
+ m_prefix_used(false)
{
- m_emsa.reset(get_emsa(emsa));
if(!m_emsa)
throw Algorithm_Not_Found(emsa);
}
@@ -108,11 +121,18 @@ PK_Ops::Verification_with_EMSA::~Verification_with_EMSA() {}
void PK_Ops::Verification_with_EMSA::update(const byte msg[], size_t msg_len)
{
+ if(has_prefix() && !m_prefix_used)
+ {
+ m_prefix_used = true;
+ secure_vector<byte> prefix = message_prefix();
+ m_emsa->update(prefix.data(), prefix.size());
+ }
m_emsa->update(msg, msg_len);
}
bool PK_Ops::Verification_with_EMSA::is_valid_signature(const byte sig[], size_t sig_len)
{
+ m_prefix_used = false;
const secure_vector<byte> msg = m_emsa->raw_data();
if(with_recovery())
diff --git a/src/lib/pubkey/pk_ops_impl.h b/src/lib/pubkey/pk_ops_impl.h
index 81637a81c..9d02de5e5 100644
--- a/src/lib/pubkey/pk_ops_impl.h
+++ b/src/lib/pubkey/pk_ops_impl.h
@@ -58,12 +58,25 @@ class Verification_with_EMSA : public Verification
bool do_check(const secure_vector<byte>& msg,
const byte sig[], size_t sig_len);
+ std::string hash_for_signature() { return m_hash; }
protected:
explicit Verification_with_EMSA(const std::string& emsa);
~Verification_with_EMSA();
/**
+ * @return boolean specifying if this signature scheme uses
+ * a message prefix returned by message_prefix()
+ */
+ virtual bool has_prefix() { return false; }
+
+ /**
+ * @return the message prefix if this signature scheme uses
+ * a message prefix, signaled via has_prefix()
+ */
+ virtual secure_vector<byte> message_prefix() const { throw Exception( "No prefix" ); }
+
+ /**
* @return boolean specifying if this key type supports message
* recovery and thus if you need to call verify() or verify_mr()
*/
@@ -95,8 +108,11 @@ class Verification_with_EMSA : public Verification
throw Invalid_State("Message recovery not supported");
}
- private:
std::unique_ptr<EMSA> m_emsa;
+
+ private:
+ const std::string m_hash;
+ bool m_prefix_used;
};
class Signature_with_EMSA : public Signature
@@ -108,6 +124,22 @@ class Signature_with_EMSA : public Signature
protected:
explicit Signature_with_EMSA(const std::string& emsa);
~Signature_with_EMSA();
+
+ std::string hash_for_signature() { return m_hash; }
+
+ /**
+ * @return boolean specifying if this signature scheme uses
+ * a message prefix returned by message_prefix()
+ */
+ virtual bool has_prefix() { return false; }
+
+ /**
+ * @return the message prefix if this signature scheme uses
+ * a message prefix, signaled via has_prefix()
+ */
+ virtual secure_vector<byte> message_prefix() const { throw Exception( "No prefix" ); }
+
+ std::unique_ptr<EMSA> m_emsa;
private:
/**
@@ -122,7 +154,8 @@ class Signature_with_EMSA : public Signature
virtual secure_vector<byte> raw_sign(const byte msg[], size_t msg_len,
RandomNumberGenerator& rng) = 0;
- std::unique_ptr<EMSA> m_emsa;
+ const std::string m_hash;
+ bool m_prefix_used;
};
class Key_Agreement_with_KDF : public Key_Agreement
diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp
index c0485fec8..8b24ee983 100644
--- a/src/lib/pubkey/pubkey.cpp
+++ b/src/lib/pubkey/pubkey.cpp
@@ -54,7 +54,7 @@ PK_Decryptor::decrypt_or_random(const byte in[],
{
const secure_vector<byte> fake_pms = rng.random_vec(expected_pt_len);
- CT::poison(in, length);
+ //CT::poison(in, length);
byte valid_mask = 0;
secure_vector<byte> decoded = do_decrypt(valid_mask, in, length);
@@ -90,8 +90,8 @@ PK_Decryptor::decrypt_or_random(const byte in[],
/*from1*/fake_pms.data(),
expected_pt_len);
- CT::unpoison(in, length);
- CT::unpoison(decoded.data(), decoded.size());
+ //CT::unpoison(in, length);
+ //CT::unpoison(decoded.data(), decoded.size());
return decoded;
}
diff --git a/src/lib/pubkey/rfc6979/rfc6979.cpp b/src/lib/pubkey/rfc6979/rfc6979.cpp
index f749b039f..94b313c3a 100644
--- a/src/lib/pubkey/rfc6979/rfc6979.cpp
+++ b/src/lib/pubkey/rfc6979/rfc6979.cpp
@@ -8,41 +8,32 @@
#include <botan/rfc6979.h>
#include <botan/hmac_drbg.h>
#include <botan/mac.h>
-#include <botan/scan_name.h>
namespace Botan {
-std::string hash_for_deterministic_signature(const std::string& emsa)
- {
- SCAN_Name emsa_name(emsa);
-
- if(emsa_name.arg_count() > 0)
- {
- const std::string pos_hash = emsa_name.arg(0);
- return pos_hash;
- }
-
- return "SHA-512"; // safe default if nothing we understand
- }
-
RFC6979_Nonce_Generator::RFC6979_Nonce_Generator(const std::string& hash,
const BigInt& order,
const BigInt& x) :
m_order(order),
m_qlen(m_order.bits()),
m_rlen(m_qlen / 8 + (m_qlen % 8 ? 1 : 0)),
- m_hmac_drbg(new HMAC_DRBG(MessageAuthenticationCode::create("HMAC(" + hash + ")").release())),
m_rng_in(m_rlen * 2),
m_rng_out(m_rlen)
{
+ m_hmac_drbg.reset(new HMAC_DRBG(MessageAuthenticationCode::create("HMAC(" + hash + ")")));
BigInt::encode_1363(m_rng_in.data(), m_rlen, x);
}
+RFC6979_Nonce_Generator::~RFC6979_Nonce_Generator()
+ {
+ // for ~unique_ptr
+ }
+
const BigInt& RFC6979_Nonce_Generator::nonce_for(const BigInt& m)
{
BigInt::encode_1363(&m_rng_in[m_rlen], m_rlen, m);
m_hmac_drbg->clear();
- m_hmac_drbg->add_entropy(m_rng_in.data(), m_rng_in.size());
+ m_hmac_drbg->initialize_with(m_rng_in.data(), m_rng_in.size());
do
{
diff --git a/src/lib/pubkey/rfc6979/rfc6979.h b/src/lib/pubkey/rfc6979/rfc6979.h
index 5b3dee8ef..2518535f7 100644
--- a/src/lib/pubkey/rfc6979/rfc6979.h
+++ b/src/lib/pubkey/rfc6979/rfc6979.h
@@ -14,7 +14,7 @@
namespace Botan {
-class RandomNumberGenerator;
+class HMAC_DRBG;
class BOTAN_DLL RFC6979_Nonce_Generator
{
@@ -26,12 +26,14 @@ class BOTAN_DLL RFC6979_Nonce_Generator
const BigInt& order,
const BigInt& x);
+ ~RFC6979_Nonce_Generator();
+
const BigInt& nonce_for(const BigInt& m);
private:
const BigInt& m_order;
BigInt m_k;
size_t m_qlen, m_rlen;
- std::unique_ptr<RandomNumberGenerator> m_hmac_drbg;
+ std::unique_ptr<HMAC_DRBG> m_hmac_drbg;
secure_vector<byte> m_rng_in, m_rng_out;
};
@@ -46,8 +48,6 @@ BigInt BOTAN_DLL generate_rfc6979_nonce(const BigInt& x,
const BigInt& h,
const std::string& hash);
-std::string hash_for_deterministic_signature(const std::string& emsa);
-
}
#endif
diff --git a/src/lib/pubkey/rsa/info.txt b/src/lib/pubkey/rsa/info.txt
index 264ff7c62..91eec565a 100644
--- a/src/lib/pubkey/rsa/info.txt
+++ b/src/lib/pubkey/rsa/info.txt
@@ -4,4 +4,6 @@ define RSA 20131128
if_algo
keypair
numbertheory
+emsa_pssr
+sha2_32
</requires>
diff --git a/src/lib/pubkey/rsa/rsa.cpp b/src/lib/pubkey/rsa/rsa.cpp
index e12586014..6a645ec88 100644
--- a/src/lib/pubkey/rsa/rsa.cpp
+++ b/src/lib/pubkey/rsa/rsa.cpp
@@ -58,7 +58,7 @@ bool RSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const
if((m_e * m_d) % lcm(m_p - 1, m_q - 1) != 1)
return false;
- return KeyPair::signature_consistency_check(rng, *this, "EMSA4(SHA-1)");
+ return KeyPair::signature_consistency_check(rng, *this, "EMSA4(SHA-256)");
}
namespace {