Module: Encryption
- Defined in:
- lib/encryption.rb
Overview
Two-way encryption helpers for short URL tokens (order/quote/locator IDs).
Two formats produced by encrypt_string:
- length(plain) <= 8 → Blowfish ECB on a single 8-byte block.
Hex-encoded. Output: 16 hex chars. - length(plain) > 8 → AES-256-CBC, hex-encoded (
url_encrypt_string).
decrypt_string recognises three on-the-wire shapes:
- length 16 → Blowfish path
- length 17–N → AES path (
url_decrypt_string); falls back to
legacy_decrypt_string(Base64+CGI-escape from
an even older format).
Blowfish notes
- This module previously depended on the
cryptgem (Crypt::Blowfish,
last released in 2007). It now uses Ruby's stdlib OpenSSL bf-ecb
cipher which produces byte-identical ciphertext for the same key +
8-byte plaintext block. Verified end-to-end (encrypt+decrypt and
cross-decrypt) against Crypt::Blowfish output before the switch. - OpenSSL 3.x moved Blowfish to the "legacy" provider; we load it on
demand at the call site so this works on both OpenSSL 1.1.x (no
legacy concept) and OpenSSL 3.x (legacy provider required). - Blowfish has a 64-bit block size and is considered legacy. We keep
it only for backward-compatibility with URL tokens already in
circulation (links inside customer emails, support tickets, etc.).
New token issuance for short IDs continues to flow through this
path so that wire format stays stable; a future migration to
signed_id/generates_token_foris tracked separately.
Class Method Summary collapse
- .aes_decrypt(text, key) ⇒ Object
- .aes_encrypt(text, key) ⇒ Object
- .blowfish_decrypt(text, key) ⇒ Object
- .blowfish_encrypt(text, key) ⇒ Object
- .decrypt_string(string) ⇒ Object
- .encrypt_string(string) ⇒ Object
- .legacy_decrypt_string(encrypted_string) ⇒ Object
- .legacy_encrypt_string(string) ⇒ Object
- .url_decrypt_string(encrypted_string) ⇒ Object
- .url_encrypt_string(string) ⇒ Object
Class Method Details
.aes_decrypt(text, key) ⇒ Object
93 94 95 96 97 |
# File 'lib/encryption.rb', line 93 def self.aes_decrypt(text, key) aes(:decrypt, text, key) rescue OpenSSL::Cipher::CipherError '' end |
.aes_encrypt(text, key) ⇒ Object
89 90 91 |
# File 'lib/encryption.rb', line 89 def self.aes_encrypt(text, key) aes(:encrypt, text, key) end |
.blowfish_decrypt(text, key) ⇒ Object
66 67 68 69 70 71 |
# File 'lib/encryption.rb', line 66 def self.blowfish_decrypt(text, key) cipher = blowfish_cipher(:decrypt, key) cipher.update(text) + cipher.final rescue OpenSSL::Cipher::CipherError '' end |
.blowfish_encrypt(text, key) ⇒ Object
61 62 63 64 |
# File 'lib/encryption.rb', line 61 def self.blowfish_encrypt(text, key) cipher = blowfish_cipher(:encrypt, key) cipher.update(text) + cipher.final end |
.decrypt_string(string) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/encryption.rb', line 46 def self.decrypt_string(string) str = string.to_s res = nil if str.length > 16 # AES path; fall through to the very old Base64+CGI format if needed. res = url_decrypt_string(string) res = legacy_decrypt_string(string) if res.blank? elsif str.length == 16 enc_str = str.each_line.to_a.pack('H*') padded_string = blowfish_decrypt(enc_str, REST_AUTH_SITE_KEY) res = padded_string.delete("\000") end res end |
.encrypt_string(string) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/encryption.rb', line 33 def self.encrypt_string(string) if string.to_s.length > 8 url_encrypt_string(string) else # Pad to an exact 8-byte block with NUL. len = string.length mod = len == 8 ? 0 : 8 - (len % 8) padded_string = string.ljust(len + mod, "\0") enc_str = blowfish_encrypt(padded_string, REST_AUTH_SITE_KEY) enc_str.unpack1('H*') end end |
.legacy_decrypt_string(encrypted_string) ⇒ Object
85 86 87 |
# File 'lib/encryption.rb', line 85 def self.legacy_decrypt_string(encrypted_string) aes_decrypt(Base64.decode64(CGI.unescape(encrypted_string)), REST_AUTH_SITE_KEY[0..31]) end |
.legacy_encrypt_string(string) ⇒ Object
81 82 83 |
# File 'lib/encryption.rb', line 81 def self.legacy_encrypt_string(string) CGI.escape(Base64.encode64(aes_encrypt(string.to_s, REST_AUTH_SITE_KEY[0..31]))) end |
.url_decrypt_string(encrypted_string) ⇒ Object
77 78 79 |
# File 'lib/encryption.rb', line 77 def self.url_decrypt_string(encrypted_string) aes_decrypt([encrypted_string].pack('H*'), REST_AUTH_SITE_KEY[0..31]) end |
.url_encrypt_string(string) ⇒ Object
73 74 75 |
# File 'lib/encryption.rb', line 73 def self.url_encrypt_string(string) aes_encrypt(string.to_s, REST_AUTH_SITE_KEY[0..31]).unpack1('H*') end |