Coverage Report

Created: 2024-09-11 06:39

/src/cryptofuzz/util.cpp
Line
Count
Source (jump to first uncovered line)
1
#include <cryptofuzz/util.h>
2
#include <cryptofuzz/util_hexdump.h>
3
#include <cryptofuzz/repository.h>
4
#include <cryptofuzz/crypto.h>
5
#include <fuzzing/datasource/id.hpp>
6
#include <iomanip>
7
#include <map>
8
#include <sstream>
9
#include <vector>
10
#include <cstdlib>
11
#include <algorithm>
12
#include <boost/algorithm/string/join.hpp>
13
#include <boost/multiprecision/cpp_int.hpp>
14
#include <boost/algorithm/hex.hpp>
15
#if defined(__x86_64__) || defined(__amd64__)
16
  #include "third_party/cpu_features/include/cpuinfo_x86.h"
17
#endif
18
#include "mutatorpool.h"
19
#include "config.h"
20
21
uint32_t PRNG(void);
22
23
extern "C" {
24
    sigjmp_buf cryptofuzz_jmpbuf;
25
    unsigned char cryptofuzz_longjmp_triggered = 0;
26
}
27
28
namespace cryptofuzz {
29
namespace util {
30
31
0
Multipart CipherInputTransform(fuzzing::datasource::Datasource& ds, component::SymmetricCipherType cipherType, const uint8_t* in, const size_t inSize) {
32
0
    if ( repository::IsXTS( cipherType.Get() ) ) {
33
        /* XTS does not support chunked updating.
34
         * See: https://github.com/openssl/openssl/issues/8699
35
         */
36
0
        return { { in, inSize} };
37
0
    } else if ( repository::IsCCM( cipherType.Get() ) ) {
38
        /* CCM does not support chunked updating.
39
         * See: https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_CCM_mode
40
         */
41
0
        return { { in, inSize} };
42
0
    } else {
43
0
        return util::ToParts(ds, in, inSize);
44
0
    }
45
0
}
46
47
0
Multipart CipherInputTransform(fuzzing::datasource::Datasource& ds, component::SymmetricCipherType cipherType, uint8_t* out, const size_t outSize, const uint8_t* in, const size_t inSize) {
48
0
    return CipherInputTransform(
49
0
        ds,
50
0
        cipherType,
51
0
        util::ToInPlace(ds, out, outSize, in, inSize),
52
0
        inSize);
53
0
}
54
55
0
const uint8_t* ToInPlace(fuzzing::datasource::Datasource& ds, uint8_t* out, const size_t outSize, const uint8_t* in, const size_t inSize) {
56
0
    bool inPlace = false;
57
58
0
    if ( outSize >= inSize ) {
59
0
        try {
60
0
            inPlace = ds.Get<bool>();
61
0
        } catch ( fuzzing::datasource::Datasource::OutOfData& ) {
62
0
        }
63
0
    }
64
65
0
    if ( inPlace == true && inSize > 0 ) {
66
0
        memcpy(out, in, inSize);
67
0
    }
68
69
0
    return inPlace ? out : in;
70
0
}
71
72
6.32k
static std::vector<size_t> Split(fuzzing::datasource::Datasource& ds, size_t N) {
73
6.32k
    std::vector<size_t> ret;
74
75
6.32k
    try {
76
529k
        while ( N ) {
77
522k
            ret.push_back( ds.Get<uint64_t>() % N );
78
522k
            N -= ret.back();
79
522k
        }
80
6.32k
    } catch ( fuzzing::datasource::Datasource::OutOfData& ) {
81
6.11k
    }
82
83
6.32k
    ret.push_back(N);
84
85
6.32k
    return ret;
86
6.32k
}
87
88
0
Multipart ToParts(fuzzing::datasource::Datasource& ds, const std::vector<uint8_t>& buffer, const size_t blocksize) {
89
0
    return ToParts(ds, buffer.data(), buffer.size(), blocksize);
90
0
}
91
92
6.06k
Multipart ToParts(fuzzing::datasource::Datasource& ds, const Buffer& buffer, const size_t blocksize) {
93
6.06k
    return ToParts(ds, buffer.GetPtr(), buffer.GetSize(), blocksize);
94
6.06k
}
95
96
6.32k
Multipart ToParts(fuzzing::datasource::Datasource& ds, const uint8_t* data, const size_t size, const size_t blocksize) {
97
6.32k
    const bool blocks = blocksize != 0;
98
6.32k
    const auto parts = Split(ds, !blocks ? size : size / blocksize);
99
6.32k
    Multipart ret;
100
6.32k
    size_t curPos = 0;
101
522k
    for (const auto& p : parts) {
102
522k
        const size_t n = !blocks ? p : blocksize * p;
103
522k
        ret.push_back({data + curPos, n});
104
522k
        curPos += n;
105
522k
    }
106
6.32k
    if ( curPos < size ) {
107
0
        ret.push_back({data + curPos, size - curPos});
108
0
    }
109
6.32k
    return ret;
110
6.32k
}
111
112
0
Multipart ToEqualParts(const Buffer& buffer, const size_t partSize) {
113
0
    return ToEqualParts(buffer.GetPtr(), buffer.GetSize(), partSize);
114
0
}
115
116
0
Multipart ToEqualParts(const uint8_t* data, const size_t size, const size_t partSize) {
117
0
    Multipart ret;
118
119
0
    const size_t numParts = size / partSize;
120
121
0
    for (size_t i = 0; i < numParts; i++) {
122
0
        ret.push_back( {data + (i*partSize), partSize} );
123
0
    }
124
125
0
    const size_t remainder = size % partSize;
126
127
0
    ret.push_back( {data + size - remainder, remainder} );
128
129
0
    return ret;
130
0
}
131
132
0
std::vector<uint8_t> Pkcs7Pad(std::vector<uint8_t> in, const size_t blocksize) {
133
0
    size_t numPadBytes = blocksize - (in.size() % blocksize);
134
135
0
    const uint8_t padByte = static_cast<uint8_t>(numPadBytes);
136
0
    for (size_t i = 0; i < numPadBytes; i++) {
137
0
        in.push_back(padByte);
138
0
    }
139
140
0
    return in;
141
0
}
142
143
0
std::optional<std::vector<uint8_t>> Pkcs7Unpad(std::vector<uint8_t> in, const size_t blocksize) {
144
0
    if ( in.size() == 0 || (in.size() % blocksize) != 0 ) {
145
0
        return std::nullopt;
146
0
    }
147
148
0
    const auto numPadBytes = static_cast<size_t>(in.back());
149
150
0
    if ( numPadBytes > in.size() ) {
151
0
        return std::nullopt;
152
0
    }
153
154
0
    return std::vector<uint8_t>(in.data(), in.data() + in.size() - numPadBytes);
155
0
}
156
157
0
std::string HexDump(const void *_data, const size_t len, const std::string description) {
158
0
    unsigned char *data = (unsigned char*)_data;
159
160
0
    std::stringstream ss;
161
162
0
    if ( description.size() > 0 ) {
163
0
        ss << description << " = ";
164
0
    }
165
166
0
    ss << "{";
167
0
    for (size_t i = 0; i < len; i++) {
168
0
        if ((i % 16) == 0 && i != 0) {
169
0
            ss << std::endl;
170
0
        }
171
0
        if ( (i % 16) == 0 && i != 0 ) {
172
0
            size_t padding;
173
0
            if ( description.size() > 0 ) {
174
0
                padding = description.size() + 4;
175
0
            } else {
176
0
                padding = 1;
177
0
            }
178
0
            for (size_t j = 0; j < padding; j++) {
179
0
                ss << " ";
180
0
            }
181
0
        }
182
0
        ss << "0x" << std::setw(2) << std::setfill('0') << std::hex << (int)(data[i]);
183
0
        if ( i == len - 1 ) {
184
0
            ss << "} (" << std::dec << len << " bytes)";
185
0
        } else {
186
0
            ss << ", ";
187
0
        }
188
0
    }
189
0
    if ( len == 0 ) {
190
0
        ss << "}";
191
0
    }
192
193
0
    return ss.str();
194
0
}
195
196
0
std::string HexDump(std::vector<uint8_t> data, const std::string description) {
197
0
    return HexDump(data.data(), data.size(), description);
198
0
}
199
200
0
std::string ToString(const Buffer& buffer) {
201
0
    return HexDump(buffer.Get());
202
0
}
203
204
0
std::string ToString(const bool val) {
205
0
    return val ? "true" : "false";
206
0
}
207
208
0
std::string ToString(const component::Ciphertext& ciphertext) {
209
0
    std::string ret;
210
211
0
    ret += util::HexDump(ciphertext.ciphertext.GetPtr(), ciphertext.ciphertext.GetSize(), "ciphertext");
212
213
0
    ret += "\n";
214
215
0
    if ( ciphertext.tag != std::nullopt ) {
216
0
        ret += util::HexDump(ciphertext.tag->GetPtr(), ciphertext.tag->GetSize(), "tag");
217
0
    } else {
218
0
        ret += "(tag is nullopt)";
219
0
    }
220
221
0
    return ret;
222
0
}
223
224
0
std::string ToString(const component::ECC_PublicKey& val) {
225
0
    std::string ret;
226
227
0
    ret += "X: ";
228
0
    ret += val.first.ToString();
229
0
    ret += "\n";
230
231
0
    ret += "Y: ";
232
0
    ret += val.second.ToString();
233
0
    ret += "\n";
234
235
0
    return ret;
236
0
}
237
238
0
std::string ToString(const component::ECC_KeyPair& val) {
239
0
    std::string ret;
240
241
0
    ret += "Priv: ";
242
0
    ret += val.priv.ToString();
243
0
    ret += "\n";
244
245
0
    ret += "X: ";
246
0
    ret += val.pub.first.ToString();
247
0
    ret += "\n";
248
249
0
    ret += "Y: ";
250
0
    ret += val.pub.second.ToString();
251
0
    ret += "\n";
252
253
0
    return ret;
254
0
}
255
256
0
std::string ToString(const component::ECCSI_Signature& val) {
257
0
    std::string ret;
258
259
0
    ret += "X: ";
260
0
    ret += val.pub.first.ToString();
261
0
    ret += "\n";
262
263
0
    ret += "Y: ";
264
0
    ret += val.pub.second.ToString();
265
0
    ret += "\n";
266
267
0
    ret += "PVT X: ";
268
0
    ret += val.pvt.first.ToString();
269
0
    ret += "\n";
270
271
0
    ret += "PVT Y: ";
272
0
    ret += val.pvt.second.ToString();
273
0
    ret += "\n";
274
275
0
    ret += "R: ";
276
0
    ret += val.signature.first.ToString();
277
0
    ret += "\n";
278
279
0
    ret += "S: ";
280
0
    ret += val.signature.second.ToString();
281
0
    ret += "\n";
282
283
0
    return ret;
284
0
}
285
286
0
std::string ToString(const component::ECDSA_Signature& val) {
287
0
    std::string ret;
288
289
0
    ret += "X: ";
290
0
    ret += val.pub.first.ToString();
291
0
    ret += "\n";
292
293
0
    ret += "Y: ";
294
0
    ret += val.pub.second.ToString();
295
0
    ret += "\n";
296
297
0
    ret += "R: ";
298
0
    ret += val.signature.first.ToString();
299
0
    ret += "\n";
300
301
0
    ret += "S: ";
302
0
    ret += val.signature.second.ToString();
303
0
    ret += "\n";
304
305
0
    return ret;
306
0
}
307
308
0
std::string ToString(const component::BLS_Signature& val) {
309
0
    std::string ret;
310
311
0
    ret += "Pub X: ";
312
0
    ret += val.pub.first.ToString();
313
0
    ret += "\n";
314
315
0
    ret += "Pub Y: ";
316
0
    ret += val.pub.second.ToString();
317
0
    ret += "\n";
318
319
0
    ret += "Sig v: ";
320
0
    ret += val.signature.first.first.ToString();
321
0
    ret += "\n";
322
323
0
    ret += "Sig w: ";
324
0
    ret += val.signature.first.second.ToString();
325
0
    ret += "\n";
326
327
0
    ret += "Sig x: ";
328
0
    ret += val.signature.second.first.ToString();
329
0
    ret += "\n";
330
331
0
    ret += "Sig y: ";
332
0
    ret += val.signature.second.second.ToString();
333
0
    ret += "\n";
334
335
0
    return ret;
336
0
}
337
338
0
std::string ToString(const component::BLS_BatchSignature& val) {
339
0
    std::string ret;
340
341
0
    for (const auto& cur : val.msgpub) {
342
0
        ret += "G1 X: ";
343
0
        ret += cur.first.first.ToString();
344
0
        ret += "\n";
345
0
        ret += "G1 Y: ";
346
0
        ret += cur.first.second.ToString();
347
0
        ret += "\n";
348
349
0
        ret += "\n";
350
351
0
        ret += "G2 V: ";
352
0
        ret += cur.second.first.first.ToString();
353
0
        ret += "\n";
354
0
        ret += "G2 W: ";
355
0
        ret += cur.second.first.second.ToString();
356
0
        ret += "\n";
357
0
        ret += "G2 X: ";
358
0
        ret += cur.second.second.first.ToString();
359
0
        ret += "\n";
360
0
        ret += "G2 Y: ";
361
0
        ret += cur.second.second.second.ToString();
362
0
        ret += "\n";
363
364
0
        ret += "----------";
365
0
        ret += "\n";
366
0
    }
367
0
    return ret;
368
0
}
369
370
0
std::string ToString(const component::BLS_KeyPair& val) {
371
0
    std::string ret;
372
373
0
    ret += "Priv : ";
374
0
    ret += val.priv.ToString();
375
0
    ret += "\n";
376
377
0
    ret += "Pub X: ";
378
0
    ret += val.pub.first.ToString();
379
0
    ret += "\n";
380
381
0
    ret += "Pub Y: ";
382
0
    ret += val.pub.second.ToString();
383
0
    ret += "\n";
384
385
0
    return ret;
386
0
}
387
388
0
std::string ToString(const component::Bignum& val) {
389
0
    return val.ToString();
390
0
}
391
392
0
std::string ToString(const component::G2& val) {
393
0
    std::string ret;
394
395
0
    ret += "X1: ";
396
0
    ret += val.first.first.ToString();
397
0
    ret += "\n";
398
399
0
    ret += "Y1: ";
400
0
    ret += val.first.second.ToString();
401
0
    ret += "\n";
402
403
0
    ret += "X2: ";
404
0
    ret += val.second.first.ToString();
405
0
    ret += "\n";
406
407
0
    ret += "Y2: ";
408
0
    ret += val.second.second.ToString();
409
0
    ret += "\n";
410
411
0
    return ret;
412
0
}
413
414
0
std::string ToString(const component::Fp12& val) {
415
0
    std::string ret;
416
417
0
    ret += "bn1: " + val.bn1.ToString() + "\n";
418
0
    ret += "bn2: " + val.bn2.ToString() + "\n";
419
0
    ret += "bn3: " + val.bn3.ToString() + "\n";
420
0
    ret += "bn4: " + val.bn4.ToString() + "\n";
421
0
    ret += "bn5: " + val.bn5.ToString() + "\n";
422
0
    ret += "bn6: " + val.bn6.ToString() + "\n";
423
0
    ret += "bn7: " + val.bn7.ToString() + "\n";
424
0
    ret += "bn8: " + val.bn8.ToString() + "\n";
425
0
    ret += "bn9: " + val.bn9.ToString() + "\n";
426
0
    ret += "bn10: " + val.bn10.ToString() + "\n";
427
0
    ret += "bn11: " + val.bn11.ToString() + "\n";
428
0
    ret += "bn12: " + val.bn12.ToString() + "\n";
429
430
0
    return ret;
431
0
}
432
433
0
std::string ToString(const component::DSA_Parameters& val) {
434
0
    std::string ret;
435
436
0
    ret += "P: " + val.p.ToString() + "\n";
437
0
    ret += "Q: " + val.q.ToString() + "\n";
438
0
    ret += "G: " + val.g.ToString() + "\n";
439
440
0
    return ret;
441
0
}
442
443
0
std::string ToString(const component::DSA_Signature& val) {
444
0
    std::string ret;
445
446
0
    ret += "R: " + val.signature.first.ToString() + "\n";
447
0
    ret += "S: " + val.signature.second.ToString() + "\n";
448
0
    ret += "Pub: " + val.pub.ToString() + "\n";
449
450
0
    return ret;
451
0
}
452
453
0
std::string ToString(const component::Key3& val) {
454
0
    std::string ret;
455
456
0
    ret += "Key 1: " + ToString(val[0]) + "\n";
457
0
    ret += "Key 2: " + ToString(val[1]) + "\n";
458
0
    ret += "Key 3: " + ToString(val[2]) + "\n";
459
460
0
    return ret;
461
0
}
462
463
0
nlohmann::json ToJSON(const Buffer& buffer) {
464
0
    return buffer.ToJSON();
465
0
}
466
467
0
nlohmann::json ToJSON(const bool val) {
468
0
    return val;
469
0
}
470
471
0
nlohmann::json ToJSON(const component::Ciphertext& ciphertext) {
472
0
    nlohmann::json ret;
473
474
0
    ret["ciphertext"] = ciphertext.ciphertext.ToJSON();
475
476
0
    if ( ciphertext.tag != std::nullopt ) {
477
0
        ret["tag"] = ciphertext.tag->ToJSON();
478
0
    }
479
480
0
    return ret;
481
0
}
482
483
0
nlohmann::json ToJSON(const component::ECC_PublicKey& val) {
484
0
    return val.ToJSON();
485
0
}
486
487
0
nlohmann::json ToJSON(const component::ECC_KeyPair& val) {
488
0
    return val.ToJSON();
489
0
}
490
491
0
nlohmann::json ToJSON(const component::ECCSI_Signature& val) {
492
0
    return val.ToJSON();
493
0
}
494
495
0
nlohmann::json ToJSON(const component::ECDSA_Signature& val) {
496
0
    return val.ToJSON();
497
0
}
498
499
0
nlohmann::json ToJSON(const component::Bignum& val) {
500
0
    return val.ToJSON();
501
0
}
502
503
0
nlohmann::json ToJSON(const component::G2& val) {
504
0
    return val.ToJSON();
505
0
}
506
507
0
nlohmann::json ToJSON(const component::BLS_Signature& val) {
508
0
    return val.ToJSON();
509
0
}
510
511
0
nlohmann::json ToJSON(const component::BLS_BatchSignature& val) {
512
0
    return val.ToJSON();
513
0
}
514
515
0
nlohmann::json ToJSON(const component::BLS_KeyPair& val) {
516
0
    return val.ToJSON();
517
0
}
518
519
0
nlohmann::json ToJSON(const component::Fp12& val) {
520
0
    return val.ToJSON();
521
0
}
522
523
0
nlohmann::json ToJSON(const component::DSA_Parameters& val) {
524
0
    return val.ToJSON();
525
0
}
526
527
0
nlohmann::json ToJSON(const component::DSA_Signature& val) {
528
0
    return val.ToJSON();
529
0
}
530
531
0
nlohmann::json ToJSON(const component::Key3& val) {
532
0
    return nlohmann::json{
533
0
        val[0].ToJSON(),
534
0
        val[1].ToJSON(),
535
0
        val[2].ToJSON(),
536
0
    };
537
0
}
538
539
class HaveBadPointer {
540
    private:
541
        bool haveBadPointer = false;
542
    public:
543
6
        HaveBadPointer(void) {
544
6
            const char* env = getenv("CRYPTOFUZZ_NULL_IS_BADPTR");
545
6
            if ( env == nullptr ) {
546
6
                haveBadPointer = false;
547
6
            } else {
548
0
                haveBadPointer = true;
549
0
            }
550
6
        }
551
552
23.0k
        bool Get(void) const {
553
23.0k
            return haveBadPointer;
554
23.0k
        }
555
};
556
557
static HaveBadPointer haveBadPointer;
558
559
fuzzing::datasource::Datasource* global_ds = nullptr;
560
561
12.0k
void SetGlobalDs(fuzzing::datasource::Datasource* ds) {
562
12.0k
    CF_ASSERT(global_ds == nullptr, "global_ds was already set");
563
564
12.0k
    global_ds = ds;
565
12.0k
}
566
567
12.0k
void UnsetGlobalDs(void) {
568
12.0k
    CF_ASSERT(global_ds != nullptr, "Trying to unset empty global_ds");
569
570
12.0k
    global_ds = nullptr;
571
12.0k
}
572
573
25.7k
uint8_t* GetNullPtr(fuzzing::datasource::Datasource* ds) {
574
25.7k
    if ( global_ds != nullptr ) {
575
2.68k
        ds = global_ds;
576
2.68k
    }
577
578
25.7k
    if ( ds != nullptr ) {
579
2.68k
        try {
580
2.68k
            return ds->Get<uint8_t*>();
581
2.68k
        } catch ( fuzzing::datasource::Datasource::OutOfData& ) {
582
1.17k
            return (uint8_t*)0x12;
583
1.17k
        }
584
2.68k
    }
585
23.0k
    return haveBadPointer.Get() == true ? (uint8_t*)0x12 : nullptr;
586
25.7k
}
587
588
19.2k
uint8_t* malloc(const size_t n) {
589
19.2k
    return n == 0 ? GetNullPtr() : (uint8_t*)::malloc(n);
590
19.2k
}
591
592
0
uint8_t* realloc(void* ptr, const size_t n) {
593
0
    if ( n == 0 ) {
594
0
        free(ptr);
595
0
        return GetNullPtr();
596
0
    } else {
597
0
        if ( ptr != GetNullPtr() ) {
598
0
            return (uint8_t*)::realloc(ptr, n);
599
0
        } else {
600
0
            return malloc(n);
601
0
        }
602
0
    }
603
0
}
604
605
19.2k
void free(void* ptr) {
606
19.2k
    if ( ptr != GetNullPtr() ) {
607
19.1k
        ::free(ptr);
608
19.1k
    }
609
19.2k
}
610
611
0
bool HaveSSE42(void) {
612
0
#if defined(__x86_64__) || defined(__amd64__)
613
0
     const cpu_features::X86Info info = cpu_features::GetX86Info();
614
0
     const auto features = info.features;
615
0
     return features.sse4_2;
616
#else
617
    return false;
618
#endif
619
0
}
620
621
0
void abort(const std::vector<std::string> components) {
622
0
    const std::string joined = boost::algorithm::join(components, "-");
623
0
    printf("Assertion failure: %s\n", joined.c_str());
624
0
    fflush(stdout);
625
0
    ::abort();
626
0
}
627
628
735k
static int HexCharToDec(const char c) {
629
735k
    if ( c >= '0' && c <= '9' ) {
630
501k
        return c - '0';
631
501k
    } else if ( c >= 'a' && c <= 'f' ) {
632
21.0k
        return c - 'a' + 10;
633
212k
    } else if ( c >= 'A' && c <= 'F' ) {
634
212k
        return c - 'A' + 10;
635
212k
    } else {
636
0
        assert(0);
637
0
    }
638
735k
}
639
640
8.36k
std::string HexToDec(std::string s) {
641
8.36k
    std::string ret;
642
8.36k
    bool negative = false;
643
644
8.36k
    if ( s.empty() ) {
645
0
        return ret;
646
0
    }
647
648
8.36k
    if ( s.size() >= 1 && s[0] == '-' ) {
649
0
        s = s.substr(1);
650
0
        negative = true;
651
0
    }
652
653
8.36k
    if ( s.size() >= 2 && s[0] == '0' && s[1] == 'x' ) {
654
5.90k
        s = s.substr(2);
655
5.90k
    }
656
657
8.36k
    if ( negative == false && s.size() >= 1 && s[0] == '-' ) {
658
0
        s = s.substr(1);
659
0
        negative = true;
660
0
    }
661
662
8.36k
    boost::multiprecision::cpp_int total;
663
664
743k
    for (long i = s.size() - 1; i >= 0; i--) {
665
735k
        total += boost::multiprecision::cpp_int(HexCharToDec(s[i])) << ((s.size()-i-1)*4);
666
735k
    }
667
668
8.36k
    std::stringstream ss;
669
8.36k
    if ( negative ) ss << "-";
670
8.36k
    ss << total;
671
672
8.36k
    if ( ss.str().empty() ) {
673
0
        return "0";
674
8.36k
    } else {
675
8.36k
        return ss.str();
676
8.36k
    }
677
8.36k
}
678
679
6.32k
std::string DecToHex(std::string s, const std::optional<size_t> padTo) {
680
6.32k
    bool negative = false;
681
6.32k
    if ( s.size() && s[0] == '-' ) {
682
0
        s.erase(0, 1);
683
0
        negative = true;
684
0
    }
685
6.32k
    s.erase(0, s.find_first_not_of('0'));
686
6.32k
    boost::multiprecision::cpp_int i(s);
687
6.32k
    std::stringstream ss;
688
6.32k
    if ( negative == true ) {
689
0
        ss << "-";
690
0
    }
691
6.32k
    ss << std::hex << i;
692
6.32k
    auto ret = ss.str();
693
6.32k
    if ( ret.size() % 2 != 0 ) {
694
2.31k
        ret = "0" + ret;
695
2.31k
    }
696
6.32k
    if ( padTo != std::nullopt && ret.size() < *padTo ) {
697
0
        ret = std::string(*padTo - ret.size(), '0') + ret;
698
0
    }
699
6.32k
    return ret;
700
6.32k
}
701
702
0
std::vector<uint8_t> HexToBin(const std::string s) {
703
0
    std::vector<uint8_t> data;
704
705
0
    boost::algorithm::unhex(s, std::back_inserter(data));
706
707
0
    return data;
708
0
}
709
710
1.78k
std::optional<std::vector<uint8_t>> DecToBin(const std::string s, std::optional<size_t> size) {
711
1.78k
    if ( !s.empty() && s[0] == '-' ) {
712
0
        return std::nullopt;
713
0
    }
714
1.78k
    std::vector<uint8_t> v;
715
1.78k
    boost::multiprecision::cpp_int c(s);
716
1.78k
    boost::multiprecision::export_bits(c, std::back_inserter(v), 8);
717
1.78k
    if ( size == std::nullopt ) {
718
0
        return v;
719
0
    }
720
721
1.78k
    if ( v.size() > *size ) {
722
47
        return std::nullopt;
723
47
    }
724
1.73k
    const auto diff = *size - v.size();
725
726
1.73k
    std::vector<uint8_t> ret(*size);
727
1.73k
    if ( diff > 0 ) {
728
925
        memset(ret.data(), 0, diff);
729
925
    }
730
1.73k
    memcpy(ret.data() + diff, v.data(), v.size());
731
732
1.73k
    return ret;
733
1.78k
}
734
735
0
std::string BinToHex(const uint8_t* data, const size_t size) {
736
0
    return BinToHex(std::vector<uint8_t>(data, data + size));
737
0
}
738
739
0
std::string BinToHex(const std::vector<uint8_t> data) {
740
0
    std::string res;
741
0
    boost::algorithm::hex_lower(data.begin(), data.end(), back_inserter(res));
742
743
0
    return res;
744
0
}
745
746
4.88k
std::string BinToDec(const uint8_t* data, const size_t size) {
747
4.88k
    return BinToDec(std::vector<uint8_t>(data, data + size));
748
4.88k
}
749
750
4.88k
std::string BinToDec(const std::vector<uint8_t> data) {
751
4.88k
    if ( data.empty() ) {
752
0
        return "0";
753
0
    }
754
755
4.88k
    boost::multiprecision::cpp_int i;
756
4.88k
    boost::multiprecision::import_bits(i, data.data(), data.data() + data.size());
757
758
4.88k
    std::stringstream ss;
759
4.88k
    ss << i;
760
761
4.88k
    if ( ss.str().empty() ) {
762
0
        return "0";
763
4.88k
    } else {
764
4.88k
        return ss.str();
765
4.88k
    }
766
4.88k
}
767
768
0
std::optional<std::vector<uint8_t>> ToDER(const std::string A, const std::string B) {
769
0
    std::vector<uint8_t> ret;
770
771
0
    const auto ABin = DecToBin(A);
772
0
    if ( ABin == std::nullopt ) {
773
0
        return std::nullopt;
774
0
    }
775
0
    const auto BBin = DecToBin(B);
776
0
    if ( BBin == std::nullopt ) {
777
0
        return std::nullopt;
778
0
    }
779
780
0
    size_t ABinSize = ABin->size();
781
0
    size_t BBinSize = BBin->size();
782
0
    if ( ABinSize + BBinSize + 2 + 2 > 255 ) {
783
0
        return std::nullopt;
784
0
    }
785
786
0
    const bool AHigh = ABinSize > 0 && ((*ABin)[0] & 0x80) == 0x80;
787
0
    const bool BHigh = BBinSize > 0 && ((*BBin)[0] & 0x80) == 0x80;
788
789
0
    ABinSize += AHigh ? 1 : 0;
790
0
    BBinSize += BHigh ? 1 : 0;
791
792
0
    ret.push_back(0x30);
793
0
    ret.push_back(2 + ABinSize + 2 + BBinSize);
794
795
0
    ret.push_back(0x02);
796
0
    ret.push_back(ABinSize);
797
0
    if ( AHigh == true ) {
798
0
        ret.push_back(0x00);
799
0
    }
800
0
    ret.insert(std::end(ret), std::begin(*ABin), std::end(*ABin));
801
802
0
    ret.push_back(0x02);
803
0
    ret.push_back(BBinSize);
804
0
    if ( BHigh == true ) {
805
0
        ret.push_back(0x00);
806
0
    }
807
0
    ret.insert(std::end(ret), std::begin(*BBin), std::end(*BBin));
808
809
0
    return ret;
810
0
}
811
812
0
std::optional<std::pair<std::string, std::string>> SignatureFromDER(const std::string s) {
813
0
    return SignatureFromDER(HexToBin(s));
814
0
}
815
816
0
std::optional<std::pair<std::string, std::string>> SignatureFromDER(const std::vector<uint8_t> data) {
817
0
#define ADVANCE(n) { \
818
0
    i += n; \
819
0
    left -= n; \
820
0
}
821
822
0
#define GETBYTE() { \
823
0
    CF_CHECK_LT(i, data.size()); \
824
0
    b = data[i]; \
825
0
    ADVANCE(1); \
826
0
}
827
0
    std::optional<std::pair<std::string, std::string>> ret = std::nullopt;
828
0
    uint8_t b;
829
0
    size_t i = 0, left = data.size();
830
0
    std::string R, S;
831
832
0
    GETBYTE(); CF_CHECK_EQ(b, 0x30);
833
834
0
    GETBYTE(); CF_CHECK_EQ(b, left);
835
836
    /* R */
837
0
    {
838
0
        GETBYTE(); CF_CHECK_EQ(b, 0x02);
839
840
0
        GETBYTE(); CF_CHECK_LTE(b, left);
841
0
        auto size = b;
842
843
0
        R = BinToDec(std::vector<uint8_t>(&data[i], &data[i+size]));
844
0
        ADVANCE(size);
845
846
0
    }
847
848
    /* S */
849
0
    {
850
0
        GETBYTE(); CF_CHECK_EQ(b, 0x02);
851
852
0
        GETBYTE(); CF_CHECK_LTE(b, left);
853
0
        auto size = b;
854
855
0
        S = BinToDec(std::vector<uint8_t>(&data[i], &data[i+size]));
856
0
        ADVANCE(size);
857
0
    }
858
859
0
    ret = {R, S};
860
861
0
end:
862
0
    return ret;
863
0
}
864
865
0
std::optional<std::pair<std::string, std::string>> PubkeyFromASN1(const uint64_t curveType, const std::string s) {
866
0
    return PubkeyFromASN1(curveType, HexToBin(s));
867
0
}
868
869
0
std::optional<std::pair<std::string, std::string>> PubkeyFromASN1(const uint64_t curveType, const std::vector<uint8_t> data) {
870
0
    const auto numBits = cryptofuzz::repository::ECC_CurveToBits(curveType);
871
0
    if ( numBits == std::nullopt ) {
872
0
        return std::nullopt;
873
0
    }
874
0
    const size_t coordsize = (*numBits + 7) / 8;
875
0
    if ( data.size() < ((coordsize*2) + 2) ) {
876
0
        return std::nullopt;
877
0
    }
878
879
0
    const uint8_t* start2 = data.data() + data.size() - (coordsize * 2);
880
0
    const uint8_t* start1 = start2 - 2;
881
882
0
    if ( start1[0] != 0x00 || start1[1] != 0x04 ) {
883
0
        return std::nullopt;
884
0
    }
885
886
0
    return std::pair<std::string, std::string>{
887
0
        BinToDec({start2, start2 + coordsize}),
888
0
        BinToDec({start2 + coordsize, start2 + (coordsize * 2)}),
889
0
    };
890
0
}
891
892
0
std::string SHA1(const std::vector<uint8_t> data) {
893
0
    return BinToHex(crypto::sha1(data));
894
0
}
895
896
0
void HintBignum(const std::string bn) {
897
0
    if ( bn.size() < config::kMaxBignumSize ) {
898
0
        Pool_Bignum.Set(bn);
899
0
    }
900
0
}
901
902
0
void HintBignumPow2(size_t maxSize) {
903
0
    if ( maxSize > config::kMaxBignumSize ) {
904
0
        maxSize = config::kMaxBignumSize;
905
0
    }
906
907
0
    if ( maxSize == 0 ) {
908
0
        return;
909
0
    }
910
911
0
    boost::multiprecision::cpp_int pow2(1);
912
0
    const size_t count = PRNG() % static_cast<size_t>(maxSize * 3.322);
913
0
    pow2 <<= count;
914
0
    HintBignum(pow2.str());
915
0
}
916
917
0
void HintBignumInt(void) {
918
0
    HintBignum( std::to_string(PRNG() % 2147483648) );
919
0
}
920
921
0
void HintBignumOpt(const std::optional<std::string> bn) {
922
0
    if ( bn != std::nullopt ) {
923
0
        HintBignum(*bn);
924
0
    }
925
0
}
926
927
0
std::vector<uint8_t> Append(const std::vector<uint8_t> A, const std::vector<uint8_t> B) {
928
0
    std::vector<uint8_t> ret;
929
930
0
    ret.reserve(A.size() + B.size());
931
0
    ret.insert(ret.end(), A.begin(), A.end());
932
0
    ret.insert(ret.end(), B.begin(), B.end());
933
934
0
    return ret;
935
0
}
936
937
0
std::vector<uint8_t> RemoveLeadingZeroes(std::vector<uint8_t> v) {
938
0
    const auto it = std::find_if(v.begin(), v.end(), [](const size_t v) { return v != 0; });
939
0
    v.erase(v.begin(), it);
940
0
    return v;
941
0
}
942
943
0
std::vector<uint8_t> AddLeadingZeroes(fuzzing::datasource::Datasource& ds, const std::vector<uint8_t>& v) {
944
0
    const auto stripped = RemoveLeadingZeroes(v);
945
946
0
    uint16_t numZeroes = 0;
947
0
    try {
948
0
        numZeroes = ds.Get<uint8_t>();
949
0
        numZeroes %= 64;
950
0
    } catch ( fuzzing::datasource::Datasource::OutOfData& ) {
951
0
    }
952
0
    const std::vector<uint8_t> zeroes(numZeroes, 0);
953
954
0
    return Append(zeroes, stripped);
955
0
}
956
957
0
void AdjustECDSASignature(const uint64_t curveType, component::Bignum& s) {
958
0
    if ( curveType == CF_ECC_CURVE("secp256k1") ) {
959
0
        if ( !s.IsGreaterThan("57896044618658097711785492504343953926418782139537452191302581570759080747168") ) {
960
0
            return;
961
0
        }
962
0
        s.SubFrom("115792089237316195423570985008687907852837564279074904382605163141518161494337");
963
0
    } else if ( curveType == CF_ECC_CURVE("secp256r1") ) {
964
0
        if ( !s.IsGreaterThan("57896044605178124381348723474703786764998477612067880171211129530534256022184") ) {
965
0
            return;
966
0
        }
967
0
        s.SubFrom("115792089210356248762697446949407573529996955224135760342422259061068512044369");
968
0
    } else {
969
        /* No modification required */
970
0
        return;
971
0
    }
972
0
}
973
974
static inline boost::multiprecision::cpp_int sqrt_mod(
975
        const boost::multiprecision::cpp_int& in,
976
0
        const boost::multiprecision::cpp_int& prime) {
977
0
    using namespace boost::multiprecision;
978
979
    /* https://www.rieselprime.de/ziki/Modular_square_root */
980
981
0
    if ( prime % 4 == 3 ) {
982
0
        const cpp_int r = powm(in, (prime + 1) / 4, prime);
983
984
0
        return r;
985
0
    } else if ( prime % 8 == 5 ) {
986
0
        const cpp_int v = powm((2 * in), (prime - 5) / 8, prime);
987
0
        const cpp_int i = (2 * in * pow(v, 2)) % prime;
988
0
        const cpp_int r = (in * v * (i - 1)) % prime;
989
990
0
        return r;
991
0
    }
992
993
    /* Other primes not yet supported */
994
995
0
    return 0;
996
0
}
997
998
/* Find corresponding Y coordinate given X, A, B, P */
999
std::string Find_ECC_Y(
1000
        const std::string& x,
1001
        const std::string& a,
1002
        const std::string& b,
1003
        const std::string& p,
1004
0
        const std::string& o, const bool addOrder) {
1005
0
    using namespace boost::multiprecision;
1006
1007
0
    const cpp_int A(a), B(b), P(p);
1008
0
    const cpp_int X = cpp_int(x) % P;
1009
1010
0
    const cpp_int Z = (pow(X, 3) + (A*X) + B) % P;
1011
0
    const cpp_int res = sqrt_mod(Z, P) + (addOrder ? cpp_int(o) : cpp_int(0));
1012
1013
0
    return res.str();
1014
0
}
1015
1016
std::array<std::string, 3> ToRandomProjective(
1017
        fuzzing::datasource::Datasource& ds,
1018
        const std::string& x,
1019
        const std::string& y,
1020
        const uint64_t curveType,
1021
        const bool jacobian,
1022
0
        const bool inRange) {
1023
0
    using namespace boost::multiprecision;
1024
0
    const auto p = cryptofuzz::repository::ECC_CurveToPrime(curveType);
1025
0
    if ( p == std::nullopt ) {
1026
0
        return {x, y, "1"};
1027
0
    }
1028
1029
0
    std::vector<uint8_t> data;
1030
0
    try {
1031
0
        data = ds.GetData(0, 0, 1024 / 8);
1032
0
    } catch ( fuzzing::datasource::Datasource::OutOfData& ) {
1033
0
    }
1034
0
    if ( data.empty() ) {
1035
0
        return {x, y, "1"};
1036
0
    }
1037
1038
0
    cpp_int X(x), Y(y);
1039
0
    const cpp_int P(*p);
1040
1041
0
    if ( inRange == true ) {
1042
        /* Ensure coordinates are within bounds.
1043
         *
1044
         * This is to prevent that an affine ECC_Point with oversized coordinates
1045
         * will be regarded as invalid by a library, but then the projective
1046
         * coordinates (which are always within bounds, because they are reduced
1047
         * MOD P below), are regarded as valid.
1048
         *
1049
         * This can create discrepancies in operations such as ECC_ValidatePubKey.
1050
         */
1051
0
        if ( X < 0 || X >= P ) {
1052
0
            return {x, y, "1"};
1053
0
        }
1054
0
        if ( Y < 0 || Y >= P ) {
1055
0
            return {x, y, "1"};
1056
0
        }
1057
0
    }
1058
1059
0
    cpp_int Z;
1060
0
    boost::multiprecision::import_bits(Z, data.data(), data.data() + data.size());
1061
0
    Z %= P;
1062
0
    if ( Z == 0 ) {
1063
0
        return {x, y, "1"};
1064
0
    }
1065
0
    if ( jacobian == true ) {
1066
0
        X = (X * (Z * Z)) % P;
1067
0
        Y = (Y * (Z * Z * Z)) % P;
1068
0
    } else {
1069
0
        X = (X * Z) % P;
1070
0
        Y = (Y * Z) % P;
1071
0
    }
1072
0
    return {X.str(), Y.str(), Z.str()};
1073
0
}
1074
1075
namespace Ethereum_ModExp {
1076
    using namespace boost::multiprecision;
1077
1078
0
    static cpp_int modexpMultComplexity(const cpp_int& x) {
1079
0
            if ( x <= 64 ) {
1080
0
            return x * x;
1081
0
        } else if ( x <= 1024 ) {
1082
0
            return ((x * x) / 4) + ((96 * x) - 3072);
1083
0
        } else {
1084
0
            return ((x * x) / 16) + ((480 * x) - 199680);
1085
0
        }
1086
0
    }
1087
1088
0
    static cpp_int Max(const cpp_int& a, const cpp_int& b) {
1089
0
        return a > b ? a : b;
1090
0
    }
1091
1092
0
    static size_t BitSize(cpp_int v) {
1093
0
        size_t ret = 0;
1094
1095
0
        while ( v ) {
1096
0
            v >>= 1;
1097
0
            ret++;
1098
0
        }
1099
1100
0
        return ret;
1101
0
    }
1102
1103
    static std::vector<uint8_t> getData(
1104
            const std::vector<uint8_t> input,
1105
            const uint64_t start,
1106
0
            const uint64_t size) {
1107
0
        std::vector<uint8_t> ret;
1108
0
        if ( size == 0 ) {
1109
0
            return ret;
1110
0
        }
1111
1112
0
        if ( start < input.size() ) {
1113
0
            size_t end = start + size;
1114
0
            if ( end >= input.size() ) {
1115
0
                end = input.size();
1116
0
            }
1117
0
            ret.insert(std::end(ret),
1118
0
                    std::begin(input) + start,
1119
0
                    std::begin(input) + end);
1120
0
        }
1121
1122
0
        if ( ret.size() < size ) {
1123
0
            const std::vector<uint8_t> zeroes(size - ret.size(), 0);
1124
0
            ret.insert(std::end(ret), std::begin(zeroes), std::end(zeroes));
1125
0
        }
1126
1127
0
        return ret;
1128
0
    }
1129
1130
0
    static cpp_int Load(const std::vector<uint8_t>& input) {
1131
0
        if ( input.empty() ) {
1132
0
            return 0;
1133
0
        }
1134
1135
0
        boost::multiprecision::cpp_int ret;
1136
0
        boost::multiprecision::import_bits(ret, input.data(), input.data() + input.size());
1137
1138
0
        return ret;
1139
0
    }
1140
1141
    uint64_t Gas(
1142
            std::vector<uint8_t> input,
1143
0
            const bool eip2565) {
1144
0
        constexpr uint64_t uint64_t_max = std::numeric_limits<uint64_t>::max();
1145
1146
0
        const auto baseLen = Load(getData(input, 0, 32));
1147
0
        const auto expLen = Load(getData(input, 32, 32));
1148
0
        const auto modLen = Load(getData(input, 64, 32));
1149
1150
0
        if ( input.size() > 96 ) {
1151
0
            input = getData(input, 96, input.size() - 96);
1152
0
        } else {
1153
0
            input = {};
1154
0
        }
1155
1156
0
        cpp_int expHead;
1157
0
        if ( input.size() <= baseLen ) {
1158
0
            expHead = 0;
1159
0
        } else {
1160
0
            if ( expLen > 32 ) {
1161
0
                expHead = Load(getData(input, baseLen.convert_to<uint64_t>(), 32));
1162
0
            } else {
1163
0
                expHead = Load(getData(input,
1164
0
                            baseLen.convert_to<uint64_t>(),
1165
0
                            expLen.convert_to<uint64_t>()));
1166
0
            }
1167
0
        }
1168
1169
0
        const auto bitsize = BitSize(expHead);
1170
0
        uint64_t msb = 0;
1171
0
        if ( bitsize > 0 ) {
1172
0
            msb = bitsize - 1;
1173
0
        }
1174
1175
0
        cpp_int adjExpLen = 0;
1176
0
        if ( expLen > 32 ) {
1177
0
            adjExpLen = expLen - 32;
1178
0
            adjExpLen *= 8;
1179
0
        }
1180
0
        adjExpLen += msb;
1181
1182
0
        auto gas = Max(modLen, baseLen);
1183
1184
0
        if ( eip2565 == true ) {
1185
0
            gas += 7;
1186
0
            gas /= 8;
1187
0
            gas *= gas;
1188
0
            gas *= Max(adjExpLen, 1);
1189
0
            gas /= 3;
1190
1191
0
            if ( gas > uint64_t_max ) {
1192
0
                return uint64_t_max;
1193
0
            }
1194
1195
0
            if ( gas < 200 ) {
1196
0
                return 200;
1197
0
            }
1198
1199
0
            return gas.convert_to<uint64_t>();
1200
0
        }
1201
0
        gas = modexpMultComplexity(gas);
1202
0
        gas *= Max(adjExpLen, 1);
1203
0
        gas /= 20;
1204
1205
0
        if ( gas > uint64_t_max ) {
1206
0
            return uint64_t_max;
1207
0
        }
1208
1209
0
        return gas.convert_to<uint64_t>();
1210
0
    }
1211
1212
    std::vector<uint8_t> ToInput(
1213
            const component::Bignum& base,
1214
            const component::Bignum& exp,
1215
0
            const component::Bignum& mod) {
1216
0
        std::vector<uint8_t> input;
1217
1218
0
        const auto b = *base.ToBin();
1219
0
        const auto bl = DecToBin(std::to_string(b.size()), 32);
1220
0
        const auto e = *exp.ToBin();
1221
0
        const auto el = DecToBin(std::to_string(e.size()), 32);
1222
0
        const auto m = *mod.ToBin();
1223
0
        const auto ml = DecToBin(std::to_string(m.size()), 32);
1224
1225
0
        input.insert(input.end(), bl->begin(), bl->end());
1226
0
        input.insert(input.end(), el->begin(), el->end());
1227
0
        input.insert(input.end(), ml->begin(), ml->end());
1228
0
        input.insert(input.end(), b.begin(), b.end());
1229
0
        input.insert(input.end(), e.begin(), e.end());
1230
0
        input.insert(input.end(), m.begin(), m.end());
1231
1232
0
        return input;
1233
0
    }
1234
}
1235
1236
extern "C" {
1237
23.1k
    __attribute__((weak)) void __msan_unpoison(const volatile void*, size_t) { }
1238
}
1239
1240
0
void MemorySanitizerUnpoison(const void* data, const size_t size) {
1241
0
    __msan_unpoison(data, size);
1242
0
}
1243
1244
} /* namespace util */
1245
} /* namespace cryptofuzz */