Class: Familia::Encryption::Providers::SecureXChaCha20Poly1305Provider
Overview
Enhanced XChaCha20Poly1305Provider with improved memory security
While complete avoidance of Ruby strings for secrets is challenging due to
RbNaCl's internal implementation, this provider implements several security
improvements:
- Minimizes key lifetime in memory
- Uses immediate secure wiping after operations
- Avoids unnecessary key duplication
- Uses locked memory where possible (future enhancement)
Constant Summary
collapse
- ALGORITHM =
'xchacha20poly1305-secure'.freeze
- NONCE_SIZE =
24
- AUTH_TAG_SIZE =
16
Class Method Summary
collapse
Instance Method Summary
collapse
Class Method Details
.available? ⇒ Boolean
54
55
56
|
# File 'lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb', line 54
def self.available?
!!defined?(RbNaCl) && !!defined?(FFI)
end
|
.dependency_hint ⇒ Object
58
59
60
|
# File 'lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb', line 58
def self.dependency_hint
'rbnacl/libsodium and ffi'
end
|
.priority ⇒ Object
62
63
64
|
# File 'lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb', line 62
def self.priority
110 end
|
Instance Method Details
#decrypt(ciphertext, key, nonce, auth_tag, additional_data = nil) ⇒ Object
81
82
83
84
85
86
87
88
89
90
91
92
93
|
# File 'lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb', line 81
def decrypt(ciphertext, key, nonce, auth_tag, additional_data = nil)
validate_key_length!(key)
begin
result = perform_decryption(ciphertext, key, nonce, auth_tag, additional_data)
ensure
secure_wipe(key)
end
result
end
|
#derive_key(master_key, context, personal: nil) ⇒ Object
Enhanced key derivation with immediate cleanup
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
# File 'lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb', line 100
def derive_key(master_key, context, personal: nil)
validate_key_length!(master_key)
raw_personal = personal || Familia.config.encryption_personalization
unless raw_personal.is_a?(String) && !raw_personal.empty?
raise EncryptionError, 'encryption_personalization must be a non-empty string for key derivation'
end
raise EncryptionError, 'Personalization string must not contain null bytes' if raw_personal.include?("\0")
personal_string = raw_personal.ljust(16, "\0")
derived_key = RbNaCl::Hash.blake2b(
context.force_encoding('BINARY'),
key: master_key,
digest_size: 32,
personal: personal_string
)
personal_string.clear
derived_key
end
|
#encrypt(plaintext, key, additional_data = nil) ⇒ Object
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
# File 'lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb', line 66
def encrypt(plaintext, key, additional_data = nil)
validate_key_length!(key)
nonce = generate_nonce
result = perform_encryption(plaintext, key, nonce, additional_data)
secure_wipe(key)
result
end
|
#generate_nonce ⇒ Object
95
96
97
|
# File 'lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb', line 95
def generate_nonce
RbNaCl::Random.random_bytes(NONCE_SIZE)
end
|
#secure_wipe(key) ⇒ Object
Clear key from memory (still no security guarantees in Ruby)
129
130
131
|
# File 'lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb', line 129
def secure_wipe(key)
key&.clear
end
|