For Programmers: Free Programming Magazines  


Home > Archive > Java Security > March 2004 > One-way encryption question









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author One-way encryption question
Jonck van der Kogel

2004-03-19, 8:55 pm

Hi everybody,
I would like to implement an authentication scheme that is used in PHP
websites all the time, but I can't seem to figure out how to make a
Java equivelant.
The PHP code is really simple:

/ Get the two character salt from the username
$salt = substr($loginName, 0, 2);

// Encrypt the password
$crypted_password = crypt($loginPassword, $salt);

// Formulate the SQL query to find the user
$query = "SELECT password FROM customers
WHERE email = '$loginName'
AND password = '$crypted_password'";

// Execute the query
$result = @ mysql_query ($query,
$connection)
or showerror();

// exactly one row? then we have found the user
if (mysql_num_rows($result) != 1 || $already_logged===true)
return false;
else
return true;

As you can see, nothing shocking is happening there. A password is
encrypted using a salt (first two letters of the login name). It is
then checked whether this password is in the database for the user
that is trying to log in. This has the advantage that the password is
stored in the database in encrypted form meaning that even if the
database is comprimized the users passwords are still safe.

In other words, what I'm looking for is an encryption method that
simply encrypts using a salt (and thus produces the same
encrypted_string every time given a certain password/salt
combination). No decryption is ever needed. However, all the examples
on encryption that I find on the Net are all regarding public and
secret keys and make things way too complicated for my humble needs.

Does anybody have a simple example on how to do this in Java or know
of a URL where such an example is posted?

Any help is much appreciated, thanks, Jonck
nobody

2004-03-19, 8:55 pm

This is really a digest/hash (not encryption). You could get similar
results doing:

String username = "user";
String password = "pass";

public String hash(String username, String password) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA1");
byte[] bytes = (username + password).getBytes("UTF-8");
byte[] hash = digest.doFinal(bytes);
// now hex-encode the hash to get a nice string
StringBuffer s = new StringBuffer();
for (int i = 0; i < hash.length; i++) {
s.append(Integer.toHexString((hash[i] >> 4) & 0x0f));
s.append(Integer.toHexString(hash[i] & 0x0f));
}
return s.toString();
}

While salting the password as above (i.e. with a portion/all of the
username) does reduce the possibility of a dictionary attack, it's still
possible to get a collision (i.e., user "cowb" with password "oys" and
user "cow" with password "boys" would have the same hash). You could
diffuse this a bit by using a MAC with the username as the key.

Jonck van der Kogel wrote:
> Hi everybody,
> I would like to implement an authentication scheme that is used in PHP
> websites all the time, but I can't seem to figure out how to make a
> Java equivelant.
> The PHP code is really simple:
>
> / Get the two character salt from the username
> $salt = substr($loginName, 0, 2);
>
> // Encrypt the password
> $crypted_password = crypt($loginPassword, $salt);
>
> // Formulate the SQL query to find the user
> $query = "SELECT password FROM customers
> WHERE email = '$loginName'
> AND password = '$crypted_password'";
>
> // Execute the query
> $result = @ mysql_query ($query,
> $connection)
> or showerror();
>
> // exactly one row? then we have found the user
> if (mysql_num_rows($result) != 1 || $already_logged===true)
> return false;
> else
> return true;
>
> As you can see, nothing shocking is happening there. A password is
> encrypted using a salt (first two letters of the login name). It is
> then checked whether this password is in the database for the user
> that is trying to log in. This has the advantage that the password is
> stored in the database in encrypted form meaning that even if the
> database is comprimized the users passwords are still safe.
>
> In other words, what I'm looking for is an encryption method that
> simply encrypts using a salt (and thus produces the same
> encrypted_string every time given a certain password/salt
> combination). No decryption is ever needed. However, all the examples
> on encryption that I find on the Net are all regarding public and
> secret keys and make things way too complicated for my humble needs.
>
> Does anybody have a simple example on how to do this in Java or know
> of a URL where such an example is posted?
>
> Any help is much appreciated, thanks, Jonck


Michael Amling

2004-03-19, 8:55 pm

nobody wrote:
> This is really a digest/hash (not encryption). You could get similar
> results doing:
>
> String username = "user";
> String password = "pass";
>
> public String hash(String username, String password) throws Exception {
> MessageDigest digest = MessageDigest.getInstance("SHA1");
> byte[] bytes = (username + password).getBytes("UTF-8");
> byte[] hash = digest.doFinal(bytes);
> // now hex-encode the hash to get a nice string
> StringBuffer s = new StringBuffer();
> for (int i = 0; i < hash.length; i++) {
> s.append(Integer.toHexString((hash[i] >> 4) & 0x0f));
> s.append(Integer.toHexString(hash[i] & 0x0f));
> }


Note that this generates one String object per hex digit. While
that's fine in many environments, if the OP is getting many logins, GC
can be held down by reducing the number of ephemeral objects, e.g.
char[] hexed=new char[hash.length*2];
for (int jj=0, kk=0; jj<hash.length; ++jj) {
hexed[kk++]="0123456789ABCDEF".charAt((hash[jj]>>4) & 0x0F);
hexed[kk++]="0123456789ABCDEF".charAt(hash[jj] & 0x0F);
}
return new String(hexed);


> return s.toString();
> }
>
> While salting the password as above (i.e. with a portion/all of the
> username) does reduce the possibility of a dictionary attack, it's still
> possible to get a collision (i.e., user "cowb" with password "oys" and
> user "cow" with password "boys" would have the same hash). You could
> diffuse this a bit by using a MAC with the username as the key.


Typically a collision is made impossible interposing a character that
is not legal in the username, such as
byte[] bytes=(username+':'+password).getBytes("UTF-8");

--Mike Amling

Jonck van der Kogel

2004-03-19, 8:55 pm

Thanks very much for your responses guys, this is just what I was looking for!
Thanks again, Jonck

Michael Amling <nospam@nospam.com> wrote in message news:<NZ84c.33241$PY.29579@newssvr26.news.prodigy.com>...
> nobody wrote:
>
> Note that this generates one String object per hex digit. While
> that's fine in many environments, if the OP is getting many logins, GC
> can be held down by reducing the number of ephemeral objects, e.g.
> char[] hexed=new char[hash.length*2];
> for (int jj=0, kk=0; jj<hash.length; ++jj) {
> hexed[kk++]="0123456789ABCDEF".charAt((hash[jj]>>4) & 0x0F);
> hexed[kk++]="0123456789ABCDEF".charAt(hash[jj] & 0x0F);
> }
> return new String(hexed);
>
>
>
> Typically a collision is made impossible interposing a character that
> is not legal in the username, such as
> byte[] bytes=(username+':'+password).getBytes("UTF-8");
>
> --Mike Amling

Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com