Coverage Report

Created: 2023-02-22 06:14

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