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>
21#include <botan/internal/stl_util.h>
43std::unique_ptr<HashFunction> eckcdsa_signature_hash(std::string_view padding) {
48 SCAN_Name req(padding);
50 if(req.algo_name() ==
"EMSA1" && req.arg_count() == 1) {
59 throw Algorithm_Not_Found(padding);
62std::unique_ptr<HashFunction> eckcdsa_signature_hash(
const AlgorithmIdentifier& alg_id) {
63 const auto oid_info =
split_on(alg_id.oid().to_formatted_string(),
'/');
65 if(oid_info.size() != 2 || oid_info[0] !=
"ECKCDSA") {
66 throw Decoding_Error(
fmt(
"Unexpected AlgorithmIdentifier OID {} in association with ECKCDSA key", alg_id.oid()));
69 if(!alg_id.parameters_are_empty()) {
70 throw Decoding_Error(
"Unexpected non-empty AlgorithmIdentifier parameters for ECKCDSA");
76std::vector<uint8_t> eckcdsa_prefix(
const EC_Point& point,
size_t hash_block_size) {
80 prefix.resize(hash_block_size);
109 if(digest.size() > group_order_bytes) {
110 const size_t bytes_to_truncate = digest.size() - group_order_bytes;
111 digest.erase(digest.begin(), digest.begin() + bytes_to_truncate);
118class ECKCDSA_Signature_Operation
final :
public PK_Ops::Signature {
120 ECKCDSA_Signature_Operation(
const ECKCDSA_PrivateKey& eckcdsa, std::string_view padding) :
121 m_group(eckcdsa.domain()),
122 m_x(eckcdsa.private_value()),
123 m_hash(eckcdsa_signature_hash(padding)),
124 m_prefix_used(false) {
125 m_prefix = eckcdsa_prefix(eckcdsa.public_point(), m_hash->hash_block_size());
128 void update(
const uint8_t msg[],
size_t msg_len)
override {
130 m_hash->update(m_prefix.data(), m_prefix.size());
131 m_prefix_used =
true;
133 m_hash->update(msg, msg_len);
137 m_prefix_used =
false;
139 truncate_hash_if_needed(digest, m_group.get_order_bytes());
140 return raw_sign(digest.data(), digest.size(), rng);
143 size_t signature_length()
const override {
return 2 * m_group.get_order_bytes(); }
145 AlgorithmIdentifier algorithm_identifier()
const override;
147 std::string hash_function()
const override {
return m_hash->name(); }
152 const EC_Group m_group;
154 std::unique_ptr<HashFunction> m_hash;
155 std::vector<uint8_t> m_prefix;
156 std::vector<BigInt> m_ws;
160AlgorithmIdentifier ECKCDSA_Signature_Operation::algorithm_identifier()
const {
161 const std::string full_name =
"ECKCDSA/" + m_hash->name();
162 const OID oid = OID::from_string(full_name);
163 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
168 RandomNumberGenerator& rng) {
172 auto hash = m_hash->new_object();
174 secure_vector<uint8_t> c = hash->final();
181 const BigInt w = m_group.
mod_order(BigInt::from_bytes(c));
185 throw Internal_Error(
"During ECKCDSA signature generation created zero s");
194class ECKCDSA_Verification_Operation
final :
public PK_Ops::Verification {
196 ECKCDSA_Verification_Operation(
const ECKCDSA_PublicKey& eckcdsa, std::string_view padding) :
197 m_group(eckcdsa.domain()),
198 m_gy_mul(m_group.get_base_point(), eckcdsa.public_point()),
199 m_hash(eckcdsa_signature_hash(padding)),
200 m_prefix_used(false) {
201 m_prefix = eckcdsa_prefix(eckcdsa.public_point(), m_hash->hash_block_size());
204 ECKCDSA_Verification_Operation(
const ECKCDSA_PublicKey& eckcdsa,
const AlgorithmIdentifier& alg_id) :
205 m_group(eckcdsa.domain()),
206 m_gy_mul(m_group.get_base_point(), eckcdsa.public_point()),
207 m_hash(eckcdsa_signature_hash(alg_id)),
208 m_prefix_used(false) {
209 m_prefix = eckcdsa_prefix(eckcdsa.public_point(), m_hash->hash_block_size());
212 void update(
const uint8_t msg[],
size_t msg_len)
override;
214 bool is_valid_signature(
const uint8_t sig[],
size_t sig_len)
override;
216 std::string hash_function()
const override {
return m_hash->name(); }
219 bool verify(
const uint8_t msg[],
size_t msg_len,
const uint8_t sig[],
size_t sig_len);
221 const EC_Group m_group;
222 const EC_Point_Multi_Point_Precompute m_gy_mul;
223 std::vector<uint8_t> m_prefix;
224 std::unique_ptr<HashFunction> m_hash;
228void ECKCDSA_Verification_Operation::update(
const uint8_t msg[],
size_t msg_len) {
230 m_prefix_used =
true;
231 m_hash->update(m_prefix.data(), m_prefix.size());
233 m_hash->update(msg, msg_len);
236bool ECKCDSA_Verification_Operation::is_valid_signature(
const uint8_t sig[],
size_t sig_len) {
237 m_prefix_used =
false;
238 secure_vector<uint8_t> digest = m_hash->final();
240 return verify(digest.data(), digest.size(), sig, sig_len);
243bool ECKCDSA_Verification_Operation::verify(
const uint8_t msg[],
size_t msg_len,
const uint8_t sig[],
size_t sig_len) {
248 const size_t size_r = std::min(msg_len, order_bytes);
249 if(sig_len != size_r + order_bytes) {
253 secure_vector<uint8_t> r(sig, sig + size_r);
256 const BigInt s(sig + size_r, order_bytes);
262 secure_vector<uint8_t> r_xor_e(r);
263 xor_buf(r_xor_e, msg, r.size());
265 const BigInt w = m_group.
mod_order(BigInt::from_bytes(r_xor_e));
267 const EC_Point q = m_gy_mul.
multi_exp(w, s);
272 auto c_hash = m_hash->new_object();
273 c_hash->update(q.x_bytes());
274 secure_vector<uint8_t> v = c_hash->final();
283 return std::make_unique<ECKCDSA_PrivateKey>(rng, domain());
287 std::string_view provider)
const {
288 if(provider ==
"base" || provider.empty()) {
289 return std::make_unique<ECKCDSA_Verification_Operation>(*
this, params);
296 if(provider ==
"base" || provider.empty()) {
297 return std::make_unique<ECKCDSA_Verification_Operation>(*
this, signature_algorithm);
304 std::string_view params,
305 std::string_view provider)
const {
306 if(provider ==
"base" || provider.empty()) {
307 return std::make_unique<ECKCDSA_Signature_Operation>(*
this, params);
#define BOTAN_ASSERT_NOMSG(expr)
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
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 auto concat(Rs &&... ranges)
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)
std::vector< T, secure_allocator< T > > secure_vector