/src/ndpi/fuzz/fuzz_gcrypt_cipher.cpp
Line | Count | Source |
1 | | #include <stdlib.h> |
2 | | #include <stdint.h> |
3 | | #include <assert.h> |
4 | | #include "fuzzer/FuzzedDataProvider.h" |
5 | | |
6 | | #define MBEDTLS_CHECK_RETURN_TYPICAL |
7 | 1.20k | #define MBEDTLS_INTERNAL_VALIDATE_RET( cond, ret ) do { } while( 0 ) |
8 | | #include "gcrypt/cipher.h" |
9 | | #include "gcrypt/error.h" |
10 | | #include "gcrypt/aes.h" |
11 | | |
12 | | extern int force_no_aesni; |
13 | | |
14 | 217 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
15 | 217 | FuzzedDataProvider fuzzed_data(data, size); |
16 | 217 | int key_lens[] = { 128, 192, 256 }; |
17 | 217 | int key_len, iv_len, rc_e, rc_d, input_length; |
18 | 217 | unsigned char *output, *decrypted; |
19 | 217 | size_t output_size, output_size2, decrypted_size; |
20 | 217 | mbedtls_cipher_type_t cipher_type; |
21 | | /* TODO: GCM. This code/fuzzer doesn't work with GCM ciphers. Not sure why.. :( */ |
22 | 217 | const char *cipher_names[] = { NULL, "", "AES-128-ECB", "AES-192-ECB", "AES-256-ECB", |
23 | 217 | /* "AES-128-GCM", "AES-192-GCM", "AES-256-GCM" */ }; |
24 | 217 | const char *cipher_name; |
25 | 217 | mbedtls_cipher_context_t *ctx_e, *ctx_d; |
26 | | |
27 | | /* No real memory allocations involved */ |
28 | | |
29 | 217 | if(fuzzed_data.remaining_bytes() < 512) /* Some data */ |
30 | 16 | return -1; |
31 | | |
32 | 201 | posix_memalign((void **)&ctx_e, 8, sizeof(mbedtls_cipher_context_t)); |
33 | 201 | posix_memalign((void **)&ctx_d, 8, sizeof(mbedtls_cipher_context_t)); |
34 | | |
35 | 201 | key_len = fuzzed_data.PickValueInArray(key_lens); |
36 | 201 | std::vector<unsigned char>key = fuzzed_data.ConsumeBytes<u_int8_t>(key_len / 8); |
37 | 201 | iv_len = fuzzed_data.ConsumeIntegralInRange(0, MBEDTLS_MAX_IV_LENGTH + 1); |
38 | 201 | std::vector<u_int8_t>iv = fuzzed_data.ConsumeBytes<uint8_t>(iv_len); |
39 | 201 | input_length = fuzzed_data.ConsumeIntegralInRange(16, 17); |
40 | 201 | std::vector<unsigned char>input = fuzzed_data.ConsumeBytes<u_int8_t>(input_length); |
41 | 201 | output = (unsigned char *)malloc(input_length); |
42 | 201 | decrypted = (unsigned char *)malloc(input_length); |
43 | | |
44 | 201 | mbedtls_cipher_list(); |
45 | | /* Random iteration */ |
46 | 201 | cipher_type = static_cast<mbedtls_cipher_type_t>(fuzzed_data.ConsumeIntegralInRange(0, (int)MBEDTLS_CIPHER_AES_256_KWP) + 1); |
47 | 201 | mbedtls_cipher_info_from_type(cipher_type); |
48 | | |
49 | | /* Real cipher used */ |
50 | 201 | cipher_name = cipher_names[fuzzed_data.ConsumeIntegralInRange(0, (int)(sizeof(cipher_names) / sizeof(char *) - 1))]; |
51 | 201 | mbedtls_cipher_init(ctx_e); |
52 | 201 | mbedtls_cipher_init(ctx_d); |
53 | 201 | ctx_e->cipher_info = mbedtls_cipher_info_from_string(cipher_name); |
54 | 201 | ctx_d->cipher_info = ctx_e->cipher_info; |
55 | | |
56 | 201 | mbedtls_cipher_info_get_mode(ctx_e->cipher_info); |
57 | 201 | mbedtls_cipher_info_get_type(ctx_e->cipher_info); |
58 | 201 | mbedtls_cipher_info_get_name(ctx_e->cipher_info); |
59 | 201 | mbedtls_cipher_info_has_variable_key_bitlen(ctx_e->cipher_info); |
60 | 201 | mbedtls_cipher_info_has_variable_iv_size(ctx_e->cipher_info); |
61 | 201 | mbedtls_cipher_info_get_iv_size(ctx_e->cipher_info); |
62 | 201 | mbedtls_cipher_info_get_block_size(ctx_e->cipher_info); |
63 | 201 | mbedtls_cipher_get_cipher_mode(ctx_e); |
64 | 201 | mbedtls_cipher_get_iv_size(ctx_e); |
65 | 201 | mbedtls_cipher_get_type(ctx_e); |
66 | 201 | mbedtls_cipher_get_name(ctx_e); |
67 | 201 | mbedtls_cipher_get_key_bitlen(ctx_e); |
68 | 201 | mbedtls_cipher_get_operation(ctx_e); |
69 | 201 | mbedtls_cipher_info_get_key_bitlen(ctx_e->cipher_info); |
70 | 201 | mbedtls_error_add(0, 0, NULL, 0); |
71 | | |
72 | 201 | posix_memalign((void **)&ctx_e->cipher_ctx, 8, sizeof(mbedtls_aes_context)); |
73 | 201 | posix_memalign((void **)&ctx_d->cipher_ctx, 8, sizeof(mbedtls_aes_context)); |
74 | | |
75 | 201 | rc_e = mbedtls_cipher_setkey(ctx_e, key.data(), key.size() * 8, MBEDTLS_ENCRYPT); |
76 | 201 | rc_d = mbedtls_cipher_setkey(ctx_d, key.data(), key.size() * 8, MBEDTLS_DECRYPT); |
77 | 201 | if(rc_e == 0 && rc_d == 0) { |
78 | | |
79 | 84 | if(fuzzed_data.ConsumeBool()) { |
80 | 47 | rc_e = mbedtls_cipher_crypt(ctx_e, iv.data(), iv.size(), |
81 | 47 | input.data(), input.size(), output, &output_size); |
82 | 47 | } else { |
83 | 37 | rc_e = mbedtls_cipher_set_iv(ctx_e, iv.data(), iv.size()); |
84 | 37 | rc_d = mbedtls_cipher_set_iv(ctx_d, iv.data(), iv.size()); |
85 | 37 | if(rc_e == 0 && rc_d == 0) { |
86 | 32 | mbedtls_cipher_reset(ctx_e); |
87 | 32 | mbedtls_cipher_reset(ctx_d); |
88 | | |
89 | 32 | rc_e = mbedtls_cipher_update(ctx_e, input.data(), input.size(), output, &output_size); |
90 | 32 | if(rc_e == 0) { |
91 | 23 | rc_e = mbedtls_cipher_finish(ctx_e, NULL, &output_size2); |
92 | 23 | if(rc_e == 0) { |
93 | | |
94 | 23 | rc_d = mbedtls_cipher_update(ctx_d, output, output_size, decrypted, &decrypted_size); |
95 | 23 | if(rc_d == 0) { |
96 | 23 | rc_d = mbedtls_cipher_finish(ctx_d, NULL, &output_size2); |
97 | | /* TODO: decryption doesn't work with no-aesni data path! |
98 | | Note that with MASAN, aesni is always disabled */ |
99 | | #if 0 |
100 | | if(rc_d == 0) { |
101 | | assert(input.size() == decrypted_size); |
102 | | assert(memcmp(input.data(), decrypted, decrypted_size) == 0); |
103 | | } |
104 | | #endif |
105 | 23 | } |
106 | 23 | } |
107 | 23 | } |
108 | 32 | } |
109 | 37 | } |
110 | 84 | } |
111 | | |
112 | 201 | free(output); |
113 | 201 | free(decrypted); |
114 | 201 | free(ctx_e->cipher_ctx); |
115 | 201 | free(ctx_e); |
116 | 201 | free(ctx_d->cipher_ctx); |
117 | 201 | free(ctx_d); |
118 | 201 | return 0; |
119 | 217 | } |