Skip to content

Instantly share code, notes, and snippets.

@alfuken
Created October 17, 2025 08:03
Show Gist options
  • Save alfuken/b4d0cae0c831657da1fb452f4c6f1dad to your computer and use it in GitHub Desktop.
Save alfuken/b4d0cae0c831657da1fb452f4c6f1dad to your computer and use it in GitHub Desktop.
# frozen_string_literal: true
# LICENSE: MIT
#
# A very simple deterministic string encryption.
# Variation of a Caesar cipher.
#
# Intended to be used with strings,
# primary purpose of this approach is to merely make it *harder* for an eavesdropper
# to see the actual data contained in a string.
#
# This is in no way a replacement for a "proper" encryption, but it's fast as all hells,
# and, unlike "proper" encryption methods, increases string length only slightly
# (`Base64.urlsafe_encode64` overhead), which can sometimes be crucial.
#
#
# Usage:
#
# require "dencrypt"
#
# things = "Eggs, brains, signals, wires."
# things.length #=> 29
# mush = Dencrypt.scramble(things) #=> "3tbFotPazpak3dnXu-CujojhmNHQ3N1U0Y6S0N0"
# mash = Dencrypt.scramble(things) #=> "3tbFotPazpak3dnXu-CujojhmNHQ3N1U0Y6S0N0"
# mush == mash #=> true
# mush.length #=> 39
# neat = Dencrypt.unscramble(mush) #=> "Eggs, brains, signals, wires."
# neat == things #=> true
#
module Dencrypt
class DencryptionError < StandardError; end
class EncryptionError < DencryptionError; end
class DecryptionError < DencryptionError; end
DENCRYPTION_KEY = defined?(Rails) ? Rails.application.secret_key_base : ENV.fetch("DENCRYPTION_KEY")
module_function def scramble(data)
seed = Digest::MD5.hexdigest(DENCRYPTION_KEY.to_s).to_i(16) # deterministic seed integer for Random
key = DENCRYPTION_KEY.bytes.cycle
data.bytes. # for each byte in the string stream,
map{|byte| ((byte + key.next) % 255).chr }. # perform a simple byte shift
shuffle(random: Random.new(seed)). # then sprinkle with deterministic Array#shuffle on top,
join. # to make things interesting.
then{ Base64.urlsafe_encode64 _1, padding: false }
rescue
raise EncryptionError.new
end
# Well, duh.
module_function def unscramble(data)
seed = Digest::MD5.hexdigest(DENCRYPTION_KEY.to_s).to_i(16) # same deterministic seed int
key = DENCRYPTION_KEY.bytes.cycle
Base64.urlsafe_decode64(data).bytes.
unshuffle(random: Random.new(seed)). # <- hero of the day!
map{|byte| ((byte - key.next) % 255).chr }. # shift that byte back
join
rescue
raise DecryptionError.new
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment