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