Class: SSL

Inherits:
Object
  • Object
show all
Defined in:
lib/ssl.rb

Overview

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 and IV 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 be base 64 encoded already

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

Constant Summary collapse

PASSWD_CHARS =
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@$%^&*()_+{}|":\;?><,./~`'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pubkey = nil, privkey = nil, passphrase = nil, ssl_cipher = "aes-256-cbc") ⇒ SSL

Returns a new instance of SSL.



35
36
37
38
39
40
41
42
43
44
# File 'lib/ssl.rb', line 35

def initialize(pubkey=nil, privkey=nil, passphrase=nil, ssl_cipher="aes-256-cbc")
    @public_key_file = pubkey
    @private_key_file = privkey

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

    raise "Unknown SSL cipher #{ssl_cipher}" unless OpenSSL::Cipher.ciphers.include?(ssl_cipher)
end

Instance Attribute Details

#private_key_fileObject (readonly)

Returns the value of attribute private_key_file.



33
34
35
# File 'lib/ssl.rb', line 33

def private_key_file
  @private_key_file
end

#public_key_fileObject (readonly)

Returns the value of attribute public_key_file.



33
34
35
# File 'lib/ssl.rb', line 33

def public_key_file
  @public_key_file
end

#ssl_cipherObject (readonly)

Returns the value of attribute ssl_cipher.



33
34
35
# File 'lib/ssl.rb', line 33

def ssl_cipher
  @ssl_cipher
end

Instance Method Details

#aes_decrypt(key, crypt_string) ⇒ Object

decrypts a string given key, iv and data



135
136
137
138
139
140
141
142
# File 'lib/ssl.rb', line 135

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) ⇒ Object

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



121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/ssl.rb', line 121

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) ⇒ Object

base 64 decode a string



150
151
152
# File 'lib/ssl.rb', line 150

def base64_decode(string)
    Base64.decode64(string)
end

#base64_encode(string) ⇒ Object

base 64 encode a string



145
146
147
# File 'lib/ssl.rb', line 145

def base64_encode(string)
    Base64.encode64(string).chomp
end

#crypt_with_private(plain_text) ⇒ Object

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

Return a hash with everything base 64 encoded



63
64
65
66
67
68
69
70
# File 'lib/ssl.rb', line 63

def crypt_with_private(plain_text)
    crypted = aes_encrypt(plain_text)

    encoded_key = base64_encode(rsa_encrypt_with_private(crypted[:key]))
    encoded_data = base64_encode(crypted[:data])

    {:key => encoded_key, :data => encoded_data}
end

#decrypt_with_private(crypted) ⇒ Object

Decrypts data, expects a hash as create with crypt_with_public



73
74
75
76
77
78
79
80
# File 'lib/ssl.rb', line 73

def decrypt_with_private(crypted)
    raise "Crypted data should include a key" unless crypted.include?(:key)
    raise "Crypted data should include data" unless crypted.include?(:data)

    key = rsa_decrypt_with_private(base64_decode(crypted[:key]))

    aes_decrypt(key, base64_decode(crypted[:data]))
end

#decrypt_with_public(crypted) ⇒ Object

Decrypts data, expects a hash as create with crypt_with_private



83
84
85
86
87
88
89
90
# File 'lib/ssl.rb', line 83

def decrypt_with_public(crypted)
    raise "Crypted data should include a key" unless crypted.include?(:key)
    raise "Crypted data should include data" unless crypted.include?(:data)

    key = rsa_decrypt_with_public(base64_decode(crypted[:key]))

    aes_decrypt(key, base64_decode(crypted[:data]))
end

#encrypt_with_public(plain_text) ⇒ Object

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

Return a hash with everything base 64 encoded



50
51
52
53
54
55
56
57
# File 'lib/ssl.rb', line 50

def encrypt_with_public(plain_text)
    crypted = aes_encrypt(plain_text)

    encoded_key = base64_encode(rsa_encrypt_with_public(crypted[:key]))
    encoded_data = base64_encode(crypted[:data])

    {:key => encoded_key, :data => encoded_data}
end

#random_string(length = 20) ⇒ Object

returns a random string made up of characters in the constant PASSWD_CHARS



155
156
157
158
159
160
161
162
163
164
165
# File 'lib/ssl.rb', line 155

def random_string(length=20)
    pw = ""

    nr_chars = PASSWD_CHARS.size

    srand()

    length.times { pw << PASSWD_CHARS[ rand( nr_chars ) ] }

    return pw
end

#read_key(type, key = nil, passphrase = nil) ⇒ Object

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



169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/ssl.rb', line 169

def read_key(type, key=nil, passphrase=nil)
    return key if key.nil?

    raise "Could not find key #{key}" unless File.exist?(key)

    if type == :public
        return OpenSSL::PKey::RSA.new(File.read(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) ⇒ Object

Use the private key to RSA decrypt data



100
101
102
103
104
# File 'lib/ssl.rb', line 100

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) ⇒ Object

Use the public key to RSA decrypt data



114
115
116
117
118
# File 'lib/ssl.rb', line 114

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) ⇒ Object

Use the private key to RSA encrypt data



107
108
109
110
111
# File 'lib/ssl.rb', line 107

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) ⇒ Object

Use the public key to RSA encrypt data



93
94
95
96
97
# File 'lib/ssl.rb', line 93

def rsa_encrypt_with_public(plain_string)
    raise "No public key set" unless @public_key

    @public_key.public_encrypt(plain_string)
end