aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-09-07 10:29:47 -0400
committerJack Lloyd <[email protected]>2017-09-07 10:29:47 -0400
commit1a39eca36d5b2f41b3178fbb1a359e42d47b7a74 (patch)
tree66f5d3224b6070572753779b413c46d3400104cc /src
parente3f0b9ed6843f44162f482c10b1f214d6e634104 (diff)
parent729ee64431748d898a2a53baa8f8e17f2925e16e (diff)
Merge GH #1188 Support arbitrary hashes in SM2
Diffstat (limited to 'src')
-rw-r--r--src/lib/ffi/ffi.h6
-rw-r--r--src/lib/ffi/ffi_pkey_algs.cpp36
-rw-r--r--src/lib/pubkey/sm2/sm2.cpp44
-rw-r--r--src/lib/pubkey/sm2/sm2_enc.cpp30
-rw-r--r--src/tests/data/pubkey/sm2_sig.vec1
-rw-r--r--src/tests/test_ffi.cpp8
-rw-r--r--src/tests/test_sm2.cpp10
7 files changed, 110 insertions, 25 deletions
diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h
index 565d5ce7b..005d32eee 100644
--- a/src/lib/ffi/ffi.h
+++ b/src/lib/ffi/ffi.h
@@ -961,6 +961,12 @@ BOTAN_DLL int botan_privkey_load_sm2_enc(botan_privkey_t* key,
const botan_mp_t scalar,
const char* curve_name);
+BOTAN_DLL int botan_pubkey_sm2_compute_za(uint8_t out[],
+ size_t* out_len,
+ const char* ident,
+ const char* hash_algo,
+ const botan_pubkey_t key);
+
/*
* Public Key Encryption
*/
diff --git a/src/lib/ffi/ffi_pkey_algs.cpp b/src/lib/ffi/ffi_pkey_algs.cpp
index b06fd113c..83ee51768 100644
--- a/src/lib/ffi/ffi_pkey_algs.cpp
+++ b/src/lib/ffi/ffi_pkey_algs.cpp
@@ -6,6 +6,7 @@
*/
#include <botan/ffi.h>
+#include <botan/hash.h>
#include <botan/internal/ffi_util.h>
#include <botan/internal/ffi_pkey.h>
#include <botan/internal/ffi_rng.h>
@@ -570,6 +571,41 @@ int botan_privkey_load_ecdh(botan_privkey_t* key,
/* SM2 specific operations */
+int botan_pubkey_sm2_compute_za(uint8_t out[],
+ size_t* out_len,
+ const char* ident,
+ const char* hash_algo,
+ const botan_pubkey_t key)
+ {
+ if(out == nullptr || out_len == nullptr)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+ if(ident == nullptr || hash_algo == nullptr || key == nullptr)
+ return BOTAN_FFI_ERROR_NULL_POINTER;
+
+#if defined(BOTAN_HAS_SM2)
+ return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() {
+ const Botan::Public_Key& pub_key = safe_get(key);
+ const Botan::EC_PublicKey* ec_key = dynamic_cast<const Botan::EC_PublicKey*>(&pub_key);
+ if(key == nullptr)
+ return BOTAN_FFI_ERROR_BAD_PARAMETER;
+
+ if(ec_key->algo_name() != "SM2_Sig" && ec_key->algo_name() != "SM2_Enc")
+ return BOTAN_FFI_ERROR_BAD_PARAMETER;
+
+ const std::string ident_str(ident);
+ std::unique_ptr<Botan::HashFunction> hash =
+ Botan::HashFunction::create_or_throw(hash_algo);
+
+ const std::vector<uint8_t> za =
+ Botan::sm2_compute_za(*hash, ident_str, ec_key->domain(), ec_key->public_point());
+
+ return write_vec_output(out, out_len, za);
+ });
+#else
+ return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+ }
+
int botan_pubkey_load_sm2(botan_pubkey_t* key,
const botan_mp_t public_x,
const botan_mp_t public_y,
diff --git a/src/lib/pubkey/sm2/sm2.cpp b/src/lib/pubkey/sm2/sm2.cpp
index 2882cb0ad..dbb22ca6d 100644
--- a/src/lib/pubkey/sm2/sm2.cpp
+++ b/src/lib/pubkey/sm2/sm2.cpp
@@ -1,5 +1,5 @@
/*
-* SM2
+* SM2 Signatures
* (C) 2017 Ribose Inc
*
* Botan is released under the Simplified BSD License (see license.txt)
@@ -79,13 +79,14 @@ class SM2_Signature_Operation : public PK_Ops::Signature
public:
SM2_Signature_Operation(const SM2_Signature_PrivateKey& sm2,
- const std::string& ident) :
+ const std::string& ident,
+ const std::string& hash) :
m_order(sm2.domain().get_order()),
m_base_point(sm2.domain().get_base_point(), m_order),
m_x(sm2.private_value()),
m_da_inv(sm2.get_da_inv()),
m_mod_order(m_order),
- m_hash(HashFunction::create_or_throw("SM3"))
+ m_hash(HashFunction::create_or_throw(hash))
{
// ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
m_za = sm2_compute_za(*m_hash, ident, sm2.domain(), sm2.public_point());
@@ -134,12 +135,13 @@ class SM2_Verification_Operation : public PK_Ops::Verification
{
public:
SM2_Verification_Operation(const SM2_Signature_PublicKey& sm2,
- const std::string& ident) :
+ const std::string& ident,
+ const std::string& hash) :
m_base_point(sm2.domain().get_base_point()),
m_public_point(sm2.public_point()),
m_order(sm2.domain().get_order()),
m_mod_order(m_order),
- m_hash(HashFunction::create_or_throw("SM3"))
+ m_hash(HashFunction::create_or_throw(hash))
{
// ZA=H256(ENTLA || IDA || a || b || xG || yG || xA || yA)
m_za = sm2_compute_za(*m_hash, ident, sm2.domain(), sm2.public_point());
@@ -199,7 +201,21 @@ SM2_Signature_PublicKey::create_verification_op(const std::string& params,
const std::string& provider) const
{
if(provider == "base" || provider.empty())
- return std::unique_ptr<PK_Ops::Verification>(new SM2_Verification_Operation(*this, params));
+ {
+ std::string userid = "";
+ std::string hash = "SM3";
+
+ auto comma = params.find(',');
+ if(comma == std::string::npos)
+ userid = params;
+ else
+ {
+ userid = params.substr(0, comma);
+ hash = params.substr(comma+1, std::string::npos);
+ }
+
+ return std::unique_ptr<PK_Ops::Verification>(new SM2_Verification_Operation(*this, userid, hash));
+ }
throw Provider_Not_Found(algo_name(), provider);
}
@@ -210,7 +226,21 @@ SM2_Signature_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
const std::string& provider) const
{
if(provider == "base" || provider.empty())
- return std::unique_ptr<PK_Ops::Signature>(new SM2_Signature_Operation(*this, params));
+ {
+ std::string userid = "";
+ std::string hash = "SM3";
+
+ auto comma = params.find(',');
+ if(comma == std::string::npos)
+ userid = params;
+ else
+ {
+ userid = params.substr(0, comma);
+ hash = params.substr(comma+1, std::string::npos);
+ }
+
+ return std::unique_ptr<PK_Ops::Signature>(new SM2_Signature_Operation(*this, userid, hash));
+ }
throw Provider_Not_Found(algo_name(), provider);
}
diff --git a/src/lib/pubkey/sm2/sm2_enc.cpp b/src/lib/pubkey/sm2/sm2_enc.cpp
index a832dd1ac..9bd4bf11c 100644
--- a/src/lib/pubkey/sm2/sm2_enc.cpp
+++ b/src/lib/pubkey/sm2/sm2_enc.cpp
@@ -43,11 +43,12 @@ namespace {
class SM2_Encryption_Operation : public PK_Ops::Encryption
{
public:
- SM2_Encryption_Operation(const SM2_Encryption_PublicKey& key) :
+ SM2_Encryption_Operation(const SM2_Encryption_PublicKey& key, const std::string& kdf_hash) :
m_p_bytes(key.domain().get_curve().get_p().bytes()),
m_order(key.domain().get_order()),
m_base_point(key.domain().get_base_point(), m_order),
- m_public_point(key.public_point(), m_order)
+ m_public_point(key.public_point(), m_order),
+ m_kdf_hash(kdf_hash)
{}
size_t max_input_bits() const override
@@ -60,8 +61,8 @@ class SM2_Encryption_Operation : public PK_Ops::Encryption
size_t msg_len,
RandomNumberGenerator& rng) override
{
- std::unique_ptr<HashFunction> hash = HashFunction::create("SM3");
- std::unique_ptr<KDF> kdf = KDF::create("KDF2(SM3)");
+ std::unique_ptr<HashFunction> hash = HashFunction::create_or_throw(m_kdf_hash);
+ std::unique_ptr<KDF> kdf = KDF::create_or_throw("KDF2(" + m_kdf_hash + ")");
secure_vector<uint8_t> ciphertext;
ciphertext.reserve(1 + m_p_bytes*2 + msg_len + hash->output_length());
@@ -115,15 +116,18 @@ class SM2_Encryption_Operation : public PK_Ops::Encryption
const BigInt& m_order;
Blinded_Point_Multiply m_base_point;
Blinded_Point_Multiply m_public_point;
+ const std::string m_kdf_hash;
};
class SM2_Decryption_Operation : public PK_Ops::Decryption
{
public:
SM2_Decryption_Operation(const SM2_Encryption_PrivateKey& key,
- RandomNumberGenerator& rng) :
+ RandomNumberGenerator& rng,
+ const std::string& kdf_hash) :
m_key(key),
- m_rng(rng)
+ m_rng(rng),
+ m_kdf_hash(kdf_hash)
{}
secure_vector<uint8_t> decrypt(uint8_t& valid_mask,
@@ -135,7 +139,8 @@ class SM2_Decryption_Operation : public PK_Ops::Decryption
valid_mask = 0;
- std::unique_ptr<HashFunction> hash = HashFunction::create("SM3");
+ std::unique_ptr<HashFunction> hash = HashFunction::create_or_throw(m_kdf_hash);
+ std::unique_ptr<KDF> kdf = KDF::create_or_throw("KDF2(" + m_kdf_hash + ")");
// Too short to be valid - no timing problem from early return
if(ciphertext_len < 1 + p_bytes*2 + hash->output_length())
@@ -174,7 +179,6 @@ class SM2_Decryption_Operation : public PK_Ops::Decryption
const size_t msg_len = ciphertext_len - (1 + p_bytes*2 + hash->output_length());
- std::unique_ptr<KDF> kdf = KDF::create("KDF2(SM3)");
const secure_vector<uint8_t> kdf_output =
kdf->derive_key(msg_len, kdf_input.data(), kdf_input.size());
@@ -195,7 +199,7 @@ class SM2_Decryption_Operation : public PK_Ops::Decryption
private:
const SM2_Encryption_PrivateKey& m_key;
RandomNumberGenerator& m_rng;
- const std::string m_ident;
+ const std::string m_kdf_hash;
};
}
@@ -207,8 +211,8 @@ SM2_Encryption_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/,
{
if(provider == "base" || provider.empty())
{
- if(params == "")
- return std::unique_ptr<PK_Ops::Encryption>(new SM2_Encryption_Operation(*this));
+ const std::string kdf_hash = (params.empty() ? "SM3" : params);
+ return std::unique_ptr<PK_Ops::Encryption>(new SM2_Encryption_Operation(*this, kdf_hash));
}
throw Provider_Not_Found(algo_name(), provider);
@@ -221,8 +225,8 @@ SM2_Encryption_PrivateKey::create_decryption_op(RandomNumberGenerator& rng,
{
if(provider == "base" || provider.empty())
{
- if(params == "")
- return std::unique_ptr<PK_Ops::Decryption>(new SM2_Decryption_Operation(*this, rng));
+ const std::string kdf_hash = (params.empty() ? "SM3" : params);
+ return std::unique_ptr<PK_Ops::Decryption>(new SM2_Decryption_Operation(*this, rng, kdf_hash));
}
throw Provider_Not_Found(algo_name(), provider);
diff --git a/src/tests/data/pubkey/sm2_sig.vec b/src/tests/data/pubkey/sm2_sig.vec
index d3356cceb..8a86dfc7d 100644
--- a/src/tests/data/pubkey/sm2_sig.vec
+++ b/src/tests/data/pubkey/sm2_sig.vec
@@ -7,6 +7,7 @@ yG = 0x0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2
Order = 0x8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7
Cofactor = 1
+Hash = SM3
Msg = 6D65737361676520646967657374
x = 0x128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263
diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp
index 41fa3a044..4a8e7b317 100644
--- a/src/tests/test_ffi.cpp
+++ b/src/tests/test_ffi.cpp
@@ -1408,6 +1408,10 @@ class FFI_Unit_Tests : public Test
TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
ffi_test_pubkey_export(result, pub, priv, rng);
+ uint8_t za[32];
+ size_t sizeof_za = sizeof(za);
+ TEST_FFI_OK(botan_pubkey_sm2_compute_za, (za, &sizeof_za, "Ident", "SM3", pub));
+
// Check key load functions
botan_mp_t private_scalar, public_x, public_y;
botan_mp_init(&private_scalar);
@@ -1495,6 +1499,10 @@ class FFI_Unit_Tests : public Test
TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
ffi_test_pubkey_export(result, pub, priv, rng);
+ uint8_t za[32];
+ size_t sizeof_za = sizeof(za);
+ TEST_FFI_OK(botan_pubkey_sm2_compute_za, (za, &sizeof_za, "Ident", "SM3", pub));
+
// Check key load functions
botan_mp_t private_scalar, public_x, public_y;
botan_mp_init(&private_scalar);
diff --git a/src/tests/test_sm2.cpp b/src/tests/test_sm2.cpp
index 88d872435..0497ccedd 100644
--- a/src/tests/test_sm2.cpp
+++ b/src/tests/test_sm2.cpp
@@ -27,11 +27,11 @@ class SM2_Signature_KAT_Tests : public PK_Signature_Generation_Test
"SM2",
"pubkey/sm2_sig.vec",
"P,A,B,xG,yG,Order,Cofactor,Ident,Msg,x,Nonce,Signature",
- "") {}
+ "Hash") {}
virtual std::string default_padding(const VarMap& vars) const override
{
- return get_req_str(vars, "Ident");
+ return get_req_str(vars, "Ident") + "," + get_opt_str(vars, "Hash", "SM3");
}
Botan::RandomNumberGenerator* test_rng(const std::vector<uint8_t>& nonce) const override
@@ -71,11 +71,11 @@ class SM2_Encryption_KAT_Tests : public PK_Encryption_Decryption_Test
"SM2",
"pubkey/sm2_enc.vec",
"P,A,B,xG,yG,Order,Cofactor,Msg,x,Nonce,Ciphertext",
- "") {}
+ "Hash") {}
- virtual std::string default_padding(const VarMap&) const override
+ virtual std::string default_padding(const VarMap& vars) const override
{
- return "";
+ return get_opt_str(vars, "Hash", "SM3");
}
Botan::RandomNumberGenerator* test_rng(const std::vector<uint8_t>& nonce) const override