I need a simple encryption for some text strings. I want to create coupon codes and make them look cool so subsequently created code should look very different. (And besides looking cool, it shouldn't be easy to guess a code.) But I want to be able to decrypt them again. So the algorithm must be reversible.
I alread tried some stuff with moving bits around so they look kind of random already. But two subsequent codes (just one bit different) of course look very similar.
Any suggestions? I would like to do that without using external gems.
Philip
You could use OpenSSL::Cipher
# for more info, see http://ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/Cipher.html
require 'openssl'
require 'digest/sha1'
# create the cipher for encrypting
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
cipher.encrypt
# you will need to store these for later, in order to decrypt your data
key = Digest::SHA1.hexdigest("yourpass")
iv = cipher.random_iv
# load them into the cipher
cipher.key = key
cipher.iv = iv
# encrypt the message
encrypted = cipher.update('This is a secure message, meet at the clock-tower at dawn.')
encrypted << cipher.final
puts "encrypted: #{encrypted}\n"
# now we create a sipher for decrypting
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
cipher.decrypt
cipher.key = key
cipher.iv = iv
# and decrypt it
decrypted = cipher.update(encrypted)
decrypted << cipher.final
puts "decrypted: #{decrypted}\n"
But the intermediate form doesn't lend itself well to printing
Given your thought that it would be nice if the intermediate form was the same length, you might just use a simple map of one char to another.
You can easily brute force the key, but it seems to be congruent with your requirements.
class Cipher
def initialize(shuffled)
normal = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + [' ']
@map = normal.zip(shuffled).inject(:encrypt => {} , :decrypt => {}) do |hash,(a,b)|
hash[:encrypt][a] = b
hash[:decrypt][b] = a
hash
end
end
def encrypt(str)
str.split(//).map { |char| @map[:encrypt][char] }.join
end
def decrypt(str)
str.split(//).map { |char| @map[:decrypt][char] }.join
end
end
# pass the shuffled version to the cipher
cipher = Cipher.new ["K", "D", "w", "X", "H", "3", "e", "1", "S", "B", "g", "a", "y", "v", "I", "6", "u", "W", "C", "0", "9", "b", "z", "T", "A", "q", "U", "4", "O", "o", "E", "N", "r", "n", "m", "d", "k", "x", "P", "t", "R", "s", "J", "L", "f", "h", "Z", "j", "Y", "5", "7", "l", "p", "c", "2", "8", "M", "V", "G", "i", " ", "Q", "F"]
msg = "howdy pardner"
crypted = cipher.encrypt msg
crypted # => "1IzXAF6KWXvHW"
decrypted = cipher.decrypt crypted
decrypted # => "howdy pardner"
If you don't need real encryption, you can use a simple cipher. (This can be used when you don't need security, or to encrypt short random/one-off strings.)
ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
#generated with ALPHABET.split('').shuffle.join
ENCODING = "MOhqm0PnycUZeLdK8YvDCgNfb7FJtiHT52BrxoAkas9RWlXpEujSGI64VzQ31w"
def encode(text)
text.tr(ALPHABET, ENCODING)
end
def decode(text)
text.tr(ENCODING, ALPHABET)
end
Optional method for encryption and decryption
gem 'activesupport'
require 'active_support'
key = SecureRandom.random_bytes(32)
crypt = ActiveSupport::MessageEncryptor.new(key)
encrypted_data = crypt.encrypt_and_sign("your password")
password = crypt.decrypt_and_verify(encrypted_data)
For basic encoding/decode purpose I guess ruby's inbuilt Base64 library can be handy:
2.2.1 :001 > require 'base64'
=> true
2.2.1 :002 > str = "[email protected]"
=> "[email protected]"
2.2.1 :003 > Base64.encode64(str)
=> "YWJjQGV4YW1wbGUuY29t\n"
It also has the urlsafe version methods in case the encoded strings are to be used in urls.
Reference: http://ruby-doc.org/stdlib-2.3.0/libdoc/base64/rdoc/Base64.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With