10#include <botan/eckcdsa.h>
12#include <botan/hash.h>
14#include <botan/internal/fmt.h>
15#include <botan/internal/keypair.h>
16#include <botan/internal/parsing.h>
17#include <botan/internal/pk_ops_impl.h>
18#include <botan/internal/scan_name.h>
19#include <botan/internal/stl_util.h>
41std::unique_ptr<HashFunction> eckcdsa_signature_hash(std::string_view padding) {
46 SCAN_Name req(padding);
48 if(req.algo_name() ==
"EMSA1" && req.arg_count() == 1) {
57 throw Algorithm_Not_Found(padding);
60std::unique_ptr<HashFunction> eckcdsa_signature_hash(
const AlgorithmIdentifier& alg_id) {
61 const auto oid_info =
split_on(alg_id.oid().to_formatted_string(),
'/');
63 if(oid_info.size() != 2 || oid_info[0] !=
"ECKCDSA") {
64 throw Decoding_Error(
fmt(
"Unexpected AlgorithmIdentifier OID {} in association with ECKCDSA key", alg_id.oid()));
67 if(!alg_id.parameters_are_empty()) {
68 throw Decoding_Error(
"Unexpected non-empty AlgorithmIdentifier parameters for ECKCDSA");
74std::vector<uint8_t> eckcdsa_prefix(
const EC_AffinePoint& point,
size_t hash_block_size) {
75 auto prefix = point.xy_bytes<std::vector<uint8_t>>();
78 prefix.resize(hash_block_size);
106void truncate_hash_if_needed(std::vector<uint8_t>& digest,
size_t group_order_bytes) {
107 if(digest.size() > group_order_bytes) {
108 const size_t bytes_to_truncate = digest.size() - group_order_bytes;
109 digest.erase(digest.begin(), digest.begin() + bytes_to_truncate);
116class ECKCDSA_Signature_Operation
final :
public PK_Ops::Signature {
118 ECKCDSA_Signature_Operation(
const ECKCDSA_PrivateKey& eckcdsa, std::string_view padding) :
119 m_group(eckcdsa.domain()),
120 m_x(eckcdsa._private_key()),
121 m_hash(eckcdsa_signature_hash(padding)),
122 m_prefix(eckcdsa_prefix(eckcdsa._public_ec_point(), m_hash->hash_block_size())),
123 m_prefix_used(false) {}
125 void update(std::span<const uint8_t> input)
override {
127 m_hash->update(m_prefix);
128 m_prefix_used =
true;
130 m_hash->update(input);
133 std::vector<uint8_t> sign(RandomNumberGenerator& rng)
override {
134 m_prefix_used =
false;
135 std::vector<uint8_t> digest = m_hash->final_stdvec();
136 truncate_hash_if_needed(digest, m_group.get_order_bytes());
137 return raw_sign(digest, rng);
140 size_t signature_length()
const override {
return 2 * m_group.get_order_bytes(); }
142 AlgorithmIdentifier algorithm_identifier()
const override;
144 std::string hash_function()
const override {
return m_hash->name(); }
147 std::vector<uint8_t> raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng);
149 const EC_Group m_group;
151 std::unique_ptr<HashFunction> m_hash;
152 std::vector<uint8_t> m_prefix;
153 std::vector<BigInt> m_ws;
157AlgorithmIdentifier ECKCDSA_Signature_Operation::algorithm_identifier()
const {
158 const std::string full_name =
"ECKCDSA/" + m_hash->name();
159 const OID oid = OID::from_string(full_name);
160 return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
163std::vector<uint8_t> ECKCDSA_Signature_Operation::raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) {
164 const auto k = EC_Scalar::random(m_group, rng);
168 m_hash->update(EC_AffinePoint::g_mul(k, rng, m_ws).x_bytes());
169 auto c = m_hash->final_stdvec();
175 const auto w = EC_Scalar::from_bytes_mod_order(m_group, c);
177 const auto s = m_x * (k - w);
179 throw Internal_Error(
"During ECKCDSA signature generation created zero s");
182 return concat(r, s.serialize());
188class ECKCDSA_Verification_Operation
final :
public PK_Ops::Verification {
190 ECKCDSA_Verification_Operation(
const ECKCDSA_PublicKey& eckcdsa, std::string_view padding) :
191 m_group(eckcdsa.domain()),
192 m_gy_mul(eckcdsa._public_ec_point()),
193 m_hash(eckcdsa_signature_hash(padding)),
194 m_prefix(eckcdsa_prefix(eckcdsa._public_ec_point(), m_hash->hash_block_size())),
195 m_prefix_used(false) {}
197 ECKCDSA_Verification_Operation(
const ECKCDSA_PublicKey& eckcdsa,
const AlgorithmIdentifier& alg_id) :
198 m_group(eckcdsa.domain()),
199 m_gy_mul(eckcdsa._public_ec_point()),
200 m_hash(eckcdsa_signature_hash(alg_id)),
201 m_prefix(eckcdsa_prefix(eckcdsa._public_ec_point(), m_hash->hash_block_size())),
202 m_prefix_used(false) {}
204 void update(std::span<const uint8_t> msg)
override;
206 bool is_valid_signature(std::span<const uint8_t> sig)
override;
208 std::string hash_function()
const override {
return m_hash->name(); }
211 bool verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig);
213 const EC_Group m_group;
214 const EC_Group::Mul2Table m_gy_mul;
215 std::unique_ptr<HashFunction> m_hash;
216 std::vector<uint8_t> m_prefix;
220void ECKCDSA_Verification_Operation::update(std::span<const uint8_t> msg) {
222 m_prefix_used =
true;
223 m_hash->update(m_prefix.data(), m_prefix.size());
228bool ECKCDSA_Verification_Operation::is_valid_signature(std::span<const uint8_t> sig) {
229 m_prefix_used =
false;
230 std::vector<uint8_t> digest = m_hash->final_stdvec();
232 return verify(digest, sig);
235bool ECKCDSA_Verification_Operation::verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) {
238 const size_t size_r = std::min(msg.size(), order_bytes);
239 if(sig.size() != size_r + order_bytes) {
243 auto r = sig.first(size_r);
245 if(
auto s = EC_Scalar::deserialize(m_group, sig.last(order_bytes))) {
246 std::vector<uint8_t> r_xor_e(r.size());
247 xor_buf(r_xor_e, r, msg.first(size_r));
249 const auto w = EC_Scalar::from_bytes_mod_order(m_group, r_xor_e);
252 std::vector<uint8_t> v = m_hash->process<std::vector<uint8_t>>(q->x_bytes());
264 return std::make_unique<ECKCDSA_PrivateKey>(rng, domain());
268 std::string_view provider)
const {
269 if(provider ==
"base" || provider.empty()) {
270 return std::make_unique<ECKCDSA_Verification_Operation>(*
this, params);
277 if(provider ==
"base" || provider.empty()) {
278 return std::make_unique<ECKCDSA_Verification_Operation>(*
this, signature_algorithm);
285 std::string_view params,
286 std::string_view provider)
const {
287 if(provider ==
"base" || provider.empty()) {
288 return std::make_unique<ECKCDSA_Signature_Operation>(*
this, params);
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
std::optional< EC_AffinePoint > mul2_vartime(const EC_Scalar &x, const EC_Scalar &y) const
size_t get_order_bytes() const
bool check_key(RandomNumberGenerator &rng, bool strong) const override
const EC_Group & domain() const
const EC_AffinePoint & _public_ec_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)
bool constant_time_compare(std::span< const uint8_t > x, std::span< const uint8_t > y)