Class: Familia::Encryption::Providers::XChaCha20Poly1305Provider
Overview
XChaCha20-Poly1305 AEAD provider backed by RbNaCl/libsodium. Derives
per-context keys via BLAKE2b keyed hashing with a rotatable
personalization string (see Blake2bPersonalization, #333).
Constant Summary
collapse
- ALGORITHM =
'xchacha20poly1305'
- NONCE_SIZE =
24
- AUTH_TAG_SIZE =
16
- KEY_SIZE =
32
Blake2bPersonalization::LEGACY_PERSONALIZATION
Class Method Summary
collapse
Instance Method Summary
collapse
#current_personalization, #personalizations
Class Method Details
.auth_tag_size ⇒ Object
136
137
138
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 136
def self.auth_tag_size
AUTH_TAG_SIZE
end
|
.available? ⇒ Boolean
48
49
50
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 48
def self.available?
!!defined?(RbNaCl)
end
|
.dependency_hint ⇒ Object
52
53
54
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 52
def self.dependency_hint
'rbnacl/libsodium'
end
|
.nonce_size ⇒ Object
132
133
134
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 132
def self.nonce_size
NONCE_SIZE
end
|
.priority ⇒ Object
56
57
58
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 56
def self.priority
100 end
|
Instance Method Details
#algorithm ⇒ Object
148
149
150
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 148
def algorithm
ALGORITHM
end
|
#auth_tag_size ⇒ Object
144
145
146
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 144
def auth_tag_size
AUTH_TAG_SIZE
end
|
#decrypt(ciphertext, key, nonce, auth_tag, additional_data = nil) ⇒ Object
75
76
77
78
79
80
81
82
83
84
85
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 75
def decrypt(ciphertext, key, nonce, auth_tag, additional_data = nil)
validate_key_length!(key)
box = RbNaCl::AEAD::XChaCha20Poly1305IETF.new(key)
ciphertext_with_tag = ciphertext + auth_tag
aad = additional_data.to_s
box.decrypt(nonce, ciphertext_with_tag, aad)
rescue RbNaCl::CryptoError
raise EncryptionError, 'Decryption failed - invalid key or corrupted data'
end
|
#derive_key(master_key, context, personal: nil) ⇒ String
Derives a context-specific encryption key using BLAKE2b.
The personalization parameter provides cryptographic domain separation,
ensuring that derived keys are unique per application even when using
identical master keys and contexts. This prevents key reuse across
different applications or library versions.
personal defaults to the current configured personalization
(Blake2bPersonalization#current_personalization), which fails closed
on a nil/blank config. The decrypt path passes explicit candidates
from #personalizations so ciphertext written under a previous
personalization stays decryptable after a rotation (#333).
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 108
def derive_key(master_key, context, personal: nil)
validate_key_length!(master_key)
raw_personal = personal ? validate_personalization!(personal) : current_personalization
personal_string = raw_personal.ljust(16, "\0")
RbNaCl::Hash.blake2b(
context.to_s.b,
key: master_key,
digest_size: KEY_SIZE,
personal: personal_string,
)
end
|
#encrypt(plaintext, key, additional_data = nil) ⇒ Object
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 60
def encrypt(plaintext, key, additional_data = nil)
validate_key_length!(key)
nonce = generate_nonce
box = RbNaCl::AEAD::XChaCha20Poly1305IETF.new(key)
aad = additional_data.to_s
ciphertext_with_tag = box.encrypt(nonce, plaintext.to_s, aad)
{
ciphertext: ciphertext_with_tag[0...-16],
auth_tag: ciphertext_with_tag[-16..],
nonce: nonce,
}
end
|
#generate_nonce ⇒ Object
87
88
89
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 87
def generate_nonce
RbNaCl::Random.random_bytes(NONCE_SIZE)
end
|
#nonce_size ⇒ Object
140
141
142
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 140
def nonce_size
NONCE_SIZE
end
|
#secure_wipe(key) ⇒ Object
Clear key from memory (no security guarantees in Ruby)
128
129
130
|
# File 'lib/familia/encryption/providers/xchacha20_poly1305_provider.rb', line 128
def secure_wipe(key)
key&.clear
end
|