Class: Familia::Encryption::Manager

Inherits:
Object
  • Object
show all
Defined in:
lib/familia/encryption/manager.rb

Overview

High-level encryption manager - replaces monolithic Encryption module

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(algorithm: nil) ⇒ Manager

Returns a new instance of Manager.

Raises:



9
10
11
12
13
# File 'lib/familia/encryption/manager.rb', line 9

def initialize(algorithm: nil)
  Registry.setup! if Registry.providers.empty?
  @provider = algorithm ? Registry.get(algorithm) : Registry.default_provider
  raise EncryptionError, 'No encryption provider available' unless @provider
end

Instance Attribute Details

#providerObject (readonly)

Returns the value of attribute provider.



7
8
9
# File 'lib/familia/encryption/manager.rb', line 7

def provider
  @provider
end

Instance Method Details

#decrypt(encrypted_json, context:, additional_data: nil) ⇒ Object



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
59
60
61
# File 'lib/familia/encryption/manager.rb', line 33

def decrypt(encrypted_json, context:, additional_data: nil)
  return nil if encrypted_json.nil? || encrypted_json.empty?

  # Increment counter immediately to track all decryption attempts, even failed ones
  Familia::Encryption.derivation_count.increment

  begin
    data = Familia::Encryption::EncryptedData.new(**JSON.parse(encrypted_json, symbolize_names: true))

    # Validate algorithm support
    provider = Registry.get(data.algorithm)
    key = derive_key_without_increment(context, version: data.key_version, provider: provider)

    # Safely decode and validate sizes
    nonce = decode_and_validate(data.nonce, provider.nonce_size, 'nonce')
    ciphertext = decode_and_validate_ciphertext(data.ciphertext)
    auth_tag = decode_and_validate(data.auth_tag, provider.auth_tag_size, 'auth_tag')

    provider.decrypt(ciphertext, key, nonce, auth_tag, additional_data)
  rescue EncryptionError
    raise
  rescue JSON::ParserError => e
    raise EncryptionError, "Invalid JSON structure: #{e.message}"
  rescue StandardError => e
    raise EncryptionError, "Decryption failed: #{e.message}"
  end
ensure
  Familia::Encryption.secure_wipe(key) if key
end

#encrypt(plaintext, context:, additional_data: nil) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/familia/encryption/manager.rb', line 15

def encrypt(plaintext, context:, additional_data: nil)
  return nil if plaintext.to_s.empty?

  key = derive_key(context)

  result = @provider.encrypt(plaintext, key, additional_data)

  Familia::Encryption::EncryptedData.new(
    algorithm: @provider.algorithm,
    nonce: Base64.strict_encode64(result[:nonce]),
    ciphertext: Base64.strict_encode64(result[:ciphertext]),
    auth_tag: Base64.strict_encode64(result[:auth_tag]),
    key_version: current_key_version
  ).to_h.to_json
ensure
  Familia::Encryption.secure_wipe(key) if key
end