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



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
62
63
64
# File 'lib/familia/encryption/manager.rb', line 35

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(**Familia::JsonSerializer.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 Familia::SerializerError => 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
32
33
# 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)

  encrypted_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

  Familia::JsonSerializer.dump(encrypted_data)
ensure
  Familia::Encryption.secure_wipe(key) if key
end