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