Russ Cox | 470549d | 2012-01-25 15:31:12 -0500 | [diff] [blame] | 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 | ) |
| 12 | |
| 13 | // streamDump is used to dump the initial keystream for stream ciphers. It is a |
| 14 | // a write-only buffer, and not intended for reading so do not require a mutex. |
| 15 | var streamDump [512]byte |
| 16 | |
| 17 | // noneCipher implements cipher.Stream and provides no encryption. It is used |
| 18 | // by the transport before the first key-exchange. |
| 19 | type noneCipher struct{} |
| 20 | |
| 21 | func (c noneCipher) XORKeyStream(dst, src []byte) { |
| 22 | copy(dst, src) |
| 23 | } |
| 24 | |
| 25 | func newAESCTR(key, iv []byte) (cipher.Stream, error) { |
| 26 | c, err := aes.NewCipher(key) |
| 27 | if err != nil { |
| 28 | return nil, err |
| 29 | } |
| 30 | return cipher.NewCTR(c, iv), nil |
| 31 | } |
| 32 | |
| 33 | func newRC4(key, iv []byte) (cipher.Stream, error) { |
| 34 | return rc4.NewCipher(key) |
| 35 | } |
| 36 | |
| 37 | type cipherMode struct { |
Adam Langley | 63f855d | 2012-04-20 15:17:42 -0400 | [diff] [blame] | 38 | keySize int |
| 39 | ivSize int |
| 40 | skip int |
| 41 | createFunc func(key, iv []byte) (cipher.Stream, error) |
Russ Cox | 470549d | 2012-01-25 15:31:12 -0500 | [diff] [blame] | 42 | } |
| 43 | |
| 44 | func (c *cipherMode) createCipher(key, iv []byte) (cipher.Stream, error) { |
| 45 | if len(key) < c.keySize { |
| 46 | panic("ssh: key length too small for cipher") |
| 47 | } |
| 48 | if len(iv) < c.ivSize { |
| 49 | panic("ssh: iv too small for cipher") |
| 50 | } |
| 51 | |
Adam Langley | 63f855d | 2012-04-20 15:17:42 -0400 | [diff] [blame] | 52 | stream, err := c.createFunc(key[:c.keySize], iv[:c.ivSize]) |
Russ Cox | 470549d | 2012-01-25 15:31:12 -0500 | [diff] [blame] | 53 | if err != nil { |
| 54 | return nil, err |
| 55 | } |
| 56 | |
| 57 | for remainingToDump := c.skip; remainingToDump > 0; { |
| 58 | dumpThisTime := remainingToDump |
| 59 | if dumpThisTime > len(streamDump) { |
| 60 | dumpThisTime = len(streamDump) |
| 61 | } |
| 62 | stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) |
| 63 | remainingToDump -= dumpThisTime |
| 64 | } |
| 65 | |
| 66 | return stream, nil |
| 67 | } |
| 68 | |
| 69 | // Specifies a default set of ciphers and a preference order. This is based on |
| 70 | // OpenSSH's default client preference order, minus algorithms that are not |
| 71 | // implemented. |
| 72 | var DefaultCipherOrder = []string{ |
| 73 | "aes128-ctr", "aes192-ctr", "aes256-ctr", |
| 74 | "arcfour256", "arcfour128", |
| 75 | } |
| 76 | |
Dave Cheney | 1582bf0 | 2012-10-30 18:13:59 +1100 | [diff] [blame] | 77 | // cipherModes documents properties of supported ciphers. Ciphers not included |
| 78 | // are not supported and will not be negotiated, even if explicitly requested in |
| 79 | // ClientConfig.Crypto.Ciphers. |
Russ Cox | 470549d | 2012-01-25 15:31:12 -0500 | [diff] [blame] | 80 | var cipherModes = map[string]*cipherMode{ |
| 81 | // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms |
| 82 | // are defined in the order specified in the RFC. |
| 83 | "aes128-ctr": {16, aes.BlockSize, 0, newAESCTR}, |
| 84 | "aes192-ctr": {24, aes.BlockSize, 0, newAESCTR}, |
| 85 | "aes256-ctr": {32, aes.BlockSize, 0, newAESCTR}, |
| 86 | |
| 87 | // Ciphers from RFC4345, which introduces security-improved arcfour ciphers. |
| 88 | // They are defined in the order specified in the RFC. |
| 89 | "arcfour128": {16, 0, 1536, newRC4}, |
| 90 | "arcfour256": {32, 0, 1536, newRC4}, |
| 91 | } |
Han-Wen Nienhuys | d7d50b0 | 2013-08-28 10:50:25 -0400 | [diff] [blame] | 92 | |
| 93 | // defaultKeyExchangeOrder specifies a default set of key exchange algorithms |
| 94 | // with preferences. |
| 95 | var defaultKeyExchangeOrder = []string{ |
| 96 | // P384 and P521 are not constant-time yet, but since we don't |
| 97 | // reuse ephemeral keys, using them for ECDH should be OK. |
| 98 | kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, |
| 99 | kexAlgoDH14SHA1, kexAlgoDH1SHA1, |
| 100 | } |