Parent

Class/Module Index [+]

Quicksearch

MCollective::SSL

A class that assists in encrypting and decrypting data using a combination of RSA and AES

Data will be AES encrypted for speed, the Key used in # the AES stage will be encrypted using RSA

ssl = SSL.new(public_key, private_key, passphrase)

data = File.read("largefile.dat")

crypted_data = ssl.encrypt_with_private(data)

pp crypted_data

This will result in a hash of data like:

crypted = {:key  => "crd4NHvG....=",
           :data => "XWXlqN+i...=="}

The key and data will all be base 64 encoded already by default you can pass a 2nd parameter as false to encrypt_with_private and counterparts that will prevent the base 64 encoding

You can pass the data hash into ssl.decrypt_with_public which should return your original data

There are matching methods for using a public key to encrypt data to be decrypted using a private key

Attributes

private_key_file[R]
public_key_file[R]
ssl_cipher[R]

Public Class Methods

base64_decode(string) click to toggle source
# File lib/mcollective/ssl.rb, line 195
def self.base64_decode(string)
  Base64.decode64(string)
end
base64_encode(string) click to toggle source
# File lib/mcollective/ssl.rb, line 186
def self.base64_encode(string)
  Base64.encode64(string)
end
md5(string) click to toggle source
# File lib/mcollective/ssl.rb, line 203
def self.md5(string)
  Digest::MD5.hexdigest(string)
end
new(pubkey=nil, privkey=nil, passphrase=nil, cipher=nil) click to toggle source
# File lib/mcollective/ssl.rb, line 37
def initialize(pubkey=nil, privkey=nil, passphrase=nil, cipher=nil)
  @public_key_file = pubkey
  @private_key_file = privkey

  @public_key  = read_key(:public, pubkey)
  @private_key = read_key(:private, privkey, passphrase)

  @ssl_cipher = "aes-256-cbc"
  @ssl_cipher = Config.instance.ssl_cipher if Config.instance.ssl_cipher
  @ssl_cipher = cipher if cipher

  raise "The supplied cipher '#{@ssl_cipher}' is not supported" unless OpenSSL::Cipher.ciphers.include?(@ssl_cipher)
end
uuid(string=nil) click to toggle source

Creates a RFC 4122 version 5 UUID. If string is supplied it will produce repeatable UUIDs for that string else a random 128bit string will be used from OpenSSL::BN

Code used with permission from:

https://github.com/kwilczynski/puppet-functions/blob/master/lib/puppet/parser/functions/uuid.rb
# File lib/mcollective/ssl.rb, line 213
def self.uuid(string=nil)
  string ||= OpenSSL::Random.random_bytes(16).unpack('H*').shift

  uuid_name_space_dns = "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8"

  sha1 = Digest::SHA1.new
  sha1.update(uuid_name_space_dns)
  sha1.update(string)

  # first 16 bytes..
  bytes = sha1.digest[0, 16].bytes.to_a

  # version 5 adjustments
  bytes[6] &= 0x0f
  bytes[6] |= 0x50

  # variant is DCE 1.1
  bytes[8] &= 0x3f
  bytes[8] |= 0x80

  bytes = [4, 2, 2, 2, 6].collect do |i|
    bytes.slice!(0, i).pack('C*').unpack('H*')
  end

  bytes.join('-')
end

Public Instance Methods

aes_decrypt(key, crypt_string) click to toggle source

decrypts a string given key, iv and data

# File lib/mcollective/ssl.rb, line 158
def aes_decrypt(key, crypt_string)
  cipher = OpenSSL::Cipher::Cipher.new(ssl_cipher)

  cipher.decrypt
  cipher.key = key
  cipher.pkcs5_keyivgen(key)
  decrypted_data = cipher.update(crypt_string) + cipher.final
end
aes_encrypt(plain_string) click to toggle source

encrypts a string, returns a hash of key, iv and data

# File lib/mcollective/ssl.rb, line 144
def aes_encrypt(plain_string)
  cipher = OpenSSL::Cipher::Cipher.new(ssl_cipher)
  cipher.encrypt

  key = cipher.random_key

  cipher.key = key
  cipher.pkcs5_keyivgen(key)
  encrypted_data = cipher.update(plain_string) + cipher.final

  {:key => key, :data => encrypted_data}
end
base64_decode(string) click to toggle source

base 64 decode a string

# File lib/mcollective/ssl.rb, line 191
def base64_decode(string)
  SSL.base64_decode(string)
end
base64_encode(string) click to toggle source

base 64 encode a string

# File lib/mcollective/ssl.rb, line 182
def base64_encode(string)
  SSL.base64_encode(string)
end
decrypt_with_private(crypted, base64=true) click to toggle source

Decrypts data, expects a hash as create with crypt_with_public

# File lib/mcollective/ssl.rb, line 88
def decrypt_with_private(crypted, base64=true)
  raise "Crypted data should include a key" unless crypted.include?(:key)
  raise "Crypted data should include data" unless crypted.include?(:data)

  if base64
    key = rsa_decrypt_with_private(base64_decode(crypted[:key]))
    aes_decrypt(key, base64_decode(crypted[:data]))
  else
    key = rsa_decrypt_with_private(crypted[:key])
    aes_decrypt(key, crypted[:data])
  end
end
decrypt_with_public(crypted, base64=true) click to toggle source

Decrypts data, expects a hash as create with crypt_with_private

# File lib/mcollective/ssl.rb, line 102
def decrypt_with_public(crypted, base64=true)
  raise "Crypted data should include a key" unless crypted.include?(:key)
  raise "Crypted data should include data" unless crypted.include?(:data)

  if base64
    key = rsa_decrypt_with_public(base64_decode(crypted[:key]))
    aes_decrypt(key, base64_decode(crypted[:data]))
  else
    key = rsa_decrypt_with_public(crypted[:key])
    aes_decrypt(key, crypted[:data])
  end
end
encrypt_with_private(plain_text, base64=true) click to toggle source

Encrypts supplied data using AES and then encrypts using RSA the key and IV

Return a hash with everything optionally base 64 encoded

# File lib/mcollective/ssl.rb, line 73
def encrypt_with_private(plain_text, base64=true)
  crypted = aes_encrypt(plain_text)

  if base64
    key = base64_encode(rsa_encrypt_with_private(crypted[:key]))
    data = base64_encode(crypted[:data])
  else
    key = rsa_encrypt_with_private(crypted[:key])
    data = crypted[:data]
  end

  {:key => key, :data => data}
end
encrypt_with_public(plain_text, base64=true) click to toggle source

Encrypts supplied data using AES and then encrypts using RSA the key and IV

Return a hash with everything optionally base 64 encoded

# File lib/mcollective/ssl.rb, line 55
def encrypt_with_public(plain_text, base64=true)
  crypted = aes_encrypt(plain_text)

  if base64
    key = base64_encode(rsa_encrypt_with_public(crypted[:key]))
    data = base64_encode(crypted[:data])
  else
    key = rsa_encrypt_with_public(crypted[:key])
    data = crypted[:data]
  end

  {:key => key, :data => data}
end
md5(string) click to toggle source
# File lib/mcollective/ssl.rb, line 199
def md5(string)
  SSL.md5(string)
end
read_key(type, key=nil, passphrase=nil) click to toggle source

Reads either a :public or :private key from disk, uses an optional passphrase to read the private key

# File lib/mcollective/ssl.rb, line 242
def read_key(type, key=nil, passphrase=nil)
  return key if key.nil?

  raise "Could not find key #{key}" unless File.exist?(key)
  raise "#{type} key file '#{key}' is empty" if File.zero?(key)

  if type == :public
    begin
      key = OpenSSL::PKey::RSA.new(File.read(key))
    rescue OpenSSL::PKey::RSAError
      key = OpenSSL::X509::Certificate.new(File.read(key)).public_key
    end

    # Ruby < 1.9.3 had a bug where it does not correctly clear the
    # queue of errors while reading a key.  It tries various ways
    # to read the key and each failing attempt pushes an error onto
    # the queue.  With pubkeys only the 3rd attempt pass leaving 2
    # stale errors on the error queue.
    #
    # In 1.9.3 they fixed this by simply discarding the errors after
    # every attempt.  So we simulate this fix here for older rubies
    # as without it we get SSL_read errors from the Stomp+TLS sessions
    #
    # We do this only on 1.8 relying on 1.9.3 to do the right thing
    # and we do not support 1.9 less than 1.9.3
    #
    # See  http://bugs.ruby-lang.org/issues/4550
    OpenSSL.errors if Util.ruby_version =~ /^1.8/

    return key
  elsif type == :private
    return OpenSSL::PKey::RSA.new(File.read(key), passphrase)
  else
    raise "Can only load :public or :private keys"
  end
end
rsa_decrypt_with_private(crypt_string) click to toggle source

Use the private key to RSA decrypt data

# File lib/mcollective/ssl.rb, line 123
def rsa_decrypt_with_private(crypt_string)
  raise "No private key set" unless @private_key

  @private_key.private_decrypt(crypt_string)
end
rsa_decrypt_with_public(crypt_string) click to toggle source

Use the public key to RSA decrypt data

# File lib/mcollective/ssl.rb, line 137
def rsa_decrypt_with_public(crypt_string)
  raise "No public key set" unless @public_key

  @public_key.public_decrypt(crypt_string)
end
rsa_encrypt_with_private(plain_string) click to toggle source

Use the private key to RSA encrypt data

# File lib/mcollective/ssl.rb, line 130
def rsa_encrypt_with_private(plain_string)
  raise "No private key set" unless @private_key

  @private_key.private_encrypt(plain_string)
end
rsa_encrypt_with_public(plain_string) click to toggle source

Use the public key to RSA encrypt data

# File lib/mcollective/ssl.rb, line 116
def rsa_encrypt_with_public(plain_string)
  raise "No public key set" unless @public_key

  @public_key.public_encrypt(plain_string)
end
sign(string, base64=false) click to toggle source

Signs a string using the private key

# File lib/mcollective/ssl.rb, line 168
def sign(string, base64=false)
  sig = @private_key.sign(OpenSSL::Digest::SHA1.new, string)

  base64 ? base64_encode(sig) : sig
end
verify_signature(signature, string, base64=false) click to toggle source

Using the public key verifies that a string was signed using the private key

# File lib/mcollective/ssl.rb, line 175
def verify_signature(signature, string, base64=false)
  signature = base64_decode(signature) if base64

  @public_key.verify(OpenSSL::Digest::SHA1.new, signature, string)
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.