diff options
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh/cipher.go')
-rw-r--r-- | vendor/golang.org/x/crypto/ssh/cipher.go | 627 |
1 files changed, 0 insertions, 627 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go deleted file mode 100644 index 13484ab..0000000 --- a/vendor/golang.org/x/crypto/ssh/cipher.go +++ /dev/null | |||
@@ -1,627 +0,0 @@ | |||
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 || 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 | ||
407 | type 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 | |||
423 | func 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 | |||
437 | func 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 | |||
451 | func 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 | |||
465 | func maxUInt32(a, b int) uint32 { | ||
466 | if a > b { | ||
467 | return uint32(a) | ||
468 | } | ||
469 | return uint32(b) | ||
470 | } | ||
471 | |||
472 | const ( | ||
473 | cbcMinPacketSizeMultiple = 8 | ||
474 | cbcMinPacketSize = 16 | ||
475 | cbcMinPaddingSize = 4 | ||
476 | ) | ||
477 | |||
478 | // cbcError represents a verification error that may leak information. | ||
479 | type cbcError string | ||
480 | |||
481 | func (e cbcError) Error() string { return string(e) } | ||
482 | |||
483 | func (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 | |||
497 | func (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 | |||
573 | func (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 | } | ||