0

I have a PBE-generated secret key and I ciphered a string using the algorithm "PBEWithHmacSHA256AndAES_128" however I'm unable to decipher the said string.

Secret key generate:

private final static byte[] SALT = { (byte) 0xc9, (byte) 0x36, (byte) 0x78, (byte) 0x99, (byte) 0x52, (byte) 0x3e, (byte) 0xea,
        (byte) 0xf2 };

PBEKeySpec keySpec = new PBEKeySpec(pwd.toCharArray(), SALT, 20 , 128);     
    try {
        SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_128");
        PRIVATE_KEY = kf.generateSecret(keySpec);
    } catch (NoSuchAlgorithmException | InvalidKeySpecException  e) {
        e.printStackTrace();
    }

Encypt String:

private static String cipherString(String string) {


    PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(SALT, 100);
    Cipher cipher;
    try {
        cipher = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
        cipher.init(Cipher.ENCRYPT_MODE, PRIVATE_KEY, pbeParameterSpec);
        byte[] input = string.getBytes();
        byte[] encryptedp = cipher.doFinal(input);

        return encryptedp.toString();
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

Decrypt String:

private static String decipherString(String string) {
    Cipher c;
    try {
        c = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");

        c.init(Cipher.DECRYPT_MODE, PRIVATE_KEY);

        byte[] input = string.getBytes();
        byte[] encryptedp = c.doFinal(input);

        return encryptedp.toString();

    } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;
}
erickson
  • 265,237
  • 58
  • 395
  • 493
Dariko77
  • 141
  • 1
  • 8
  • 2
    And what happens? If there's an error, include it. If results are not what you expect, describe what you get and how it differs. – erickson Apr 03 '17 at 16:54
  • 3
    `encryptedp.toString()` doesn't return the encrypted String. When dealing with encrypted bytes, you should only manipulate the byte array –  Apr 03 '17 at 17:02
  • Possible duplicate of [Encrypt and decrypt with AES and Base64 encoding](http://stackoverflow.com/questions/3954611/encrypt-and-decrypt-with-aes-and-base64-encoding) – Artjom B. Apr 03 '17 at 20:55
  • Also, see [Java: Syntax and meaning behind “[B@1ef9157”? Binary/Address?](http://stackoverflow.com/questions/1040868/java-syntax-and-meaning-behind-b1ef9157-binary-address) You need to use Base64 or similar to transport your ciphertext. – Artjom B. Apr 03 '17 at 20:56
  • You didn't give an explicit iv, so a random one was created. You never retrieved and stored that, so you don't have it available when it's time to decrypt. Thus it fails. – Frugal Guy Oct 13 '22 at 18:50

1 Answers1

2

Just use the following code that works on J2SE. As the algorithm PBEWithHmacSHA256AndAES_128 uses AES in CBC mode internally we also have to provide an IV, which is my example generated randomly. You have to use the same IV for encryption as well as decryption. For security reasons for each encryption you should use a new random IV and save it together with the encrypted text.

    SecureRandom rnd = new SecureRandom();
    byte[] iv = new byte[16];
    rnd.nextBytes(iv);
    
    String password = "password";
    byte[] plaintext = "plaintext".getBytes(StandardCharsets.UTF_8);

    IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
    PBEParameterSpec pbeParamSpec = new PBEParameterSpec(SALT, 10000, ivParamSpec);
    PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
    try {
        SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_128");
        SecretKey secretKey = kf.generateSecret(keySpec);

        // On J2SE the SecretKeyfactory does not actually generate a key, it just wraps the password.
        // The real encryption key is generated later on-the-fly when initializing the cipher
        System.out.println(new String(secretKey.getEncoded()));

        // Encrypt
        Cipher enc = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
        enc.init(Cipher.ENCRYPT_MODE, secretKey, pbeParamSpec);
        byte[] encrypted = enc.doFinal(plaintext);
        String encryptedBase64 = new BASE64Encoder().encode(encrypted);
        System.out.println("Encrypted text: " + encryptedBase64);

        // Decrypt
        Cipher dec = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
        dec.init(Cipher.DECRYPT_MODE, secretKey, pbeParamSpec);
        byte[] decrypted = dec.doFinal(new BASE64Decoder().decode(encryptedBase64));
        String message = new String(decrypted, StandardCharsets.UTF_8);
        
        System.out.println(message);

    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
        e.printStackTrace();
    }
JMax
  • 1,134
  • 1
  • 11
  • 20
  • Now I have a problem when I try to Cipher, that gives me a runtime exception " java.security.InvalidKeyException: Invalid AES key length: 11 bytes " – Dariko77 Apr 03 '17 at 21:20
  • My first answer was wrong - I updated it. On J2SE you should use the code I posted. – JMax Apr 04 '17 at 07:41
  • @JMax I have a question, imagine a scenario where you have a server that encrypts and decrypts a text file with a passoword based encryption like this one that u have posted, if the server falls, is it possible to decrypt the encrypted file again? – Bruno Cotrim Apr 01 '22 at 16:54
  • @BrunoCotrim Sorry, but I don't understand why you think that the server would play a role in this encryption. You just need the password, the PBE parameters like salt, iterations, the IV, and of course the encrypted data and the knowledge that the algorithm `PBEWithHmacSHA256AndAES_128` was used to decrypt the data. – JMax Apr 02 '22 at 17:07