get hexadecimal hash string for a number

M

Magnus Warker

Hi,

I want users to register on a site and send confirmation emails to them.
These emails should contain a link like this:

http://myurl?registration=E4AC4BD4

Here, "E4AC4BD4" should be a unique string. My idea for such a string is
just to hash an integer, i. e. the internal database key for the
registration record.

However, I actually don't know how to get such a hash. I tried BCrypt,
but this produces hashes built out of characters that I would not want
to be in a URL, e. g. commatas and that.

I would like to have a string like this:

- hexadecimal only
- fixed size, e. g. always n characters, independend of the integer

Can you help?

Thank you!

Magnus
 
M

markspace

L

Lew

Magnus said:
I want users to register on a site and send confirmation emails to them.
These emails should contain a link like this:

http://myurl?registration=E4AC4BD4

Here, "E4AC4BD4" should be a unique string. My idea for such a string is
just to hash an integer, i. e. the internal database key for the
registration record.

However, I actually don't know how to get such a hash. I tried BCrypt,
but this produces hashes built out of characters that I would not want
to be in a URL, e. g. commatas and that.

I would like to have a string like this:

- hexadecimal only
- fixed size, e. g. always n characters, independend of the integer

Can you help?

First of all, hashing a unique integer is silly. It's already unique!

If you have a reliably unique, stable integer ID, you don't need to hash it!

Just use the value.

Got that? Good, because an internal database ID is not reliable.
It's *internal*! It's not meant to be used externally!

Got that? Good, because the database record has (or you're not doing it
right) an external unique key, one based on visible attributes. You could
hash that key.

Or you could perhaps use
http://docs.oracle.com/javase/7/docs/api/java/rmi/server/UID.html

You'll want to store that UID with the registration record.

First and foremost google around for hash codes and how to use them.
Your lack of understanding will screw you otherwise.
 
A

Arne Vajhøj

<http://docs.oracle.com/javase/7/docs/api/java/util/UUID.html>

I think UUID is better, as it is more random than just an integer, and
I'm pretty sure it uses a hexadecimal representation, so you can just
use it as-is. Make a new one, call toString, and you're ready to go.

It meets the stated requirements of being unique.

But the original poster most likely have a requirement he
forgot to mention: that it should be hard to guess as well.

The point of emailing a confirmation link is to ensure that the
registrant indeed own the email address.

If the link is guessable then there is no point.

UUID's are not intended to be cryptographic secure, so they
are not the right toll for the job.

The correct approach is to use a cryptographic secure
RNG to generate a number of random bytes.

Being slightly paranoid I will recommend generating
maybe 100 bytes and do a SHA-256 of that just to
protect against weaknesses.

It does not cost much coding or many resources runtime, so
I can not see any reason to not do it the right way.

Arne
 
A

Arne Vajhøj

First of all, hashing a unique integer is silly. It's already unique!

If you have a reliably unique, stable integer ID, you don't need to hash it!

Just use the value.

The real issue for the confirmation link problem is not
uniqueness but that it has to be hard to guess.

Which changes the solution quite a bit.

Arne
 
A

Arne Vajhøj

I want users to register on a site and send confirmation emails to them.
These emails should contain a link like this:

http://myurl?registration=E4AC4BD4

Here, "E4AC4BD4" should be a unique string. My idea for such a string is
just to hash an integer, i. e. the internal database key for the
registration record.

However, I actually don't know how to get such a hash. I tried BCrypt,
but this produces hashes built out of characters that I would not want
to be in a URL, e. g. commatas and that.

I would like to have a string like this:

- hexadecimal only
- fixed size, e. g. always n characters, independend of the integer

Use a secure RNG (java.security.SecureRandom) to generate 100 random bytes.

Convert it to 32 bytes with SHA-256 (java.security.MessageDigest).

And convert it to 64 hex characters.

Done.

Arne
 
M

markspace

The correct approach is to use a cryptographic secure
RNG to generate a number of random bytes.


I looked up"cryptographic secure" on Wikipedia, and I have to disagree.
The key he's sending is going out as plain text. Cryptographically
secure RNGs are used to generate keys, you never reveal your seed value
or there's no point to the keys either. The UUID is plenty hard to
guess; using a hard-to-guess value that you then send out as plain text
isn't going to improve your security.

Also, there's human factors to consider as well. "Fake" but valid email
addresses are plenty easy to generate. If someone really wants to use a
bogus address, they just make one, get the link you send them, and then
ignore the email address after that. This whole process is easy to
automate. Hundreds or thousands of fake ID per day can be generated
this way. "Cryptographically secure" doesn't mean much when Alice and
Mallory are the same person. In this case the human factor is a coder
who thinks "cryptographically secure" is going to solve some problem
when it won't.

If you can show me how UUIDs are "easy to guess," I might retract my
statements somewhat.
 
M

markspace

Use a secure RNG (java.security.SecureRandom) to generate 100 random
bytes.


And UUID uses SecureRandom internally to generate its values, so this is
bogus advice. Sorry, Arne, but you really should have checked before
you posted.
 
A

Arne Vajhøj

And UUID uses SecureRandom internally to generate its values,

In that case UUID is good.
so this is
bogus advice. Sorry, Arne, but you really should have checked before
you posted.

Maybe.

But UUID is not a Java specific concept and in general UUID's are
not guaranteed to be hard to guess values.

It turns out that Java UUID support two types of UUID's - of which
one of them per Java doc is using a "cryptographically strong
pseudo random number generator".

I was not aware.

Arne
 
A

Arne Vajhøj

I looked up"cryptographic secure" on Wikipedia, and I have to disagree.
The key he's sending is going out as plain text. Cryptographically
secure RNGs are used to generate keys,

Yes and no.

A cryptographic secure RNG is really just an RNG that produces
values that are hard/impossible to predict.

It has an obvious usage for generating cryptography keys.

But it also has other usages.

Hard to guess id's are one of the other.
you never reveal your seed value
or there's no point to the keys either. The UUID is plenty hard to
guess; using a hard-to-guess value that you then send out as plain text
isn't going to improve your security.

It solves the problem it is intended to solve.

The purpose of a confirmation email with a link with such an
id is to verify that the owner of the email account is indeed
the one registering.

You can not ensure that if it is possible for the registering
person to guess the id.

It need to be hard to guess.

Which is what a cryptographic secure RNG provide.
Also, there's human factors to consider as well. "Fake" but valid email
addresses are plenty easy to generate. If someone really wants to use a
bogus address, they just make one, get the link you send them, and then
ignore the email address after that. This whole process is easy to
automate. Hundreds or thousands of fake ID per day can be generated
this way. "Cryptographically secure" doesn't mean much when Alice and
Mallory are the same person. In this case the human factor is a coder
who thinks "cryptographically secure" is going to solve some problem
when it won't.

That is not relevant for what we are discussing.

We are discussing how to send out confirmation emails with links.

Whether that idea brings value or not is another question.

Arne
 
A

Arne Vajhøj

If you can show me how UUIDs are "easy to guess," I might retract my
statements somewhat.

UUID's type 1, 2 and 3 are not random at all.

UUID's type 4 is random but if it is not a cryptographic
secure RNG then it is vulnerable. And if it is something
trivial like a 32 bit LCG then it is trivial to break.

Arne
 
K

Kevin McMurtrie

Magnus Warker said:
Hi,

I want users to register on a site and send confirmation emails to them.
These emails should contain a link like this:

http://myurl?registration=E4AC4BD4

Here, "E4AC4BD4" should be a unique string. My idea for such a string is
just to hash an integer, i. e. the internal database key for the
registration record.

However, I actually don't know how to get such a hash. I tried BCrypt,
but this produces hashes built out of characters that I would not want
to be in a URL, e. g. commatas and that.

I would like to have a string like this:

- hexadecimal only
- fixed size, e. g. always n characters, independend of the integer

Can you help?

Thank you!

Magnus

You can't use a 32 bit integer here. Valid values would quickly become
easier to guess as you add users.

1) Use SecureRandom to generate a string of link-safe characters.
2) Insert the key into the database
3) Send the link


Base64 will work well for step one. Base 64 encodes sets of 3 bytes
into sets of 4 characters. You'll want 9 SecureRandom bytes generating
a 12 character id.


Should step two give you a unique key violation, buy a lottery ticket
using the numbers. If you don't retire on the winnings, make sure that
SecureRandom doesn't have a stupid implementation in your JVM. You can
find it with the debugger.
 
M

Magnus Warker

Magnus Warker wrote:
First of all, hashing a unique integer is silly. It's already unique!
First and foremost google around for hash codes and how to use them.
Your lack of understanding will screw you otherwise.

As Arne guessed, I should have said "encrypt" instead of "hash". You
could also guess this, but I think you didn't want to.

Magnus
 
M

Magnus Warker

Hi Arne!

The correct approach is to use a cryptographic secure
RNG to generate a number of random bytes.

What about encrypting the database key?
Being slightly paranoid I will recommend generating
maybe 100 bytes and do a SHA-256 of that just to
protect against weaknesses.

If we are paranoid, we should also remember the uniqueness requirement.
"Random" could be a problem here.
It does not cost much coding or many resources runtime, so
I can not see any reason to not do it the right way.

I am sure that your approach will do the job. Thanks!

But I would like to know if encrypting the database key would also be
ok. Can we encrypt it and also ensure a fixed-length hex value?

Magnus
 
A

Arne Vajhøj

What about encrypting the database key?

That relies on the key being kept secret.

In many cases this is a necessary requirement, but not
in this case, so I would say that it is second best option.

And since Java UUID do provide a way to generate using
a cryptographic secure RNG as markspace pointed out, then it
it is even simpler to code than I expected (not that SecureRandom
is that hard to use in the first place).
If we are paranoid, we should also remember the uniqueness requirement.
"Random" could be a problem here.

If you make the column unique in the database then you will get an error
inserting and can then just pick another.

It will happen at average 1 out of some billion/trillion years, so
I think you can live with that.
I am sure that your approach will do the job. Thanks!

But I would like to know if encrypting the database key would also be
ok. Can we encrypt it and also ensure a fixed-length hex value?

You can sure pad and encrypt.

But as explained above then I think it is just the second best
option.

Arne
 
K

Kevin McMurtrie

Magnus Warker said:
Hi Arne!



What about encrypting the database key?


If we are paranoid, we should also remember the uniqueness requirement.
"Random" could be a problem here.


I am sure that your approach will do the job. Thanks!

But I would like to know if encrypting the database key would also be
ok. Can we encrypt it and also ensure a fixed-length hex value?

Magnus

What is your database key?

If it's 1, 2, 3, 4, ... then encrypting it will simply reveal your
encryption key. If characters aren't efficient for your keys, simply use
a translation table between the random and sequential values. Use the
randomized value as a database key on all traffic leaving and entering
your server. It prevents the public from guessing new database keys.

create table urlparams
{
param char(16) primary key,
id integer unique not null references main_table (id)
}
-- param is the outside database key made of random characters
-- id is the local primary key

create table main_table
{
id integer primary key,
...
}

create table other_table
{
id integer primary key references main_table (id),
...
}

create table more_table
{
id integer primary key references main_table (id),
...
}

You fetch all your table data together efficiently in one join:

select ... from main_table, other_table, more_table, urlparams
where
urlparams.param=?
and urlparams.id=main_table.id
and urlparams.id=other_table.id
and urlparams.id=more_table.id
 
M

Magnus Warker

As has been pointed out, integers are already unique. Just decide on
a large enough fixed size and zero pad the small numbers:
0000000000001
If you want to disguise the actual number you are using, which is what
I take your mention of "hash" to mean, then you need an encryption.
Each unique input gives a unique output. It has to be unique,
otherwise you couldn't decrypt it reliably.

What about Kevin's posting? He noted that encrypting sequential numbers
would reveal the encryption key?
For 64 bit numbers, just use DES and encrypt the numbers 0, 1, 2, 3,
... n in turn. For 128 bits use AES.

Could you please explain this? I haven't used encryption in Java, but I
would expect that the encryption method should be independend of the
size of the data to encrypt?
Again, you will need to be sure that your chosen bit size will
acommodate enough users, with plenty to spare for keeping the gaps
numerous enough.

Well, I would simply choose the size of SQL standard integer (64)...

Magnus
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top