@@ -358,6 +358,7 @@ impl PrivateKey {
358
358
& mut & * * buffer,
359
359
self . public_key . key_data . clone ( ) ,
360
360
self . cipher . block_size ( ) ,
361
+ self . cipher . block_size ( ) - 1 ,
361
362
)
362
363
}
363
364
@@ -548,8 +549,10 @@ impl PrivateKey {
548
549
reader : & mut impl Reader ,
549
550
public_key : public:: KeyData ,
550
551
block_size : usize ,
552
+ max_padding_size : usize ,
551
553
) -> Result < Self > {
552
554
debug_assert ! ( block_size <= MAX_BLOCK_SIZE ) ;
555
+ debug_assert ! ( max_padding_size <= MAX_BLOCK_SIZE ) ;
553
556
554
557
// Ensure input data is padding-aligned
555
558
if reader. remaining_len ( ) . checked_rem ( block_size) != Some ( 0 ) {
@@ -575,7 +578,7 @@ impl PrivateKey {
575
578
576
579
let padding_len = reader. remaining_len ( ) ;
577
580
578
- if padding_len >= block_size {
581
+ if padding_len > max_padding_size {
579
582
return Err ( encoding:: Error :: Length . into ( ) ) ;
580
583
}
581
584
@@ -733,7 +736,24 @@ impl Decode for PrivateKey {
733
736
}
734
737
735
738
reader. read_prefixed ( |reader| {
736
- Self :: decode_privatekey_comment_pair ( reader, public_key, cipher. block_size ( ) )
739
+ // PuTTYgen uses a non-standard block size of 16
740
+ // and _always_ adds a padding even if data length
741
+ // is divisible by 16 - for unencrypted keys
742
+ // in the OpenSSH format.
743
+ // We're only relaxing the exact length check, but will
744
+ // still validate that the contents of the padding area.
745
+ // In all other cases there can be up to (but not including)
746
+ // `block_size` padding bytes as per `PROTOCOL.key`.
747
+ let max_padding_size = match cipher {
748
+ Cipher :: None => 16 ,
749
+ _ => cipher. block_size ( ) - 1 ,
750
+ } ;
751
+ Self :: decode_privatekey_comment_pair (
752
+ reader,
753
+ public_key,
754
+ cipher. block_size ( ) ,
755
+ max_padding_size,
756
+ )
737
757
} )
738
758
}
739
759
}
0 commit comments