Class: Llmemory::Crypto::Cipher
- Inherits:
-
Object
- Object
- Llmemory::Crypto::Cipher
- Defined in:
- lib/llmemory/crypto/cipher.rb
Overview
AES-256-GCM encryption with separate content (random IV) and index (deterministic IV) subkeys derived from the master key via HMAC-SHA256.
Constant Summary collapse
- MARKER =
"enc:v1:"- DETERMINISTIC_MARKER =
"encd:v1:"- IV_LENGTH =
12- TAG_LENGTH =
16
Instance Method Summary collapse
- #decrypt(ciphertext) ⇒ Object
- #decrypt_json(str) ⇒ Object
- #enabled? ⇒ Boolean
- #encrypt(plaintext) ⇒ Object
- #encrypt_deterministic(plaintext) ⇒ Object
- #encrypt_json(obj) ⇒ Object
- #encrypted?(str) ⇒ Boolean
-
#initialize(key) ⇒ Cipher
constructor
A new instance of Cipher.
Constructor Details
#initialize(key) ⇒ Cipher
Returns a new instance of Cipher.
49 50 51 52 53 |
# File 'lib/llmemory/crypto/cipher.rb', line 49 def initialize(key) @master_key = derive_master_key(key) @content_key = derive_subkey("content") @index_key = derive_subkey("index") end |
Instance Method Details
#decrypt(ciphertext) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/llmemory/crypto/cipher.rb', line 74 def decrypt(ciphertext) str = ciphertext.to_s return str if str.empty? return str unless encrypted?(str) marker, key = if str.start_with?(DETERMINISTIC_MARKER) [DETERMINISTIC_MARKER, @index_key] else [MARKER, @content_key] end payload = decode64(str.delete_prefix(marker)) iv = payload[0, IV_LENGTH] tag = payload[IV_LENGTH, TAG_LENGTH] ct = payload[(IV_LENGTH + TAG_LENGTH)..] cipher = OpenSSL::Cipher.new("aes-256-gcm") cipher.decrypt cipher.key = key cipher.iv = iv cipher.auth_tag = tag cipher.auth_data = "" cipher.update(ct) + cipher.final rescue OpenSSL::Cipher::CipherError, ArgumentError => e raise DecryptionError, "Failed to decrypt data: #{e.}" end |
#decrypt_json(str) ⇒ Object
105 106 107 |
# File 'lib/llmemory/crypto/cipher.rb', line 105 def decrypt_json(str) JSON.parse(decrypt(str), symbolize_names: true) end |
#enabled? ⇒ Boolean
55 56 57 |
# File 'lib/llmemory/crypto/cipher.rb', line 55 def enabled? true end |
#encrypt(plaintext) ⇒ Object
59 60 61 62 63 64 |
# File 'lib/llmemory/crypto/cipher.rb', line 59 def encrypt(plaintext) str = plaintext.to_s return str if str.empty? encrypt_with_key(str, @content_key, iv: OpenSSL::Random.random_bytes(IV_LENGTH), marker: MARKER) end |
#encrypt_deterministic(plaintext) ⇒ Object
66 67 68 69 70 71 72 |
# File 'lib/llmemory/crypto/cipher.rb', line 66 def encrypt_deterministic(plaintext) str = plaintext.to_s return str if str.empty? iv = OpenSSL::HMAC.digest("SHA256", @index_key, str)[0, IV_LENGTH] encrypt_with_key(str, @index_key, iv: iv, marker: DETERMINISTIC_MARKER) end |
#encrypt_json(obj) ⇒ Object
101 102 103 |
# File 'lib/llmemory/crypto/cipher.rb', line 101 def encrypt_json(obj) encrypt(JSON.generate(obj)) end |
#encrypted?(str) ⇒ Boolean
109 110 111 112 |
# File 'lib/llmemory/crypto/cipher.rb', line 109 def encrypted?(str) s = str.to_s s.start_with?(MARKER) || s.start_with?(DETERMINISTIC_MARKER) end |