Encrypted Password in database

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

Hi Partha,

you may want to look at the code and see how it is working:

The client and the server both encrypt a plain-text password using a random hash. The client sends the hashed password to the server. If it matches the servers one then the user did enter the right password. The hash is always another and so the hashed password.

The encryption techniques are unique and should be defined in a JEP.

LG

I’'d love to vote for this. Where do I do that?

You can visit JM-291 to vote for the bug. However, the good news is that I already checked in the fix to make make encrypted passwords work. It will be released in Wildfire 2.6.

Regards,

Matt

I’'m running Wildfire 3.0 (upgraded from 2.5) and I noticed JM-291 is closed … and yes I see i have an encryptedPassword column in my database… and my new accounts have nice encrypted passwords.

The problem is all the old accounts (created in 2.5) are using the plain text ‘‘password’’ still. Is there an easy way I can have all the old accounts have their passwords converted over to the encryptedPassword? I’‘ve dug around the web admin side of things and didn’'t see anythign obvious.

thanks for getting the encryptedPassword thing implimented… it was my biggest sadness about using jabber … I really don’‘t like having to see my users passwords (good ones and bad ones) when I’'m debugging things… there are now some states where it would be illegal for me to know their password w/o their written permission…

-dayne