1use std::fmt;
7use std::fmt::Write;
8
9use prost::Message;
10use sha2::digest::Digest;
11use sha2::Sha512;
12use subtle::ConstantTimeEq;
13
14use crate::{proto, IdentityKey, Result, SignalProtocolError};
15
16#[derive(Debug, Clone)]
17pub struct DisplayableFingerprint {
18 local: String,
19 remote: String,
20}
21
22impl fmt::Display for DisplayableFingerprint {
23 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24 if self.local < self.remote {
25 write!(f, "{}{}", self.local, self.remote)
26 } else {
27 write!(f, "{}{}", self.remote, self.local)
28 }
29 }
30}
31
32fn get_encoded_string(fprint: &[u8]) -> Result<String> {
33 if fprint.len() < 30 {
34 return Err(SignalProtocolError::InvalidArgument(
35 "DisplayableFingerprint created with short encoding".to_string(),
36 ));
37 }
38
39 fn read5_mod_100k(fprint: &[u8]) -> u64 {
40 assert_eq!(fprint.len(), 5);
41 let x = fprint.iter().fold(0u64, |acc, &x| (acc << 8) | (x as u64));
42 x % 100_000
43 }
44
45 let s = fprint.chunks_exact(5).take(6).map(read5_mod_100k).fold(
46 String::with_capacity(5 * 6),
47 |mut s, n| {
48 write!(s, "{:05}", n).expect("can always write to a String");
49 s
50 },
51 );
52
53 Ok(s)
54}
55
56impl DisplayableFingerprint {
57 pub fn new(local: &[u8], remote: &[u8]) -> Result<Self> {
58 Ok(Self {
59 local: get_encoded_string(local)?,
60 remote: get_encoded_string(remote)?,
61 })
62 }
63}
64
65#[derive(Debug, Clone)]
66pub struct ScannableFingerprint {
67 version: u32,
68 local_fingerprint: Vec<u8>,
69 remote_fingerprint: Vec<u8>,
70}
71
72impl ScannableFingerprint {
73 fn new(version: u32, local_fprint: &[u8], remote_fprint: &[u8]) -> Self {
74 Self {
75 version,
76 local_fingerprint: local_fprint[..32].to_vec(),
77 remote_fingerprint: remote_fprint[..32].to_vec(),
78 }
79 }
80
81 pub fn deserialize(protobuf: &[u8]) -> Result<Self> {
82 let fingerprint = proto::fingerprint::CombinedFingerprints::decode(protobuf)
83 .map_err(|_| SignalProtocolError::FingerprintParsingError)?;
84
85 Ok(Self {
86 version: fingerprint
87 .version
88 .ok_or(SignalProtocolError::FingerprintParsingError)?,
89 local_fingerprint: fingerprint
90 .local_fingerprint
91 .ok_or(SignalProtocolError::FingerprintParsingError)?
92 .content
93 .ok_or(SignalProtocolError::FingerprintParsingError)?,
94 remote_fingerprint: fingerprint
95 .remote_fingerprint
96 .ok_or(SignalProtocolError::FingerprintParsingError)?
97 .content
98 .ok_or(SignalProtocolError::FingerprintParsingError)?,
99 })
100 }
101
102 pub fn serialize(&self) -> Result<Vec<u8>> {
103 let combined_fingerprints = proto::fingerprint::CombinedFingerprints {
104 version: Some(self.version),
105 local_fingerprint: Some(proto::fingerprint::LogicalFingerprint {
106 content: Some(self.local_fingerprint.to_owned()),
107 }),
108 remote_fingerprint: Some(proto::fingerprint::LogicalFingerprint {
109 content: Some(self.remote_fingerprint.to_owned()),
110 }),
111 };
112
113 Ok(combined_fingerprints.encode_to_vec())
114 }
115
116 pub fn compare(&self, combined: &[u8]) -> Result<bool> {
117 let combined = proto::fingerprint::CombinedFingerprints::decode(combined)
118 .map_err(|_| SignalProtocolError::FingerprintParsingError)?;
119
120 let their_version = combined.version.unwrap_or(0);
121
122 if their_version != self.version {
123 return Err(SignalProtocolError::FingerprintVersionMismatch(
124 their_version,
125 self.version,
126 ));
127 }
128
129 let same1 = combined
130 .local_fingerprint
131 .as_ref()
132 .ok_or(SignalProtocolError::FingerprintParsingError)?
133 .content
134 .as_ref()
135 .ok_or(SignalProtocolError::FingerprintParsingError)?
136 .ct_eq(&self.remote_fingerprint);
137 let same2 = combined
138 .remote_fingerprint
139 .as_ref()
140 .ok_or(SignalProtocolError::FingerprintParsingError)?
141 .content
142 .as_ref()
143 .ok_or(SignalProtocolError::FingerprintParsingError)?
144 .ct_eq(&self.local_fingerprint);
145
146 Ok(same1.into() && same2.into())
147 }
148}
149
150#[derive(Debug, Clone)]
151pub struct Fingerprint {
152 pub display: DisplayableFingerprint,
153 pub scannable: ScannableFingerprint,
154}
155
156impl Fingerprint {
157 fn get_fingerprint(
158 iterations: u32,
159 local_id: &[u8],
160 local_key: &IdentityKey,
161 ) -> Result<Vec<u8>> {
162 if iterations <= 1 || iterations > 1000000 {
163 return Err(SignalProtocolError::InvalidArgument(format!(
164 "Invalid fingerprint iterations {}",
165 iterations
166 )));
167 }
168
169 let fingerprint_version = [0u8, 0u8]; let key_bytes = local_key.serialize();
171
172 let mut sha512 = Sha512::new();
173
174 sha512.update(&fingerprint_version[..]);
177 sha512.update(&key_bytes);
178 sha512.update(local_id);
179 sha512.update(&key_bytes);
180 let mut buf = sha512.finalize();
181
182 for _i in 1..iterations {
183 let mut sha512 = Sha512::new();
184 sha512.update(&buf[..]);
186 sha512.update(&key_bytes);
187 buf = sha512.finalize();
188 }
189
190 Ok(buf.to_vec())
191 }
192
193 pub fn new(
194 version: u32,
195 iterations: u32,
196 local_id: &[u8],
197 local_key: &IdentityKey,
198 remote_id: &[u8],
199 remote_key: &IdentityKey,
200 ) -> Result<Fingerprint> {
201 let local_fingerprint = Fingerprint::get_fingerprint(iterations, local_id, local_key)?;
202 let remote_fingerprint = Fingerprint::get_fingerprint(iterations, remote_id, remote_key)?;
203
204 Ok(Fingerprint {
205 display: DisplayableFingerprint::new(&local_fingerprint, &remote_fingerprint)?,
206 scannable: ScannableFingerprint::new(version, &local_fingerprint, &remote_fingerprint),
207 })
208 }
209
210 pub fn display_string(&self) -> Result<String> {
211 Ok(format!("{}", self.display))
212 }
213}
214
215#[cfg(test)]
216mod test {
217 use hex_literal::hex;
218
219 use super::*;
220
221 const ALICE_IDENTITY: &[u8] =
222 &hex!("0506863bc66d02b40d27b8d49ca7c09e9239236f9d7d25d6fcca5ce13c7064d868");
223 const BOB_IDENTITY: &[u8] =
224 &hex!("05f781b6fb32fed9ba1cf2de978d4d5da28dc34046ae814402b5c0dbd96fda907b");
225
226 const DISPLAYABLE_FINGERPRINT_V1: &str =
227 "300354477692869396892869876765458257569162576843440918079131";
228 const ALICE_SCANNABLE_FINGERPRINT_V1 : &str = "080112220a201e301a0353dce3dbe7684cb8336e85136cdc0ee96219494ada305d62a7bd61df1a220a20d62cbf73a11592015b6b9f1682ac306fea3aaf3885b84d12bca631e9d4fb3a4d";
229 const BOB_SCANNABLE_FINGERPRINT_V1 : &str = "080112220a20d62cbf73a11592015b6b9f1682ac306fea3aaf3885b84d12bca631e9d4fb3a4d1a220a201e301a0353dce3dbe7684cb8336e85136cdc0ee96219494ada305d62a7bd61df";
230
231 const ALICE_SCANNABLE_FINGERPRINT_V2 : &str = "080212220a201e301a0353dce3dbe7684cb8336e85136cdc0ee96219494ada305d62a7bd61df1a220a20d62cbf73a11592015b6b9f1682ac306fea3aaf3885b84d12bca631e9d4fb3a4d";
232 const BOB_SCANNABLE_FINGERPRINT_V2 : & str = "080212220a20d62cbf73a11592015b6b9f1682ac306fea3aaf3885b84d12bca631e9d4fb3a4d1a220a201e301a0353dce3dbe7684cb8336e85136cdc0ee96219494ada305d62a7bd61df";
233
234 const ALICE_STABLE_ID: &str = "+14152222222";
235 const BOB_STABLE_ID: &str = "+14153333333";
236
237 #[test]
238 fn fingerprint_encodings() -> Result<()> {
239 let l = vec![0x12; 32];
240 let r = vec![0xBA; 32];
241
242 let fprint2 = ScannableFingerprint::new(2, &l, &r);
243 let proto2 = fprint2.serialize()?;
244
245 let expected2_encoding =
246 "080212220a20".to_owned() + &"12".repeat(32) + "1a220a20" + &"ba".repeat(32);
247 assert_eq!(hex::encode(proto2), expected2_encoding);
248
249 Ok(())
250 }
251
252 #[test]
253 fn fingerprint_test_v1() -> Result<()> {
254 let a_key = IdentityKey::decode(ALICE_IDENTITY)?;
257 let b_key = IdentityKey::decode(BOB_IDENTITY)?;
258
259 let version = 1;
260 let iterations = 5200;
261
262 let a_fprint = Fingerprint::new(
263 version,
264 iterations,
265 ALICE_STABLE_ID.as_bytes(),
266 &a_key,
267 BOB_STABLE_ID.as_bytes(),
268 &b_key,
269 )?;
270
271 let b_fprint = Fingerprint::new(
272 version,
273 iterations,
274 BOB_STABLE_ID.as_bytes(),
275 &b_key,
276 ALICE_STABLE_ID.as_bytes(),
277 &a_key,
278 )?;
279
280 assert_eq!(
281 hex::encode(a_fprint.scannable.serialize()?),
282 ALICE_SCANNABLE_FINGERPRINT_V1
283 );
284 assert_eq!(
285 hex::encode(b_fprint.scannable.serialize()?),
286 BOB_SCANNABLE_FINGERPRINT_V1
287 );
288
289 assert_eq!(format!("{}", a_fprint.display), DISPLAYABLE_FINGERPRINT_V1);
290 assert_eq!(format!("{}", b_fprint.display), DISPLAYABLE_FINGERPRINT_V1);
291
292 assert_eq!(
293 hex::encode(a_fprint.scannable.serialize()?),
294 ALICE_SCANNABLE_FINGERPRINT_V1
295 );
296 assert_eq!(
297 hex::encode(b_fprint.scannable.serialize()?),
298 BOB_SCANNABLE_FINGERPRINT_V1
299 );
300
301 Ok(())
302 }
303
304 #[test]
305 fn fingerprint_test_v2() -> Result<()> {
306 let a_key = IdentityKey::decode(ALICE_IDENTITY)?;
309 let b_key = IdentityKey::decode(BOB_IDENTITY)?;
310
311 let version = 2;
312 let iterations = 5200;
313
314 let a_fprint = Fingerprint::new(
315 version,
316 iterations,
317 ALICE_STABLE_ID.as_bytes(),
318 &a_key,
319 BOB_STABLE_ID.as_bytes(),
320 &b_key,
321 )?;
322
323 let b_fprint = Fingerprint::new(
324 version,
325 iterations,
326 BOB_STABLE_ID.as_bytes(),
327 &b_key,
328 ALICE_STABLE_ID.as_bytes(),
329 &a_key,
330 )?;
331
332 assert_eq!(
333 hex::encode(a_fprint.scannable.serialize()?),
334 ALICE_SCANNABLE_FINGERPRINT_V2
335 );
336 assert_eq!(
337 hex::encode(b_fprint.scannable.serialize()?),
338 BOB_SCANNABLE_FINGERPRINT_V2
339 );
340
341 assert_eq!(format!("{}", a_fprint.display), DISPLAYABLE_FINGERPRINT_V1);
343 assert_eq!(format!("{}", b_fprint.display), DISPLAYABLE_FINGERPRINT_V1);
344
345 assert_eq!(
346 hex::encode(a_fprint.scannable.serialize()?),
347 ALICE_SCANNABLE_FINGERPRINT_V2
348 );
349 assert_eq!(
350 hex::encode(b_fprint.scannable.serialize()?),
351 BOB_SCANNABLE_FINGERPRINT_V2
352 );
353
354 Ok(())
355 }
356
357 #[test]
358 fn fingerprint_matching_identifiers() -> Result<()> {
359 use rand::rngs::OsRng;
362
363 use crate::IdentityKeyPair;
364
365 let a_key_pair = IdentityKeyPair::generate(&mut OsRng);
366 let b_key_pair = IdentityKeyPair::generate(&mut OsRng);
367
368 let a_key = a_key_pair.identity_key();
369 let b_key = b_key_pair.identity_key();
370
371 let version = 1;
372 let iterations = 1024;
373
374 let a_fprint = Fingerprint::new(
375 version,
376 iterations,
377 ALICE_STABLE_ID.as_bytes(),
378 a_key,
379 BOB_STABLE_ID.as_bytes(),
380 b_key,
381 )?;
382
383 let b_fprint = Fingerprint::new(
384 version,
385 iterations,
386 BOB_STABLE_ID.as_bytes(),
387 b_key,
388 ALICE_STABLE_ID.as_bytes(),
389 a_key,
390 )?;
391
392 assert_eq!(
393 format!("{}", a_fprint.display),
394 format!("{}", b_fprint.display)
395 );
396 assert_eq!(format!("{}", a_fprint.display).len(), 60);
397
398 assert!(a_fprint
399 .scannable
400 .compare(&b_fprint.scannable.serialize()?)?);
401 assert!(b_fprint
402 .scannable
403 .compare(&a_fprint.scannable.serialize()?)?);
404
405 assert!(!a_fprint
407 .scannable
408 .compare(&a_fprint.scannable.serialize()?)?);
409 assert!(!b_fprint
410 .scannable
411 .compare(&b_fprint.scannable.serialize()?)?);
412
413 Ok(())
414 }
415
416 #[test]
417 fn fingerprint_mismatching_fingerprints() -> Result<()> {
418 use rand::rngs::OsRng;
419
420 use crate::IdentityKeyPair;
421
422 let a_key_pair = IdentityKeyPair::generate(&mut OsRng);
423 let b_key_pair = IdentityKeyPair::generate(&mut OsRng);
424 let m_key_pair = IdentityKeyPair::generate(&mut OsRng); let a_key = a_key_pair.identity_key();
427 let b_key = b_key_pair.identity_key();
428 let m_key = m_key_pair.identity_key();
429
430 let version = 1;
431 let iterations = 1024;
432
433 let a_fprint = Fingerprint::new(
434 version,
435 iterations,
436 ALICE_STABLE_ID.as_bytes(),
437 a_key,
438 BOB_STABLE_ID.as_bytes(),
439 m_key,
440 )?;
441
442 let b_fprint = Fingerprint::new(
443 version,
444 iterations,
445 BOB_STABLE_ID.as_bytes(),
446 b_key,
447 ALICE_STABLE_ID.as_bytes(),
448 a_key,
449 )?;
450
451 assert_ne!(
452 format!("{}", a_fprint.display),
453 format!("{}", b_fprint.display)
454 );
455
456 assert!(!a_fprint
457 .scannable
458 .compare(&b_fprint.scannable.serialize()?)?);
459 assert!(!b_fprint
460 .scannable
461 .compare(&a_fprint.scannable.serialize()?)?);
462
463 Ok(())
464 }
465
466 #[test]
467 fn fingerprint_mismatching_identifiers() -> Result<()> {
468 use rand::rngs::OsRng;
469
470 use crate::IdentityKeyPair;
471
472 let a_key_pair = IdentityKeyPair::generate(&mut OsRng);
473 let b_key_pair = IdentityKeyPair::generate(&mut OsRng);
474
475 let a_key = a_key_pair.identity_key();
476 let b_key = b_key_pair.identity_key();
477
478 let version = 1;
479 let iterations = 1024;
480
481 let a_fprint = Fingerprint::new(
482 version,
483 iterations,
484 "+141512222222".as_bytes(),
485 a_key,
486 BOB_STABLE_ID.as_bytes(),
487 b_key,
488 )?;
489
490 let b_fprint = Fingerprint::new(
491 version,
492 iterations,
493 BOB_STABLE_ID.as_bytes(),
494 b_key,
495 ALICE_STABLE_ID.as_bytes(),
496 a_key,
497 )?;
498
499 assert_ne!(
500 format!("{}", a_fprint.display),
501 format!("{}", b_fprint.display)
502 );
503
504 assert!(!a_fprint
505 .scannable
506 .compare(&b_fprint.scannable.serialize()?)?);
507 assert!(!b_fprint
508 .scannable
509 .compare(&a_fprint.scannable.serialize()?)?);
510
511 Ok(())
512 }
513
514 #[test]
515 fn fingerprint_mismatching_versions() -> Result<()> {
516 let a_key = IdentityKey::decode(ALICE_IDENTITY)?;
517 let b_key = IdentityKey::decode(BOB_IDENTITY)?;
518
519 let iterations = 5200;
520
521 let a_fprint_v1 = Fingerprint::new(
522 1,
523 iterations,
524 ALICE_STABLE_ID.as_bytes(),
525 &a_key,
526 BOB_STABLE_ID.as_bytes(),
527 &b_key,
528 )?;
529
530 let a_fprint_v2 = Fingerprint::new(
531 2,
532 iterations,
533 BOB_STABLE_ID.as_bytes(),
534 &b_key,
535 ALICE_STABLE_ID.as_bytes(),
536 &a_key,
537 )?;
538
539 assert_eq!(
541 format!("{}", a_fprint_v1.display),
542 format!("{}", a_fprint_v2.display)
543 );
544
545 assert_ne!(
547 hex::encode(a_fprint_v1.scannable.serialize()?),
548 hex::encode(a_fprint_v2.scannable.serialize()?)
549 );
550
551 Ok(())
552 }
553}