a geicko-2 based round robin ranking system designed to test c++ battleship submissions battleship.dunkirk.sh
at main 22 kB view raw
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 5package ssh 6 7import ( 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 23const ( 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. 40type noneCipher struct{} 41 42func (c noneCipher) XORKeyStream(dst, src []byte) { 43 copy(dst, src) 44} 45 46func 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 54func newRC4(key, iv []byte) (cipher.Stream, error) { 55 return rc4.NewCipher(key) 56} 57 58type cipherMode struct { 59 keySize int 60 ivSize int 61 create func(key, iv []byte, macKey []byte, algs DirectionAlgorithms) (packetCipher, error) 62} 63 64func 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. 98var 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 CipherAES128CTR: {16, aes.BlockSize, streamCipherMode(0, newAESCTR)}, 102 CipherAES192CTR: {24, aes.BlockSize, streamCipherMode(0, newAESCTR)}, 103 CipherAES256CTR: {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 InsecureCipherRC4128: {16, 0, streamCipherMode(1536, newRC4)}, 108 InsecureCipherRC4256: {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 InsecureCipherRC4: {16, 0, streamCipherMode(0, newRC4)}, 115 116 // AEAD ciphers 117 CipherAES128GCM: {16, 12, newGCMCipher}, 118 CipherAES256GCM: {32, 12, newGCMCipher}, 119 CipherChaCha20Poly1305: {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 InsecureCipherAES128CBC: {16, aes.BlockSize, newAESCBCCipher}, 127 128 // 3des-cbc is insecure and is not included in the default 129 // config. 130 InsecureCipherTripleDESCBC: {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. 135const prefixLen = 5 136 137// streamPacketCipher is a packetCipher using a stream cipher. 138type 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. 152func (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 224func (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 303type gcmCipher struct { 304 aead cipher.AEAD 305 prefix [4]byte 306 iv []byte 307 buf []byte 308} 309 310func 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 327const gcmTagSize = 16 328 329func (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 363func (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 372func (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 416type 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 432func 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 446func 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 460func 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 474func maxUInt32(a, b int) uint32 { 475 if a > b { 476 return uint32(a) 477 } 478 return uint32(b) 479} 480 481const ( 482 cbcMinPacketSizeMultiple = 8 483 cbcMinPacketSize = 16 484 cbcMinPaddingSize = 4 485) 486 487// cbcError represents a verification error that may leak information. 488type cbcError string 489 490func (e cbcError) Error() string { return string(e) } 491 492func (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 506func (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 582func (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// chacha20Poly1305Cipher implements the chacha20-poly1305@openssh.com 639// AEAD, which is described here: 640// 641// https://tools.ietf.org/html/draft-josefsson-ssh-chacha20-poly1305-openssh-00 642// 643// the methods here also implement padding, which RFC 4253 Section 6 644// also requires of stream ciphers. 645type chacha20Poly1305Cipher struct { 646 lengthKey [32]byte 647 contentKey [32]byte 648 buf []byte 649} 650 651func newChaCha20Cipher(key, unusedIV, unusedMACKey []byte, unusedAlgs DirectionAlgorithms) (packetCipher, error) { 652 if len(key) != 64 { 653 panic(len(key)) 654 } 655 656 c := &chacha20Poly1305Cipher{ 657 buf: make([]byte, 256), 658 } 659 660 copy(c.contentKey[:], key[:32]) 661 copy(c.lengthKey[:], key[32:]) 662 return c, nil 663} 664 665func (c *chacha20Poly1305Cipher) readCipherPacket(seqNum uint32, r io.Reader) ([]byte, error) { 666 nonce := make([]byte, 12) 667 binary.BigEndian.PutUint32(nonce[8:], seqNum) 668 s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce) 669 if err != nil { 670 return nil, err 671 } 672 var polyKey, discardBuf [32]byte 673 s.XORKeyStream(polyKey[:], polyKey[:]) 674 s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes 675 676 encryptedLength := c.buf[:4] 677 if _, err := io.ReadFull(r, encryptedLength); err != nil { 678 return nil, err 679 } 680 681 var lenBytes [4]byte 682 ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce) 683 if err != nil { 684 return nil, err 685 } 686 ls.XORKeyStream(lenBytes[:], encryptedLength) 687 688 length := binary.BigEndian.Uint32(lenBytes[:]) 689 if length > maxPacket { 690 return nil, errors.New("ssh: invalid packet length, packet too large") 691 } 692 693 contentEnd := 4 + length 694 packetEnd := contentEnd + poly1305.TagSize 695 if uint32(cap(c.buf)) < packetEnd { 696 c.buf = make([]byte, packetEnd) 697 copy(c.buf[:], encryptedLength) 698 } else { 699 c.buf = c.buf[:packetEnd] 700 } 701 702 if _, err := io.ReadFull(r, c.buf[4:packetEnd]); err != nil { 703 return nil, err 704 } 705 706 var mac [poly1305.TagSize]byte 707 copy(mac[:], c.buf[contentEnd:packetEnd]) 708 if !poly1305.Verify(&mac, c.buf[:contentEnd], &polyKey) { 709 return nil, errors.New("ssh: MAC failure") 710 } 711 712 plain := c.buf[4:contentEnd] 713 s.XORKeyStream(plain, plain) 714 715 if len(plain) == 0 { 716 return nil, errors.New("ssh: empty packet") 717 } 718 719 padding := plain[0] 720 if padding < 4 { 721 // padding is a byte, so it automatically satisfies 722 // the maximum size, which is 255. 723 return nil, fmt.Errorf("ssh: illegal padding %d", padding) 724 } 725 726 if int(padding)+1 >= len(plain) { 727 return nil, fmt.Errorf("ssh: padding %d too large", padding) 728 } 729 730 plain = plain[1 : len(plain)-int(padding)] 731 732 return plain, nil 733} 734 735func (c *chacha20Poly1305Cipher) writeCipherPacket(seqNum uint32, w io.Writer, rand io.Reader, payload []byte) error { 736 nonce := make([]byte, 12) 737 binary.BigEndian.PutUint32(nonce[8:], seqNum) 738 s, err := chacha20.NewUnauthenticatedCipher(c.contentKey[:], nonce) 739 if err != nil { 740 return err 741 } 742 var polyKey, discardBuf [32]byte 743 s.XORKeyStream(polyKey[:], polyKey[:]) 744 s.XORKeyStream(discardBuf[:], discardBuf[:]) // skip the next 32 bytes 745 746 // There is no blocksize, so fall back to multiple of 8 byte 747 // padding, as described in RFC 4253, Sec 6. 748 const packetSizeMultiple = 8 749 750 padding := packetSizeMultiple - (1+len(payload))%packetSizeMultiple 751 if padding < 4 { 752 padding += packetSizeMultiple 753 } 754 755 // size (4 bytes), padding (1), payload, padding, tag. 756 totalLength := 4 + 1 + len(payload) + padding + poly1305.TagSize 757 if cap(c.buf) < totalLength { 758 c.buf = make([]byte, totalLength) 759 } else { 760 c.buf = c.buf[:totalLength] 761 } 762 763 binary.BigEndian.PutUint32(c.buf, uint32(1+len(payload)+padding)) 764 ls, err := chacha20.NewUnauthenticatedCipher(c.lengthKey[:], nonce) 765 if err != nil { 766 return err 767 } 768 ls.XORKeyStream(c.buf, c.buf[:4]) 769 c.buf[4] = byte(padding) 770 copy(c.buf[5:], payload) 771 packetEnd := 5 + len(payload) + padding 772 if _, err := io.ReadFull(rand, c.buf[5+len(payload):packetEnd]); err != nil { 773 return err 774 } 775 776 s.XORKeyStream(c.buf[4:], c.buf[4:packetEnd]) 777 778 var mac [poly1305.TagSize]byte 779 poly1305.Sum(&mac, c.buf[:packetEnd], &polyKey) 780 781 copy(c.buf[packetEnd:], mac[:]) 782 783 if _, err := w.Write(c.buf); err != nil { 784 return err 785 } 786 return nil 787}