Skip to content

Commit 7d1e3c4

Browse files
committed
fix: ignore garbage at the end of the keys
1 parent 2f976d8 commit 7d1e3c4

File tree

1 file changed

+63
-1
lines changed

1 file changed

+63
-1
lines changed

src/key.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,39 @@ use crate::tools::{self, time_elapsed};
3030
pub(crate) trait DcKey: Serialize + Deserializable + PublicKeyTrait + Clone {
3131
/// Create a key from some bytes.
3232
fn from_slice(bytes: &[u8]) -> Result<Self> {
33-
Ok(<Self as Deserializable>::from_bytes(Cursor::new(bytes))?)
33+
let res = <Self as Deserializable>::from_bytes(Cursor::new(bytes));
34+
if let Ok(res) = res {
35+
return Ok(res);
36+
}
37+
38+
// Workaround for keys imported using
39+
// Delta Chat core < 1.0.0.
40+
// Old Delta Chat core had a bug
41+
// that resulted in treating CRC24 checksum
42+
// as part of the key when reading ASCII Armor.
43+
// Some users that started using Delta Chat in 2019
44+
// have such corrupted keys with garbage bytes at the end.
45+
//
46+
// Garbage is at least 3 bytes long
47+
// and may be longer due to padding
48+
// at the end of the real key data
49+
// and importing the key multiple times.
50+
//
51+
// If removing 10 bytes is not enough,
52+
// the key is likely actually corrupted.
53+
for garbage_bytes in 3..std::cmp::min(bytes.len(), 10) {
54+
let res = <Self as Deserializable>::from_bytes(Cursor::new(
55+
bytes
56+
.get(..bytes.len().saturating_sub(garbage_bytes))
57+
.unwrap_or_default(),
58+
));
59+
if let Ok(res) = res {
60+
return Ok(res);
61+
}
62+
}
63+
64+
// Removing garbage bytes did not help, return the error.
65+
Ok(res?)
3466
}
3567

3668
/// Create a key from a base64 string.
@@ -565,6 +597,36 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
565597
}
566598
}
567599

600+
/// Tests workaround for Delta Chat core < 1.0.0
601+
/// which parsed CRC24 at the end of ASCII Armor
602+
/// as the part of the key.
603+
/// Depending on the alignment and the number of
604+
/// `=` characters at the end of the key,
605+
/// this resulted in various number of garbage
606+
/// octets at the end of the key, starting from 3 octets,
607+
/// but possibly 4 or 5 and maybe more octets
608+
/// if the key is imported or transferred
609+
/// using Autocrypt Setup Message multiple times.
610+
#[test]
611+
fn test_ignore_trailing_garbage() {
612+
// Test several variants of garbage.
613+
for garbage in [
614+
b"\x02\xfc\xaa\x38\x4b\x5c".as_slice(),
615+
b"\x02\xfc\xaa".as_slice(),
616+
b"\x01\x02\x03\x04\x05".as_slice(),
617+
] {
618+
let private_key = KEYPAIR.secret.clone();
619+
620+
let mut binary = DcKey::to_bytes(&private_key);
621+
binary.extend(garbage);
622+
623+
let private_key2 =
624+
SignedSecretKey::from_slice(&binary).expect("Failed to ignore garbage");
625+
626+
assert_eq!(private_key.dc_fingerprint(), private_key2.dc_fingerprint());
627+
}
628+
}
629+
568630
#[test]
569631
fn test_base64_roundtrip() {
570632
let key = KEYPAIR.public.clone();

0 commit comments

Comments
 (0)