Coverage Report

Created: 2023-02-22 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
0
Multipart ToParts(fuzzing::datasource::Datasource& ds, const std::vector<uint8_t>& buffer) {
73
0
    return ToParts(ds, buffer.data(), buffer.size());
74
0
}
75
76
3.79k
Multipart ToParts(fuzzing::datasource::Datasource& ds, const Buffer& buffer) {
77
3.79k
    return ToParts(ds, buffer.GetPtr(), buffer.GetSize());
78
3.79k
}
79
80
3.79k
Multipart ToParts(fuzzing::datasource::Datasource& ds, const uint8_t* data, const size_t size) {
81
3.79k
    Multipart ret;
82
83
    /* Position in buffer */
84
3.79k
    size_t curPos = 0;
85
86
3.79k
    try {
87
29.5k
        while ( ds.Get<bool>() == true ) {
88
25.7k
            const size_t left = size - curPos;
89
90
            /* Determine part length */
91
25.7k
            const size_t len = left == 0 ? 0 : ds.Get<uint64_t>() % left;
92
93
            /* Append part */
94
25.7k
            if ( len == 0 ) {
95
                /* Intentionally invalid pointer to detect dereference
96
                 * of buffer of size 0 */
97
22.2k
                ret.push_back( {GetNullPtr(), 0} );
98
22.2k
            } else {
99
3.55k
                ret.push_back( {data + curPos, len} );
100
3.55k
            }
101
102
            /* Advance */
103
25.7k
            curPos += len;
104
25.7k
        }
105
3.79k
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
106
1.93k
    }
107
108
    /* Append the remainder of the buffer */
109
3.79k
    if ( size - curPos == 0 ) {
110
        /* Intentionally invalid pointer to detect dereference
111
         * of buffer of size 0 */
112
732
        ret.push_back( {GetNullPtr(), 0} );
113
3.06k
    } else {
114
3.06k
        ret.push_back( {data + curPos, size - curPos} );
115
3.06k
    }
116
117
3.79k
    return ret;
118
3.79k
}
119
120
0
Multipart ToEqualParts(const Buffer& buffer, const size_t partSize) {
121
0
    return ToEqualParts(buffer.GetPtr(), buffer.GetSize(), partSize);
122
0
}
123
124
0
Multipart ToEqualParts(const uint8_t* data, const size_t size, const size_t partSize) {
125
0
    Multipart ret;
126
127
0
    const size_t numParts = size / partSize;
128
129
0
    for (size_t i = 0; i < numParts; i++) {
130
0
        ret.push_back( {data + (i*partSize), partSize} );
131
0
    }
132
133
0
    const size_t remainder = size % partSize;
134
135
0
    ret.push_back( {data + size - remainder, remainder} );
136
137
0
    return ret;
138
0
}
139
140
0
std::vector<uint8_t> Pkcs7Pad(std::vector<uint8_t> in, const size_t blocksize) {
141
0
    size_t numPadBytes = blocksize - (in.size() % blocksize);
142
143
0
    const uint8_t padByte = static_cast<uint8_t>(numPadBytes);
144
0
    for (size_t i = 0; i < numPadBytes; i++) {
145
0
        in.push_back(padByte);
146
0
    }
147
148
0
    return in;
149
0
}
150
151
0
std::optional<std::vector<uint8_t>> Pkcs7Unpad(std::vector<uint8_t> in, const size_t blocksize) {
152
0
    if ( in.size() == 0 || (in.size() % blocksize) != 0 ) {
153
0
        return std::nullopt;
154
0
    }
155
156
0
    const auto numPadBytes = static_cast<size_t>(in.back());
157
158
0
    if ( numPadBytes > in.size() ) {
159
0
        return std::nullopt;
160
0
    }
161
162
0
    return std::vector<uint8_t>(in.data(), in.data() + in.size() - numPadBytes);
163
0
}
164
165
0
std::string HexDump(const void *_data, const size_t len, const std::string description) {
166
0
    unsigned char *data = (unsigned char*)_data;
167
168
0
    std::stringstream ss;
169
170
0
    if ( description.size() > 0 ) {
171
0
        ss << description << " = ";
172
0
    }
173
174
0
    ss << "{";
175
0
    for (size_t i = 0; i < len; i++) {
176
0
        if ((i % 16) == 0 && i != 0) {
177
0
            ss << std::endl;
178
0
        }
179
0
        if ( (i % 16) == 0 && i != 0 ) {
180
0
            size_t padding;
181
0
            if ( description.size() > 0 ) {
182
0
                padding = description.size() + 4;
183
0
            } else {
184
0
                padding = 1;
185
0
            }
186
0
            for (size_t j = 0; j < padding; j++) {
187
0
                ss << " ";
188
0
            }
189
0
        }
190
0
        ss << "0x" << std::setw(2) << std::setfill('0') << std::hex << (int)(data[i]);
191
0
        if ( i == len - 1 ) {
192
0
            ss << "} (" << std::dec << len << " bytes)";
193
0
        } else {
194
0
            ss << ", ";
195
0
        }
196
0
    }
197
0
    if ( len == 0 ) {
198
0
        ss << "}";
199
0
    }
200
201
0
    return ss.str();
202
0
}
203
204
0
std::string HexDump(std::vector<uint8_t> data, const std::string description) {
205
0
    return HexDump(data.data(), data.size(), description);
206
0
}
207
208
0
std::string ToString(const Buffer& buffer) {
209
0
    return HexDump(buffer.Get());
210
0
}
211
212
0
std::string ToString(const bool val) {
213
0
    return val ? "true" : "false";
214
0
}
215
216
0
std::string ToString(const component::Ciphertext& ciphertext) {
217
0
    std::string ret;
218
219
0
    ret += util::HexDump(ciphertext.ciphertext.GetPtr(), ciphertext.ciphertext.GetSize(), "ciphertext");
220
221
0
    ret += "\n";
222
223
0
    if ( ciphertext.tag != std::nullopt ) {
224
0
        ret += util::HexDump(ciphertext.tag->GetPtr(), ciphertext.tag->GetSize(), "tag");
225
0
    } else {
226
0
        ret += "(tag is nullopt)";
227
0
    }
228
229
0
    return ret;
230
0
}
231
232
0
std::string ToString(const component::ECC_PublicKey& val) {
233
0
    std::string ret;
234
235
0
    ret += "X: ";
236
0
    ret += val.first.ToString();
237
0
    ret += "\n";
238
239
0
    ret += "Y: ";
240
0
    ret += val.second.ToString();
241
0
    ret += "\n";
242
243
0
    return ret;
244
0
}
245
246
0
std::string ToString(const component::ECC_KeyPair& val) {
247
0
    std::string ret;
248
249
0
    ret += "Priv: ";
250
0
    ret += val.priv.ToString();
251
0
    ret += "\n";
252
253
0
    ret += "X: ";
254
0
    ret += val.pub.first.ToString();
255
0
    ret += "\n";
256
257
0
    ret += "Y: ";
258
0
    ret += val.pub.second.ToString();
259
0
    ret += "\n";
260
261
0
    return ret;
262
0
}
263
264
0
std::string ToString(const component::ECCSI_Signature& val) {
265
0
    std::string ret;
266
267
0
    ret += "X: ";
268
0
    ret += val.pub.first.ToString();
269
0
    ret += "\n";
270
271
0
    ret += "Y: ";
272
0
    ret += val.pub.second.ToString();
273
0
    ret += "\n";
274
275
0
    ret += "PVT X: ";
276
0
    ret += val.pvt.first.ToString();
277
0
    ret += "\n";
278
279
0
    ret += "PVT Y: ";
280
0
    ret += val.pvt.second.ToString();
281
0
    ret += "\n";
282
283
0
    ret += "R: ";
284
0
    ret += val.signature.first.ToString();
285
0
    ret += "\n";
286
287
0
    ret += "S: ";
288
0
    ret += val.signature.second.ToString();
289
0
    ret += "\n";
290
291
0
    return ret;
292
0
}
293
294
0
std::string ToString(const component::ECDSA_Signature& val) {
295
0
    std::string ret;
296
297
0
    ret += "X: ";
298
0
    ret += val.pub.first.ToString();
299
0
    ret += "\n";
300
301
0
    ret += "Y: ";
302
0
    ret += val.pub.second.ToString();
303
0
    ret += "\n";
304
305
0
    ret += "R: ";
306
0
    ret += val.signature.first.ToString();
307
0
    ret += "\n";
308
309
0
    ret += "S: ";
310
0
    ret += val.signature.second.ToString();
311
0
    ret += "\n";
312
313
0
    return ret;
314
0
}
315
316
0
std::string ToString(const component::BLS_Signature& val) {
317
0
    std::string ret;
318
319
0
    ret += "Pub X: ";
320
0
    ret += val.pub.first.ToString();
321
0
    ret += "\n";
322
323
0
    ret += "Pub Y: ";
324
0
    ret += val.pub.second.ToString();
325
0
    ret += "\n";
326
327
0
    ret += "Sig v: ";
328
0
    ret += val.signature.first.first.ToString();
329
0
    ret += "\n";
330
331
0
    ret += "Sig w: ";
332
0
    ret += val.signature.first.second.ToString();
333
0
    ret += "\n";
334
335
0
    ret += "Sig x: ";
336
0
    ret += val.signature.second.first.ToString();
337
0
    ret += "\n";
338
339
0
    ret += "Sig y: ";
340
0
    ret += val.signature.second.second.ToString();
341
0
    ret += "\n";
342
343
0
    return ret;
344
0
}
345
346
0
std::string ToString(const component::BLS_BatchSignature& val) {
347
0
    std::string ret;
348
349
0
    for (const auto& cur : val.msgpub) {
350
0
        ret += "G1 X: ";
351
0
        ret += cur.first.first.ToString();
352
0
        ret += "\n";
353
0
        ret += "G1 Y: ";
354
0
        ret += cur.first.second.ToString();
355
0
        ret += "\n";
356
357
0
        ret += "\n";
358
359
0
        ret += "G2 V: ";
360
0
        ret += cur.second.first.first.ToString();
361
0
        ret += "\n";
362
0
        ret += "G2 W: ";
363
0
        ret += cur.second.first.second.ToString();
364
0
        ret += "\n";
365
0
        ret += "G2 X: ";
366
0
        ret += cur.second.second.first.ToString();
367
0
        ret += "\n";
368
0
        ret += "G2 Y: ";
369
0
        ret += cur.second.second.second.ToString();
370
0
        ret += "\n";
371
372
0
        ret += "----------";
373
0
        ret += "\n";
374
0
    }
375
0
    return ret;
376
0
}
377
378
0
std::string ToString(const component::BLS_KeyPair& val) {
379
0
    std::string ret;
380
381
0
    ret += "Priv : ";
382
0
    ret += val.priv.ToString();
383
0
    ret += "\n";
384
385
0
    ret += "Pub X: ";
386
0
    ret += val.pub.first.ToString();
387
0
    ret += "\n";
388
389
0
    ret += "Pub Y: ";
390
0
    ret += val.pub.second.ToString();
391
0
    ret += "\n";
392
393
0
    return ret;
394
0
}
395
396
0
std::string ToString(const component::Bignum& val) {
397
0
    return val.ToString();
398
0
}
399
400
0
std::string ToString(const component::G2& val) {
401
0
    std::string ret;
402
403
0
    ret += "X1: ";
404
0
    ret += val.first.first.ToString();
405
0
    ret += "\n";
406
407
0
    ret += "Y1: ";
408
0
    ret += val.first.second.ToString();
409
0
    ret += "\n";
410
411
0
    ret += "X2: ";
412
0
    ret += val.second.first.ToString();
413
0
    ret += "\n";
414
415
0
    ret += "Y2: ";
416
0
    ret += val.second.second.ToString();
417
0
    ret += "\n";
418
419
0
    return ret;
420
0
}
421
422
0
std::string ToString(const component::Fp12& val) {
423
0
    std::string ret;
424
425
0
    ret += "bn1: " + val.bn1.ToString() + "\n";
426
0
    ret += "bn2: " + val.bn2.ToString() + "\n";
427
0
    ret += "bn3: " + val.bn3.ToString() + "\n";
428
0
    ret += "bn4: " + val.bn4.ToString() + "\n";
429
0
    ret += "bn5: " + val.bn5.ToString() + "\n";
430
0
    ret += "bn6: " + val.bn6.ToString() + "\n";
431
0
    ret += "bn7: " + val.bn7.ToString() + "\n";
432
0
    ret += "bn8: " + val.bn8.ToString() + "\n";
433
0
    ret += "bn9: " + val.bn9.ToString() + "\n";
434
0
    ret += "bn10: " + val.bn10.ToString() + "\n";
435
0
    ret += "bn11: " + val.bn11.ToString() + "\n";
436
0
    ret += "bn12: " + val.bn12.ToString() + "\n";
437
438
0
    return ret;
439
0
}
440
441
0
std::string ToString(const component::DSA_Parameters& val) {
442
0
    std::string ret;
443
444
0
    ret += "P: " + val.p.ToString() + "\n";
445
0
    ret += "Q: " + val.q.ToString() + "\n";
446
0
    ret += "G: " + val.g.ToString() + "\n";
447
448
0
    return ret;
449
0
}
450
451
0
std::string ToString(const component::DSA_Signature& val) {
452
0
    std::string ret;
453
454
0
    ret += "R: " + val.signature.first.ToString() + "\n";
455
0
    ret += "S: " + val.signature.second.ToString() + "\n";
456
0
    ret += "Pub: " + val.pub.ToString() + "\n";
457
458
0
    return ret;
459
0
}
460
461
0
nlohmann::json ToJSON(const Buffer& buffer) {
462
0
    return buffer.ToJSON();
463
0
}
464
465
0
nlohmann::json ToJSON(const bool val) {
466
0
    return val;
467
0
}
468
469
0
nlohmann::json ToJSON(const component::Ciphertext& ciphertext) {
470
0
    nlohmann::json ret;
471
472
0
    ret["ciphertext"] = ciphertext.ciphertext.ToJSON();
473
474
0
    if ( ciphertext.tag != std::nullopt ) {
475
0
        ret["tag"] = ciphertext.tag->ToJSON();
476
0
    }
477
478
0
    return ret;
479
0
}
480
481
0
nlohmann::json ToJSON(const component::ECC_PublicKey& val) {
482
0
    return val.ToJSON();
483
0
}
484
485
0
nlohmann::json ToJSON(const component::ECC_KeyPair& val) {
486
0
    return val.ToJSON();
487
0
}
488
489
0
nlohmann::json ToJSON(const component::ECCSI_Signature& val) {
490
0
    return val.ToJSON();
491
0
}
492
493
0
nlohmann::json ToJSON(const component::ECDSA_Signature& val) {
494
0
    return val.ToJSON();
495
0
}
496
497
0
nlohmann::json ToJSON(const component::Bignum& val) {
498
0
    return val.ToJSON();
499
0
}
500
501
0
nlohmann::json ToJSON(const component::G2& val) {
502
0
    return val.ToJSON();
503
0
}
504
505
0
nlohmann::json ToJSON(const component::BLS_Signature& val) {
506
0
    return val.ToJSON();
507
0
}
508
509
0
nlohmann::json ToJSON(const component::BLS_BatchSignature& val) {
510
0
    return val.ToJSON();
511
0
}
512
513
0
nlohmann::json ToJSON(const component::BLS_KeyPair& val) {
514
0
    return val.ToJSON();
515
0
}
516
517
0
nlohmann::json ToJSON(const component::Fp12& val) {
518
0
    return val.ToJSON();
519
0
}
520
521
0
nlohmann::json ToJSON(const component::DSA_Parameters& val) {
522
0
    return val.ToJSON();
523
0
}
524
525
0
nlohmann::json ToJSON(const component::DSA_Signature& val) {
526
0
    return val.ToJSON();
527
0
}
528
529
class HaveBadPointer {
530
    private:
531
        bool haveBadPointer = false;
532
    public:
533
2
        HaveBadPointer(void) {
534
2
            const char* env = getenv("CRYPTOFUZZ_NULL_IS_BADPTR");
535
2
            if ( env == nullptr ) {
536
2
                haveBadPointer = false;
537
2
            } else {
538
0
                haveBadPointer = true;
539
0
            }
540
2
        }
541
542
12.2M
        bool Get(void) const {
543
12.2M
            return haveBadPointer;
544
12.2M
        }
545
};
546
547
static HaveBadPointer haveBadPointer;
548
549
fuzzing::datasource::Datasource* global_ds = nullptr;
550
551
0
void SetGlobalDs(fuzzing::datasource::Datasource* ds) {
552
0
    CF_ASSERT(global_ds == nullptr, "global_ds was already set");
553
554
0
    global_ds = ds;
555
0
}
556
557
0
void UnsetGlobalDs(void) {
558
0
    CF_ASSERT(global_ds != nullptr, "Trying to unset empty global_ds");
559
560
0
    global_ds = nullptr;
561
0
}
562
563
12.2M
uint8_t* GetNullPtr(fuzzing::datasource::Datasource* ds) {
564
12.2M
    if ( global_ds != nullptr ) {
565
0
        ds = global_ds;
566
0
    }
567
568
12.2M
    if ( ds != nullptr ) {
569
34
        try {
570
34
            return ds->Get<uint8_t*>();
571
34
        } catch ( fuzzing::datasource::Datasource::OutOfData ) {
572
17
            return (uint8_t*)0x12;
573
17
        }
574
34
    }
575
12.2M
    return haveBadPointer.Get() == true ? (uint8_t*)0x12 : nullptr;
576
12.2M
}
577
578
12.1M
uint8_t* malloc(const size_t n) {
579
12.1M
    return n == 0 ? GetNullPtr() : (uint8_t*)::malloc(n);
580
12.1M
}
581
582
0
uint8_t* realloc(void* ptr, const size_t n) {
583
0
    if ( n == 0 ) {
584
0
        free(ptr);
585
0
        return GetNullPtr();
586
0
    } else {
587
0
        if ( ptr != GetNullPtr() ) {
588
0
            return (uint8_t*)::realloc(ptr, n);
589
0
        } else {
590
0
            return malloc(n);
591
0
        }
592
0
    }
593
0
}
594
595
12.2M
void free(void* ptr) {
596
12.2M
    if ( ptr != GetNullPtr() ) {
597
12.1M
        ::free(ptr);
598
12.1M
    }
599
12.2M
}
600
601
0
bool HaveSSE42(void) {
602
0
#if defined(__x86_64__) || defined(__amd64__)
603
0
     const cpu_features::X86Info info = cpu_features::GetX86Info();
604
0
     const auto features = info.features;
605
0
     return features.sse4_2;
606
#else
607
    return false;
608
#endif
609
0
}
610
611
0
void abort(const std::vector<std::string> components) {
612
0
    const std::string joined = boost::algorithm::join(components, "-");
613
0
    printf("Assertion failure: %s\n", joined.c_str());
614
0
    fflush(stdout);
615
0
    ::abort();
616
0
}
617
618
2.13M
static int HexCharToDec(const char c) {
619
2.13M
    if ( c >= '0' && c <= '9' ) {
620
1.33M
        return c - '0';
621
1.33M
    } else if ( c >= 'a' && c <= 'f' ) {
622
0
        return c - 'a' + 10;
623
800k
    } else if ( c >= 'A' && c <= 'F' ) {
624
800k
        return c - 'A' + 10;
625
800k
    } else {
626
0
        assert(0);
627
0
    }
628
2.13M
}
629
630
5.73k
std::string HexToDec(std::string s) {
631
5.73k
    std::string ret;
632
5.73k
    bool negative = false;
633
634
5.73k
    if ( s.empty() ) {
635
0
        return ret;
636
0
    }
637
638
5.73k
    if ( s.size() >= 1 && s[0] == '-' ) {
639
56
        s = s.substr(1);
640
56
        negative = true;
641
56
    }
642
643
5.73k
    if ( s.size() >= 2 && s[0] == '0' && s[1] == 'x' ) {
644
4.39k
        s = s.substr(2);
645
4.39k
    }
646
647
5.73k
    if ( negative == false && s.size() >= 1 && s[0] == '-' ) {
648
0
        s = s.substr(1);
649
0
        negative = true;
650
0
    }
651
652
5.73k
    boost::multiprecision::cpp_int total;
653
654
2.13M
    for (long i = s.size() - 1; i >= 0; i--) {
655
2.13M
        total += boost::multiprecision::cpp_int(HexCharToDec(s[i])) << ((s.size()-i-1)*4);
656
2.13M
    }
657
658
5.73k
    std::stringstream ss;
659
5.73k
    if ( negative ) ss << "-";
660
5.73k
    ss << total;
661
662
5.73k
    if ( ss.str().empty() ) {
663
0
        return "0";
664
5.73k
    } else {
665
5.73k
        return ss.str();
666
5.73k
    }
667
5.73k
}
668
669
3.94k
std::string DecToHex(std::string s, const std::optional<size_t> padTo) {
670
3.94k
    bool negative = false;
671
3.94k
    if ( s.size() && s[0] == '-' ) {
672
0
        s.erase(0, 1);
673
0
        negative = true;
674
0
    }
675
3.94k
    s.erase(0, s.find_first_not_of('0'));
676
3.94k
    boost::multiprecision::cpp_int i(s);
677
3.94k
    std::stringstream ss;
678
3.94k
    if ( negative == true ) {
679
0
        ss << "-";
680
0
    }
681
3.94k
    ss << std::hex << i;
682
3.94k
    auto ret = ss.str();
683
3.94k
    if ( ret.size() % 2 != 0 ) {
684
1.59k
        ret = "0" + ret;
685
1.59k
    }
686
3.94k
    if ( padTo != std::nullopt && ret.size() < *padTo ) {
687
0
        ret = std::string(*padTo - ret.size(), '0') + ret;
688
0
    }
689
3.94k
    return ret;
690
3.94k
}
691
692
0
std::vector<uint8_t> HexToBin(const std::string s) {
693
0
    std::vector<uint8_t> data;
694
695
0
    boost::algorithm::unhex(s, std::back_inserter(data));
696
697
0
    return data;
698
0
}
699
700
19.4k
std::optional<std::vector<uint8_t>> DecToBin(const std::string s, std::optional<size_t> size) {
701
19.4k
    if ( !s.empty() && s[0] == '-' ) {
702
0
        return std::nullopt;
703
0
    }
704
19.4k
    std::vector<uint8_t> v;
705
19.4k
    boost::multiprecision::cpp_int c(s);
706
19.4k
    boost::multiprecision::export_bits(c, std::back_inserter(v), 8);
707
19.4k
    if ( size == std::nullopt ) {
708
13.1k
        return v;
709
13.1k
    }
710
711
6.24k
    if ( v.size() > *size ) {
712
303
        return std::nullopt;
713
303
    }
714
5.94k
    const auto diff = *size - v.size();
715
716
5.94k
    std::vector<uint8_t> ret(*size);
717
5.94k
    if ( diff > 0 ) {
718
2.32k
        memset(ret.data(), 0, diff);
719
2.32k
    }
720
5.94k
    memcpy(ret.data() + diff, v.data(), v.size());
721
722
5.94k
    return ret;
723
6.24k
}
724
725
0
std::string BinToHex(const uint8_t* data, const size_t size) {
726
0
    return BinToHex(std::vector<uint8_t>(data, data + size));
727
0
}
728
729
0
std::string BinToHex(const std::vector<uint8_t> data) {
730
0
    std::string res;
731
0
    boost::algorithm::hex_lower(data.begin(), data.end(), back_inserter(res));
732
733
0
    return res;
734
0
}
735
736
6.13k
std::string BinToDec(const uint8_t* data, const size_t size) {
737
6.13k
    return BinToDec(std::vector<uint8_t>(data, data + size));
738
6.13k
}
739
740
6.58k
std::string BinToDec(const std::vector<uint8_t> data) {
741
6.58k
    if ( data.empty() ) {
742
0
        return "0";
743
0
    }
744
745
6.58k
    boost::multiprecision::cpp_int i;
746
6.58k
    boost::multiprecision::import_bits(i, data.data(), data.data() + data.size());
747
748
6.58k
    std::stringstream ss;
749
6.58k
    ss << i;
750
751
6.58k
    if ( ss.str().empty() ) {
752
0
        return "0";
753
6.58k
    } else {
754
6.58k
        return ss.str();
755
6.58k
    }
756
6.58k
}
757
758
0
std::optional<std::vector<uint8_t>> ToDER(const std::string A, const std::string B) {
759
0
    std::vector<uint8_t> ret;
760
761
0
    const auto ABin = DecToBin(A);
762
0
    if ( ABin == std::nullopt ) {
763
0
        return std::nullopt;
764
0
    }
765
0
    const auto BBin = DecToBin(B);
766
0
    if ( BBin == std::nullopt ) {
767
0
        return std::nullopt;
768
0
    }
769
770
0
    size_t ABinSize = ABin->size();
771
0
    size_t BBinSize = BBin->size();
772
0
    if ( ABinSize + BBinSize + 2 + 2 > 255 ) {
773
0
        return std::nullopt;
774
0
    }
775
776
0
    const bool AHigh = ABinSize > 0 && ((*ABin)[0] & 0x80) == 0x80;
777
0
    const bool BHigh = BBinSize > 0 && ((*BBin)[0] & 0x80) == 0x80;
778
779
0
    ABinSize += AHigh ? 1 : 0;
780
0
    BBinSize += BHigh ? 1 : 0;
781
782
0
    ret.push_back(0x30);
783
0
    ret.push_back(2 + ABinSize + 2 + BBinSize);
784
785
0
    ret.push_back(0x02);
786
0
    ret.push_back(ABinSize);
787
0
    if ( AHigh == true ) {
788
0
        ret.push_back(0x00);
789
0
    }
790
0
    ret.insert(std::end(ret), std::begin(*ABin), std::end(*ABin));
791
792
0
    ret.push_back(0x02);
793
0
    ret.push_back(BBinSize);
794
0
    if ( BHigh == true ) {
795
0
        ret.push_back(0x00);
796
0
    }
797
0
    ret.insert(std::end(ret), std::begin(*BBin), std::end(*BBin));
798
799
0
    return ret;
800
0
}
801
802
0
std::optional<std::pair<std::string, std::string>> SignatureFromDER(const std::string s) {
803
0
    return SignatureFromDER(HexToBin(s));
804
0
}
805
806
0
std::optional<std::pair<std::string, std::string>> SignatureFromDER(const std::vector<uint8_t> data) {
807
0
#define ADVANCE(n) { \
808
0
    i += n; \
809
0
    left -= n; \
810
0
}
811
812
0
#define GETBYTE() { \
813
0
    CF_CHECK_LT(i, data.size()); \
814
0
    b = data[i]; \
815
0
    ADVANCE(1); \
816
0
}
817
0
    std::optional<std::pair<std::string, std::string>> ret = std::nullopt;
818
0
    uint8_t b;
819
0
    size_t i = 0, left = data.size();
820
0
    std::string R, S;
821
822
0
    GETBYTE(); CF_CHECK_EQ(b, 0x30);
823
824
0
    GETBYTE(); CF_CHECK_EQ(b, left);
825
826
    /* R */
827
0
    {
828
0
        GETBYTE(); CF_CHECK_EQ(b, 0x02);
829
830
0
        GETBYTE(); CF_CHECK_LTE(b, left);
831
0
        auto size = b;
832
833
0
        R = BinToDec(std::vector<uint8_t>(&data[i], &data[i+size]));
834
0
        ADVANCE(size);
835
836
0
    }
837
838
    /* S */
839
0
    {
840
0
        GETBYTE(); CF_CHECK_EQ(b, 0x02);
841
842
0
        GETBYTE(); CF_CHECK_LTE(b, left);
843
0
        auto size = b;
844
845
0
        S = BinToDec(std::vector<uint8_t>(&data[i], &data[i+size]));
846
0
        ADVANCE(size);
847
0
    }
848
849
0
    ret = {R, S};
850
851
0
end:
852
0
    return ret;
853
0
}
854
855
0
std::optional<std::pair<std::string, std::string>> PubkeyFromASN1(const uint64_t curveType, const std::string s) {
856
0
    return PubkeyFromASN1(curveType, HexToBin(s));
857
0
}
858
859
0
std::optional<std::pair<std::string, std::string>> PubkeyFromASN1(const uint64_t curveType, const std::vector<uint8_t> data) {
860
0
    const auto numBits = cryptofuzz::repository::ECC_CurveToBits(curveType);
861
0
    if ( numBits == std::nullopt ) {
862
0
        return std::nullopt;
863
0
    }
864
0
    const size_t coordsize = (*numBits + 7) / 8;
865
0
    if ( data.size() < ((coordsize*2) + 2) ) {
866
0
        return std::nullopt;
867
0
    }
868
869
0
    const uint8_t* start2 = data.data() + data.size() - (coordsize * 2);
870
0
    const uint8_t* start1 = start2 - 2;
871
872
0
    if ( start1[0] != 0x00 || start1[1] != 0x04 ) {
873
0
        return std::nullopt;
874
0
    }
875
876
0
    return std::pair<std::string, std::string>{
877
0
        BinToDec({start2, start2 + coordsize}),
878
0
        BinToDec({start2 + coordsize, start2 + (coordsize * 2)}),
879
0
    };
880
0
}
881
882
0
std::string SHA1(const std::vector<uint8_t> data) {
883
0
    return BinToHex(crypto::sha1(data));
884
0
}
885
886
540
void HintBignum(const std::string bn) {
887
540
    if ( bn.size() < config::kMaxBignumSize ) {
888
540
        Pool_Bignum.Set(bn);
889
540
    }
890
540
}
891
892
0
void HintBignumPow2(size_t maxSize) {
893
0
    if ( maxSize > config::kMaxBignumSize ) {
894
0
        maxSize = config::kMaxBignumSize;
895
0
    }
896
897
0
    if ( maxSize == 0 ) {
898
0
        return;
899
0
    }
900
901
0
    boost::multiprecision::cpp_int pow2(1);
902
0
    const size_t count = PRNG() % static_cast<size_t>(maxSize * 3.322);
903
0
    pow2 <<= count;
904
0
    HintBignum(pow2.str());
905
0
}
906
907
0
void HintBignumInt(void) {
908
0
    HintBignum( std::to_string(PRNG() % 2147483648) );
909
0
}
910
911
641
void HintBignumOpt(const std::optional<std::string> bn) {
912
641
    if ( bn != std::nullopt ) {
913
531
        HintBignum(*bn);
914
531
    }
915
641
}
916
917
0
std::vector<uint8_t> Append(const std::vector<uint8_t> A, const std::vector<uint8_t> B) {
918
0
    std::vector<uint8_t> ret;
919
920
0
    ret.reserve(A.size() + B.size());
921
0
    ret.insert(ret.end(), A.begin(), A.end());
922
0
    ret.insert(ret.end(), B.begin(), B.end());
923
924
0
    return ret;
925
0
}
926
927
0
std::vector<uint8_t> RemoveLeadingZeroes(std::vector<uint8_t> v) {
928
0
    const auto it = std::find_if(v.begin(), v.end(), [](const size_t v) { return v != 0; });
929
0
    v.erase(v.begin(), it);
930
0
    return v;
931
0
}
932
933
0
std::vector<uint8_t> AddLeadingZeroes(fuzzing::datasource::Datasource& ds, const std::vector<uint8_t>& v) {
934
0
    const auto stripped = RemoveLeadingZeroes(v);
935
936
0
    uint16_t numZeroes = 0;
937
0
    try {
938
0
        numZeroes = ds.Get<uint8_t>();
939
0
        numZeroes %= 64;
940
0
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
941
0
    }
942
0
    const std::vector<uint8_t> zeroes(numZeroes, 0);
943
944
0
    return Append(zeroes, stripped);
945
0
}
946
947
394
void AdjustECDSASignature(const uint64_t curveType, component::Bignum& s) {
948
394
    if ( curveType == CF_ECC_CURVE("secp256k1") ) {
949
79
        if ( !s.IsGreaterThan("57896044618658097711785492504343953926418782139537452191302581570759080747168") ) {
950
43
            return;
951
43
        }
952
36
        s.SubFrom("115792089237316195423570985008687907852837564279074904382605163141518161494337");
953
315
    } else if ( curveType == CF_ECC_CURVE("secp256r1") ) {
954
88
        if ( !s.IsGreaterThan("57896044605178124381348723474703786764998477612067880171211129530534256022184") ) {
955
42
            return;
956
42
        }
957
46
        s.SubFrom("115792089210356248762697446949407573529996955224135760342422259061068512044369");
958
227
    } else {
959
        /* No modification required */
960
227
        return;
961
227
    }
962
394
}
963
964
static inline boost::multiprecision::cpp_int sqrt_mod(
965
        const boost::multiprecision::cpp_int& in,
966
0
        const boost::multiprecision::cpp_int& prime) {
967
0
    using namespace boost::multiprecision;
968
969
    /* https://www.rieselprime.de/ziki/Modular_square_root */
970
971
0
    if ( prime % 4 == 3 ) {
972
0
        const cpp_int r = powm(in, (prime + 1) / 4, prime);
973
974
0
        return r;
975
0
    } else if ( prime % 8 == 5 ) {
976
0
        const cpp_int v = powm((2 * in), (prime - 5) / 8, prime);
977
0
        const cpp_int i = (2 * in * pow(v, 2)) % prime;
978
0
        const cpp_int r = (in * v * (i - 1)) % prime;
979
980
0
        return r;
981
0
    }
982
983
    /* Other primes not yet supported */
984
985
0
    return 0;
986
0
}
987
988
/* Find corresponding Y coordinate given X, A, B, P */
989
std::string Find_ECC_Y(
990
        const std::string& x,
991
        const std::string& a,
992
        const std::string& b,
993
        const std::string& p,
994
0
        const std::string& o, const bool addOrder) {
995
0
    using namespace boost::multiprecision;
996
997
0
    const cpp_int A(a), B(b), P(p);
998
0
    const cpp_int X = cpp_int(x) % P;
999
1000
0
    const cpp_int Z = (pow(X, 3) + (A*X) + B) % P;
1001
0
    const cpp_int res = sqrt_mod(Z, P) + (addOrder ? cpp_int(o) : cpp_int(0));
1002
1003
0
    return res.str();
1004
0
}
1005
1006
std::array<std::string, 3> ToRandomProjective(
1007
        fuzzing::datasource::Datasource& ds,
1008
        const std::string& x,
1009
        const std::string& y,
1010
        const uint64_t curveType,
1011
519
        const bool jacobian) {
1012
519
    using namespace boost::multiprecision;
1013
519
    const auto p = cryptofuzz::repository::ECC_CurveToPrime(curveType);
1014
519
    if ( p == std::nullopt ) {
1015
31
        return {x, y, "1"};
1016
31
    }
1017
488
    std::vector<uint8_t> data;
1018
488
    try {
1019
488
        data = ds.GetData(0, 0, 1024 / 8);
1020
488
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
1021
114
    }
1022
488
    if ( data.empty() ) {
1023
114
        return {x, y, "1"};
1024
114
    }
1025
374
    cpp_int Z;
1026
374
    boost::multiprecision::import_bits(Z, data.data(), data.data() + data.size());
1027
374
    if ( Z == 0 ) {
1028
2
        return {x, y, "1"};
1029
2
    }
1030
372
    cpp_int X(x), Y(y);
1031
372
    const cpp_int P(*p);
1032
372
    Z %= P;
1033
372
    if ( jacobian == true ) {
1034
96
        X = (X * (Z * Z)) % P;
1035
96
        Y = (Y * (Z * Z * Z)) % P;
1036
276
    } else {
1037
276
        X = (X * Z) % P;
1038
276
        Y = (Y * Z) % P;
1039
276
    }
1040
372
    return {X.str(), Y.str(), Z.str()};
1041
374
}
1042
1043
extern "C" {
1044
8.29k
    __attribute__((weak)) void __msan_unpoison(const volatile void*, size_t) { }
1045
}
1046
1047
0
void MemorySanitizerUnpoison(const void* data, const size_t size) {
1048
0
    __msan_unpoison(data, size);
1049
0
}
1050
1051
} /* namespace util */
1052
} /* namespace cryptofuzz */