11// Format documentation:
22// https://tartarus.org/~simon/putty-snapshots/htmldoc/AppendixC.html
33
4+ use alloc:: collections:: BTreeMap ;
5+ use alloc:: string:: { String , ToString } ;
6+ use alloc:: vec:: Vec ;
47use argon2:: Argon2 ;
58use core:: fmt:: { Debug , Display } ;
69use core:: num:: ParseIntError ;
@@ -9,9 +12,6 @@ use hex::FromHex;
912use hmac:: digest:: KeyInit ;
1013use hmac:: { Hmac , Mac } ;
1114use sha2:: Sha256 ;
12- use std:: collections:: HashMap ;
13- use std:: string:: { String , ToString } ;
14- use std:: vec:: Vec ;
1515
1616use crate :: private:: { EcdsaKeypair , KeypairData } ;
1717use crate :: public:: KeyData ;
@@ -75,25 +75,32 @@ pub enum Cipher {
7575 Aes256Cbc ,
7676}
7777
78+ type Aes256CbcKey = [ u8 ; 32 ] ;
79+ type Aes256CbcIv = [ u8 ; 16 ] ;
80+ type HmacKey = [ u8 ; 32 ] ;
81+
7882impl Cipher {
7983 fn derive_aes_params (
8084 kdf : & Kdf ,
8185 password : & str ,
82- ) -> Result < ( [ u8 ; 32 ] , [ u8 ; 16 ] , [ u8 ; 32 ] ) , Error > {
86+ ) -> Result < ( Aes256CbcKey , Aes256CbcIv , HmacKey ) , Error > {
8387 let mut key_iv_mac = vec ! [ 0 ; 80 ] ;
8488 kdf. derive ( password. as_bytes ( ) , & mut key_iv_mac)
8589 . map_err ( PpkParseError :: Argon2 ) ?;
8690 let key = & key_iv_mac[ ..32 ] ;
8791 let iv = & key_iv_mac[ 32 ..48 ] ;
8892 let mac_key = & key_iv_mac[ 48 ..80 ] ;
8993 Ok ( (
90- key. try_into ( ) . unwrap ( ) , // const size
91- iv. try_into ( ) . unwrap ( ) , // const size
92- mac_key. try_into ( ) . unwrap ( ) , // const size
94+ #[ allow( clippy:: unwrap_used) ] // const size
95+ key. try_into ( ) . unwrap ( ) ,
96+ #[ allow ( clippy:: unwrap_used) ] // const size
97+ iv. try_into ( ) . unwrap ( ) ,
98+ #[ allow ( clippy:: unwrap_used) ] // const size
99+ mac_key. try_into ( ) . unwrap ( ) ,
93100 ) )
94101 }
95102
96- pub fn derive_mac_key ( & self , kdf : & Kdf , password : & str ) -> Result < [ u8 ; 32 ] , Error > {
103+ pub fn derive_mac_key ( & self , kdf : & Kdf , password : & str ) -> Result < HmacKey , Error > {
97104 Ok ( Cipher :: derive_aes_params ( kdf, password) ?. 2 )
98105 }
99106
@@ -114,7 +121,7 @@ pub struct PpkEncryption {
114121 pub passphrase : String ,
115122}
116123
117- #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
124+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
118125pub enum PpkKey {
119126 Encryption ,
120127 Comment ,
@@ -149,7 +156,7 @@ pub struct PpkWrapper {
149156 pub algorithm : Algorithm ,
150157 pub public_key : Option < Vec < u8 > > ,
151158 pub private_key : Option < Vec < u8 > > ,
152- pub values : HashMap < PpkKey , String > ,
159+ pub values : BTreeMap < PpkKey , String > ,
153160}
154161
155162impl Debug for PpkWrapper {
@@ -249,7 +256,7 @@ impl TryFrom<&str> for PpkWrapper {
249256 let mut public_key = None ;
250257 let mut private_key = None ;
251258
252- let mut values = HashMap :: new ( ) ;
259+ let mut values = BTreeMap :: new ( ) ;
253260 while let Some ( line) = lines. next ( ) {
254261 let ( key, value) = line
255262 . split_once ( ": " )
@@ -353,12 +360,13 @@ impl PpkContainer {
353360 } ;
354361
355362 let hmac_key = match & encryption {
356- None => [ 0 ; 32 ] . into ( ) ,
363+ None => HmacKey :: default ( ) ,
357364 Some ( enc) => enc. cipher . derive_mac_key ( & enc. kdf , & enc. passphrase ) ?,
358365 } ;
359366
360367 let expected_mac = {
361- let mut hmac = Hmac :: < Sha256 > :: new_from_slice ( & hmac_key) . unwrap ( ) ; //fixed length
368+ #[ allow( clippy:: unwrap_used) ] // const key length
369+ let mut hmac = Hmac :: < Sha256 > :: new_from_slice ( & hmac_key) . unwrap ( ) ;
362370 hmac. update ( & mac_buffer) ;
363371 hmac. finalize ( )
364372 } ;
@@ -417,17 +425,22 @@ fn decode_private_key_as(
417425 let mut buf = Zeroizing :: new ( [ 0u8 ; Ed25519PrivateKey :: BYTE_SIZE ] ) ;
418426 let e = Mpint :: decode ( reader) ?;
419427 let e_bytes = e. as_bytes ( ) ;
420- assert ! ( e_bytes. len( ) <= buf. len( ) ) ;
428+
429+ if e_bytes. len ( ) > buf. len ( ) {
430+ return Err ( Error :: Crypto ) ;
431+ }
432+
433+ #[ allow( clippy:: arithmetic_side_effects) ] // length checked
421434 buf[ Ed25519PrivateKey :: BYTE_SIZE - e_bytes. len ( ) ..] . copy_from_slice ( e_bytes) ;
422435
423436 let private = Ed25519PrivateKey :: from_bytes ( & buf) ;
424437 Ok ( KeypairData :: Ed25519 ( Ed25519Keypair {
425- public : pk . clone ( ) ,
438+ public : * pk ,
426439 private,
427440 } ) )
428441 }
429442
430- #[ cfg( feature = "ecdsa" ) ]
443+ #[ cfg( any ( feature = "p256" , feature = "p384" , feature = "p521" ) ) ]
431444 ( Algorithm :: Ecdsa { curve } , KeyData :: Ecdsa ( public) ) => {
432445 // PPK encodes EcDSA private exponent as an mpint
433446 use crate :: public:: EcdsaPublicKey ;
@@ -440,28 +453,28 @@ fn decode_private_key_as(
440453 return Err ( Error :: Crypto ) ;
441454 }
442455
443- type EC = EcdsaCurve ;
444- type EPK = EcdsaPublicKey ;
445- type EKP = EcdsaKeypair ;
456+ type Ec = EcdsaCurve ;
457+ type Epk = EcdsaPublicKey ;
458+ type Ekp = EcdsaKeypair ;
446459
447- let keypair: EKP = match ( curve, public) {
460+ let keypair: Ekp = match ( curve, public) {
448461 #[ cfg( feature = "p256" ) ]
449- ( EC :: NistP256 , EPK :: NistP256 ( public) ) => EKP :: NistP256 {
450- public : public. clone ( ) ,
462+ ( Ec :: NistP256 , Epk :: NistP256 ( public) ) => Ekp :: NistP256 {
463+ public : * public,
451464 private : p256:: SecretKey :: from_slice ( e_bytes)
452465 . map_err ( |_| Error :: Crypto ) ?
453466 . into ( ) ,
454467 } ,
455468 #[ cfg( feature = "p384" ) ]
456- ( EC :: NistP384 , EPK :: NistP384 ( public) ) => EKP :: NistP384 {
457- public : public. clone ( ) ,
469+ ( Ec :: NistP384 , Epk :: NistP384 ( public) ) => Ekp :: NistP384 {
470+ public : * public,
458471 private : p384:: SecretKey :: from_slice ( e_bytes)
459472 . map_err ( |_| Error :: Crypto ) ?
460473 . into ( ) ,
461474 } ,
462475 #[ cfg( feature = "p521" ) ]
463- ( EC :: NistP521 , EPK :: NistP521 ( public) ) => EKP :: NistP521 {
464- public : public. clone ( ) ,
476+ ( Ec :: NistP521 , Epk :: NistP521 ( public) ) => Ekp :: NistP521 {
477+ public : * public,
465478 private : p521:: SecretKey :: from_slice ( e_bytes)
466479 . map_err ( |_| Error :: Crypto ) ?
467480 . into ( ) ,
0 commit comments