Coverage Report

Created: 2026-07-10 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/crypto_aead_fuzzer.cc
Line
Count
Source
1
// Copyright 2026 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <assert.h>
16
#include <stdlib.h>
17
#include <stdint.h>
18
#include <string.h>
19
#include <sodium.h>
20
21
#include "fake_random.h"
22
23
typedef int (*aead_encrypt_fn)(unsigned char *cipher,
24
                               unsigned long long *cipher_len,
25
                               const unsigned char *message,
26
                               unsigned long long message_len,
27
                               const unsigned char *ad,
28
                               unsigned long long ad_len,
29
                               const unsigned char *nsec,
30
                               const unsigned char *npub,
31
                               const unsigned char *k);
32
33
typedef int (*aead_decrypt_fn)(unsigned char *message,
34
                               unsigned long long *message_len,
35
                               unsigned char *nsec,
36
                               const unsigned char *cipher,
37
                               unsigned long long cipher_len,
38
                               const unsigned char *ad,
39
                               unsigned long long ad_len,
40
                               const unsigned char *npub,
41
                               const unsigned char *k);
42
43
struct AEAD_Algorithm {
44
    aead_encrypt_fn encrypt;
45
    aead_decrypt_fn decrypt;
46
    size_t key_bytes;
47
    size_t npub_bytes;
48
    size_t a_bytes;
49
    int (*is_available)(void);
50
};
51
52
375
static int always_available(void) { return 1; }
53
54
598
extern "C" int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) {
55
598
  if (sodium_init() == -1) {
56
0
    return 0;
57
0
  }
58
59
598
  if (size < 2) {
60
2
    return 0;
61
2
  }
62
63
596
  static AEAD_Algorithm algs[] = {
64
596
    {
65
596
      crypto_aead_chacha20poly1305_ietf_encrypt,
66
596
      crypto_aead_chacha20poly1305_ietf_decrypt,
67
596
      crypto_aead_chacha20poly1305_ietf_KEYBYTES,
68
596
      crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
69
596
      crypto_aead_chacha20poly1305_ietf_ABYTES,
70
596
      always_available
71
596
    },
72
596
    {
73
596
      crypto_aead_xchacha20poly1305_ietf_encrypt,
74
596
      crypto_aead_xchacha20poly1305_ietf_decrypt,
75
596
      crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
76
596
      crypto_aead_xchacha20poly1305_ietf_NPUBBYTES,
77
596
      crypto_aead_xchacha20poly1305_ietf_ABYTES,
78
596
      always_available
79
596
    },
80
596
    {
81
596
      crypto_aead_chacha20poly1305_encrypt,
82
596
      crypto_aead_chacha20poly1305_decrypt,
83
596
      crypto_aead_chacha20poly1305_KEYBYTES,
84
596
      crypto_aead_chacha20poly1305_NPUBBYTES,
85
596
      crypto_aead_chacha20poly1305_ABYTES,
86
596
      always_available
87
596
    },
88
596
#ifdef crypto_aead_aegis128l_KEYBYTES
89
596
    {
90
596
      crypto_aead_aegis128l_encrypt,
91
596
      crypto_aead_aegis128l_decrypt,
92
596
      crypto_aead_aegis128l_KEYBYTES,
93
596
      crypto_aead_aegis128l_NPUBBYTES,
94
596
      crypto_aead_aegis128l_ABYTES,
95
596
      always_available
96
596
    },
97
596
#endif
98
596
#ifdef crypto_aead_aegis256_KEYBYTES
99
596
    {
100
596
      crypto_aead_aegis256_encrypt,
101
596
      crypto_aead_aegis256_decrypt,
102
596
      crypto_aead_aegis256_KEYBYTES,
103
596
      crypto_aead_aegis256_NPUBBYTES,
104
596
      crypto_aead_aegis256_ABYTES,
105
596
      always_available
106
596
    },
107
596
#endif
108
596
    {
109
596
      crypto_aead_aes256gcm_encrypt,
110
596
      crypto_aead_aes256gcm_decrypt,
111
596
      crypto_aead_aes256gcm_KEYBYTES,
112
596
      crypto_aead_aes256gcm_NPUBBYTES,
113
596
      crypto_aead_aes256gcm_ABYTES,
114
596
      crypto_aead_aes256gcm_is_available
115
596
    }
116
596
  };
117
596
  size_t num_algs = sizeof(algs) / sizeof(algs[0]);
118
119
596
  uint8_t choice = data[0] % num_algs;
120
596
  const AEAD_Algorithm &alg = algs[choice];
121
122
596
  if (alg.is_available && !alg.is_available()) {
123
0
      return 0;
124
0
  }
125
126
596
  if (size < 1 + alg.key_bytes + alg.npub_bytes) {
127
12
    return 0;
128
12
  }
129
130
584
  const unsigned char *k = data + 1;
131
584
  const unsigned char *npub = data + 1 + alg.key_bytes;
132
584
  const unsigned char *msg = data + 1 + alg.key_bytes + alg.npub_bytes;
133
584
  size_t total_msg_len = size - (1 + alg.key_bytes + alg.npub_bytes);
134
135
  // Split remaining data into message and associated data
136
584
  size_t ad_len = total_msg_len / 4;
137
584
  size_t msg_len = total_msg_len - ad_len;
138
584
  const unsigned char *ad = msg;
139
584
  msg += ad_len;
140
141
  // Limit lengths to avoid timeouts
142
584
  if (msg_len > 4096) msg_len = 4096;
143
584
  if (ad_len > 4096) ad_len = 4096;
144
145
584
  unsigned char *ciphertext = (unsigned char *) malloc(msg_len + alg.a_bytes);
146
584
  unsigned long long ciphertext_len;
147
148
584
  alg.encrypt(ciphertext, &ciphertext_len,
149
584
              msg, msg_len,
150
584
              ad, ad_len,
151
584
              NULL, npub, k);
152
153
584
  unsigned char *decrypted = (unsigned char *) malloc(msg_len + alg.a_bytes);
154
584
  unsigned long long decrypted_len;
155
584
  int err = alg.decrypt(decrypted, &decrypted_len,
156
584
                        NULL,
157
584
                        ciphertext, ciphertext_len,
158
584
                        ad, ad_len,
159
584
                        npub, k);
160
  
161
584
  if (err == 0) {
162
584
      assert(decrypted_len == msg_len);
163
584
      assert(memcmp(decrypted, msg, msg_len) == 0);
164
584
  }
165
166
584
  free(ciphertext);
167
584
  free(decrypted);
168
169
584
  return 0;
170
584
}