libsignal_rust/
numeric_fingerprint.rs

1use crate::crypto::hash;
2
3const VERSION: u16 = 0;
4
5fn iterate_hash(data: &[u8], key: &[u8], count: usize) -> Vec<u8> {
6    let mut combined = Vec::new();
7    combined.extend_from_slice(data);
8    combined.extend_from_slice(key);
9    
10    let mut result = hash(&combined);
11    
12    for _ in 1..count {
13        combined.clear();
14        combined.extend_from_slice(&result);
15        combined.extend_from_slice(key);
16        result = hash(&combined);
17    }
18    
19    result
20}
21
22fn short_to_bytes(number: u16) -> [u8; 2] {
23    number.to_le_bytes()
24}
25
26fn get_encoded_chunk(hash: &[u8], offset: usize) -> String {
27    let chunk = (hash[offset] as u64) * (1u64 << 32) +
28                (hash[offset + 1] as u64) * (1u64 << 24) +
29                (hash[offset + 2] as u64) * (1u64 << 16) +
30                (hash[offset + 3] as u64) * (1u64 << 8) +
31                (hash[offset + 4] as u64);
32    
33    let chunk = chunk % 100000;
34    format!("{:05}", chunk)
35}
36
37fn get_display_string_for(identifier: &str, key: &[u8], iterations: usize) -> String {
38    let mut bytes = Vec::new();
39    bytes.extend_from_slice(&short_to_bytes(VERSION));
40    bytes.extend_from_slice(key);
41    bytes.extend_from_slice(identifier.as_bytes());
42    
43    let output = iterate_hash(&bytes, key, iterations);
44    
45    get_encoded_chunk(&output, 0) +
46        &get_encoded_chunk(&output, 5) +
47        &get_encoded_chunk(&output, 10) +
48        &get_encoded_chunk(&output, 15) +
49        &get_encoded_chunk(&output, 20) +
50        &get_encoded_chunk(&output, 25)
51}
52
53pub struct FingerprintGenerator {
54    iterations: usize,
55}
56
57impl FingerprintGenerator {
58    pub fn new(iterations: usize) -> Self {
59        Self { iterations }
60    }
61
62    pub fn create_for(&self, 
63                      local_identifier: &str, 
64                      local_identity_key: &[u8],
65                      remote_identifier: &str, 
66                      remote_identity_key: &[u8]) -> String {
67        let local_fingerprint = get_display_string_for(local_identifier, local_identity_key, self.iterations);
68        let remote_fingerprint = get_display_string_for(remote_identifier, remote_identity_key, self.iterations);
69        
70        format!("{}{}", local_fingerprint, remote_fingerprint)
71    }
72}