EncryptedData password decryption

Hello there!

I'm having problems with the EncryptedData way to handle the encrypted password, in detail:

I am modifying a table adapter to be used for provisioning to a db where we have stored procedures to insert/delete users and a read only table view to get the list of users and their details.

The problem comes up when I have to modify a user, the only way I can handle it is by removing and adding the user with the new details.

When I use thedecryptToString method what I get is the following string:

11D1DEF534EA1BE0:15003966:10D7D5002A0:-7FFD|YI81hzDZ8AHMO4cHevldggd8Tn8nE3QZ3x5CcPWk0ms=

...which is not the password I typed at the userView.

How can I handle this situation? The string looks like some object... and if I try to decrypt the base64 encoded bit of this string:

YI81hzDZ8AHMO4cHevldggd8Tn8nE3QZ3x5CcPWk0ms=

by setting an EncryptedData usingfromString and then calling againdecryptToString I get just some random binary gibberish.

Question is: what am I doing wrong?

Fabio

[1101 byte] By [MrWHO] at [2007-11-26 10:03:58]
# 1

I think that you may have used EncryptedData = new EncryptedData("YI81hzDZ8AHMO4cHevldggd8Tn8nE3QZ3x5CcPWk0ms=") which basically encrypts the string "YI81hzDZ8AHMO4cHevldggd8Tn8nE3QZ3x5CcPWk0ms=" and then if you call data.decryptToString(),. output will be YI81hzDZ8AHMO4cHevldggd8Tn8nE3QZ3x5CcPWk0ms=.

Looking at your output, it seems like you are encrypting the already encrypted password (I have seen that usually all IDM encrypted passwords will have "=" at the end).

Following code may yield the expected results. In any case, plaese follow up.

try {

String encryptedPassword = "YI81hzDZ8AHMO4cHevldggd8Tn8nE3QZ3x5CcPWk0ms=";

EncryptedData data = new EncryptedData();

data.fromString(encryptedPassword);

System.out.println(data.decryptToString());

} catch (Exception e) {

e.printStackTrace();

}

Message was edited by:

_raj

_raj at 2007-7-7 1:38:39 > top of Java-index,Web & Directory Servers,Directory Servers...
# 2

The relevant code I'm using right now in the realCreate, that is called from realUpdate when I need to update a user since I have no modify procedure or write access to the user table, is the following:

protected void realCreate(WSUser user, WavesetResult result)

throws WavesetException {

....

....

// This function comes from the reference DB table

// adapter.

addQuoted(b, getUserPassword(user));

....

....

}

....

....

protected String getUserPassword(WSUser user) {

String userPassword = null;

ResourceInfo resInfo = user.getResourceInfo(_resource);

if (resInfo != null) {

EncryptedData ePassword = resInfo.getPassword();

if (ePassword != null) {

userPassword = ePassword.decryptToString();

}

}

TRACE.info4("getUserPassword", "Got password from ed: " + userPassword);

return userPassword;

}

This code will leave the following trace during user creation:

.... AcumeDBResourceAdapter#getUserPassword() Info Got password from ed: password

where "password" is the password specified from the form when creating the user. During update the log shows the following when executing the realCreate after the realDelete:

.... AcumeDBResourceAdapter#getUserPassword() Info Got password from ed: 11D1DEF534EA1BE0:15003966:10D7D5002A0:-7FFD|y2Lv1LWZgK4=

To be sure I left no stone unturned in this bug hunting I added the following code to realUpdate:

protected void realUpdate(WSUser user, WavesetResult result)

throws WavesetException {

....

....

ResourceInfo resInfo = user.getResourceInfo(_resource);

....

Connection con = getConnection();

....

WSUser current = getUser(con, user);

....

....

TRACE.info4("realUpdate", "Current user: " + getUserPassword(current));

TRACE.info4("realUpdate", "New user: " + getUserPassword(user));

TRACE.info4("realUpdate", "Decrypted: " + encryptPassword(resInfo.getPassword()));

if ( resInfo.getPassword() != null )

TRACE.info4("realUpdate", "ResInfo: " + resInfo.getPassword().decryptToString() );

....

....

}

....

....

public String encryptPassword(EncryptedData ed) {

TRACE.info4("encryptPassword - ed ", "Got: " + ed.decryptToString() );

String encString = ed.decryptToString();

if ( encString.split(":", 4)[0].equals("11D1DEF534EA1BE0") ) {

TRACE.info4("encryptPassword - ed ", "Got encrypted object: " + encString );

EncryptedData edNew = new EncryptedData();

String encPassword = encString.split(":", 4)[3].split("\\|",2)[1];

TRACE.info4("encryptPassword - ed ", "Got encrypted password: " + encPassword);

try {

edNew.fromString(encPassword);

encString = edNew.decryptToString();

} catch ( Exception e ) {

// Bummer!

TRACE.info4("encryptPassword - ed ", "Failed to decrypt: " + encPassword);

}

TRACE.info4("encryptPassword - ed ", "Got clear password: " + encString);

}

else {

TRACE.info4("encryptPassword - ed ", "Got unencrypted string: " + encString );

}

TRACE.info4("encryptPassword - ed ", "XML: " + encString );

return encString;

}

Tracing this code during creation I get:

.... AcumeDBResourceAdapter#getUserPassword() Info Got password from ed: null

.... AcumeDBResourceAdapter#realUpdate() Info Current user: null

.... AcumeDBResourceAdapter#getUserPassword() Info Got password from ed: 11D1DEF534EA1BE0:15003966:10D7D5002A0:-7FFD|y2Lv1LWZgK4=

.... AcumeDBResourceAdapter#realUpdate() Info New user: 11D1DEF534EA1BE0:15003966:10D7D5002A0:-7FFD|y2Lv1LWZgK4=

.... AcumeDBResourceAdapter#encryptPassword - ed () Info Got: 11D1DEF534EA1BE0:15003966:10D7D5002A0:-7FFD|y2Lv1LWZgK4=

.... AcumeDBResourceAdapter#encryptPassword - ed () Info Got encrypted object: 11D1DEF534EA1BE0:15003966:10D7D5002A0:-7FFD|y2Lv1LWZgK4=

.... AcumeDBResourceAdapter#encryptPassword - ed () Info Got encrypted password: y2Lv1LWZgK4=

.... AcumeDBResourceAdapter#encryptPassword - ed () Info Got clear password: o�^UC5YJ

.... AcumeDBResourceAdapter#encryptPassword - ed () Info XML: o�^UC5YJ

.... AcumeDBResourceAdapter#realUpdate() Info Decrypted: o�^UC5YJ

.... AcumeDBResourceAdapter#realUpdate() Info ResInfo: 11D1DEF534EA1BE0:15003966:10D7D5002A0:-7FFD|y2Lv1LWZgK4=

...and of course the updated password was not the jibberish you see there...

Hope this was a bit more clear now...

Fabio

PS: I've tried to massage the "fromString" parameter, so I now progressed as far as:

....

....

encPassword = "PBEWithMD5AndDES|" + encPassword;

TRACE.info4("encryptPassword - ed ", "Got encrypted password: " + encPassword);

try {

// 4) Decrypt the little dingleberry

edNew.fromString(encPassword);

encString = edNew.decryptToString();

....

....

Now the tracing looks like this:

....

....

AcumeDBResourceAdapter#encryptPassword - ed () Info Got encrypted password: PBEWithMD5AndDES|YI81hzDZ8AHMO4cHevldggd8Tn8nE3QZ3x5CcPWk0ms=

EncryptedData#fromString() Entry arg1=estring=PBEWithMD5AndDES|YI81hzDZ8AHMO4cHevldggd8Tn8nE3QZ3x5CcPWk0ms=

....

....

EncryptedData#decrypt() Throw javax.crypto.BadPaddingException: Given final block not properly padded

....

....

Message was edited by:

MrWHO

MrWHO at 2007-7-7 1:38:39 > top of Java-index,Web & Directory Servers,Directory Servers...
# 3

Interesting. Looks like you are converitng an update into delete+insert opertation. So, for example, the document for MySQLResourceAdapter.realUpdate() says the following:

" updateAccount method needs to modify the individual account attributes

and not replace the entire record. The user password will only be

present if it is needing to be changed. The password if it does need to

be changed will not be found in the user.password variable passed in,

it will instead be found on the resource info object password"

// EncryptedData pw = resInfo.getPassword();

Since yours may be a regular update not involving password, I am wondering if the avove paragraph may hint something.

_raj at 2007-7-7 1:38:39 > top of Java-index,Web & Directory Servers,Directory Servers...
# 4

Problem solved. There was a mistake in the form view that would deselect the resource in question when propagating the password change. Now: when this happens the password is propagated anyhow with the old password value, BUT...

...here is the catch: the EncryptedData you get when this kind of update happens is an EncryptedData that contains an EncryptedData that contains the password, so you may want to check for this while getting the password.

Here is what I do to be on the safe side:

// This is a little bit of twisted code to check for double encrypted

// passwords, it may be as useful as a kick in the privates...

public String decryptPassword(EncryptedData ed) {

// Get out of here is someone is playing funny tricks on

// us, like sending over a null EncryptedData object

if (ed == null)

return null;

// Now, decrypt the EncryptedObject to get the contents..

String encString = ed.decryptToString();

// ...and make some space for the result.

String clearPassword = "";

// Looks horrible and I have no idea if it is a reliable way to get

// the object type, it works here, trace your output to see if you have

// the same beginning as string.

if ( encString.split(":", 4)[0].equals("11D1DEF534EA1BE0") ) {

// We have an encrypted object as result of decrypting the

// EncryptedData we have been sent, get ready to decrypt

// this as well.

EncryptedData edNew = new EncryptedData();

TRACE.info4("encryptPassword - ed ", "Got encrypted password: " + encString);

try {

// Now let's try and decrypt an EcryptedData made out

// of the string we got from the first decryption

edNew.fromString(encString);

// clearPassword may end up being null if something

// goes wrong, it is the expected result...

clearPassword = edNew.decryptToString();

} catch ( Exception e ) {

// Dingleberry! The trick didn't work.

TRACE.info4("encryptPassword - ed ", "Failed to decrypt: " + encString);

clearPassword = null;

}

// We managed to decrypt an ecrypted EncryptedData... if you follow

// the drift...

TRACE.info4("encryptPassword - ed ", "Got clear password: " + clearPassword);

}

else {

// Lucky us, the EncodedData had actually a password encoded in it

clearPassword = encString;

TRACE.info4("encryptPassword - ed ", "Got unencrypted string: " + clearPassword );

}

return clearPassword;

}

Little you know in life... and most of it's wrong! :)

Fabio

MrWHO at 2007-7-7 1:38:39 > top of Java-index,Web & Directory Servers,Directory Servers...
# 5

Bravo, you got it working !

Doesn't it seem like a IDM bug , there is no need to double-encrypt the password.

Not sure,. but it may be worth to try to make password type as String in the resource map (resource definition), IDM may pass a clear text password to the adapter., in which case, you do not need to worry about Encryption.

Anyway, good to know that you got it working, must have been very frustrating.

Message was edited by:

_raj

_raj at 2007-7-7 1:38:39 > top of Java-index,Web & Directory Servers,Directory Servers...
# 6

Hi there!

Yep, very much frustrating. Spent a couple of days before realizing what the behaviour was.

The attribute, resource mapping wise, is a String attribute. It is encrypted by LH because of its mapping to a password field, so it will be passed on encrypted anyhow.

The real mistery is why is it encrypted twice when it's propagated in an update action that doesn't involve password update. This is a kind of problem if you consider my situation where I have to get all of the attributes to recreate the new user, since my modify is basically a DELETE/CREATE operation.

Well, I survived this! :)

Fabio

MrWHO at 2007-7-7 1:38:39 > top of Java-index,Web & Directory Servers,Directory Servers...