github.com/psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/crypto/ssh/cipher.go (about) 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 "io/ioutil" 19 20 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/internal/poly1305" 21 "golang.org/x/crypto/chacha20" 22 ) 23 24 const ( 25 packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher. 26 27 // RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations 28 // MUST be able to process (plus a few more kilobytes for padding and mac). The RFC 29 // indicates implementations SHOULD be able to handle larger packet sizes, but then 30 // waffles on about reasonable limits. 31 // 32 // OpenSSH caps their maxPacket at 256kB so we choose to do 33 // the same. maxPacket is also used to ensure that uint32 34 // length fields do not overflow, so it should remain well 35 // below 4G. 36 maxPacket = 256 * 1024 37 ) 38 39 // noneCipher implements cipher.Stream and provides no encryption. It is used 40 // by the transport before the first key-exchange. 41 type noneCipher struct{} 42 43 func (c noneCipher) XORKeyStream(dst, src []byte) { 44 copy(dst, src) 45 } 46 47 func newAESCTR(key, iv []byte) (cipher.Stream, error) { 48 c, err := aes.NewCipher(key) 49 if err != nil { 50 return nil, err 51 } 52 return cipher.NewCTR(c, iv), nil 53 } 54 55 func newRC4(key, iv []byte) (cipher.Stream, error) { 56 return rc4.NewCipher(key) 57 } 58 59 type cipherMode struct { 60 keySize int 61 ivSize int 62 create func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) 63 } 64 65 func streamCipherMode(skip int, createFunc func(key, iv []byte) (cipher.Stream, error)) func(key, iv []byte, macKey []byte, algs directionAlgorithms) (packetCipher, error) { 66 return func(key, iv, macKey []byte, algs directionAlgorithms) (packetCipher, error) { 67 stream, err := createFunc(key, iv) 68 if err != nil { 69 return nil, err 70 } 71 72 var streamDump []byte 73 if skip > 0 { 74 streamDump = make([]byte, 512) 75 } 76 77 for remainingToDump := skip; remainingToDump > 0; { 78 dumpThisTime := remainingToDump 79 if dumpThisTime > len(streamDump) { 80 dumpThisTime = len(streamDump) 81 } 82 stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) 83 remainingToDump -= dumpThisTime 84 } 85 86 mac := macModes[algs.MAC].new(macKey) 87 return &streamPacketCipher{ 88 mac: mac, 89 etm: macModes[algs.MAC].etm, 90 macResult: make([]byte, mac.Size()), 91 cipher: stream, 92 }, nil 93 } 94 } 95 96 // cipherModes documents properties of supported ciphers. Ciphers not included 97 // are not supported and will not be negotiated, even if explicitly requested in 98 // ClientConfig.Crypto.Ciphers. 99 var cipherModes = map[string]*cipherMode{ 100 // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms 101 // are defined in the order specified in the RFC. 102 "aes128-ctr": {16, aes.BlockSize, streamCipherMode(0, newAESCTR)}, 103 "aes192-ctr": {24, aes.BlockSize, streamCipherMode(0, newAESCTR)}, 104 "aes256-ctr": {32, aes.BlockSize, streamCipherMode(0, newAESCTR)}, 105 106 // Ciphers from RFC4345, which introduces security-improved arcfour ciphers. 107 // They are defined in the order specified in the RFC. 108 "arcfour128": {16, 0, streamCipherMode(1536, newRC4)}, 109 "arcfour256": {32, 0, streamCipherMode(1536, newRC4)}, 110 111 // Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol. 112 // Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and 113 // RC4) has problems with weak keys, and should be used with caution." 114 // RFC4345 introduces improved versions of Arcfour. 115 "arcfour": {16, 0, streamCipherMode(0, newRC4)}, 116 117 // AEAD ciphers 118 gcmCipherID: {16, 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(ioutil.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 RFC4253 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 }