Skip to content

Commit 9ecf1f3

Browse files
committed
Differential fuzzing of key exchange
1 parent 789ab6c commit 9ecf1f3

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

fuzz/Cargo.toml

+7
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,10 @@ path = "fuzzer/aead.rs"
2727
test = false
2828
doc = false
2929
bench = false
30+
31+
[[bin]]
32+
name = "kx"
33+
path = "fuzzer/kx.rs"
34+
test = false
35+
doc = false
36+
bench = false

fuzz/fuzzer/kx.rs

+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#![no_main]
2+
3+
use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target};
4+
5+
fuzz_target!(|op: Operation| {
6+
match op {
7+
Operation::X25519BaseMul(scalar) => {
8+
let left = aws_lc_rs::agreement::PrivateKey::from_private_key(
9+
&aws_lc_rs::agreement::X25519,
10+
&scalar,
11+
)
12+
.unwrap()
13+
.compute_public_key()
14+
.unwrap();
15+
16+
let right =
17+
graviola::key_agreement::x25519::StaticPrivateKey::from_array(&scalar).public_key();
18+
19+
assert_eq!(left.as_ref(), right.as_bytes());
20+
}
21+
22+
Operation::X25519Agree { scalar, peer } => {
23+
let left = aws_lc_rs::agreement::agree(
24+
&aws_lc_rs::agreement::PrivateKey::from_private_key(
25+
&aws_lc_rs::agreement::X25519,
26+
&scalar,
27+
)
28+
.unwrap(),
29+
&aws_lc_rs::agreement::UnparsedPublicKey::new(&aws_lc_rs::agreement::X25519, &peer),
30+
aws_lc_rs::error::Unspecified,
31+
|key| Ok(key.to_vec()),
32+
)
33+
.map_err(|_| ());
34+
35+
let right = graviola::key_agreement::x25519::StaticPrivateKey::from_array(&scalar)
36+
.diffie_hellman(&graviola::key_agreement::x25519::PublicKey::from_array(
37+
&peer,
38+
))
39+
.map(|ss| ss.0.to_vec())
40+
.map_err(|_| ());
41+
42+
assert_eq!(&left, &right);
43+
}
44+
45+
Operation::P256BaseMul(scalar) => {
46+
let left = aws_lc_rs::agreement::PrivateKey::from_private_key(
47+
&aws_lc_rs::agreement::ECDH_P256,
48+
&scalar,
49+
)
50+
.map(|private| private.compute_public_key().unwrap().as_ref().to_vec())
51+
.map_err(|_| ());
52+
53+
let right = graviola::key_agreement::p256::StaticPrivateKey::from_bytes(&scalar)
54+
.map(|private| private.public_key_uncompressed().to_vec())
55+
.map_err(|_| ());
56+
57+
assert_eq!(left, right);
58+
}
59+
60+
Operation::P256Agree { scalar, peer } => {
61+
let left = aws_lc_rs::agreement::PrivateKey::from_private_key(
62+
&aws_lc_rs::agreement::ECDH_P256,
63+
&scalar,
64+
)
65+
.map_err(|_| ())
66+
.and_then(|private| {
67+
aws_lc_rs::agreement::agree(
68+
&private,
69+
&aws_lc_rs::agreement::UnparsedPublicKey::new(
70+
&aws_lc_rs::agreement::ECDH_P256,
71+
&peer,
72+
),
73+
(),
74+
|key| Ok(key.to_vec()),
75+
)
76+
})
77+
.map_err(|_| ());
78+
79+
let right = graviola::key_agreement::p256::StaticPrivateKey::from_bytes(&scalar)
80+
.and_then(|private| {
81+
graviola::key_agreement::p256::PublicKey::from_x962_uncompressed(&peer)
82+
.map(|public| (private, public))
83+
})
84+
.and_then(|(private, public)| private.diffie_hellman(&public))
85+
.map(|ss| ss.0.to_vec())
86+
.map_err(|_| ());
87+
88+
assert_eq!(&left, &right);
89+
}
90+
91+
Operation::P384BaseMul(scalar) => {
92+
let left = aws_lc_rs::agreement::PrivateKey::from_private_key(
93+
&aws_lc_rs::agreement::ECDH_P384,
94+
&scalar,
95+
)
96+
.map(|private| private.compute_public_key().unwrap().as_ref().to_vec())
97+
.map_err(|_| ());
98+
99+
let right = graviola::key_agreement::p384::StaticPrivateKey::from_bytes(&scalar)
100+
.map(|private| private.public_key_uncompressed().to_vec())
101+
.map_err(|_| ());
102+
103+
assert_eq!(left, right);
104+
}
105+
106+
Operation::P384Agree { scalar, peer } => {
107+
let left = aws_lc_rs::agreement::PrivateKey::from_private_key(
108+
&aws_lc_rs::agreement::ECDH_P384,
109+
&scalar,
110+
)
111+
.map_err(|_| ())
112+
.and_then(|private| {
113+
aws_lc_rs::agreement::agree(
114+
&private,
115+
&aws_lc_rs::agreement::UnparsedPublicKey::new(
116+
&aws_lc_rs::agreement::ECDH_P384,
117+
&peer,
118+
),
119+
(),
120+
|key| Ok(key.to_vec()),
121+
)
122+
})
123+
.map_err(|_| ());
124+
125+
let right = graviola::key_agreement::p384::StaticPrivateKey::from_bytes(&scalar)
126+
.and_then(|private| {
127+
graviola::key_agreement::p384::PublicKey::from_x962_uncompressed(&peer)
128+
.map(|public| (private, public))
129+
})
130+
.and_then(|(private, public)| private.diffie_hellman(&public))
131+
.map(|ss| ss.0.to_vec())
132+
.map_err(|_| ());
133+
134+
assert_eq!(&left, &right);
135+
}
136+
}
137+
});
138+
139+
#[derive(Arbitrary, Debug)]
140+
enum Operation {
141+
X25519BaseMul([u8; 32]),
142+
X25519Agree { scalar: [u8; 32], peer: [u8; 32] },
143+
P256BaseMul([u8; 32]),
144+
P256Agree { scalar: [u8; 32], peer: [u8; 65] },
145+
P384BaseMul([u8; 48]),
146+
P384Agree { scalar: [u8; 48], peer: [u8; 97] },
147+
}

0 commit comments

Comments
 (0)