Encrypted Password in database

Hi all,

I read few thread regarding password hashing or encryption in the database but not a fully working solution.

Does someone have something on that ? I’'m not a Java coder, can find, but not a lot of time to waste on that.

Also cleartext password is a nogo for me. The security department will kill the project if they knew that.

Please HELP!!!

Thanks

Hi Sabey,

I did vote for JM-291 - if some more people vote for it this could be realized.

Maybe you are using Oracle as database, there is a feature called “Transparent Data Encryption” which should offer the ability to encrypt single columns.

LG

Hi Sabey,

You are right, plain password in the databse is a killer. Here is how I would do it,

1.) Modify: DefaultUserProvider.java

public void setPassword(String username, String password) throws UserNotFoundException {

}

Problem: Currently there is not enough space to store MD5 or SHA hash:

Algorithm Strength

MD5 128 bit

SHA-1 160 bit

2.) Therefore modify database schema for table:jiveUser (User data)

(current schema see below)

Column Name Type Length Description

username VARCHAR 32 User Name (Primary Key)

password VARCHAR 32 Password Data (plain-text or MD5 hash depending on settings)

name VARCHAR 100 Name

email VARCHAR 100 Email Address

creationDate VARCHAR 15 Creation Date

modificationDate VARCHAR 15 Last Modified Date

3.) We need to store three fields instead of user name and password:

username VARCHAR 32 User Name (Primary Key)

password VARCHAR 32 Password Data (plain-text or MD5 hash depending on settings)

salt VARCHAR 160 MD5/SHA1 hash depending on settings

saltedHash VARCHAR 160 Salted hash of password

See also http://www.jivesoftware.org/community/thread.jspa?messageID=109949&#109949

Michael

Nice hack, but I have the plan to use this IM for a lot of people.

Now the problem is how to maintain this change, how this will impact any upgrade of the server. What will append if they decide to use another format of encrypted password ? I will not be able to migrate the hashed password…

Seb

I’'m not a Java coder, do you have to code or the modified java file ?

Thank a lot

Hi Michael,

it seems to be a bit more complicated than to modify only setPassword. As far as I understand the code the client sends the ‘‘username’’, a ‘‘token’’ (the streamID) and a ‘‘digest’’ (digest=hash(streamID, password)). Stream ID’'s are generated by the server and should be unique and random.

To verify the digest Wildfire reads the plaintext password and calculates the ‘‘anticipatedDigest’’ (DefaultAuthProvider.java, line 76ff). If ‘‘anticipatedDigest’’==’‘digest’’ then the client is authenticated.

Storing a hashed password (or salt and hashed password) should make it impossible to calculate ‘‘anticipatedDigest’’. Or is there a way?

LG

LG,

Storing a hashed password (or salt and hashed password) should make it

impossible to calculate ‘‘anticipatedDigest’’. Or is there a way?

Nope, that’'s exactly the problem. In order to do digest auth or SASL-digest, the plain text password is required. If only a hash is stored, that basically means that users have to use a TLS connection in order for authentication to be secure.

-Matt

Matt or any other developer,

Any timeframe when this security feature will be implemented ?

Thanks

HI LG,

my idea was to forget ‘‘password’’ as plain text. ‘‘password’’ shall no longer be accessed. Instead I want to compare always with ‘‘hash’’

(as described in http://www.securitytechnique.com/1/8-2 )

Systems that store password hashes effectively all do the same thing:

  1. When a user creates his or her password, the password is hashed and the hash is stored in the password database

  2. When a user attempts to login, the password entered at the login terminal (the trial password) is hashed

  3. The hash of the trial password is compared with the password stored in the password database

  4. If the two hashes are identical, we assume the user entered the correct password.

I haven’'t considered ‘‘anticipatedDigest’’. It seems that what I want is already in the code; just the ‘‘digest’’ is to be stored and not the plain password???

I need to debug.

Thanks LG

Michael

Michael,

Yes, but that means that the plain text password must be sent from the XMPP client to the XMPP server. You gain security in one place (database) but lose it in the other (network). That’'s why TLS is essentially required when doing plain text auth.

-Matt

Matt,

your are basically saying, it is up to the database to deal with encryption/hashing (e.g Orcale can do it, HSQOL and others can not). How does Oracle’'s feature called “Transparent Data Encryption” work?

Regards

Michael

Hi Michael,

http://www.oracle.com/technology/pub/articles/10gdba/nanda_10gr2dba_part1.html describes it very good. This could be also implemented without the Oracle Wallet using a java keystore. Then this key would be used to encrypt the passwords and to decrypt them, so the encrypted passwords must not be a hash so they can be decrypted once again.

Regarding security: It usually doesn’'t matter for a DBA if the passwords are stored in plaintext, as a hash or encrypted being independant of the username. If he wants to hack a user he can update the password field with his password value.

LG

Thanks LG,

The recommendation seems using the combination Oracle + Wildfire .

but never use Wildfire’'s embedded database

So it still remains, if a system (OS, DBMS, e-mail, IM,…) decides to store passwords it SHOULD NOT use plain text.

In the case of Wildfire, if we need the original ‘‘plain text’’ password back (in memory) then we can only use encrypt/decrypt (since hash can not be reversed).

To take the algorithm to store local Oracle user passwords as an example (it is described (and critiqued) here: http://www.sans.org/rr/special/index.php?id=oracle_pass

  1. Concatenate the username and the password to produce a plaintext string;

  2. Convert the plaintext string to uppercase characters;

  3. Convert the plaintext string to multi-byte storage format; ASCII characters have the

high byte set to 0x00;

  1. Encrypt the plaintext string (padded with 0s if necessary to the next even block length)

using the DES algorithm in cipher block chaining (CBC) mode with a fixed key value of

0x0123456789ABCDEF;

  1. Encrypt the plaintext string again with DES-CBC, but using the last block of the output

of the previous step (ignoring parity bits) as the encryption key. The last block of the

output is converted into a printable string to produce the password hash value.

This at least makes it difficult for an attacker to crack a password (XOR and ROT are a nogos).

How about using Intel’'s contribution of the security class library code (http://issues.apache.org/jira/browse/HARMONY-16 )

It is based on ASN.1. ASN.1 encoding rules are sets of rules used to transform data specified in the ASN.1 language into a standard format. The ASN.1 encoding rules currently standardized are: Basic Encoding Rules (BER), Distinguished Encoding Rules (DER), Canonical Encoding Rules (CER), Packed Encoding Rules (PER), XML Encoding Rules (XER) and Extended XML Encoding Rules (E-XER).

From http://www.oss.com/asn1/rules.html :

BER was created in the early 1980s and is used in a wide range of applications, such as Simple Network Management Protocol (SNMP) for management of the Internet; Message Handling Services (MHS) for exchange of electronic mail and TSAPI for control of telephone/computer interactions.

DER is a specialized form of BER that is used in security-conscious applications. These applications, such as electronic commerce, typically involve cryptography, and require that there be one and only one way to encode and decode a message.

CER is another specialized form of BER that is similar to DER, but is meant for use with messages so huge that it is easiest to start encoding them before their entire value is fully available. CER is rarely used, as the industry has locked onto DER as the preferred means of encoding values for use in secure exchanges.

PER is more recent than the above sets of encoding rules and is noted for its efficient algorithms that result in faster and more compact encodings than BER. PER is used in applications that are bandwidth or CPU starved, such as air traffic control and audiovisual telecommunications.

XER (XML Encoding Rules) allow you to encode a message that has been defined via ASN.1 using XML. You can now add visibility to your ASN.1-described messages via XML.

E-XER (Extended XML Encoding Rules) is an amendment to the ITU-T Rec. X.693 (23002) ASN.1 Encoding Rules: Specification of XML Encoding Rules (XER). Extended-XER encoding makes ASN.1 an XML schema notation as powerful as XSD, with the simplicity of ASN.1.

Regards

Michael

Hi Michael,

here’‘s a short example which could be used with every application to store encrypted passwords in a database. That’'s nearly the same thing as Oracle does, but in this case the application (Wildfire) must do the de-/encryption.

@ Matt: Very similar code should already be used in Spark, as the settings.xml also stores the password encrypted.

That’'s the output with base64key=“nW1UOFSrdbA=” for the ones without javac:

authenticated

password=secret

encryptesPassword=iYQzm7DO1PQu5sQvSm+nUw==

decryptesPassword=secret

LG

import javax.crypto.Cipher;

import javax.crypto.KeyGenerator;

import javax.crypto.SecretKey;

import javax.crypto.SecretKeyFactory;

import javax.crypto.spec.DESKeySpec;

import sun.misc.BASE64Decoder;

import sun.misc.BASE64Encoder;

public class DesMain

{

public static void main(String[] args) throws Exception

{

String username = “bar”;

String password = “secret”;

String base64key = “nW1UOFSrdbA=”;

String encryptesPassword = encryptPassword(username,

password, base64key);

// now store encryptesPassword in database

// use this also in DefaultAuthProvider.authenticate(line 39ff)

// before “pstmt.setString(2, password);”

// read encryptesPassword from database

String decryptesPassword = decryptPassword(username,

encryptesPassword, base64key);

// now use it to calculate a digest

// use this in DefaultAuthProvider.authenticate(line 72ff)

// before "String anticipatedDigest

= AuthFactory.createDigest(token, pass);"

if (password.equals(decryptesPassword))

{

System.out.println(“authenticated”);

};

System.out.println(“password=” + password);

System.out.println(“encryptesPassword=” + encryptesPassword);

System.out.println(“decryptesPassword=” + decryptesPassword);

};

public static String encryptPassword(String username,

String password, String b64key) throws Exception

{

String value2encode = username.toLowerCase() + password.toLowerCase();

Cipher ecipher = Cipher.getInstance(“DES”);

SecretKey key = getKey(b64key);

ecipher.init(Cipher.ENCRYPT_MODE, key);

BASE64Encoder be = new sun.misc.BASE64Encoder();

return be.encode(ecipher.doFinal(value2encode.getBytes(“UTF8”)));

};

public static String decryptPassword(String username,

String epassword, String b64key) throws Exception

{

Cipher dcipher = Cipher.getInstance(“DES”);

SecretKey key = getKey(b64key);

dcipher.init(Cipher.DECRYPT_MODE, key);

BASE64Decoder bd = new sun.misc.BASE64Decoder();

return new String(dcipher.doFinal(bd.decodeBuffer(epassword)),

“UTF8”).substring(username.length());

};

/*

  • TODO should be a singleton

*/

private static SecretKey getKey(String b64key) throws Exception

{

/*

  • TODO read key from a file; it must never change

  • (actually the software should provide an option to use a new key

  • and to migrate all accounts)

  • losing the key disables all accounts

*/

SecretKey key = null;

if (b64key == “”)

{

/* dynamic key option, useless */

key = KeyGenerator.getInstance(“DES”).generateKey();

} else {

BASE64Decoder bd = new sun.misc.BASE64Decoder();

SecretKeyFactory desFactory = SecretKeyFactory.getInstance(“DES”);

DESKeySpec keyspec = new DESKeySpec(bd.decodeBuffer(b64key));

key = desFactory.generateSecret(keyspec);

};

return key;

};

};

/code

Hi LG,

this looks great. Your code allows to close JM-291; I don’'t think that “hashed password to be stored in the DB” is the right title (way to go) anymore.

Your code comments even show what is to be done:

  • Changes in Admin Console:

  • To add under Server -> Server Settings -> Security Settings:

Group box “Password Encryption”

Edit Field “Key”

Button “Save Settings & Apply Key”

  • To store key in conf/wildfire.xml as

  • To apply decryptPassword/encryptPassword whenever password is changed

User/Groups -> Create New User

User/Groups -> User Summary -> Edit

Group Chat -> Create New Room

Group Chat -> Room Summary -> Change/modify password

  • To consider decryptPassword/encryptPassword when importing/exporting users (as plain text???)

  • To consider decryptPassword/encryptPassword when upgrading

  • To change DefaultAuthProvider.authenticate(line 39ff)

DefaultAuthProvider.authenticate(line 72ff)

  • To change database schema if 32 chars are not enough to hold “encryptPassword”

If SecretKeyFactory.getInstance(“DES”) would be enough, then no more options would be required. I guess just “DES” is good enough for the beginning.

Did I miss something?

Cheers

Michael

I like this approach in general. I’'ll update the JIRA issue to suggest this method instead of hashing passwords.

-Matt

I see that this is planned for 2.5.2

Is there any update on the progress? The work log looks sadly bare. This feature is the only thing keeping me using IRC at work and frankly I want IRC out of my life.

Jaylakes,

I am trying to encourage everyone to vote for this feature but only 15 people voted for it so far (rank 7 in the Popular Issues list).

Michael

Donno whether this actually solves the real problem:

From the client I send an encrypted password (during log in), the server should not even try to decrypt it rather it should only compare it against the encrypted password that it already has …

am i missing something?

Also, different client may use different encryption techniques …so how do we get the same final result everytime?

Should we have something like a public-private key ?

Pretty confused at this stage … any help?

Hi,

I have a question? if i store the Encrypted Password in database , in the moment of the autentication what class and methods i have to modify but that i can make the match between my password that i send without encrypt witn my password Encrypted in the database???

Thanks,

oosloss