|
@@ -135,6 +135,7 @@ const prefixLen = 5
|
|
|
type streamPacketCipher struct {
|
|
type streamPacketCipher struct {
|
|
|
mac hash.Hash
|
|
mac hash.Hash
|
|
|
cipher cipher.Stream
|
|
cipher cipher.Stream
|
|
|
|
|
+ etm bool
|
|
|
|
|
|
|
|
// The following members are to avoid per-packet allocations.
|
|
// The following members are to avoid per-packet allocations.
|
|
|
prefix [prefixLen]byte
|
|
prefix [prefixLen]byte
|
|
@@ -150,7 +151,14 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
|
|
|
return nil, err
|
|
return nil, err
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
|
|
|
|
|
|
+ var encryptedPaddingLength [1]byte
|
|
|
|
|
+ if s.mac != nil && s.etm {
|
|
|
|
|
+ copy(encryptedPaddingLength[:], s.prefix[4:5])
|
|
|
|
|
+ s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
|
|
|
|
|
+ } else {
|
|
|
|
|
+ s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
length := binary.BigEndian.Uint32(s.prefix[0:4])
|
|
length := binary.BigEndian.Uint32(s.prefix[0:4])
|
|
|
paddingLength := uint32(s.prefix[4])
|
|
paddingLength := uint32(s.prefix[4])
|
|
|
|
|
|
|
@@ -159,7 +167,12 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
|
|
|
s.mac.Reset()
|
|
s.mac.Reset()
|
|
|
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
|
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
|
|
s.mac.Write(s.seqNumBytes[:])
|
|
s.mac.Write(s.seqNumBytes[:])
|
|
|
- s.mac.Write(s.prefix[:])
|
|
|
|
|
|
|
+ if s.etm {
|
|
|
|
|
+ s.mac.Write(s.prefix[:4])
|
|
|
|
|
+ s.mac.Write(encryptedPaddingLength[:])
|
|
|
|
|
+ } else {
|
|
|
|
|
+ s.mac.Write(s.prefix[:])
|
|
|
|
|
+ }
|
|
|
macSize = uint32(s.mac.Size())
|
|
macSize = uint32(s.mac.Size())
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -184,10 +197,17 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
|
|
|
}
|
|
}
|
|
|
mac := s.packetData[length-1:]
|
|
mac := s.packetData[length-1:]
|
|
|
data := s.packetData[:length-1]
|
|
data := s.packetData[:length-1]
|
|
|
|
|
+
|
|
|
|
|
+ if s.mac != nil && s.etm {
|
|
|
|
|
+ s.mac.Write(data)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
s.cipher.XORKeyStream(data, data)
|
|
s.cipher.XORKeyStream(data, data)
|
|
|
|
|
|
|
|
if s.mac != nil {
|
|
if s.mac != nil {
|
|
|
- s.mac.Write(data)
|
|
|
|
|
|
|
+ if !s.etm {
|
|
|
|
|
+ s.mac.Write(data)
|
|
|
|
|
+ }
|
|
|
s.macResult = s.mac.Sum(s.macResult[:0])
|
|
s.macResult = s.mac.Sum(s.macResult[:0])
|
|
|
if subtle.ConstantTimeCompare(s.macResult, mac) != 1 {
|
|
if subtle.ConstantTimeCompare(s.macResult, mac) != 1 {
|
|
|
return nil, errors.New("ssh: MAC failure")
|
|
return nil, errors.New("ssh: MAC failure")
|
|
@@ -203,7 +223,13 @@ func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Rea
|
|
|
return errors.New("ssh: packet too large")
|
|
return errors.New("ssh: packet too large")
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- paddingLength := packetSizeMultiple - (prefixLen+len(packet))%packetSizeMultiple
|
|
|
|
|
|
|
+ aadlen := 0
|
|
|
|
|
+ if s.mac != nil && s.etm {
|
|
|
|
|
+ // packet length is not encrypted for EtM modes
|
|
|
|
|
+ aadlen = 4
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple
|
|
|
if paddingLength < 4 {
|
|
if paddingLength < 4 {
|
|
|
paddingLength += packetSizeMultiple
|
|
paddingLength += packetSizeMultiple
|
|
|
}
|
|
}
|
|
@@ -220,15 +246,37 @@ func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Rea
|
|
|
s.mac.Reset()
|
|
s.mac.Reset()
|
|
|
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
|
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
|
|
s.mac.Write(s.seqNumBytes[:])
|
|
s.mac.Write(s.seqNumBytes[:])
|
|
|
|
|
+
|
|
|
|
|
+ if s.etm {
|
|
|
|
|
+ // For EtM algorithms, the packet length must stay unencrypted,
|
|
|
|
|
+ // but the following data (padding length) must be encrypted
|
|
|
|
|
+ s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
s.mac.Write(s.prefix[:])
|
|
s.mac.Write(s.prefix[:])
|
|
|
- s.mac.Write(packet)
|
|
|
|
|
- s.mac.Write(padding)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if !s.etm {
|
|
|
|
|
+ // For non-EtM algorithms, the algorithm is applied on unencrypted data
|
|
|
|
|
+ s.mac.Write(packet)
|
|
|
|
|
+ s.mac.Write(padding)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if !(s.mac != nil && s.etm) {
|
|
|
|
|
+ // For EtM algorithms, the padding length has already been encrypted
|
|
|
|
|
+ // and the packet length must remain unencrypted
|
|
|
|
|
+ s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
|
|
|
|
s.cipher.XORKeyStream(packet, packet)
|
|
s.cipher.XORKeyStream(packet, packet)
|
|
|
s.cipher.XORKeyStream(padding, padding)
|
|
s.cipher.XORKeyStream(padding, padding)
|
|
|
|
|
|
|
|
|
|
+ if s.mac != nil && s.etm {
|
|
|
|
|
+ // For EtM algorithms, packet and padding must be encrypted
|
|
|
|
|
+ s.mac.Write(packet)
|
|
|
|
|
+ s.mac.Write(padding)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if _, err := w.Write(s.prefix[:]); err != nil {
|
|
if _, err := w.Write(s.prefix[:]); err != nil {
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|