...

Source file src/golang.org/x/crypto/ssh/cipher.go

Documentation: golang.org/x/crypto/ssh

     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.
     4  
     5  package ssh
     6  
     7  import (
     8  	"crypto/aes"
     9  	"crypto/cipher"
    10  	"crypto/des"
    11  	"crypto/rc4"
    12  	"crypto/subtle"
    13  	"encoding/binary"
    14  	"errors"
    15  	"fmt"
    16  	"hash"
    17  	"io"
    18  
    19  	"golang.org/x/crypto/chacha20"
    20  	"golang.org/x/crypto/internal/poly1305"
    21  )
    22  
    23  const (
    24  	packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher.
    25  
    26  	// RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations
    27  	// MUST be able to process (plus a few more kilobytes for padding and mac). The RFC
    28  	// indicates implementations SHOULD be able to handle larger packet sizes, but then
    29  	// waffles on about reasonable limits.
    30  	//
    31  	// OpenSSH caps their maxPacket at 256kB so we choose to do
    32  	// the same. maxPacket is also used to ensure that uint32
    33  	// length fields do not overflow, so it should remain well
    34  	// below 4G.
    35  	maxPacket = 256 * 1024
    36  )
    37  
    38  // noneCipher implements cipher.Stream and provides no encryption. It is used
    39  // by the transport before the first key-exchange.
    40  type noneCipher struct{}
    41  
    42  func (c noneCipher) XORKeyStream(dst, src []byte) {
    43  	copy(dst, src)
    44  }
    45  
    46  func newAESCTR(key, iv []byte) (cipher.Stream, error) {
    47  	c, err := aes.NewCipher(key)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  	return cipher.NewCTR(c, iv), nil
    52  }
    53  
    54  func newRC4(key, iv []byte) (cipher.Stream, error) {
    55  	return rc4.NewCipher(key)
    56  }
    57  
    58  type cipherMode struct {
    59  	keySize int
    60  	ivSize  int
    61  	create  func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error)
    62  }
    63  
    64  func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream, error)) func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
    65  	return func(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
    66  		stream, err := createFunc(key, iv)
    67  		if err != nil {
    68  			return nil, err
    69  		}
    70  
    71  		var streamDump []byte
    72  		if skip > 0 {
    73  			streamDump = make([]byte, 512)
    74  		}
    75  
    76  		for remainingToDump := skip; remainingToDump > 0; {
    77  			dumpThisTime := remainingToDump
    78  			if dumpThisTime > len(streamDump) {
    79  				dumpThisTime = len(streamDump)
    80  			}
    81  			stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime])
    82  			remainingToDump -= dumpThisTime
    83  		}
    84  
    85  		mac := macModes[algs.MAC].new(macKey)
    86  		return &streamPacketCipher{
    87  			mac:       mac,
    88  			etm:       macModes[algs.MAC].etm,
    89  			macResult: make([]byte, mac.Size()),
    90  			cipher:    stream,
    91  		}, nil
    92  	}
    93  }
    94  
    95  // cipherModes documents properties of supported ciphers. Ciphers not included
    96  // are not supported and will not be negotiated, even if explicitly requested in
    97  // ClientConfig.Crypto.Ciphers.
    98  var cipherModes = map[string]*cipherMode{
    99  	// Ciphers from RFC 4344, which introduced many CTR-based ciphers. Algorithms
   100  	// are defined in the order specified in the RFC.
   101  	"aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)},
   102  	"aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)},
   103  	"aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)},
   104  
   105  	// Ciphers from RFC 4345, which introduces security-improved arcfour ciphers.
   106  	// They are defined in the order specified in the RFC.
   107  	"arcfour128": {16, 0, streamCipherMode(1536, newRC4)},
   108  	"arcfour256": {32, 0, streamCipherMode(1536, newRC4)},
   109  
   110  	// Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol.
   111  	// Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and
   112  	// RC4) has problems with weak keys, and should be used with caution."
   113  	// RFC 4345 introduces improved versions of Arcfour.
   114  	"arcfour": {16, 0, streamCipherMode(0, newRC4)},
   115  
   116  	// AEAD ciphers
   117  	gcm128CipherID:     {16, 12, newGCMCipher},
   118  	gcm256CipherID:     {32, 12, newGCMCipher},
   119  	chacha20Poly1305ID: {64, 0, newChaCha20Cipher},
   120  
   121  	// CBC mode is insecure and so is not included in the default config.
   122  	// (See https://www.ieee-security.org/TC/SP2013/papers/4977a526.pdf). If absolutely
   123  	// needed, it's possible to specify a custom Config to enable it.
   124  	// You should expect that an active attacker can recover plaintext if
   125  	// you do.
   126  	aes128cbcID: {16, aes.BlockSize, newAESCBCCipher},
   127  
   128  	// 3des-cbc is insecure and is not included in the default
   129  	// config.
   130  	tripledescbcID: {24, des.BlockSize, newTripleDESCBCCipher},
   131  }
   132  
   133  // prefixLen is the length of the packet prefix that contains the packet length
   134  // and number of padding bytes.
   135  const prefixLen = 5
   136  
   137  // streamPacketCipher is a packetCipher using a stream cipher.
   138  type streamPacketCipher struct {
   139  	mac    hash.Hash
   140  	cipher cipher.Stream
   141  	etm    bool
   142  
   143  	// The following members are to avoid per-packet allocations.
   144  	prefix      [prefixLen]byte
   145  	seqNumBytes [4]byte
   146  	padding     [2 * packetSizeMultiple]byte
   147  	packetData  []byte
   148  	macResult   []byte
   149  }
   150  
   151  // readCipherPacket reads and decrypt a single packet from the reader argument.
   152  func (s *streamPacketCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
   153  	if _, err := io.ReadFull(r, s.prefix[:]); err != nil {
   154  		return nil, err
   155  	}
   156  
   157  	var encryptedPaddingLength [1]byte
   158  	if s.mac != nil && s.etm {
   159  		copy(encryptedPaddingLength[:], s.prefix[4:5])
   160  		s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
   161  	} else {
   162  		s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
   163  	}
   164  
   165  	length := binary.BigEndian.Uint32(s.prefix[0:4])
   166  	paddingLength := uint32(s.prefix[4])
   167  
   168  	var macSize uint32
   169  	if s.mac != nil {
   170  		s.mac.Reset()
   171  		binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
   172  		s.mac.Write(s.seqNumBytes[:])
   173  		if s.etm {
   174  			s.mac.Write(s.prefix[:4])
   175  			s.mac.Write(encryptedPaddingLength[:])
   176  		} else {
   177  			s.mac.Write(s.prefix[:])
   178  		}
   179  		macSize = uint32(s.mac.Size())
   180  	}
   181  
   182  	if length <= paddingLength+1 {
   183  		return nil, errors.New("ssh: invalid packet length, packet too small")
   184  	}
   185  
   186  	if length > maxPacket {
   187  		return nil, errors.New("ssh: invalid packet length, packet too large")
   188  	}
   189  
   190  	// the maxPacket check above ensures that length-1+macSize
   191  	// does not overflow.
   192  	if uint32(cap(s.packetData)) < length-1+macSize {
   193  		s.packetData = make([]byte, length-1+macSize)
   194  	} else {
   195  		s.packetData = s.packetData[:length-1+macSize]
   196  	}
   197  
   198  	if _, err := io.ReadFull(r, s.packetData); err != nil {
   199  		return nil, err
   200  	}
   201  	mac := s.packetData[length-1:]
   202  	data := s.packetData[:length-1]
   203  
   204  	if s.mac != nil && s.etm {
   205  		s.mac.Write(data)
   206  	}
   207  
   208  	s.cipher.XORKeyStream(data, data)
   209  
   210  	if s.mac != nil {
   211  		if !s.etm {
   212  			s.mac.Write(data)
   213  		}
   214  		s.macResult = s.mac.Sum(s.macResult[:0])
   215  		if subtle.ConstantTimeCompare(s.macResult, mac) != 1 {
   216  			return nil, errors.New("ssh: MAC failure")
   217  		}
   218  	}
   219  
   220  	return s.packetData[:length-paddingLength-1], nil
   221  }
   222  
   223  // writeCipherPacket encrypts and sends a packet of data to the writer argument
   224  func (s *streamPacketCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
   225  	if len(packet) > maxPacket {
   226  		return errors.New("ssh: packet too large")
   227  	}
   228  
   229  	aadlen := 0
   230  	if s.mac != nil && s.etm {
   231  		// packet length is not encrypted for EtM modes
   232  		aadlen = 4
   233  	}
   234  
   235  	paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple
   236  	if paddingLength < 4 {
   237  		paddingLength += packetSizeMultiple
   238  	}
   239  
   240  	length := len(packet) + 1 + paddingLength
   241  	binary.BigEndian.PutUint32(s.prefix[:], uint32(length))
   242  	s.prefix[4] = byte(paddingLength)
   243  	padding := s.padding[:paddingLength]
   244  	if _, err := io.ReadFull(rand, padding); err != nil {
   245  		return err
   246  	}
   247  
   248  	if s.mac != nil {
   249  		s.mac.Reset()
   250  		binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
   251  		s.mac.Write(s.seqNumBytes[:])
   252  
   253  		if s.etm {
   254  			// For EtM algorithms, the packet length must stay unencrypted,
   255  			// but the following data (padding length) must be encrypted
   256  			s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
   257  		}
   258  
   259  		s.mac.Write(s.prefix[:])
   260  
   261  		if !s.etm {
   262  			// For non-EtM algorithms, the algorithm is applied on unencrypted data
   263  			s.mac.Write(packet)
   264  			s.mac.Write(padding)
   265  		}
   266  	}
   267  
   268  	if !(s.mac != nil && s.etm) {
   269  		// For EtM algorithms, the padding length has already been encrypted
   270  		// and the packet length must remain unencrypted
   271  		s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
   272  	}
   273  
   274  	s.cipher.XORKeyStream(packet, packet)
   275  	s.cipher.XORKeyStream(padding, padding)
   276  
   277  	if s.mac != nil && s.etm {
   278  		// For EtM algorithms, packet and padding must be encrypted
   279  		s.mac.Write(packet)
   280  		s.mac.Write(padding)
   281  	}
   282  
   283  	if _, err := w.Write(s.prefix[:]); err != nil {
   284  		return err
   285  	}
   286  	if _, err := w.Write(packet); err != nil {
   287  		return err
   288  	}
   289  	if _, err := w.Write(padding); err != nil {
   290  		return err
   291  	}
   292  
   293  	if s.mac != nil {
   294  		s.macResult = s.mac.Sum(s.macResult[:0])
   295  		if _, err := w.Write(s.macResult); err != nil {
   296  			return err
   297  		}
   298  	}
   299  
   300  	return nil
   301  }
   302  
   303  type gcmCipher struct {
   304  	aead   cipher.AEAD
   305  	prefix [4]byte
   306  	iv     []byte
   307  	buf    []byte
   308  }
   309  
   310  func newGCMCipher(key, iv, unusedMacKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) {
   311  	c, err := aes.NewCipher(key)
   312  	if err != nil {
   313  		return nil, err
   314  	}
   315  
   316  	aead, err := cipher.NewGCM(c)
   317  	if err != nil {
   318  		return nil, err
   319  	}
   320  
   321  	return &gcmCipher{
   322  		aead: aead,
   323  		iv:   iv,
   324  	}, nil
   325  }
   326  
   327  const gcmTagSize = 16
   328  
   329  func (c *gcmCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
   330  	// Pad out to multiple of 16 bytes. This is different from the
   331  	// stream cipher because that encrypts the length too.
   332  	padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple)
   333  	if padding < 4 {
   334  		padding += packetSizeMultiple
   335  	}
   336  
   337  	length := uint32(len(packet) + int(padding) + 1)
   338  	binary.BigEndian.PutUint32(c.prefix[:], length)
   339  	if _, err := w.Write(c.prefix[:]); err != nil {
   340  		return err
   341  	}
   342  
   343  	if cap(c.buf) < int(length) {
   344  		c.buf = make([]byte, length)
   345  	} else {
   346  		c.buf = c.buf[:length]
   347  	}
   348  
   349  	c.buf[0] = padding
   350  	copy(c.buf[1:], packet)
   351  	if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil {
   352  		return err
   353  	}
   354  	c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:])
   355  	if _, err := w.Write(c.buf); err != nil {
   356  		return err
   357  	}
   358  	c.incIV()
   359  
   360  	return nil
   361  }
   362  
   363  func (c *gcmCipher) incIV() {
   364  	for i := 4 + 7; i >= 4; i-- {
   365  		c.iv[i]++
   366  		if c.iv[i] != 0 {
   367  			break
   368  		}
   369  	}
   370  }
   371  
   372  func (c *gcmCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
   373  	if _, err := io.ReadFull(r, c.prefix[:]); err != nil {
   374  		return nil, err
   375  	}
   376  	length := binary.BigEndian.Uint32(c.prefix[:])
   377  	if length > maxPacket {
   378  		return nil, errors.New("ssh: max packet length exceeded")
   379  	}
   380  
   381  	if cap(c.buf) < int(length+gcmTagSize) {
   382  		c.buf = make([]byte, length+gcmTagSize)
   383  	} else {
   384  		c.buf = c.buf[:length+gcmTagSize]
   385  	}
   386  
   387  	if _, err := io.ReadFull(r, c.buf); err != nil {
   388  		return nil, err
   389  	}
   390  
   391  	plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:])
   392  	if err != nil {
   393  		return nil, err
   394  	}
   395  	c.incIV()
   396  
   397  	if len(plain) == 0 {
   398  		return nil, errors.New("ssh: empty packet")
   399  	}
   400  
   401  	padding := plain[0]
   402  	if padding < 4 {
   403  		// padding is a byte, so it automatically satisfies
   404  		// the maximum size, which is 255.
   405  		return nil, fmt.Errorf("ssh: illegal padding %d", padding)
   406  	}
   407  
   408  	if int(padding+1) >= len(plain) {
   409  		return nil, fmt.Errorf("ssh: padding %d too large", padding)
   410  	}
   411  	plain = plain[1 : length-uint32(padding)]
   412  	return plain, nil
   413  }
   414  
   415  // cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1
   416  type cbcCipher struct {
   417  	mac       hash.Hash
   418  	macSize   uint32
   419  	decrypter cipher.BlockMode
   420  	encrypter cipher.BlockMode
   421  
   422  	// The following members are to avoid per-packet allocations.
   423  	seqNumBytes [4]byte
   424  	packetData  []byte
   425  	macResult   []byte
   426  
   427  	// Amount of data we should still read to hide which
   428  	// verification error triggered.
   429  	oracleCamouflage uint32
   430  }
   431  
   432  func newCBCCipher(c cipher.Block, key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
   433  	cbc := &cbcCipher{
   434  		mac:        macModes[algs.MAC].new(macKey),
   435  		decrypter:  cipher.NewCBCDecrypter(c, iv),
   436  		encrypter:  cipher.NewCBCEncrypter(c, iv),
   437  		packetData: make([]byte, 1024),
   438  	}
   439  	if cbc.mac != nil {
   440  		cbc.macSize = uint32(cbc.mac.Size())
   441  	}
   442  
   443  	return cbc, nil
   444  }
   445  
   446  func newAESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
   447  	c, err := aes.NewCipher(key)
   448  	if err != nil {
   449  		return nil, err
   450  	}
   451  
   452  	cbc, err := newCBCCipher(c, key, iv, macKey, algs)
   453  	if err != nil {
   454  		return nil, err
   455  	}
   456  
   457  	return cbc, nil
   458  }
   459  
   460  func newTripleDESCBCCipher(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
   461  	c, err := des.NewTripleDESCipher(key)
   462  	if err != nil {
   463  		return nil, err
   464  	}
   465  
   466  	cbc, err := newCBCCipher(c, key, iv, macKey, algs)
   467  	if err != nil {
   468  		return nil, err
   469  	}
   470  
   471  	return cbc, nil
   472  }
   473  
   474  func maxUInt32(a, b int) uint32 {
   475  	if a > b {
   476  		return uint32(a)
   477  	}
   478  	return uint32(b)
   479  }
   480  
   481  const (
   482  	cbcMinPacketSizeMultiple = 8
   483  	cbcMinPacketSize         = 16
   484  	cbcMinPaddingSize        = 4
   485  )
   486  
   487  // cbcError represents a verification error that may leak information.
   488  type cbcError string
   489  
   490  func (e cbcError) Error() string { return string(e) }
   491  
   492  func (c *cbcCipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
   493  	p, err := c.readCipherPacketLeaky(seqNum, r)
   494  	if err != nil {
   495  		if _, ok := err.(cbcError); ok {
   496  			// Verification error: read a fixed amount of
   497  			// data, to make distinguishing between
   498  			// failing MAC and failing length check more
   499  			// difficult.
   500  			io.CopyN(io.Discard, r, int64(c.oracleCamouflage))
   501  		}
   502  	}
   503  	return p, err
   504  }
   505  
   506  func (c *cbcCipher) readCipherPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
   507  	blockSize := c.decrypter.BlockSize()
   508  
   509  	// Read the header, which will include some of the subsequent data in the
   510  	// case of block ciphers - this is copied back to the payload later.
   511  	// How many bytes of payload/padding will be read with this first read.
   512  	firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize)
   513  	firstBlock := c.packetData[:firstBlockLength]
   514  	if _, err := io.ReadFull(r, firstBlock); err != nil {
   515  		return nil, err
   516  	}
   517  
   518  	c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength
   519  
   520  	c.decrypter.CryptBlocks(firstBlock, firstBlock)
   521  	length := binary.BigEndian.Uint32(firstBlock[:4])
   522  	if length > maxPacket {
   523  		return nil, cbcError("ssh: packet too large")
   524  	}
   525  	if length+4 < maxUInt32(cbcMinPacketSize, blockSize) {
   526  		// The minimum size of a packet is 16 (or the cipher block size, whichever
   527  		// is larger) bytes.
   528  		return nil, cbcError("ssh: packet too small")
   529  	}
   530  	// The length of the packet (including the length field but not the MAC) must
   531  	// be a multiple of the block size or 8, whichever is larger.
   532  	if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 {
   533  		return nil, cbcError("ssh: invalid packet length multiple")
   534  	}
   535  
   536  	paddingLength := uint32(firstBlock[4])
   537  	if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 {
   538  		return nil, cbcError("ssh: invalid packet length")
   539  	}
   540  
   541  	// Positions within the c.packetData buffer:
   542  	macStart := 4 + length
   543  	paddingStart := macStart - paddingLength
   544  
   545  	// Entire packet size, starting before length, ending at end of mac.
   546  	entirePacketSize := macStart + c.macSize
   547  
   548  	// Ensure c.packetData is large enough for the entire packet data.
   549  	if uint32(cap(c.packetData)) < entirePacketSize {
   550  		// Still need to upsize and copy, but this should be rare at runtime, only
   551  		// on upsizing the packetData buffer.
   552  		c.packetData = make([]byte, entirePacketSize)
   553  		copy(c.packetData, firstBlock)
   554  	} else {
   555  		c.packetData = c.packetData[:entirePacketSize]
   556  	}
   557  
   558  	n, err := io.ReadFull(r, c.packetData[firstBlockLength:])
   559  	if err != nil {
   560  		return nil, err
   561  	}
   562  	c.oracleCamouflage -= uint32(n)
   563  
   564  	remainingCrypted := c.packetData[firstBlockLength:macStart]
   565  	c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted)
   566  
   567  	mac := c.packetData[macStart:]
   568  	if c.mac != nil {
   569  		c.mac.Reset()
   570  		binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
   571  		c.mac.Write(c.seqNumBytes[:])
   572  		c.mac.Write(c.packetData[:macStart])
   573  		c.macResult = c.mac.Sum(c.macResult[:0])
   574  		if subtle.ConstantTimeCompare(c.macResult, mac) != 1 {
   575  			return nil, cbcError("ssh: MAC failure")
   576  		}
   577  	}
   578  
   579  	return c.packetData[prefixLen:paddingStart], nil
   580  }
   581  
   582  func (c *cbcCipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
   583  	effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize())
   584  
   585  	// Length of encrypted portion of the packet (header, payload, padding).
   586  	// Enforce minimum padding and packet size.
   587  	encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize)
   588  	// Enforce block size.
   589  	encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize
   590  
   591  	length := encLength - 4
   592  	paddingLength := int(length) - (1 + len(packet))
   593  
   594  	// Overall buffer contains: header, payload, padding, mac.
   595  	// Space for the MAC is reserved in the capacity but not the slice length.
   596  	bufferSize := encLength + c.macSize
   597  	if uint32(cap(c.packetData)) < bufferSize {
   598  		c.packetData = make([]byte, encLength, bufferSize)
   599  	} else {
   600  		c.packetData = c.packetData[:encLength]
   601  	}
   602  
   603  	p := c.packetData
   604  
   605  	// Packet header.
   606  	binary.BigEndian.PutUint32(p, length)
   607  	p = p[4:]
   608  	p[0] = byte(paddingLength)
   609  
   610  	// Payload.
   611  	p = p[1:]
   612  	copy(p, packet)
   613  
   614  	// Padding.
   615  	p = p[len(packet):]
   616  	if _, err := io.ReadFull(rand, p); err != nil {
   617  		return err
   618  	}
   619  
   620  	if c.mac != nil {
   621  		c.mac.Reset()
   622  		binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
   623  		c.mac.Write(c.seqNumBytes[:])
   624  		c.mac.Write(c.packetData)
   625  		// The MAC is now appended into the capacity reserved for it earlier.
   626  		c.packetData = c.mac.Sum(c.packetData)
   627  	}
   628  
   629  	c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength])
   630  
   631  	if _, err := w.Write(c.packetData); err != nil {
   632  		return err
   633  	}
   634  
   635  	return nil
   636  }
   637  
   638  const chacha20Poly1305ID = "chacha20-poly1305@openssh.com"
   639  
   640  // chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com
   641  // AEAD, which is described here:
   642  //
   643  //	https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00
   644  //
   645  // the methods here also implement padding, which RFC 4253 Section 6
   646  // also requires of stream ciphers.
   647  type chacha20Poly1305Cipher struct {
   648  	lengthKey  [32]byte
   649  	contentKey [32]byte
   650  	buf        []byte
   651  }
   652  
   653  func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs directionAlgorithms) (packetCipher, error) {
   654  	if len(key) != 64 {
   655  		panic(len(key))
   656  	}
   657  
   658  	c := &chacha20Poly1305Cipher{
   659  		buf: make([]byte, 256),
   660  	}
   661  
   662  	copy(c.contentKey[:], key[:32])
   663  	copy(c.lengthKey[:], key[32:])
   664  	return c, nil
   665  }
   666  
   667  func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) {
   668  	nonce := make([]byte, 12)
   669  	binary.BigEndian.PutUint32(nonce[8:], seqNum)
   670  	s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce)
   671  	if err != nil {
   672  		return nil, err
   673  	}
   674  	var polyKey, discardBuf [32]byte
   675  	s.XORKeyStream(polyKey[:], polyKey[:])
   676  	s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes
   677  
   678  	encryptedLength := c.buf[:4]
   679  	if _, err := io.ReadFull(r, encryptedLength); err != nil {
   680  		return nil, err
   681  	}
   682  
   683  	var lenBytes [4]byte
   684  	ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce)
   685  	if err != nil {
   686  		return nil, err
   687  	}
   688  	ls.XORKeyStream(lenBytes[:], encryptedLength)
   689  
   690  	length := binary.BigEndian.Uint32(lenBytes[:])
   691  	if length > maxPacket {
   692  		return nil, errors.New("ssh: invalid packet length, packet too large")
   693  	}
   694  
   695  	contentEnd := 4 + length
   696  	packetEnd := contentEnd + poly1305.TagSize
   697  	if uint32(cap(c.buf)) < packetEnd {
   698  		c.buf = make([]byte, packetEnd)
   699  		copy(c.buf[:], encryptedLength)
   700  	} else {
   701  		c.buf = c.buf[:packetEnd]
   702  	}
   703  
   704  	if _, err := io.ReadFull(r, c.buf[4:packetEnd]); err != nil {
   705  		return nil, err
   706  	}
   707  
   708  	var mac [poly1305.TagSize]byte
   709  	copy(mac[:], c.buf[contentEnd:packetEnd])
   710  	if !poly1305.Verify(&mac, c.buf[:contentEnd], &polyKey) {
   711  		return nil, errors.New("ssh: MAC failure")
   712  	}
   713  
   714  	plain := c.buf[4:contentEnd]
   715  	s.XORKeyStream(plain, plain)
   716  
   717  	if len(plain) == 0 {
   718  		return nil, errors.New("ssh: empty packet")
   719  	}
   720  
   721  	padding := plain[0]
   722  	if padding < 4 {
   723  		// padding is a byte, so it automatically satisfies
   724  		// the maximum size, which is 255.
   725  		return nil, fmt.Errorf("ssh: illegal padding %d", padding)
   726  	}
   727  
   728  	if int(padding)+1 >= len(plain) {
   729  		return nil, fmt.Errorf("ssh: padding %d too large", padding)
   730  	}
   731  
   732  	plain = plain[1 : len(plain)-int(padding)]
   733  
   734  	return plain, nil
   735  }
   736  
   737  func (c *chacha20Poly1305Cipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error {
   738  	nonce := make([]byte, 12)
   739  	binary.BigEndian.PutUint32(nonce[8:], seqNum)
   740  	s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce)
   741  	if err != nil {
   742  		return err
   743  	}
   744  	var polyKey, discardBuf [32]byte
   745  	s.XORKeyStream(polyKey[:], polyKey[:])
   746  	s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes
   747  
   748  	// There is no blocksize, so fall back to multiple of 8 byte
   749  	// padding, as described in RFC 4253, Sec 6.
   750  	const packetSizeMultiple = 8
   751  
   752  	padding := packetSizeMultiple - (1+len(payload))%packetSizeMultiple
   753  	if padding < 4 {
   754  		padding += packetSizeMultiple
   755  	}
   756  
   757  	// size (4 bytes), padding (1), payload, padding, tag.
   758  	totalLength := 4 + 1 + len(payload) + padding + poly1305.TagSize
   759  	if cap(c.buf) < totalLength {
   760  		c.buf = make([]byte, totalLength)
   761  	} else {
   762  		c.buf = c.buf[:totalLength]
   763  	}
   764  
   765  	binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding))
   766  	ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce)
   767  	if err != nil {
   768  		return err
   769  	}
   770  	ls.XORKeyStream(c.buf, c.buf[:4])
   771  	c.buf[4] = byte(padding)
   772  	copy(c.buf[5:], payload)
   773  	packetEnd := 5 + len(payload) + padding
   774  	if _, err := io.ReadFull(rand, c.buf[5+len(payload):packetEnd]); err != nil {
   775  		return err
   776  	}
   777  
   778  	s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd])
   779  
   780  	var mac [poly1305.TagSize]byte
   781  	poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey)
   782  
   783  	copy(c.buf[packetEnd:], mac[:])
   784  
   785  	if _, err := w.Write(c.buf); err != nil {
   786  		return err
   787  	}
   788  	return nil
   789  }
   790  

View as plain text