Class: Net::SSH::Transport::CipherFactory

Inherits:
Object
  • Object
show all
Defined in:
lib/net/ssh/transport/cipher_factory.rb

Overview

Implements a factory of OpenSSL cipher algorithms.

Constant Summary collapse

SSH_TO_OSSL =

Maps the SSH name of a cipher to it’s corresponding OpenSSL name

{
  "3des-cbc" => "des-ede3-cbc",
  "blowfish-cbc" => "bf-cbc",
  "aes256-cbc" => "aes-256-cbc",
  "aes192-cbc" => "aes-192-cbc",
  "aes128-cbc" => "aes-128-cbc",
  "idea-cbc" => "idea-cbc",
  "cast128-cbc" => "cast-cbc",
  "[email protected]" => "aes-256-cbc",
  "3des-ctr" => "des-ede3",
  "blowfish-ctr" => "bf-ecb",

  "aes256-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-256-ctr") ? "aes-256-ctr" : "aes-256-ecb",
  "aes192-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-192-ctr") ? "aes-192-ctr" : "aes-192-ecb",
  "aes128-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-128-ctr") ? "aes-128-ctr" : "aes-128-ecb",
  'cast128-ctr' => 'cast5-ecb',

  'none' => 'none'
}
SSH_TO_CLASS =
if Net::SSH::Transport::ChaCha20Poly1305CipherLoader::LOADED
  {
    '[email protected]' => Net::SSH::Transport::ChaCha20Poly1305Cipher
  }
else
  {
  }
end

Class Method Summary collapse

Class Method Details

.get(name, options = {}) ⇒ Object

Retrieves a new instance of the named algorithm. The new instance will be initialized using an iv and key generated from the given iv, key, shared, hash and digester values. Additionally, the cipher will be put into encryption or decryption mode, based on the value of the encrypt parameter.



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/net/ssh/transport/cipher_factory.rb', line 60

def self.get(name, options = {})
  klass = SSH_TO_CLASS[name]
  unless klass.nil?
    key_len = klass.key_length
    key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
    return klass.new(encrypt: options[:encrypt], key: key)
  end

  ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
  return IdentityCipher if ossl_name == "none"

  cipher = OpenSSL::Cipher.new(ossl_name)

  cipher.send(options[:encrypt] ? :encrypt : :decrypt)

  cipher.padding = 0

  cipher.extend(Net::SSH::Transport::OpenSSLCipherExtensions)
  if name =~ /-ctr(@openssh.org)?$/
    if ossl_name !~ /-ctr/
      cipher.extend(Net::SSH::Transport::CTR)
    else
      cipher = Net::SSH::Transport::OpenSSLAESCTR.new(cipher)
    end
  end
  cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options)

  key_len = cipher.key_len
  cipher.key_len = key_len
  cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)

  return cipher
end

.get_lengths(name, options = {}) ⇒ Object

Returns a two-element array containing the [ key-length, block-size ] for the named cipher algorithm. If the cipher algorithm is unknown, or is “none”, 0 is returned for both elements of the tuple. if :iv_len option is supplied the third return value will be ivlen



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/net/ssh/transport/cipher_factory.rb', line 99

def self.get_lengths(name, options = {})
  klass = SSH_TO_CLASS[name]
  return [klass.key_length, klass.block_size] unless klass.nil?

  ossl_name = SSH_TO_OSSL[name]
  if ossl_name.nil? || ossl_name == "none"
    result = [0, 0]
    result << 0 if options[:iv_len]
  else
    cipher = OpenSSL::Cipher.new(ossl_name)
    key_len = cipher.key_len
    cipher.key_len = key_len

    block_size =
      case ossl_name
      when /\-ctr/
        Net::SSH::Transport::OpenSSLAESCTR.block_size
      else
        cipher.block_size
      end

    result = [key_len, block_size]
    result << cipher.iv_len if options[:iv_len]
  end
  result
end

.supported?(name) ⇒ Boolean

Returns true if the underlying OpenSSL library supports the given cipher, and false otherwise.

Returns:

  • (Boolean)


46
47
48
49
50
51
52
53
# File 'lib/net/ssh/transport/cipher_factory.rb', line 46

def self.supported?(name)
  return true if SSH_TO_CLASS.key?(name)

  ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
  return true if ossl_name == "none"

  return SSH_TO_CLASS.key?(name) || OpenSSL::Cipher.ciphers.include?(ossl_name)
end