Module: Lockbox

Extended by:
Padding
Defined in:
lib/lockbox/active_storage_extensions.rb,
lib/lockbox.rb,
lib/lockbox/io.rb,
lib/lockbox/box.rb,
lib/lockbox/model.rb,
lib/lockbox/utils.rb,
lib/lockbox/aes_gcm.rb,
lib/lockbox/padding.rb,
lib/lockbox/railtie.rb,
lib/lockbox/version.rb,
lib/lockbox/migrator.rb,
lib/lockbox/encryptor.rb,
lib/lockbox/calculations.rb,
lib/lockbox/key_generator.rb,
lib/lockbox/log_subscriber.rb,
lib/lockbox/carrier_wave_extensions.rb,
lib/generators/lockbox/audits_generator.rb

Overview

ideally encrypt and decrypt would happen at the blob/service level however, there isn’t really a great place to define encryption settings there instead, we encrypt and decrypt at the attachment level, and we define encryption settings at the model level

Defined Under Namespace

Modules: ActiveStorageExtensions, Calculations, CarrierWaveExtensions, Generators, Model, Padding Classes: AES_GCM, Box, DecryptionError, Encryptor, Error, IO, KeyGenerator, LogSubscriber, Migrator, PaddingError, Railtie, Utils

Constant Summary collapse

VERSION =
"0.4.4"

Constants included from Padding

Padding::PAD_FIRST_BYTE, Padding::PAD_ZERO_BYTE

Class Attribute Summary collapse

Class Method Summary collapse

Methods included from Padding

pad, pad!, unpad, unpad!

Class Attribute Details

.default_optionsObject

Returns the value of attribute default_options.



47
48
49
# File 'lib/lockbox.rb', line 47

def default_options
  @default_options
end

.master_keyObject



52
53
54
# File 'lib/lockbox.rb', line 52

def self.master_key
  @master_key ||= ENV["LOCKBOX_MASTER_KEY"]
end

Class Method Details

.attribute_key(table:, attribute:, master_key: nil, encode: true) ⇒ Object

Raises:

  • (ArgumentError)


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

def self.attribute_key(table:, attribute:, master_key: nil, encode: true)
  master_key ||= Lockbox.master_key
  raise ArgumentError, "Missing master key" unless master_key

  key = Lockbox::KeyGenerator.new(master_key).attribute_key(table: table, attribute: attribute)
  key = to_hex(key) if encode
  key
end

.encrypts_action_text_body(**options) ⇒ Object



99
100
101
102
103
# File 'lib/lockbox.rb', line 99

def self.encrypts_action_text_body(**options)
  ActiveSupport.on_load(:action_text_rich_text) do
    ActionText::RichText.encrypts :body, **options
  end
end

.generate_keyObject



64
65
66
# File 'lib/lockbox.rb', line 64

def self.generate_key
  SecureRandom.hex(32)
end

.generate_key_pairObject



68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/lockbox.rb', line 68

def self.generate_key_pair
  require "rbnacl"
  # encryption and decryption servers exchange public keys
  # this produces smaller ciphertext than sealed box
  alice = RbNaCl::PrivateKey.generate
  bob = RbNaCl::PrivateKey.generate
  # alice is sending message to bob
  # use bob first in both cases to prevent keys being swappable
  {
    encryption_key: to_hex(bob.public_key.to_bytes + alice.to_bytes),
    decryption_key: to_hex(bob.to_bytes + alice.public_key.to_bytes)
  }
end

.migrate(relation, batch_size: 1000, restart: false) ⇒ Object



56
57
58
# File 'lib/lockbox.rb', line 56

def self.migrate(relation, batch_size: 1000, restart: false)
  Migrator.new(relation, batch_size: batch_size).migrate(restart: restart)
end

.new(**options) ⇒ Object



95
96
97
# File 'lib/lockbox.rb', line 95

def self.new(**options)
  Encryptor.new(**options)
end

.rotate(relation, batch_size: 1000, attributes:) ⇒ Object



60
61
62
# File 'lib/lockbox.rb', line 60

def self.rotate(relation, batch_size: 1000, attributes:)
  Migrator.new(relation, batch_size: batch_size).rotate(attributes: attributes)
end

.to_hex(str) ⇒ Object



91
92
93
# File 'lib/lockbox.rb', line 91

def self.to_hex(str)
  str.unpack("H*").first
end