Coverage Report

Created: 2024-09-11 06:39

/src/cryptofuzz/modules/bitcoin/module.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "module.h"
2
#include <cryptofuzz/util.h>
3
#include <cryptofuzz/repository.h>
4
#include <fuzzing/datasource/id.hpp>
5
#include <memory>
6
7
#include "crypto/sha1.cpp"
8
#include "crypto/sha256.cpp"
9
#include "crypto/sha512.cpp"
10
#include "crypto/sha3.cpp"
11
#include "crypto/ripemd160.cpp"
12
13
#include "crypto/hmac_sha256.cpp"
14
#include "crypto/hmac_sha512.cpp"
15
16
#include "crypto/hkdf_sha256_32.cpp"
17
18
#include "crypto/aes.cpp"
19
#include "crypto/chacha20.cpp"
20
#include "crypto/poly1305.cpp"
21
#include "crypto/chacha_poly_aead.cpp"
22
23
#include "crypto/siphash.cpp"
24
25
#include "uint256.cpp"
26
#include "arith_uint256.cpp"
27
28
#include "cleanse.cpp"
29
#include "util/strencodings.cpp"
30
31
namespace cryptofuzz {
32
namespace module {
33
34
Bitcoin::Bitcoin(void) :
35
6
    Module("Bitcoin") { }
36
37
namespace Bitcoin_detail {
38
39
template <class Alg>
40
118k
void digest_write(std::shared_ptr<Alg> alg, const uint8_t* data, const size_t size) {
41
118k
    alg->Write(data, size);
42
118k
}
void cryptofuzz::module::Bitcoin_detail::digest_write<CSHA1>(std::__1::shared_ptr<CSHA1>, unsigned char const*, unsigned long)
Line
Count
Source
40
27.2k
void digest_write(std::shared_ptr<Alg> alg, const uint8_t* data, const size_t size) {
41
27.2k
    alg->Write(data, size);
42
27.2k
}
void cryptofuzz::module::Bitcoin_detail::digest_write<CSHA256>(std::__1::shared_ptr<CSHA256>, unsigned char const*, unsigned long)
Line
Count
Source
40
20.5k
void digest_write(std::shared_ptr<Alg> alg, const uint8_t* data, const size_t size) {
41
20.5k
    alg->Write(data, size);
42
20.5k
}
void cryptofuzz::module::Bitcoin_detail::digest_write<CSHA512>(std::__1::shared_ptr<CSHA512>, unsigned char const*, unsigned long)
Line
Count
Source
40
26.0k
void digest_write(std::shared_ptr<Alg> alg, const uint8_t* data, const size_t size) {
41
26.0k
    alg->Write(data, size);
42
26.0k
}
void cryptofuzz::module::Bitcoin_detail::digest_write<CRIPEMD160>(std::__1::shared_ptr<CRIPEMD160>, unsigned char const*, unsigned long)
Line
Count
Source
40
44.5k
void digest_write(std::shared_ptr<Alg> alg, const uint8_t* data, const size_t size) {
41
44.5k
    alg->Write(data, size);
42
44.5k
}
43
44
template <>
45
15.6k
void digest_write(std::shared_ptr<SHA3_256> alg, const uint8_t* data, const size_t size) {
46
15.6k
    alg->Write({data, size});
47
15.6k
}
48
49
template <class Alg>
50
1.46k
std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) {
51
1.46k
    std::optional<component::Digest> ret = std::nullopt;
52
53
1.46k
    size_t numResets = 0;
54
1.46k
    util::Multipart parts;
55
1.46k
    std::shared_ptr<Alg> alg = nullptr;
56
57
    /* Initialize */
58
1.46k
    {
59
1.46k
        parts = util::ToParts(ds, op.cleartext);
60
1.46k
        alg = std::make_shared<Alg>();
61
1.46k
    }
62
63
1.84k
again:
64
65
    /* Process */
66
134k
    for (const auto& part : parts) {
67
134k
        digest_write(alg, part.first, part.second);
68
134k
        try {
69
134k
            if ( numResets < 5 && ds.Get<bool>() ) {
70
386
                alg->Reset();
71
386
                numResets++;
72
386
                goto again;
73
386
            }
74
134k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) {
75
133k
        }
76
134k
    }
77
78
    /* Finalize */
79
1.46k
    {
80
1.46k
        uint8_t out[Alg::OUTPUT_SIZE];
81
1.46k
        alg->Finalize(out);
82
1.46k
        ret = component::Digest(out, Alg::OUTPUT_SIZE);
83
1.46k
    }
84
85
1.46k
    return ret;
86
1.84k
}
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::digest<CSHA1>(cryptofuzz::operation::Digest&, fuzzing::datasource::Datasource&)
Line
Count
Source
50
320
std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) {
51
320
    std::optional<component::Digest> ret = std::nullopt;
52
53
320
    size_t numResets = 0;
54
320
    util::Multipart parts;
55
320
    std::shared_ptr<Alg> alg = nullptr;
56
57
    /* Initialize */
58
320
    {
59
320
        parts = util::ToParts(ds, op.cleartext);
60
320
        alg = std::make_shared<Alg>();
61
320
    }
62
63
402
again:
64
65
    /* Process */
66
27.2k
    for (const auto& part : parts) {
67
27.2k
        digest_write(alg, part.first, part.second);
68
27.2k
        try {
69
27.2k
            if ( numResets < 5 && ds.Get<bool>() ) {
70
82
                alg->Reset();
71
82
                numResets++;
72
82
                goto again;
73
82
            }
74
27.2k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) {
75
27.1k
        }
76
27.2k
    }
77
78
    /* Finalize */
79
320
    {
80
320
        uint8_t out[Alg::OUTPUT_SIZE];
81
320
        alg->Finalize(out);
82
320
        ret = component::Digest(out, Alg::OUTPUT_SIZE);
83
320
    }
84
85
320
    return ret;
86
402
}
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::digest<CSHA256>(cryptofuzz::operation::Digest&, fuzzing::datasource::Datasource&)
Line
Count
Source
50
244
std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) {
51
244
    std::optional<component::Digest> ret = std::nullopt;
52
53
244
    size_t numResets = 0;
54
244
    util::Multipart parts;
55
244
    std::shared_ptr<Alg> alg = nullptr;
56
57
    /* Initialize */
58
244
    {
59
244
        parts = util::ToParts(ds, op.cleartext);
60
244
        alg = std::make_shared<Alg>();
61
244
    }
62
63
313
again:
64
65
    /* Process */
66
20.5k
    for (const auto& part : parts) {
67
20.5k
        digest_write(alg, part.first, part.second);
68
20.5k
        try {
69
20.5k
            if ( numResets < 5 && ds.Get<bool>() ) {
70
69
                alg->Reset();
71
69
                numResets++;
72
69
                goto again;
73
69
            }
74
20.5k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) {
75
20.4k
        }
76
20.5k
    }
77
78
    /* Finalize */
79
244
    {
80
244
        uint8_t out[Alg::OUTPUT_SIZE];
81
244
        alg->Finalize(out);
82
244
        ret = component::Digest(out, Alg::OUTPUT_SIZE);
83
244
    }
84
85
244
    return ret;
86
313
}
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::digest<CSHA512>(cryptofuzz::operation::Digest&, fuzzing::datasource::Datasource&)
Line
Count
Source
50
252
std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) {
51
252
    std::optional<component::Digest> ret = std::nullopt;
52
53
252
    size_t numResets = 0;
54
252
    util::Multipart parts;
55
252
    std::shared_ptr<Alg> alg = nullptr;
56
57
    /* Initialize */
58
252
    {
59
252
        parts = util::ToParts(ds, op.cleartext);
60
252
        alg = std::make_shared<Alg>();
61
252
    }
62
63
333
again:
64
65
    /* Process */
66
26.0k
    for (const auto& part : parts) {
67
26.0k
        digest_write(alg, part.first, part.second);
68
26.0k
        try {
69
26.0k
            if ( numResets < 5 && ds.Get<bool>() ) {
70
81
                alg->Reset();
71
81
                numResets++;
72
81
                goto again;
73
81
            }
74
26.0k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) {
75
25.9k
        }
76
26.0k
    }
77
78
    /* Finalize */
79
252
    {
80
252
        uint8_t out[Alg::OUTPUT_SIZE];
81
252
        alg->Finalize(out);
82
252
        ret = component::Digest(out, Alg::OUTPUT_SIZE);
83
252
    }
84
85
252
    return ret;
86
333
}
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::digest<CRIPEMD160>(cryptofuzz::operation::Digest&, fuzzing::datasource::Datasource&)
Line
Count
Source
50
335
std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) {
51
335
    std::optional<component::Digest> ret = std::nullopt;
52
53
335
    size_t numResets = 0;
54
335
    util::Multipart parts;
55
335
    std::shared_ptr<Alg> alg = nullptr;
56
57
    /* Initialize */
58
335
    {
59
335
        parts = util::ToParts(ds, op.cleartext);
60
335
        alg = std::make_shared<Alg>();
61
335
    }
62
63
404
again:
64
65
    /* Process */
66
44.5k
    for (const auto& part : parts) {
67
44.5k
        digest_write(alg, part.first, part.second);
68
44.5k
        try {
69
44.5k
            if ( numResets < 5 && ds.Get<bool>() ) {
70
69
                alg->Reset();
71
69
                numResets++;
72
69
                goto again;
73
69
            }
74
44.5k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) {
75
44.4k
        }
76
44.5k
    }
77
78
    /* Finalize */
79
335
    {
80
335
        uint8_t out[Alg::OUTPUT_SIZE];
81
335
        alg->Finalize(out);
82
335
        ret = component::Digest(out, Alg::OUTPUT_SIZE);
83
335
    }
84
85
335
    return ret;
86
404
}
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::digest<SHA3_256>(cryptofuzz::operation::Digest&, fuzzing::datasource::Datasource&)
Line
Count
Source
50
310
std::optional<component::Digest> digest(operation::Digest& op, Datasource& ds) {
51
310
    std::optional<component::Digest> ret = std::nullopt;
52
53
310
    size_t numResets = 0;
54
310
    util::Multipart parts;
55
310
    std::shared_ptr<Alg> alg = nullptr;
56
57
    /* Initialize */
58
310
    {
59
310
        parts = util::ToParts(ds, op.cleartext);
60
310
        alg = std::make_shared<Alg>();
61
310
    }
62
63
395
again:
64
65
    /* Process */
66
15.6k
    for (const auto& part : parts) {
67
15.6k
        digest_write(alg, part.first, part.second);
68
15.6k
        try {
69
15.6k
            if ( numResets < 5 && ds.Get<bool>() ) {
70
85
                alg->Reset();
71
85
                numResets++;
72
85
                goto again;
73
85
            }
74
15.6k
        } catch ( fuzzing::datasource::Datasource::OutOfData ) {
75
15.5k
        }
76
15.6k
    }
77
78
    /* Finalize */
79
310
    {
80
310
        uint8_t out[Alg::OUTPUT_SIZE];
81
310
        alg->Finalize(out);
82
310
        ret = component::Digest(out, Alg::OUTPUT_SIZE);
83
310
    }
84
85
310
    return ret;
86
395
}
87
88
} /* namespace Bitcoin_detail */
89
90
1.48k
std::optional<component::Digest> Bitcoin::OpDigest(operation::Digest& op) {
91
1.48k
    std::optional<component::Digest> ret = std::nullopt;
92
93
1.48k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
94
95
1.48k
    switch ( op.digestType.Get() ) {
96
320
        case CF_DIGEST("SHA1"):
97
320
            return Bitcoin_detail::digest<CSHA1>(op, ds);
98
244
        case CF_DIGEST("SHA256"):
99
244
            return Bitcoin_detail::digest<CSHA256>(op, ds);
100
252
        case CF_DIGEST("SHA512"):
101
252
            return Bitcoin_detail::digest<CSHA512>(op, ds);
102
335
        case CF_DIGEST("RIPEMD160"):
103
335
            return Bitcoin_detail::digest<CRIPEMD160>(op, ds);
104
310
        case CF_DIGEST("SHA3-256"):
105
310
            return Bitcoin_detail::digest<SHA3_256>(op, ds);
106
1.48k
    }
107
108
27
    return ret;
109
1.48k
}
110
111
namespace Bitcoin_detail {
112
113
template <class Alg>
114
528
std::optional<component::MAC> hmac(operation::HMAC& op, Datasource& ds) {
115
528
    std::optional<component::MAC> ret = std::nullopt;
116
117
528
    util::Multipart parts;
118
528
    std::unique_ptr<Alg> alg = nullptr;
119
120
    /* Initialize */
121
528
    {
122
528
        parts = util::ToParts(ds, op.cleartext);
123
528
        alg = std::make_unique<Alg>(op.cipher.key.GetPtr(), op.cipher.key.GetSize());
124
528
    }
125
126
    /* Process */
127
34.2k
    for (const auto& part : parts) {
128
34.2k
        alg->Write(part.first, part.second);
129
34.2k
    }
130
131
    /* Finalize */
132
528
    {
133
528
        uint8_t out[Alg::OUTPUT_SIZE];
134
528
        alg->Finalize(out);
135
528
        ret = component::MAC(out, Alg::OUTPUT_SIZE);
136
528
    }
137
138
528
    return ret;
139
528
}
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::hmac<CHMAC_SHA256>(cryptofuzz::operation::HMAC&, fuzzing::datasource::Datasource&)
Line
Count
Source
114
245
std::optional<component::MAC> hmac(operation::HMAC& op, Datasource& ds) {
115
245
    std::optional<component::MAC> ret = std::nullopt;
116
117
245
    util::Multipart parts;
118
245
    std::unique_ptr<Alg> alg = nullptr;
119
120
    /* Initialize */
121
245
    {
122
245
        parts = util::ToParts(ds, op.cleartext);
123
245
        alg = std::make_unique<Alg>(op.cipher.key.GetPtr(), op.cipher.key.GetSize());
124
245
    }
125
126
    /* Process */
127
17.7k
    for (const auto& part : parts) {
128
17.7k
        alg->Write(part.first, part.second);
129
17.7k
    }
130
131
    /* Finalize */
132
245
    {
133
245
        uint8_t out[Alg::OUTPUT_SIZE];
134
245
        alg->Finalize(out);
135
245
        ret = component::MAC(out, Alg::OUTPUT_SIZE);
136
245
    }
137
138
245
    return ret;
139
245
}
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::hmac<CHMAC_SHA512>(cryptofuzz::operation::HMAC&, fuzzing::datasource::Datasource&)
Line
Count
Source
114
283
std::optional<component::MAC> hmac(operation::HMAC& op, Datasource& ds) {
115
283
    std::optional<component::MAC> ret = std::nullopt;
116
117
283
    util::Multipart parts;
118
283
    std::unique_ptr<Alg> alg = nullptr;
119
120
    /* Initialize */
121
283
    {
122
283
        parts = util::ToParts(ds, op.cleartext);
123
283
        alg = std::make_unique<Alg>(op.cipher.key.GetPtr(), op.cipher.key.GetSize());
124
283
    }
125
126
    /* Process */
127
16.5k
    for (const auto& part : parts) {
128
16.5k
        alg->Write(part.first, part.second);
129
16.5k
    }
130
131
    /* Finalize */
132
283
    {
133
283
        uint8_t out[Alg::OUTPUT_SIZE];
134
283
        alg->Finalize(out);
135
283
        ret = component::MAC(out, Alg::OUTPUT_SIZE);
136
283
    }
137
138
283
    return ret;
139
283
}
140
141
} /* namespace Bitcoin_detail */
142
143
namespace Bitcoin_detail {
144
202
    static std::optional<component::Digest> SipHash64(operation::HMAC& op, Datasource& ds) {
145
202
        std::optional<component::Digest> ret = std::nullopt;
146
147
202
        util::Multipart parts;
148
202
        std::unique_ptr<CSipHasher> alg = nullptr;
149
150
        /* Initialize */
151
202
        {
152
202
            if ( op.cipher.key.GetSize() != 16 ) {
153
29
                return ret;
154
29
            }
155
156
173
            uint64_t key[2];
157
173
            memcpy(&key[0], op.cipher.key.GetPtr(), 8);
158
173
            memcpy(&key[1], op.cipher.key.GetPtr() + 8, 8);
159
160
173
            if ( op.cleartext.GetSize() == 32 || op.cleartext.GetSize() == 36 ) {
161
5
                bool oneShot = false;
162
5
                try {
163
5
                    oneShot = ds.Get<bool>();
164
5
                } catch ( ... ) { }
165
166
5
                if ( oneShot == true ) {
167
3
                    uint64_t out;
168
169
3
                    if ( op.cleartext.GetSize() == 32 ) {
170
1
                        out = SipHashUint256(key[0], key[1], uint256(op.cleartext.Get()));
171
2
                    } else if ( op.cleartext.GetSize() == 36 ) {
172
2
                        uint8_t in[32];
173
2
                        uint32_t extra;
174
175
2
                        memcpy(in, op.cleartext.GetPtr(), sizeof(in));
176
2
                        memcpy(&extra, op.cleartext.GetPtr() + 32, sizeof(extra));
177
178
2
                        out = SipHashUint256Extra(
179
2
                                key[0],
180
2
                                key[1],
181
2
                                uint256(std::vector<uint8_t>(in, in + sizeof(in))),
182
2
                                extra);
183
2
                    } else {
184
0
                        abort();
185
0
                    }
186
187
3
                    ret = component::Digest((const uint8_t*)&out, sizeof(out));
188
189
3
                    return ret;
190
3
                }
191
5
            }
192
193
170
            alg = std::make_unique<CSipHasher>(key[0], key[1]);
194
195
            //if ( op.cleartext.GetSize() > 0 && (op.cleartext.GetSize() % 8) == 0 && ds.Get<bool>() == true ) {
196
170
            if ( (op.cleartext.GetSize() % 8) == 0 && ds.Get<bool>() == true ) {
197
5.07k
                for (size_t i = 0; i < op.cleartext.GetSize(); i += 8) {
198
5.04k
                    uint64_t v;
199
5.04k
                    memcpy(&v, op.cleartext.GetPtr() + i, sizeof(v));
200
5.04k
                    alg->Write(v);
201
5.04k
                }
202
203
28
                const auto out = alg->Finalize();
204
28
                ret = component::Digest((const uint8_t*)&out, sizeof(out));
205
206
28
                return ret;
207
28
            }
208
209
210
142
            parts = util::ToParts(ds, op.cleartext);
211
142
        }
212
213
        /* Process */
214
0
        {
215
12.0k
            for (const auto& part : parts) {
216
12.0k
                alg->Write(part.first, part.second);
217
12.0k
            }
218
142
        }
219
220
        /* Finalize */
221
142
        {
222
142
            const auto out = alg->Finalize();
223
142
            ret = component::Digest((const uint8_t*)&out, sizeof(out));
224
142
        }
225
226
142
        return ret;
227
170
    }
228
}
229
230
842
std::optional<component::MAC> Bitcoin::OpHMAC(operation::HMAC& op) {
231
842
    std::optional<component::MAC> ret = std::nullopt;
232
233
842
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
234
235
842
    switch ( op.digestType.Get() ) {
236
245
        case CF_DIGEST("SHA256"):
237
245
            return Bitcoin_detail::hmac<CHMAC_SHA256>(op, ds);
238
283
        case CF_DIGEST("SHA512"):
239
283
            return Bitcoin_detail::hmac<CHMAC_SHA512>(op, ds);
240
202
        case CF_DIGEST("SIPHASH64"):
241
202
            return Bitcoin_detail::SipHash64(op, ds);
242
842
    }
243
244
112
    return ret;
245
842
}
246
247
namespace Bitcoin_detail {
248
    template <class T>
249
696
    std::optional<T> chacha20(const Buffer& key, const Buffer& iv, const Buffer& in) {
250
696
        std::optional<T> ret = std::nullopt;
251
252
696
        if ( key.GetSize() != 16 && key.GetSize() != 32 ) {
253
135
            return ret;
254
135
        }
255
561
        if ( iv.GetSize() != 8 ) {
256
255
            return std::nullopt;
257
255
        }
258
259
306
        uint64_t iv_uint64_t;
260
261
306
        ChaCha20 cc20(key.GetPtr(), key.GetSize());
262
263
306
        memcpy(&iv_uint64_t, iv.GetPtr(), sizeof(iv_uint64_t));
264
306
        cc20.SetIV(iv_uint64_t);
265
266
306
        uint8_t* out = util::malloc(in.GetSize());
267
268
306
        CF_NORET(cc20.Crypt(in.GetPtr(), out, in.GetSize()));
269
270
306
        ret = T(Buffer(out, in.GetSize()));
271
306
        util::free(out);
272
273
306
        return ret;
274
561
    }
std::__1::optional<cryptofuzz::component::Ciphertext> cryptofuzz::module::Bitcoin_detail::chacha20<cryptofuzz::component::Ciphertext>(cryptofuzz::Buffer const&, cryptofuzz::Buffer const&, cryptofuzz::Buffer const&)
Line
Count
Source
249
318
    std::optional<T> chacha20(const Buffer& key, const Buffer& iv, const Buffer& in) {
250
318
        std::optional<T> ret = std::nullopt;
251
252
318
        if ( key.GetSize() != 16 && key.GetSize() != 32 ) {
253
63
            return ret;
254
63
        }
255
255
        if ( iv.GetSize() != 8 ) {
256
142
            return std::nullopt;
257
142
        }
258
259
113
        uint64_t iv_uint64_t;
260
261
113
        ChaCha20 cc20(key.GetPtr(), key.GetSize());
262
263
113
        memcpy(&iv_uint64_t, iv.GetPtr(), sizeof(iv_uint64_t));
264
113
        cc20.SetIV(iv_uint64_t);
265
266
113
        uint8_t* out = util::malloc(in.GetSize());
267
268
113
        CF_NORET(cc20.Crypt(in.GetPtr(), out, in.GetSize()));
269
270
113
        ret = T(Buffer(out, in.GetSize()));
271
113
        util::free(out);
272
273
113
        return ret;
274
255
    }
std::__1::optional<cryptofuzz::Buffer> cryptofuzz::module::Bitcoin_detail::chacha20<cryptofuzz::Buffer>(cryptofuzz::Buffer const&, cryptofuzz::Buffer const&, cryptofuzz::Buffer const&)
Line
Count
Source
249
378
    std::optional<T> chacha20(const Buffer& key, const Buffer& iv, const Buffer& in) {
250
378
        std::optional<T> ret = std::nullopt;
251
252
378
        if ( key.GetSize() != 16 && key.GetSize() != 32 ) {
253
72
            return ret;
254
72
        }
255
306
        if ( iv.GetSize() != 8 ) {
256
113
            return std::nullopt;
257
113
        }
258
259
193
        uint64_t iv_uint64_t;
260
261
193
        ChaCha20 cc20(key.GetPtr(), key.GetSize());
262
263
193
        memcpy(&iv_uint64_t, iv.GetPtr(), sizeof(iv_uint64_t));
264
193
        cc20.SetIV(iv_uint64_t);
265
266
193
        uint8_t* out = util::malloc(in.GetSize());
267
268
193
        CF_NORET(cc20.Crypt(in.GetPtr(), out, in.GetSize()));
269
270
193
        ret = T(Buffer(out, in.GetSize()));
271
193
        util::free(out);
272
273
193
        return ret;
274
306
    }
275
276
0
    std::optional<component::Ciphertext> chacha20_poly1305(const operation::SymmetricEncrypt& op) {
277
0
        std::optional<component::Ciphertext> ret = std::nullopt;
278
279
0
        if ( op.cipher.key.GetSize() != CHACHA20_POLY1305_AEAD_KEY_LEN ) {
280
0
            return ret;
281
0
        }
282
283
0
        if ( op.aad == std::nullopt || op.aad->GetSize() != CHACHA20_POLY1305_AEAD_KEY_LEN ) {
284
0
            return ret;
285
0
        }
286
287
0
        if ( op.tagSize == std::nullopt || *op.tagSize != POLY1305_TAGLEN ) {
288
0
            return ret;
289
0
        }
290
291
0
        if ( op.cipher.iv.GetSize() != 12 ) {
292
0
            return ret;
293
0
        }
294
295
0
        uint64_t seqnr_payload, seqnr_aad;
296
0
        memcpy(&seqnr_payload, op.cipher.iv.GetPtr(), sizeof(seqnr_payload));
297
0
        memcpy(&seqnr_aad, op.cipher.iv.GetPtr() + sizeof(seqnr_payload), sizeof(seqnr_aad));
298
299
0
        uint8_t* out = util::malloc(op.ciphertextSize);
300
301
0
        ChaCha20Poly1305AEAD aead(op.cipher.key.GetPtr(), op.cipher.key.GetSize(), op.aad->GetPtr(), op.aad->GetSize());
302
303
0
        CF_CHECK_TRUE(aead.Crypt(seqnr_payload, seqnr_aad, 0, out, op.ciphertextSize, op.cleartext.GetPtr(), op.cleartext.GetSize(), true));
304
305
0
        CF_ASSERT(op.ciphertextSize >= op.cleartext.GetSize() + POLY1305_TAGLEN, "ChaCha20Poly1305AEAD succeeded with invalid output size");
306
307
0
        ret = component::Ciphertext(
308
0
                Buffer(out, op.cleartext.GetSize()),
309
0
                Buffer(out + op.cleartext.GetSize(), POLY1305_TAGLEN));
310
311
0
end:
312
0
        util::free(out);
313
314
0
        return ret;
315
0
    }
316
317
0
    std::optional<component::Cleartext> chacha20_poly1305(const operation::SymmetricDecrypt& op) {
318
0
        std::optional<component::Cleartext> ret = std::nullopt;
319
320
0
        if ( op.cipher.key.GetSize() != CHACHA20_POLY1305_AEAD_KEY_LEN ) {
321
0
            return ret;
322
0
        }
323
324
0
        if ( op.aad == std::nullopt || op.aad->GetSize() != CHACHA20_POLY1305_AEAD_KEY_LEN ) {
325
0
            return ret;
326
0
        }
327
328
0
        if ( op.tag == std::nullopt || op.tag->GetSize() != POLY1305_TAGLEN ) {
329
0
            return ret;
330
0
        }
331
332
0
        if ( op.cipher.iv.GetSize() != 12 ) {
333
0
            return ret;
334
0
        }
335
336
0
        uint8_t* out = util::malloc(op.cleartextSize);
337
338
0
        ChaCha20Poly1305AEAD aead(op.cipher.key.GetPtr(), op.cipher.key.GetSize(), op.aad->GetPtr(), op.aad->GetSize());
339
340
0
        const auto in = util::Append(op.ciphertext.Get(), op.tag->Get());
341
0
        CF_CHECK_TRUE(aead.Crypt(0, 0, 0, out, op.cleartextSize, in.data(), in.size(), false));
342
343
0
        CF_ASSERT(op.cleartextSize >= op.ciphertext.GetSize(), "ChaCha20Poly1305AEAD succeeded with invalid output size");
344
345
0
        ret = component::Cleartext(Buffer(out, op.ciphertext.GetSize()));
346
347
0
end:
348
0
        util::free(out);
349
350
0
        return ret;
351
0
    }
352
353
152
    std::optional<component::Ciphertext> aes_256_cbc(const operation::SymmetricEncrypt& op) {
354
152
        std::optional<component::Ciphertext> ret = std::nullopt;
355
356
152
        std::unique_ptr<AES256CBCEncrypt> aes = nullptr;
357
152
        uint8_t* out = util::malloc(op.cleartext.GetSize() + AES_BLOCKSIZE);
358
152
        int numWritten;
359
360
        /* Initialize */
361
152
        {
362
152
            CF_CHECK_EQ(op.cipher.key.GetSize(), AES256_KEYSIZE);
363
101
            CF_CHECK_EQ(op.cipher.iv.GetSize(), AES_BLOCKSIZE);
364
90
            aes = std::make_unique<AES256CBCEncrypt>(op.cipher.key.GetPtr(), op.cipher.iv.GetPtr(), true);
365
90
        }
366
367
        /* Process */
368
0
        {
369
90
            CF_CHECK_GT(numWritten = aes->Encrypt(op.cleartext.GetPtr(), op.cleartext.GetSize(), out), 0);
370
87
        }
371
372
        /* Finalize */
373
0
        {
374
87
            ret = component::Ciphertext(Buffer(out, numWritten));
375
87
        }
376
377
152
end:
378
152
        util::free(out);
379
380
152
        return ret;
381
87
    }
382
383
197
    std::optional<component::Cleartext> aes_256_cbc(const operation::SymmetricDecrypt& op) {
384
197
        std::optional<component::Cleartext> ret = std::nullopt;
385
386
197
        std::unique_ptr<AES256CBCDecrypt> aes = nullptr;
387
197
        uint8_t* out = util::malloc(op.ciphertext.GetSize());
388
197
        int numWritten;
389
390
        /* Initialize */
391
197
        {
392
197
            CF_CHECK_EQ(op.cipher.cipherType.Get(), CF_CIPHER("AES_256_CBC"));
393
197
            CF_CHECK_EQ(op.cipher.key.GetSize(), AES256_KEYSIZE);
394
127
            CF_CHECK_EQ(op.cipher.iv.GetSize(), AES_BLOCKSIZE);
395
110
            aes = std::make_unique<AES256CBCDecrypt>(op.cipher.key.GetPtr(), op.cipher.iv.GetPtr(), true);
396
110
        }
397
398
        /* Process */
399
0
        {
400
110
            CF_CHECK_GT(numWritten = aes->Decrypt(op.ciphertext.GetPtr(), op.ciphertext.GetSize(), out), 0);
401
87
        }
402
403
        /* Finalize */
404
0
        {
405
87
            ret = component::Cleartext(out, numWritten);
406
87
        }
407
408
197
end:
409
197
        util::free(out);
410
411
197
        return ret;
412
87
    }
413
414
} /* namespace Bitcoin_detail */
415
416
470
std::optional<component::Ciphertext> Bitcoin::OpSymmetricEncrypt(operation::SymmetricEncrypt& op) {
417
470
    if ( op.cipher.cipherType.Is(CF_CIPHER("CHACHA20")) ) {
418
318
        return Bitcoin_detail::chacha20<component::Ciphertext>(op.cipher.key, op.cipher.iv, op.cleartext);
419
318
    } else if ( op.cipher.cipherType.Is(CF_CIPHER("CHACHA20_POLY1305")) ) {
420
0
        return Bitcoin_detail::chacha20_poly1305(op);
421
152
    } else if ( op.cipher.cipherType.Is(CF_CIPHER("AES_256_CBC")) ) {
422
152
        return Bitcoin_detail::aes_256_cbc(op);
423
152
    }
424
425
0
    return std::nullopt;
426
427
470
}
428
429
575
std::optional<component::Cleartext> Bitcoin::OpSymmetricDecrypt(operation::SymmetricDecrypt& op) {
430
575
    if ( op.cipher.cipherType.Is(CF_CIPHER("CHACHA20")) ) {
431
378
        return Bitcoin_detail::chacha20<component::Cleartext>(op.cipher.key, op.cipher.iv, op.ciphertext);
432
378
    } else if ( op.cipher.cipherType.Is(CF_CIPHER("CHACHA20_POLY1305")) ) {
433
0
        return Bitcoin_detail::chacha20_poly1305(op);
434
197
    } else if ( op.cipher.cipherType.Is(CF_CIPHER("AES_256_CBC")) ) {
435
197
        return Bitcoin_detail::aes_256_cbc(op);
436
197
    }
437
438
0
    return std::nullopt;
439
575
}
440
441
613
std::optional<component::Key> Bitcoin::OpKDF_HKDF(operation::KDF_HKDF& op) {
442
613
    if ( !op.digestType.Is(CF_DIGEST("SHA256")) ) {
443
485
        return std::nullopt;
444
485
    }
445
446
128
    if ( op.keySize != 32 ) {
447
125
        return std::nullopt;
448
125
    }
449
450
3
    if ( op.info.GetSize() > 128 ) {
451
2
        return std::nullopt;
452
2
    }
453
454
1
    uint8_t out[32];
455
456
1
    CHKDF_HMAC_SHA256_L32 hkdf(
457
1
            op.password.GetPtr(), op.password.GetSize(),
458
1
            op.salt.AsString());
459
460
1
    CF_NORET(hkdf.Expand32(op.info.AsString(), out));
461
462
1
    return component::Key(out, sizeof(out));
463
3
}
464
465
namespace Bitcoin_detail {
466
    class Bignum {
467
        private:
468
            Datasource& ds;
469
            arith_uint256 bn;
470
        public:
471
            Bignum(Datasource& ds) :
472
9.48k
                ds(ds) {
473
9.48k
            }
474
21.3k
            arith_uint256& Ref(void) {
475
21.3k
                {
476
21.3k
                    bool convert = false;
477
21.3k
                    try {
478
21.3k
                        convert = ds.Get<bool>();
479
21.3k
                    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
480
481
21.3k
                    if ( convert ) {
482
8.22k
                        bn = UintToArith256(ArithToUint256(bn));
483
8.22k
                    }
484
21.3k
                }
485
486
21.3k
                {
487
21.3k
                    bool getDouble = false;
488
21.3k
                    try {
489
21.3k
                        getDouble = ds.Get<bool>();
490
21.3k
                    } catch ( fuzzing::datasource::Datasource::OutOfData ) { }
491
492
21.3k
                    if ( getDouble ) {
493
7.62k
                        const auto d = bn.getdouble();
494
7.62k
                        (void)d;
495
7.62k
                    }
496
21.3k
                }
497
498
21.3k
                return bn;
499
21.3k
            }
500
    };
501
}
502
503
namespace Bitcoin_detail {
504
2.55k
    bool UseParamTwice(fuzzing::datasource::Datasource& ds, const arith_uint256& A, const arith_uint256& B) {
505
2.55k
        if ( A != B ) {
506
2.45k
            return false;
507
2.45k
        }
508
509
94
        try {
510
94
            return ds.Get<bool>();
511
94
        } catch ( fuzzing::datasource::Base::OutOfData ) {
512
30
        }
513
514
30
        return false;
515
94
    }
516
517
3.16k
    uint8_t GetMod3(fuzzing::datasource::Datasource& ds) {
518
3.16k
        try {
519
3.16k
            return ds.Get<uint8_t>() % 3;
520
3.16k
        } catch ( fuzzing::datasource::Base::OutOfData ) {
521
601
        }
522
523
601
        return 0;
524
3.16k
    }
525
} /* namespace Bitcoin_detail */
526
527
528
3.16k
std::optional<component::Bignum> Bitcoin::OpBignumCalc(operation::BignumCalc& op) {
529
3.16k
#define PREPARE_RESULT() {resultIdx = Bitcoin_detail::GetMod3(ds);}
530
3.16k
#define RESULT_REF() (resultIdx == 0 ? result : (resultIdx == 1 ? &a : &b))
531
7.37k
#define RESULT() ((resultIdx == 0 ? result : (resultIdx == 1 ? a : b)).Ref())
532
3.16k
#define PARAM_B() ((Bitcoin_detail::UseParamTwice(ds, a.Ref(), b.Ref()) ? a : b).Ref())
533
534
3.16k
    if ( op.modulo == std::nullopt ) {
535
0
        return std::nullopt;
536
0
    }
537
538
3.16k
    if ( op.modulo->ToTrimmedString() != "115792089237316195423570985008687907853269984665640564039457584007913129639936" ) {
539
0
        return std::nullopt;
540
0
    }
541
542
3.16k
    Datasource ds(op.modifier.GetPtr(), op.modifier.GetSize());
543
3.16k
    std::optional<component::Bignum> ret = std::nullopt;
544
545
3.16k
    Bitcoin_detail::Bignum result(ds), a(ds), b(ds);
546
547
3.16k
    a.Ref().SetHex(util::DecToHex(op.bn0.ToTrimmedString()));
548
3.16k
    b.Ref().SetHex(util::DecToHex(op.bn1.ToTrimmedString()));
549
550
3.16k
    uint8_t resultIdx;
551
552
3.16k
    PREPARE_RESULT();
553
554
3.16k
    switch ( op.calcOp.Get() ) {
555
99
        case    CF_CALCOP("Add(A,B)"):
556
99
            RESULT() = a.Ref() + PARAM_B();
557
99
            break;
558
298
        case    CF_CALCOP("Sub(A,B)"):
559
298
            RESULT() = a.Ref() - PARAM_B();
560
298
            break;
561
333
        case    CF_CALCOP("Mul(A,B)"):
562
333
            RESULT() = a.Ref() * PARAM_B();
563
333
            break;
564
429
        case    CF_CALCOP("Div(A,B)"):
565
429
            CF_CHECK_NE(PARAM_B(), 0);
566
413
            RESULT() = a.Ref() / PARAM_B();
567
413
            break;
568
159
        case    CF_CALCOP("IsEq(A,B)"):
569
159
            RESULT() = a.Ref() == PARAM_B();
570
159
            break;
571
176
        case    CF_CALCOP("IsGt(A,B)"):
572
176
            RESULT() = a.Ref() > PARAM_B();
573
176
            break;
574
149
        case    CF_CALCOP("IsGte(A,B)"):
575
149
            RESULT() = a.Ref() >= PARAM_B();
576
149
            break;
577
176
        case    CF_CALCOP("IsLt(A,B)"):
578
176
            RESULT() = a.Ref() < PARAM_B();
579
176
            break;
580
189
        case    CF_CALCOP("IsLte(A,B)"):
581
189
            RESULT() = a.Ref() <= PARAM_B();
582
189
            break;
583
44
        case    CF_CALCOP("IsOdd(A)"):
584
44
            RESULT() = a.Ref() & 1;
585
44
            break;
586
65
        case    CF_CALCOP("Set(A)"):
587
65
            RESULT() = a.Ref();
588
65
            break;
589
42
        case    CF_CALCOP("And(A,B)"):
590
42
            RESULT() = a.Ref() & PARAM_B();
591
42
            break;
592
50
        case    CF_CALCOP("Or(A,B)"):
593
50
            RESULT() = a.Ref() | PARAM_B();
594
50
            break;
595
37
        case    CF_CALCOP("Xor(A,B)"):
596
37
            RESULT() = a.Ref() ^ PARAM_B();
597
37
            break;
598
227
        case    CF_CALCOP("NumBits(A)"):
599
227
            RESULT() = a.Ref().bits();
600
227
            break;
601
690
        default:
602
690
            goto end;
603
3.16k
    }
604
605
2.45k
    ret = util::HexToDec(RESULT().GetHex());
606
607
3.16k
end:
608
3.16k
    return ret;
609
610
2.45k
#undef PREPARE_RESULT
611
2.45k
#undef RESULT_PTR
612
2.45k
#undef RESULT
613
2.45k
#undef PARAM_B
614
2.45k
}
615
616
3.16k
bool Bitcoin::SupportsModularBignumCalc(void) const {
617
3.16k
    return true;
618
3.16k
}
619
620
} /* namespace module */
621
} /* namespace cryptofuzz */