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