Module: Familia::Encryption::Providers::Blake2bPersonalization
- Included in:
- SecureXChaCha20Poly1305Provider, XChaCha20Poly1305Provider
- Defined in:
- lib/familia/encryption/providers/blake2b_personalization.rb
Overview
Shared BLAKE2b personalization handling for the XChaCha20-Poly1305 providers (XChaCha20Poly1305Provider and its unregistered prototype sibling SecureXChaCha20Poly1305Provider). Both providers include this module so the personalization rotation logic exists exactly once -- the two files have drifted apart before (#250, #356).
Mirrors the AES-GCM HKDF salt rotation design from #310/#311: encryption uses the fail-closed current value, decryption walks a permissive candidate list ending with the pre-rotation default. See issue #333.
Constant Summary collapse
- LEGACY_PERSONALIZATION =
The built-in personalization every deployment shipped with before rotation support (#333). Retained ONLY as a decryption fallback (see
personalizations) so data written under the default stays readable
after an operator rotates to a deployment-specific value. Never used to encrypt new data once the config no longer resolves to it.
'FamilialMatters'
Instance Method Summary collapse
-
#current_personalization ⇒ String
The personalization string used to ENCRYPT new data.
-
#personalizations ⇒ Array<String>
Ordered list of personalization strings to consider when DECRYPTING, current first.
Instance Method Details
#current_personalization ⇒ String
The personalization string used to ENCRYPT new data.
Unlike #personalizations (the permissive decryption candidate list), this fails CLOSED. A nil or empty encryption_personalization is a misconfiguration -- and the raw attr_writer can set one, bypassing the reader's guards -- so refuse rather than silently deriving under a fallback (#311). Null-byte padding to BLAKE2b's 16 bytes happens at derive time (ljust in #derive_key), not here.
68 69 70 |
# File 'lib/familia/encryption/providers/blake2b_personalization.rb', line 68 def current_personalization validate_personalization!(Familia.config.encryption_personalization) end |
#personalizations ⇒ Array<String>
Ordered list of personalization strings to consider when DECRYPTING, current first.
Decryption walks this list until the authenticated decrypt succeeds, so it is intentionally permissive: it reads the raw config value (not
current_personalization, which raises) and ends with the built-in
default, so existing ciphertext stays readable even if the current config is broken. A wrong personalization derives a different key and fails Poly1305 authentication cleanly, so iterating never yields a false positive.
The filter is load-bearing, not cosmetic: a candidate that is not a String, is blank, contains null bytes, or exceeds BLAKE2b's 16-byte personalization limit would raise mid-walk (EncryptionError or RbNaCl::LengthError) and abort the remaining candidates, so such entries are dropped here instead of attempted.
ENCRYPTION does NOT use this list's head -- see
current_personalization, which fails closed rather than silently
encrypting under a fallback value.
48 49 50 51 52 53 54 55 |
# File 'lib/familia/encryption/providers/blake2b_personalization.rb', line 48 def personalizations current = Familia.config.encryption_personalization history = Familia.config.encryption_personalization_history [current, *history, LEGACY_PERSONALIZATION].select do |candidate| candidate.is_a?(String) && !candidate.empty? && !candidate.include?("\0") && candidate.bytesize <= 16 end.uniq end |