Skip to content

Instantly share code, notes, and snippets.

@wteuber
Last active February 2, 2026 15:13
Show Gist options
  • Select an option

  • Save wteuber/5318013 to your computer and use it in GitHub Desktop.

Select an option

Save wteuber/5318013 to your computer and use it in GitHub Desktop.
Basic encrypt and decrypt Strings in Ruby with deterministic salt or IV, generate and store random salt and IV in production
require 'openssl'
class String
CIPHER_NAME = 'aes-256-cbc'.freeze
PBKDF_ITER = 200_000
KEY_LEN = 32 # 256 bits
SALT_CONST = "fixed-global-salt-v1".freeze
IV_SALT_CONST = "fixed-iv-salt-v1".freeze
def encrypt(password)
cipher = OpenSSL::Cipher.new(CIPHER_NAME)
cipher.encrypt
# derive key
key = OpenSSL::PKCS5.pbkdf2_hmac(
password,
SALT_CONST,
PBKDF_ITER,
KEY_LEN,
"sha256"
)
cipher.key = key
# derive deterministic IV (no storage needed)
iv = OpenSSL::PKCS5.pbkdf2_hmac(
password,
IV_SALT_CONST,
PBKDF_ITER,
cipher.iv_len,
"sha256"
)
cipher.iv = iv
ciphertext = cipher.update(self) + cipher.final
# encode as IV || CIPHERTEXT (hex)
(iv + ciphertext).unpack1("H*").upcase
end
def decrypt(password)
raw = [self].pack("H*")
cipher = OpenSSL::Cipher.new(CIPHER_NAME)
cipher.decrypt
key = OpenSSL::PKCS5.pbkdf2_hmac(
password,
SALT_CONST,
PBKDF_ITER,
KEY_LEN,
"sha256"
)
cipher.key = key
iv_len = cipher.iv_len
iv = raw[0, iv_len]
ct = raw[iv_len..-1]
cipher.iv = iv
cipher.update(ct) + cipher.final
end
end
puts plain = 'confidential' # confidential
puts key = 'secret' # secret
puts cipher = plain.encrypt(key) # 5C6D4C5FAFFCF09F271E01C5A132BE89
puts cipher.decrypt('guess') # raises OpenSSL::Cipher::CipherError
puts cipher.decrypt(key) # confidential
@gustavo-iha
Copy link

avoiding key must be 24 bytes

def encrypt(key)
        cipher = OpenSSL::Cipher.new("aes-256-cbc").encrypt
        cipher.key = Digest::MD5.hexdigest key
        s = cipher.update(self) + cipher.final

        s.unpack('H*')[0].upcase
      end

      def decrypt(key)
        cipher = OpenSSL::Cipher.new('aes-256-cbc').decrypt
        cipher.key = Digest::MD5.hexdigest key
        s = [self].pack("H*").unpack("C*").pack("c*")

        cipher.update(s) + cipher.final
      end

thanks, works perfectly!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment