Coverage Report

Created: 2026-06-15 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rnp/src/lib/crypto/exdsa_ecdhkem.cpp
Line
Count
Source
1
/*
2
 * Copyright (c) 2023, [MTG AG](https://www.mtg.de).
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without modification,
6
 * are permitted provided that the following conditions are met:
7
 *
8
 * 1.  Redistributions of source code must retain the above copyright notice,
9
 *     this list of conditions and the following disclaimer.
10
 *
11
 * 2.  Redistributions in binary form must reproduce the above copyright notice,
12
 *     this list of conditions and the following disclaimer in the documentation
13
 *     and/or other materials provided with the distribution.
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
19
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
 */
26
27
#include "exdsa_ecdhkem.h"
28
#include "ecdh.h"
29
#include "ed25519.h"
30
#include "ecdsa.h"
31
#include "ec.h"
32
#include "types.h"
33
#include "logging.h"
34
#include "string.h"
35
#include "utils.h"
36
#include <cassert>
37
38
ec_key_t::~ec_key_t()
39
71.9k
{
40
71.9k
}
41
42
17.1k
ec_key_t::ec_key_t(pgp_curve_t curve) : curve_(curve)
43
17.1k
{
44
17.1k
}
45
46
ecdh_kem_public_key_t::ecdh_kem_public_key_t(uint8_t *   key_buf,
47
                                             size_t      key_buf_len,
48
                                             pgp_curve_t curve)
49
7.76k
    : ec_key_t(curve), key_(std::vector<uint8_t>(key_buf, key_buf + key_buf_len))
50
7.76k
{
51
7.76k
}
52
ecdh_kem_public_key_t::ecdh_kem_public_key_t(std::vector<uint8_t> key, pgp_curve_t curve)
53
0
    : ec_key_t(curve), key_(key)
54
0
{
55
0
}
56
57
ecdh_kem_private_key_t::ecdh_kem_private_key_t(uint8_t *   key_buf,
58
                                               size_t      key_buf_len,
59
                                               pgp_curve_t curve)
60
600
    : ec_key_t(curve), key_(key_buf, key_buf + key_buf_len)
61
600
{
62
600
}
63
ecdh_kem_private_key_t::ecdh_kem_private_key_t(std::vector<uint8_t> key, pgp_curve_t curve)
64
1.98k
    : ec_key_t(curve), key_(Botan::secure_vector<uint8_t>(key.begin(), key.end()))
65
1.98k
{
66
1.98k
}
67
68
Botan::ECDH_PrivateKey
69
ecdh_kem_private_key_t::botan_key_ecdh(rnp::RNG *rng) const
70
0
{
71
0
    assert(curve_ >= PGP_CURVE_NIST_P_256 && curve_ <= PGP_CURVE_P256K1);
72
0
    auto ec_desc = pgp::ec::Curve::get(curve_);
73
0
    return Botan::ECDH_PrivateKey(
74
0
      *(rng->obj()), Botan::EC_Group(ec_desc->botan_name), Botan::BigInt(key_));
75
0
}
76
77
Botan::ECDH_PublicKey
78
ecdh_kem_public_key_t::botan_key_ecdh(rnp::RNG *rng) const
79
0
{
80
0
    assert(curve_ >= PGP_CURVE_NIST_P_256 && curve_ <= PGP_CURVE_P256K1);
81
82
0
    auto            ec_desc = pgp::ec::Curve::get(curve_);
83
0
    Botan::EC_Group group(ec_desc->botan_name);
84
0
    const size_t    curve_order = ec_desc->bytes();
85
0
    Botan::BigInt   x(key_.data() + 1, curve_order);
86
0
    Botan::BigInt   y(key_.data() + 1 + curve_order, curve_order);
87
0
    return Botan::ECDH_PublicKey(group, group.point(x, y));
88
0
}
89
90
Botan::Curve25519_PrivateKey
91
ecdh_kem_private_key_t::botan_key_x25519() const
92
0
{
93
0
    assert(curve_ == PGP_CURVE_25519);
94
0
    return Botan::Curve25519_PrivateKey(key_);
95
0
}
96
97
Botan::Curve25519_PublicKey
98
ecdh_kem_public_key_t::botan_key_x25519() const
99
0
{
100
0
    assert(curve_ == PGP_CURVE_25519);
101
0
    return Botan::Curve25519_PublicKey(key_);
102
0
}
103
104
std::vector<uint8_t>
105
ecdh_kem_private_key_t::get_pubkey_encoded(rnp::RNG *rng) const
106
0
{
107
0
    if (curve_ == PGP_CURVE_25519) {
108
0
        Botan::X25519_PrivateKey botan_key = botan_key_x25519();
109
0
        return botan_key.public_value();
110
0
    } else {
111
0
        Botan::ECDH_PrivateKey botan_key = botan_key_ecdh(rng);
112
0
        return botan_key.public_value();
113
0
    }
114
0
}
115
116
rnp_result_t
117
ecdh_kem_public_key_t::encapsulate(rnp::RNG *            rng,
118
                                   std::vector<uint8_t> &ciphertext,
119
                                   std::vector<uint8_t> &symmetric_key) const
120
0
{
121
0
    if (curve_ == PGP_CURVE_25519) {
122
0
        Botan::Curve25519_PrivateKey eph_prv_key(*(rng->obj()));
123
0
        ciphertext = eph_prv_key.public_value();
124
0
        Botan::PK_Key_Agreement key_agreement(eph_prv_key, *(rng->obj()), "Raw");
125
0
        symmetric_key = Botan::unlock(key_agreement.derive_key(0, key_).bits_of());
126
0
    } else {
127
0
        auto curve_desc = pgp::ec::Curve::get(curve_);
128
0
        if (!curve_desc) {
129
0
            RNP_LOG("unknown curve");
130
0
            return RNP_ERROR_NOT_SUPPORTED;
131
0
        }
132
133
0
        Botan::EC_Group         domain(curve_desc->botan_name);
134
0
        Botan::ECDH_PrivateKey  eph_prv_key(*(rng->obj()), domain);
135
0
        Botan::PK_Key_Agreement key_agreement(eph_prv_key, *(rng->obj()), "Raw");
136
0
        ciphertext = eph_prv_key.public_value();
137
0
        symmetric_key = Botan::unlock(key_agreement.derive_key(0, key_).bits_of());
138
0
    }
139
0
    return RNP_SUCCESS;
140
0
}
141
142
rnp_result_t
143
ecdh_kem_private_key_t::decapsulate(rnp::RNG *                  rng,
144
                                    const std::vector<uint8_t> &ciphertext,
145
                                    std::vector<uint8_t> &      plaintext)
146
0
{
147
0
    if (curve_ == PGP_CURVE_25519) {
148
0
        Botan::Curve25519_PrivateKey priv_key = botan_key_x25519();
149
0
        Botan::PK_Key_Agreement      key_agreement(priv_key, *(rng->obj()), "Raw");
150
0
        plaintext = Botan::unlock(key_agreement.derive_key(0, ciphertext).bits_of());
151
0
    } else {
152
0
        Botan::ECDH_PrivateKey  priv_key = botan_key_ecdh(rng);
153
0
        Botan::PK_Key_Agreement key_agreement(priv_key, *(rng->obj()), "Raw");
154
0
        plaintext = Botan::unlock(key_agreement.derive_key(0, ciphertext).bits_of());
155
0
    }
156
0
    return RNP_SUCCESS;
157
0
}
158
159
rnp_result_t
160
ec_key_t::generate_ecdh_kem_key_pair(rnp::RNG *rng, ecdh_kem_key_t *out, pgp_curve_t curve)
161
0
{
162
0
    std::vector<uint8_t> pub, priv;
163
0
    rnp_result_t         result = ecdh_kem_gen_keypair_native(rng, priv, pub, curve);
164
0
    if (result != RNP_SUCCESS) {
165
0
        RNP_LOG("error when generating EC key pair");
166
0
        return result;
167
0
    }
168
169
0
    out->priv = ecdh_kem_private_key_t(priv, curve);
170
0
    out->pub = ecdh_kem_public_key_t(pub, curve);
171
172
0
    return RNP_SUCCESS;
173
0
}
174
175
exdsa_public_key_t::exdsa_public_key_t(uint8_t *key_buf, size_t key_buf_len, pgp_curve_t curve)
176
6.77k
    : ec_key_t(curve), key_(key_buf, key_buf + key_buf_len)
177
6.77k
{
178
6.77k
}
179
exdsa_public_key_t::exdsa_public_key_t(std::vector<uint8_t> key, pgp_curve_t curve)
180
0
    : ec_key_t(curve), key_(key)
181
0
{
182
0
}
183
184
exdsa_private_key_t::exdsa_private_key_t(uint8_t *   key_buf,
185
                                         size_t      key_buf_len,
186
                                         pgp_curve_t curve)
187
14
    : ec_key_t(curve), key_(key_buf, key_buf + key_buf_len)
188
14
{
189
14
}
190
exdsa_private_key_t::exdsa_private_key_t(std::vector<uint8_t> key, pgp_curve_t curve)
191
14
    : ec_key_t(curve), key_(Botan::secure_vector<uint8_t>(key.begin(), key.end()))
192
14
{
193
14
}
194
195
rnp_result_t
196
ec_key_t::generate_exdsa_key_pair(rnp::RNG *rng, exdsa_key_t *out, pgp_curve_t curve)
197
0
{
198
0
    std::vector<uint8_t> pub, priv;
199
0
    rnp_result_t         result = exdsa_gen_keypair_native(rng, priv, pub, curve);
200
0
    if (result != RNP_SUCCESS) {
201
0
        RNP_LOG("error when generating EC key pair");
202
0
        return result;
203
0
    }
204
205
0
    out->priv = exdsa_private_key_t(priv, curve);
206
0
    out->pub = exdsa_public_key_t(pub, curve);
207
208
0
    return RNP_SUCCESS;
209
0
}
210
211
Botan::ECDSA_PrivateKey
212
exdsa_private_key_t::botan_key(rnp::RNG *rng) const
213
0
{
214
0
    auto                    ec_desc = pgp::ec::Curve::get(curve_);
215
0
    Botan::ECDSA_PrivateKey priv_key(
216
0
      *(rng->obj()), Botan::EC_Group(ec_desc->botan_name), Botan::BigInt(key_));
217
0
    return priv_key;
218
0
}
219
220
Botan::ECDSA_PublicKey
221
exdsa_public_key_t::botan_key() const
222
0
{
223
    // format: 04 | X | Y
224
0
    auto            ec_desc = pgp::ec::Curve::get(curve_);
225
0
    Botan::EC_Group group(ec_desc->botan_name);
226
0
    const size_t    curve_order = ec_desc->bytes();
227
0
    Botan::BigInt   x(key_.data() + 1, curve_order);
228
0
    Botan::BigInt   y(key_.data() + 1 + curve_order, curve_order);
229
0
    return Botan::ECDSA_PublicKey(group, group.point(x, y));
230
0
}
231
232
/* NOTE hash_alg unused for ed25519/x25519 curves */
233
rnp_result_t
234
exdsa_private_key_t::sign(rnp::RNG *            rng,
235
                          std::vector<uint8_t> &sig_out,
236
                          const uint8_t *       hash,
237
                          size_t                hash_len,
238
                          pgp_hash_alg_t        hash_alg) const
239
0
{
240
0
    if (curve_ == PGP_CURVE_ED25519) {
241
0
        return ed25519_sign_native(rng, sig_out, Botan::unlock(key_), hash, hash_len);
242
0
    } else {
243
0
        Botan::ECDSA_PrivateKey priv_key = botan_key(rng);
244
0
        auto                    signer =
245
0
          Botan::PK_Signer(priv_key, *(rng->obj()), pgp::ecdsa::padding_str_for(hash_alg));
246
0
        sig_out = signer.sign_message(hash, hash_len, *(rng->obj()));
247
0
    }
248
0
    return RNP_SUCCESS;
249
0
}
250
251
rnp_result_t
252
exdsa_public_key_t::verify(const std::vector<uint8_t> &sig,
253
                           const uint8_t *             hash,
254
                           size_t                      hash_len,
255
                           pgp_hash_alg_t              hash_alg) const
256
0
{
257
0
    if (curve_ == PGP_CURVE_ED25519) {
258
0
        return ed25519_verify_native(sig, key_, hash, hash_len);
259
0
    } else {
260
0
        Botan::ECDSA_PublicKey pub_key = botan_key();
261
0
        auto verifier = Botan::PK_Verifier(pub_key, pgp::ecdsa::padding_str_for(hash_alg));
262
0
        if (verifier.verify_message(hash, hash_len, sig.data(), sig.size())) {
263
0
            return RNP_SUCCESS;
264
0
        }
265
0
    }
266
0
    return RNP_ERROR_VERIFICATION_FAILED;
267
0
}
268
269
bool
270
exdsa_public_key_t::is_valid(rnp::RNG *rng) const
271
0
{
272
0
    if (curve_ == PGP_CURVE_ED25519) {
273
0
        Botan::Ed25519_PublicKey pub_key(key_);
274
0
        return pub_key.check_key(*(rng->obj()), false);
275
0
    } else {
276
0
        Botan::ECDSA_PublicKey pub_key = botan_key();
277
0
        return pub_key.check_key(*(rng->obj()), false);
278
0
    }
279
0
}
280
281
bool
282
exdsa_private_key_t::is_valid(rnp::RNG *rng) const
283
0
{
284
0
    if (curve_ == PGP_CURVE_ED25519) {
285
0
        Botan::Ed25519_PrivateKey priv_key(key_);
286
0
        return priv_key.check_key(*(rng->obj()), false);
287
0
    } else {
288
0
        auto priv_key = botan_key(rng);
289
0
        return priv_key.check_key(*(rng->obj()), false);
290
0
    }
291
0
}
292
293
bool
294
ecdh_kem_public_key_t::is_valid(rnp::RNG *rng) const
295
0
{
296
0
    if (curve_ == PGP_CURVE_25519) {
297
0
        auto pub_key = botan_key_x25519();
298
0
        return pub_key.check_key(*(rng->obj()), false);
299
0
    } else {
300
0
        auto pub_key = botan_key_ecdh(rng);
301
0
        return pub_key.check_key(*(rng->obj()), false);
302
0
    }
303
0
}
304
305
bool
306
ecdh_kem_private_key_t::is_valid(rnp::RNG *rng) const
307
0
{
308
0
    if (curve_ == PGP_CURVE_25519) {
309
0
        auto priv_key = botan_key_x25519();
310
0
        return priv_key.check_key(*(rng->obj()), false);
311
0
    } else {
312
0
        auto priv_key = botan_key_ecdh(rng);
313
0
        return priv_key.check_key(*(rng->obj()), false);
314
0
    }
315
0
}