Thread: Encoding passwords
Hey everyone, Is there a function out there for pg which allows you to generate a random number given a seed value? I'm trying to create a users table which would require the storage of a password in a database field, and I'm hesitant to put it in there in plain text, despite the fact I plan to put very tight restrictions on that particular table. Ideally, I would encode each letter one by one, using the random number generator with the previous letter as a seed for the next. I was told that certain unixes use a similar way to store their passwords, and it seemed to make sense for this application. I noticed that there is a rand() function, but I'm a little slow today and couldn't think a way to use that in this scenario. Any suggestions would be greatly appreciated. Thanks Mike _________________________________________________________________ Get your FREE download of MSN Explorer at http://explorer.msn.com/intl.asp
On Tue, Sep 25, 2001 at 08:42:04AM -0400, Mike Arace <mikearace@hotmail.com> wrote: > > Is there a function out there for pg which allows you to generate a random > number given a seed value? I'm trying to create a users table which would > require the storage of a password in a database field, and I'm hesitant to > put it in there in plain text, despite the fact I plan to put very tight > restrictions on that particular table. Ideally, I would encode each letter > one by one, using the random number generator with the previous letter as a > seed for the next. I was told that certain unixes use a similar way to > store their passwords, and it seemed to make sense for this application. I > noticed that there is a rand() function, but I'm a little slow today and > couldn't think a way to use that in this scenario. Any suggestions would be > greatly appreciated. The more normal way to do this is to store a cryptographic hash of the password in the database and have the application calculate the hash and compare that to the hash in the database. This approach won't work if the database is used to store passwords for use by applications in connecting to other services. Typical cryptographic hash functions are SHA-1 and MD5 and you shouldn't have much trouble finding libraries that provide these functions.
On Tue, Sep 25, 2001 at 08:42:04AM -0400, Mike Arace wrote: > > Is there a function out there for pg which allows you to generate a random > number given a seed value? I'm trying to create a users table which would > require the storage of a password in a database field, and I'm hesitant to > put it in there in plain text, despite the fact I plan to put very tight > restrictions on that particular table. Ideally, I would encode each letter > one by one, using the random number generator with the previous letter as a > seed for the next. I was told that certain unixes use a similar way to > store their passwords, and it seemed to make sense for this application. I > noticed that there is a rand() function, but I'm a little slow today and > couldn't think a way to use that in this scenario. Any suggestions would be > > greatly appreciated. Look into contrib/pgcrypto in CVS, or http://www.l-t.ee/marko/pgsql/pgcrypto-0.3.tar.gz in meantime. Gives you crypt() function not unlike in UNIXes. Also gen_salt() for generating salts for it. -- marko
> Is there a function out there for pg which allows you to generate > a random > number given a seed value? I'm trying to create a users table > which would There is the following: "select setseed(<new seed value>);" This sets the seed for the random() function. However, the approach we use is more like the suggestion from Bruno Wolf that you received earlier- In our case we use JDBC to pass data between our application & the database, so we use the java crypt package to encrypt everything we get before it gets stored or compared to a stored value & then just compare the hash. I think his suggestion is the best way *if* your development environment supports something similar. -Nick --------------------------------------------------------------------- Nick Fankhauser Business: nickf@doxpop.com Phone 1.765.965.7363 Fax 1.765.962.9788 doxpop - Court records at your fingertips - http://www.doxpop.com/ Personal: nick@fankhausers.com http://www.fankhausers.com
I personally use encoded password= hash( concat(salt,password)), and store both the salt and the encoded password. Where hash = sha1 or md5. The DB columns are: salt, encoded password, encoding method. Note that apparently there are some cryptographic weaknesses with concatenating the salt and the password with the salt in the front, the way I did it unfortunately :). If I recall correctly, if the salt is short then attackers only need to attack a subset of the full hash. The salt being a known plaintext. So some say to concat with the salt at the back. I suspect a long salt should make the attack far less feasible, or alternatively XORed the salt with the password or maybe hash multiple times. Unfortunately I can't seem to find the original article. I haven't got around to changing my apps. It's not too bad since the fields allow for different encoding methods - for this reason I suggest you have a field to store the encoding method too. So you can have 'NONE' or 'SHA1' or 'MD5' or 'SHA1B' and so on. That said if hostile people get to the stage where they can read the encoded passwords, you're probably screwed anyway - they're likely to be able to do other things some even more undesirable. So it's not really a big deal compared to other issues. Cheerio, Link. At 08:42 AM 9/25/01 -0400, Mike Arace wrote: > >Hey everyone, > >Is there a function out there for pg which allows you to generate a random >number given a seed value? I'm trying to create a users table which would >require the storage of a password in a database field, and I'm hesitant to >put it in there in plain text, despite the fact I plan to put very tight >restrictions on that particular table. Ideally, I would encode each letter >one by one, using the random number generator with the previous letter
> I personally use encoded password= hash( concat(salt,password)), and store > both the salt and the encoded password. Where hash = sha1 or md5. > > The DB columns are: salt, encoded password, encoding method. > > Note that apparently there are some cryptographic weaknesses with > concatenating the salt and the password with the salt in the front, the way > I did it unfortunately :). If I recall correctly, if the salt is short then > attackers only need to attack a subset of the full hash. The salt being a > known plaintext. So some say to concat with the salt at the back. I suspect > a long salt should make the attack far less feasible, or alternatively > XORed the salt with the password or maybe hash multiple times. > Unfortunately I can't seem to find the original article. > > I haven't got around to changing my apps. It's not too bad since the fields > allow for different encoding methods - for this reason I suggest you have a > field to store the encoding method too. > > So you can have 'NONE' or 'SHA1' or 'MD5' or 'SHA1B' and so on. > > That said if hostile people get to the stage where they can read the > encoded passwords, you're probably screwed anyway - they're likely to be > able to do other things some even more undesirable. So it's not really a > big deal compared to other issues. > We have new code in 7.2 that will do MD5 encryption of passwords stored in pg_shadow. We add the salt to the front of the password before passing through MD5. You are suggesting putting the salt at the end. I guess the issue is that if you can get the salt part found out, you can use that to attack the password part. Also, consider that we use the username as the salt as stored in pg_shadow. We can easily put the salt in the back, but then there is the risk that a long password would not take into account the salt. My feeling that this is more a theoretical concern and we may be opening ourselves up to more problems if we make the change. Other ideas? -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
> > That said if hostile people get to the stage where they can read the > > encoded passwords, you're probably screwed anyway - they're likely to be > > able to do other things some even more undesirable. So it's not really a > > big deal compared to other issues. > > > > We have new code in 7.2 that will do MD5 encryption of passwords stored > in pg_shadow. We add the salt to the front of the password before > passing through MD5. You are suggesting putting the salt at the end. > > I guess the issue is that if you can get the salt part found out, you > can use that to attack the password part. Also, consider that we use > the username as the salt as stored in pg_shadow. We can easily put the > salt in the back, but then there is the risk that a long password would > not take into account the salt. My feeling that this is more a > theoretical concern and we may be opening ourselves up to more problems > if we make the change. OK, I have applied the following patch to the MD5 code that puts the salt at the end. We can't change the crypt() stuff because that is being used in older releases. -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026 Index: src/backend/libpq/md5.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/libpq/md5.c,v retrieving revision 1.6 diff -c -r1.6 md5.c *** src/backend/libpq/md5.c 2001/09/21 20:31:47 1.6 --- src/backend/libpq/md5.c 2001/09/27 22:23:20 *************** *** 19,24 **** --- 19,32 ---- #include "libpq/crypt.h" + #ifdef FRONTEND + #undef palloc + #define palloc malloc + #undef pfree + #define pfree free + #endif + + /* * PRIVATE FUNCTIONS */ *************** *** 289,303 **** bool EncryptMD5(const char *passwd, const char *salt, size_t salt_len, char *buf) { ! char crypt_buf[128]; ! ! if (salt_len + strlen(passwd) > 127) ! return false; ! strcpy(buf, "md5"); ! memset(crypt_buf, 0, 128); ! memcpy(crypt_buf, salt, salt_len); ! memcpy(crypt_buf+salt_len, passwd, strlen(passwd)); ! return md5_hash(crypt_buf, salt_len + strlen(passwd), buf + 3); } --- 297,315 ---- bool EncryptMD5(const char *passwd, const char *salt, size_t salt_len, char *buf) { ! char *crypt_buf = palloc(strlen(passwd) + salt_len); ! bool ret; ! strcpy(buf, "md5"); ! /* ! * Place salt at the end because it may be known by users ! * trying to crack the MD5 output. ! */ ! strcpy(crypt_buf, passwd); ! memcpy(crypt_buf+strlen(passwd), salt, salt_len); ! ! ret = md5_hash(crypt_buf, strlen(passwd) + salt_len, buf + 3); ! pfree(crypt_buf); ! return ret; }
> >OK, I have applied the following patch to the MD5 code that puts the > >salt at the end. We can't change the crypt() stuff because that is > >being used in older releases. > > I think it needs further confirmation, because what I said was from memory > - I still can't find the source- so take what I said with a pinch of erm > MSG. I'd personally go with the XOR rather than concat. And I'd use a > random salt rather than a predictable salt. > > But I emphasize again that I believe this is actually a small issue, and > that leaving the salt in front won't really weaken things much looking at > the big picture. Because nowadays computers are so fast and cheap, cracking > the passwords usually boils down to whether the password is weak or not, > and usually the passwords picked are weak, a week at most to crack :). You > use salts just to _discourage_ attackers from precomputing. A skilled and > determined attacker who knows how to exploit any hash-salt weakness will > find it easier to crack the whole blooming computer open and get root. It was easy to throw the salt on the end, and XOR is easy too. Can somone else comment on this? -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 853-3000 + If your life is a hard drive, | 830 Blythe Avenue + Christ can be your backup. | Drexel Hill, Pennsylvania 19026
On Thu, Sep 27, 2001 at 02:58:37PM -0400, Bruce Momjian wrote: > > I personally use encoded password= hash( concat(salt,password)), and store > > both the salt and the encoded password. Where hash = sha1 or md5. > > > > The DB columns are: salt, encoded password, encoding method. > We have new code in 7.2 that will do MD5 encryption of passwords stored > in pg_shadow. We add the salt to the front of the password before > passing through MD5. You are suggesting putting the salt at the end. > > I guess the issue is that if you can get the salt part found out, you > can use that to attack the password part. Also, consider that we use > the username as the salt as stored in pg_shadow. We can easily put the > salt in the back, but then there is the risk that a long password would > not take into account the salt. My feeling that this is more a > theoretical concern and we may be opening ourselves up to more problems > if we make the change. > > Other ideas? It does not matter. As you are using only one round of MD5/SHA1 which are quite fast, on very short data, it is very easy to brute-force it anyway, salt or no salt. Only good solution for storing short data hashed is to use very slow algorithm, like crypt-md5 and crypt-blowfish are doing. On crypt-blowfish you can even 'tune' the slowness by giving number of rounds to run. Another idea is stop storing hashes altogether and use protocol like SRP which stores on server side on 'verificators'. I am interested hacking PostgreSQL to use SRP, but have not had time for it yet. -- marko
At 07:15 PM 9/27/01 -0400, Bruce Momjian wrote: >> >> I guess the issue is that if you can get the salt part found out, you >> can use that to attack the password part. Also, consider that we use >> the username as the salt as stored in pg_shadow. We can easily put the >> salt in the back, but then there is the risk that a long password would >> not take into account the salt. My feeling that this is more a >> theoretical concern and we may be opening ourselves up to more problems >> if we make the change. > >OK, I have applied the following patch to the MD5 code that puts the >salt at the end. We can't change the crypt() stuff because that is >being used in older releases. I think it needs further confirmation, because what I said was from memory - I still can't find the source- so take what I said with a pinch of erm MSG. I'd personally go with the XOR rather than concat. And I'd use a random salt rather than a predictable salt. But I emphasize again that I believe this is actually a small issue, and that leaving the salt in front won't really weaken things much looking at the big picture. Because nowadays computers are so fast and cheap, cracking the passwords usually boils down to whether the password is weak or not, and usually the passwords picked are weak, a week at most to crack :). You use salts just to _discourage_ attackers from precomputing. A skilled and determined attacker who knows how to exploit any hash-salt weakness will find it easier to crack the whole blooming computer open and get root. Cheerio, Link.
Lincoln Yeoh <lyeoh@pop.jaring.my> writes: > I think it needs further confirmation, because what I said was from memory > - I still can't find the source- so take what I said with a pinch of erm > MSG. I'd personally go with the XOR rather than concat. Why? AFAIK, appending a salt is a well-understood process with MD5. I see no reason to think that XORing would be better, and it might be worse. > And I'd use a random salt rather than a predictable salt. We do, at least for passwords flowing across the net. There's no randomness in the salt for a password stored in pg_shadow, but the only way to have randomness there would be to add a separate column showing what the random salt was --- so an attacker with access to pg_shadow would know what the salt was, anyway. > But I emphasize again that I believe this is actually a small issue, Indeed, but I'd rather get it right now than realize we made a small error after it's too late to change. regards, tom lane
Marko Kreen <marko@l-t.ee> writes: > Another idea is stop storing hashes altogether You can already avoid passwords by using kerberos authentication. -- Trond Eivind Glomsrød Red Hat, Inc.
> > Another idea is stop storing hashes altogether > > You can already avoid passwords by using kerberos authentication. Are there any good docs on kerberos with postgres? Unlike almost everything else in this project, I've found them quite lacking. My biggest question would be I've got kerberos setup and working well. How do I get postgres to authorize a user. For the sake of example, let's say I've got the principle: johndoe@REALM.COM. Do I need to create a principle johndoe/postgres@REALM.COM? If so, what is the keytab that I'd create for the postmaster? postgres/host.example.com@REALM.COM? Thanks. -sc -- Sean Chittenden
sean-pgsql-general@chittenden.org writes: > Are there any good docs on kerberos with postgres? No. Since you seem to know more about Kerberos than most of us (ie, more than zero), could we trouble you to dig into it and write some docs? You might find there are some bugs to fix too. I doubt that code has seen much use lately :-( regards, tom lane
Tom Lane <tgl@sss.pgh.pa.us> writes: > sean-pgsql-general@chittenden.org writes: > > Are there any good docs on kerberos with postgres? > > No. Since you seem to know more about Kerberos than most of us > (ie, more than zero), could we trouble you to dig into it and > write some docs? > > You might find there are some bugs to fix too. I doubt that code > has seen much use lately :-( We've been using it a little lately, and it seems to work (we added a postgres principle, but that was about it) - one think which would be nice, though, is multiple authentication methods for the same database, keyed by user. While you might want to use kerberos for standard users, you might like to give an unprivileged one access to some simple selects, to give one example. -- Trond Eivind Glomsrød Red Hat, Inc.
On Sat, Sep 29, 2001 at 07:05:19PM -0700, Sean Chittenden wrote: > For the sake of example, let's say I've got the principle: > johndoe@REALM.COM. Do I need to create a principle > johndoe/postgres@REALM.COM? If so, what is the keytab that I'd create > for the postmaster? postgres/host.example.com@REALM.COM? You're right about the keytab -- the postmaster needs a key for "postgres/hostname@REALM" in the keytab file (which it needs to be able to read -- I often forget that) in order to use Kerberos for authentication. Authorization is still handled the same way it would be if you were using password authentication (i.e., you need to grant privileges to particular users for particular databases and tables, in your example, for a user named "johndoe"). HTH, Nalin
> > Another idea is stop storing hashes altogether > > You can already avoid passwords by using kerberos authentication. Are there any good docs on kerberos with postgres? Unlike almost everything else in this project, I've found them quite lacking. My biggest question would be I've got kerberos setup and working well. How do I get postgres to authorize a user. For the sake of example, let's say I've got the principle: johndoe@REALM.COM. Do I need to create a principle johndoe/postgres@REALM.COM? If so, what is the keytab that I'd create for the postmaster? postgres/host.example.com@REALM.COM? Thanks. -sc -- Sean Chittenden