deltachat/
key.rs

1//! Cryptographic key module.
2
3use std::collections::BTreeMap;
4use std::fmt;
5use std::io::Cursor;
6
7use anyhow::{Context as _, Result, bail, ensure};
8use base64::Engine as _;
9use deltachat_contact_tools::EmailAddress;
10use pgp::composed::Deserializable;
11pub use pgp::composed::{SignedPublicKey, SignedSecretKey};
12use pgp::ser::Serialize;
13use pgp::types::{KeyDetails, KeyId, Password};
14use rand::thread_rng;
15use tokio::runtime::Handle;
16
17use crate::context::Context;
18use crate::events::EventType;
19use crate::log::{LogExt, info};
20use crate::pgp::KeyPair;
21use crate::tools::{self, time_elapsed};
22
23/// Convenience trait for working with keys.
24///
25/// This trait is implemented for rPGP's [SignedPublicKey] and
26/// [SignedSecretKey] types and makes working with them a little
27/// easier in the deltachat world.
28pub trait DcKey: Serialize + Deserializable + Clone {
29    /// Create a key from some bytes.
30    fn from_slice(bytes: &[u8]) -> Result<Self> {
31        let res = <Self as Deserializable>::from_bytes(Cursor::new(bytes));
32        if let Ok(res) = res {
33            return Ok(res);
34        }
35
36        // Workaround for keys imported using
37        // Delta Chat core < 1.0.0.
38        // Old Delta Chat core had a bug
39        // that resulted in treating CRC24 checksum
40        // as part of the key when reading ASCII Armor.
41        // Some users that started using Delta Chat in 2019
42        // have such corrupted keys with garbage bytes at the end.
43        //
44        // Garbage is at least 3 bytes long
45        // and may be longer due to padding
46        // at the end of the real key data
47        // and importing the key multiple times.
48        //
49        // If removing 10 bytes is not enough,
50        // the key is likely actually corrupted.
51        for garbage_bytes in 3..std::cmp::min(bytes.len(), 10) {
52            let res = <Self as Deserializable>::from_bytes(Cursor::new(
53                bytes
54                    .get(..bytes.len().saturating_sub(garbage_bytes))
55                    .unwrap_or_default(),
56            ));
57            if let Ok(res) = res {
58                return Ok(res);
59            }
60        }
61
62        // Removing garbage bytes did not help, return the error.
63        Ok(res?)
64    }
65
66    /// Create a key from a base64 string.
67    fn from_base64(data: &str) -> Result<Self> {
68        // strip newlines and other whitespace
69        let cleaned: String = data.split_whitespace().collect();
70        let bytes = base64::engine::general_purpose::STANDARD.decode(cleaned.as_bytes())?;
71        Self::from_slice(&bytes)
72    }
73
74    /// Create a key from an ASCII-armored string.
75    fn from_asc(data: &str) -> Result<Self> {
76        let bytes = data.as_bytes();
77        let res = Self::from_armor_single(Cursor::new(bytes));
78        let (key, _headers) = match res {
79            Err(pgp::errors::Error::NoMatchingPacket { .. }) => match Self::is_private() {
80                true => bail!("No private key packet found"),
81                false => bail!("No public key packet found"),
82            },
83            _ => res.context("rPGP error")?,
84        };
85        Ok(key)
86    }
87
88    /// Serialise the key as bytes.
89    fn to_bytes(&self) -> Vec<u8> {
90        // Not using Serialize::to_bytes() to make clear *why* it is
91        // safe to ignore this error.
92        // Because we write to a Vec<u8> the io::Write impls never
93        // fail and we can hide this error.
94        let mut buf = Vec::new();
95        self.to_writer(&mut buf).unwrap();
96        buf
97    }
98
99    /// Serialise the key to a base64 string.
100    fn to_base64(&self) -> String {
101        base64::engine::general_purpose::STANDARD.encode(DcKey::to_bytes(self))
102    }
103
104    /// Serialise the key to ASCII-armored representation.
105    ///
106    /// Each header line must be terminated by `\r\n`.  Only allows setting one
107    /// header as a simplification since that's the only way it's used so far.
108    // Since .to_armored_string() are actual methods on SignedPublicKey and
109    // SignedSecretKey we can not generically implement this.
110    fn to_asc(&self, header: Option<(&str, &str)>) -> String;
111
112    /// The fingerprint for the key.
113    fn dc_fingerprint(&self) -> Fingerprint;
114
115    /// Whether the key is private (or public).
116    fn is_private() -> bool;
117
118    /// Returns the OpenPGP Key ID.
119    fn key_id(&self) -> KeyId;
120}
121
122/// Attempts to load own public key.
123///
124/// Returns `None` if no key is generated yet.
125pub(crate) async fn load_self_public_key_opt(context: &Context) -> Result<Option<SignedPublicKey>> {
126    let Some(public_key_bytes) = context
127        .sql
128        .query_row_optional(
129            "SELECT public_key
130             FROM keypairs
131             WHERE id=(SELECT value FROM config WHERE keyname='key_id')",
132            (),
133            |row| {
134                let bytes: Vec<u8> = row.get(0)?;
135                Ok(bytes)
136            },
137        )
138        .await?
139    else {
140        return Ok(None);
141    };
142    let public_key = SignedPublicKey::from_slice(&public_key_bytes)?;
143    Ok(Some(public_key))
144}
145
146/// Loads own public key.
147///
148/// If no key is generated yet, generates a new one.
149pub(crate) async fn load_self_public_key(context: &Context) -> Result<SignedPublicKey> {
150    match load_self_public_key_opt(context).await? {
151        Some(public_key) => Ok(public_key),
152        None => {
153            let keypair = generate_keypair(context).await?;
154            Ok(keypair.public)
155        }
156    }
157}
158
159/// Returns our own public keyring.
160pub(crate) async fn load_self_public_keyring(context: &Context) -> Result<Vec<SignedPublicKey>> {
161    let keys = context
162        .sql
163        .query_map(
164            r#"SELECT public_key
165               FROM keypairs
166               ORDER BY id=(SELECT value FROM config WHERE keyname='key_id') DESC"#,
167            (),
168            |row| row.get::<_, Vec<u8>>(0),
169            |keys| keys.collect::<Result<Vec<_>, _>>().map_err(Into::into),
170        )
171        .await?
172        .into_iter()
173        .filter_map(|bytes| SignedPublicKey::from_slice(&bytes).log_err(context).ok())
174        .collect();
175    Ok(keys)
176}
177
178/// Returns own public key fingerprint in (not human-readable) hex representation.
179/// This is the fingerprint format that is used in the database.
180///
181/// If no key is generated yet, generates a new one.
182///
183/// For performance reasons, the fingerprint is cached after the first invocation.
184pub(crate) async fn self_fingerprint(context: &Context) -> Result<&str> {
185    if let Some(fp) = context.self_fingerprint.get() {
186        Ok(fp)
187    } else {
188        let fp = load_self_public_key(context).await?.dc_fingerprint().hex();
189        Ok(context.self_fingerprint.get_or_init(|| fp))
190    }
191}
192
193/// Returns own public key fingerprint in (not human-readable) hex representation.
194/// This is the fingerprint format that is used in the database.
195///
196/// Returns `None` if no key is generated yet.
197///
198/// For performance reasons, the fingerprint is cached after the first invocation.
199pub(crate) async fn self_fingerprint_opt(context: &Context) -> Result<Option<&str>> {
200    if let Some(fp) = context.self_fingerprint.get() {
201        Ok(Some(fp))
202    } else if let Some(key) = load_self_public_key_opt(context).await? {
203        let fp = key.dc_fingerprint().hex();
204        Ok(Some(context.self_fingerprint.get_or_init(|| fp)))
205    } else {
206        Ok(None)
207    }
208}
209
210pub(crate) async fn load_self_secret_key(context: &Context) -> Result<SignedSecretKey> {
211    let private_key = context
212        .sql
213        .query_row_optional(
214            "SELECT private_key
215             FROM keypairs
216             WHERE id=(SELECT value FROM config WHERE keyname='key_id')",
217            (),
218            |row| {
219                let bytes: Vec<u8> = row.get(0)?;
220                Ok(bytes)
221            },
222        )
223        .await?;
224    match private_key {
225        Some(bytes) => SignedSecretKey::from_slice(&bytes),
226        None => {
227            let keypair = generate_keypair(context).await?;
228            Ok(keypair.secret)
229        }
230    }
231}
232
233pub(crate) async fn load_self_secret_keyring(context: &Context) -> Result<Vec<SignedSecretKey>> {
234    let keys = context
235        .sql
236        .query_map(
237            r#"SELECT private_key
238               FROM keypairs
239               ORDER BY id=(SELECT value FROM config WHERE keyname='key_id') DESC"#,
240            (),
241            |row| row.get::<_, Vec<u8>>(0),
242            |keys| keys.collect::<Result<Vec<_>, _>>().map_err(Into::into),
243        )
244        .await?
245        .into_iter()
246        .filter_map(|bytes| SignedSecretKey::from_slice(&bytes).log_err(context).ok())
247        .collect();
248    Ok(keys)
249}
250
251impl DcKey for SignedPublicKey {
252    fn to_asc(&self, header: Option<(&str, &str)>) -> String {
253        // Not using .to_armored_string() to make clear *why* it is
254        // safe to ignore this error.
255        // Because we write to a Vec<u8> the io::Write impls never
256        // fail and we can hide this error.
257        let headers =
258            header.map(|(key, value)| BTreeMap::from([(key.to_string(), vec![value.to_string()])]));
259        let mut buf = Vec::new();
260        self.to_armored_writer(&mut buf, headers.as_ref().into())
261            .unwrap_or_default();
262        std::string::String::from_utf8(buf).unwrap_or_default()
263    }
264
265    fn is_private() -> bool {
266        false
267    }
268
269    fn dc_fingerprint(&self) -> Fingerprint {
270        self.fingerprint().into()
271    }
272
273    fn key_id(&self) -> KeyId {
274        KeyDetails::key_id(self)
275    }
276}
277
278impl DcKey for SignedSecretKey {
279    fn to_asc(&self, header: Option<(&str, &str)>) -> String {
280        // Not using .to_armored_string() to make clear *why* it is
281        // safe to do these unwraps.
282        // Because we write to a Vec<u8> the io::Write impls never
283        // fail and we can hide this error.  The string is always ASCII.
284        let headers =
285            header.map(|(key, value)| BTreeMap::from([(key.to_string(), vec![value.to_string()])]));
286        let mut buf = Vec::new();
287        self.to_armored_writer(&mut buf, headers.as_ref().into())
288            .unwrap_or_default();
289        std::string::String::from_utf8(buf).unwrap_or_default()
290    }
291
292    fn is_private() -> bool {
293        true
294    }
295
296    fn dc_fingerprint(&self) -> Fingerprint {
297        self.fingerprint().into()
298    }
299
300    fn key_id(&self) -> KeyId {
301        KeyDetails::key_id(&**self)
302    }
303}
304
305/// Deltachat extension trait for secret keys.
306///
307/// Provides some convenience wrappers only applicable to [SignedSecretKey].
308pub(crate) trait DcSecretKey {
309    /// Create a public key from a private one.
310    fn split_public_key(&self) -> Result<SignedPublicKey>;
311}
312
313impl DcSecretKey for SignedSecretKey {
314    fn split_public_key(&self) -> Result<SignedPublicKey> {
315        self.verify()?;
316        let unsigned_pubkey = self.public_key();
317        let mut rng = thread_rng();
318        let signed_pubkey = unsigned_pubkey.sign(
319            &mut rng,
320            &self.primary_key,
321            self.primary_key.public_key(),
322            &Password::empty(),
323        )?;
324        Ok(signed_pubkey)
325    }
326}
327
328async fn generate_keypair(context: &Context) -> Result<KeyPair> {
329    let addr = context.get_primary_self_addr().await?;
330    let addr = EmailAddress::new(&addr)?;
331    let _guard = context.generating_key_mutex.lock().await;
332
333    // Check if the key appeared while we were waiting on the lock.
334    match load_keypair(context).await? {
335        Some(key_pair) => Ok(key_pair),
336        None => {
337            let start = tools::Time::now();
338            info!(context, "Generating keypair.");
339            let keypair = Handle::current()
340                .spawn_blocking(move || crate::pgp::create_keypair(addr))
341                .await??;
342
343            store_self_keypair(context, &keypair).await?;
344            info!(
345                context,
346                "Keypair generated in {:.3}s.",
347                time_elapsed(&start).as_secs(),
348            );
349            Ok(keypair)
350        }
351    }
352}
353
354pub(crate) async fn load_keypair(context: &Context) -> Result<Option<KeyPair>> {
355    let res = context
356        .sql
357        .query_row_optional(
358            "SELECT public_key, private_key
359             FROM keypairs
360             WHERE id=(SELECT value FROM config WHERE keyname='key_id')",
361            (),
362            |row| {
363                let pub_bytes: Vec<u8> = row.get(0)?;
364                let sec_bytes: Vec<u8> = row.get(1)?;
365                Ok((pub_bytes, sec_bytes))
366            },
367        )
368        .await?;
369
370    Ok(if let Some((pub_bytes, sec_bytes)) = res {
371        Some(KeyPair {
372            public: SignedPublicKey::from_slice(&pub_bytes)?,
373            secret: SignedSecretKey::from_slice(&sec_bytes)?,
374        })
375    } else {
376        None
377    })
378}
379
380/// Store the keypair as an owned keypair for addr in the database.
381///
382/// This will save the keypair as keys for the given address.  The
383/// "self" here refers to the fact that this DC instance owns the
384/// keypair.  Usually `addr` will be [Config::ConfiguredAddr].
385///
386/// If either the public or private keys are already present in the
387/// database, this entry will be removed first regardless of the
388/// address associated with it.  Practically this means saving the
389/// same key again overwrites it.
390///
391/// [Config::ConfiguredAddr]: crate::config::Config::ConfiguredAddr
392pub(crate) async fn store_self_keypair(context: &Context, keypair: &KeyPair) -> Result<()> {
393    let mut config_cache_lock = context.sql.config_cache.write().await;
394    let new_key_id = context
395        .sql
396        .transaction(|transaction| {
397            let public_key = DcKey::to_bytes(&keypair.public);
398            let secret_key = DcKey::to_bytes(&keypair.secret);
399
400            // private_key and public_key columns
401            // are UNIQUE since migration 107,
402            // so this fails if we already have this key.
403            transaction
404                .execute(
405                    "INSERT INTO keypairs (public_key, private_key)
406                     VALUES (?,?)",
407                    (&public_key, &secret_key),
408                )
409                .context("Failed to insert keypair")?;
410
411            let new_key_id = transaction.last_insert_rowid();
412
413            // This will fail if we already have `key_id`.
414            //
415            // Setting default key is only possible if we don't
416            // have a key already.
417            transaction.execute(
418                "INSERT INTO config (keyname, value) VALUES ('key_id', ?)",
419                (new_key_id,),
420            )?;
421            Ok(new_key_id)
422        })
423        .await?;
424    context.emit_event(EventType::AccountsItemChanged);
425    config_cache_lock.insert("key_id".to_string(), Some(new_key_id.to_string()));
426    Ok(())
427}
428
429/// Saves a keypair as the default keys.
430///
431/// This API is used for testing purposes
432/// to avoid generating the key in tests.
433/// Use import/export APIs instead.
434pub async fn preconfigure_keypair(context: &Context, secret_data: &str) -> Result<()> {
435    let secret = SignedSecretKey::from_asc(secret_data)?;
436    let public = secret.split_public_key()?;
437    let keypair = KeyPair { public, secret };
438    store_self_keypair(context, &keypair).await?;
439    Ok(())
440}
441
442/// A key fingerprint
443#[derive(Clone, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)]
444pub struct Fingerprint(Vec<u8>);
445
446impl Fingerprint {
447    /// Creates new 160-bit (20 bytes) fingerprint.
448    pub fn new(v: Vec<u8>) -> Fingerprint {
449        debug_assert_eq!(v.len(), 20);
450        Fingerprint(v)
451    }
452
453    /// Make a hex string from the fingerprint.
454    ///
455    /// Use [std::fmt::Display] or [ToString::to_string] to get a
456    /// human-readable formatted string.
457    pub fn hex(&self) -> String {
458        hex::encode_upper(&self.0)
459    }
460}
461
462impl From<pgp::types::Fingerprint> for Fingerprint {
463    fn from(fingerprint: pgp::types::Fingerprint) -> Fingerprint {
464        Self::new(fingerprint.as_bytes().into())
465    }
466}
467
468impl fmt::Debug for Fingerprint {
469    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
470        f.debug_struct("Fingerprint")
471            .field("hex", &self.hex())
472            .finish()
473    }
474}
475
476/// Make a human-readable fingerprint.
477impl fmt::Display for Fingerprint {
478    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
479        // Split key into chunks of 4 with space and newline at 20 chars
480        for (i, c) in self.hex().chars().enumerate() {
481            if i > 0 && i % 20 == 0 {
482                writeln!(f)?;
483            } else if i > 0 && i % 4 == 0 {
484                write!(f, " ")?;
485            }
486            write!(f, "{c}")?;
487        }
488        Ok(())
489    }
490}
491
492/// Parse a human-readable or otherwise formatted fingerprint.
493impl std::str::FromStr for Fingerprint {
494    type Err = anyhow::Error;
495
496    fn from_str(input: &str) -> Result<Self> {
497        let hex_repr: String = input
498            .to_uppercase()
499            .chars()
500            .filter(|&c| c.is_ascii_hexdigit())
501            .collect();
502        let v: Vec<u8> = hex::decode(&hex_repr)?;
503        ensure!(v.len() == 20, "wrong fingerprint length: {hex_repr}");
504        let fp = Fingerprint::new(v);
505        Ok(fp)
506    }
507}
508
509#[cfg(test)]
510mod tests {
511    use std::sync::{Arc, LazyLock};
512
513    use super::*;
514    use crate::config::Config;
515    use crate::test_utils::{TestContext, alice_keypair};
516
517    static KEYPAIR: LazyLock<KeyPair> = LazyLock::new(alice_keypair);
518
519    #[test]
520    fn test_from_armored_string() {
521        let private_key = SignedSecretKey::from_asc(
522            "-----BEGIN PGP PRIVATE KEY BLOCK-----
523
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
5767yPJeQ==
577=KZk/
578-----END PGP PRIVATE KEY BLOCK-----",
579        )
580        .expect("failed to decode");
581        let binary = DcKey::to_bytes(&private_key);
582        SignedSecretKey::from_slice(&binary).expect("invalid private key");
583    }
584
585    #[test]
586    fn test_asc_roundtrip() {
587        let key = KEYPAIR.public.clone();
588        let asc = key.to_asc(Some(("spam", "ham")));
589        let key2 = SignedPublicKey::from_asc(&asc).unwrap();
590        assert_eq!(key, key2);
591
592        let key = KEYPAIR.secret.clone();
593        let asc = key.to_asc(Some(("spam", "ham")));
594        let key2 = SignedSecretKey::from_asc(&asc).unwrap();
595        assert_eq!(key, key2);
596    }
597
598    #[test]
599    fn test_from_slice_roundtrip() {
600        let public_key = KEYPAIR.public.clone();
601        let private_key = KEYPAIR.secret.clone();
602
603        let binary = DcKey::to_bytes(&public_key);
604        let public_key2 = SignedPublicKey::from_slice(&binary).expect("invalid public key");
605        assert_eq!(public_key, public_key2);
606
607        let binary = DcKey::to_bytes(&private_key);
608        let private_key2 = SignedSecretKey::from_slice(&binary).expect("invalid private key");
609        assert_eq!(private_key, private_key2);
610    }
611
612    #[test]
613    fn test_from_slice_bad_data() {
614        let mut bad_data: [u8; 4096] = [0; 4096];
615        for (i, v) in bad_data.iter_mut().enumerate() {
616            *v = (i & 0xff) as u8;
617        }
618        for j in 0..(4096 / 40) {
619            let slice = &bad_data.get(j..j + 4096 / 2 + j).unwrap();
620            assert!(SignedPublicKey::from_slice(slice).is_err());
621            assert!(SignedSecretKey::from_slice(slice).is_err());
622        }
623    }
624
625    /// Tests workaround for Delta Chat core < 1.0.0
626    /// which parsed CRC24 at the end of ASCII Armor
627    /// as the part of the key.
628    /// Depending on the alignment and the number of
629    /// `=` characters at the end of the key,
630    /// this resulted in various number of garbage
631    /// octets at the end of the key, starting from 3 octets,
632    /// but possibly 4 or 5 and maybe more octets
633    /// if the key is imported or transferred
634    /// using Autocrypt Setup Message multiple times.
635    #[test]
636    fn test_ignore_trailing_garbage() {
637        // Test several variants of garbage.
638        for garbage in [
639            b"\x02\xfc\xaa\x38\x4b\x5c".as_slice(),
640            b"\x02\xfc\xaa".as_slice(),
641            b"\x01\x02\x03\x04\x05".as_slice(),
642        ] {
643            let private_key = KEYPAIR.secret.clone();
644
645            let mut binary = DcKey::to_bytes(&private_key);
646            binary.extend(garbage);
647
648            let private_key2 =
649                SignedSecretKey::from_slice(&binary).expect("Failed to ignore garbage");
650
651            assert_eq!(private_key.dc_fingerprint(), private_key2.dc_fingerprint());
652        }
653    }
654
655    #[test]
656    fn test_base64_roundtrip() {
657        let key = KEYPAIR.public.clone();
658        let base64 = key.to_base64();
659        let key2 = SignedPublicKey::from_base64(&base64).unwrap();
660        assert_eq!(key, key2);
661    }
662
663    #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
664    async fn test_load_self_generate_public() {
665        let t = TestContext::new().await;
666        t.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
667            .await
668            .unwrap();
669        let key = load_self_public_key(&t).await;
670        assert!(key.is_ok());
671    }
672
673    #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
674    async fn test_load_self_generate_secret() {
675        let t = TestContext::new().await;
676        t.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
677            .await
678            .unwrap();
679        let key = load_self_secret_key(&t).await;
680        assert!(key.is_ok());
681    }
682
683    #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
684    async fn test_load_self_generate_concurrent() {
685        use std::thread;
686
687        let t = TestContext::new().await;
688        t.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
689            .await
690            .unwrap();
691        let thr0 = {
692            let ctx = t.clone();
693            thread::spawn(move || {
694                tokio::runtime::Runtime::new()
695                    .unwrap()
696                    .block_on(load_self_public_key(&ctx))
697            })
698        };
699        let thr1 = {
700            let ctx = t.clone();
701            thread::spawn(move || {
702                tokio::runtime::Runtime::new()
703                    .unwrap()
704                    .block_on(load_self_public_key(&ctx))
705            })
706        };
707        let res0 = thr0.join().unwrap();
708        let res1 = thr1.join().unwrap();
709        assert_eq!(res0.unwrap(), res1.unwrap());
710    }
711
712    #[test]
713    fn test_split_key() {
714        let pubkey = KEYPAIR.secret.split_public_key().unwrap();
715        assert_eq!(pubkey.primary_key, KEYPAIR.public.primary_key);
716    }
717
718    /// Tests that setting a default key second time is not allowed.
719    #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
720    async fn test_save_self_key_twice() {
721        // Saving the same key twice should result in only one row in
722        // the keypairs table.
723        let t = TestContext::new().await;
724        let ctx = Arc::new(t);
725
726        let nrows = || async {
727            ctx.sql
728                .count("SELECT COUNT(*) FROM keypairs;", ())
729                .await
730                .unwrap()
731        };
732        assert_eq!(nrows().await, 0);
733        store_self_keypair(&ctx, &KEYPAIR).await.unwrap();
734        assert_eq!(nrows().await, 1);
735
736        // Saving a second key fails.
737        let res = store_self_keypair(&ctx, &KEYPAIR).await;
738        assert!(res.is_err());
739
740        assert_eq!(nrows().await, 1);
741    }
742
743    #[test]
744    fn test_fingerprint_from_str() {
745        let res = Fingerprint::new(vec![
746            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
747        ]);
748
749        let fp: Fingerprint = "0102030405060708090A0B0c0d0e0F1011121314".parse().unwrap();
750        assert_eq!(fp, res);
751
752        let fp: Fingerprint = "zzzz 0102 0304 0506\n0708090a0b0c0D0E0F1011121314 yyy"
753            .parse()
754            .unwrap();
755        assert_eq!(fp, res);
756
757        assert!("1".parse::<Fingerprint>().is_err());
758    }
759
760    #[test]
761    fn test_fingerprint_hex() {
762        let fp = Fingerprint::new(vec![
763            1, 2, 4, 8, 16, 32, 64, 128, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
764        ]);
765        assert_eq!(fp.hex(), "0102040810204080FF0A0B0C0D0E0F1011121314");
766    }
767
768    #[test]
769    fn test_fingerprint_to_string() {
770        let fp = Fingerprint::new(vec![
771            1, 2, 4, 8, 16, 32, 64, 128, 255, 1, 2, 4, 8, 16, 32, 64, 128, 255, 19, 20,
772        ]);
773        assert_eq!(
774            fp.to_string(),
775            "0102 0408 1020 4080 FF01\n0204 0810 2040 80FF 1314"
776        );
777    }
778}