Coverage Report

Created: 2022-08-24 06:26

/src/cryptofuzz-sp-math/modules/botan/module.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "module.h"
2
#include <cryptofuzz/util.h>
3
#include <cryptofuzz/repository.h>
4
#include <botan/aead.h>
5
#include <botan/ber_dec.h>
6
#include <botan/bigint.h>
7
#include <botan/cipher_mode.h>
8
#include <botan/curve25519.h>
9
#include <botan/dh.h>
10
#include <botan/ecdsa.h>
11
#include <botan/ecgdsa.h>
12
#include <botan/ed25519.h>
13
#include <botan/hash.h>
14
#include <botan/kdf.h>
15
#include <botan/mac.h>
16
#include <botan/pbkdf.h>
17
#include <botan/pubkey.h>
18
#include <botan/pwdhash.h>
19
#include <botan/system_rng.h>
20
#include "bn_ops.h"
21
22
namespace cryptofuzz {
23
namespace module {
24
25
Botan::Botan(void) :
26
2
    Module("Botan") {
27
2
    if ( setenv("BOTAN_MLOCK_POOL_SIZE", "0", 1) != 0 ) {
28
0
        abort();
29
0
    }
30
2
}
31
32
#if !defined(CRYPTOFUZZ_BOTAN_IS_ORACLE)
33
 #define BOTAN_FUZZER_RNG Botan_detail::Fuzzer_RNG rng(ds);
34
#else
35
6.92k
 #define BOTAN_FUZZER_RNG ::Botan::System_RNG rng;
36
#endif /* CRYPTOFUZZ_BOTAN_IS_ORACLE */
37
38
#if !defined(CRYPTOFUZZ_BOTAN_IS_ORACLE)
39
 #define BOTAN_SET_GLOBAL_DS CF_NORET(util::SetGlobalDs(&ds));
40
 #define BOTAN_UNSET_GLOBAL_DS CF_NORET(util::UnsetGlobalDs());
41
#else
42
 #define BOTAN_SET_GLOBAL_DS
43
 #define BOTAN_UNSET_GLOBAL_DS
44
#endif
45
46
namespace Botan_detail {
47
48
#if !defined(CRYPTOFUZZ_BOTAN_IS_ORACLE)
49
    class Fuzzer_RNG final : public ::Botan::RandomNumberGenerator {
50
        private:
51
            Datasource& ds;
52
        public:
53
            Fuzzer_RNG(Datasource& ds) :
54
                ds(ds)
55
            { }
56
57
            bool is_seeded() const override { return true; }
58
59
            bool accepts_input() const override { return false; }
60
61
            void clear() override {}
62
63
            virtual void randomize(uint8_t output[], size_t length) override {
64
                if ( length == 0 ) {
65
                    return;
66
                }
67
68
                const auto data = ds.GetData(0, length, length);
69
70
                memcpy(output, data.data(), length);
71
            }
72
73
            void add_entropy(const uint8_t[], size_t) override {
74
            }
75
76
            std::string name() const override { return "Fuzzer_RNG"; }
77
    };
78
#endif /* CRYPTOFUZZ_BOTAN_IS_ORACLE */
79
80
0
    const std::string parenthesize(const std::string parent, const std::string child) {
81
0
        static const std::string pOpen("(");
82
0
        static const std::string pClose(")");
83
84
0
        return parent + pOpen + child + pClose;
85
0
    }
86
87
0
    std::optional<std::string> DigestIDToString(const uint64_t digestType, const bool altShake = false, const bool isHmac = false) {
88
0
#include "digest_string_lut.h"
89
0
        std::optional<std::string> ret = std::nullopt;
90
91
0
        CF_CHECK_NE(LUT.find(digestType), LUT.end());
92
93
0
        if ( isHmac == false ) {
94
0
            if (    digestType == CF_DIGEST("SIPHASH64") ||
95
0
                    digestType == CF_DIGEST("SIPHASH128") ) {
96
0
                return std::nullopt;
97
0
            }
98
0
        }
99
0
        if ( altShake == true && digestType == CF_DIGEST("SHAKE128") ) {
100
0
            ret = "SHAKE-128(256)";
101
0
        } else if ( altShake == true && digestType == CF_DIGEST("SHAKE256") ) {
102
0
            ret = "SHAKE-256(512)";
103
0
        } else if ( altShake == true && digestType == CF_DIGEST("SHAKE256_114") ) {
104
0
            ret = "SHAKE-256(912)"; /* 114 bytes * 8 = 912 bits */
105
0
        } else {
106
0
            ret = LUT.at(digestType);
107
0
        }
108
0
end:
109
0
        return ret;
110
0
    }
111
112
} /* namespace Botan_detail */
113
114
0
std::optional<component::Digest> Botan::OpDigest(operation::Digest& op) {
115
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
116
0
    std::optional<component::Digest> ret = std::nullopt;
117
0
    std::unique_ptr<::Botan::HashFunction> hash = nullptr;
118
0
    util::Multipart parts;
119
0
    size_t numClears = 0;
120
121
    /* Initialize */
122
0
    {
123
0
        BOTAN_SET_GLOBAL_DS
124
125
0
        std::optional<std::string> algoString;
126
0
        CF_CHECK_NE(algoString = Botan_detail::DigestIDToString(op.digestType.Get()), std::nullopt);
127
0
        CF_CHECK_NE(hash = ::Botan::HashFunction::create(*algoString), nullptr);
128
129
0
        parts = util::ToParts(ds, op.cleartext);
130
0
    }
131
132
0
again:
133
    /* Process */
134
0
    for (const auto& part : parts) {
135
0
        hash->update(part.first, part.second);
136
0
        bool clear = false;
137
138
0
        if ( numClears < 3 ) {
139
0
            try {
140
#if !defined(CRYPTOFUZZ_BOTAN_IS_ORACLE)
141
                clear = ds.Get<bool>();
142
#endif /* CRYPTOFUZZ_BOTAN_IS_ORACLE */
143
0
            } catch ( ... ) { }
144
0
        }
145
146
0
        if ( clear == true ) {
147
0
            hash->clear();
148
0
            numClears++;
149
0
            goto again;
150
0
        }
151
0
    }
152
153
    /* Finalize */
154
0
    {
155
0
        const auto res = hash->final();
156
0
        ret = component::Digest(res.data(), res.size());
157
0
    }
158
159
0
end:
160
0
    BOTAN_UNSET_GLOBAL_DS
161
162
0
    return ret;
163
0
}
164
165
0
std::optional<component::MAC> Botan::OpHMAC(operation::HMAC& op) {
166
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
167
0
    std::optional<component::MAC> ret = std::nullopt;
168
0
    std::unique_ptr<::Botan::MessageAuthenticationCode> hmac = nullptr;
169
0
    util::Multipart parts;
170
171
0
    try {
172
        /* Initialize */
173
0
        {
174
0
            BOTAN_SET_GLOBAL_DS
175
176
0
            std::optional<std::string> algoString;
177
0
            CF_CHECK_NE(algoString = Botan_detail::DigestIDToString(op.digestType.Get(), true, true), std::nullopt);
178
179
0
            std::string hmacString;
180
0
            if (
181
0
                    op.digestType.Is(CF_DIGEST("SIPHASH64")) ||
182
0
                    op.digestType.Is(CF_DIGEST("BLAKE2B_MAC")) ) {
183
0
                hmacString = *algoString;
184
0
            } else {
185
0
                hmacString = Botan_detail::parenthesize("HMAC", *algoString);
186
0
            }
187
188
0
            CF_CHECK_NE(hmac = ::Botan::MessageAuthenticationCode::create(hmacString), nullptr);
189
190
0
            try {
191
0
                hmac->set_key(op.cipher.key.GetPtr(), op.cipher.key.GetSize());
192
0
            } catch ( ... ) {
193
0
                goto end;
194
0
            }
195
196
0
            parts = util::ToParts(ds, op.cleartext);
197
0
        }
198
199
        /* Process */
200
0
        for (const auto& part : parts) {
201
0
            hmac->update(part.first, part.second);
202
0
        }
203
204
        /* Finalize */
205
0
        {
206
0
            const auto res = hmac->final();
207
0
            ret = component::MAC(res.data(), res.size());
208
0
        }
209
210
0
    } catch ( ... ) { }
211
212
0
end:
213
0
    BOTAN_UNSET_GLOBAL_DS
214
215
0
    return ret;
216
0
}
217
218
namespace Botan_detail {
219
220
0
    std::optional<std::string> CipherIDToString(const uint64_t digestType, const bool withMode = true) {
221
0
#include "cipher_string_lut.h"
222
0
        std::optional<std::string> ret = std::nullopt;
223
224
0
        CF_CHECK_NE(LUT.find(digestType), LUT.end());
225
0
        ret = withMode ? LUT.at(digestType).first : LUT.at(digestType).second;
226
0
end:
227
0
        return ret;
228
0
    }
229
230
    template <class OperationType>
231
    const uint8_t* GetInPtr(const OperationType& op);
232
233
    template <>
234
0
    const uint8_t* GetInPtr(const operation::SymmetricEncrypt& op) {
235
0
        return op.cleartext.GetPtr();
236
0
    }
237
238
    template <>
239
0
    const uint8_t* GetInPtr(const operation::SymmetricDecrypt& op) {
240
0
        return op.ciphertext.GetPtr();
241
0
    }
242
243
    template <class OperationType>
244
    size_t GetInSize(const OperationType& op);
245
246
    template <>
247
0
    size_t GetInSize(const operation::SymmetricEncrypt& op) {
248
0
        return op.cleartext.GetSize();
249
0
    }
250
251
    template <>
252
0
    size_t GetInSize(const operation::SymmetricDecrypt& op) {
253
0
        return op.ciphertext.GetSize();
254
0
    }
255
256
    template <class OperationType>
257
    ::Botan::Cipher_Dir GetCryptType(void);
258
259
    template <>
260
0
    ::Botan::Cipher_Dir GetCryptType<operation::SymmetricEncrypt>(void) {
261
0
        return ::Botan::ENCRYPTION;
262
0
    }
263
264
    template <>
265
0
    ::Botan::Cipher_Dir GetCryptType<operation::SymmetricDecrypt>(void) {
266
0
        return ::Botan::DECRYPTION;
267
0
    }
268
269
    template <class OperationType>
270
    std::optional<size_t> GetTagSize(const OperationType& op);
271
272
    template <>
273
0
    std::optional<size_t> GetTagSize<>(const operation::SymmetricEncrypt& op) {
274
0
        if ( op.tagSize == std::nullopt ) {
275
0
            return std::nullopt;
276
0
        }
277
278
0
        return *op.tagSize;
279
0
    }
280
281
    template <>
282
0
    std::optional<size_t> GetTagSize<>(const operation::SymmetricDecrypt& op) {
283
0
        if ( op.tag == std::nullopt ) {
284
0
            return std::nullopt;
285
0
        }
286
287
0
        return op.tag->GetSize();
288
0
    }
289
290
    template <class OperationType>
291
    const uint8_t* GetTagPtr(const OperationType& op);
292
293
    template <>
294
0
    const uint8_t* GetTagPtr<>(const operation::SymmetricEncrypt& op) {
295
0
        (void)op;
296
297
0
        return nullptr;
298
0
    }
299
300
    template <>
301
0
    const uint8_t* GetTagPtr<>(const operation::SymmetricDecrypt& op) {
302
0
        if ( op.tag == std::nullopt ) {
303
0
            return nullptr;
304
0
        }
305
306
0
        return op.tag->GetPtr();
307
0
    }
308
309
    template <class CryptClass>
310
    void SetAAD(std::shared_ptr<CryptClass> crypt, const std::optional<component::AAD>& aad);
311
312
    template <>
313
0
    void SetAAD<>(std::shared_ptr<::Botan::AEAD_Mode> crypt, const std::optional<component::AAD>& aad) {
314
0
        if ( aad != std::nullopt ) {
315
0
            crypt->set_ad(aad->Get());
316
0
        }
317
0
    }
318
319
    template <>
320
0
    void SetAAD<>(std::shared_ptr<::Botan::Cipher_Mode> crypt, const std::optional<component::AAD>& aad) {
321
0
        (void)crypt;
322
0
        (void)aad;
323
0
    }
324
325
    template <class OperationType>
326
0
    ::Botan::secure_vector<uint8_t> GetInData(const OperationType& op) {
327
0
        const auto inPtr = GetInPtr(op);
328
0
        ::Botan::secure_vector<uint8_t> ret(inPtr, inPtr + GetInSize(op));
329
330
0
        if ( GetCryptType<OperationType>() == ::Botan::ENCRYPTION ) {
331
0
            return ret;
332
0
        }
333
334
0
        const auto tagSize = GetTagSize(op);
335
336
0
        if ( tagSize == std::nullopt || *tagSize == 0 ) {
337
0
            return ret;
338
0
        }
339
340
        /* Append the tag */
341
342
0
        ret.resize(ret.size() + *tagSize);
343
344
0
        memcpy(ret.data() + GetInSize(op), GetTagPtr(op), *tagSize);
345
346
0
        return ret;
347
0
    }
Unexecuted instantiation: std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> > cryptofuzz::module::Botan_detail::GetInData<cryptofuzz::operation::SymmetricEncrypt>(cryptofuzz::operation::SymmetricEncrypt const&)
Unexecuted instantiation: std::__1::vector<unsigned char, Botan::secure_allocator<unsigned char> > cryptofuzz::module::Botan_detail::GetInData<cryptofuzz::operation::SymmetricDecrypt>(cryptofuzz::operation::SymmetricDecrypt const&)
348
349
    template <class ReturnType>
350
    ReturnType ToReturnType(const ::Botan::secure_vector<uint8_t>& data, std::optional<size_t> tagSize);
351
352
    template <>
353
0
    component::Ciphertext ToReturnType(const ::Botan::secure_vector<uint8_t>& data, std::optional<size_t> tagSize) {
354
0
        if ( tagSize == std::nullopt ) {
355
0
            return component::Ciphertext(Buffer(data.data(), data.size()));
356
0
        }
357
358
0
        const size_t ciphertextSize = data.size() - *tagSize;
359
360
0
        return component::Ciphertext(Buffer(data.data(), ciphertextSize), Buffer(data.data() + ciphertextSize, *tagSize));
361
0
    }
362
363
    template <>
364
0
    component::Cleartext ToReturnType(const ::Botan::secure_vector<uint8_t>& data, std::optional<size_t> tagSize) {
365
0
        (void)tagSize;
366
367
0
        return component::Cleartext(Buffer(data.data(), data.size()));
368
0
    }
369
370
    template <class ReturnType, class OperationType, class CryptClass>
371
0
        std::optional<ReturnType> Crypt(OperationType& op, Datasource& ds) {
372
0
            std::optional<ReturnType> ret = std::nullopt;
373
374
0
            if ( typeid(CryptClass) == typeid(::Botan::Cipher_Mode) ) {
375
0
                if ( op.aad != std::nullopt ) {
376
0
                    return std::nullopt;
377
0
                }
378
0
                if ( GetTagSize(op) != std::nullopt ) {
379
0
                    return std::nullopt;
380
0
                }
381
0
            }
382
383
0
            std::shared_ptr<CryptClass> crypt = nullptr;
384
0
            const ::Botan::SymmetricKey key(op.cipher.key.GetPtr(), op.cipher.key.GetSize());
385
0
            const ::Botan::InitializationVector iv(op.cipher.iv.GetPtr(), op.cipher.iv.GetSize());
386
0
            ::Botan::secure_vector<uint8_t> in = GetInData(op);
387
0
            std::vector<uint8_t> out;
388
0
            bool useOneShot = true;
389
0
            util::Multipart parts;
390
391
0
            const std::optional<size_t> tagSize = GetTagSize(op);
392
393
0
            try {
394
                /* Initialize */
395
0
                {
396
0
                    std::optional<std::string> _algoString;
397
0
                    CF_CHECK_NE(_algoString = Botan_detail::CipherIDToString(op.cipher.cipherType.Get()), std::nullopt);
398
0
                    std::string algoString;
399
0
                    if ( tagSize == std::nullopt ) {
400
0
                        algoString = Botan_detail::parenthesize(*_algoString, std::to_string(0));
401
0
                    } else {
402
0
                        algoString = Botan_detail::parenthesize(*_algoString, std::to_string(*tagSize));
403
0
                    }
404
405
0
                    CF_CHECK_NE(crypt = CryptClass::create(algoString, GetCryptType<OperationType>()), nullptr);
406
0
                    crypt->set_key(key);
407
408
0
                    SetAAD(crypt, op.aad);
409
410
0
                    crypt->start(iv.bits_of());
411
0
                    if ( crypt->update_granularity() == 1 ) {
412
0
                        try {
413
0
                            useOneShot = ds.Get<bool>();
414
0
                        } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
415
0
                    }
416
0
                    if ( useOneShot == false ) {
417
0
                        parts = util::ToParts(ds, GetInPtr(op), GetInSize(op));
418
0
                    }
419
0
                }
420
421
                /* Process */
422
0
                {
423
0
                    if ( useOneShot == true ) {
424
0
                        crypt->finish(in);
425
0
                    } else {
426
0
                        for (const auto& part : parts) {
427
0
                            std::vector<uint8_t> tmp(part.first, part.first + part.second);
428
0
                            crypt->process(tmp.data(), tmp.size());
429
0
                            out.insert(out.end(), tmp.begin(), tmp.end());
430
0
                        }
431
0
                    }
432
0
                }
433
434
                /* Finalize */
435
0
                {
436
                    /* TODO take max output size in consideration */
437
438
0
                    if ( useOneShot == true ) {
439
0
                        ret = ToReturnType<ReturnType>(in, tagSize);
440
0
                    } else {
441
0
                        ret = ToReturnType<ReturnType>(::Botan::secure_vector<uint8_t>(out.data(), out.data() + out.size()), tagSize);
442
0
                    }
443
0
                }
444
0
            } catch ( ... ) { }
445
0
end:
446
447
0
            return ret;
448
0
        }
Unexecuted instantiation: std::__1::optional<cryptofuzz::component::Ciphertext> cryptofuzz::module::Botan_detail::Crypt<cryptofuzz::component::Ciphertext, cryptofuzz::operation::SymmetricEncrypt, Botan::AEAD_Mode>(cryptofuzz::operation::SymmetricEncrypt&, fuzzing::datasource::Datasource&)
Unexecuted instantiation: std::__1::optional<cryptofuzz::component::Ciphertext> cryptofuzz::module::Botan_detail::Crypt<cryptofuzz::component::Ciphertext, cryptofuzz::operation::SymmetricEncrypt, Botan::Cipher_Mode>(cryptofuzz::operation::SymmetricEncrypt&, fuzzing::datasource::Datasource&)
Unexecuted instantiation: std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Botan_detail::Crypt<cryptofuzz::Buffer, cryptofuzz::operation::SymmetricDecrypt, Botan::AEAD_Mode>(cryptofuzz::operation::SymmetricDecrypt&, fuzzing::datasource::Datasource&)
Unexecuted instantiation: std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Botan_detail::Crypt<cryptofuzz::Buffer, cryptofuzz::operation::SymmetricDecrypt, Botan::Cipher_Mode>(cryptofuzz::operation::SymmetricDecrypt&, fuzzing::datasource::Datasource&)
449
450
} /* namespace Botan_detail */
451
452
0
std::optional<component::MAC> Botan::OpCMAC(operation::CMAC& op) {
453
0
    if ( !repository::IsCBC(op.cipher.cipherType.Get()) ) {
454
0
        return std::nullopt;
455
0
    }
456
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
457
0
    std::optional<component::MAC> ret = std::nullopt;
458
0
    std::unique_ptr<::Botan::MessageAuthenticationCode> cmac = nullptr;
459
0
    util::Multipart parts;
460
461
0
    try {
462
        /* Initialize */
463
0
        {
464
0
            BOTAN_SET_GLOBAL_DS
465
466
0
            std::optional<std::string> algoString;
467
0
            CF_CHECK_NE(algoString = Botan_detail::CipherIDToString(op.cipher.cipherType.Get(), false), std::nullopt);
468
469
0
            const std::string cmacString = Botan_detail::parenthesize("CMAC", *algoString);
470
471
0
            CF_CHECK_NE(cmac = ::Botan::MessageAuthenticationCode::create(cmacString), nullptr);
472
473
0
            try {
474
0
                cmac->set_key(op.cipher.key.GetPtr(), op.cipher.key.GetSize());
475
0
            } catch ( ... ) {
476
0
                goto end;
477
0
            }
478
479
0
            parts = util::ToParts(ds, op.cleartext);
480
0
        }
481
482
        /* Process */
483
0
        for (const auto& part : parts) {
484
0
            cmac->update(part.first, part.second);
485
0
        }
486
487
        /* Finalize */
488
0
        {
489
0
            const auto res = cmac->final();
490
0
            ret = component::MAC(res.data(), res.size());
491
0
        }
492
493
0
    } catch ( ... ) { }
494
495
0
end:
496
0
    BOTAN_UNSET_GLOBAL_DS
497
498
0
    return ret;
499
0
}
500
501
0
std::optional<component::Ciphertext> Botan::OpSymmetricEncrypt(operation::SymmetricEncrypt& op) {
502
0
    if ( op.cipher.cipherType.Is(CF_CIPHER("CHACHA20_POLY1305")) && op.cipher.iv.GetSize() == 24 ) {
503
        /* Botan interpretes CHACHA20_POLY1305 + 192 bits IV as XCHACHA20_POLY1305 */
504
0
        return std::nullopt;
505
0
    }
506
507
0
    std::optional<component::Ciphertext> ret = std::nullopt;
508
509
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
510
0
    BOTAN_SET_GLOBAL_DS
511
512
0
    if ( cryptofuzz::repository::IsAEAD(op.cipher.cipherType.Get()) ) {
513
0
        ret = Botan_detail::Crypt<component::Ciphertext, operation::SymmetricEncrypt, ::Botan::AEAD_Mode>(op, ds);
514
0
    } else {
515
0
        ret = Botan_detail::Crypt<component::Ciphertext, operation::SymmetricEncrypt, ::Botan::Cipher_Mode>(op, ds);
516
0
    }
517
518
    BOTAN_UNSET_GLOBAL_DS
519
520
0
    return ret;
521
0
}
522
523
0
std::optional<component::Cleartext> Botan::OpSymmetricDecrypt(operation::SymmetricDecrypt& op) {
524
0
    if ( op.cipher.cipherType.Is(CF_CIPHER("CHACHA20_POLY1305")) && op.cipher.iv.GetSize() == 24 ) {
525
0
        return std::nullopt;
526
0
    }
527
528
0
    std::optional<component::Cleartext> ret = std::nullopt;
529
530
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
531
0
    BOTAN_SET_GLOBAL_DS
532
533
0
    if ( cryptofuzz::repository::IsAEAD(op.cipher.cipherType.Get()) ) {
534
0
        ret = Botan_detail::Crypt<component::Cleartext, operation::SymmetricDecrypt, ::Botan::AEAD_Mode>(op, ds);
535
0
    } else {
536
0
        ret = Botan_detail::Crypt<component::Cleartext, operation::SymmetricDecrypt, ::Botan::Cipher_Mode>(op, ds);
537
0
    }
538
539
    BOTAN_UNSET_GLOBAL_DS
540
541
0
    return ret;
542
0
}
543
544
0
std::optional<component::Key> Botan::OpKDF_SCRYPT(operation::KDF_SCRYPT& op) {
545
0
    std::optional<component::Key> ret = std::nullopt;
546
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
547
0
    std::unique_ptr<::Botan::PasswordHashFamily> pwdhash_fam = nullptr;
548
0
    std::unique_ptr<::Botan::PasswordHash> pwdhash = nullptr;
549
0
    uint8_t* out = util::malloc(op.keySize);
550
551
0
    try {
552
        /* Initialize */
553
0
        {
554
0
            BOTAN_SET_GLOBAL_DS
555
556
0
            CF_CHECK_NE(pwdhash_fam = ::Botan::PasswordHashFamily::create("Scrypt"), nullptr);
557
0
            CF_CHECK_NE(pwdhash = pwdhash_fam->from_params(op.N, op.r, op.p), nullptr);
558
559
0
        }
560
561
        /* Process */
562
0
        {
563
0
            pwdhash->derive_key(
564
0
                    out,
565
0
                    op.keySize,
566
0
                    (const char*)op.password.GetPtr(),
567
0
                    op.password.GetSize(),
568
0
                    op.salt.GetPtr(),
569
0
                    op.salt.GetSize());
570
0
        }
571
572
        /* Finalize */
573
0
        {
574
0
            ret = component::Key(out, op.keySize);
575
0
        }
576
0
    } catch ( ... ) { }
577
578
0
end:
579
0
    util::free(out);
580
581
    BOTAN_UNSET_GLOBAL_DS
582
583
0
    return ret;
584
0
}
585
586
0
std::optional<component::Key> Botan::OpKDF_HKDF(operation::KDF_HKDF& op) {
587
0
    std::optional<component::Key> ret = std::nullopt;
588
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
589
0
    std::unique_ptr<::Botan::KDF> hkdf = nullptr;
590
591
0
    try {
592
0
        {
593
0
            BOTAN_SET_GLOBAL_DS
594
595
0
            std::optional<std::string> algoString;
596
0
            CF_CHECK_NE(algoString = Botan_detail::DigestIDToString(op.digestType.Get(), true), std::nullopt);
597
598
0
            const std::string hkdfString = Botan_detail::parenthesize("HKDF", *algoString);
599
0
            hkdf = ::Botan::KDF::create(hkdfString);
600
0
        }
601
602
0
        {
603
0
            auto derived = hkdf->derive_key(op.keySize, op.password.Get(), op.salt.Get(), op.info.Get());
604
605
0
            ret = component::Key(derived.data(), derived.size());
606
0
        }
607
0
    } catch ( ... ) { }
608
609
0
end:
610
0
    BOTAN_UNSET_GLOBAL_DS
611
612
0
    return ret;
613
0
}
614
615
0
std::optional<component::Key> Botan::OpKDF_PBKDF1(operation::KDF_PBKDF1& op) {
616
0
    std::optional<component::Key> ret = std::nullopt;
617
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
618
0
    std::unique_ptr<::Botan::PBKDF> pbkdf1 = nullptr;
619
0
    uint8_t* out = util::malloc(op.keySize);
620
621
0
    try {
622
        /* Initialize */
623
0
        {
624
0
            BOTAN_SET_GLOBAL_DS
625
626
0
            std::optional<std::string> algoString;
627
0
            CF_CHECK_NE(algoString = Botan_detail::DigestIDToString(op.digestType.Get(), true), std::nullopt);
628
629
0
            const std::string pbkdf1String = Botan_detail::parenthesize("PBKDF1", *algoString);
630
0
            CF_CHECK_NE(pbkdf1 = ::Botan::PBKDF::create(pbkdf1String), nullptr);
631
0
        }
632
633
        /* Process */
634
0
        {
635
0
            const std::string passphrase(op.password.GetPtr(), op.password.GetPtr() + op.password.GetSize());
636
0
            pbkdf1->pbkdf_iterations(
637
0
                    out,
638
0
                    op.keySize,
639
0
                    passphrase,
640
0
                    op.salt.GetPtr(),
641
0
                    op.salt.GetSize(),
642
0
                    op.iterations);
643
0
        }
644
645
        /* Finalize */
646
0
        {
647
0
            ret = component::Key(out, op.keySize);
648
0
        }
649
0
    } catch ( ... ) { }
650
651
0
end:
652
0
    util::free(out);
653
654
    BOTAN_UNSET_GLOBAL_DS
655
656
0
    return ret;
657
0
}
658
659
0
std::optional<component::Key> Botan::OpKDF_PBKDF2(operation::KDF_PBKDF2& op) {
660
0
    std::optional<component::Key> ret = std::nullopt;
661
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
662
0
    std::unique_ptr<::Botan::PasswordHashFamily> pwdhash_fam = nullptr;
663
0
    std::unique_ptr<::Botan::PasswordHash> pwdhash = nullptr;
664
0
    uint8_t* out = util::malloc(op.keySize);
665
666
0
    try {
667
        /* Initialize */
668
0
        {
669
0
            BOTAN_SET_GLOBAL_DS
670
671
0
            std::optional<std::string> algoString;
672
0
            CF_CHECK_NE(algoString = Botan_detail::DigestIDToString(op.digestType.Get(), true), std::nullopt);
673
674
0
            const std::string pbkdf2String = Botan_detail::parenthesize("PBKDF2", *algoString);
675
0
            CF_CHECK_NE(pwdhash_fam = ::Botan::PasswordHashFamily::create(pbkdf2String), nullptr);
676
677
0
            CF_CHECK_NE(pwdhash = pwdhash_fam->from_params(op.iterations), nullptr);
678
679
0
        }
680
681
        /* Process */
682
0
        {
683
0
            pwdhash->derive_key(
684
0
                    out,
685
0
                    op.keySize,
686
0
                    (const char*)op.password.GetPtr(),
687
0
                    op.password.GetSize(),
688
0
                    op.salt.GetPtr(),
689
0
                    op.salt.GetSize());
690
0
        }
691
692
        /* Finalize */
693
0
        {
694
0
            ret = component::Key(out, op.keySize);
695
0
        }
696
0
    } catch ( ... ) { }
697
698
0
end:
699
0
    util::free(out);
700
701
    BOTAN_UNSET_GLOBAL_DS
702
703
0
    return ret;
704
0
}
705
706
0
std::optional<component::Key> Botan::OpKDF_ARGON2(operation::KDF_ARGON2& op) {
707
0
    std::optional<component::Key> ret = std::nullopt;
708
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
709
0
    std::unique_ptr<::Botan::PasswordHashFamily> pwdhash_fam = nullptr;
710
0
    std::unique_ptr<::Botan::PasswordHash> pwdhash = nullptr;
711
0
    uint8_t* out = util::malloc(op.keySize);
712
713
0
    try {
714
        /* Initialize */
715
0
        {
716
0
            BOTAN_SET_GLOBAL_DS
717
718
0
            std::string argon2String;
719
720
0
            switch ( op.type ) {
721
0
                case    0:
722
0
                    argon2String = "Argon2d";
723
0
                    break;
724
0
                case    1:
725
0
                    argon2String = "Argon2i";
726
0
                    break;
727
0
                case    2:
728
0
                    argon2String = "Argon2id";
729
0
                    break;
730
0
                default:
731
0
                    goto end;
732
0
            }
733
0
            CF_CHECK_NE(pwdhash_fam = ::Botan::PasswordHashFamily::create(argon2String), nullptr);
734
735
0
            CF_CHECK_NE(pwdhash = pwdhash_fam->from_params(
736
0
                        op.memory,
737
0
                        op.iterations,
738
0
                        op.threads), nullptr);
739
0
        }
740
741
        /* Process */
742
0
        {
743
0
            pwdhash->derive_key(
744
0
                    out,
745
0
                    op.keySize,
746
0
                    (const char*)op.password.GetPtr(),
747
0
                    op.password.GetSize(),
748
0
                    op.salt.GetPtr(),
749
0
                    op.salt.GetSize());
750
0
        }
751
752
        /* Finalize */
753
0
        {
754
0
            ret = component::Key(out, op.keySize);
755
0
        }
756
0
    } catch ( ... ) { }
757
758
0
end:
759
0
    util::free(out);
760
761
    BOTAN_UNSET_GLOBAL_DS
762
763
0
    return ret;
764
0
}
765
766
0
std::optional<component::Key> Botan::OpKDF_SP_800_108(operation::KDF_SP_800_108& op) {
767
0
    std::optional<component::Key> ret = std::nullopt;
768
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
769
0
    uint8_t* out = util::malloc(op.keySize);
770
0
    std::unique_ptr<::Botan::KDF> sp_800_108 = nullptr;
771
772
0
    try {
773
0
        BOTAN_SET_GLOBAL_DS
774
775
0
        std::optional<std::string> algoString;
776
0
        CF_CHECK_NE(algoString = Botan_detail::DigestIDToString(op.mech.type.Get(), true), std::nullopt);
777
778
0
        const std::string hmacString = Botan_detail::parenthesize("HMAC", *algoString);
779
0
        std::string sp_800_108_string;
780
0
        switch ( op.mode ) {
781
0
            case    0:
782
0
                sp_800_108_string = Botan_detail::parenthesize("SP800-108-Counter", hmacString);
783
0
                break;
784
0
            case    1:
785
0
                sp_800_108_string = Botan_detail::parenthesize("SP800-108-Feedback", hmacString);
786
0
                break;
787
0
            case    2:
788
0
                sp_800_108_string = Botan_detail::parenthesize("SP800-108-Pipeline", hmacString);
789
0
                break;
790
0
            default:
791
0
                goto end;
792
0
        }
793
794
0
        sp_800_108 = ::Botan::KDF::create(sp_800_108_string);
795
796
0
        {
797
0
            auto derived = sp_800_108->derive_key(op.keySize, op.secret.Get(), op.salt.Get(), op.label.Get());
798
799
0
            ret = component::Key(derived.data(), derived.size());
800
0
        }
801
0
    } catch ( ... ) { }
802
803
0
end:
804
0
    util::free(out);
805
806
    BOTAN_UNSET_GLOBAL_DS
807
808
0
    return ret;
809
0
}
810
811
0
std::optional<component::Key> Botan::OpKDF_TLS1_PRF(operation::KDF_TLS1_PRF& op) {
812
0
    std::optional<component::Key> ret = std::nullopt;
813
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
814
0
    std::unique_ptr<::Botan::KDF> tlsprf = nullptr;
815
816
0
    try {
817
0
        BOTAN_SET_GLOBAL_DS
818
819
0
        {
820
0
            CF_CHECK_EQ(op.digestType.Get(), CF_DIGEST("MD5_SHA1"));
821
0
            CF_CHECK_NE(tlsprf = ::Botan::KDF::create("TLS-PRF()"), nullptr);
822
0
        }
823
824
0
        {
825
0
            const auto derived = tlsprf->derive_key(op.keySize, op.secret.Get(), op.seed.Get(), std::vector<uint8_t>{});
826
827
0
            ret = component::Key(derived.data(), derived.size());
828
0
        }
829
0
    } catch ( ... ) { }
830
831
0
end:
832
0
    BOTAN_UNSET_GLOBAL_DS
833
834
0
    return ret;
835
0
}
836
837
0
std::optional<component::Key> Botan::OpKDF_BCRYPT(operation::KDF_BCRYPT& op) {
838
0
    std::optional<component::Key> ret = std::nullopt;
839
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
840
0
    std::unique_ptr<::Botan::PasswordHashFamily> pwdhash_fam = nullptr;
841
0
    std::unique_ptr<::Botan::PasswordHash> pwdhash = nullptr;
842
0
    uint8_t* out = util::malloc(op.keySize);
843
844
0
    try {
845
0
        BOTAN_SET_GLOBAL_DS
846
847
        /* Initialize */
848
0
        {
849
0
            CF_CHECK_EQ(op.digestType.Get(), CF_DIGEST("SHA512"));
850
0
            CF_CHECK_NE(pwdhash_fam = ::Botan::PasswordHashFamily::create("Bcrypt-PBKDF"), nullptr);
851
0
            CF_CHECK_NE(pwdhash = pwdhash_fam->from_params(op.iterations), nullptr);
852
853
0
        }
854
855
        /* Process */
856
0
        {
857
0
            pwdhash->derive_key(
858
0
                    out,
859
0
                    op.keySize,
860
0
                    (const char*)op.secret.GetPtr(),
861
0
                    op.secret.GetSize(),
862
0
                    op.salt.GetPtr(),
863
0
                    op.salt.GetSize());
864
0
        }
865
866
        /* Finalize */
867
0
        {
868
0
            ret = component::Key(out, op.keySize);
869
0
        }
870
0
    } catch ( ... ) { }
871
872
0
end:
873
0
    util::free(out);
874
875
    BOTAN_UNSET_GLOBAL_DS
876
877
0
    return ret;
878
0
}
879
880
namespace Botan_detail {
881
5.09k
    std::optional<std::string> CurveIDToString(const uint64_t curveID) {
882
5.09k
#include "curve_string_lut.h"
883
5.09k
        std::optional<std::string> ret = std::nullopt;
884
885
5.09k
        CF_CHECK_NE(LUT.find(curveID), LUT.end());
886
3.57k
        ret = LUT.at(curveID);
887
5.09k
end:
888
5.09k
        return ret;
889
3.57k
    }
890
} /* namespace Botan_detail */
891
892
1.34k
std::optional<component::ECC_KeyPair> Botan::OpECC_GenerateKeyPair(operation::ECC_GenerateKeyPair& op) {
893
1.34k
    std::optional<component::ECC_KeyPair> ret = std::nullopt;
894
1.34k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
895
896
1.34k
    std::optional<std::string> curveString;
897
1.34k
    BOTAN_FUZZER_RNG;
898
899
1.34k
    CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
900
901
719
    try {
902
719
        ::Botan::EC_Group group(*curveString);
903
719
        auto priv = ::Botan::ECDSA_PrivateKey(rng, group);
904
905
719
        const auto pub_x = priv.public_point().get_affine_x();
906
719
        const auto pub_y = priv.public_point().get_affine_y();
907
908
719
        {
909
719
            const auto pub = std::make_unique<::Botan::ECDSA_PublicKey>(::Botan::ECDSA_PublicKey(group, priv.public_point()));
910
719
            CF_ASSERT(pub->check_key(rng, true) == true, "Generated pubkey fails validation");
911
719
        }
912
913
0
        ret = { priv.private_value().to_dec_string(), { pub_x.to_dec_string(), pub_y.to_dec_string() } };
914
915
      /* Catch exception thrown from Botan_detail::Fuzzer_RNG::randomize */
916
719
    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
917
918
1.34k
end:
919
1.34k
    return ret;
920
719
}
921
922
978
std::optional<bool> Botan::OpECC_ValidatePubkey(operation::ECC_ValidatePubkey& op) {
923
978
    std::optional<bool> ret = std::nullopt;
924
978
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
925
926
978
    BOTAN_FUZZER_RNG;
927
978
    std::unique_ptr<::Botan::Public_Key> pub = nullptr;
928
929
978
    try {
930
978
        std::optional<std::string> curveString;
931
978
        CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
932
933
579
        ::Botan::EC_Group group(*curveString);
934
579
        const ::Botan::BigInt pub_x(op.pub.first.ToString(ds));
935
579
        const ::Botan::BigInt pub_y(op.pub.second.ToString(ds));
936
579
        const ::Botan::PointGFp public_point = group.point(pub_x, pub_y);
937
579
        pub = std::make_unique<::Botan::ECDSA_PublicKey>(::Botan::ECDSA_PublicKey(group, public_point));
938
939
579
        ret = pub->check_key(rng, true);
940
579
    } catch ( ... ) { }
941
942
978
end:
943
978
    return ret;
944
978
}
945
946
1.17k
std::optional<component::ECC_PublicKey> Botan::OpECC_PrivateToPublic(operation::ECC_PrivateToPublic& op) {
947
1.17k
    std::optional<component::ECC_PublicKey> ret = std::nullopt;
948
1.17k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
949
950
1.17k
    BOTAN_FUZZER_RNG;
951
952
1.17k
    try {
953
1.17k
        std::optional<std::string> curveString;
954
955
        /* Botan appears to generate a new key if the input key is 0, so don't do this */
956
1.17k
        CF_CHECK_NE(op.priv.ToTrimmedString(), "0");
957
958
871
        if ( op.curveType.Get() == CF_ECC_CURVE("x25519") ) {
959
137
            uint8_t priv_bytes[32];
960
961
137
            ::Botan::BigInt priv_bigint(op.priv.ToString(ds));
962
137
            priv_bigint.binary_encode(priv_bytes, sizeof(priv_bytes));
963
137
            priv_bytes[0] &= 248;
964
137
            priv_bytes[31] &= 127;
965
137
            priv_bytes[31] |= 64;
966
137
            const ::Botan::secure_vector<uint8_t> priv_vec(priv_bytes, priv_bytes + sizeof(priv_bytes));
967
968
137
            auto priv = ::Botan::X25519_PrivateKey(priv_vec);
969
970
137
            ::Botan::BigInt pub;
971
137
            pub.binary_decode(priv.public_value());
972
973
137
            ret = { pub.to_dec_string(), "0" };
974
734
        } else {
975
734
            CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
976
447
            ::Botan::EC_Group group(*curveString);
977
978
447
            const ::Botan::BigInt priv_bn(op.priv.ToString(ds));
979
447
            auto priv = std::make_unique<::Botan::ECDSA_PrivateKey>(::Botan::ECDSA_PrivateKey(rng, group, priv_bn));
980
981
447
            const auto pub_x = priv->public_point().get_affine_x();
982
447
            const auto pub_y = priv->public_point().get_affine_y();
983
984
447
            ret = { pub_x.to_dec_string(), pub_y.to_dec_string() };
985
447
        }
986
871
    } catch ( ... ) { }
987
988
1.17k
end:
989
1.17k
    return ret;
990
1.17k
}
991
992
namespace Botan_detail {
993
    template <class PrivkeyType, class Operation, bool RFC6979 = true>
994
1.27k
        std::optional<component::ECDSA_Signature> ECxDSA_Sign(Operation& op) {
995
1.27k
            std::optional<component::ECDSA_Signature> ret = std::nullopt;
996
1.27k
            Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
997
998
1.27k
            std::unique_ptr<PrivkeyType> priv = nullptr;
999
1.27k
            std::unique_ptr<::Botan::Public_Key> pub = nullptr;
1000
1.27k
            std::unique_ptr<::Botan::PK_Signer> signer;
1001
1002
1.27k
            BOTAN_FUZZER_RNG;
1003
1004
            BOTAN_SET_GLOBAL_DS
1005
1006
1.27k
            if ( RFC6979 == true ) {
1007
1.27k
                CF_CHECK_EQ(op.UseRFC6979Nonce(), true);
1008
84
            } else {
1009
0
                CF_CHECK_EQ(op.UseRandomNonce(), true);
1010
0
            }
1011
1012
84
            CF_CHECK_EQ(op.digestType.Get(), CF_DIGEST("SHA256"));
1013
1014
0
            try {
1015
                /* Initialize */
1016
0
                {
1017
1018
0
                    std::optional<std::string> curveString, algoString;
1019
1020
                    /* Botan appears to generate a new key if the input key is 0, so don't do this */
1021
0
                    CF_CHECK_NE(op.priv.ToTrimmedString(), "0");
1022
1023
0
                    CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
1024
0
                    ::Botan::EC_Group group(*curveString);
1025
1026
                    /* Private key */
1027
0
                    {
1028
0
                        const ::Botan::BigInt priv_bn(op.priv.ToString(ds));
1029
0
                        priv = std::make_unique<PrivkeyType>(PrivkeyType(rng, group, priv_bn));
1030
0
                    }
1031
1032
                    /* Prepare signer */
1033
0
                    CF_CHECK_NE(algoString = Botan_detail::DigestIDToString(op.digestType.Get()), std::nullopt);
1034
1035
0
                    const std::string emsa1String = Botan_detail::parenthesize("EMSA1", *algoString);
1036
0
                    signer.reset(new ::Botan::PK_Signer(*priv, rng, emsa1String, ::Botan::DER_SEQUENCE));
1037
0
                }
1038
1039
                /* Process */
1040
0
                {
1041
0
                    const auto signature = signer->sign_message(op.cleartext.Get(), rng);
1042
1043
                    /* Retrieve R and S */
1044
0
                    {
1045
0
                        ::Botan::BER_Decoder decoder(signature);
1046
0
                        ::Botan::BER_Decoder ber_sig = decoder.start_sequence();
1047
1048
0
                        size_t count = 0;
1049
1050
0
                        ::Botan::BigInt R;
1051
0
                        ::Botan::BigInt S;
1052
0
                        while(ber_sig.more_items())
1053
0
                        {
1054
0
                            switch ( count ) {
1055
0
                                case    0:
1056
0
                                    ber_sig.decode(R);
1057
0
                                    break;
1058
0
                                case    1:
1059
0
                                    ber_sig.decode(S);
1060
0
                                    break;
1061
0
                                default:
1062
0
                                    printf("Error: Too many parts in signature BER\n");
1063
0
                                    abort();
1064
0
                            }
1065
1066
0
                            ++count;
1067
0
                        }
1068
1069
0
                        if ( op.curveType.Get() == CF_ECC_CURVE("secp256k1") ) {
1070
                            /* For compatibility with the secp256k1 library.
1071
                             * See: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#low-s-values-in-signatures
1072
                             */
1073
0
                            if (S > ::Botan::BigInt("57896044618658097711785492504343953926418782139537452191302581570759080747168")) {
1074
0
                                S = ::Botan::BigInt("115792089237316195423570985008687907852837564279074904382605163141518161494337") - S;
1075
0
                            }
1076
0
                        } else if ( op.curveType.Get() == CF_ECC_CURVE("secp256r1") ) {
1077
                            /* Similar ECDSA signature malleability adjustment for compatibility with trezor-firmware */
1078
0
                            if (S > ::Botan::BigInt("57896044605178124381348723474703786764998477612067880171211129530534256022184")) {
1079
0
                                S = ::Botan::BigInt("115792089210356248762697446949407573529996955224135760342422259061068512044369") - S;
1080
0
                            }
1081
0
                        }
1082
1083
0
                        const auto pub_x = priv->public_point().get_affine_x().to_dec_string();
1084
0
                        const auto pub_y = priv->public_point().get_affine_y().to_dec_string();
1085
1086
0
                        const auto R_str = R.to_dec_string();
1087
0
                        const auto S_str = S.to_dec_string();
1088
1089
0
                        ret = component::ECDSA_Signature({ R_str, S_str }, { pub_x, pub_y });
1090
0
                    }
1091
0
                }
1092
0
            } catch ( ... ) { }
1093
1094
1.27k
end:
1095
1.27k
            BOTAN_UNSET_GLOBAL_DS
1096
1097
1.27k
            return ret;
1098
0
        }
std::__1::optional<cryptofuzz::component::ECDSA_Signature> cryptofuzz::module::Botan_detail::ECxDSA_Sign<Botan::ECDSA_PrivateKey, cryptofuzz::operation::ECDSA_Sign, true>(cryptofuzz::operation::ECDSA_Sign&)
Line
Count
Source
994
1.27k
        std::optional<component::ECDSA_Signature> ECxDSA_Sign(Operation& op) {
995
1.27k
            std::optional<component::ECDSA_Signature> ret = std::nullopt;
996
1.27k
            Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
997
998
1.27k
            std::unique_ptr<PrivkeyType> priv = nullptr;
999
1.27k
            std::unique_ptr<::Botan::Public_Key> pub = nullptr;
1000
1.27k
            std::unique_ptr<::Botan::PK_Signer> signer;
1001
1002
1.27k
            BOTAN_FUZZER_RNG;
1003
1004
            BOTAN_SET_GLOBAL_DS
1005
1006
1.27k
            if ( RFC6979 == true ) {
1007
1.27k
                CF_CHECK_EQ(op.UseRFC6979Nonce(), true);
1008
84
            } else {
1009
0
                CF_CHECK_EQ(op.UseRandomNonce(), true);
1010
0
            }
1011
1012
84
            CF_CHECK_EQ(op.digestType.Get(), CF_DIGEST("SHA256"));
1013
1014
0
            try {
1015
                /* Initialize */
1016
0
                {
1017
1018
0
                    std::optional<std::string> curveString, algoString;
1019
1020
                    /* Botan appears to generate a new key if the input key is 0, so don't do this */
1021
0
                    CF_CHECK_NE(op.priv.ToTrimmedString(), "0");
1022
1023
0
                    CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
1024
0
                    ::Botan::EC_Group group(*curveString);
1025
1026
                    /* Private key */
1027
0
                    {
1028
0
                        const ::Botan::BigInt priv_bn(op.priv.ToString(ds));
1029
0
                        priv = std::make_unique<PrivkeyType>(PrivkeyType(rng, group, priv_bn));
1030
0
                    }
1031
1032
                    /* Prepare signer */
1033
0
                    CF_CHECK_NE(algoString = Botan_detail::DigestIDToString(op.digestType.Get()), std::nullopt);
1034
1035
0
                    const std::string emsa1String = Botan_detail::parenthesize("EMSA1", *algoString);
1036
0
                    signer.reset(new ::Botan::PK_Signer(*priv, rng, emsa1String, ::Botan::DER_SEQUENCE));
1037
0
                }
1038
1039
                /* Process */
1040
0
                {
1041
0
                    const auto signature = signer->sign_message(op.cleartext.Get(), rng);
1042
1043
                    /* Retrieve R and S */
1044
0
                    {
1045
0
                        ::Botan::BER_Decoder decoder(signature);
1046
0
                        ::Botan::BER_Decoder ber_sig = decoder.start_sequence();
1047
1048
0
                        size_t count = 0;
1049
1050
0
                        ::Botan::BigInt R;
1051
0
                        ::Botan::BigInt S;
1052
0
                        while(ber_sig.more_items())
1053
0
                        {
1054
0
                            switch ( count ) {
1055
0
                                case    0:
1056
0
                                    ber_sig.decode(R);
1057
0
                                    break;
1058
0
                                case    1:
1059
0
                                    ber_sig.decode(S);
1060
0
                                    break;
1061
0
                                default:
1062
0
                                    printf("Error: Too many parts in signature BER\n");
1063
0
                                    abort();
1064
0
                            }
1065
1066
0
                            ++count;
1067
0
                        }
1068
1069
0
                        if ( op.curveType.Get() == CF_ECC_CURVE("secp256k1") ) {
1070
                            /* For compatibility with the secp256k1 library.
1071
                             * See: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#low-s-values-in-signatures
1072
                             */
1073
0
                            if (S > ::Botan::BigInt("57896044618658097711785492504343953926418782139537452191302581570759080747168")) {
1074
0
                                S = ::Botan::BigInt("115792089237316195423570985008687907852837564279074904382605163141518161494337") - S;
1075
0
                            }
1076
0
                        } else if ( op.curveType.Get() == CF_ECC_CURVE("secp256r1") ) {
1077
                            /* Similar ECDSA signature malleability adjustment for compatibility with trezor-firmware */
1078
0
                            if (S > ::Botan::BigInt("57896044605178124381348723474703786764998477612067880171211129530534256022184")) {
1079
0
                                S = ::Botan::BigInt("115792089210356248762697446949407573529996955224135760342422259061068512044369") - S;
1080
0
                            }
1081
0
                        }
1082
1083
0
                        const auto pub_x = priv->public_point().get_affine_x().to_dec_string();
1084
0
                        const auto pub_y = priv->public_point().get_affine_y().to_dec_string();
1085
1086
0
                        const auto R_str = R.to_dec_string();
1087
0
                        const auto S_str = S.to_dec_string();
1088
1089
0
                        ret = component::ECDSA_Signature({ R_str, S_str }, { pub_x, pub_y });
1090
0
                    }
1091
0
                }
1092
0
            } catch ( ... ) { }
1093
1094
1.27k
end:
1095
1.27k
            BOTAN_UNSET_GLOBAL_DS
1096
1097
1.27k
            return ret;
1098
0
        }
Unexecuted instantiation: std::__1::optional<cryptofuzz::component::ECDSA_Signature> cryptofuzz::module::Botan_detail::ECxDSA_Sign<Botan::ECGDSA_PrivateKey, cryptofuzz::operation::ECGDSA_Sign, false>(cryptofuzz::operation::ECGDSA_Sign&)
1099
} /* namespace Botan_detail */
1100
1101
1.48k
std::optional<component::ECDSA_Signature> Botan::OpECDSA_Sign(operation::ECDSA_Sign& op) {
1102
1.48k
    if ( op.curveType.Is(CF_ECC_CURVE("ed25519")) ) {
1103
198
        const auto _priv_bytes = util::DecToBin(op.priv.ToTrimmedString(), 32);
1104
198
        if ( _priv_bytes == std::nullopt ) {
1105
5
            return std::nullopt;
1106
5
        }
1107
1108
193
        const ::Botan::secure_vector<uint8_t> priv_bytes(_priv_bytes->data(), _priv_bytes->data() + _priv_bytes->size());
1109
1110
193
        const auto priv = std::make_unique<::Botan::Ed25519_PrivateKey>(priv_bytes);
1111
1112
193
        std::unique_ptr<::Botan::PK_Signer> signer;
1113
1114
193
        Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1115
193
        BOTAN_FUZZER_RNG;
1116
1117
193
        signer.reset(new ::Botan::PK_Signer(*priv, rng, "Pure", ::Botan::IEEE_1363));
1118
1119
193
        const auto signature = signer->sign_message(op.cleartext.Get(), rng);
1120
193
        CF_ASSERT(signature.size() == 64, "ed25519 signature is not 64 bytes");
1121
1122
193
        const auto pub = priv->get_public_key();
1123
193
        CF_ASSERT(pub.size() == 32, "ed25519 pubkey is not 32 bytes");
1124
1125
193
        const auto ret = component::ECDSA_Signature(
1126
193
                { util::BinToDec(signature.data(), 32), util::BinToDec(signature.data() + 32, 32) },
1127
193
                { util::BinToDec(pub.data(), 32), "0"}
1128
193
        );
1129
1130
193
        return ret;
1131
1.28k
    } else if (
1132
1.28k
                op.curveType.Is(CF_ECC_CURVE("secp160k1")) ||
1133
1.28k
                op.curveType.Is(CF_ECC_CURVE("secp160r1")) ||
1134
1.28k
                op.curveType.Is(CF_ECC_CURVE("secp160r2")) ||
1135
1.28k
                op.curveType.Is(CF_ECC_CURVE("secp224k1")) ||
1136
1.28k
                op.curveType.Is(CF_ECC_CURVE("x962_p239v1")) ||
1137
1.28k
                op.curveType.Is(CF_ECC_CURVE("x962_p239v2")) ||
1138
1.28k
                op.curveType.Is(CF_ECC_CURVE("x962_p239v3"))
1139
1.28k
    ) {
1140
        /* Workaround for ECDSA signing bug
1141
         *
1142
         * https://github.com/randombit/botan/issues/2841
1143
         */
1144
7
        return std::nullopt;
1145
7
    }
1146
1147
1.27k
    return Botan_detail::ECxDSA_Sign<::Botan::ECDSA_PrivateKey, operation::ECDSA_Sign>(op);
1148
1.48k
}
1149
1150
0
std::optional<component::ECGDSA_Signature> Botan::OpECGDSA_Sign(operation::ECGDSA_Sign& op) {
1151
0
    return Botan_detail::ECxDSA_Sign<::Botan::ECGDSA_PrivateKey, operation::ECGDSA_Sign, false>(op);
1152
0
}
1153
1154
namespace Botan_detail {
1155
    template <class PubkeyType, class Operation>
1156
548
        std::optional<bool> ECxDSA_Verify(Operation& op) {
1157
548
            std::optional<bool> ret = std::nullopt;
1158
548
            Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1159
1160
548
            ::Botan::secure_vector<uint8_t> sig;
1161
548
            std::unique_ptr<::Botan::Public_Key> pub = nullptr;
1162
548
            std::unique_ptr<::Botan::EC_Group> group = nullptr;
1163
548
            Buffer CT;
1164
1165
548
            {
1166
548
                BOTAN_SET_GLOBAL_DS
1167
1168
548
                std::optional<std::string> curveString;
1169
548
                CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
1170
388
                group = std::make_unique<::Botan::EC_Group>(*curveString);
1171
388
            }
1172
1173
            /* Construct signature */
1174
0
            {
1175
388
                const ::Botan::BigInt R(op.signature.signature.first.ToString(ds));
1176
388
                const ::Botan::BigInt S(op.signature.signature.second.ToString(ds));
1177
388
                try {
1178
388
                    sig = ::Botan::BigInt::encode_fixed_length_int_pair(R, S, group->get_order_bytes());
1179
388
                } catch ( ::Botan::Encoding_Error ) {
1180
                    /* Invalid signature */
1181
46
                    BOTAN_UNSET_GLOBAL_DS
1182
46
                    return false;
1183
46
                }
1184
388
            }
1185
1186
            /* Construct pubkey */
1187
342
            try {
1188
342
                const ::Botan::BigInt pub_x(op.signature.pub.first.ToString(ds));
1189
342
                const ::Botan::BigInt pub_y(op.signature.pub.second.ToString(ds));
1190
342
                const ::Botan::PointGFp public_point = group->point(pub_x, pub_y);
1191
342
                pub = std::make_unique<PubkeyType>(PubkeyType(*group, public_point));
1192
342
            } catch ( ::Botan::Invalid_Argument ) {
1193
                /* Invalid point */
1194
7
                BOTAN_UNSET_GLOBAL_DS
1195
7
                return false;
1196
7
            }
1197
1198
            /* Construct input */
1199
335
            {
1200
335
                if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
1201
335
                    CT = op.cleartext.ECDSA_RandomPad(ds, op.curveType);
1202
335
                } else {
1203
0
                    std::optional<std::string> algoString;
1204
0
                    CF_CHECK_NE(algoString = Botan_detail::DigestIDToString(op.digestType.Get()), std::nullopt);
1205
1206
0
                    auto hash = ::Botan::HashFunction::create(*algoString);
1207
0
                    hash->update(op.cleartext.GetPtr(), op.cleartext.GetSize());
1208
0
                    const auto _CT = hash->final();
1209
0
                    CT = Buffer(_CT.data(), _CT.size()).ECDSA_RandomPad(ds, op.curveType);
1210
0
                }
1211
335
            }
1212
1213
335
            ret = ::Botan::PK_Verifier(*pub, "Raw").verify_message(CT.Get(), sig);
1214
1215
495
end:
1216
495
            BOTAN_UNSET_GLOBAL_DS
1217
1218
495
            return ret;
1219
335
        }
std::__1::optional<bool> cryptofuzz::module::Botan_detail::ECxDSA_Verify<Botan::ECDSA_PublicKey, cryptofuzz::operation::ECDSA_Verify>(cryptofuzz::operation::ECDSA_Verify&)
Line
Count
Source
1156
548
        std::optional<bool> ECxDSA_Verify(Operation& op) {
1157
548
            std::optional<bool> ret = std::nullopt;
1158
548
            Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1159
1160
548
            ::Botan::secure_vector<uint8_t> sig;
1161
548
            std::unique_ptr<::Botan::Public_Key> pub = nullptr;
1162
548
            std::unique_ptr<::Botan::EC_Group> group = nullptr;
1163
548
            Buffer CT;
1164
1165
548
            {
1166
548
                BOTAN_SET_GLOBAL_DS
1167
1168
548
                std::optional<std::string> curveString;
1169
548
                CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
1170
388
                group = std::make_unique<::Botan::EC_Group>(*curveString);
1171
388
            }
1172
1173
            /* Construct signature */
1174
0
            {
1175
388
                const ::Botan::BigInt R(op.signature.signature.first.ToString(ds));
1176
388
                const ::Botan::BigInt S(op.signature.signature.second.ToString(ds));
1177
388
                try {
1178
388
                    sig = ::Botan::BigInt::encode_fixed_length_int_pair(R, S, group->get_order_bytes());
1179
388
                } catch ( ::Botan::Encoding_Error ) {
1180
                    /* Invalid signature */
1181
46
                    BOTAN_UNSET_GLOBAL_DS
1182
46
                    return false;
1183
46
                }
1184
388
            }
1185
1186
            /* Construct pubkey */
1187
342
            try {
1188
342
                const ::Botan::BigInt pub_x(op.signature.pub.first.ToString(ds));
1189
342
                const ::Botan::BigInt pub_y(op.signature.pub.second.ToString(ds));
1190
342
                const ::Botan::PointGFp public_point = group->point(pub_x, pub_y);
1191
342
                pub = std::make_unique<PubkeyType>(PubkeyType(*group, public_point));
1192
342
            } catch ( ::Botan::Invalid_Argument ) {
1193
                /* Invalid point */
1194
7
                BOTAN_UNSET_GLOBAL_DS
1195
7
                return false;
1196
7
            }
1197
1198
            /* Construct input */
1199
335
            {
1200
335
                if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
1201
335
                    CT = op.cleartext.ECDSA_RandomPad(ds, op.curveType);
1202
335
                } else {
1203
0
                    std::optional<std::string> algoString;
1204
0
                    CF_CHECK_NE(algoString = Botan_detail::DigestIDToString(op.digestType.Get()), std::nullopt);
1205
1206
0
                    auto hash = ::Botan::HashFunction::create(*algoString);
1207
0
                    hash->update(op.cleartext.GetPtr(), op.cleartext.GetSize());
1208
0
                    const auto _CT = hash->final();
1209
0
                    CT = Buffer(_CT.data(), _CT.size()).ECDSA_RandomPad(ds, op.curveType);
1210
0
                }
1211
335
            }
1212
1213
335
            ret = ::Botan::PK_Verifier(*pub, "Raw").verify_message(CT.Get(), sig);
1214
1215
495
end:
1216
495
            BOTAN_UNSET_GLOBAL_DS
1217
1218
495
            return ret;
1219
335
        }
Unexecuted instantiation: std::__1::optional<bool> cryptofuzz::module::Botan_detail::ECxDSA_Verify<Botan::ECGDSA_PublicKey, cryptofuzz::operation::ECGDSA_Verify>(cryptofuzz::operation::ECGDSA_Verify&)
1220
} /* namespace Botan_detail */
1221
1222
920
std::optional<bool> Botan::OpECDSA_Verify(operation::ECDSA_Verify& op) {
1223
920
    if ( op.curveType.Is(CF_ECC_CURVE("ed25519")) ) {
1224
372
        const auto pub_bytes = util::DecToBin(op.signature.pub.first.ToTrimmedString(), 32);
1225
372
        if ( pub_bytes == std::nullopt ) {
1226
6
            return std::nullopt;
1227
6
        }
1228
366
        const auto pub = std::make_unique<::Botan::Ed25519_PublicKey>(*pub_bytes);
1229
1230
366
        const auto sig_r = util::DecToBin(op.signature.signature.first.ToTrimmedString(), 32);
1231
366
        if ( sig_r == std::nullopt ) {
1232
4
            return std::nullopt;
1233
4
        }
1234
1235
362
        const auto sig_s = util::DecToBin(op.signature.signature.second.ToTrimmedString(), 32);
1236
362
        if ( sig_s == std::nullopt ) {
1237
8
            return std::nullopt;
1238
8
        }
1239
1240
354
        std::vector<uint8_t> sig_bytes(64);
1241
354
        memcpy(sig_bytes.data(), sig_r->data(), 32);
1242
354
        memcpy(sig_bytes.data() + 32, sig_s->data(), 32);
1243
1244
354
        const bool ret = ::Botan::PK_Verifier(*pub, "Pure").verify_message(op.cleartext.Get(), sig_bytes);
1245
354
        return ret;
1246
1247
548
    } else {
1248
548
        return Botan_detail::ECxDSA_Verify<::Botan::ECDSA_PublicKey, operation::ECDSA_Verify>(op);
1249
548
    }
1250
920
}
1251
1252
0
std::optional<bool> Botan::OpECGDSA_Verify(operation::ECGDSA_Verify& op) {
1253
0
    return Botan_detail::ECxDSA_Verify<::Botan::ECGDSA_PublicKey, operation::ECGDSA_Verify>(op);
1254
0
}
1255
1256
0
std::optional<component::ECC_PublicKey> Botan::OpECDSA_Recover(operation::ECDSA_Recover& op) {
1257
0
    std::optional<component::ECC_PublicKey> ret = std::nullopt;
1258
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1259
1260
0
    std::unique_ptr<::Botan::EC_Group> group = nullptr;
1261
0
    Buffer CT;
1262
1263
0
    {
1264
0
        std::optional<std::string> curveString;
1265
0
        CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
1266
0
        group = std::make_unique<::Botan::EC_Group>(*curveString);
1267
0
    }
1268
1269
    /* Construct input */
1270
0
    {
1271
0
        if ( op.digestType.Get() == CF_DIGEST("NULL") ) {
1272
0
            CT = op.cleartext.ECDSA_RandomPad(ds, op.curveType);
1273
0
        } else {
1274
0
            std::optional<std::string> algoString;
1275
0
            CF_CHECK_NE(algoString = Botan_detail::DigestIDToString(op.digestType.Get()), std::nullopt);
1276
1277
0
            auto hash = ::Botan::HashFunction::create(*algoString);
1278
0
            hash->update(op.cleartext.GetPtr(), op.cleartext.GetSize());
1279
0
            const auto _CT = hash->final();
1280
0
            CT = Buffer(_CT.data(), _CT.size()).ECDSA_RandomPad(ds, op.curveType);
1281
0
        }
1282
0
    }
1283
1284
0
    {
1285
0
        const ::Botan::BigInt R(op.signature.first.ToString(ds));
1286
0
        const ::Botan::BigInt S(op.signature.second.ToString(ds));
1287
1288
0
        std::unique_ptr<::Botan::ECDSA_PublicKey> pub = nullptr;
1289
0
        try {
1290
0
            pub = std::make_unique<::Botan::ECDSA_PublicKey>(*group, CT.Get(), R, S, op.id);
1291
1292
0
            ret = {
1293
0
                pub->public_point().get_affine_x().to_dec_string(),
1294
0
                pub->public_point().get_affine_y().to_dec_string()
1295
0
            };
1296
0
        } catch ( ::Botan::Invalid_State& e ) {
1297
0
        } catch ( ::Botan::Decoding_Error& ) {
1298
0
        } catch ( ::Botan::Invalid_Argument& ) {
1299
            //ret = {"0", "0"};
1300
0
        }
1301
1302
0
    }
1303
1304
0
end:
1305
0
    return ret;
1306
0
}
1307
1308
471
std::optional<component::Bignum> Botan::OpDH_Derive(operation::DH_Derive& op) {
1309
471
    std::optional<component::Bignum> ret = std::nullopt;
1310
471
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1311
1312
471
    BOTAN_FUZZER_RNG;
1313
1314
471
    try {
1315
471
        CF_CHECK_NE(op.priv.ToTrimmedString(), "0");
1316
1317
413
        const ::Botan::BigInt g(op.base.ToString(ds));
1318
413
        const ::Botan::BigInt p(op.prime.ToString(ds));
1319
413
        const ::Botan::DL_Group grp(p, g);
1320
1321
413
        const ::Botan::BigInt _priv(op.priv.ToString(ds));
1322
1323
        /* Prevent time-out */
1324
413
        CF_CHECK_LT(g.bytes(), 80);
1325
394
        CF_CHECK_LT(p.bytes(), 80);
1326
210
        CF_CHECK_LT(_priv.bytes(), 80);
1327
1328
208
        std::unique_ptr<::Botan::Private_Key> priv(new ::Botan::DH_PrivateKey(rng, grp, _priv));
1329
1330
208
        const ::Botan::BigInt _pub(op.pub.ToString(ds));
1331
208
        ::Botan::DH_PublicKey pub(grp, _pub);
1332
1333
208
        std::unique_ptr<::Botan::PK_Key_Agreement> kas(new ::Botan::PK_Key_Agreement(*priv, rng, "Raw"));
1334
208
        const auto derived_key = kas->derive_key(0, pub.public_value());
1335
1336
208
        const auto derived_str = ::Botan::BigInt(derived_key.bits_of()).to_dec_string();
1337
208
        if ( derived_str != "0" ) {
1338
47
            ret = derived_str;
1339
47
        }
1340
208
    } catch ( ... ) { }
1341
1342
471
end:
1343
471
    return ret;
1344
471
}
1345
1346
783
std::optional<component::ECC_Point> Botan::OpECC_Point_Add(operation::ECC_Point_Add& op) {
1347
783
    std::optional<component::ECC_Point> ret = std::nullopt;
1348
783
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1349
1350
783
    BOTAN_FUZZER_RNG;
1351
1352
783
    std::unique_ptr<::Botan::EC_Group> group = nullptr;
1353
783
    std::unique_ptr<::Botan::PointGFp> a, b;
1354
1355
783
    {
1356
783
        std::optional<std::string> curveString;
1357
783
        CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
1358
758
        group = std::make_unique<::Botan::EC_Group>(*curveString);
1359
758
    }
1360
1361
0
    {
1362
        /* A */
1363
758
        {
1364
758
            const auto a_x = ::Botan::BigInt(op.a.first.ToString(ds));
1365
758
            CF_CHECK_GTE(a_x, 0);
1366
1367
751
            const auto a_y = ::Botan::BigInt(op.a.second.ToString(ds));
1368
751
            CF_CHECK_GTE(a_y, 0);
1369
1370
750
            try {
1371
750
                a = std::make_unique<::Botan::PointGFp>(group->point(a_x, a_y));
1372
750
            } catch ( ::Botan::Invalid_Argument ) {
1373
25
                goto end;
1374
25
            }
1375
725
            CF_CHECK_TRUE(a->on_the_curve());
1376
60
        }
1377
1378
        /* B */
1379
0
        {
1380
60
            const auto b_x = ::Botan::BigInt(op.b.first.ToString(ds));
1381
60
            CF_CHECK_GTE(b_x, 0);
1382
1383
59
            const auto b_y = ::Botan::BigInt(op.b.second.ToString(ds));
1384
59
            CF_CHECK_GTE(b_y, 0);
1385
1386
58
            try {
1387
58
                b = std::make_unique<::Botan::PointGFp>(group->point(b_x, b_y));
1388
58
            } catch ( ::Botan::Invalid_Argument ) {
1389
6
                goto end;
1390
6
            }
1391
1392
52
            CF_CHECK_TRUE(b->on_the_curve());
1393
34
        }
1394
1395
0
        const bool is_negation = *a == -(*b);
1396
1397
34
        ::Botan::PointGFp _res = *a + *b;
1398
1399
34
        const bool is_zero = _res.is_zero();
1400
1401
        /* If A is a negation of B, then addition of both should result in point at infinity */
1402
        /* Otherwise, it should result in non-infinity. */
1403
34
        CF_ASSERT(is_zero == is_negation, "Unexpected point addition result");
1404
34
        CF_CHECK_FALSE(is_zero);
1405
1406
31
        const auto x = _res.get_affine_x();
1407
31
        const auto y = _res.get_affine_y();
1408
1409
31
        ret = {
1410
31
            util::HexToDec(x.to_hex_string()),
1411
31
            util::HexToDec(y.to_hex_string()),
1412
31
        };
1413
1414
31
    }
1415
1416
783
end:
1417
783
    return ret;
1418
31
}
1419
1420
711
std::optional<component::ECC_Point> Botan::OpECC_Point_Mul(operation::ECC_Point_Mul& op) {
1421
711
    std::optional<component::ECC_Point> ret = std::nullopt;
1422
711
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1423
1424
711
    BOTAN_FUZZER_RNG;
1425
1426
711
    std::unique_ptr<::Botan::EC_Group> group = nullptr;
1427
1428
711
    {
1429
711
        std::optional<std::string> curveString;
1430
711
        CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
1431
684
        group = std::make_unique<::Botan::EC_Group>(*curveString);
1432
684
    }
1433
1434
684
    try {
1435
684
        const auto a_x = ::Botan::BigInt(op.a.first.ToString(ds));
1436
684
        CF_CHECK_GTE(a_x, 0);
1437
1438
674
        const auto a_y = ::Botan::BigInt(op.a.second.ToString(ds));
1439
674
        CF_CHECK_GTE(a_y, 0);
1440
1441
671
        const auto a = group->point(a_x, a_y);
1442
671
        CF_CHECK_TRUE(a.on_the_curve());
1443
1444
184
        const auto b = ::Botan::BigInt(op.b.ToString(ds));
1445
1446
184
        CF_CHECK_GTE(b, 0);
1447
1448
183
        std::vector<::Botan::BigInt> ws(::Botan::PointGFp::WORKSPACE_SIZE);
1449
1450
183
        bool useBlinding = false;
1451
183
#if defined(CRYPTOFUZZ_BOTAN_IS_ORACLE)
1452
183
        try {
1453
183
            useBlinding = ds.Get<bool>();
1454
183
        } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
1455
183
#endif
1456
1457
183
        ::Botan::PointGFp _res;
1458
1459
149
        if ( useBlinding == false ) {
1460
104
            _res = a * b;
1461
104
        } else {
1462
45
            _res = group->blinded_var_point_multiply(a, b, rng, ws);
1463
45
        }
1464
1465
149
        const auto x = _res.get_affine_x();
1466
149
        const auto y = _res.get_affine_y();
1467
1468
149
        ret = {
1469
149
            util::HexToDec(x.to_hex_string()),
1470
149
            util::HexToDec(y.to_hex_string()),
1471
149
        };
1472
1473
149
    } catch ( ... ) { }
1474
1475
711
end:
1476
711
    return ret;
1477
684
}
1478
1479
0
std::optional<component::ECC_Point> Botan::OpECC_Point_Neg(operation::ECC_Point_Neg& op) {
1480
0
    std::optional<component::ECC_Point> ret = std::nullopt;
1481
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1482
1483
0
    std::unique_ptr<::Botan::EC_Group> group = nullptr;
1484
1485
0
    {
1486
0
        std::optional<std::string> curveString;
1487
0
        CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
1488
0
        group = std::make_unique<::Botan::EC_Group>(*curveString);
1489
0
    }
1490
1491
0
    try {
1492
0
        const auto a_x = ::Botan::BigInt(op.a.first.ToString(ds));
1493
0
        CF_CHECK_GTE(a_x, 0);
1494
1495
0
        const auto a_y = ::Botan::BigInt(op.a.second.ToString(ds));
1496
0
        CF_CHECK_GTE(a_y, 0);
1497
1498
0
        const auto a = group->point(a_x, a_y);
1499
0
        CF_CHECK_TRUE(a.on_the_curve());
1500
1501
0
        const ::Botan::PointGFp _res = -a;
1502
1503
0
        const auto x = _res.get_affine_x();
1504
0
        const auto y = _res.get_affine_y();
1505
1506
0
        ret = {
1507
0
            util::HexToDec(x.to_hex_string()),
1508
0
            util::HexToDec(y.to_hex_string()),
1509
0
        };
1510
1511
0
    } catch ( ... ) { }
1512
1513
0
end:
1514
0
    return ret;
1515
0
}
1516
1517
0
std::optional<component::ECC_Point> Botan::OpECC_Point_Dbl(operation::ECC_Point_Dbl& op) {
1518
0
    std::optional<component::ECC_Point> ret = std::nullopt;
1519
0
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1520
1521
0
    std::unique_ptr<::Botan::EC_Group> group = nullptr;
1522
1523
0
    {
1524
0
        std::optional<std::string> curveString;
1525
0
        CF_CHECK_NE(curveString = Botan_detail::CurveIDToString(op.curveType.Get()), std::nullopt);
1526
0
        group = std::make_unique<::Botan::EC_Group>(*curveString);
1527
0
    }
1528
1529
0
    try {
1530
0
        const auto a_x = ::Botan::BigInt(op.a.first.ToString(ds));
1531
0
        CF_CHECK_GTE(a_x, 0);
1532
1533
0
        const auto a_y = ::Botan::BigInt(op.a.second.ToString(ds));
1534
0
        CF_CHECK_GTE(a_y, 0);
1535
1536
0
        const auto a = group->point(a_x, a_y);
1537
0
        CF_CHECK_TRUE(a.on_the_curve());
1538
1539
0
        const ::Botan::PointGFp _res = a + a;
1540
1541
0
        const auto x = _res.get_affine_x();
1542
0
        const auto y = _res.get_affine_y();
1543
1544
0
        ret = {
1545
0
            util::HexToDec(x.to_hex_string()),
1546
0
            util::HexToDec(y.to_hex_string()),
1547
0
        };
1548
1549
0
    } catch ( ... ) { }
1550
1551
0
end:
1552
0
    return ret;
1553
0
}
1554
1555
13.8k
std::optional<component::Bignum> Botan::OpBignumCalc(operation::BignumCalc& op) {
1556
13.8k
    std::optional<component::Bignum> ret = std::nullopt;
1557
1558
13.8k
    if ( op.modulo ) {
1559
0
        switch ( op.calcOp.Get() ) {
1560
0
            case    CF_CALCOP("Add(A,B)"):
1561
0
            case    CF_CALCOP("Bit(A,B)"):
1562
0
            case    CF_CALCOP("CondSet(A,B)"):
1563
0
            case    CF_CALCOP("Exp(A,B)"):
1564
0
            case    CF_CALCOP("InvMod(A,B)"):
1565
0
            case    CF_CALCOP("IsEq(A,B)"):
1566
0
            case    CF_CALCOP("IsEven(A)"):
1567
0
            case    CF_CALCOP("IsOdd(A)"):
1568
0
            case    CF_CALCOP("IsOne(A)"):
1569
0
            case    CF_CALCOP("IsZero(A)"):
1570
0
            case    CF_CALCOP("LShift1(A)"):
1571
0
            case    CF_CALCOP("Mul(A,B)"):
1572
0
            case    CF_CALCOP("Not(A)"):
1573
0
            case    CF_CALCOP("NumBits(A)"):
1574
0
            case    CF_CALCOP("RShift(A,B)"):
1575
0
            case    CF_CALCOP("Set(A)"):
1576
0
            case    CF_CALCOP("Sqr(A)"):
1577
0
            case    CF_CALCOP("Sqrt(A)"):
1578
0
            case    CF_CALCOP("Sub(A,B)"):
1579
0
                break;
1580
0
            default:
1581
0
                return ret;
1582
0
        }
1583
0
    }
1584
13.8k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
1585
1586
13.8k
    Botan_bignum::Bignum res(&ds, "0");
1587
13.8k
    std::vector<Botan_bignum::Bignum> bn{
1588
13.8k
        Botan_bignum::Bignum(&ds, op.bn0.ToString(ds)),
1589
13.8k
        Botan_bignum::Bignum(&ds, op.bn1.ToString(ds)),
1590
13.8k
        Botan_bignum::Bignum(&ds, op.bn2.ToString(ds)),
1591
13.8k
        Botan_bignum::Bignum(&ds, op.bn3.ToString(ds))
1592
13.8k
    };
1593
13.8k
    std::unique_ptr<Botan_bignum::Operation> opRunner = nullptr;
1594
1595
13.8k
    switch ( op.calcOp.Get() ) {
1596
101
        case    CF_CALCOP("Add(A,B)"):
1597
101
            opRunner = std::make_unique<Botan_bignum::Add>();
1598
101
            break;
1599
205
        case    CF_CALCOP("Sub(A,B)"):
1600
205
            opRunner = std::make_unique<Botan_bignum::Sub>();
1601
205
            break;
1602
104
        case    CF_CALCOP("Mul(A,B)"):
1603
104
            opRunner = std::make_unique<Botan_bignum::Mul>();
1604
104
            break;
1605
27
        case    CF_CALCOP("Div(A,B)"):
1606
27
            opRunner = std::make_unique<Botan_bignum::Div>();
1607
27
            break;
1608
48
        case    CF_CALCOP("Mod(A,B)"):
1609
48
            opRunner = std::make_unique<Botan_bignum::Mod>();
1610
48
            break;
1611
1.38k
        case    CF_CALCOP("ExpMod(A,B,C)"):
1612
            /* Too slow with larger values */
1613
1.38k
            CF_CHECK_LT(op.bn0.GetSize(), 1000);
1614
1.33k
            CF_CHECK_LT(op.bn1.GetSize(), 1000);
1615
1.32k
            CF_CHECK_LT(op.bn2.GetSize(), 1000);
1616
1617
1.32k
            opRunner = std::make_unique<Botan_bignum::ExpMod>();
1618
1.32k
            break;
1619
6
        case    CF_CALCOP("Exp(A,B)"):
1620
6
            opRunner = std::make_unique<Botan_bignum::Exp>();
1621
6
            break;
1622
212
        case    CF_CALCOP("Sqr(A)"):
1623
212
            opRunner = std::make_unique<Botan_bignum::Sqr>();
1624
212
            break;
1625
489
        case    CF_CALCOP("GCD(A,B)"):
1626
489
            opRunner = std::make_unique<Botan_bignum::GCD>();
1627
489
            break;
1628
77
        case    CF_CALCOP("SqrMod(A,B)"):
1629
77
            opRunner = std::make_unique<Botan_bignum::SqrMod>();
1630
77
            break;
1631
942
        case    CF_CALCOP("InvMod(A,B)"):
1632
942
            opRunner = std::make_unique<Botan_bignum::InvMod>();
1633
942
            break;
1634
64
        case    CF_CALCOP("Cmp(A,B)"):
1635
64
            opRunner = std::make_unique<Botan_bignum::Cmp>();
1636
64
            break;
1637
195
        case    CF_CALCOP("LCM(A,B)"):
1638
195
            opRunner = std::make_unique<Botan_bignum::LCM>();
1639
195
            break;
1640
5
        case    CF_CALCOP("Abs(A)"):
1641
5
            opRunner = std::make_unique<Botan_bignum::Abs>();
1642
5
            break;
1643
161
        case    CF_CALCOP("Jacobi(A,B)"):
1644
161
            opRunner = std::make_unique<Botan_bignum::Jacobi>();
1645
161
            break;
1646
16
        case    CF_CALCOP("Neg(A)"):
1647
16
            opRunner = std::make_unique<Botan_bignum::Neg>();
1648
16
            break;
1649
200
        case    CF_CALCOP("IsPrime(A)"):
1650
200
            opRunner = std::make_unique<Botan_bignum::IsPrime>();
1651
200
            break;
1652
193
        case    CF_CALCOP("RShift(A,B)"):
1653
193
            opRunner = std::make_unique<Botan_bignum::RShift>();
1654
193
            break;
1655
10
        case    CF_CALCOP("LShift1(A)"):
1656
10
            opRunner = std::make_unique<Botan_bignum::LShift1>();
1657
10
            break;
1658
4
        case    CF_CALCOP("IsNeg(A)"):
1659
4
            opRunner = std::make_unique<Botan_bignum::IsNeg>();
1660
4
            break;
1661
25
        case    CF_CALCOP("IsEq(A,B)"):
1662
25
            opRunner = std::make_unique<Botan_bignum::IsEq>();
1663
25
            break;
1664
91
        case    CF_CALCOP("IsGt(A,B)"):
1665
91
            opRunner = std::make_unique<Botan_bignum::IsGt>();
1666
91
            break;
1667
116
        case    CF_CALCOP("IsGte(A,B)"):
1668
116
            opRunner = std::make_unique<Botan_bignum::IsGte>();
1669
116
            break;
1670
36
        case    CF_CALCOP("IsLt(A,B)"):
1671
36
            opRunner = std::make_unique<Botan_bignum::IsLt>();
1672
36
            break;
1673
273
        case    CF_CALCOP("IsLte(A,B)"):
1674
273
            opRunner = std::make_unique<Botan_bignum::IsLte>();
1675
273
            break;
1676
8
        case    CF_CALCOP("IsEven(A)"):
1677
8
            opRunner = std::make_unique<Botan_bignum::IsEven>();
1678
8
            break;
1679
10
        case    CF_CALCOP("IsOdd(A)"):
1680
10
            opRunner = std::make_unique<Botan_bignum::IsOdd>();
1681
10
            break;
1682
12
        case    CF_CALCOP("IsZero(A)"):
1683
12
            opRunner = std::make_unique<Botan_bignum::IsZero>();
1684
12
            break;
1685
2
        case    CF_CALCOP("IsNotZero(A)"):
1686
2
            opRunner = std::make_unique<Botan_bignum::IsNotZero>();
1687
2
            break;
1688
43
        case    CF_CALCOP("IsOne(A)"):
1689
43
            opRunner = std::make_unique<Botan_bignum::IsOne>();
1690
43
            break;
1691
46
        case    CF_CALCOP("MulMod(A,B,C)"):
1692
46
            opRunner = std::make_unique<Botan_bignum::MulMod>();
1693
46
            break;
1694
67
        case    CF_CALCOP("Bit(A,B)"):
1695
67
            opRunner = std::make_unique<Botan_bignum::Bit>();
1696
67
            break;
1697
12
        case    CF_CALCOP("CmpAbs(A,B)"):
1698
12
            opRunner = std::make_unique<Botan_bignum::CmpAbs>();
1699
12
            break;
1700
56
        case    CF_CALCOP("SetBit(A,B)"):
1701
56
            opRunner = std::make_unique<Botan_bignum::SetBit>();
1702
56
            break;
1703
12
        case    CF_CALCOP("Mod_NIST_192(A)"):
1704
12
            opRunner = std::make_unique<Botan_bignum::Mod_NIST_192>();
1705
12
            break;
1706
9
        case    CF_CALCOP("Mod_NIST_224(A)"):
1707
9
            opRunner = std::make_unique<Botan_bignum::Mod_NIST_224>();
1708
9
            break;
1709
17
        case    CF_CALCOP("Mod_NIST_256(A)"):
1710
17
            opRunner = std::make_unique<Botan_bignum::Mod_NIST_256>();
1711
17
            break;
1712
8
        case    CF_CALCOP("Mod_NIST_384(A)"):
1713
8
            opRunner = std::make_unique<Botan_bignum::Mod_NIST_384>();
1714
8
            break;
1715
13
        case    CF_CALCOP("Mod_NIST_521(A)"):
1716
13
            opRunner = std::make_unique<Botan_bignum::Mod_NIST_521>();
1717
13
            break;
1718
10
        case    CF_CALCOP("ClearBit(A,B)"):
1719
10
            opRunner = std::make_unique<Botan_bignum::ClearBit>();
1720
10
            break;
1721
81
        case    CF_CALCOP("MulAdd(A,B,C)"):
1722
81
            opRunner = std::make_unique<Botan_bignum::MulAdd>();
1723
81
            break;
1724
207
        case    CF_CALCOP("MulDiv(A,B,C)"):
1725
207
            opRunner = std::make_unique<Botan_bignum::MulDiv>();
1726
207
            break;
1727
48
        case    CF_CALCOP("MulDivCeil(A,B,C)"):
1728
48
            opRunner = std::make_unique<Botan_bignum::MulDivCeil>();
1729
48
            break;
1730
69
        case    CF_CALCOP("Exp2(A)"):
1731
69
            opRunner = std::make_unique<Botan_bignum::Exp2>();
1732
69
            break;
1733
89
        case    CF_CALCOP("NumLSZeroBits(A)"):
1734
89
            opRunner = std::make_unique<Botan_bignum::NumLSZeroBits>();
1735
89
            break;
1736
426
        case    CF_CALCOP("Sqrt(A)"):
1737
426
            if ( op.modulo == std::nullopt ) {
1738
426
                opRunner = std::make_unique<Botan_bignum::Sqrt>();
1739
426
            } else {
1740
0
                opRunner = std::make_unique<Botan_bignum::Ressol>();
1741
0
            }
1742
426
            break;
1743
32
        case    CF_CALCOP("AddMod(A,B,C)"):
1744
32
            opRunner = std::make_unique<Botan_bignum::AddMod>();
1745
32
            break;
1746
176
        case    CF_CALCOP("SubMod(A,B,C)"):
1747
176
            opRunner = std::make_unique<Botan_bignum::SubMod>();
1748
176
            break;
1749
4
        case    CF_CALCOP("NumBits(A)"):
1750
4
            opRunner = std::make_unique<Botan_bignum::NumBits>();
1751
4
            break;
1752
70
        case    CF_CALCOP("Set(A)"):
1753
70
            opRunner = std::make_unique<Botan_bignum::Set>();
1754
70
            break;
1755
84
        case    CF_CALCOP("CondSet(A,B)"):
1756
84
            opRunner = std::make_unique<Botan_bignum::CondSet>();
1757
84
            break;
1758
        /*
1759
        case    CF_CALCOP("Ressol(A,B)"):
1760
            opRunner = std::make_unique<Botan_bignum::Ressol>();
1761
            break;
1762
        */
1763
5
        case    CF_CALCOP("Not(A)"):
1764
5
            opRunner = std::make_unique<Botan_bignum::Not>();
1765
5
            break;
1766
303
        case    CF_CALCOP("Prime()"):
1767
303
            opRunner = std::make_unique<Botan_bignum::Prime>();
1768
303
            break;
1769
13.8k
    }
1770
1771
13.7k
    CF_CHECK_NE(opRunner, nullptr);
1772
1773
6.84k
#if defined(CRYPTOFUZZ_BOTAN_IS_ORACLE)
1774
6.84k
    try {
1775
6.84k
#endif
1776
6.84k
        CF_CHECK_EQ(opRunner->Run(
1777
6.84k
                    ds,
1778
6.84k
                    res,
1779
6.84k
                    bn,
1780
6.84k
                    op.modulo ?
1781
6.84k
                        std::optional<Botan_bignum::Bignum>(Botan_bignum::Bignum(op.modulo->ToTrimmedString())) :
1782
6.84k
                        std::nullopt), true);
1783
6.26k
#if defined(CRYPTOFUZZ_BOTAN_IS_ORACLE)
1784
6.26k
    } catch ( ... ) {
1785
0
        goto end;
1786
0
    }
1787
0
#endif
1788
1789
6.26k
    ret = { util::HexToDec(res.Ref().to_hex_string()) };
1790
1791
13.8k
end:
1792
13.8k
    return ret;
1793
6.26k
}
1794
1795
0
bool Botan::SupportsModularBignumCalc(void) const {
1796
0
    return true;
1797
0
}
1798
1799
} /* namespace module */
1800
} /* namespace cryptofuzz */