Class: Strongbox::Lock

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

Overview

The Lock class encrypts and decrypts the protected attribute. It automatically encrypts the data when set and decrypts it when the private key password is provided.

Instance Method Summary collapse

Constructor Details

#initialize(name, instance, options = {}) ⇒ Lock

Returns a new instance of Lock.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/strongbox/lock.rb', line 7

def initialize name, instance, options = {}
  @name              = name
  @instance          = instance

  @size = 0

  options = Strongbox.options.merge(options)

  @base64 = options[:base64]
  @public_key = options[:public_key] || options[:key_pair]
  @private_key = options[:private_key] || options[:key_pair]
  @padding = options[:padding]
  @symmetric = options[:symmetric]
  @symmetric_cipher = options[:symmetric_cipher]
  @symmetric_key = options[:symmetric_key] || "#{name}_key"
  @symmetric_iv = options[:symmetric_iv] || "#{name}_iv"
  @ensure_required_columns = options[:ensure_required_columns]
end

Instance Method Details

#blank?Boolean

Needed for validations

Returns:

  • (Boolean)


108
109
110
# File 'lib/strongbox/lock.rb', line 108

def blank?
  @instance[@name].blank?
end

#decrypt(password = nil, ciphertext = nil) ⇒ Object

Given the private key password decrypts the attribute. Will raise OpenSSL::PKey::RSAError if the password is wrong.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/strongbox/lock.rb', line 63

def decrypt password = nil, ciphertext = nil
  # Given a private key and a nil password OpenSSL::PKey::RSA.new() will
  # *prompt* for a password, we default to an empty string to avoid that.
  ciphertext ||= @instance[@name]
  return nil if ciphertext.nil?
  return "" if ciphertext.empty?

  return "*encrypted*" if password.nil?
  unless @private_key
    raise StrongboxError.new("#{@instance.class} model does not have private key_file")
  end

  if ciphertext
    ciphertext = Base64.decode64(ciphertext) if @base64
    private_key = get_rsa_key(@private_key,password)
    if @symmetric == :always
      random_key = @instance[@symmetric_key]
      random_iv = @instance[@symmetric_iv]
      if @base64
        random_key = Base64.decode64(random_key)
        random_iv = Base64.decode64(random_iv)
      end
      cipher = OpenSSL::Cipher::Cipher.new(@symmetric_cipher)
      cipher.decrypt
      cipher.key = private_key.private_decrypt(random_key,@padding)
      cipher.iv = private_key.private_decrypt(random_iv,@padding)
      plaintext = cipher.update(ciphertext)
      plaintext << cipher.final
    else
      plaintext = private_key.private_decrypt(ciphertext,@padding)
    end
  else
    nil
  end
end

#encrypt(plaintext) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/strongbox/lock.rb', line 26

def encrypt plaintext
  ensure_required_columns  if @ensure_required_columns
  unless @public_key
    raise StrongboxError.new("#{@instance.class} model does not have public key_file")
  end
  if !plaintext.blank?
    @size = plaintext.size # For validations
    # Using a blank password in OpenSSL::PKey::RSA.new prevents reading
    # the private key if the file is a key pair
    public_key = get_rsa_key(@public_key,"")
    if @symmetric == :always
      cipher = OpenSSL::Cipher::Cipher.new(@symmetric_cipher)
      cipher.encrypt
      cipher.key = random_key = cipher.random_key
      cipher.iv = random_iv = cipher.random_iv

      ciphertext = cipher.update(plaintext)
      ciphertext << cipher.final
      encrypted_key = public_key.public_encrypt(random_key,@padding)
      encrypted_iv = public_key.public_encrypt(random_iv,@padding)
      if @base64
        encrypted_key = Base64.encode64(encrypted_key)
        encrypted_iv = Base64.encode64(encrypted_iv)
      end
      @instance[@symmetric_key] = encrypted_key
      @instance[@symmetric_iv] = encrypted_iv
    else
      ciphertext = public_key.public_encrypt(plaintext,@padding)
    end
    ciphertext =  Base64.encode64(ciphertext) if @base64
    @instance[@name] = ciphertext
  end
end

#ensure_required_columnsObject



124
125
126
127
128
129
130
131
132
# File 'lib/strongbox/lock.rb', line 124

def ensure_required_columns
  columns = [@name.to_s]
  columns += [@symmetric_key, @symmetric_iv] if @symmetric == :always
  columns.each do |column|
    unless @instance.class.column_names.include? column
      raise StrongboxError.new("#{@instance.class} model does not have database column \"#{column}\"")
    end
  end
end

#lengthObject



120
121
122
# File 'lib/strongbox/lock.rb', line 120

def length
  @size
end

#nil?Boolean

Returns:

  • (Boolean)


112
113
114
# File 'lib/strongbox/lock.rb', line 112

def nil?
  @instance[@name].nil?
end

#sizeObject



116
117
118
# File 'lib/strongbox/lock.rb', line 116

def size
  @size
end

#to_json(options = nil) ⇒ Object



103
104
105
# File 'lib/strongbox/lock.rb', line 103

def to_json(options = nil)
  to_s
end

#to_sObject



99
100
101
# File 'lib/strongbox/lock.rb', line 99

def to_s
  decrypt
end