Coverage Report

Created: 2025-04-11 06:34

/src/botan/src/lib/pubkey/ecgdsa/ecgdsa.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* ECGDSA (BSI-TR-03111, version 2.0)
3
* (C) 2016 René Korthaus
4
* (C) 2018,2024 Jack Lloyd
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8
9
#include <botan/ecgdsa.h>
10
11
#include <botan/internal/keypair.h>
12
#include <botan/internal/pk_ops_impl.h>
13
14
namespace Botan {
15
16
0
std::unique_ptr<Public_Key> ECGDSA_PrivateKey::public_key() const {
17
0
   return std::make_unique<ECGDSA_PublicKey>(domain(), _public_ec_point());
18
0
}
19
20
0
bool ECGDSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const {
21
0
   if(!EC_PrivateKey::check_key(rng, strong)) {
22
0
      return false;
23
0
   }
24
25
0
   if(!strong) {
26
0
      return true;
27
0
   }
28
29
0
   return KeyPair::signature_consistency_check(rng, *this, "SHA-256");
30
0
}
31
32
namespace {
33
34
/**
35
* ECGDSA signature operation
36
*/
37
class ECGDSA_Signature_Operation final : public PK_Ops::Signature_with_Hash {
38
   public:
39
      ECGDSA_Signature_Operation(const ECGDSA_PrivateKey& ecgdsa, std::string_view emsa) :
40
0
            PK_Ops::Signature_with_Hash(emsa), m_group(ecgdsa.domain()), m_x(ecgdsa._private_key()) {}
41
42
      std::vector<uint8_t> raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) override;
43
44
0
      size_t signature_length() const override { return 2 * m_group.get_order_bytes(); }
45
46
      AlgorithmIdentifier algorithm_identifier() const override;
47
48
   private:
49
      const EC_Group m_group;
50
      const EC_Scalar m_x;
51
};
52
53
0
AlgorithmIdentifier ECGDSA_Signature_Operation::algorithm_identifier() const {
54
0
   const std::string full_name = "ECGDSA/" + hash_function();
55
0
   const OID oid = OID::from_string(full_name);
56
0
   return AlgorithmIdentifier(oid, AlgorithmIdentifier::USE_EMPTY_PARAM);
57
0
}
58
59
0
std::vector<uint8_t> ECGDSA_Signature_Operation::raw_sign(std::span<const uint8_t> msg, RandomNumberGenerator& rng) {
60
0
   const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
61
62
0
   const auto k = EC_Scalar::random(m_group, rng);
63
64
0
   const auto r = EC_Scalar::gk_x_mod_order(k, rng);
65
66
0
   const auto s = m_x * ((k * r) - m);
67
68
   // With overwhelming probability, a bug rather than actual zero r/s
69
0
   if(r.is_zero() || s.is_zero()) {
70
0
      throw Internal_Error("During ECGDSA signature generated zero r/s");
71
0
   }
72
73
0
   return EC_Scalar::serialize_pair(r, s);
74
0
}
75
76
/**
77
* ECGDSA verification operation
78
*/
79
class ECGDSA_Verification_Operation final : public PK_Ops::Verification_with_Hash {
80
   public:
81
      ECGDSA_Verification_Operation(const ECGDSA_PublicKey& ecgdsa, std::string_view padding) :
82
0
            PK_Ops::Verification_with_Hash(padding), m_group(ecgdsa.domain()), m_gy_mul(ecgdsa._public_ec_point()) {}
83
84
      ECGDSA_Verification_Operation(const ECGDSA_PublicKey& ecgdsa, const AlgorithmIdentifier& alg_id) :
85
0
            PK_Ops::Verification_with_Hash(alg_id, "ECGDSA"),
86
0
            m_group(ecgdsa.domain()),
87
0
            m_gy_mul(ecgdsa._public_ec_point()) {}
88
89
      bool verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) override;
90
91
   private:
92
      const EC_Group m_group;
93
      const EC_Group::Mul2Table m_gy_mul;
94
};
95
96
0
bool ECGDSA_Verification_Operation::verify(std::span<const uint8_t> msg, std::span<const uint8_t> sig) {
97
0
   if(auto rs = EC_Scalar::deserialize_pair(m_group, sig)) {
98
0
      const auto& [r, s] = rs.value();
99
100
0
      if(r.is_nonzero() && s.is_nonzero()) {
101
0
         const auto m = EC_Scalar::from_bytes_with_trunc(m_group, msg);
102
103
0
         const auto w = r.invert_vartime();
104
105
         // Check if r == x_coord(g*w*m + y*w*s) % n
106
0
         return m_gy_mul.mul2_vartime_x_mod_order_eq(r, w, m, s);
107
0
      }
108
0
   }
109
110
0
   return false;
111
0
}
112
113
}  // namespace
114
115
0
std::unique_ptr<Private_Key> ECGDSA_PublicKey::generate_another(RandomNumberGenerator& rng) const {
116
0
   return std::make_unique<ECGDSA_PrivateKey>(rng, domain());
117
0
}
118
119
std::unique_ptr<PK_Ops::Verification> ECGDSA_PublicKey::create_verification_op(std::string_view params,
120
0
                                                                               std::string_view provider) const {
121
0
   if(provider == "base" || provider.empty()) {
122
0
      return std::make_unique<ECGDSA_Verification_Operation>(*this, params);
123
0
   }
124
0
   throw Provider_Not_Found(algo_name(), provider);
125
0
}
126
127
std::unique_ptr<PK_Ops::Verification> ECGDSA_PublicKey::create_x509_verification_op(
128
0
   const AlgorithmIdentifier& signature_algorithm, std::string_view provider) const {
129
0
   if(provider == "base" || provider.empty()) {
130
0
      return std::make_unique<ECGDSA_Verification_Operation>(*this, signature_algorithm);
131
0
   }
132
133
0
   throw Provider_Not_Found(algo_name(), provider);
134
0
}
135
136
std::unique_ptr<PK_Ops::Signature> ECGDSA_PrivateKey::create_signature_op(RandomNumberGenerator& /*rng*/,
137
                                                                          std::string_view params,
138
0
                                                                          std::string_view provider) const {
139
0
   if(provider == "base" || provider.empty()) {
140
0
      return std::make_unique<ECGDSA_Signature_Operation>(*this, params);
141
0
   }
142
0
   throw Provider_Not_Found(algo_name(), provider);
143
0
}
144
145
}  // namespace Botan