Does it mean....
Henry Yick, February 17, 2004 - 4:13 am UTC
that this is a complex version of checksum/CRC. And there is chance to have different username/password with the same hash result, but the possibility is so little that can be ignored? Just want to calify.
February 17, 2004 - 8:21 am UTC
md5 checksums are cryptographic checksums. google it to find out about it.
yes,
scott with password tiger
could be the same as
bob with password monster
but the odds are pretty darn small and not really relevant. Having access to the hash is useless. You need a pair of strings that get to the hash. even if everyone has the SAME hash -- it would be "perfectly acceptable and OK" -- since all you know is the username and it takes
f(username,password) = hash
having the hash doesn't tell you squat.
APPS 11i use hashing?
RK, February 18, 2004 - 11:21 am UTC
Hi Tom,
Thanks for the above info.
Oracle apps 11i users have ids and pwds. Are these pwds hashed or encrypted and stored in the database? I had read somewhere that they're encrypted.
Thanks,
RK
February 18, 2004 - 9:19 pm UTC
you know, i don't know. i don't really touch apps myself. never really looked into it.
Jack, February 18, 2004 - 11:30 am UTC
I suppose md5 is an open standard with a public known algorithm, and no key required, right?
And second, it's possible that hash(scott, tiger) = hash(scott, cookies), there should have more than 1 (and much more) password for the same username to have the same hash result. That's mean either scott/tiger or scott/cookies can successfully logon to oracle. Is that true?
If so, is it possible for somebody who know the md5 algorithm to reverse the logic and generate a 'password' from the hash and username. This is not necessary the real password of that user, just one of the possible password. Then I can use this 'password' to login to that user....
I know that shouldn't be the fact. But where is the trick?
February 18, 2004 - 9:22 pm UTC
first - yup
second the hash function maps into a pretty darn large space, the odds are 1 in millions or billions.. yes, there is a chance even in oracle, unix, others that use this technique -- but it is so small as to be "not realistic".
knowledge of the hashing algorith won't help you (unless the hash is "trivial" which md5 is not)
Unlikely ;-)
Invisible, February 19, 2004 - 7:50 am UTC
Just to add to what Tom already said...
Hash functions are SPECIALLY DESIGNED to be very very VERY hard to reverse. This is design goal #1. (Design goal #2 is to make it really unlikely that any two things will ever have the same hash.)
The MD5 algorithm is here:
</code>
http://www.faqs.org/rfcs/rfc1321.html
MD5 produces a 128 bit hash value. That is, there are 2^128 different possible output values.
Is 2^128 big?
Look at this:
2^10 = one thousand (approx)
2^20 = one million
2^30 = one thousand million
2^40 = one billion (1 + 12 zeros)
2^50 = one thousand billion (1 + 15 zeros)
2^60 = one million billion (1 + 18 zeros)
...
2^120 = (2^60) x (2^60) = (one million billion) x (one million billion) = one billion billion billion. (1 + 36 zeros)
2^121 is TWICE AS BIG as 2^120.
2^122 is TWICE AS BIG as 2^121.
Get the picture? It's a BLOODY BIG NUMBER! :-)
In fact, 2^128 is a 38 digit number! To be exact, it is approximately
340,282,366,920,938,463,463,374,607,430,000,000,000
(as near as the standard Windows Calc.exe program will tell me)
To give you some idea of the vastness of this number, imagine 12 grams of carbon (i.e., a small lump of coal). The number of individual atoms in that is 6.022 x 10^23. In other words, roughly 6 followed by 23 zeros.
Using this, you can calculate that 2^128 carbon atoms would weigh
565,065,372 tonnes (!!!)
Think about how unimaginably TINY a single atom is, and how many trillions of them fit on a pinhead. NOW think about how HUGE 500 megatonnes is...
It's so huge it's beyond imagination... beyond comprehension!
SO, the number of possible MD5 hash values is equal to the number of atoms in 500 megatonnes of carbon. Finding two things with the same hash isn't so much "finding a needle in a haystack" as "finding a single atom in [literally] a MOUNTAIN of carbon"!
In practice, the only way somebody can get from a hash value back to the original password is to just try every password you might have used, put it through the same hash function, and see if the result matches your password hash. It takes a LONG time.
Of course, with the system Tom suggests, it doesn't MATTER if the password they find really is your password or just hashes to the same thing. However, we already said a hash function is designed so that it's highly unlikely (virtually impossible) to find anything else with the same hash!
In practice, you will usually find that any OTHER text that hashes to the same thing as your password would be
-> very very much longer
and / or
-> not printable ASCII
Chances of two SHORT, PRINTABLE text strings giving the same hash value are TINY. It's one of the design goals of the hash function. And MD5 has been around long enough to have been analysed and tested by SO many experts, I think we can safely say it does that it's supposed to very well indeed.
Just my comments :-)
[Tom - you're welcome to add all or some of this to
http://asktom.oracle.com/~tkyte/Misc/Passwords.html <code>if you feel inclined.]
PS. Guess what MY hobby is. ;-)
PPS. It took me all morning to reasurch this. It would not have been possible without the Google search engine - www.google.com
PPPS. Tom is great!
February 19, 2004 - 11:23 am UTC
forget windows "calc" ;)
ops$tkyte@ORA920PC> set numformat 999999999999999999999999999999999999999999999
ops$tkyte@ORA920PC> select power(2,128) from dual;
POWER(2,128)
----------------------------------------------
340282366920938463463374607431768211456
Wow
Invisible, February 19, 2004 - 11:30 am UTC
Wow... you can do that??? :-D
Now make it print a comma every 3 digits :-P
(Sheesh... I wonder what the hell else Oracle can do... I assumed it would have limited precition arithmatic only. Certainly had enough weird rounding errors last time I tried to use it...)
February 19, 2004 - 11:47 am UTC
you won't have any wierd rounding errors with Oracle numbers -- they are built to be extremely precise in that fashion -- 38 digits precise in fact. they are like BCD or packed decimal. Much more precise than a float or double.
they were built to count pennies accurately.
please add salt
A. Reader, February 19, 2004 - 10:58 pm UTC
In order to prevent dictionary based attacks, add salt to it:
salt = random_number()
hash = md5(salt || user || password)
and store salt and hash in the database.
February 20, 2004 - 7:24 am UTC
hmm, interesting.
but -- tell me -- how do you validate an input username/password pair later? You don't know what the salt was.
The salt has to be a fixed (semi-secret) value. even if not secret, it's OK, attacking a hash is a computationally "big" thing to do.
"they were built to count pennies accurately. "
Connor, February 20, 2004 - 2:54 am UTC
Yes I do believe "NUMBER(38)" was built by Oracle as a response to their license costs
:-)
February 20, 2004 - 7:39 am UTC
dude, thats so harsh ;)
Indeed
Invisible, February 20, 2004 - 5:01 am UTC
...and 38 digits is EXACTLY how many there are in 2^128 :-D
(Flukey or what? ;-)
BCD eh? Interesting... Oh, wait a sec - 1/10 is a recurring sequence as in binary, so can't be exactly represented. Mmm, a datbase that can't store 10p exactly wouldn't be terribly good. I guess that's why it's BCD then! :-)
As for my comment about rounding errors... don't want to get into a huge debate. I don't have the source code that experienced the problem, so it would be a rather factless ( = pointless) debate.
Basically for a project I had to develop a database that could store some 2D lines (easy), and tell me which lines cross each other (harder). In one of my test cases, two lines that overlapped were reported as NOT intersecting; but if I translated both back towards the origin by the same amount, suddenly the software said they DID overlap!
Of course, now I don't have the code any more, no way of telling whether Oracle did that or whether I fluffed up the code, so let's leave it there.
Coming back round to the original topic of this thread... the other poster's suggestion to add salt is a good one.
Basically someone might build a great long list of plausible ASCII sequences that someone might use for a password. (i.e., all possible combinations of common printable characters). They could then calculate the hash of each such sequence, and store these all in a massive [Oracle? ;-)] database.
Then when it comes to figuring out a user's password from the hash, they just compare the hash to all the values in their database. Pointless to do it this way for just one password - the amount of effort is the same. But for groups of passwords, this approach can make it a lot faster to break some of them.
Of course, this little "short cut" totally masses up if the thing that was hashed isn't in the attacker's database. So if you add random (non-printable ASCII) salt to the user's password, then the complete thing won't be in the attackers database - unless they include ALL possible strings, not just printable ones. And that makes the database several times larger, increases the time needed to compute all the hashes several times over, increases the time needed to find things several times over, etc.
In short, adding salt makes it that little bit harder to anyone wanting to break in. (Well, actually quite a lot harder...) It also makes it very slightly more complicated for you to code - but it's probably worth it! :-)
A reader, February 20, 2004 - 1:25 pm UTC
"You don't know what the salt was.
The salt has to be a fixed (semi-secret) value."
So you just embed your salt value into your PL/SQL hash function and then use that "magical PL/SQL wrapping thing" to obfuscate the function itself. :)
February 20, 2004 - 1:32 pm UTC
correct -- but in 9i and before make sure to obscure the code a bit -- else a variable define in code is very plain in the wrapped code.
use
salt := chr(23) || chr(54) || ....;
don't use
salt := 'some magic salt';
Very well explained
Beginner, February 20, 2004 - 3:25 pm UTC
But when I try to execute it, I get following error:
[1]: (Error): ORA-06553: PLS-307: too many declarations of 'MD5' match this call
February 20, 2004 - 3:27 pm UTC
yeah, they have a 'bad' overload in there (raw and varchar2).
dbms_obfuscation_toolkit.md5( INPUT_STRING => 'blah' );
^^^^^^^^^^^^^^^
will help it out.
But listener password hashes are not so secure
David Taitano, March 16, 2004 - 2:50 pm UTC
If you don't have the password for the TNS listener, just get the hash from listener.ora and use it, instead -- oracle accepts it as if it were the password! I have noticed this behavior in multiple versions of Oracle.
The only apparent way to protect the listener password is to secure the permissions on the listener.ora file, but this seems pretty weak.
March 16, 2004 - 3:56 pm UTC
they have changed this behaviour in 10g - but, it is all about access (think "/etc/shadow" for example, to prevent offline cracks). that file needs to be locked down regardless.
about salt :)
Zsolt Müller, March 16, 2004 - 6:10 pm UTC
Salt ... no meal can be made without it. ;))
That's for the joke. :)
"Salt" is used when it comes to store password hashes in a more "secure" way. It's purpose is not to make the hash more "secret", but to make it harder for an attacker to mass-decode passwords. :)
Look at it like this:
- user passwords are usually stored "together" ... in "one place" (in Unix/Linux it is a single file, in Oracle it is a single table, etc. ... the point is that an attacker usually gains access to a big collection of stored password hashes and not only to a single one)
- if you take the username+plain_password as the input of the hash function, one could "easily" make a big list with all the common (username+password/hash) pairs and decode a significant part of the passwords in a quite short time (remember: users _tend_ to choose weak passwords ...)
- if you take some random data, concatenate it with the password, compute the hash, then store the random data with the hash ... the attacker's hands are bound ... she/he cannot use any precomputed list of input+hash values, since the salt multiplies the input space by millions/billions. :)
Here's how I store a password:
- generate 16 semi-random bytes (there's quite a big literature only on this part ... I mean generating random data :)) )
- pad the cleartext password with the salt to 64 bytes (MD5() is defined to run on an 512 bits long input, so I make it 512 bits long ;) ... still better if I do the padding than if Oracle's md5() does it :D )
- store the salt together with the MD5 hash value of the "padded" cleartext password in the database
The stored hash is made up like this:
stored_password := salt || md5(LPAD(cleartext_password, 64, salt));
Every stored value contains the salt in the first 16 bytes and an md5 hash in the second 16 bytes.
The password-check looks something like this:
IF md5(LPAD(incoming_cleartext_password, 64, first_half_of_stored_password)) = second_half_of_stored_password THEN
-- passwords match
RETURN true;
ELSE
-- different passwords
RETURN false;
END IF;
March 16, 2004 - 6:30 pm UTC
you've put the horse before the cart here. the magic salt is sitting right there? whats the point of that salt.
the attackers hands are not tied, they need only add the same dash of salt -- the value of which you have provided?
Guess Tom means Cart before Horse
A reader, March 17, 2004 - 12:02 am UTC
March 17, 2004 - 7:12 am UTC
doh! of course ;)
NaCl?
Invisible, March 17, 2004 - 4:29 am UTC
The "point" is that the attacker can't precompute the hashes before hand - because the salt makes the search space many millions of times bigger (depending on how much you add) and it's truely random. (The passwords aren't really. Should be, but aren't.)
You (the attacker) now can't just compute the hash of every imaginable password and match the hashes against what you've stolen; you'll get no matches, because you didn't include the salt.
Of course the salt is right there next to the password. It just means you'll have to redo all those hash calculations for EACH user you want to crack, not just once for all of them.
If the salt is right next to the hash, this is the ONLY adventage you gain. Cracking individual passwords won't be any harder, but you won't be able to take a big "short cut" to crack whole groups of passwords, that's all.
Now, if there were some way to hide the salt away somehow... that would add even more benefit. (However, if your password manager can find it, presumably it's gotta be somewhere - so an attacker can probably find it too.)
Hope that clarifies it...
March 17, 2004 - 8:09 am UTC
that point was not clear -- it doesn't make it "harder" (it is just a program), it makes it "take longer".
The normal way is to take the USERNAME/PASSWORD -- hash that. In that fashion you still cannot compute the hash of every imaginable password since the username is part of it (the username in this case is the 'salt' but it is 'salt' in the clear meaning the attacker must take a dictionary of well known passwords and hash it for each user -- increasing the time of attack measurably).
True
Invisible, March 17, 2004 - 9:21 am UTC
Well, you could argue that true salt would be random non-ASCII symbols, possible of very great length, increasing the search space even more - but yes, simply using the username achieves something comparable.
(It depends how paraniod you are - and when talking about security, people tend to get that way I guess.)
Certainly either way is better than just hasing the password alone... It also helps if you use strong passwords. Oh, and better still - if the attacher can't get the hashes in the first place! 8-D (If only it were that easy...)
What about calling it from SQL ?
Christo Kutovsky, May 05, 2004 - 11:16 am UTC
>yeah, they have a 'bad' overload in there (raw and varchar2).
>
> dbms_obfuscation_toolkit.md5( INPUT_STRING => 'blah' );
^^^^^^^^^^^^^^^
What about running from SQL ? You can't use '=>' in sqlplus. The only work arround I found was using a wrapper function. I am concerned that this could slow down things.
What would be the "good" overload ?
Also does anyone has any experience with compiling into native code dbms_obfuscation_toolkit? I will try it out soon, I was curious if anyone has already tried that?
May 05, 2004 - 2:42 pm UTC
there isn't a good overload for raw and varchar2 -- they should have named them differently (md5 and md5raw)
the wrapper will be the only option if you want to use it.
the toolkit is a big interface to C already. the plsql layer is just a wrapper to let you call C.
A reader, January 09, 2006 - 4:50 pm UTC
January 09, 2006 - 6:16 pm UTC
You mention knowing the hashing algorithm won't help but...
Darren, March 29, 2006 - 7:37 pm UTC
Peter Finnegan says in one of his presentations (available on his website) that "until recently the Oracle password algorithm was not public" - obviously meaning it is public now. He then points out that there is a tool available (orabf) which will take an Oracle generated hash and a username and brute force the cleartext password (not decrypt it - find a matching hash).
I tried it on my P4 Dell pc and it cracked our "system" user password in 23 minutes after over 1.6 billion tries (its not a dictionary word or anything easy).
Is this not possible only because the password algorithm is known? I realise that you still need access to the hash stored in the database but if you got those via SQL injection or something this tool can get you all the cleartext passwords pretty darn quickly!
Does the existance of tools like this make it mandatory for DBAs interested in security to replace the default password algorithm? Or does that have the same problem???
Cheers.
March 29, 2006 - 7:42 pm UTC
it is possible because you allowed access to your hashes - just like why we have an /etc/passwd AND an /etc/shadow - to protect the hashes.
and only if you use weak passwords. through a number into that there password and see how fast it take to crack it.
I should have read the post above!
Darren, March 29, 2006 - 9:20 pm UTC
The link you gave the previous poster pretty much explains what you mean I think. Obviously the hashes need to be protected...I misunderstood one sentence of yours and thought you were saying that even with the hashes you couldn't get a password in a reasonable time.
Thanks for your time.
This is a great thread
kr, March 30, 2006 - 11:08 am UTC
Lots of info in here ... to be used at the right time ... later