我正在使用下面的命令迁移一个对消息进行加密和解密的Java代码,就像OpenSSL低于1.1.1一样:
echo -n "password" | openssl enc -aes-256-cbc -a -k secretKey -md sha256
这工作得很好,没有问题,当我们想要使用OpenSSL1.1.1或更高版本时,问题来了,我们会收到著名的消息:
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
阅读时,两个选项都基于-pbkdf2,在一种情况下,我们 Select 迭代次数(-iter),在另一种情况下,我们保留默认迭代次数(-pbkdf2),所以我保留了它.
echo -n "password" | openssl enc -aes-256-cbc -a -k secretKey -pbkdf2
我已经看到,使用javax.crypto库并引用-pbkdf2的唯一方法是SecretKeyFactory.getInstance("PBKDF2withHmacSHA256")
,因为它显示为here.我try 使其适应我的原始代码(在下面的代码行中),更改了此代码的key和IV,但我无法使其工作,我收到以下错误:
Exception in thread "main" modified.EncryptionDecryptionException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
我添加了新方法来生成keyAndIV,并保留了旧方法,但我无法使其工作.你知道会出什么问题吗?非常感谢!
import java.nio.charset.StandardCharsets;
import java.security.Invalid算法rithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuch算法rithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Base64;
import java.util.Base64.Decoder;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class modified
{
private static final String SECRET_KEY = "secretKey";
private static final String SALT_KEY = "Salted__";
private static final int keylen = 32;
private static final int ivlen = 16;
public static void main(String[] args) throws Exception {
String example= "U2FsdGVkX19hh2C4Gxe3ghDb/qY0x8rC4SZaZEMv5yg=";
String decryptedText = modified.decryptPassword( example.toCharArray());
System.out.println("value -> "+decryptedText);
}
private modified()
{
throw new IllegalStateException("Utility class");
}
public static String decryptPassword(char[] source) throws EncryptionDecryptionException
{
return decrypt(source, SECRET_KEY);
}
public static String encryptPassword(char[] source) throws EncryptionDecryptionException
{
return encrypt(source, SECRET_KEY);
}
private static String decrypt(char[] source, String sk) throws EncryptionDecryptionException
{
try
{
final byte[] magic = SALT_KEY.getBytes(StandardCharsets.UTF_8);
final Decoder decoder = Base64.getDecoder();
final byte[] inBytes = decoder.decode(String.valueOf(source));
checkMagic(magic, inBytes);
byte[] salt = Arrays.copyOfRange(inBytes, magic.length, magic.length + 8);
final Cipher cipher = getCipher(Cipher.DECRYPT_MODE, source, sk, salt);
final byte[] clear = cipher.doFinal(inBytes, 16, inBytes.length - 16);
return new String(clear, StandardCharsets.UTF_8);
}
catch (NoSuch算法rithmException | NoSuchPaddingException | InvalidKeyException
| Invalid算法rithmParameterException | IllegalBlockSizeException | BadPaddingException e)
{
throw new EncryptionDecryptionException(e.getMessage(), e);
}
}
private static String encrypt(char[] source, String sk) throws EncryptionDecryptionException
{
try
{
final byte[] magic = SALT_KEY.getBytes(StandardCharsets.UTF_8);
final byte[] inBytes = String.valueOf(source).getBytes(StandardCharsets.UTF_8);
byte[] salt = (new SecureRandom()).generateSeed(8);
final Cipher cipher = getCipher(Cipher.ENCRYPT_MODE, source, sk, salt);
byte[] data = cipher.doFinal(inBytes);
data = concat(concat(magic, salt), data);
return Base64.getEncoder().encodeToString(data);
}
catch (NoSuch算法rithmException | NoSuchPaddingException | InvalidKeyException
| Invalid算法rithmParameterException | IllegalBlockSizeException | BadPaddingException e)
{
throw new EncryptionDecryptionException(e.getMessage(), e);
}
}
private static Cipher getCipher(int cipherMode, char[] source, String sk, byte[] salt)
throws NoSuch算法rithmException,
NoSuchPaddingException, InvalidKeyException, Invalid算法rithmParameterException
{
final byte[] secret = sk.getBytes(StandardCharsets.UTF_8);
final byte[] passAndSalt = concat(secret, salt);
//byte[] keyAndIv = getKeyAndIv(passAndSalt);
byte[] keyAndIv = getNewKeyAndIvThatSupportPBKDF(source, salt);
final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(cipherMode, key, new IvParameterSpec(iv));
Arrays.fill(passAndSalt, (byte) 0);
return cipher;
}
private static byte[] concat(final byte[] a, final byte[] b)
{
final byte[] c = new byte[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
private static void checkMagic(final byte[] magic, final byte[] inBytes)
{
final byte[] shouldBeMagic = Arrays.copyOfRange(inBytes, 0,
magic.length);
if (!Arrays.equals(shouldBeMagic, magic))
{
throw new EncryptionDecryptionException("DecriptionException: Bad magic number");
}
}
private static byte[] getNewKeyAndIvThatSupportPBKDF(char[] source, byte[] salt) throws EncryptionDecryptionException
{
try
{
return SecretKeyFactory.getInstance("PBKDF2withHmacSHA256")
.generateSecret( new PBEKeySpec(source, salt, 10000, (keylen+ivlen)*8)
).getEncoded();
}
catch (InvalidKeySpecException | NoSuch算法rithmException e)
{
throw new EncryptionDecryptionException(e.getMessage(), e);
}
}
private static byte[] getKeyAndIv(final byte[] passAndSalt) throws NoSuch算法rithmException
{
byte[] hash = new byte[0];
byte[] keyAndIv = new byte[0];
for (int i = 0; i < 3; i++)
{
final byte[] data = concat(hash, passAndSalt);
MessageDigest md;
md = MessageDigest.getInstance("SHA-256");
hash = md.digest(data);
keyAndIv = concat(keyAndIv, hash);
}
return keyAndIv;
}
}