Coverage Report

Created: 2023-02-22 06:14

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