github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/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/rc4" 11 "crypto/subtle" 12 "encoding/binary" 13 "errors" 14 "fmt" 15 "hash" 16 "io" 17 "io/ioutil" 18 ) 19 20 const ( 21 packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher. 22 23 // RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations 24 // MUST be able to process (plus a few more kilobytes for padding and mac). The RFC 25 // indicates implementations SHOULD be able to handle larger packet sizes, but then 26 // waffles on about reasonable limits. 27 // 28 // OpenSSH caps their maxPacket at 256kB so we choose to do 29 // the same. maxPacket is also used to ensure that uint32 30 // length fields do not overflow, so it should remain well 31 // below 4G. 32 maxPacket = 256 * 1024 33 ) 34 35 // noneCipher implements cipher.Stream and provides no encryption. It is used 36 // by the transport before the first key-exchange. 37 type noneCipher struct{} 38 39 func (c noneCipher) XORKeyStream(dst, src []byte) { 40 copy(dst, src) 41 } 42 43 func newAESCTR(key, iv []byte) (cipher.Stream, error) { 44 c, err := aes.NewCipher(key) 45 if err != nil { 46 return nil, err 47 } 48 return cipher.NewCTR(c, iv), nil 49 } 50 51 func newRC4(key, iv []byte) (cipher.Stream, error) { 52 return rc4.NewCipher(key) 53 } 54 55 type streamCipherMode struct { 56 keySize int 57 ivSize int 58 skip int 59 createFunc func(key, iv []byte) (cipher.Stream, error) 60 } 61 62 func (c *streamCipherMode) createStream(key, iv []byte) (cipher.Stream, error) { 63 if len(key) < c.keySize { 64 panic("ssh: key length too small for cipher") 65 } 66 if len(iv) < c.ivSize { 67 panic("ssh: iv too small for cipher") 68 } 69 70 stream, err := c.createFunc(key[:c.keySize], iv[:c.ivSize]) 71 if err != nil { 72 return nil, err 73 } 74 75 var streamDump []byte 76 if c.skip > 0 { 77 streamDump = make([]byte, 512) 78 } 79 80 for remainingToDump := c.skip; remainingToDump > 0; { 81 dumpThisTime := remainingToDump 82 if dumpThisTime > len(streamDump) { 83 dumpThisTime = len(streamDump) 84 } 85 stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) 86 remainingToDump -= dumpThisTime 87 } 88 89 return stream, nil 90 } 91 92 // cipherModes documents properties of supported ciphers. Ciphers not included 93 // are not supported and will not be negotiated, even if explicitly requested in 94 // ClientConfig.Crypto.Ciphers. 95 var cipherModes = map[string]*streamCipherMode{ 96 // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms 97 // are defined in the order specified in the RFC. 98 "aes128-ctr": {16, aes.BlockSize, 0, newAESCTR}, 99 "aes192-ctr": {24, aes.BlockSize, 0, newAESCTR}, 100 "aes256-ctr": {32, aes.BlockSize, 0, newAESCTR}, 101 102 // Ciphers from RFC4345, which introduces security-improved arcfour ciphers. 103 // They are defined in the order specified in the RFC. 104 "arcfour128": {16, 0, 1536, newRC4}, 105 "arcfour256": {32, 0, 1536, newRC4}, 106 107 // Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol. 108 // Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and 109 // RC4) has problems with weak keys, and should be used with caution." 110 // RFC4345 introduces improved versions of Arcfour. 111 "arcfour": {16, 0, 0, newRC4}, 112 113 // AES-GCM is not a stream cipher, so it is constructed with a 114 // special case. If we add any more non-stream ciphers, we 115 // should invest a cleaner way to do this. 116 gcmCipherID: {16, 12, 0, nil}, 117 118 // insecure cipher, see http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf 119 // uncomment below to enable it. 120 // aes128cbcID: {16, aes.BlockSize, 0, nil}, 121 } 122 123 // prefixLen is the length of the packet prefix that contains the packet length 124 // and number of padding bytes. 125 const prefixLen = 5 126 127 // streamPacketCipher is a packetCipher using a stream cipher. 128 type streamPacketCipher struct { 129 mac hash.Hash 130 cipher cipher.Stream 131 132 // The following members are to avoid per-packet allocations. 133 prefix [prefixLen]byte 134 seqNumBytes [4]byte 135 padding [2 * packetSizeMultiple]byte 136 packetData []byte 137 macResult []byte 138 } 139 140 // readPacket reads and decrypt a single packet from the reader argument. 141 func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { 142 if _, err := io.ReadFull(r, s.prefix[:]); err != nil { 143 return nil, err 144 } 145 146 s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) 147 length := binary.BigEndian.Uint32(s.prefix[0:4]) 148 paddingLength := uint32(s.prefix[4]) 149 150 var macSize uint32 151 if s.mac != nil { 152 s.mac.Reset() 153 binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) 154 s.mac.Write(s.seqNumBytes[:]) 155 s.mac.Write(s.prefix[:]) 156 macSize = uint32(s.mac.Size()) 157 } 158 159 if length <= paddingLength+1 { 160 return nil, errors.New("ssh: invalid packet length, packet too small") 161 } 162 163 if length > maxPacket { 164 return nil, errors.New("ssh: invalid packet length, packet too large") 165 } 166 167 // the maxPacket check above ensures that length-1+macSize 168 // does not overflow. 169 if uint32(cap(s.packetData)) < length-1+macSize { 170 s.packetData = make([]byte, length-1+macSize) 171 } else { 172 s.packetData = s.packetData[:length-1+macSize] 173 } 174 175 if _, err := io.ReadFull(r, s.packetData); err != nil { 176 return nil, err 177 } 178 mac := s.packetData[length-1:] 179 data := s.packetData[:length-1] 180 s.cipher.XORKeyStream(data, data) 181 182 if s.mac != nil { 183 s.mac.Write(data) 184 s.macResult = s.mac.Sum(s.macResult[:0]) 185 if subtle.ConstantTimeCompare(s.macResult, mac) != 1 { 186 return nil, errors.New("ssh: MAC failure") 187 } 188 } 189 190 return s.packetData[:length-paddingLength-1], nil 191 } 192 193 // writePacket encrypts and sends a packet of data to the writer argument 194 func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { 195 if len(packet) > maxPacket { 196 return errors.New("ssh: packet too large") 197 } 198 199 paddingLength := packetSizeMultiple - (prefixLen+len(packet))%packetSizeMultiple 200 if paddingLength < 4 { 201 paddingLength += packetSizeMultiple 202 } 203 204 length := len(packet) + 1 + paddingLength 205 binary.BigEndian.PutUint32(s.prefix[:], uint32(length)) 206 s.prefix[4] = byte(paddingLength) 207 padding := s.padding[:paddingLength] 208 if _, err := io.ReadFull(rand, padding); err != nil { 209 return err 210 } 211 212 if s.mac != nil { 213 s.mac.Reset() 214 binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) 215 s.mac.Write(s.seqNumBytes[:]) 216 s.mac.Write(s.prefix[:]) 217 s.mac.Write(packet) 218 s.mac.Write(padding) 219 } 220 221 s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) 222 s.cipher.XORKeyStream(packet, packet) 223 s.cipher.XORKeyStream(padding, padding) 224 225 if _, err := w.Write(s.prefix[:]); err != nil { 226 return err 227 } 228 if _, err := w.Write(packet); err != nil { 229 return err 230 } 231 if _, err := w.Write(padding); err != nil { 232 return err 233 } 234 235 if s.mac != nil { 236 s.macResult = s.mac.Sum(s.macResult[:0]) 237 if _, err := w.Write(s.macResult); err != nil { 238 return err 239 } 240 } 241 242 return nil 243 } 244 245 type gcmCipher struct { 246 aead cipher.AEAD 247 prefix [4]byte 248 iv []byte 249 buf []byte 250 } 251 252 func newGCMCipher(iv, key, macKey []byte) (packetCipher, error) { 253 c, err := aes.NewCipher(key) 254 if err != nil { 255 return nil, err 256 } 257 258 aead, err := cipher.NewGCM(c) 259 if err != nil { 260 return nil, err 261 } 262 263 return &gcmCipher{ 264 aead: aead, 265 iv: iv, 266 }, nil 267 } 268 269 const gcmTagSize = 16 270 271 func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { 272 // Pad out to multiple of 16 bytes. This is different from the 273 // stream cipher because that encrypts the length too. 274 padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) 275 if padding < 4 { 276 padding += packetSizeMultiple 277 } 278 279 length := uint32(len(packet) + int(padding) + 1) 280 binary.BigEndian.PutUint32(c.prefix[:], length) 281 if _, err := w.Write(c.prefix[:]); err != nil { 282 return err 283 } 284 285 if cap(c.buf) < int(length) { 286 c.buf = make([]byte, length) 287 } else { 288 c.buf = c.buf[:length] 289 } 290 291 c.buf[0] = padding 292 copy(c.buf[1:], packet) 293 if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil { 294 return err 295 } 296 c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:]) 297 if _, err := w.Write(c.buf); err != nil { 298 return err 299 } 300 c.incIV() 301 302 return nil 303 } 304 305 func (c *gcmCipher) incIV() { 306 for i := 4 + 7; i >= 4; i-- { 307 c.iv[i]++ 308 if c.iv[i] != 0 { 309 break 310 } 311 } 312 } 313 314 func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { 315 if _, err := io.ReadFull(r, c.prefix[:]); err != nil { 316 return nil, err 317 } 318 length := binary.BigEndian.Uint32(c.prefix[:]) 319 if length > maxPacket { 320 return nil, errors.New("ssh: max packet length exceeded.") 321 } 322 323 if cap(c.buf) < int(length+gcmTagSize) { 324 c.buf = make([]byte, length+gcmTagSize) 325 } else { 326 c.buf = c.buf[:length+gcmTagSize] 327 } 328 329 if _, err := io.ReadFull(r, c.buf); err != nil { 330 return nil, err 331 } 332 333 plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:]) 334 if err != nil { 335 return nil, err 336 } 337 c.incIV() 338 339 padding := plain[0] 340 if padding < 4 || padding >= 20 { 341 return nil, fmt.Errorf("ssh: illegal padding %d", padding) 342 } 343 344 if int(padding+1) >= len(plain) { 345 return nil, fmt.Errorf("ssh: padding %d too large", padding) 346 } 347 plain = plain[1 : length-uint32(padding)] 348 return plain, nil 349 } 350 351 // cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1 352 type cbcCipher struct { 353 mac hash.Hash 354 macSize uint32 355 decrypter cipher.BlockMode 356 encrypter cipher.BlockMode 357 358 // The following members are to avoid per-packet allocations. 359 seqNumBytes [4]byte 360 packetData []byte 361 macResult []byte 362 363 // Amount of data we should still read to hide which 364 // verification error triggered. 365 oracleCamouflage uint32 366 } 367 368 func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { 369 c, err := aes.NewCipher(key) 370 if err != nil { 371 return nil, err 372 } 373 374 cbc := &cbcCipher{ 375 mac: macModes[algs.MAC].new(macKey), 376 decrypter: cipher.NewCBCDecrypter(c, iv), 377 encrypter: cipher.NewCBCEncrypter(c, iv), 378 packetData: make([]byte, 1024), 379 } 380 if cbc.mac != nil { 381 cbc.macSize = uint32(cbc.mac.Size()) 382 } 383 384 return cbc, nil 385 } 386 387 func maxUInt32(a, b int) uint32 { 388 if a > b { 389 return uint32(a) 390 } 391 return uint32(b) 392 } 393 394 const ( 395 cbcMinPacketSizeMultiple = 8 396 cbcMinPacketSize = 16 397 cbcMinPaddingSize = 4 398 ) 399 400 // cbcError represents a verification error that may leak information. 401 type cbcError string 402 403 func (e cbcError) Error() string { return string(e) } 404 405 func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { 406 p, err := c.readPacketLeaky(seqNum, r) 407 if err != nil { 408 if _, ok := err.(cbcError); ok { 409 // Verification error: read a fixed amount of 410 // data, to make distinguishing between 411 // failing MAC and failing length check more 412 // difficult. 413 io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage)) 414 } 415 } 416 return p, err 417 } 418 419 func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { 420 blockSize := c.decrypter.BlockSize() 421 422 // Read the header, which will include some of the subsequent data in the 423 // case of block ciphers - this is copied back to the payload later. 424 // How many bytes of payload/padding will be read with this first read. 425 firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize) 426 firstBlock := c.packetData[:firstBlockLength] 427 if _, err := io.ReadFull(r, firstBlock); err != nil { 428 return nil, err 429 } 430 431 c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength 432 433 c.decrypter.CryptBlocks(firstBlock, firstBlock) 434 length := binary.BigEndian.Uint32(firstBlock[:4]) 435 if length > maxPacket { 436 return nil, cbcError("ssh: packet too large") 437 } 438 if length+4 < maxUInt32(cbcMinPacketSize, blockSize) { 439 // The minimum size of a packet is 16 (or the cipher block size, whichever 440 // is larger) bytes. 441 return nil, cbcError("ssh: packet too small") 442 } 443 // The length of the packet (including the length field but not the MAC) must 444 // be a multiple of the block size or 8, whichever is larger. 445 if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 { 446 return nil, cbcError("ssh: invalid packet length multiple") 447 } 448 449 paddingLength := uint32(firstBlock[4]) 450 if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 { 451 return nil, cbcError("ssh: invalid packet length") 452 } 453 454 // Positions within the c.packetData buffer: 455 macStart := 4 + length 456 paddingStart := macStart - paddingLength 457 458 // Entire packet size, starting before length, ending at end of mac. 459 entirePacketSize := macStart + c.macSize 460 461 // Ensure c.packetData is large enough for the entire packet data. 462 if uint32(cap(c.packetData)) < entirePacketSize { 463 // Still need to upsize and copy, but this should be rare at runtime, only 464 // on upsizing the packetData buffer. 465 c.packetData = make([]byte, entirePacketSize) 466 copy(c.packetData, firstBlock) 467 } else { 468 c.packetData = c.packetData[:entirePacketSize] 469 } 470 471 if n, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil { 472 return nil, err 473 } else { 474 c.oracleCamouflage -= uint32(n) 475 } 476 477 remainingCrypted := c.packetData[firstBlockLength:macStart] 478 c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted) 479 480 mac := c.packetData[macStart:] 481 if c.mac != nil { 482 c.mac.Reset() 483 binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) 484 c.mac.Write(c.seqNumBytes[:]) 485 c.mac.Write(c.packetData[:macStart]) 486 c.macResult = c.mac.Sum(c.macResult[:0]) 487 if subtle.ConstantTimeCompare(c.macResult, mac) != 1 { 488 return nil, cbcError("ssh: MAC failure") 489 } 490 } 491 492 return c.packetData[prefixLen:paddingStart], nil 493 } 494 495 func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { 496 effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize()) 497 498 // Length of encrypted portion of the packet (header, payload, padding). 499 // Enforce minimum padding and packet size. 500 encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize) 501 // Enforce block size. 502 encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize 503 504 length := encLength - 4 505 paddingLength := int(length) - (1 + len(packet)) 506 507 // Overall buffer contains: header, payload, padding, mac. 508 // Space for the MAC is reserved in the capacity but not the slice length. 509 bufferSize := encLength + c.macSize 510 if uint32(cap(c.packetData)) < bufferSize { 511 c.packetData = make([]byte, encLength, bufferSize) 512 } else { 513 c.packetData = c.packetData[:encLength] 514 } 515 516 p := c.packetData 517 518 // Packet header. 519 binary.BigEndian.PutUint32(p, length) 520 p = p[4:] 521 p[0] = byte(paddingLength) 522 523 // Payload. 524 p = p[1:] 525 copy(p, packet) 526 527 // Padding. 528 p = p[len(packet):] 529 if _, err := io.ReadFull(rand, p); err != nil { 530 return err 531 } 532 533 if c.mac != nil { 534 c.mac.Reset() 535 binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) 536 c.mac.Write(c.seqNumBytes[:]) 537 c.mac.Write(c.packetData) 538 // The MAC is now appended into the capacity reserved for it earlier. 539 c.packetData = c.mac.Sum(c.packetData) 540 } 541 542 c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength]) 543 544 if _, err := w.Write(c.packetData); err != nil { 545 return err 546 } 547 548 return nil 549 }