10#include <botan/eckcdsa.h>
12#include <botan/hash.h>
13#include <botan/reducer.h>
15#include <botan/internal/fmt.h>
16#include <botan/internal/keypair.h>
17#include <botan/internal/parsing.h>
18#include <botan/internal/pk_ops_impl.h>
19#include <botan/internal/point_mul.h>
20#include <botan/internal/scan_name.h>
42std::unique_ptr<HashFunction> eckcdsa_signature_hash(std::string_view padding) {
47 SCAN_Name req(padding);
49 if(req.algo_name() ==
"EMSA1" && req.arg_count() == 1) {
58 throw Algorithm_Not_Found(padding);
61std::unique_ptr<HashFunction> eckcdsa_signature_hash(
const AlgorithmIdentifier& alg_id) {
62 const auto oid_info =
split_on(alg_id.oid().to_formatted_string(),
'/');
64 if(oid_info.size() != 2 || oid_info[0] !=
"ECKCDSA") {
65 throw Decoding_Error(
fmt(
"Unexpected AlgorithmIdentifier OID {} in association with ECKCDSA key", alg_id.oid()));
68 if(!alg_id.parameters_are_empty()) {
69 throw Decoding_Error(
"Unexpected non-empty AlgorithmIdentifier parameters for ECKCDSA");
75std::vector<uint8_t> eckcdsa_prefix(
const PointGFp& point,
size_t order_bytes,
size_t hash_block_size) {
76 const BigInt public_x = point.get_affine_x();
77 const BigInt public_y = point.get_affine_y();
79 std::vector<uint8_t> prefix(2 * order_bytes);
84 prefix.resize(hash_block_size);
112void truncate_hash_if_needed(secure_vector<uint8_t>& digest,
size_t group_order_bytes) {
113 if(digest.size() > group_order_bytes) {
114 const size_t bytes_to_truncate = digest.size() - group_order_bytes;
115 digest.erase(digest.begin(), digest.begin() + bytes_to_truncate);
122class ECKCDSA_Signature_Operation
final :
public PK_Ops::Signature {
124 ECKCDSA_Signature_Operation(
const ECKCDSA_PrivateKey& eckcdsa, std::string_view padding) :
125 m_group(eckcdsa.domain()),
126 m_x(eckcdsa.private_value()),
127 m_hash(eckcdsa_signature_hash(padding)),
128 m_prefix_used(false) {
129 m_prefix = eckcdsa_prefix(eckcdsa.public_point(), m_group.get_order_bytes(), m_hash->hash_block_size());
132 void update(
const uint8_t msg[],
size_t msg_len)
override {
134 m_hash->update(m_prefix.data(), m_prefix.size());
135 m_prefix_used =
true;
137 m_hash->update(msg, msg_len);
140 secure_vector<uint8_t> sign(RandomNumberGenerator& rng)
override {
141 m_prefix_used =
false;
142 secure_vector<uint8_t> digest = m_hash->final();
143 truncate_hash_if_needed(digest, m_group.get_order_bytes());
144 return raw_sign(digest.data(), digest.size(), rng);
147 size_t signature_length()
const override {
return 2 * m_group.get_order_bytes(); }
149 AlgorithmIdentifier algorithm_identifier()
const override;
151 std::string hash_function()
const override {
return m_hash->name(); }
154 secure_vector<uint8_t> raw_sign(
const uint8_t msg[],
size_t msg_len, RandomNumberGenerator& rng);
156 const EC_Group m_group;
158 std::unique_ptr<HashFunction> m_hash;
159 std::vector<uint8_t> m_prefix;
160 std::vector<BigInt> m_ws;
164AlgorithmIdentifier ECKCDSA_Signature_Operation::algorithm_identifier()
const {
165 const std::string full_name =
"ECKCDSA/" + m_hash->name();
166 const OID oid = OID::from_string(full_name);
167 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
170secure_vector<uint8_t> ECKCDSA_Signature_Operation::raw_sign(
const uint8_t msg[],
172 RandomNumberGenerator& rng) {
176 secure_vector<uint8_t> to_be_hashed(k_times_P_x.bytes());
177 k_times_P_x.binary_encode(to_be_hashed.data());
179 auto hash = m_hash->new_object();
180 hash->update(to_be_hashed);
181 secure_vector<uint8_t> c = hash->final();
184 const BigInt r(c.data(), c.size());
188 BigInt w(c.data(), c.size());
193 throw Internal_Error(
"During ECKCDSA signature generation created zero s");
196 secure_vector<uint8_t> output = BigInt::encode_1363(r, c.size());
204class ECKCDSA_Verification_Operation
final :
public PK_Ops::Verification {
206 ECKCDSA_Verification_Operation(
const ECKCDSA_PublicKey& eckcdsa, std::string_view padding) :
207 m_group(eckcdsa.domain()),
208 m_gy_mul(m_group.get_base_point(), eckcdsa.public_point()),
209 m_hash(eckcdsa_signature_hash(padding)),
210 m_prefix_used(false) {
211 m_prefix = eckcdsa_prefix(eckcdsa.public_point(), m_group.
get_order_bytes(), m_hash->hash_block_size());
214 ECKCDSA_Verification_Operation(
const ECKCDSA_PublicKey& eckcdsa,
const AlgorithmIdentifier& alg_id) :
215 m_group(eckcdsa.domain()),
216 m_gy_mul(m_group.get_base_point(), eckcdsa.public_point()),
217 m_hash(eckcdsa_signature_hash(alg_id)),
218 m_prefix_used(false) {
219 m_prefix = eckcdsa_prefix(eckcdsa.public_point(), m_group.
get_order_bytes(), m_hash->hash_block_size());
222 void update(
const uint8_t msg[],
size_t msg_len)
override;
224 bool is_valid_signature(
const uint8_t sig[],
size_t sig_len)
override;
226 std::string hash_function()
const override {
return m_hash->name(); }
229 bool verify(
const uint8_t msg[],
size_t msg_len,
const uint8_t sig[],
size_t sig_len);
231 const EC_Group m_group;
232 const EC_Point_Multi_Point_Precompute m_gy_mul;
233 std::vector<uint8_t> m_prefix;
234 std::unique_ptr<HashFunction> m_hash;
238void ECKCDSA_Verification_Operation::update(
const uint8_t msg[],
size_t msg_len) {
240 m_prefix_used =
true;
241 m_hash->update(m_prefix.data(), m_prefix.size());
243 m_hash->update(msg, msg_len);
246bool ECKCDSA_Verification_Operation::is_valid_signature(
const uint8_t sig[],
size_t sig_len) {
247 m_prefix_used =
false;
248 secure_vector<uint8_t> digest = m_hash->final();
250 return verify(digest.data(), digest.size(), sig, sig_len);
253bool ECKCDSA_Verification_Operation::verify(
const uint8_t msg[],
size_t msg_len,
const uint8_t sig[],
size_t sig_len) {
258 const size_t size_r = std::min(msg_len, order_bytes);
259 if(sig_len != size_r + order_bytes) {
263 secure_vector<uint8_t> r(sig, sig + size_r);
266 const BigInt s(sig + size_r, order_bytes);
272 secure_vector<uint8_t> r_xor_e(r);
273 xor_buf(r_xor_e, msg, r.size());
274 BigInt w(r_xor_e.data(), r_xor_e.size());
277 const EC_Point q = m_gy_mul.
multi_exp(w, s);
283 secure_vector<uint8_t> c(q_x.bytes());
284 q_x.binary_encode(c.data());
285 auto c_hash = m_hash->new_object();
286 c_hash->update(c.data(), c.size());
287 secure_vector<uint8_t> v = c_hash->final();
296 return std::make_unique<ECKCDSA_PrivateKey>(rng, domain());
300 std::string_view provider)
const {
301 if(provider ==
"base" || provider.empty()) {
302 return std::make_unique<ECKCDSA_Verification_Operation>(*
this, params);
309 if(provider ==
"base" || provider.empty()) {
310 return std::make_unique<ECKCDSA_Verification_Operation>(*
this, signature_algorithm);
317 std::string_view params,
318 std::string_view provider)
const {
319 if(provider ==
"base" || provider.empty()) {
320 return std::make_unique<ECKCDSA_Signature_Operation>(*
this, params);
#define BOTAN_ASSERT_NOMSG(expr)
static secure_vector< uint8_t > encode_1363(const BigInt &n, size_t bytes)
std::unique_ptr< PK_Ops::Signature > create_signature_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
std::unique_ptr< Public_Key > public_key() const override
bool check_key(RandomNumberGenerator &rng, bool) const override
std::unique_ptr< PK_Ops::Verification > create_x509_verification_op(const AlgorithmIdentifier &signature_algorithm, std::string_view provider) const override
std::unique_ptr< PK_Ops::Verification > create_verification_op(std::string_view params, std::string_view provider) const override
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const final
BigInt blinded_base_point_multiply_x(const BigInt &k, RandomNumberGenerator &rng, std::vector< BigInt > &ws) const
BigInt mod_order(const BigInt &x) const
BigInt multiply_mod_order(const BigInt &x, const BigInt &y) const
const BigInt & get_order() const
BigInt random_scalar(RandomNumberGenerator &rng) const
size_t get_order_bytes() const
EC_Point multi_exp(const BigInt &k1, const BigInt &k2) const
BigInt get_affine_x() const
bool check_key(RandomNumberGenerator &rng, bool strong) const override
const EC_Group & domain() const
const EC_Point & public_point() const
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
static std::unique_ptr< HashFunction > create(std::string_view algo_spec, std::string_view provider="")
int(* update)(CTX *, const void *, CC_LONG len)
int(* final)(unsigned char *, CTX *)
bool signature_consistency_check(RandomNumberGenerator &rng, const Private_Key &private_key, const Public_Key &public_key, std::string_view padding)
std::string fmt(std::string_view format, const T &... args)
std::vector< std::string > split_on(std::string_view str, char delim)
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)