1

I am trying to encode the passphase into a properties file so that I don't have to type in the passphase to make an SSH connection. But I am facing the following error :

javax.crypto.BadPaddingException: Given final block not properly padded
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
    at javax.crypto.Cipher.doFinal(Cipher.java:2165)
    at com.test.ssh.SSH_Public_Private.deCryptPwd(SSH_Public_Private.java:191)
    at com.test.ssh.SSH_Public_Private.checkHostName(SSH_Public_Private.java:227)
    at com.test.ssh.SSH_Public_Private.checkHostName(SSH_Public_Private.java:223)
    at com.test.ssh.SSH_Public_Private.connectToSSH(SSH_Public_Private.java:64)
    at com.test.ssh.SSH_Public_Private.main(SSH_Public_Private.java:124)

My code is as follows:

  private String checkHostName(String hostUserName) throws IOException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
            String deCrypted = null;
            FileInputStream is = new FileInputStream(new File("C:\\test\\SSH\\PrivateKey\\keystore.properties"));
            Properties properties = new Properties();
            properties.load(is);
            ssh_Public_Private = new SSH_Public_Private();
            boolean isHostNameExist = false;
            if (properties.getProperty(hostUserName) == null) {

                OutputStream outputStream = new FileOutputStream(
                        "C:\\test\\SSH\\PrivateKey\\keystore.properties");
                String passPhraseStored = new String(enCryptPwd());
                properties.setProperty(hostUserName,passPhraseStored );
                properties.store(outputStream, null);
                outputStream.close();
                is.close();
                return checkHostName(hostUserName);
            }else{
                System.out.println(properties.getProperty(hostUserName));
                String passPhrase = properties.getProperty(hostUserName);
                 deCrypted = deCryptPwd(passPhrase);            //isHostNameExist = true;
            }
            return deCrypted;

        }

My encryption and decryption piece of code is as follow :

    private static String enCryptPwd() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        String decrypted = null;
        byte[] encrypted = null;
        try {
            String text = "";
            Scanner sc = new Scanner(System.in);
            System.out.println("Enter your passphrase : " );
            text = sc.next();
            String key = "Bar12345Bar12345"; // 128 bit key
            //String key = "AesSEcREtkeyABCD";
            // Create key and cipher
            Key aesKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            System.out.println(aesKey.getFormat());
            Cipher cipher = Cipher.getInstance("AES");
            // encrypt the text
            cipher.init(Cipher.ENCRYPT_MODE, aesKey);
            encrypted = cipher.doFinal(text.getBytes("UTF-8"));
            System.err.println(new String(encrypted));
            System.err.println(encrypted.length);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return new String(encrypted);
    }

    private static  String deCryptPwd(String encrypted) throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
        String originalString = "";
        try {
            String key = "Bar12345Bar12345"; // 128 bit key
            //String key = "AesSEcREtkeyABCD";
            // Create key and cipher
            Key aesKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            Cipher cipher = Cipher.getInstance("AES");
            // decrypt the text
            cipher.init(Cipher.DECRYPT_MODE, aesKey);
            byte[] encryptBytes = new byte[encrypted.length()];
            encryptBytes = encrypted.getBytes();
            byte[] decrypted = cipher.doFinal(encryptBytes);
            originalString = new String(decrypted, "UTF-8");
            System.out.println(originalString);
            System.err.println(decrypted);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return originalString;
      }

I have been trying to read up and I have tried many other ways by including no padding Algorithms as well. My code writes the output into a property file as :

abced=Y\u201Eh\uFFFD\u00EC-:\u00F9\u00F8mC\u0160\u0002\u00F3#\u00DE

My console outputs are :

Enter your passphrase : abc!@#

After encryption >> Y„h?ì-:ùømCŠó#Þ

16

Read from property file >> Y„h?ì-:ùømCŠó#Þ

dodger
  • 245
  • 1
  • 3
  • 17
  • 1
    Your encoding's off. If you count the characters displayed at "After encryption" you'll notice that there's only 15 characters instead of the expected 16. – Kayaman Aug 10 '16 at 17:04
  • 1
    Note that encryption is byte not character based. Encrypted data is almost always not printable as text, it appears as an array of 8-bit random looking bytes. In order to display, as in a question, hexadecimal encode the encrypted data. – zaph Aug 10 '16 at 17:08
  • 2
    If you encrypt the "passphase", how will you protect that encryption key? – zaph Aug 10 '16 at 17:10
  • General advice: **Always use a fully qualified Cipher string.** `Cipher.getInstance("AES");` may result in different ciphers depending on the default security provider. It most likely results in `"AES/ECB/PKCS5Padding"`, but it doesn't have to be. If it changes, you'll lose compatibility between different JVMs. – Artjom B. Aug 10 '16 at 20:06
  • **Never use [ECB mode](http://crypto.stackexchange.com/q/14487/13022)**. It's deterministic and therefore not semantically secure. You should at the very least use a randomized mode like [CBC](http://crypto.stackexchange.com/q/22260/13022) or [CTR](http://crypto.stackexchange.com/a/2378/13022). It is better to authenticate your ciphertexts so that attacks like a [padding oracle attack](http://crypto.stackexchange.com/q/18185/13022) are not possible. This can be done with authenticated modes like GCM or EAX, or with an [encrypt-then-MAC](http://crypto.stackexchange.com/q/202/13022) scheme. – Artjom B. Aug 10 '16 at 20:06

1 Answers1

2

Generate key using KeyGenerator

KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128, new SecureRandom());
SecretKeySpec aesKey = new SecretKeySpec(kg.generateKey().getEncoded(), "AES");

Use AES/CBC/PKCS5Padding to get cipher instance.

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")

This should work.

Anupam
  • 869
  • 7
  • 13
  • As mentioned it will be cleaner. I would prefer to write 59201e683fec2d3af9f86d43160f323de in place of Y„h?ì-:ùømCŠó#Þ. – Anupam Aug 10 '16 at 17:22
  • 1
    @zaph true. edited answer. – Anupam Aug 10 '16 at 17:28
  • Now I am getting an error like this: `java.security.InvalidKeyException: Parameters missing at com.sun.crypto.provider.CipherCore.init(CipherCore.java:460) at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:307) at javax.crypto.Cipher.implInit(Cipher.java:802) at javax.crypto.Cipher.chooseProvider(Cipher.java:864) at javax.crypto.Cipher.init(Cipher.java:1249) at javax.crypto.Cipher.init(Cipher.java:1186) at ` – dodger Aug 10 '16 at 18:18
  • 1
    @dodger please use KeyGenerator to avoid InvalidKeyException error. Updated answer. – Anupam Aug 11 '16 at 08:32
  • I have been able to get to my solution using [link](http://stackoverflow.com/questions/30383736/illegalblocksizeexception-when-trying-to-encrypt-and-decrypt-a-string-with-aes). Thanks.. – dodger Aug 11 '16 at 19:32