Coverage Report

Created: 2023-02-22 06:39

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