Coverage Report

Created: 2023-09-25 06:33

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