Coverage Report

Created: 2025-03-09 06:52

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