Module: SymmetricEncryption
- Defined in:
- lib/symmetric_encryption/railtie.rb,
lib/symmetric_encryption/cipher.rb,
lib/symmetric_encryption/reader.rb,
lib/symmetric_encryption/writer.rb,
lib/symmetric_encryption/version.rb,
lib/symmetric_encryption/symmetric_encryption.rb
Overview
Encrypt using 256 Bit AES CBC symmetric key and initialization vector The symmetric key is protected using the private key below and must be distributed separately from the application
Defined Under Namespace
Classes: Cipher, Railtie, Reader, Writer
Constant Summary collapse
- VERSION =
"0.7.1"
- MAGIC_HEADER =
'@EnC'
- MAGIC_HEADER_SIZE =
MAGIC_HEADER.size
- MAGIC_HEADER_UNPACK =
"a#{MAGIC_HEADER_SIZE}v"
- @@cipher =
Defaults
nil
- @@secondary_ciphers =
[]
Class Method Summary collapse
-
.cipher(version = 0) ⇒ Object
Returns the Primary Symmetric Cipher being used If a version is supplied, then the cipher matching that version will be returned or nil if no match was found.
-
.cipher=(cipher) ⇒ Object
Set the Primary Symmetric Cipher to be used.
-
.decrypt(str) ⇒ Object
AES Symmetric Decryption of supplied string Returns decrypted string Returns nil if the supplied str is nil Returns “” if it is a string and it is empty.
-
.encrypt(str) ⇒ Object
AES Symmetric Encryption of supplied string Returns result as a Base64 encoded string Returns nil if the supplied str is nil Returns “” if it is a string and it is empty.
-
.encrypted?(encrypted_data) ⇒ Boolean
Returns [true|false] as to whether the data could be decrypted Parameters: encrypted_data: Encrypted string.
-
.generate_symmetric_key_files(filename = nil, environment = nil) ⇒ Object
Generate new random symmetric keys for use with this Encryption library.
-
.load!(filename = nil, environment = nil) ⇒ Object
Load the Encryption Configuration from a YAML file filename: Name of file to read.
-
.random_password ⇒ Object
Generate a 22 character random password.
-
.secondary_ciphers ⇒ Object
Returns the Primary Symmetric Cipher being used.
-
.secondary_ciphers=(secondary_ciphers) ⇒ Object
Set the Secondary Symmetric Ciphers Array to be used.
-
.try_decrypt(str) ⇒ Object
Invokes decrypt Returns decrypted String Return nil if it fails to decrypt a String.
Class Method Details
.cipher(version = 0) ⇒ Object
Returns the Primary Symmetric Cipher being used If a version is supplied, then the cipher matching that version will be returned or nil if no match was found
32 33 34 35 36 |
# File 'lib/symmetric_encryption/symmetric_encryption.rb', line 32 def self.cipher(version = 0) raise "Call SymmetricEncryption.load! or SymmetricEncryption.cipher= prior to encrypting or decrypting data" unless @@cipher return @@cipher if version.nil? || (version == 0) || (@@cipher.version == version) secondary_ciphers.find {|c| c.version == version} end |
.cipher=(cipher) ⇒ Object
Set the Primary Symmetric Cipher to be used
Example: For testing purposes the following test cipher can be used:
SymmetricEncryption.cipher = SymmetricEncryption::Cipher.new(
:key => '1234567890ABCDEF1234567890ABCDEF',
:iv => '1234567890ABCDEF',
:cipher => 'aes-128-cbc'
)
24 25 26 27 |
# File 'lib/symmetric_encryption/symmetric_encryption.rb', line 24 def self.cipher=(cipher) raise "Cipher must be similar to SymmetricEncryption::Ciphers" unless cipher.respond_to?(:encrypt) && cipher.respond_to?(:decrypt) @@cipher = cipher end |
.decrypt(str) ⇒ Object
AES Symmetric Decryption of supplied string
Returns decrypted string
Returns nil if the supplied str is nil
Returns "" if it is a string and it is empty
Note: If secondary ciphers are supplied in the configuration file the
first key will be used to decrypt 'str'. If it fails each cipher in the
order supplied will be tried.
It is slow to try each cipher in turn, so should be used during migrations
only
Raises: OpenSSL::Cipher::CipherError when ‘str’ was not encrypted using the supplied key and iv
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/symmetric_encryption/symmetric_encryption.rb', line 66 def self.decrypt(str) raise "Call SymmetricEncryption.load! or SymmetricEncryption.cipher= prior to encrypting or decrypting data" unless @@cipher binary = ::Base64.decode64(str) if str begin @@cipher.decrypt(binary) rescue OpenSSL::Cipher::CipherError => exc @@secondary_ciphers.each do |cipher| begin return cipher.decrypt(binary) rescue OpenSSL::Cipher::CipherError end end raise exc end end |
.encrypt(str) ⇒ Object
AES Symmetric Encryption of supplied string
Returns result as a Base64 encoded string
Returns nil if the supplied str is nil
Returns "" if it is a string and it is empty
86 87 88 89 90 91 92 93 94 95 |
# File 'lib/symmetric_encryption/symmetric_encryption.rb', line 86 def self.encrypt(str) raise "Call SymmetricEncryption.load! or SymmetricEncryption.cipher= prior to encrypting or decrypting data" unless @@cipher # Encrypt data as a binary string result = @@cipher.encrypt(str) # Base 64 Encoding of binary data result = ::Base64.encode64(result) if result result end |
.encrypted?(encrypted_data) ⇒ Boolean
Returns [true|false] as to whether the data could be decrypted
Parameters:
encrypted_data: Encrypted string
117 118 119 120 121 122 123 124 125 |
# File 'lib/symmetric_encryption/symmetric_encryption.rb', line 117 def self.encrypted?(encrypted_data) raise "Call SymmetricEncryption.load! or SymmetricEncryption.cipher= prior to encrypting or decrypting data" unless @@cipher # First make sure Base64 encoded data still ends with "\n" since it could be used in a key field somewhere return false unless encrypted_data.end_with?("\n") # For now have to decrypt it fully !try_decrypt(encrypted_data).nil? end |
.generate_symmetric_key_files(filename = nil, environment = nil) ⇒ Object
Generate new random symmetric keys for use with this Encryption library
Note: Only the current Encryption key settings are used
Creates Symmetric Key .key
and initilization vector .iv
which is encrypted with the above Public key
Warning: Existing files will be overwritten
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/symmetric_encryption/symmetric_encryption.rb', line 168 def self.generate_symmetric_key_files(filename=nil, environment=nil) config = read_config(filename, environment) cipher_cfg = config[:ciphers].first key_filename = cipher_cfg[:key_filename] iv_filename = cipher_cfg[:iv_filename] cipher = cipher_cfg[:cipher] raise "The configuration file must contain a 'private_rsa_key' parameter to generate symmetric keys" unless config[:private_rsa_key] rsa_key = OpenSSL::PKey::RSA.new(config[:private_rsa_key]) # Generate a new Symmetric Key pair key_pair = SymmetricEncryption::Cipher.random_key_pair(cipher || 'aes-256-cbc', !iv_filename.nil?) # Save symmetric key after encrypting it with the private RSA key, backing up existing files if present File.rename(key_filename, "#{key_filename}.#{Time.now.to_i}") if File.exist?(key_filename) File.open(key_filename, 'wb') {|file| file.write( rsa_key.public_encrypt(key_pair[:key]) ) } if iv_filename File.rename(iv_filename, "#{iv_filename}.#{Time.now.to_i}") if File.exist?(iv_filename) File.open(iv_filename, 'wb') {|file| file.write( rsa_key.public_encrypt(key_pair[:iv]) ) } end puts("Generated new Symmetric Key for encryption. Please copy #{key_filename} and #{iv_filename} to the other web servers in #{environment}.") end |
.load!(filename = nil, environment = nil) ⇒ Object
Load the Encryption Configuration from a YAML file
filename:
Name of file to read.
Mandatory for non-Rails apps
Default: Rails.root/config/symmetric-encryption.yml
environment:
Which environments config to load. Usually: production, development, etc.
Default: Rails.env
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/symmetric_encryption/symmetric_encryption.rb', line 135 def self.load!(filename=nil, environment=nil) config = read_config(filename, environment) # Check for hard coded key, iv and cipher if config[:key] @@cipher = Cipher.new(config) @@secondary_ciphers = [] else private_rsa_key = config[:private_rsa_key] @@cipher, *@@secondary_ciphers = config[:ciphers].collect do |cipher_conf| cipher_from_encrypted_files( private_rsa_key, cipher_conf[:cipher], cipher_conf[:key_filename], cipher_conf[:iv_filename]) end end true end |
.random_password ⇒ Object
Generate a 22 character random password
193 194 195 |
# File 'lib/symmetric_encryption/symmetric_encryption.rb', line 193 def self.random_password Base64.encode64(OpenSSL::Cipher.new('aes-128-cbc').random_key)[0..-4] end |
.secondary_ciphers ⇒ Object
Returns the Primary Symmetric Cipher being used
48 49 50 |
# File 'lib/symmetric_encryption/symmetric_encryption.rb', line 48 def self.secondary_ciphers @@secondary_ciphers end |
.secondary_ciphers=(secondary_ciphers) ⇒ Object
Set the Secondary Symmetric Ciphers Array to be used
39 40 41 42 43 44 45 |
# File 'lib/symmetric_encryption/symmetric_encryption.rb', line 39 def self.secondary_ciphers=(secondary_ciphers) raise "secondary_ciphers must be a collection" unless secondary_ciphers.respond_to? :each secondary_ciphers.each do |cipher| raise "secondary_ciphers can only consist of SymmetricEncryption::Ciphers" unless cipher.respond_to?(:encrypt) && cipher.respond_to?(:decrypt) end @@secondary_ciphers = secondary_ciphers end |
.try_decrypt(str) ⇒ Object
Invokes decrypt
Returns decrypted String
Return nil if it fails to decrypt a String
Useful for example when decoding passwords encrypted using a key from a different environment. I.e. We cannot decode production passwords in the test or development environments but still need to be able to load YAML config files that contain encrypted development and production passwords
105 106 107 108 109 110 111 112 |
# File 'lib/symmetric_encryption/symmetric_encryption.rb', line 105 def self.try_decrypt(str) raise "Call SymmetricEncryption.load! or SymmetricEncryption.cipher= prior to encrypting or decrypting data" unless @@cipher begin decrypt(str) rescue OpenSSL::Cipher::CipherError nil end end |