如何基于密码和盐创建javax.crypto.SecretKey



我不是安全专家。

我需要基于passwordsalt生成javax.crypto.SecretKey

在现有的代码中,我们已经有逻辑来生成javax.crypto.SecretKey,但不是基于password and盐'。

此外,在现有的代码中,我们已经使用javax.crypto.SecretKey进行加密和解密。数据库中已经有很多数据使用现有的加密代码加密,我认为我不能改变现有的加密和解密逻辑。

当我尝试使用基于passwordsalt与现有解密代码生成的密钥解密数据时,我正在低于错误。

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());
}
}

我能看到的唯一问题是,您将未加密的数据以解密模式传递给Cipher,这将不起作用。(密码显然无法解密未加密的数据,而不会得到奇怪的结果。)所以改变

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

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

那么,一切都很好。虽然我怀疑这个错误存在于你的生产代码中,所以如果你仍然有问题,请随时提出新的问题。

您不是在解密加密的数据,您只是在尝试解密原始数据。

同时在打印数据时使用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"));
}
}

最新更新