Module: RubynCode::Auth::KeyEncryption
- Defined in:
- lib/rubyn_code/auth/key_encryption.rb
Overview
Encrypts and decrypts provider API keys at rest using AES-256-GCM.
The encryption key is derived via PBKDF2 from machine-specific identifiers (username, hostname, home directory) combined with a random salt stored in ~/.rubyn-code/.encryption_salt. This means keys are only decryptable on the same machine by the same user.
Encrypted values are prefixed with “enc:v1:” so plaintext values from older versions are transparently migrated on first read.
Constant Summary collapse
- CIPHER =
'aes-256-gcm'- PREFIX =
'enc:v1:'- IV_LENGTH =
12- TAG_LENGTH =
16- PBKDF2_ITERATIONS =
100_000- KEY_LENGTH =
32- SALT_LENGTH =
32
Class Method Summary collapse
Class Method Details
.decrypt(value) ⇒ Object
45 46 47 48 49 50 51 52 53 |
# File 'lib/rubyn_code/auth/key_encryption.rb', line 45 def decrypt(value) return nil unless value return value unless encrypted?(value) raw = Base64.strict_decode64(value.delete_prefix(PREFIX)) decrypt_raw(raw) rescue OpenSSL::Cipher::CipherError, ArgumentError nil end |
.encrypt(plaintext) ⇒ Object
30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/rubyn_code/auth/key_encryption.rb', line 30 def encrypt(plaintext) return nil unless plaintext cipher = OpenSSL::Cipher.new(CIPHER).encrypt key = derive_key cipher.key = key iv = cipher.random_iv ciphertext = cipher.update(plaintext) + cipher.final tag = cipher.auth_tag(TAG_LENGTH) encoded = Base64.strict_encode64(iv + ciphertext + tag) "#{PREFIX}#{encoded}" end |
.encrypted?(value) ⇒ Boolean
55 56 57 |
# File 'lib/rubyn_code/auth/key_encryption.rb', line 55 def encrypted?(value) value.is_a?(String) && value.start_with?(PREFIX) end |