Module: Familia::Encryption
- Defined in:
- lib/familia/encryption.rb,
lib/familia/encryption/manager.rb,
lib/familia/encryption/provider.rb,
lib/familia/encryption/registry.rb,
lib/familia/encryption/request_cache.rb,
lib/familia/encryption/encrypted_data.rb,
lib/familia/encryption/providers/aes_gcm_provider.rb,
lib/familia/encryption/providers/xchacha20_poly1305_provider.rb,
lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb
Defined Under Namespace
Modules: Providers Classes: EncryptedData, Manager, Provider, Registry
Class Method Summary collapse
-
.benchmark(iterations: 1000) ⇒ Object
Benchmark available providers.
-
.clear_request_cache! ⇒ Object
Clear all cached keys and disable caching.
-
.decrypt(encrypted_json, context:, additional_data: nil) ⇒ Object
Quick decryption (auto-detects algorithm from data).
-
.derivation_count ⇒ Object
Derivation counter for monitoring no-caching behavior.
-
.encrypt(plaintext, context:, additional_data: nil) ⇒ Object
Quick encryption with auto-selected best provider.
-
.encrypt_with(algorithm, plaintext, context:, additional_data: nil) ⇒ Object
Encrypt with specific algorithm.
-
.hardware_acceleration? ⇒ Boolean
Check if we're using hardware acceleration.
-
.manager(algorithm: nil) ⇒ Object
Get or create a manager with specific algorithm.
- .reset_derivation_count! ⇒ Object
-
.secure_wipe(key) ⇒ Object
Clear key from memory (no security guarantees in Ruby).
-
.status ⇒ Object
Get info about current encryption setup.
- .validate_configuration! ⇒ Object
-
.with_request_cache ⇒ Object
Enable request-scoped caching (opt-in for performance).
Class Method Details
.benchmark(iterations: 1000) ⇒ Object
Benchmark available providers
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/familia/encryption.rb', line 129 def benchmark(iterations: 1000) require 'benchmark' test_data = 'x' * 1024 # 1KB test context = 'benchmark:test' results = {} Registry.providers.each do |algo, provider_class| next unless provider_class.available? mgr = Manager.new(algorithm: algo) time = Benchmark.realtime do iterations.times do encrypted = mgr.encrypt(test_data, context: context) mgr.decrypt(encrypted, context: context) end end results[algo] = { time: time, ops_per_sec: (iterations * 2 / time).round, priority: provider_class.priority, } end results end |
.clear_request_cache! ⇒ Object
Clear all cached keys and disable caching
31 32 33 34 35 36 37 38 |
# File 'lib/familia/encryption/request_cache.rb', line 31 def clear_request_cache! if (cache = Fiber[:familia_request_cache]) cache.each_value { |key| secure_wipe(key) } cache.clear end Fiber[:familia_request_cache_enabled] = false Fiber[:familia_request_cache] = nil end |
.decrypt(encrypted_json, context:, additional_data: nil) ⇒ Object
Quick decryption (auto-detects algorithm from data)
81 82 83 |
# File 'lib/familia/encryption.rb', line 81 def decrypt(encrypted_json, context:, additional_data: nil) manager.decrypt(encrypted_json, context: context, additional_data: additional_data) end |
.derivation_count ⇒ Object
Derivation counter for monitoring no-caching behavior
95 96 97 |
# File 'lib/familia/encryption.rb', line 95 def derivation_count @derivation_count ||= Concurrent::AtomicFixnum.new(0) end |
.encrypt(plaintext, context:, additional_data: nil) ⇒ Object
Quick encryption with auto-selected best provider
76 77 78 |
# File 'lib/familia/encryption.rb', line 76 def encrypt(plaintext, context:, additional_data: nil) manager.encrypt(plaintext, context: context, additional_data: additional_data) end |
.encrypt_with(algorithm, plaintext, context:, additional_data: nil) ⇒ Object
Encrypt with specific algorithm
86 87 88 89 90 91 92 |
# File 'lib/familia/encryption.rb', line 86 def encrypt_with(algorithm, plaintext, context:, additional_data: nil) manager(algorithm: algorithm).encrypt( plaintext, context: context, additional_data: additional_data ) end |
.hardware_acceleration? ⇒ Boolean
Check if we're using hardware acceleration
123 124 125 126 |
# File 'lib/familia/encryption.rb', line 123 def hardware_acceleration? provider = Registry.default_provider provider && provider.class.name.include?('Hardware') end |
.manager(algorithm: nil) ⇒ Object
Get or create a manager with specific algorithm
Thread-safe lazy initialization using Concurrent::Map to ensure only a single Manager instance is created per algorithm even under concurrent encryption/decryption requests.
70 71 72 73 |
# File 'lib/familia/encryption.rb', line 70 def manager(algorithm: nil) @managers ||= Concurrent::Map.new @managers.fetch_or_store(algorithm) { Manager.new(algorithm: algorithm) } end |
.reset_derivation_count! ⇒ Object
99 100 101 |
# File 'lib/familia/encryption.rb', line 99 def reset_derivation_count! derivation_count.value = 0 end |
.secure_wipe(key) ⇒ Object
Clear key from memory (no security guarantees in Ruby)
104 105 106 |
# File 'lib/familia/encryption.rb', line 104 def secure_wipe(key) key&.clear end |
.status ⇒ Object
Get info about current encryption setup
109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/familia/encryption.rb', line 109 def status Registry.setup! if Registry.providers.empty? { default_algorithm: Registry.default_provider&.algorithm, available_algorithms: Registry.available_algorithms, preferred_available: Registry.default_provider&.class&.name, using_hardware: hardware_acceleration?, key_versions: encryption_keys.keys, current_version: current_key_version, } end |
.validate_configuration! ⇒ Object
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/familia/encryption.rb', line 156 def validate_configuration! raise EncryptionError, 'No encryption keys configured' if encryption_keys.empty? raise EncryptionError, 'No current key version set' unless current_key_version current_key = encryption_keys[current_key_version] raise EncryptionError, "Current key version not found: #{current_key_version}" unless current_key begin Base64.strict_decode64(current_key) rescue ArgumentError raise EncryptionError, 'Current encryption key is not valid Base64' end Registry.setup! raise EncryptionError, 'No encryption providers available' unless Registry.default_provider end |
.with_request_cache ⇒ Object
Enable request-scoped caching (opt-in for performance)
22 23 24 25 26 27 28 |
# File 'lib/familia/encryption/request_cache.rb', line 22 def with_request_cache Fiber[:familia_request_cache_enabled] = true Fiber[:familia_request_cache] = {} yield ensure clear_request_cache! end |