Skip to content

Instantly share code, notes, and snippets.

@billdueber
Last active December 10, 2015 19:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save billdueber/4484735 to your computer and use it in GitHub Desktop.
Save billdueber/4484735 to your computer and use it in GitHub Desktop.
Packing a bunch of ids into an encrypted string for use in a URL -- just some experiments. Driven by https://bibwild.wordpress.com/2013/01/07/crazy-use-of-encryption-to-protect-refworks-callback-urls/
# Packing a bunch of ids into an encrypted string for use in a URL -- just some experiments.
# Driven by https://bibwild.wordpress.com/2013/01/07/crazy-use-of-encryption-to-protect-refworks-callback-urls/
# A quick experiment to look at how many ids of various types we can crust into a
# encrypted string. Obviously we could be more particular about how we pack them in
# if we know the characteristics of the IDs ahead of time.
require 'stringio'
require 'zlib'
require 'random'
require 'encryptor' # not part of stdlib; will have to install the gem
require 'base64'
# Generate a random list of IDs of the given length
# so we have something to mess with. This is just a simple,
# comma-delimited list of ids; we're not doing anything smart at all.
def idlist(size = 100, idlength=9, allow_alpha=false)
a = {}
r = Random.new # re-seed
if allow_alpha
anum = [(0..9).to_a, ('A'..'Z').to_a, ('a'..'z').to_a].flatten
else
anum = [0,1,2,3,4,5,6,7,8,9]
end
while a.size < size
x = []
idlength.times do
x << anum[r.rand(anum.size)]
end
a[x.join('')] = 1
end
return a.keys.join(',')
end
# Simple helpers to do gzipping
def gz(str)
s = StringIO.new
gz = Zlib::GzipWriter.new(s)
gz.write str
gz.close
return s.string
end
# ...and encryption
@secret_key = Digest::SHA256.hexdigest('generating the secret key with this text')
def ec(str)
el = Encryptor.encrypt(str, :key=>@secret_key)
return el
end
# Pull it all together: gzip, then encrypt, then base64 encode
def bstring(str)
Base64.encode64(ec(gz(str)))
end
# Wrap it up nicely
def composed_list(size, idlength, allow_alpha=false)
return bstring(idlist(size, idlength, allow_alpha))
end
# Reverse the process to get the original list back again
def decomposed_list(str)
unb64 = Base64.decode64(str)
uncrypt = Encryptor.decrypt(unb64, :key=>@secret_key)
return Zlib::GzipReader.new(StringIO.new(uncrypt)).read
end
# How big are they? We need to know how many bytes these things take up so we know
# roughly how many ids we can stuff into a URL. The size is affected most significantly
# by how efficiently gzip can compress the list; you see this in the differences between
# the straight-numeric and alpha-numeric IDs.
def compare_sizes(sizes_to_compare = [10, 25, 50, 75, 100, 125, 150, 175,200, 225, 250])
puts "\nSizes (in bytes) for a list of ids of various lengths, numeric-only or alpha-numeric"
puts "after gzip/encrypt/base64 encoding (i.e., ready to include in a URL)"
puts '\n%3s %5s %5s %5s %7s %7s %7s' % ['IDs', '8num', '9num', '10num', '8alpha', '9alpha', '10alpha']
sizes_to_compare.each do |ids|
a = [ids]
a << composed_list(ids, 8).size
a << composed_list(ids, 9).size
a << composed_list(ids, 10).size
a << composed_list(ids, 8, true).size
a << composed_list(ids, 9, true).size
a << composed_list(ids, 10, true).size
puts '%3d %5d %5d %5d %7d %7d %7d' % a
end
puts "\n"
end
compare_sizes()
Sizes (in bytes) for a list of ids of various lengths, numeric-only or alpha-numeric
after gzip/encrypt/base64 encoding (i.e., ready to include in a URL)
IDs 8num 9num 10num 8alpha 9alpha 10alpha
10 110 131 131 155 175 196
25 196 220 240 305 326 350
50 350 391 415 521 566 631
75 501 566 610 741 826 891
100 651 716 806 956 1066 1172
125 826 911 1001 1196 1326 1432
150 956 1066 1172 1412 1562 1717
175 1131 1261 1367 1627 1822 1997
200 1281 1432 1586 1867 2062 2278
225 1456 1607 1782 2083 2323 2562
250 1607 1782 1952 2302 2562 2823
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment