From d2a4f62593073eb3edc8aa9af58c8edff5be9742 Mon Sep 17 00:00:00 2001 From: Damian Minkov Date: Thu, 15 Jul 2010 12:47:20 +0000 Subject: [PATCH] Fix storing passwords on Linux, wrong key length. Now tries first the default key length(256) and if it fails it goes to 128. Fix authentication failed detection when connecting to openfire. --- .../impl/credentialsstorage/AESCrypto.java | 81 ++++++++++++++----- .../ProtocolProviderServiceJabberImpl.java | 5 +- 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/src/net/java/sip/communicator/impl/credentialsstorage/AESCrypto.java b/src/net/java/sip/communicator/impl/credentialsstorage/AESCrypto.java index 8fda279c2..f1f83b1ad 100644 --- a/src/net/java/sip/communicator/impl/credentialsstorage/AESCrypto.java +++ b/src/net/java/sip/communicator/impl/credentialsstorage/AESCrypto.java @@ -40,9 +40,9 @@ public class AESCrypto { 0x0C, 0x0A, 0x0F, 0x0E, 0x0B, 0x0E, 0x0E, 0x0F }; /** - * Length of the key in bits. + * Possible length of the keys in bits. */ - private static int KEY_LENGTH = 256; + private static int[] KEY_LENGTHS = new int[]{256, 128}; /** * Number of iterations to use when creating the key. @@ -71,30 +71,32 @@ public class AESCrypto */ public AESCrypto(String masterPassword) { - // if the password is empty, we get an exception constructing the key - if (masterPassword == null) - { - // here a default password can be set, - // cannot be an empty string - masterPassword = " "; - } - try { decryptCipher = Cipher.getInstance(CIPHER_ALGORITHM); encryptCipher = Cipher.getInstance(CIPHER_ALGORITHM); - - // Password-Based Key Derivation Function found in PKCS5 v2.0. - // This is only available with java 6. - SecretKeyFactory factory = - SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); - // Make a key from the master password - KeySpec spec = - new PBEKeySpec(masterPassword.toCharArray(), SALT, - ITERATION_COUNT, KEY_LENGTH); - SecretKey tmp = factory.generateSecret(spec); - // Make an algorithm specific key - key = new SecretKeySpec(tmp.getEncoded(), KEY_ALGORITHM); + + // we try init of key with suupplied lengths + // we stop after the first successful attempt + for (int i = 0; i < KEY_LENGTHS.length; i++) + { + try + { + initKey(masterPassword, KEY_LENGTHS[i]); + + // its ok stop trying + break; + } + catch (InvalidKeyException e) + { + if(i == KEY_LENGTHS.length - 1) + throw e; + } + } + } + catch (InvalidKeyException e) + { + throw new RuntimeException("Invalid key", e); } catch (InvalidKeySpecException e) { @@ -110,6 +112,41 @@ public AESCrypto(String masterPassword) } } + /** + * Initialize key with specified length. + * + * @param masterPassword used to derive the key. Can be null. + * @param keyLength Length of the key in bits. + * @throws InvalidKeyException + * @throws NoSuchAlgorithmException + * @throws InvalidKeySpecException + */ + private void initKey(String masterPassword, int keyLength) + throws InvalidKeyException, + NoSuchAlgorithmException, + InvalidKeySpecException + { + // if the password is empty, we get an exception constructing the key + if (masterPassword == null) + { + // here a default password can be set, + // cannot be an empty string + masterPassword = " "; + } + + // Password-Based Key Derivation Function found in PKCS5 v2.0. + // This is only available with java 6. + SecretKeyFactory factory = + SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); + // Make a key from the master password + KeySpec spec = + new PBEKeySpec(masterPassword.toCharArray(), SALT, + ITERATION_COUNT, keyLength); + SecretKey tmp = factory.generateSecret(spec); + // Make an algorithm specific key + key = new SecretKeySpec(tmp.getEncoded(), KEY_ALGORITHM); + } + /** * Decrypts the cyphertext using the key. * diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java index 0c7ec1a95..a122679ed 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java @@ -317,7 +317,7 @@ private synchronized void connectAndLogin(SecurityAuthority authority, { //verify whether a password has already been stored for this account String password = JabberActivator. - getProtocolProviderFactory().loadPassword(getAccountID()); + getProtocolProviderFactory().loadPassword(getAccountID()); //decode if (password == null) @@ -1008,11 +1008,14 @@ private void fireRegistrationStateChanged(XMPPException ex) // we try determine the reason according to their message // all messages that were found in smack 3.1.0 were took in count if(exMsg.indexOf("authentication failed") != -1 + || (exMsg.indexOf("authentication") != -1 + && exMsg.indexOf("failed") != -1) || exMsg.indexOf("login failed") != -1 || exMsg.indexOf("unable to determine password") != -1) { JabberActivator.getProtocolProviderFactory(). storePassword(getAccountID(), null); + reason = RegistrationStateChangeEvent .REASON_AUTHENTICATION_FAILED;