Class: ActiveCipherStorage::Cipher

Inherits:
Object
  • Object
show all
Includes:
KeyUtils
Defined in:
lib/active_cipher_storage/cipher.rb

Constant Summary collapse

OPENSSL_ALGO =
"aes-256-gcm"
KEY_SIZE =
32

Instance Method Summary collapse

Constructor Details

#initialize(config = ActiveCipherStorage.configuration) ⇒ Cipher

Returns a new instance of Cipher.



12
13
14
15
16
# File 'lib/active_cipher_storage/cipher.rb', line 12

def initialize(config = ActiveCipherStorage.configuration)
  config.validate!
  @config   = config
  @provider = config.provider
end

Instance Method Details

#decrypt(encrypted_data) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/active_cipher_storage/cipher.rb', line 39

def decrypt(encrypted_data)
  io     = to_binary_io(encrypted_data)
  header = Format.read_header(io)
  raise Errors::InvalidFormat, "Payload is chunked; use StreamCipher#decrypt" if header.chunked

  key       = @provider.decrypt_data_key(header.encrypted_dek)
  iv        = io.read(Format::IV_SIZE)
  tail      = drain(io)
  ciphertext = tail.byteslice(0, tail.bytesize - Format::AUTH_TAG_SIZE)
  auth_tag   = tail.byteslice(-Format::AUTH_TAG_SIZE, Format::AUTH_TAG_SIZE)

  c = build_cipher(:decrypt, key, iv, auth_tag)
  c.update(ciphertext) + c.final
rescue OpenSSL::Cipher::CipherError
  raise Errors::DecryptionError, "Authentication failed — ciphertext may be tampered or the key is wrong"
ensure
  zero_bytes!(key)
end

#encrypt(io) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/active_cipher_storage/cipher.rb', line 18

def encrypt(io)
  plaintext  = io.read.b
  dek_bundle = @provider.generate_data_key
  key        = dek_bundle.fetch(:plaintext_key)
  iv         = SecureRandom.random_bytes(Format::IV_SIZE)

  c          = build_cipher(:encrypt, key, iv)
  ciphertext = c.update(plaintext) + c.final
  auth_tag   = c.auth_tag

  out = StringIO.new("".b)
  Format.write_header(out, header(dek_bundle, chunked: false))
  out.write(iv)
  out.write(ciphertext)
  out.write(auth_tag)
  out.string
ensure
  zero_bytes!(key)
  zero_bytes!(plaintext)
end