joeforker
joeforker

Reputation: 41817

Which "good" block encryption algorithm has the shortest output?

I would like to give customers a random-looking order number but use 0, 1, 2, ... in the backend. That way the customer gets a non-password-protected order status URL with the encrypted order number and they cannot look at other customers' order numbers by adding or subtracting 1. This might replace a scheme where random order keys are generated, checked for uniqueness among all the previous orders, and re-generated until unique. When the web server gets a request to view an order, it decrypts the order number and retrieves the order.

To keep the URL short, what "good" encryption algorithm has the shortest block size? Is this scheme a good idea? (What if I was encrypting Apple, Inc. employee ids to keep Steve Jobs from asking for Employee #0?)

Observe that all the package tracking websites allow you to track packages without authentication. It would be fine to limit the amount of information shown on the password-free order status page.

Upvotes: 20

Views: 9332

Answers (7)

gertas
gertas

Reputation: 17145

Recently I started using Hashids set of small libraries. The idea is to encrypt a number or list of numbers into hashed string like:

12345 => "NkK9"
[683, 94108, 123, 5] => "aBMswoO2UB3Sj"

The libraries are implemented in popular programming languages by various authors. They are also cross-compatible, which means you can encode the number in Python and then decode it JavaScript. It supports salts, alphabet definition and even exclusion of bad words.

Python:

hashids = Hashids(salt="this is my salt")
id = hashids.encode(683, 94108, 123, 5)

JS:

var hashids = new Hashids("this is my salt"),
numbers = hashids.decode("aBMswoO2UB3Sj");

This is not govt proof encryption but totally sufficient for some non-predictable permalink sharing sites.

Upvotes: 4

Adam M.
Adam M.

Reputation: 189

Issues of whether you should actually be doing this aside, here's a very simple block cipher with a fixed key (since you only seem to need one permutation anyway).

static uint permute(uint id)
{
  uint R = id & 0xFFFF, L = (id>>16) ^ (((((R>>5)^(R<<2)) + ((R>>3)^(R<<4))) ^ ((R^0x79b9) + R)) & 0xFFFF);
  R ^= ((((L>>5)^(L<<2)) + ((L>>3)^(L<<4))) ^ ((L^0xf372) + L)) & 0xFFFF;
  return ((L ^ ((((R>>5)^(R<<2)) + ((R>>3)^(R<<4))) ^ ((R^0x6d2b) + R))) << 16) | R;
}

Skip32 is much better as far as 32-bit block ciphers go, but it's a bit heavyweight when three (long) lines would do. :-)

Upvotes: 2

joeforker
joeforker

Reputation: 41817

I prototyped this idea using Blowfish, a block cipher with 64-bit blocks.

Upvotes: 1

Liudvikas Bukys
Liudvikas Bukys

Reputation: 5870

If your idea is that just knowing the order number (or URL) is enough to get information on the order then:

  • The order number space needs to be extremely large, otherwise attackers and/or customers will conceivably search the order space, to see what can be seen.
  • You should consider that an attacker may launch gradual probing from numerous machines, and may be patient.
  • Probing the order number space can be mitigated by rate limiting, but that's very hard to apply in a web environment -- it's hard to distinguish your customer access from attacker access.
  • Consider also that the order number is not much of a secret, people could be sending around in emails; once it's out, it's impossible to retract.

So, for the convenience of one-click check-my-order-without-logging-in, you have created a permanent security risk.

Even if you make the order number space huge, you still have the problem that those URLs are floating around out there, maybe in possession of folks who shouldn't have gotten them.

It would be much much better to require a login session in order to see anything, then only show them the orders they're authorized to see. Then you don't have to worry about hiding order numbers or attackers guessing order numbers, because just the order number isn't enough information to access anything.

Upvotes: 4

MichaelGG
MichaelGG

Reputation: 10006

Most block ciphers are going to use larger than 32-bit sized blocks, for security reasons.

However, I found one that is made specifically for what you are doing: Skip32

You may consider using a GUID, but perhaps you have reasons you want to avoid that. (Say, your app is done already.)

Edit: Actually, if a GUID is permissible, then that gives you a range of 128 bits. You could easily use any other block cipher. The benefit to having a larger space (at the cost of long ID strings) is that you'll have much more protection from people guessing IDs. (Not that it an order ID by itself should be a security token anyways...)

Upvotes: 13

Gavin Miller
Gavin Miller

Reputation: 43855

To meet the requirement you could simply use a hash such as SHA-1 or MD5 on your indexes. These will provide the adequate security you require.

To bring down the size you can change to a different encoding; such as 64 bit.

I'd also very strongly recommend insist on using a salt, otherwise the hash values could easily be broken.

Upvotes: 0

Bob
Bob

Reputation: 99814

I don't think this scheme is that great of an idea. Why aren't you verifying that a user is logged in and has access to view a specified order?

If you REALLY want to just have all orders out there without any authentication, a GUID would be best.

Or, you could try to come up with order numbers prefixed with something about the customer. Like (PhoneNumber)(1...100)

Upvotes: 0

Related Questions