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