Module: EncryptedStrings::Extensions::String

Defined in:
lib/encrypted_strings/extensions/string.rb

Overview

Adds support for in-place encryption/decryption of strings

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

:nodoc:


5
6
7
8
9
10
11
12
# File 'lib/encrypted_strings/extensions/string.rb', line 5

def self.included(base) #:nodoc:
  base.class_eval do
    attr_accessor :cipher
    
    alias_method :equals_without_encryption, :==
    alias_method :==, :equals_with_encryption
  end
end

Instance Method Details

#can_decrypt?Boolean

Can this string be decrypted? Strings can only be decrypted if they have previously been decrypted and the cipher supports decryption. To determine whether or not the cipher supports decryption, see the api for the cipher.

Returns:

  • (Boolean)

126
127
128
# File 'lib/encrypted_strings/extensions/string.rb', line 126

def can_decrypt?
  encrypted? && cipher.can_decrypt?
end

#decrypt(*args) ⇒ Object

Decrypts this string. If this is not a string that was previously encrypted, the cipher must be specified in the same way that it is when encrypting a string.

Example

Without being previously encrypted:

password = "qSg8vOo6QfU=\n"
password.decrypt(:symmetric, :password => 'secret')   # => "shhhh"

After being previously encrypted:

password = 'shhhh'
password.encrypt!(:symmetric, :password => 'secret')  # => "qSg8vOo6QfU=\n"
password.decrypt                                      # => "shhhh"

Raises:

  • (ArgumentError)

97
98
99
100
101
102
103
104
105
# File 'lib/encrypted_strings/extensions/string.rb', line 97

def decrypt(*args)
  raise ArgumentError, 'Cipher cannot be inferred: must specify it as an argument' if args.empty? && !encrypted?
  
  cipher = args.empty? && self.cipher || cipher_from_args(*args)
  encrypted_string = cipher.decrypt(self)
  encrypted_string.cipher = nil
  
  encrypted_string
end

#decrypt!(*args) ⇒ Object

Decrypts this string and replaces it with the decrypted value This takes the same parameters as #decrypt, but returns the same string instead of a different one.

For example,

password = "qSg8vOo6QfU=\n"
password.decrypt!(:symmetric, :password => 'secret')  # => "shhhh"
password                                              # => "shhhh"

116
117
118
119
120
# File 'lib/encrypted_strings/extensions/string.rb', line 116

def decrypt!(*args)
  value = replace(decrypt(*args))
  self.cipher = nil
  value
end

#encrypt(*args) ⇒ Object

Encrypts the current string using the specified cipher. The default cipher is sha.

Configuration options are cipher-specific. See each individual cipher class to find out the options available.

Example

The following uses an SHA cipher to encrypt the string:

password = 'shhhh'
password.encrypt  # => "66c85d26dadde7e1db27e15a0776c921e27143bd"

Custom encryption mode

The following uses Symmetric cipher (with a default password) to encrypt the string:

EncryptedStrings::SymmetricCipher.default_password = 'secret'
password = 'shhhh'
password.encrypt(:symmetric)  # => "jDACXI5hMPI=\n"

Custom encryption options

Some encryption modes also support additional configuration options that determine how to encrypt the string. For example, SHA supports a salt which seeds the algorithm:

password = 'shhhh'
password.encrypt(:sha, :salt => 'secret') # => "3b22cbe4acde873c3efc82681096f3ae69aff828"

44
45
46
47
48
49
50
# File 'lib/encrypted_strings/extensions/string.rb', line 44

def encrypt(*args)
  cipher = cipher_from_args(*args)
  encrypted_string = cipher.encrypt(self)
  encrypted_string.cipher = cipher
  
  encrypted_string
end

#encrypt!(*args) ⇒ Object

Encrypts this string and replaces it with the encrypted value. This takes the same parameters as #encrypt, but returns the same string instead of a different one.

Example

password = 'shhhh'
password.encrypt!(:symmetric, :password => 'secret')  # => "qSg8vOo6QfU=\n"
password                                              # => "qSg8vOo6QfU=\n"

61
62
63
64
65
66
# File 'lib/encrypted_strings/extensions/string.rb', line 61

def encrypt!(*args)
  encrypted_string = encrypt(*args)
  self.cipher = encrypted_string.cipher
  
  replace(encrypted_string)
end

#encrypted?Boolean

Is this string encrypted? This will return true if the string is the result of a call to #encrypt or #encrypt!.

Example

password = 'shhhh'
password.encrypted? # => false
password.encrypt!   # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
password.encrypted? # => true

Returns:

  • (Boolean)

77
78
79
# File 'lib/encrypted_strings/extensions/string.rb', line 77

def encrypted?
  !cipher.nil?
end

#equals_with_encryption(other) ⇒ Object

Tests whether the other object is equal to this one. Encrypted strings will be tested not only on their encrypted strings, but also by decrypting them and running tests against the decrypted value.

Equality with strings

password = 'shhhh'
password.encrypt!   # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
password            # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
password == "shhhh" # => true

Equality with encrypted strings

password = 'shhhh'
password.encrypt!             # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
password                      # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
password == 'shhhh'           # => true

another_password = 'shhhh'
another_password.encrypt!     # => "66c85d26dadde7e1db27e15a0776c921e27143bd"
password == another_password  # => true

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/encrypted_strings/extensions/string.rb', line 151

def equals_with_encryption(other)
  if !(is_equal = equals_without_encryption(other)) && String === other
    if encrypted?
      if other.encrypted?
        # We're both encrypted, so check if:
        # (1) The other string is the encrypted value of this string
        # (2) This string is the encrypted value of the other string
        # (3) The other string is the encrypted value of this string, decrypted
        # (4) This string is the encrypted value of the other string, decrypted
        is_string_equal?(self, other) || is_string_equal?(other, self) || self.can_decrypt? && is_string_equal?(self.decrypt, other) || other.can_decrypt? && is_string_equal?(other.decrypt, self)
      else
        # Only we're encrypted
        is_string_equal?(other, self)
      end
    else
      if other.encrypted?
        # Only the other string is encrypted
        is_string_equal?(self, other)
      else
        # Neither are encrypted and equality test didn't work before, so
        # they can't be equal
        false
      end
    end
  else
    # The other value wasn't a string, so we can't check encryption equality
    is_equal
  end
end