X-Git-Url: https://review.fuel-infra.org/gitweb?a=blobdiff_plain;ds=sidebyside;f=doc%2Fclasses%2FMCollective%2FSSL.html;fp=doc%2Fclasses%2FMCollective%2FSSL.html;h=678945dba14a2a52b8f642fd9dd79a3540144c88;hb=d1f1649ba43c5cbc43c4beb2380096ba051d646a;hp=0000000000000000000000000000000000000000;hpb=8a3fe7daeecccf43dd71c59371c5005400d35101;p=packages%2Fprecise%2Fmcollective.git diff --git a/doc/classes/MCollective/SSL.html b/doc/classes/MCollective/SSL.html new file mode 100644 index 0000000..678945d --- /dev/null +++ b/doc/classes/MCollective/SSL.html @@ -0,0 +1,886 @@ + + + + +
+Class | +MCollective::SSL | +
In: | +
+
+ lib/mcollective/ssl.rb
+
+ + |
+
Parent: | ++ Object + | +
+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 +
+ +private_key_file | +[R] | ++ |
public_key_file | +[R] | ++ |
ssl_cipher | +[R] | ++ |
+ # File lib/mcollective/ssl.rb, line 195 +195: def self.base64_decode(string) +196: Base64.decode64(string) +197: end ++
+ # File lib/mcollective/ssl.rb, line 186 +186: def self.base64_encode(string) +187: Base64.encode64(string) +188: end ++
+ # File lib/mcollective/ssl.rb, line 203 +203: def self.md5(string) +204: Digest::MD5.hexdigest(string) +205: end ++
+ # File lib/mcollective/ssl.rb, line 37 +37: def initialize(pubkey=nil, privkey=nil, passphrase=nil, cipher=nil) +38: @public_key_file = pubkey +39: @private_key_file = privkey +40: +41: @public_key = read_key(:public, pubkey) +42: @private_key = read_key(:private, privkey, passphrase) +43: +44: @ssl_cipher = "aes-256-cbc" +45: @ssl_cipher = Config.instance.ssl_cipher if Config.instance.ssl_cipher +46: @ssl_cipher = cipher if cipher +47: +48: raise "The supplied cipher '#{@ssl_cipher}' is not supported" unless OpenSSL::Cipher.ciphers.include?(@ssl_cipher) +49: end ++
+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 +213: def self.uuid(string=nil) +214: string ||= OpenSSL::Random.random_bytes(16).unpack('H*').shift +215: +216: uuid_name_space_dns = "\x6b\xa7\xb8\x10\x9d\xad\x11\xd1\x80\xb4\x00\xc0\x4f\xd4\x30\xc8" +217: +218: sha1 = Digest::SHA1.new +219: sha1.update(uuid_name_space_dns) +220: sha1.update(string) +221: +222: # first 16 bytes.. +223: bytes = sha1.digest[0, 16].bytes.to_a +224: +225: # version 5 adjustments +226: bytes[6] &= 0x0f +227: bytes[6] |= 0x50 +228: +229: # variant is DCE 1.1 +230: bytes[8] &= 0x3f +231: bytes[8] |= 0x80 +232: +233: bytes = [4, 2, 2, 2, 6].collect do |i| +234: bytes.slice!(0, i).pack('C*').unpack('H*') +235: end +236: +237: bytes.join('-') +238: end ++
+decrypts a string given key, iv and data +
+ ++ # File lib/mcollective/ssl.rb, line 158 +158: def aes_decrypt(key, crypt_string) +159: cipher = OpenSSL::Cipher::Cipher.new(ssl_cipher) +160: +161: cipher.decrypt +162: cipher.key = key +163: cipher.pkcs5_keyivgen(key) +164: decrypted_data = cipher.update(crypt_string) + cipher.final +165: end ++
+encrypts a string, returns a hash of key, iv and data +
+ ++ # File lib/mcollective/ssl.rb, line 144 +144: def aes_encrypt(plain_string) +145: cipher = OpenSSL::Cipher::Cipher.new(ssl_cipher) +146: cipher.encrypt +147: +148: key = cipher.random_key +149: +150: cipher.key = key +151: cipher.pkcs5_keyivgen(key) +152: encrypted_data = cipher.update(plain_string) + cipher.final +153: +154: {:key => key, :data => encrypted_data} +155: end ++
+base 64 decode a string +
+ ++ # File lib/mcollective/ssl.rb, line 191 +191: def base64_decode(string) +192: SSL.base64_decode(string) +193: end ++
+base 64 encode a string +
+ ++ # File lib/mcollective/ssl.rb, line 182 +182: def base64_encode(string) +183: SSL.base64_encode(string) +184: end ++
+Decrypts data, expects a hash as create with crypt_with_public +
+ ++ # File lib/mcollective/ssl.rb, line 88 +88: def decrypt_with_private(crypted, base64=true) +89: raise "Crypted data should include a key" unless crypted.include?(:key) +90: raise "Crypted data should include data" unless crypted.include?(:data) +91: +92: if base64 +93: key = rsa_decrypt_with_private(base64_decode(crypted[:key])) +94: aes_decrypt(key, base64_decode(crypted[:data])) +95: else +96: key = rsa_decrypt_with_private(crypted[:key]) +97: aes_decrypt(key, crypted[:data]) +98: end +99: end ++
+Decrypts data, expects a hash as create with crypt_with_private +
+ ++ # File lib/mcollective/ssl.rb, line 102 +102: def decrypt_with_public(crypted, base64=true) +103: raise "Crypted data should include a key" unless crypted.include?(:key) +104: raise "Crypted data should include data" unless crypted.include?(:data) +105: +106: if base64 +107: key = rsa_decrypt_with_public(base64_decode(crypted[:key])) +108: aes_decrypt(key, base64_decode(crypted[:data])) +109: else +110: key = rsa_decrypt_with_public(crypted[:key]) +111: aes_decrypt(key, crypted[:data]) +112: end +113: end ++
+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 +73: def encrypt_with_private(plain_text, base64=true) +74: crypted = aes_encrypt(plain_text) +75: +76: if base64 +77: key = base64_encode(rsa_encrypt_with_private(crypted[:key])) +78: data = base64_encode(crypted[:data]) +79: else +80: key = rsa_encrypt_with_private(crypted[:key]) +81: data = crypted[:data] +82: end +83: +84: {:key => key, :data => data} +85: end ++
+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 +55: def encrypt_with_public(plain_text, base64=true) +56: crypted = aes_encrypt(plain_text) +57: +58: if base64 +59: key = base64_encode(rsa_encrypt_with_public(crypted[:key])) +60: data = base64_encode(crypted[:data]) +61: else +62: key = rsa_encrypt_with_public(crypted[:key]) +63: data = crypted[:data] +64: end +65: +66: {:key => key, :data => data} +67: end ++
+ # File lib/mcollective/ssl.rb, line 199 +199: def md5(string) +200: SSL.md5(string) +201: end ++
+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 +242: def read_key(type, key=nil, passphrase=nil) +243: return key if key.nil? +244: +245: raise "Could not find key #{key}" unless File.exist?(key) +246: raise "#{type} key file '#{key}' is empty" if File.zero?(key) +247: +248: if type == :public +249: begin +250: key = OpenSSL::PKey::RSA.new(File.read(key)) +251: rescue OpenSSL::PKey::RSAError +252: key = OpenSSL::X509::Certificate.new(File.read(key)).public_key +253: end +254: +255: # Ruby < 1.9.3 had a bug where it does not correctly clear the +256: # queue of errors while reading a key. It tries various ways +257: # to read the key and each failing attempt pushes an error onto +258: # the queue. With pubkeys only the 3rd attempt pass leaving 2 +259: # stale errors on the error queue. +260: # +261: # In 1.9.3 they fixed this by simply discarding the errors after +262: # every attempt. So we simulate this fix here for older rubies +263: # as without it we get SSL_read errors from the Stomp+TLS sessions +264: # +265: # We do this only on 1.8 relying on 1.9.3 to do the right thing +266: # and we do not support 1.9 less than 1.9.3 +267: # +268: # See http://bugs.ruby-lang.org/issues/4550 +269: OpenSSL.errors if Util.ruby_version =~ /^1.8/ +270: +271: return key +272: elsif type == :private +273: return OpenSSL::PKey::RSA.new(File.read(key), passphrase) +274: else +275: raise "Can only load :public or :private keys" +276: end +277: end ++
+Use the private key to RSA decrypt data +
+ ++ # File lib/mcollective/ssl.rb, line 123 +123: def rsa_decrypt_with_private(crypt_string) +124: raise "No private key set" unless @private_key +125: +126: @private_key.private_decrypt(crypt_string) +127: end ++
+Use the public key to RSA decrypt data +
+ ++ # File lib/mcollective/ssl.rb, line 137 +137: def rsa_decrypt_with_public(crypt_string) +138: raise "No public key set" unless @public_key +139: +140: @public_key.public_decrypt(crypt_string) +141: end ++
+Use the private key to RSA encrypt data +
+ ++ # File lib/mcollective/ssl.rb, line 130 +130: def rsa_encrypt_with_private(plain_string) +131: raise "No private key set" unless @private_key +132: +133: @private_key.private_encrypt(plain_string) +134: end ++
+Use the public key to RSA encrypt data +
+ ++ # File lib/mcollective/ssl.rb, line 116 +116: def rsa_encrypt_with_public(plain_string) +117: raise "No public key set" unless @public_key +118: +119: @public_key.public_encrypt(plain_string) +120: end ++
+Signs a string using the private key +
+ ++ # File lib/mcollective/ssl.rb, line 168 +168: def sign(string, base64=false) +169: sig = @private_key.sign(OpenSSL::Digest::SHA1.new, string) +170: +171: base64 ? base64_encode(sig) : sig +172: end ++
+Using the public key verifies that a string was signed using the private +key +
+ ++ # File lib/mcollective/ssl.rb, line 175 +175: def verify_signature(signature, string, base64=false) +176: signature = base64_decode(signature) if base64 +177: +178: @public_key.verify(OpenSSL::Digest::SHA1.new, signature, string) +179: end ++