<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Alice, Bob, and Mallory: Blowfish in the URL</title>
    <link>http://www.alicebobandmallory.com/articles/2007/11/15/blowfish-in-the-url</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>metasyntactics</description>
    <item>
      <title>Blowfish in the URL</title>
      <description>&lt;p&gt;Sometimes you do not want to show the database id for a row in the URL. The reason could be that you do not want someone to be able to scan through all the data.&lt;/p&gt;

&lt;p&gt;One solution is to use &lt;a href="http://en.wikipedia.org/wiki/Globally_Unique_Identifier"&gt;GUID's&lt;/a&gt; but they have drawbacks and one of them is that they add a considerable length to the URL. The shortest URL-safe representation of a GUID I've seen is &lt;a href="http://tools.assembla.com/breakout/wiki/FreeSoftware"&gt;22 characters&lt;/a&gt; but usually they are 36 characters.&lt;/p&gt;

&lt;p&gt;Depending on how your id's are implemented a much shorter way could be to simply to encrypt them.&lt;/p&gt;

&lt;p&gt;Here's a &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt;-example that Blowfish encrypts, Base64 encodes and URL-encodes an integer value. You can get crypt as a gem:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gem install crypt&lt;/code&gt;&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;require &lt;span style="background-color:#fff0f0;color:#D20"&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;span style=""&gt;rubygems&lt;/span&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span style="background-color:#fff0f0;color:#D20"&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;span style=""&gt;crypt/blowfish&lt;/span&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span style="background-color:#fff0f0;color:#D20"&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;span style=""&gt;Base64&lt;/span&gt;&lt;span style="color:#710"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;blowfish = &lt;span style="color:#036;font-weight:bold"&gt;Crypt&lt;/span&gt;::&lt;span style="color:#036;font-weight:bold"&gt;Blowfish&lt;/span&gt;.new(&lt;span style="background-color:#fff0f0;color:#D20"&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;span style=""&gt;A key up to 56 bytes long&lt;/span&gt;&lt;span style="color:#710"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;plainId=&lt;span style="color:#00D;font-weight:bold"&gt;123456&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;encrypted = blowfish.encrypt_block(plainId.to_s.ljust(&lt;span style="color:#00D;font-weight:bold"&gt;8&lt;/span&gt;))&lt;tt&gt;
&lt;/tt&gt;idForURL = &lt;span style="color:#036;font-weight:bold"&gt;URI&lt;/span&gt;.escape((&lt;span style="color:#036;font-weight:bold"&gt;Base64&lt;/span&gt;.encode64(encrypted).strip))&lt;tt&gt;
&lt;/tt&gt;decryptedId = blowfish.decrypt_block(  &lt;tt&gt;
&lt;/tt&gt;                          &lt;span style="color:#036;font-weight:bold"&gt;Base64&lt;/span&gt;.decode64(  &lt;tt&gt;
&lt;/tt&gt;                          &lt;span style="color:#036;font-weight:bold"&gt;URI&lt;/span&gt;.unescape(idForURL))).&lt;tt&gt;
&lt;/tt&gt;                          strip.to_i&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;&lt;br&gt;
The .ljust(8) is because &lt;a href="http://www.schneier.com/blowfish.html"&gt;Blowfish&lt;/a&gt; is a 64-bit block &lt;a href="http://en.wikipedia.org/wiki/Blowfish_(cipher)"&gt;cipher&lt;/a&gt; and the &lt;a href="http://crypt.rubyforge.org/"&gt;Ruby-implementation&lt;/a&gt; does not pad the data itself.&lt;/p&gt;

&lt;p&gt;The id in the URL in this case would be &lt;code&gt;c2PSXWgky40=&lt;/code&gt;. Its 12 characters long (11 if you skip the equal sign) and that's 10 or 24 characters shorter than a GUID. Also there is zero percent chance of collusion and if you want to you can even decrypt it.&lt;/p&gt;

&lt;p&gt;This is not a super safe implementation but if you start your id's at a random and not too low number you are making it a bit harder for someone to crack the 56-bit key. Actually a truly random and at least 64-bit big number would be a better choice as it would have no connection to the true id at all. You would have to check for uniqueness before storing those in the database though.&lt;/p&gt;</description>
      <pubDate>Thu, 15 Nov 2007 22:38:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:9071a4d1-aaf0-4f17-a796-4ecd65976d64</guid>
      <author>Jonas Elfström</author>
      <link>http://www.alicebobandmallory.com/articles/2007/11/15/blowfish-in-the-url</link>
      <category>Security</category>
      <category>Ruby</category>
      <category>Cryptography</category>
    </item>
  </channel>
</rss>

