Module: RosettAi::Mcp::KeyHasher
- Defined in:
- lib/rosett_ai/mcp/key_hasher.rb
Overview
Cryptographic key hashing with per-key random salt.
Uses SHA-256 with 16-byte random salt. Verification uses constant-time comparison via Rack::Utils.secure_compare.
Constant Summary collapse
- SALT_BYTES =
16- KEY_PREFIX =
'nncc_'
Class Method Summary collapse
-
.generate_key ⇒ String
Generate a new random API key with the Rosett-AI_ prefix.
-
.hash_key(plaintext) ⇒ String
Hash a plaintext API key with a random salt.
-
.secure_compare(a_str, b_str) ⇒ Boolean
Constant-time string comparison to prevent timing attacks.
-
.verify_key(plaintext, stored_hash) ⇒ Boolean
Verify a plaintext key against a stored hash.
Class Method Details
.generate_key ⇒ String
Generate a new random API key with the Rosett-AI_ prefix.
50 51 52 |
# File 'lib/rosett_ai/mcp/key_hasher.rb', line 50 def generate_key "#{KEY_PREFIX}#{SecureRandom.hex(24)}" end |
.hash_key(plaintext) ⇒ String
Hash a plaintext API key with a random salt.
28 29 30 31 32 |
# File 'lib/rosett_ai/mcp/key_hasher.rb', line 28 def hash_key(plaintext) salt = SecureRandom.hex(SALT_BYTES) digest = OpenSSL::Digest::SHA256.hexdigest("#{salt}#{plaintext}") "#{salt}$#{digest}" end |
.secure_compare(a_str, b_str) ⇒ Boolean
Constant-time string comparison to prevent timing attacks.
59 60 61 62 63 |
# File 'lib/rosett_ai/mcp/key_hasher.rb', line 59 def secure_compare(a_str, b_str) return false unless a_str.bytesize == b_str.bytesize OpenSSL.fixed_length_secure_compare(a_str, b_str) end |
.verify_key(plaintext, stored_hash) ⇒ Boolean
Verify a plaintext key against a stored hash.
39 40 41 42 43 44 45 |
# File 'lib/rosett_ai/mcp/key_hasher.rb', line 39 def verify_key(plaintext, stored_hash) salt, expected_digest = stored_hash.split('$', 2) return false unless salt && expected_digest actual_digest = OpenSSL::Digest::SHA256.hexdigest("#{salt}#{plaintext}") secure_compare(actual_digest, expected_digest) end |