@@ -30,7 +30,39 @@ use crate::tools::{self, time_elapsed};
30
30
pub ( crate ) trait DcKey : Serialize + Deserializable + PublicKeyTrait + Clone {
31
31
/// Create a key from some bytes.
32
32
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?)
34
66
}
35
67
36
68
/// Create a key from a base64 string.
@@ -565,6 +597,36 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
565
597
}
566
598
}
567
599
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
+
568
630
#[ test]
569
631
fn test_base64_roundtrip ( ) {
570
632
let key = KEYPAIR . public . clone ( ) ;
0 commit comments