1
votes

Currently we are encrypting the passwords entered by the user from login page and store them in the Database. Here am developing a new login page for internal purpose and reusing the same username and encrypted password. If user is authorised, then will allow him to access the reports. Here my question is, how can I get the secret key which they have used to encrypt. Would like to use the same key to decrypt the password and I can go ahead with my logic.

This is the code we are using to encrypt method to encrypt the password.

user = userRemote.loginUser(userName, new String(EncryptDecrypt.storePassword(password),"Cp1252"));

Here password is Password entered in the login page.

This is the method to encrypt the password.

final static byte[] salt = {
        (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
        (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
    };
final static int count = 1;

public static byte[] storePassword(char[] password) throws InternalException {
      PBEKeySpec pbeKeySpec;
      PBEParameterSpec pbeParamSpec;
      SecretKeyFactory keyFac;
      byte[] ciphertext = null;
      try {
        // Install SunJCE provider
        Provider sunJce = new com.sun.crypto.provider.SunJCE();
        Security.addProvider(sunJce);

        // Create PBE parameter set
        pbeParamSpec = new PBEParameterSpec(salt, count);

        pbeKeySpec = new PBEKeySpec(password);
        keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
        SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
        // Create PBE Cipher
        Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");

        // Initialize PBE Cipher with key and parameters
        pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

        // Our cleartext
        byte[] cleartext = (new String(password)).getBytes("Cp1252");

        // Encrypt the cleartext
        ciphertext = pbeCipher.doFinal(cleartext);
      } catch (BadPaddingException ex) {
        log.error("EncryptDecrypt: " + ex.getMessage());
        throw new InternalException(ex.getMessage());
      } catch (Exception ex) {
        log.error("EncryptDecrypt: " + ex.getMessage());
        throw new InternalException(ex.getMessage());
      }
     return ciphertext;
  }

This is the class am using to decrypt the password. Here I have only encrypted password as an input to decrypt the password. For example •Ä0BÒ¦O , so am using the same to generate secret key and decrypt it. But, getting below exception. java.security.spec.InvalidKeySpecException: Password is not ASCII

import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;

public class DecryptPassword {

    public static void main(String[] args) {
        String decryptedStr = checkPassword("•Ä0BÒ¦O");
        System.out.println("decryptedStr : "+decryptedStr);
    }

    final static byte[] salt = {
        (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
        (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
    };

    final static int count = 1;

    static String decryptedPassword = "";

     public static String checkPassword(String encryptedPassword) {
          PBEKeySpec pbeKeySpec;
          PBEParameterSpec pbeParamSpec;
          SecretKeyFactory keyFac;
          try {
            // Install SunJCE provider
            Provider sunJce = new com.sun.crypto.provider.SunJCE();
            Security.addProvider(sunJce);
            // Create PBE parameter set
            pbeParamSpec = new PBEParameterSpec(salt, count);
            pbeKeySpec = new PBEKeySpec(encryptedPassword.toCharArray());
            keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
            SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
            // Create PBE Cipher
            Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
            // Initialize PBE Cipher with key and parameters
            pbeCipher.init(Cipher.DECRYPT_MODE, pbeKey, pbeParamSpec);
            byte[] decrypted = pbeCipher.doFinal(encryptedPassword.getBytes());
            decryptedPassword = decrypted.toString();
        } catch (BadPaddingException ex) {
          System.out.println("EncryptDecrypt: " + ex.getMessage());
        } catch (Exception ex) {
          System.out.println("EncryptDecrypt: " + ex.getMessage());
        }
        return decryptedPassword;
      }

}

Here I should be able to decrypt the password successfully, but not.Can anyone please help me what am missing here? Thanks In Advance.

1
I don't think you should store the encrypted password at all. Instead of doing that, store the password hashes is better.Dang Nguyen
Why in the world would you want to decrypt a password? This is the last thing you want to do. You hash a password and store the hash. When the User supplies a password that password is hashed and is compared to the stored hash for equality. Only the User should ever know what his or her password might be.DevilsHnd
@DevilsHnd Here my use case is there is a URL which will be accessible across company. I want to restrict it to section of people whose username and password already present in DB. Currently that password is encrypted. Is there any better way to authorize user apart from decrypt password and allow him to access the URL?Honey
@DangNguyen Already passwords are encrypted(This is a legacy application), am just trying to reuse them.Honey
The bottom line is, if you can decrypt a password so can anyone else. If you give me an encrypted password, I can eventually decrypt it. A Hash on the other hand is basically one way whereas the possibility of reversing it is virtually impossible. A Hash is not encryption, it's a Hash and because of this it can not be decrypted. The only possible threat to a Hash is what is called a collision where one hash would somehow end up the same as another hash such as the same password is being used. Even this can be prevented. You should possibly reconsider your password security model.DevilsHnd

1 Answers

2
votes

That's no encryption, that's a hash! (rim-shot)

That storePassword routine effectively uses the password to encrypt itself; more exactly, PBEwithMD5andDES uses a key derived from the password by the original PKCS5v1 derivation function, now retronymed PBKDF1 for clarity, instantiated with MD5, fixed salt, and 1 (!) iteration, to encrypt with original DES CBC the password. This is a variation on a formerly popular way of creating a cryptographic hash.

During the 1960s and 1970s and maybe 1980s, before cryptologists turned their attention to designing specific cryptographic hash functions so ciphers were the only crypto primitive, a common method of turning a cipher (a keyed permutation) into a crypto hash (an unkeyed function) was to use the data as key to encrypt a constant; a slight variation of this was implemented as a library function inaccurately named crypt and used as the password hashing function in early Unix ca 1970, and is still remembered (sometimes even used) but now often retronymed DES-crypt or descrypt to distinguish from the alternatives and replacements developed since.

Unlike a cipher which is designed to be decrypted, this is a hash and designed NOT to be reversed. I don't know of any way to reverse this method easier than brute force (i.e. an analytic 'break'), but original DES, now usually called single-DES (or 1DES) to distinguish from its direct successor triple-DES (or 3DES or formally TDEA), is weak enough it can now be brute forced if you really want to. For example JTR reports roughly 10M-30M trials/sec for single-salt descrypt, which would correspond to roughly 0.5G/sec for simple DES, so trying all DES keys would take several years with one computer, a few days with a thousand computers, or a few minutes with a million computers. Data on hashcat is harder to find but appears roughly comparable. If you have any clue how the password was chosen, it may be faster to try only the possible passwords rather than all possible keys.

But don't. The correct way to verify a password hash is for the user to supply the claimed password, repeat the hashing process with the same parameters (here easy because it doesn't use a variable salt as it should), and see whether the new hashed result matches the stored one.