dup_crypto/private_message/
authentication.rs1use super::{PrivateMessageError, AUTHENTICATION_DATAS_LEN, SENDER_PUBLIC_KEY_LEN};
19use crate::keys::x25519::{diffie_hellman, X25519PublicKey, X25519SecretKey};
20use crate::keys::{KeyPair, PublicKey, Signator};
21use crate::{
22 hashs::Hash64,
23 keys::ed25519::{Ed25519KeyPair, PublicKey as Ed25519PublicKey, Signature},
24};
25use std::{convert::TryFrom, hint::unreachable_unchecked};
26
27#[derive(Clone, Copy, Debug)]
28pub enum AuthenticationPolicy {
33 PrivateAuthentication,
39 Signature,
45}
46
47impl From<AuthenticationPolicy> for u8 {
48 fn from(val: AuthenticationPolicy) -> Self {
49 match val {
50 AuthenticationPolicy::PrivateAuthentication => 0,
51 AuthenticationPolicy::Signature => 1,
52 }
53 }
54}
55
56impl From<u8> for AuthenticationPolicy {
57 fn from(source: u8) -> Self {
58 match source {
59 0 => Self::PrivateAuthentication,
60 _ => Self::Signature,
61 }
62 }
63}
64
65pub(crate) struct AuthenticationProof([u8; 64]);
66
67impl AsRef<[u8]> for AuthenticationProof {
68 fn as_ref(&self) -> &[u8] {
69 &self.0
70 }
71}
72
73pub(crate) fn write_anthentication_datas(
74 sender_public_key: &Ed25519PublicKey,
75 authent_proof: AuthenticationProof,
76 authent_policy: AuthenticationPolicy,
77) -> impl AsRef<[u8]> + IntoIterator<Item = u8> {
78 let mut authent_datas = arrayvec::ArrayVec::<u8, 97>::new();
79 authent_datas
80 .try_extend_from_slice(sender_public_key.datas.as_ref())
81 .unwrap_or_else(|_| unsafe { unreachable_unchecked() }); authent_datas
83 .try_extend_from_slice(authent_proof.as_ref())
84 .unwrap_or_else(|_| unsafe { unreachable_unchecked() }); authent_datas.push(authent_policy.into());
86 authent_datas
87}
88
89pub(crate) fn generate_authentication_proof(
90 authentication_policy: AuthenticationPolicy,
91 sender_keypair: &Ed25519KeyPair,
92 receiver_public_key: &Ed25519PublicKey,
93 message: &[u8],
94) -> AuthenticationProof {
95 AuthenticationProof(match authentication_policy {
96 AuthenticationPolicy::PrivateAuthentication => diffie_hellman(
97 X25519SecretKey::from(sender_keypair.seed()),
98 X25519PublicKey::from(receiver_public_key),
99 |key_material| Hash64::sha512_multipart(&[message, key_material]).0,
100 ),
101 AuthenticationPolicy::Signature => {
102 sender_keypair.generate_signator().sign(message.as_ref()).0
103 }
104 })
105}
106
107pub(crate) fn verify_authentication_proof(
108 receiver_key_pair: &Ed25519KeyPair,
109 message: &[u8],
110 authentication_datas: &[u8],
111) -> Result<(Ed25519PublicKey, Option<Signature>), PrivateMessageError> {
112 let sender_public_key =
113 Ed25519PublicKey::try_from(&authentication_datas[..SENDER_PUBLIC_KEY_LEN])
114 .map_err(PrivateMessageError::InvalidSenderPubKey)?;
115 let mut authent_proof = AuthenticationProof([0u8; 64]);
116 authent_proof.0.copy_from_slice(
117 &authentication_datas[SENDER_PUBLIC_KEY_LEN..(AUTHENTICATION_DATAS_LEN - 1)],
118 );
119 let mut signature_opt = None;
120 match AuthenticationPolicy::from(authentication_datas[AUTHENTICATION_DATAS_LEN - 1]) {
121 AuthenticationPolicy::PrivateAuthentication => {
122 let expected_proof = AuthenticationProof(diffie_hellman(
123 X25519SecretKey::from(receiver_key_pair.seed()),
124 X25519PublicKey::from(&sender_public_key),
125 |key_material| Hash64::sha512_multipart(&[message, key_material]).0,
126 ));
127 for i in 0..32 {
128 if expected_proof.0[i] != authent_proof.0[i] {
129 return Err(PrivateMessageError::InvalidAuthenticationProof);
130 }
131 }
132 }
133 AuthenticationPolicy::Signature => {
134 signature_opt = Some(Signature(authent_proof.0));
135 sender_public_key
136 .verify(message, &Signature(authent_proof.0))
137 .map_err(|_| PrivateMessageError::InvalidAuthenticationProof)?;
138 }
139 }
140 Ok((sender_public_key, signature_opt))
141}
142
143#[cfg(test)]
144mod tests {
145
146 use super::*;
147 use crate::keys::ed25519::KeyPairFromSeed32Generator;
148 use crate::seeds::Seed32;
149
150 const MESSAGE: &[u8] = b"message";
151
152 #[test]
153 fn private_authent_ok() -> Result<(), PrivateMessageError> {
154 let sender_key_pair = KeyPairFromSeed32Generator::generate(Seed32::random()?);
155 let receiver_key_pair = KeyPairFromSeed32Generator::generate(Seed32::random()?);
156
157 let authent_policy = AuthenticationPolicy::PrivateAuthentication;
158
159 let authent_proof = generate_authentication_proof(
160 authent_policy,
161 &sender_key_pair,
162 &receiver_key_pair.public_key(),
163 MESSAGE,
164 );
165
166 let authent_datas = write_anthentication_datas(
167 &sender_key_pair.public_key(),
168 authent_proof,
169 authent_policy,
170 );
171
172 verify_authentication_proof(&receiver_key_pair, MESSAGE, authent_datas.as_ref())?;
173
174 Ok(())
175 }
176
177 #[test]
178 fn invalid_sender_pubkey() -> Result<(), PrivateMessageError> {
179 let sender_key_pair = KeyPairFromSeed32Generator::generate(Seed32::random()?);
180 let receiver_key_pair = KeyPairFromSeed32Generator::generate(Seed32::random()?);
181
182 let authent_policy = AuthenticationPolicy::PrivateAuthentication;
183
184 let authent_proof = generate_authentication_proof(
185 authent_policy,
186 &sender_key_pair,
187 &receiver_key_pair.public_key(),
188 MESSAGE,
189 );
190
191 let mut authent_datas: Vec<u8> = write_anthentication_datas(
192 &sender_key_pair.public_key(),
193 authent_proof,
194 authent_policy,
195 )
196 .as_ref()
197 .to_vec();
198
199 let invalid_pubkey_bytes = [
200 206u8, 58, 67, 221, 20, 133, 0, 225, 86, 115, 26, 104, 142, 116, 140, 132, 119, 51,
201 175, 45, 82, 225, 14, 195, 7, 107, 43, 212, 8, 37, 234, 23,
202 ];
203
204 authent_datas[..32].copy_from_slice(&invalid_pubkey_bytes);
205
206 if let Err(PrivateMessageError::InvalidSenderPubKey(_)) =
207 verify_authentication_proof(&receiver_key_pair, MESSAGE, authent_datas.as_ref())
208 {
209 Ok(())
210 } else {
211 panic!("Expected PrivateMessageError::InvalidSenderPubKey.")
212 }
213 }
214
215 #[test]
216 fn invalid_private_authent_proof() -> Result<(), PrivateMessageError> {
217 let sender_key_pair = KeyPairFromSeed32Generator::generate(Seed32::random()?);
218 let receiver_key_pair = KeyPairFromSeed32Generator::generate(Seed32::random()?);
219
220 let authent_policy = AuthenticationPolicy::PrivateAuthentication;
221
222 let authent_proof = generate_authentication_proof(
223 authent_policy,
224 &receiver_key_pair, &receiver_key_pair.public_key(),
226 MESSAGE,
227 );
228
229 let authent_datas = write_anthentication_datas(
230 &sender_key_pair.public_key(),
231 authent_proof,
232 authent_policy,
233 );
234
235 if let Err(PrivateMessageError::InvalidAuthenticationProof) =
236 verify_authentication_proof(&receiver_key_pair, MESSAGE, authent_datas.as_ref())
237 {
238 Ok(())
239 } else {
240 panic!("Expected PrivateMessageError::InvalidSenderPubKey.")
241 }
242 }
243
244 #[test]
245 fn invalid_sig_authent_proof() -> Result<(), PrivateMessageError> {
246 let sender_key_pair = KeyPairFromSeed32Generator::generate(Seed32::random()?);
247 let receiver_key_pair = KeyPairFromSeed32Generator::generate(Seed32::random()?);
248
249 let authent_policy = AuthenticationPolicy::Signature;
250
251 let authent_proof = generate_authentication_proof(
252 authent_policy,
253 &receiver_key_pair, &receiver_key_pair.public_key(),
255 MESSAGE,
256 );
257
258 let authent_datas = write_anthentication_datas(
259 &sender_key_pair.public_key(),
260 authent_proof,
261 authent_policy,
262 );
263
264 if let Err(PrivateMessageError::InvalidAuthenticationProof) =
265 verify_authentication_proof(&receiver_key_pair, MESSAGE, authent_datas.as_ref())
266 {
267 Ok(())
268 } else {
269 panic!("Expected PrivateMessageError::InvalidSenderPubKey.")
270 }
271 }
272
273 #[test]
274 fn sig_authent_ok() -> Result<(), PrivateMessageError> {
275 let sender_key_pair = KeyPairFromSeed32Generator::generate(Seed32::random()?);
276 let receiver_key_pair = KeyPairFromSeed32Generator::generate(Seed32::random()?);
277
278 let authent_policy = AuthenticationPolicy::Signature;
279
280 let authent_proof = generate_authentication_proof(
281 authent_policy,
282 &sender_key_pair,
283 &receiver_key_pair.public_key(),
284 MESSAGE,
285 );
286
287 let authent_datas = write_anthentication_datas(
288 &sender_key_pair.public_key(),
289 authent_proof,
290 authent_policy,
291 );
292
293 verify_authentication_proof(&receiver_key_pair, MESSAGE, authent_datas.as_ref())?;
294
295 Ok(())
296 }
297}