diff --git a/ssh/cipher.go b/ssh/cipher.go index 2732963..34d3917 100644 --- a/ssh/cipher.go +++ b/ssh/cipher.go @@ -7,6 +7,7 @@ package ssh import ( "crypto/aes" "crypto/cipher" + "crypto/des" "crypto/rc4" "crypto/subtle" "encoding/binary" @@ -121,6 +122,9 @@ var cipherModes = map[string]*streamCipherMode{ // You should expect that an active attacker can recover plaintext if // you do. aes128cbcID: {16, aes.BlockSize, 0, nil}, + + // 3des-cbc is insecure and is disabled by default. + tripledescbcID: {24, des.BlockSize, 0, nil}, } // prefixLen is the length of the packet prefix that contains the packet length @@ -368,12 +372,7 @@ type cbcCipher struct { oracleCamouflage uint32 } -func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { - c, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - +func newCBCCipher(c cipher.Block, iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { cbc := &cbcCipher{ mac: macModes[algs.MAC].new(macKey), decrypter: cipher.NewCBCDecrypter(c, iv), @@ -387,6 +386,34 @@ func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCi return cbc, nil } +func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + cbc, err := newCBCCipher(c, iv, key, macKey, algs) + if err != nil { + return nil, err + } + + return cbc, nil +} + +func newTripleDESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { + c, err := des.NewTripleDESCipher(key) + if err != nil { + return nil, err + } + + cbc, err := newCBCCipher(c, iv, key, macKey, algs) + if err != nil { + return nil, err + } + + return cbc, nil +} + func maxUInt32(a, b int) uint32 { if a > b { return uint32(a) diff --git a/ssh/test/session_test.go b/ssh/test/session_test.go index d27ade7..faf2d2b 100644 --- a/ssh/test/session_test.go +++ b/ssh/test/session_test.go @@ -280,9 +280,9 @@ func TestCiphers(t *testing.T) { var config ssh.Config config.SetDefaults() cipherOrder := config.Ciphers - // This cipher will not be tested when commented out in cipher.go it will + // These ciphers will not be tested when commented out in cipher.go it will // fallback to the next available as per line 292. - cipherOrder = append(cipherOrder, "aes128-cbc") + cipherOrder = append(cipherOrder, "aes128-cbc", "3des-cbc") for _, ciph := range cipherOrder { server := newServer(t) diff --git a/ssh/transport.go b/ssh/transport.go index bf7dd61..62fba62 100644 --- a/ssh/transport.go +++ b/ssh/transport.go @@ -11,8 +11,9 @@ import ( ) const ( - gcmCipherID = "aes128-gcm@openssh.com" - aes128cbcID = "aes128-cbc" + gcmCipherID = "aes128-gcm@openssh.com" + aes128cbcID = "aes128-cbc" + tripledescbcID = "3des-cbc" ) // packetConn represents a transport that implements packet based @@ -219,6 +220,10 @@ func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (pac return newAESCBCCipher(iv, key, macKey, algs) } + if algs.Cipher == tripledescbcID { + return newTripleDESCBCCipher(iv, key, macKey, algs) + } + c := &streamPacketCipher{ mac: macModes[algs.MAC].new(macKey), }