Coverage Report

Created: 2022-08-24 06:31

/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
3.14k
Multipart CipherInputTransform(fuzzing::datasource::Datasource& ds, component::SymmetricCipherType cipherType, const uint8_t* in, const size_t inSize) {
32
3.14k
    if ( repository::IsXTS( cipherType.Get() ) ) {
33
        /* XTS does not support chunked updating.
34
         * See: https://github.com/openssl/openssl/issues/8699
35
         */
36
94
        return { { in, inSize} };
37
3.04k
    } 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
75
        return { { in, inSize} };
42
2.97k
    } else {
43
2.97k
        return util::ToParts(ds, in, inSize);
44
2.97k
    }
45
3.14k
}
46
47
3.14k
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
3.14k
    return CipherInputTransform(
49
3.14k
        ds,
50
3.14k
        cipherType,
51
3.14k
        util::ToInPlace(ds, out, outSize, in, inSize),
52
3.14k
        inSize);
53
3.14k
}
54
55
3.14k
const uint8_t* ToInPlace(fuzzing::datasource::Datasource& ds, uint8_t* out, const size_t outSize, const uint8_t* in, const size_t inSize) {
56
3.14k
    bool inPlace = false;
57
58
3.14k
    if ( outSize >= inSize ) {
59
2.98k
        try {
60
2.98k
            inPlace = ds.Get<bool>();
61
2.98k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) {
62
1.58k
        }
63
2.98k
    }
64
65
3.14k
    if ( inPlace == true && inSize > 0 ) {
66
1.18k
        memcpy(out, in, inSize);
67
1.18k
    }
68
69
3.14k
    return inPlace ? out : in;
70
3.14k
}
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
7.42k
Multipart ToParts(fuzzing::datasource::Datasource& ds, const Buffer& buffer) {
77
7.42k
    return ToParts(ds, buffer.GetPtr(), buffer.GetSize());
78
7.42k
}
79
80
10.4k
Multipart ToParts(fuzzing::datasource::Datasource& ds, const uint8_t* data, const size_t size) {
81
10.4k
    Multipart ret;
82
83
    /* Position in buffer */
84
10.4k
    size_t curPos = 0;
85
86
10.4k
    try {
87
356k
        while ( ds.Get<bool>() == true ) {
88
346k
            const size_t left = size - curPos;
89
90
            /* Determine part length */
91
346k
            const size_t len = left == 0 ? 0 : ds.Get<uint64_t>() % left;
92
93
            /* Append part */
94
346k
            if ( len == 0 ) {
95
                /* Intentionally invalid pointer to detect dereference
96
                 * of buffer of size 0 */
97
330k
                ret.push_back( {GetNullPtr(), 0} );
98
330k
            } else {
99
16.1k
                ret.push_back( {data + curPos, len} );
100
16.1k
            }
101
102
            /* Advance */
103
346k
            curPos += len;
104
346k
        }
105
10.4k
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
106
9.84k
    }
107
108
    /* Append the remainder of the buffer */
109
10.4k
    if ( size - curPos == 0 ) {
110
        /* Intentionally invalid pointer to detect dereference
111
         * of buffer of size 0 */
112
3.88k
        ret.push_back( {GetNullPtr(), 0} );
113
6.51k
    } else {
114
6.51k
        ret.push_back( {data + curPos, size - curPos} );
115
6.51k
    }
116
117
10.4k
    return ret;
118
10.4k
}
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::ECDSA_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 += "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::BLS_Signature& val) {
287
0
    std::string ret;
288
289
0
    ret += "Pub X: ";
290
0
    ret += val.pub.first.ToString();
291
0
    ret += "\n";
292
293
0
    ret += "Pub Y: ";
294
0
    ret += val.pub.second.ToString();
295
0
    ret += "\n";
296
297
0
    ret += "Sig v: ";
298
0
    ret += val.signature.first.first.ToString();
299
0
    ret += "\n";
300
301
0
    ret += "Sig w: ";
302
0
    ret += val.signature.first.second.ToString();
303
0
    ret += "\n";
304
305
0
    ret += "Sig x: ";
306
0
    ret += val.signature.second.first.ToString();
307
0
    ret += "\n";
308
309
0
    ret += "Sig y: ";
310
0
    ret += val.signature.second.second.ToString();
311
0
    ret += "\n";
312
313
0
    return ret;
314
0
}
315
316
0
std::string ToString(const component::BLS_BatchSignature& val) {
317
0
    std::string ret;
318
319
0
    for (const auto& cur : val.msgpub) {
320
0
        ret += "G1 X: ";
321
0
        ret += cur.first.first.ToString();
322
0
        ret += "\n";
323
0
        ret += "G1 Y: ";
324
0
        ret += cur.first.second.ToString();
325
0
        ret += "\n";
326
327
0
        ret += "\n";
328
329
0
        ret += "G2 V: ";
330
0
        ret += cur.second.first.first.ToString();
331
0
        ret += "\n";
332
0
        ret += "G2 W: ";
333
0
        ret += cur.second.first.second.ToString();
334
0
        ret += "\n";
335
0
        ret += "G2 X: ";
336
0
        ret += cur.second.second.first.ToString();
337
0
        ret += "\n";
338
0
        ret += "G2 Y: ";
339
0
        ret += cur.second.second.second.ToString();
340
0
        ret += "\n";
341
342
0
        ret += "----------";
343
0
        ret += "\n";
344
0
    }
345
0
    return ret;
346
0
}
347
348
0
std::string ToString(const component::BLS_KeyPair& val) {
349
0
    std::string ret;
350
351
0
    ret += "Priv : ";
352
0
    ret += val.priv.ToString();
353
0
    ret += "\n";
354
355
0
    ret += "Pub X: ";
356
0
    ret += val.pub.first.ToString();
357
0
    ret += "\n";
358
359
0
    ret += "Pub Y: ";
360
0
    ret += val.pub.second.ToString();
361
0
    ret += "\n";
362
363
0
    return ret;
364
0
}
365
366
0
std::string ToString(const component::Bignum& val) {
367
0
    return val.ToString();
368
0
}
369
370
0
std::string ToString(const component::G2& val) {
371
0
    std::string ret;
372
373
0
    ret += "X1: ";
374
0
    ret += val.first.first.ToString();
375
0
    ret += "\n";
376
377
0
    ret += "Y1: ";
378
0
    ret += val.first.second.ToString();
379
0
    ret += "\n";
380
381
0
    ret += "X2: ";
382
0
    ret += val.second.first.ToString();
383
0
    ret += "\n";
384
385
0
    ret += "Y2: ";
386
0
    ret += val.second.second.ToString();
387
0
    ret += "\n";
388
389
0
    return ret;
390
0
}
391
392
0
std::string ToString(const component::Fp12& val) {
393
0
    std::string ret;
394
395
0
    ret += "bn1: " + val.bn1.ToString() + "\n";
396
0
    ret += "bn2: " + val.bn2.ToString() + "\n";
397
0
    ret += "bn3: " + val.bn3.ToString() + "\n";
398
0
    ret += "bn4: " + val.bn4.ToString() + "\n";
399
0
    ret += "bn5: " + val.bn5.ToString() + "\n";
400
0
    ret += "bn6: " + val.bn6.ToString() + "\n";
401
0
    ret += "bn7: " + val.bn7.ToString() + "\n";
402
0
    ret += "bn8: " + val.bn8.ToString() + "\n";
403
0
    ret += "bn9: " + val.bn9.ToString() + "\n";
404
0
    ret += "bn10: " + val.bn10.ToString() + "\n";
405
0
    ret += "bn11: " + val.bn11.ToString() + "\n";
406
0
    ret += "bn12: " + val.bn12.ToString() + "\n";
407
408
0
    return ret;
409
0
}
410
411
0
nlohmann::json ToJSON(const Buffer& buffer) {
412
0
    return buffer.ToJSON();
413
0
}
414
415
0
nlohmann::json ToJSON(const bool val) {
416
0
    return val;
417
0
}
418
419
0
nlohmann::json ToJSON(const component::Ciphertext& ciphertext) {
420
0
    nlohmann::json ret;
421
422
0
    ret["ciphertext"] = ciphertext.ciphertext.ToJSON();
423
424
0
    if ( ciphertext.tag != std::nullopt ) {
425
0
        ret["tag"] = ciphertext.tag->ToJSON();
426
0
    }
427
428
0
    return ret;
429
0
}
430
431
0
nlohmann::json ToJSON(const component::ECC_PublicKey& val) {
432
0
    return val.ToJSON();
433
0
}
434
435
0
nlohmann::json ToJSON(const component::ECC_KeyPair& val) {
436
0
    return val.ToJSON();
437
0
}
438
439
0
nlohmann::json ToJSON(const component::ECDSA_Signature& val) {
440
0
    return val.ToJSON();
441
0
}
442
443
0
nlohmann::json ToJSON(const component::Bignum& val) {
444
0
    return val.ToJSON();
445
0
}
446
447
0
nlohmann::json ToJSON(const component::G2& val) {
448
0
    return val.ToJSON();
449
0
}
450
451
0
nlohmann::json ToJSON(const component::BLS_Signature& val) {
452
0
    return val.ToJSON();
453
0
}
454
455
0
nlohmann::json ToJSON(const component::BLS_BatchSignature& val) {
456
0
    return val.ToJSON();
457
0
}
458
459
0
nlohmann::json ToJSON(const component::BLS_KeyPair& val) {
460
0
    return val.ToJSON();
461
0
}
462
463
0
nlohmann::json ToJSON(const component::Fp12& val) {
464
0
    return val.ToJSON();
465
0
}
466
467
class HaveBadPointer {
468
    private:
469
        bool haveBadPointer = false;
470
    public:
471
2
        HaveBadPointer(void) {
472
2
            const char* env = getenv("CRYPTOFUZZ_NULL_IS_BADPTR");
473
2
            if ( env == nullptr ) {
474
2
                haveBadPointer = false;
475
2
            } else {
476
0
                haveBadPointer = true;
477
0
            }
478
2
        }
479
480
359k
        bool Get(void) const {
481
359k
            return haveBadPointer;
482
359k
        }
483
};
484
485
static HaveBadPointer haveBadPointer;
486
487
fuzzing::datasource::Datasource* global_ds = nullptr;
488
489
0
void SetGlobalDs(fuzzing::datasource::Datasource* ds) {
490
0
    CF_ASSERT(global_ds == nullptr, "global_ds was already set");
491
492
0
    global_ds = ds;
493
0
}
494
495
0
void UnsetGlobalDs(void) {
496
0
    CF_ASSERT(global_ds != nullptr, "Trying to unset empty global_ds");
497
498
0
    global_ds = nullptr;
499
0
}
500
501
359k
uint8_t* GetNullPtr(fuzzing::datasource::Datasource* ds) {
502
359k
    if ( global_ds != nullptr ) {
503
0
        ds = global_ds;
504
0
    }
505
506
359k
    if ( ds != nullptr ) {
507
0
        try {
508
0
            return ds->Get<uint8_t*>();
509
0
        } catch ( fuzzing::datasource::Datasource::OutOfData ) {
510
0
            return (uint8_t*)0x12;
511
0
        }
512
0
    }
513
359k
    return haveBadPointer.Get() == true ? (uint8_t*)0x12 : nullptr;
514
359k
}
515
516
6.67k
uint8_t* malloc(const size_t n) {
517
6.67k
    return n == 0 ? GetNullPtr() : (uint8_t*)::malloc(n);
518
6.67k
}
519
520
0
uint8_t* realloc(void* ptr, const size_t n) {
521
0
    if ( n == 0 ) {
522
0
        free(ptr);
523
0
        return GetNullPtr();
524
0
    } else {
525
0
        if ( ptr != GetNullPtr() ) {
526
0
            return (uint8_t*)::realloc(ptr, n);
527
0
        } else {
528
0
            return malloc(n);
529
0
        }
530
0
    }
531
0
}
532
533
8.46k
void free(void* ptr) {
534
8.46k
    if ( ptr != GetNullPtr() ) {
535
6.01k
        ::free(ptr);
536
6.01k
    }
537
8.46k
}
538
539
0
bool HaveSSE42(void) {
540
0
#if defined(__x86_64__) || defined(__amd64__)
541
0
     const cpu_features::X86Info info = cpu_features::GetX86Info();
542
0
     const auto features = info.features;
543
0
     return features.sse4_2;
544
#else
545
    return false;
546
#endif
547
0
}
548
549
0
void abort(const std::vector<std::string> components) {
550
0
    const std::string joined = boost::algorithm::join(components, "-");
551
0
    printf("Assertion failure: %s\n", joined.c_str());
552
0
    fflush(stdout);
553
0
    ::abort();
554
0
}
555
556
130k
static int HexCharToDec(const char c) {
557
130k
    if ( c >= '0' && c <= '9' ) {
558
85.2k
        return c - '0';
559
85.2k
    } else if ( c >= 'a' && c <= 'f' ) {
560
0
        return c - 'a' + 10;
561
45.2k
    } else if ( c >= 'A' && c <= 'F' ) {
562
45.2k
        return c - 'A' + 10;
563
45.2k
    } else {
564
0
        assert(0);
565
0
    }
566
130k
}
567
568
1.67k
std::string HexToDec(std::string s) {
569
1.67k
    std::string ret;
570
1.67k
    bool negative = false;
571
572
1.67k
    if ( s.empty() ) {
573
0
        return ret;
574
0
    }
575
576
1.67k
    if ( s.size() >= 1 && s[0] == '-' ) {
577
68
        s = s.substr(1);
578
68
        negative = true;
579
68
    }
580
581
1.67k
    if ( s.size() >= 2 && s[0] == '0' && s[1] == 'x' ) {
582
0
        s = s.substr(2);
583
0
    }
584
585
1.67k
    if ( negative == false && s.size() >= 1 && s[0] == '-' ) {
586
0
        s = s.substr(1);
587
0
        negative = true;
588
0
    }
589
590
1.67k
    boost::multiprecision::cpp_int total;
591
592
132k
    for (long i = s.size() - 1; i >= 0; i--) {
593
130k
        total += boost::multiprecision::cpp_int(HexCharToDec(s[i])) << ((s.size()-i-1)*4);
594
130k
    }
595
596
1.67k
    std::stringstream ss;
597
1.67k
    if ( negative ) ss << "-";
598
1.67k
    ss << total;
599
600
1.67k
    if ( ss.str().empty() ) {
601
0
        return "0";
602
1.67k
    } else {
603
1.67k
        return ss.str();
604
1.67k
    }
605
1.67k
}
606
607
0
std::string DecToHex(std::string s, const std::optional<size_t> padTo) {
608
0
    bool negative = false;
609
0
    if ( s.size() && s[0] == '-' ) {
610
0
        s.erase(0, 1);
611
0
        negative = true;
612
0
    }
613
0
    s.erase(0, s.find_first_not_of('0'));
614
0
    boost::multiprecision::cpp_int i(s);
615
0
    std::stringstream ss;
616
0
    if ( negative == true ) {
617
0
        ss << "-";
618
0
    }
619
0
    ss << std::hex << i;
620
0
    auto ret = ss.str();
621
0
    if ( ret.size() % 2 != 0 ) {
622
0
        ret = "0" + ret;
623
0
    }
624
0
    if ( padTo != std::nullopt && ret.size() < *padTo ) {
625
0
        ret = std::string(*padTo - ret.size(), '0') + ret;
626
0
    }
627
0
    return ret;
628
0
}
629
630
0
std::vector<uint8_t> HexToBin(const std::string s) {
631
0
    std::vector<uint8_t> data;
632
633
0
    boost::algorithm::unhex(s, std::back_inserter(data));
634
635
0
    return data;
636
0
}
637
638
0
std::optional<std::vector<uint8_t>> DecToBin(const std::string s, std::optional<size_t> size) {
639
0
    if ( !s.empty() && s[0] == '-' ) {
640
0
        return std::nullopt;
641
0
    }
642
0
    std::vector<uint8_t> v;
643
0
    boost::multiprecision::cpp_int c(s);
644
0
    boost::multiprecision::export_bits(c, std::back_inserter(v), 8);
645
0
    if ( size == std::nullopt ) {
646
0
        return v;
647
0
    }
648
649
0
    if ( v.size() > *size ) {
650
0
        return std::nullopt;
651
0
    }
652
0
    const auto diff = *size - v.size();
653
654
0
    std::vector<uint8_t> ret(*size);
655
0
    if ( diff > 0 ) {
656
0
        memset(ret.data(), 0, diff);
657
0
    }
658
0
    memcpy(ret.data() + diff, v.data(), v.size());
659
660
0
    return ret;
661
0
}
662
663
0
std::string BinToHex(const uint8_t* data, const size_t size) {
664
0
    return BinToHex(std::vector<uint8_t>(data, data + size));
665
0
}
666
667
0
std::string BinToHex(const std::vector<uint8_t> data) {
668
0
    std::string res;
669
0
    boost::algorithm::hex_lower(data.begin(), data.end(), back_inserter(res));
670
671
0
    return res;
672
0
}
673
674
0
std::string BinToDec(const uint8_t* data, const size_t size) {
675
0
    return BinToDec(std::vector<uint8_t>(data, data + size));
676
0
}
677
678
23
std::string BinToDec(const std::vector<uint8_t> data) {
679
23
    if ( data.empty() ) {
680
0
        return "0";
681
0
    }
682
683
23
    boost::multiprecision::cpp_int i;
684
23
    boost::multiprecision::import_bits(i, data.data(), data.data() + data.size());
685
686
23
    std::stringstream ss;
687
23
    ss << i;
688
689
23
    if ( ss.str().empty() ) {
690
0
        return "0";
691
23
    } else {
692
23
        return ss.str();
693
23
    }
694
23
}
695
696
0
std::optional<std::vector<uint8_t>> ToDER(const std::string A, const std::string B) {
697
0
    std::vector<uint8_t> ret;
698
699
0
    const auto ABin = DecToBin(A);
700
0
    if ( ABin == std::nullopt ) {
701
0
        return std::nullopt;
702
0
    }
703
0
    const auto BBin = DecToBin(B);
704
0
    if ( BBin == std::nullopt ) {
705
0
        return std::nullopt;
706
0
    }
707
708
0
    size_t ABinSize = ABin->size();
709
0
    size_t BBinSize = BBin->size();
710
0
    if ( ABinSize + BBinSize + 2 + 2 > 255 ) {
711
0
        return std::nullopt;
712
0
    }
713
714
0
    const bool AHigh = ABinSize > 0 && ((*ABin)[0] & 0x80) == 0x80;
715
0
    const bool BHigh = BBinSize > 0 && ((*BBin)[0] & 0x80) == 0x80;
716
717
0
    ABinSize += AHigh ? 1 : 0;
718
0
    BBinSize += BHigh ? 1 : 0;
719
720
0
    ret.push_back(0x30);
721
0
    ret.push_back(2 + ABinSize + 2 + BBinSize);
722
723
0
    ret.push_back(0x02);
724
0
    ret.push_back(ABinSize);
725
0
    if ( AHigh == true ) {
726
0
        ret.push_back(0x00);
727
0
    }
728
0
    ret.insert(std::end(ret), std::begin(*ABin), std::end(*ABin));
729
730
0
    ret.push_back(0x02);
731
0
    ret.push_back(BBinSize);
732
0
    if ( BHigh == true ) {
733
0
        ret.push_back(0x00);
734
0
    }
735
0
    ret.insert(std::end(ret), std::begin(*BBin), std::end(*BBin));
736
737
0
    return ret;
738
0
}
739
740
0
std::optional<std::pair<std::string, std::string>> SignatureFromDER(const std::string s) {
741
0
    return SignatureFromDER(HexToBin(s));
742
0
}
743
744
0
std::optional<std::pair<std::string, std::string>> SignatureFromDER(const std::vector<uint8_t> data) {
745
0
#define ADVANCE(n) { \
746
0
    i += n; \
747
0
    left -= n; \
748
0
}
749
750
0
#define GETBYTE() { \
751
0
    CF_CHECK_LT(i, data.size()); \
752
0
    b = data[i]; \
753
0
    ADVANCE(1); \
754
0
}
755
0
    std::optional<std::pair<std::string, std::string>> ret = std::nullopt;
756
0
    uint8_t b;
757
0
    size_t i = 0, left = data.size();
758
0
    std::string R, S;
759
760
0
    GETBYTE(); CF_CHECK_EQ(b, 0x30);
761
762
0
    GETBYTE(); CF_CHECK_EQ(b, left);
763
764
    /* R */
765
0
    {
766
0
        GETBYTE(); CF_CHECK_EQ(b, 0x02);
767
768
0
        GETBYTE(); CF_CHECK_LTE(b, left);
769
0
        auto size = b;
770
771
0
        R = BinToDec(std::vector<uint8_t>(&data[i], &data[i+size]));
772
0
        ADVANCE(size);
773
774
0
    }
775
776
    /* S */
777
0
    {
778
0
        GETBYTE(); CF_CHECK_EQ(b, 0x02);
779
780
0
        GETBYTE(); CF_CHECK_LTE(b, left);
781
0
        auto size = b;
782
783
0
        S = BinToDec(std::vector<uint8_t>(&data[i], &data[i+size]));
784
0
        ADVANCE(size);
785
0
    }
786
787
0
    ret = {R, S};
788
789
0
end:
790
0
    return ret;
791
0
}
792
793
0
std::optional<std::pair<std::string, std::string>> PubkeyFromASN1(const uint64_t curveType, const std::string s) {
794
0
    return PubkeyFromASN1(curveType, HexToBin(s));
795
0
}
796
797
0
std::optional<std::pair<std::string, std::string>> PubkeyFromASN1(const uint64_t curveType, const std::vector<uint8_t> data) {
798
0
    const auto numBits = cryptofuzz::repository::ECC_CurveToBits(curveType);
799
0
    if ( numBits == std::nullopt ) {
800
0
        return std::nullopt;
801
0
    }
802
0
    const size_t coordsize = (*numBits + 7) / 8;
803
0
    if ( data.size() < ((coordsize*2) + 2) ) {
804
0
        return std::nullopt;
805
0
    }
806
807
0
    const uint8_t* start2 = data.data() + data.size() - (coordsize * 2);
808
0
    const uint8_t* start1 = start2 - 2;
809
810
0
    if ( start1[0] != 0x00 || start1[1] != 0x04 ) {
811
0
        return std::nullopt;
812
0
    }
813
814
0
    return std::pair<std::string, std::string>{
815
0
        BinToDec({start2, start2 + coordsize}),
816
0
        BinToDec({start2 + coordsize, start2 + (coordsize * 2)}),
817
0
    };
818
0
}
819
820
0
std::string SHA1(const std::vector<uint8_t> data) {
821
0
    return BinToHex(crypto::sha1(data));
822
0
}
823
824
254
void HintBignum(const std::string bn) {
825
254
    if ( bn.size() < config::kMaxBignumSize ) {
826
254
        Pool_Bignum.Set(bn);
827
254
    }
828
254
}
829
830
0
void HintBignumPow2(size_t maxSize) {
831
0
    if ( maxSize > config::kMaxBignumSize ) {
832
0
        maxSize = config::kMaxBignumSize;
833
0
    }
834
835
0
    if ( maxSize == 0 ) {
836
0
        return;
837
0
    }
838
839
0
    boost::multiprecision::cpp_int pow2(1);
840
0
    const size_t count = PRNG() % static_cast<size_t>(maxSize * 3.322);
841
0
    pow2 <<= count;
842
0
    HintBignum(pow2.str());
843
0
}
844
845
99
void HintBignumInt(void) {
846
99
    HintBignum( std::to_string(PRNG() % 2147483648) );
847
99
}
848
849
0
void HintBignumOpt(const std::optional<std::string> bn) {
850
0
    if ( bn != std::nullopt ) {
851
0
        HintBignum(*bn);
852
0
    }
853
0
}
854
855
0
std::vector<uint8_t> Append(const std::vector<uint8_t> A, const std::vector<uint8_t> B) {
856
0
    std::vector<uint8_t> ret;
857
858
0
    ret.reserve(A.size() + B.size());
859
0
    ret.insert(ret.end(), A.begin(), A.end());
860
0
    ret.insert(ret.end(), B.begin(), B.end());
861
862
0
    return ret;
863
0
}
864
865
0
std::vector<uint8_t> RemoveLeadingZeroes(std::vector<uint8_t> v) {
866
0
    const auto it = std::find_if(v.begin(), v.end(), [](const size_t v) { return v != 0; });
867
0
    v.erase(v.begin(), it);
868
0
    return v;
869
0
}
870
871
0
std::vector<uint8_t> AddLeadingZeroes(fuzzing::datasource::Datasource& ds, const std::vector<uint8_t>& v) {
872
0
    const auto stripped = RemoveLeadingZeroes(v);
873
874
0
    uint16_t numZeroes = 0;
875
0
    try {
876
0
        numZeroes = ds.Get<uint8_t>();
877
0
        numZeroes %= 64;
878
0
    } catch ( fuzzing::datasource::Datasource::OutOfData ) {
879
0
    }
880
0
    const std::vector<uint8_t> zeroes(numZeroes, 0);
881
882
0
    return Append(zeroes, stripped);
883
0
}
884
885
379
void AdjustECDSASignature(const uint64_t curveType, component::Bignum& s) {
886
379
    if ( curveType == CF_ECC_CURVE("secp256k1") ) {
887
15
        if ( !s.IsGreaterThan("57896044618658097711785492504343953926418782139537452191302581570759080747168") ) {
888
7
            return;
889
7
        }
890
8
        s.SubFrom("115792089237316195423570985008687907852837564279074904382605163141518161494337");
891
364
    } else if ( curveType == CF_ECC_CURVE("secp256r1") ) {
892
8
        if ( !s.IsGreaterThan("57896044605178124381348723474703786764998477612067880171211129530534256022184") ) {
893
3
            return;
894
3
        }
895
5
        s.SubFrom("115792089210356248762697446949407573529996955224135760342422259061068512044369");
896
356
    } else {
897
        /* No modification required */
898
356
        return;
899
356
    }
900
379
}
901
902
static inline boost::multiprecision::cpp_int sqrt_mod(
903
        const boost::multiprecision::cpp_int& in,
904
0
        const boost::multiprecision::cpp_int& prime) {
905
0
    using namespace boost::multiprecision;
906
907
    /* https://www.rieselprime.de/ziki/Modular_square_root */
908
909
0
    if ( prime % 4 == 3 ) {
910
0
        const cpp_int r = powm(in, (prime + 1) / 4, prime);
911
912
0
        return r;
913
0
    } else if ( prime % 8 == 5 ) {
914
0
        const cpp_int v = powm((2 * in), (prime - 5) / 8, prime);
915
0
        const cpp_int i = (2 * in * pow(v, 2)) % prime;
916
0
        const cpp_int r = (in * v * (i - 1)) % prime;
917
918
0
        return r;
919
0
    }
920
921
    /* Other primes not yet supported */
922
923
0
    return 0;
924
0
}
925
926
/* Find corresponding Y coordinate given X, A, B, P */
927
std::string Find_ECC_Y(
928
        const std::string& x,
929
        const std::string& a,
930
        const std::string& b,
931
        const std::string& p,
932
0
        const std::string& o, const bool addOrder) {
933
0
    using namespace boost::multiprecision;
934
935
0
    const cpp_int A(a), B(b), P(p);
936
0
    const cpp_int X = cpp_int(x) % P;
937
938
0
    const cpp_int Z = (pow(X, 3) + (A*X) + B) % P;
939
0
    const cpp_int res = sqrt_mod(Z, P) + (addOrder ? cpp_int(o) : cpp_int(0));
940
941
0
    return res.str();
942
0
}
943
944
extern "C" {
945
13.1k
    __attribute__((weak)) void __msan_unpoison(const volatile void*, size_t) { }
946
}
947
948
0
void MemorySanitizerUnpoison(const void* data, const size_t size) {
949
0
    __msan_unpoison(data, size);
950
0
}
951
952
} /* namespace util */
953
} /* namespace cryptofuzz */