diff options
| author | Delano Mandelbaum <delano.mandelbaum@gmail.com> | 2012-01-11 03:37:55 -0800 |
|---|---|---|
| committer | Delano Mandelbaum <delano.mandelbaum@gmail.com> | 2012-01-11 03:37:55 -0800 |
| commit | 17cea0164e3c18f4fd6fa0c25f967ded8064939e (patch) | |
| tree | 6a724bb4ead5e84862f3c7f622d14717217c751b /lib | |
| parent | e0c9efa487121023b226eee5264c185965d10d90 (diff) | |
| parent | b390295736ce509b86651d003a6d06e6b2247d32 (diff) | |
| download | net-ssh-17cea0164e3c18f4fd6fa0c25f967ded8064939e.tar.gz | |
Merge pull request #30 from nappa/sha2mac
hmac-sha2 and diffie-hellman-group-exchange-sha256 support
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/net/ssh/transport/algorithms.rb | 18 | ||||
| -rw-r--r-- | lib/net/ssh/transport/cipher_factory.rb | 24 | ||||
| -rw-r--r-- | lib/net/ssh/transport/hmac.rb | 17 | ||||
| -rw-r--r-- | lib/net/ssh/transport/hmac/sha2_256.rb | 15 | ||||
| -rw-r--r-- | lib/net/ssh/transport/hmac/sha2_256_96.rb | 13 | ||||
| -rw-r--r-- | lib/net/ssh/transport/hmac/sha2_512.rb | 14 | ||||
| -rw-r--r-- | lib/net/ssh/transport/hmac/sha2_512_96.rb | 13 | ||||
| -rw-r--r-- | lib/net/ssh/transport/kex.rb | 8 | ||||
| -rw-r--r-- | lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb | 7 | ||||
| -rw-r--r-- | lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb | 15 | ||||
| -rw-r--r-- | lib/net/ssh/transport/key_expander.rb | 26 |
11 files changed, 134 insertions, 36 deletions
diff --git a/lib/net/ssh/transport/algorithms.rb b/lib/net/ssh/transport/algorithms.rb index 9c7f8d0..1c0c8ce 100644 --- a/lib/net/ssh/transport/algorithms.rb +++ b/lib/net/ssh/transport/algorithms.rb @@ -24,11 +24,14 @@ module Net; module SSH; module Transport ALGORITHMS = { :host_key => %w(ssh-rsa ssh-dss), :kex => %w(diffie-hellman-group-exchange-sha1 - diffie-hellman-group1-sha1), + diffie-hellman-group1-sha1 + diffie-hellman-group-exchange-sha256), :encryption => %w(aes128-cbc 3des-cbc blowfish-cbc cast128-cbc aes192-cbc aes256-cbc rijndael-cbc@lysator.liu.se idea-cbc none arcfour128 arcfour256), - :hmac => %w(hmac-sha1 hmac-md5 hmac-sha1-96 hmac-md5-96 none), + :hmac => %w(hmac-sha1 hmac-md5 hmac-sha1-96 hmac-md5-96 + hmac-sha2-256 hmac-sha2-512 hmac-sha2-256-96 + hmac-sha2-512-96 none), :compression => %w(none zlib@openssh.com zlib), :language => %w() } @@ -345,14 +348,13 @@ module Net; module SSH; module Transport mac_key_client = key["E"] mac_key_server = key["F"] - parameters = { :iv => iv_client, :key => key_client, :shared => secret, - :hash => hash, :digester => digester } + parameters = { :shared => secret, :hash => hash, :digester => digester } - cipher_client = CipherFactory.get(encryption_client, parameters.merge(:encrypt => true)) + cipher_client = CipherFactory.get(encryption_client, parameters.merge(:iv => iv_client, :key => key_client, :encrypt => true)) cipher_server = CipherFactory.get(encryption_server, parameters.merge(:iv => iv_server, :key => key_server, :decrypt => true)) - mac_client = HMAC.get(hmac_client, mac_key_client) - mac_server = HMAC.get(hmac_server, mac_key_server) + mac_client = HMAC.get(hmac_client, mac_key_client, parameters) + mac_server = HMAC.get(hmac_server, mac_key_server, parameters) session.configure_client :cipher => cipher_client, :hmac => mac_client, :compression => normalize_compression_name(compression_client), @@ -381,4 +383,4 @@ module Net; module SSH; module Transport end end end -end; end; end
\ No newline at end of file +end; end; end diff --git a/lib/net/ssh/transport/cipher_factory.rb b/lib/net/ssh/transport/cipher_factory.rb index ae57f2c..4a07aa2 100644 --- a/lib/net/ssh/transport/cipher_factory.rb +++ b/lib/net/ssh/transport/cipher_factory.rb @@ -1,4 +1,5 @@ require 'openssl' +require 'net/ssh/transport/key_expander' require 'net/ssh/transport/identity_cipher' module Net; module SSH; module Transport @@ -50,10 +51,10 @@ module Net; module SSH; module Transport cipher.send(options[:encrypt] ? :encrypt : :decrypt) cipher.padding = 0 - cipher.iv = make_key(cipher.iv_len, options[:iv], options) if ossl_name != "rc4" + cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options) if ossl_name != "rc4" key_len = KEY_LEN_OVERRIDE[name] || cipher.key_len cipher.key_len = key_len - cipher.key = make_key(key_len, options[:key], options) + cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options) cipher.update(" " * 1536) if ossl_name == "rc4" return cipher @@ -73,25 +74,6 @@ module Net; module SSH; module Transport return [key_len, ossl_name=="rc4" ? 8 : cipher.block_size] end - - private - - # Generate a key value in accordance with the SSH2 specification. - def self.make_key(bytes, start, options={}) - k = start[0, bytes] - - digester = options[:digester] or raise 'No digester supplied' - shared = options[:shared] or raise 'No shared secret supplied' - hash = options[:hash] or raise 'No hash supplied' - - while k.length < bytes - step = digester.digest(shared + hash + k) - bytes_needed = bytes - k.length - k << step[0, bytes_needed] - end - - return k - end end end; end; end diff --git a/lib/net/ssh/transport/hmac.rb b/lib/net/ssh/transport/hmac.rb index 262db73..8452046 100644 --- a/lib/net/ssh/transport/hmac.rb +++ b/lib/net/ssh/transport/hmac.rb @@ -1,7 +1,12 @@ +require 'net/ssh/transport/key_expander' require 'net/ssh/transport/hmac/md5' require 'net/ssh/transport/hmac/md5_96' require 'net/ssh/transport/hmac/sha1' require 'net/ssh/transport/hmac/sha1_96' +require 'net/ssh/transport/hmac/sha2_256' +require 'net/ssh/transport/hmac/sha2_256_96' +require 'net/ssh/transport/hmac/sha2_512' +require 'net/ssh/transport/hmac/sha2_512_96' require 'net/ssh/transport/hmac/none' # Implements a simple factory interface for fetching hmac implementations, or @@ -16,11 +21,17 @@ module Net::SSH::Transport::HMAC 'none' => None } + # add mapping to sha2 hmac algorithms if they're available + MAP['hmac-sha2-256'] = SHA2_256 if defined?(::Net::SSH::Transport::HMAC::SHA2_256) + MAP['hmac-sha2-256-96'] = SHA2_256_96 if defined?(::Net::SSH::Transport::HMAC::SHA2_256_96) + MAP['hmac-sha2-512'] = SHA2_512 if defined?(::Net::SSH::Transport::HMAC::SHA2_512) + MAP['hmac-sha2-512-96'] = SHA2_512_96 if defined?(::Net::SSH::Transport::HMAC::SHA2_512_96) + # Retrieves a new hmac instance of the given SSH type (+name+). If +key+ is # given, the new instance will be initialized with that key. - def self.get(name, key="") + def self.get(name, key="", parameters = {}) impl = MAP[name] or raise ArgumentError, "hmac not found: #{name.inspect}" - impl.new(key) + impl.new(Net::SSH::Transport::KeyExpander.expand_key(impl.key_length, key, parameters)) end # Retrieves the key length for the hmac of the given SSH type (+name+). @@ -28,4 +39,4 @@ module Net::SSH::Transport::HMAC impl = MAP[name] or raise ArgumentError, "hmac not found: #{name.inspect}" impl.key_length end -end
\ No newline at end of file +end diff --git a/lib/net/ssh/transport/hmac/sha2_256.rb b/lib/net/ssh/transport/hmac/sha2_256.rb new file mode 100644 index 0000000..8191a90 --- /dev/null +++ b/lib/net/ssh/transport/hmac/sha2_256.rb @@ -0,0 +1,15 @@ +require 'net/ssh/transport/hmac/abstract' + +if defined?(OpenSSL::Digest::SHA256) # need openssl support + module Net::SSH::Transport::HMAC + + # The SHA-256 HMAC algorithm. This has a mac and key length of 32, and + # uses the SHA-256 digest algorithm. + class SHA2_256 < Abstract + mac_length 32 + key_length 32 + digest_class OpenSSL::Digest::SHA256 + end + + end +end diff --git a/lib/net/ssh/transport/hmac/sha2_256_96.rb b/lib/net/ssh/transport/hmac/sha2_256_96.rb new file mode 100644 index 0000000..15e36ff --- /dev/null +++ b/lib/net/ssh/transport/hmac/sha2_256_96.rb @@ -0,0 +1,13 @@ +require 'net/ssh/transport/hmac/abstract' + +module Net::SSH::Transport::HMAC + + if defined?(SHA2_256) # need openssl support + # The SHA256-96 HMAC algorithm. This returns only the first 12 bytes of + # the digest. + class SHA2_256_96 < SHA2_256 + mac_length 12 + end + end + +end diff --git a/lib/net/ssh/transport/hmac/sha2_512.rb b/lib/net/ssh/transport/hmac/sha2_512.rb new file mode 100644 index 0000000..e68df19 --- /dev/null +++ b/lib/net/ssh/transport/hmac/sha2_512.rb @@ -0,0 +1,14 @@ +require 'net/ssh/transport/hmac/abstract' + +module Net::SSH::Transport::HMAC + + if defined?(OpenSSL::Digest::SHA512) # need openssl support + # The SHA-512 HMAC algorithm. This has a mac and key length of 64, and + # uses the SHA-512 digest algorithm. + class SHA2_512 < Abstract + mac_length 64 + key_length 64 + digest_class OpenSSL::Digest::SHA512 + end + end +end diff --git a/lib/net/ssh/transport/hmac/sha2_512_96.rb b/lib/net/ssh/transport/hmac/sha2_512_96.rb new file mode 100644 index 0000000..5cc7aed --- /dev/null +++ b/lib/net/ssh/transport/hmac/sha2_512_96.rb @@ -0,0 +1,13 @@ +require 'net/ssh/transport/hmac/abstract' + +module Net::SSH::Transport::HMAC + + if defined?(SHA2_512) # need openssl support + # The SHA2-512-96 HMAC algorithm. This returns only the first 12 bytes of + # the digest. + class SHA2_512_96 < SHA2_512 + mac_length 12 + end + end + +end diff --git a/lib/net/ssh/transport/kex.rb b/lib/net/ssh/transport/kex.rb index 29123c3..79a46a1 100644 --- a/lib/net/ssh/transport/kex.rb +++ b/lib/net/ssh/transport/kex.rb @@ -1,5 +1,6 @@ require 'net/ssh/transport/kex/diffie_hellman_group1_sha1' require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1' +require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha256' module Net::SSH::Transport module Kex @@ -7,7 +8,10 @@ module Net::SSH::Transport # to their corresponding implementors. MAP = { 'diffie-hellman-group-exchange-sha1' => DiffieHellmanGroupExchangeSHA1, - 'diffie-hellman-group1-sha1' => DiffieHellmanGroup1SHA1 + 'diffie-hellman-group1-sha1' => DiffieHellmanGroup1SHA1, } + if defined?(DiffieHellmanGroupExchangeSHA256) + MAP['diffie-hellman-group-exchange-sha256'] = DiffieHellmanGroupExchangeSHA256 + end end -end
\ No newline at end of file +end diff --git a/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb b/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb index da47ec2..8fb69e8 100644 --- a/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +++ b/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb @@ -19,7 +19,10 @@ module Net::SSH::Transport::Kex # Compute the number of bits needed for the given number of bytes. def compute_need_bits - need_bits = data[:need_bytes] * 8 + + # for Compatibility: OpenSSH requires (need_bits * 2 + 1) length of parameter + need_bits = data[:need_bytes] * 8 * 2 + 1 + if need_bits < MINIMUM_BITS need_bits = MINIMUM_BITS elsif need_bits > MAXIMUM_BITS @@ -74,4 +77,4 @@ module Net::SSH::Transport::Kex end end -end
\ No newline at end of file +end diff --git a/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb b/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb new file mode 100644 index 0000000..656254c --- /dev/null +++ b/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb @@ -0,0 +1,15 @@ +require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1' + +module Net::SSH::Transport::Kex + if defined?(OpenSSL::Digest::SHA256) + # A key-exchange service implementing the + # "diffie-hellman-group-exchange-sha256" key-exchange algorithm. + class DiffieHellmanGroupExchangeSHA256 < DiffieHellmanGroupExchangeSHA1 + def initialize(*args) + super(*args) + + @digester = OpenSSL::Digest::SHA256 + end + end + end +end diff --git a/lib/net/ssh/transport/key_expander.rb b/lib/net/ssh/transport/key_expander.rb new file mode 100644 index 0000000..86e608d --- /dev/null +++ b/lib/net/ssh/transport/key_expander.rb @@ -0,0 +1,26 @@ +module Net; module SSH; module Transport + module KeyExpander + + # Generate a key value in accordance with the SSH2 specification. + # (RFC4253 7.2. "Output from Key Exchange") + def self.expand_key(bytes, start, options={}) + if bytes == 0 + return "" + end + + k = start[0, bytes] + + digester = options[:digester] or raise 'No digester supplied' + shared = options[:shared] or raise 'No shared secret supplied' + hash = options[:hash] or raise 'No hash supplied' + + while k.length < bytes + step = digester.digest(shared + hash + k) + bytes_needed = bytes - k.length + k << step[0, bytes_needed] + end + + return k + end +end +end; end; end |
