Coverage Report

Created: 2025-04-11 06:34

/src/botan/src/lib/pubkey/ecc_key/ec_key_data.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* (C) 2024 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6
7
#include <botan/internal/ec_key_data.h>
8
9
#include <botan/mem_ops.h>
10
#include <botan/rng.h>
11
12
namespace Botan {
13
14
EC_PublicKey_Data::EC_PublicKey_Data(EC_Group group, EC_AffinePoint pt) :
15
22.6k
      m_group(std::move(group)), m_point(std::move(pt)) {
16
22.6k
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
17
22.6k
   m_legacy_point = m_point.to_legacy_point();
18
22.6k
#endif
19
20
   // Checking that the point lies on the curve is done in the deserialization
21
   // of EC_AffinePoint.
22
22.6k
   BOTAN_ARG_CHECK(!m_point.is_identity(), "ECC public key cannot be point at infinity");
23
22.6k
}
24
25
EC_PrivateKey_Data::EC_PrivateKey_Data(EC_Group group, EC_Scalar x) :
26
20.6k
      m_group(std::move(group)), m_scalar(std::move(x)), m_legacy_x(m_scalar.to_bigint()) {
27
   // Checking that the scalar is lower than the group order is ensured in the
28
   // deserialization of the EC_Scalar or during the random generation respectively.
29
20.6k
   BOTAN_ARG_CHECK(m_scalar.is_nonzero(), "ECC private key cannot be zero");
30
20.6k
}
31
32
namespace {
33
34
8.93k
EC_Scalar decode_ec_secret_key_scalar(const EC_Group& group, std::span<const uint8_t> bytes) {
35
8.93k
   const size_t order_bytes = group.get_order_bytes();
36
37
8.93k
   if(bytes.size() < order_bytes) {
38
      /*
39
      * Older versions had a bug which caused secret keys to not be encoded to
40
      * the full byte length of the order if there were leading zero bytes. This
41
      * was particularly a problem for P-521, where on average half of keys do
42
      * not have their high bit set and so can be encoded in 65 bytes, vs 66
43
      * bytes for the full order.
44
      *
45
      * To accomodate this, zero prefix the key if we see such a short input
46
      */
47
966
      secure_vector<uint8_t> padded_sk(order_bytes);
48
966
      copy_mem(std::span{padded_sk}.last(bytes.size()), bytes);
49
966
      return decode_ec_secret_key_scalar(group, padded_sk);
50
966
   }
51
52
7.96k
   if(auto s = EC_Scalar::deserialize(group, bytes)) {
53
7.88k
      return s.value();
54
7.88k
   } else {
55
80
      throw Decoding_Error("EC private key is invalid for this group");
56
80
   }
57
7.96k
}
58
59
}  // namespace
60
61
EC_PrivateKey_Data::EC_PrivateKey_Data(const EC_Group& group, std::span<const uint8_t> bytes) :
62
7.96k
      Botan::EC_PrivateKey_Data(group, decode_ec_secret_key_scalar(group, bytes)) {}
63
64
std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(RandomNumberGenerator& rng,
65
12.9k
                                                                  bool with_modular_inverse) const {
66
12.9k
   auto public_point = [&] {
67
12.9k
      if(with_modular_inverse) {
68
0
         return EC_AffinePoint::g_mul(m_scalar.invert(), rng);
69
12.9k
      } else {
70
12.9k
         return EC_AffinePoint::g_mul(m_scalar, rng);
71
12.9k
      }
72
12.9k
   };
73
74
12.9k
   return std::make_shared<EC_PublicKey_Data>(m_group, public_point());
75
12.9k
}
76
77
152
std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(bool with_modular_inverse) const {
78
152
   Null_RNG null_rng;
79
152
   return this->public_key(null_rng, with_modular_inverse);
80
152
}
81
82
0
void EC_PrivateKey_Data::serialize_to(std::span<uint8_t> output) const {
83
0
   m_scalar.serialize_to(output);
84
0
}
85
86
}  // namespace Botan