Home > Mobile >  How to create javax.crypto.SecretKey based on password and salt
How to create javax.crypto.SecretKey based on password and salt

Time:07-04

I am not a security expert.

I have a requirement to generate javax.crypto.SecretKey based on password and salt.

In the existing code, we already have logic to generate javax.crypto.SecretKey but not based on password and salt`.

Also, in the existing code we already encrypt and decrypt using the javax.crypto.SecretKey. There is already lot of data in DB which is encrypted using existing encrypt code and I dont think I can change existing encrypt and decrypt logic.

I am getting below the error when I try to decrypt data using the key generated based on password and salt with existing decrypt code.

key.getAlgorithm(): DESede
encryptedData: [B@31dc339b
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
    at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
    at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
    at com.sun.crypto.provider.DESedeCipher.engineDoFinal(DESedeCipher.java:294)
    at javax.crypto.Cipher.doFinal(Cipher.java:2168)
    at com.arjun.mytest.PMAdminKeyTest.main(PMAdminKeyTest.java:41)

import java.security.KeyStore;
import java.security.Provider;
import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class PMAdminKeyTest {

    public static void main(String[] args) throws Exception {
        // Requirement is to generate Key based on password and salt
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec keySpec = new PBEKeySpec("password".toCharArray(), "salt".getBytes(), 65536, 192);
        SecretKey key = new SecretKeySpec(secretKeyFactory.generateSecret(keySpec).getEncoded(), "DESede");

        System.out.println("key.getAlgorithm(): "   key.getAlgorithm());

        byte[] data = "12345678".getBytes("UTF8");

        // Existing encrypt and decrypt code. There is already lot of data in DB
        // encrypted in this manner. I dont think I can change this code.
        Cipher cipher = Cipher.getInstance(key.getAlgorithm()   "/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] encryptedData = cipher.doFinal(data);

        System.out.println("encryptedData: "   encryptedData.toString());

        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decryptedData = cipher.doFinal(data);

        System.out.println("decryptedData: "   decryptedData.toString());
    }

}

CodePudding user response:

You are not decrypting the encrypted data, you are simply trying to decrypt the original data.

Also while printing the data use UTF-8

import java.security.spec.KeySpec;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class PMAdminKeyTest {

    public static void main(String[] args) throws Exception {
        // Requirement is to generate Key based on password and salt
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec keySpec = new PBEKeySpec("password".toCharArray(), "salt".getBytes(), 65536, 192);
        SecretKey key = new SecretKeySpec(secretKeyFactory.generateSecret(keySpec).getEncoded(), "DESede");

        System.out.println("key.getAlgorithm(): "   key.getAlgorithm());

        byte[] data = "12345678".getBytes("UTF8");

        // Existing encrypt and decrypt code. There is already lot of data in DB
        // encrypted in this manner. I dont think I can change this code.
        Cipher cipher = Cipher.getInstance(key.getAlgorithm()   "/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] encryptedData = cipher.doFinal(data);

        System.out.println("encryptedData: "   encryptedData.toString());

        cipher.init(Cipher.DECRYPT_MODE, key);

        // Notice this
        byte[] decryptedData = cipher.doFinal(encryptedData);

        // while printing the data use UTF-8 
        System.out.println("decryptedData: "    new String(decryptedData, "UTF-8"));
    }
}

CodePudding user response:

The only issue I can see is that you pass the unencrypted data to the Cipher in decrypt mode, which won't work. (The cipher obviously cannot decrypt data which is not encrypted without getting odd results.) So change

byte[] decryptedData = cipher.doFinal(data);

to

byte[] decryptedData = cipher.doFinal(encryptedData);

Then, everything works fine. Altough I doubt this error exists in your productive code, so if you still have problems on that one, feel free to ask a new question.

  • Related