]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/golang.org/x/crypto/ssh/cipher.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / golang.org / x / crypto / ssh / cipher.go
CommitLineData
bae9f6d2
JC
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 "io/ioutil"
19)
20
21const (
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.
38type noneCipher struct{}
39
40func (c noneCipher) XORKeyStream(dst, src []byte) {
41 copy(dst, src)
42}
43
44func 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
52func newRC4(key, iv []byte) (cipher.Stream, error) {
53 return rc4.NewCipher(key)
54}
55
56type streamCipherMode struct {
57 keySize int
58 ivSize int
59 skip int
60 createFunc func(key, iv []byte) (cipher.Stream, error)
61}
62
63func (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.
96var 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.
132const prefixLen = 5
133
134// streamPacketCipher is a packetCipher using a stream cipher.
135type 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.
149func (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
221func (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
300type gcmCipher struct {
301 aead cipher.AEAD
302 prefix [4]byte
303 iv []byte
304 buf []byte
305}
306
307func 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
324const gcmTagSize = 16
325
326func (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
360func (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
369func (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 || padding >= 20 {
396 return nil, fmt.Errorf("ssh: illegal padding %d", padding)
397 }
398
399 if int(padding+1) >= len(plain) {
400 return nil, fmt.Errorf("ssh: padding %d too large", padding)
401 }
402 plain = plain[1 : length-uint32(padding)]
403 return plain, nil
404}
405
406// cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1
407type cbcCipher struct {
408 mac hash.Hash
409 macSize uint32
410 decrypter cipher.BlockMode
411 encrypter cipher.BlockMode
412
413 // The following members are to avoid per-packet allocations.
414 seqNumBytes [4]byte
415 packetData []byte
416 macResult []byte
417
418 // Amount of data we should still read to hide which
419 // verification error triggered.
420 oracleCamouflage uint32
421}
422
423func newCBCCipher(c cipher.Block, iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
424 cbc := &cbcCipher{
425 mac: macModes[algs.MAC].new(macKey),
426 decrypter: cipher.NewCBCDecrypter(c, iv),
427 encrypter: cipher.NewCBCEncrypter(c, iv),
428 packetData: make([]byte, 1024),
429 }
430 if cbc.mac != nil {
431 cbc.macSize = uint32(cbc.mac.Size())
432 }
433
434 return cbc, nil
435}
436
437func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
438 c, err := aes.NewCipher(key)
439 if err != nil {
440 return nil, err
441 }
442
443 cbc, err := newCBCCipher(c, iv, key, macKey, algs)
444 if err != nil {
445 return nil, err
446 }
447
448 return cbc, nil
449}
450
451func newTripleDESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
452 c, err := des.NewTripleDESCipher(key)
453 if err != nil {
454 return nil, err
455 }
456
457 cbc, err := newCBCCipher(c, iv, key, macKey, algs)
458 if err != nil {
459 return nil, err
460 }
461
462 return cbc, nil
463}
464
465func maxUInt32(a, b int) uint32 {
466 if a > b {
467 return uint32(a)
468 }
469 return uint32(b)
470}
471
472const (
473 cbcMinPacketSizeMultiple = 8
474 cbcMinPacketSize = 16
475 cbcMinPaddingSize = 4
476)
477
478// cbcError represents a verification error that may leak information.
479type cbcError string
480
481func (e cbcError) Error() string { return string(e) }
482
483func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
484 p, err := c.readPacketLeaky(seqNum, r)
485 if err != nil {
486 if _, ok := err.(cbcError); ok {
487 // Verification error: read a fixed amount of
488 // data, to make distinguishing between
489 // failing MAC and failing length check more
490 // difficult.
491 io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage))
492 }
493 }
494 return p, err
495}
496
497func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
498 blockSize := c.decrypter.BlockSize()
499
500 // Read the header, which will include some of the subsequent data in the
501 // case of block ciphers - this is copied back to the payload later.
502 // How many bytes of payload/padding will be read with this first read.
503 firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize)
504 firstBlock := c.packetData[:firstBlockLength]
505 if _, err := io.ReadFull(r, firstBlock); err != nil {
506 return nil, err
507 }
508
509 c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength
510
511 c.decrypter.CryptBlocks(firstBlock, firstBlock)
512 length := binary.BigEndian.Uint32(firstBlock[:4])
513 if length > maxPacket {
514 return nil, cbcError("ssh: packet too large")
515 }
516 if length+4 < maxUInt32(cbcMinPacketSize, blockSize) {
517 // The minimum size of a packet is 16 (or the cipher block size, whichever
518 // is larger) bytes.
519 return nil, cbcError("ssh: packet too small")
520 }
521 // The length of the packet (including the length field but not the MAC) must
522 // be a multiple of the block size or 8, whichever is larger.
523 if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 {
524 return nil, cbcError("ssh: invalid packet length multiple")
525 }
526
527 paddingLength := uint32(firstBlock[4])
528 if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 {
529 return nil, cbcError("ssh: invalid packet length")
530 }
531
532 // Positions within the c.packetData buffer:
533 macStart := 4 + length
534 paddingStart := macStart - paddingLength
535
536 // Entire packet size, starting before length, ending at end of mac.
537 entirePacketSize := macStart + c.macSize
538
539 // Ensure c.packetData is large enough for the entire packet data.
540 if uint32(cap(c.packetData)) < entirePacketSize {
541 // Still need to upsize and copy, but this should be rare at runtime, only
542 // on upsizing the packetData buffer.
543 c.packetData = make([]byte, entirePacketSize)
544 copy(c.packetData, firstBlock)
545 } else {
546 c.packetData = c.packetData[:entirePacketSize]
547 }
548
549 if n, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil {
550 return nil, err
551 } else {
552 c.oracleCamouflage -= uint32(n)
553 }
554
555 remainingCrypted := c.packetData[firstBlockLength:macStart]
556 c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted)
557
558 mac := c.packetData[macStart:]
559 if c.mac != nil {
560 c.mac.Reset()
561 binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
562 c.mac.Write(c.seqNumBytes[:])
563 c.mac.Write(c.packetData[:macStart])
564 c.macResult = c.mac.Sum(c.macResult[:0])
565 if subtle.ConstantTimeCompare(c.macResult, mac) != 1 {
566 return nil, cbcError("ssh: MAC failure")
567 }
568 }
569
570 return c.packetData[prefixLen:paddingStart], nil
571}
572
573func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
574 effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize())
575
576 // Length of encrypted portion of the packet (header, payload, padding).
577 // Enforce minimum padding and packet size.
578 encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize)
579 // Enforce block size.
580 encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize
581
582 length := encLength - 4
583 paddingLength := int(length) - (1 + len(packet))
584
585 // Overall buffer contains: header, payload, padding, mac.
586 // Space for the MAC is reserved in the capacity but not the slice length.
587 bufferSize := encLength + c.macSize
588 if uint32(cap(c.packetData)) < bufferSize {
589 c.packetData = make([]byte, encLength, bufferSize)
590 } else {
591 c.packetData = c.packetData[:encLength]
592 }
593
594 p := c.packetData
595
596 // Packet header.
597 binary.BigEndian.PutUint32(p, length)
598 p = p[4:]
599 p[0] = byte(paddingLength)
600
601 // Payload.
602 p = p[1:]
603 copy(p, packet)
604
605 // Padding.
606 p = p[len(packet):]
607 if _, err := io.ReadFull(rand, p); err != nil {
608 return err
609 }
610
611 if c.mac != nil {
612 c.mac.Reset()
613 binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
614 c.mac.Write(c.seqNumBytes[:])
615 c.mac.Write(c.packetData)
616 // The MAC is now appended into the capacity reserved for it earlier.
617 c.packetData = c.mac.Sum(c.packetData)
618 }
619
620 c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength])
621
622 if _, err := w.Write(c.packetData); err != nil {
623 return err
624 }
625
626 return nil
627}