• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 29471089948

15 Jul 2026 11:28PM UTC coverage: 89.402% (-2.3%) from 91.656%
29471089948

push

github

web-flow
Merge pull request #5724 from randombit/jack/filter-fixes

Fix various bugs in the Pipe/Filter library

113560 of 127022 relevant lines covered (89.4%)

10935343.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.96
/src/lib/pubkey/ecc_key/ec_key_data.cpp
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/exceptn.h>
10
#include <botan/mem_ops.h>
11
#include <botan/rng.h>
12

13
namespace Botan {
14

15
namespace {
16

17
EC_AffinePoint decode_ec_public_key_point(const EC_Group& group, std::span<const uint8_t> bytes) {
7,733✔
18
   /*
19
   * RFC 5480 section 2.2:
20
   *    The first octet of the OCTET STRING indicates whether the key is
21
   *    compressed or uncompressed.  The uncompressed form is indicated
22
   *    by 0x04 and the compressed form is indicated by either 0x02 or
23
   *    0x03 (see 2.3.3 in [SEC1]).  The public key MUST be rejected if
24
   *    any other value is included in the first octet.
25
   */
26
   if(auto pt_uncompressed = EC_AffinePoint::deserialize_uncompressed(group, bytes)) {
7,733✔
27
      return std::move(pt_uncompressed).value();
7,721✔
28
   } else if(auto pt_compressed = EC_AffinePoint::deserialize_compressed(group, bytes)) {
12✔
29
      return std::move(pt_compressed).value();
×
30
   } else {
31
      throw Decoding_Error("Failed to deserialize elliptic curve point");
12✔
32
   }
7,733✔
33
}
34

35
}  // namespace
36

37
EC_PublicKey_Data::EC_PublicKey_Data(const EC_Group& group, std::span<const uint8_t> bytes) :
7,733✔
38
      EC_PublicKey_Data(group, decode_ec_public_key_point(group, bytes)) {}
7,733✔
39

40
EC_PublicKey_Data::EC_PublicKey_Data(EC_Group group, EC_AffinePoint pt) :
27,705✔
41
      m_group(std::move(group)), m_point(std::move(pt)) {
27,705✔
42
#if defined(BOTAN_HAS_LEGACY_EC_POINT)
43
   m_legacy_point = m_point.to_legacy_point();
55,410✔
44
#endif
45

46
   // Checking that the point lies on the curve is done in the deserialization
47
   // of EC_AffinePoint.
48
   BOTAN_ARG_CHECK(!m_point.is_identity(), "ECC public key cannot be point at infinity");
27,705✔
49
}
27,761✔
50

51
EC_PrivateKey_Data::EC_PrivateKey_Data(EC_Group group, EC_Scalar x) :
8,750✔
52
      m_group(std::move(group)), m_scalar(std::move(x)), m_legacy_x(m_scalar.to_bigint()) {
8,750✔
53
   // Checking that the scalar is lower than the group order is ensured in the
54
   // deserialization of the EC_Scalar or during the random generation respectively.
55
   BOTAN_ARG_CHECK(m_scalar.is_nonzero(), "ECC private key cannot be zero");
8,750✔
56
}
8,806✔
57

58
namespace {
59

60
EC_Scalar decode_ec_secret_key_scalar(const EC_Group& group, std::span<const uint8_t> bytes) {
1,712✔
61
   const size_t order_bytes = group.get_order_bytes();
1,712✔
62

63
   if(bytes.size() < order_bytes) {
1,712✔
64
      /*
65
      * Older versions had a bug which caused secret keys to not be encoded to
66
      * the full byte length of the order if there were leading zero bytes. This
67
      * was particularly a problem for P-521, where on average half of keys do
68
      * not have their high bit set and so can be encoded in 65 bytes, vs 66
69
      * bytes for the full order.
70
      *
71
      * To accommodate this, zero prefix the key if we see such a short input
72
      */
73
      secure_vector<uint8_t> padded_sk(order_bytes);
13✔
74
      copy_mem(std::span{padded_sk}.last(bytes.size()), bytes);
13✔
75
      return decode_ec_secret_key_scalar(group, padded_sk);
13✔
76
   }
13✔
77

78
   if(auto s = EC_Scalar::deserialize(group, bytes)) {
1,699✔
79
      return s.value();
1,695✔
80
   } else {
81
      throw Decoding_Error("EC private key is invalid for this group");
4✔
82
   }
1,695✔
83
}
13✔
84

85
}  // namespace
86

87
EC_PrivateKey_Data::EC_PrivateKey_Data(const EC_Group& group, std::span<const uint8_t> bytes) :
1,699✔
88
      Botan::EC_PrivateKey_Data(group, decode_ec_secret_key_scalar(group, bytes)) {}
1,699✔
89

90
EC_PrivateKey_Data::~EC_PrivateKey_Data() {
8,722✔
91
   m_scalar.zeroize();
8,722✔
92
}
8,722✔
93

94
std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(RandomNumberGenerator& rng,
7,137✔
95
                                                                  bool with_modular_inverse) const {
96
   auto public_point = [&] {
14,274✔
97
      if(with_modular_inverse) {
7,137✔
98
         return EC_AffinePoint::g_mul(m_scalar.invert(), rng);
151✔
99
      } else {
100
         return EC_AffinePoint::g_mul(m_scalar, rng);
6,986✔
101
      }
102
   };
7,137✔
103

104
   return std::make_shared<EC_PublicKey_Data>(m_group, public_point());
7,137✔
105
}
106

107
std::shared_ptr<EC_PublicKey_Data> EC_PrivateKey_Data::public_key(bool with_modular_inverse) const {
152✔
108
   Null_RNG null_rng;
152✔
109
   return this->public_key(null_rng, with_modular_inverse);
152✔
110
}
152✔
111

112
void EC_PrivateKey_Data::serialize_to(std::span<uint8_t> output) const {
775✔
113
   m_scalar.serialize_to(output);
775✔
114
}
775✔
115

116
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc