Coverage Report

Created: 2026-06-07 06:38

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
381
static int always_available(void) { return 1; }
53
54
605
extern "C" int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) {
55
605
  if (sodium_init() == -1) {
56
0
    return 0;
57
0
  }
58
59
605
  if (size < 2) {
60
2
    return 0;
61
2
  }
62
63
603
  static AEAD_Algorithm algs[] = {
64
603
    {
65
603
      crypto_aead_chacha20poly1305_ietf_encrypt,
66
603
      crypto_aead_chacha20poly1305_ietf_decrypt,
67
603
      crypto_aead_chacha20poly1305_ietf_KEYBYTES,
68
603
      crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
69
603
      crypto_aead_chacha20poly1305_ietf_ABYTES,
70
603
      always_available
71
603
    },
72
603
    {
73
603
      crypto_aead_xchacha20poly1305_ietf_encrypt,
74
603
      crypto_aead_xchacha20poly1305_ietf_decrypt,
75
603
      crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
76
603
      crypto_aead_xchacha20poly1305_ietf_NPUBBYTES,
77
603
      crypto_aead_xchacha20poly1305_ietf_ABYTES,
78
603
      always_available
79
603
    },
80
603
    {
81
603
      crypto_aead_chacha20poly1305_encrypt,
82
603
      crypto_aead_chacha20poly1305_decrypt,
83
603
      crypto_aead_chacha20poly1305_KEYBYTES,
84
603
      crypto_aead_chacha20poly1305_NPUBBYTES,
85
603
      crypto_aead_chacha20poly1305_ABYTES,
86
603
      always_available
87
603
    },
88
603
#ifdef crypto_aead_aegis128l_KEYBYTES
89
603
    {
90
603
      crypto_aead_aegis128l_encrypt,
91
603
      crypto_aead_aegis128l_decrypt,
92
603
      crypto_aead_aegis128l_KEYBYTES,
93
603
      crypto_aead_aegis128l_NPUBBYTES,
94
603
      crypto_aead_aegis128l_ABYTES,
95
603
      always_available
96
603
    },
97
603
#endif
98
603
#ifdef crypto_aead_aegis256_KEYBYTES
99
603
    {
100
603
      crypto_aead_aegis256_encrypt,
101
603
      crypto_aead_aegis256_decrypt,
102
603
      crypto_aead_aegis256_KEYBYTES,
103
603
      crypto_aead_aegis256_NPUBBYTES,
104
603
      crypto_aead_aegis256_ABYTES,
105
603
      always_available
106
603
    },
107
603
#endif
108
603
    {
109
603
      crypto_aead_aes256gcm_encrypt,
110
603
      crypto_aead_aes256gcm_decrypt,
111
603
      crypto_aead_aes256gcm_KEYBYTES,
112
603
      crypto_aead_aes256gcm_NPUBBYTES,
113
603
      crypto_aead_aes256gcm_ABYTES,
114
603
      crypto_aead_aes256gcm_is_available
115
603
    }
116
603
  };
117
603
  size_t num_algs = sizeof(algs) / sizeof(algs[0]);
118
119
603
  uint8_t choice = data[0] % num_algs;
120
603
  const AEAD_Algorithm &alg = algs[choice];
121
122
603
  if (alg.is_available && !alg.is_available()) {
123
0
      return 0;
124
0
  }
125
126
603
  if (size < 1 + alg.key_bytes + alg.npub_bytes) {
127
11
    return 0;
128
11
  }
129
130
592
  const unsigned char *k = data + 1;
131
592
  const unsigned char *npub = data + 1 + alg.key_bytes;
132
592
  const unsigned char *msg = data + 1 + alg.key_bytes + alg.npub_bytes;
133
592
  size_t total_msg_len = size - (1 + alg.key_bytes + alg.npub_bytes);
134
135
  // Split remaining data into message and associated data
136
592
  size_t ad_len = total_msg_len / 4;
137
592
  size_t msg_len = total_msg_len - ad_len;
138
592
  const unsigned char *ad = msg;
139
592
  msg += ad_len;
140
141
  // Limit lengths to avoid timeouts
142
592
  if (msg_len > 4096) msg_len = 4096;
143
592
  if (ad_len > 4096) ad_len = 4096;
144
145
592
  unsigned char *ciphertext = (unsigned char *) malloc(msg_len + alg.a_bytes);
146
592
  unsigned long long ciphertext_len;
147
148
592
  alg.encrypt(ciphertext, &ciphertext_len,
149
592
              msg, msg_len,
150
592
              ad, ad_len,
151
592
              NULL, npub, k);
152
153
592
  unsigned char *decrypted = (unsigned char *) malloc(msg_len + alg.a_bytes);
154
592
  unsigned long long decrypted_len;
155
592
  int err = alg.decrypt(decrypted, &decrypted_len,
156
592
                        NULL,
157
592
                        ciphertext, ciphertext_len,
158
592
                        ad, ad_len,
159
592
                        npub, k);
160
  
161
592
  if (err == 0) {
162
592
      assert(decrypted_len == msg_len);
163
592
      assert(memcmp(decrypted, msg, msg_len) == 0);
164
592
  }
165
166
592
  free(ciphertext);
167
592
  free(decrypted);
168
169
592
  return 0;
170
592
}