1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
22 packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher.
24 // RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations
25 // MUST be able to process (plus a few more kilobytes for padding and mac). The RFC
26 // indicates implementations SHOULD be able to handle larger packet sizes, but then
27 // waffles on about reasonable limits.
29 // OpenSSH caps their maxPacket at 256kB so we choose to do
30 // the same. maxPacket is also used to ensure that uint32
31 // length fields do not overflow, so it should remain well
33 maxPacket = 256 * 1024
36 // noneCipher implements cipher.Stream and provides no encryption. It is used
37 // by the transport before the first key-exchange.
38 type noneCipher struct{}
40 func (c noneCipher) XORKeyStream(dst, src []byte) {
44 func newAESCTR(key, iv []byte) (cipher.Stream, error) {
45 c, err := aes.NewCipher(key)
49 return cipher.NewCTR(c, iv), nil
52 func newRC4(key, iv []byte) (cipher.Stream, error) {
53 return rc4.NewCipher(key)
56 type streamCipherMode struct {
60 createFunc func(key, iv []byte) (cipher.Stream, error)
63 func (c *streamCipherMode) createStream(key, iv []byte) (cipher.Stream, error) {
64 if len(key) < c.keySize {
65 panic("ssh: key length too small for cipher")
67 if len(iv) < c.ivSize {
68 panic("ssh: iv too small for cipher")
71 stream, err := c.createFunc(key[:c.keySize], iv[:c.ivSize])
78 streamDump = make([]byte, 512)
81 for remainingToDump := c.skip; remainingToDump > 0; {
82 dumpThisTime := remainingToDump
83 if dumpThisTime > len(streamDump) {
84 dumpThisTime = len(streamDump)
86 stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime])
87 remainingToDump -= dumpThisTime
93 // cipherModes documents properties of supported ciphers. Ciphers not included
94 // are not supported and will not be negotiated, even if explicitly requested in
95 // ClientConfig.Crypto.Ciphers.
96 var cipherModes = map[string]*streamCipherMode{
97 // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms
98 // are defined in the order specified in the RFC.
99 "aes128-ctr": {16, aes.BlockSize, 0, newAESCTR},
100 "aes192-ctr": {24, aes.BlockSize, 0, newAESCTR},
101 "aes256-ctr": {32, aes.BlockSize, 0, newAESCTR},
103 // Ciphers from RFC4345, which introduces security-improved arcfour ciphers.
104 // They are defined in the order specified in the RFC.
105 "arcfour128": {16, 0, 1536, newRC4},
106 "arcfour256": {32, 0, 1536, newRC4},
108 // Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol.
109 // Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and
110 // RC4) has problems with weak keys, and should be used with caution."
111 // RFC4345 introduces improved versions of Arcfour.
112 "arcfour": {16, 0, 0, newRC4},
114 // AES-GCM is not a stream cipher, so it is constructed with a
115 // special case. If we add any more non-stream ciphers, we
116 // should invest a cleaner way to do this.
117 gcmCipherID: {16, 12, 0, nil},
119 // CBC mode is insecure and so is not included in the default config.
120 // (See http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf). If absolutely
121 // needed, it's possible to specify a custom Config to enable it.
122 // You should expect that an active attacker can recover plaintext if
124 aes128cbcID: {16, aes.BlockSize, 0, nil},
126 // 3des-cbc is insecure and is disabled by default.
127 tripledescbcID: {24, des.BlockSize, 0, nil},
130 // prefixLen is the length of the packet prefix that contains the packet length
131 // and number of padding bytes.
134 // streamPacketCipher is a packetCipher using a stream cipher.
135 type streamPacketCipher struct {
140 // The following members are to avoid per-packet allocations.
141 prefix [prefixLen]byte
143 padding [2 * packetSizeMultiple]byte
148 // readPacket reads and decrypt a single packet from the reader argument.
149 func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
150 if _, err := io.ReadFull(r, s.prefix[:]); err != nil {
154 var encryptedPaddingLength [1]byte
155 if s.mac != nil && s.etm {
156 copy(encryptedPaddingLength[:], s.prefix[4:5])
157 s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
159 s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
162 length := binary.BigEndian.Uint32(s.prefix[0:4])
163 paddingLength := uint32(s.prefix[4])
168 binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
169 s.mac.Write(s.seqNumBytes[:])
171 s.mac.Write(s.prefix[:4])
172 s.mac.Write(encryptedPaddingLength[:])
174 s.mac.Write(s.prefix[:])
176 macSize = uint32(s.mac.Size())
179 if length <= paddingLength+1 {
180 return nil, errors.New("ssh: invalid packet length, packet too small")
183 if length > maxPacket {
184 return nil, errors.New("ssh: invalid packet length, packet too large")
187 // the maxPacket check above ensures that length-1+macSize
188 // does not overflow.
189 if uint32(cap(s.packetData)) < length-1+macSize {
190 s.packetData = make([]byte, length-1+macSize)
192 s.packetData = s.packetData[:length-1+macSize]
195 if _, err := io.ReadFull(r, s.packetData); err != nil {
198 mac := s.packetData[length-1:]
199 data := s.packetData[:length-1]
201 if s.mac != nil && s.etm {
205 s.cipher.XORKeyStream(data, data)
211 s.macResult = s.mac.Sum(s.macResult[:0])
212 if subtle.ConstantTimeCompare(s.macResult, mac) != 1 {
213 return nil, errors.New("ssh: MAC failure")
217 return s.packetData[:length-paddingLength-1], nil
220 // writePacket encrypts and sends a packet of data to the writer argument
221 func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
222 if len(packet) > maxPacket {
223 return errors.New("ssh: packet too large")
227 if s.mac != nil && s.etm {
228 // packet length is not encrypted for EtM modes
232 paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple
233 if paddingLength < 4 {
234 paddingLength += packetSizeMultiple
237 length := len(packet) + 1 + paddingLength
238 binary.BigEndian.PutUint32(s.prefix[:], uint32(length))
239 s.prefix[4] = byte(paddingLength)
240 padding := s.padding[:paddingLength]
241 if _, err := io.ReadFull(rand, padding); err != nil {
247 binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
248 s.mac.Write(s.seqNumBytes[:])
251 // For EtM algorithms, the packet length must stay unencrypted,
252 // but the following data (padding length) must be encrypted
253 s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
256 s.mac.Write(s.prefix[:])
259 // For non-EtM algorithms, the algorithm is applied on unencrypted data
265 if !(s.mac != nil && s.etm) {
266 // For EtM algorithms, the padding length has already been encrypted
267 // and the packet length must remain unencrypted
268 s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
271 s.cipher.XORKeyStream(packet, packet)
272 s.cipher.XORKeyStream(padding, padding)
274 if s.mac != nil && s.etm {
275 // For EtM algorithms, packet and padding must be encrypted
280 if _, err := w.Write(s.prefix[:]); err != nil {
283 if _, err := w.Write(packet); err != nil {
286 if _, err := w.Write(padding); err != nil {
291 s.macResult = s.mac.Sum(s.macResult[:0])
292 if _, err := w.Write(s.macResult); err != nil {
300 type gcmCipher struct {
307 func newGCMCipher(iv, key, macKey []byte) (packetCipher, error) {
308 c, err := aes.NewCipher(key)
313 aead, err := cipher.NewGCM(c)
324 const gcmTagSize = 16
326 func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
327 // Pad out to multiple of 16 bytes. This is different from the
328 // stream cipher because that encrypts the length too.
329 padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple)
331 padding += packetSizeMultiple
334 length := uint32(len(packet) + int(padding) + 1)
335 binary.BigEndian.PutUint32(c.prefix[:], length)
336 if _, err := w.Write(c.prefix[:]); err != nil {
340 if cap(c.buf) < int(length) {
341 c.buf = make([]byte, length)
343 c.buf = c.buf[:length]
347 copy(c.buf[1:], packet)
348 if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil {
351 c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:])
352 if _, err := w.Write(c.buf); err != nil {
360 func (c *gcmCipher) incIV() {
361 for i := 4 + 7; i >= 4; i-- {
369 func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
370 if _, err := io.ReadFull(r, c.prefix[:]); err != nil {
373 length := binary.BigEndian.Uint32(c.prefix[:])
374 if length > maxPacket {
375 return nil, errors.New("ssh: max packet length exceeded.")
378 if cap(c.buf) < int(length+gcmTagSize) {
379 c.buf = make([]byte, length+gcmTagSize)
381 c.buf = c.buf[:length+gcmTagSize]
384 if _, err := io.ReadFull(r, c.buf); err != nil {
388 plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:])
396 // padding is a byte, so it automatically satisfies
397 // the maximum size, which is 255.
398 return nil, fmt.Errorf("ssh: illegal padding %d", padding)
401 if int(padding+1) >= len(plain) {
402 return nil, fmt.Errorf("ssh: padding %d too large", padding)
404 plain = plain[1 : length-uint32(padding)]
408 // cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1
409 type cbcCipher struct {
412 decrypter cipher.BlockMode
413 encrypter cipher.BlockMode
415 // The following members are to avoid per-packet allocations.
420 // Amount of data we should still read to hide which
421 // verification error triggered.
422 oracleCamouflage uint32
425 func newCBCCipher(c cipher.Block, iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
427 mac: macModes[algs.MAC].new(macKey),
428 decrypter: cipher.NewCBCDecrypter(c, iv),
429 encrypter: cipher.NewCBCEncrypter(c, iv),
430 packetData: make([]byte, 1024),
433 cbc.macSize = uint32(cbc.mac.Size())
439 func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
440 c, err := aes.NewCipher(key)
445 cbc, err := newCBCCipher(c, iv, key, macKey, algs)
453 func newTripleDESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
454 c, err := des.NewTripleDESCipher(key)
459 cbc, err := newCBCCipher(c, iv, key, macKey, algs)
467 func maxUInt32(a, b int) uint32 {
475 cbcMinPacketSizeMultiple = 8
476 cbcMinPacketSize = 16
477 cbcMinPaddingSize = 4
480 // cbcError represents a verification error that may leak information.
483 func (e cbcError) Error() string { return string(e) }
485 func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
486 p, err := c.readPacketLeaky(seqNum, r)
488 if _, ok := err.(cbcError); ok {
489 // Verification error: read a fixed amount of
490 // data, to make distinguishing between
491 // failing MAC and failing length check more
493 io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage))
499 func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
500 blockSize := c.decrypter.BlockSize()
502 // Read the header, which will include some of the subsequent data in the
503 // case of block ciphers - this is copied back to the payload later.
504 // How many bytes of payload/padding will be read with this first read.
505 firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize)
506 firstBlock := c.packetData[:firstBlockLength]
507 if _, err := io.ReadFull(r, firstBlock); err != nil {
511 c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength
513 c.decrypter.CryptBlocks(firstBlock, firstBlock)
514 length := binary.BigEndian.Uint32(firstBlock[:4])
515 if length > maxPacket {
516 return nil, cbcError("ssh: packet too large")
518 if length+4 < maxUInt32(cbcMinPacketSize, blockSize) {
519 // The minimum size of a packet is 16 (or the cipher block size, whichever
521 return nil, cbcError("ssh: packet too small")
523 // The length of the packet (including the length field but not the MAC) must
524 // be a multiple of the block size or 8, whichever is larger.
525 if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 {
526 return nil, cbcError("ssh: invalid packet length multiple")
529 paddingLength := uint32(firstBlock[4])
530 if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 {
531 return nil, cbcError("ssh: invalid packet length")
534 // Positions within the c.packetData buffer:
535 macStart := 4 + length
536 paddingStart := macStart - paddingLength
538 // Entire packet size, starting before length, ending at end of mac.
539 entirePacketSize := macStart + c.macSize
541 // Ensure c.packetData is large enough for the entire packet data.
542 if uint32(cap(c.packetData)) < entirePacketSize {
543 // Still need to upsize and copy, but this should be rare at runtime, only
544 // on upsizing the packetData buffer.
545 c.packetData = make([]byte, entirePacketSize)
546 copy(c.packetData, firstBlock)
548 c.packetData = c.packetData[:entirePacketSize]
551 if n, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil {
554 c.oracleCamouflage -= uint32(n)
557 remainingCrypted := c.packetData[firstBlockLength:macStart]
558 c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted)
560 mac := c.packetData[macStart:]
563 binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
564 c.mac.Write(c.seqNumBytes[:])
565 c.mac.Write(c.packetData[:macStart])
566 c.macResult = c.mac.Sum(c.macResult[:0])
567 if subtle.ConstantTimeCompare(c.macResult, mac) != 1 {
568 return nil, cbcError("ssh: MAC failure")
572 return c.packetData[prefixLen:paddingStart], nil
575 func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
576 effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize())
578 // Length of encrypted portion of the packet (header, payload, padding).
579 // Enforce minimum padding and packet size.
580 encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize)
581 // Enforce block size.
582 encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize
584 length := encLength - 4
585 paddingLength := int(length) - (1 + len(packet))
587 // Overall buffer contains: header, payload, padding, mac.
588 // Space for the MAC is reserved in the capacity but not the slice length.
589 bufferSize := encLength + c.macSize
590 if uint32(cap(c.packetData)) < bufferSize {
591 c.packetData = make([]byte, encLength, bufferSize)
593 c.packetData = c.packetData[:encLength]
599 binary.BigEndian.PutUint32(p, length)
601 p[0] = byte(paddingLength)
609 if _, err := io.ReadFull(rand, p); err != nil {
615 binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
616 c.mac.Write(c.seqNumBytes[:])
617 c.mac.Write(c.packetData)
618 // The MAC is now appended into the capacity reserved for it earlier.
619 c.packetData = c.mac.Sum(c.packetData)
622 c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength])
624 if _, err := w.Write(c.packetData); err != nil {