我正在使用下面的命令迁移一个对消息进行加密和解密的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;
  }

}


推荐答案

在应该使用密钥的地方使用source(这是Base64编码的密文加).以下是您的代码的一个经过修剪和最小程度更正的版本:

//nopackage
import java.nio.charset.StandardCharsets;
//--import java.security.MessageDigest;
//--import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;


public class SO76624363encpbkdf2
{

  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 = decryptPassword( example.toCharArray());
      System.out.println("value -> "+decryptedText);
  }

  public static String decryptPassword(char[] source) throws Exception
  {
    return decrypt(source, SECRET_KEY);
  }
/*
  public static String encryptPassword(char[] source) throws Exception
  {

    return encrypt(source, SECRET_KEY);
  }
*/
  private static String decrypt(char[] source, String sk) throws Exception
  {
      final byte[] magic = SALT_KEY.getBytes(StandardCharsets.UTF_8);
      final byte[] inBytes = Base64.getDecoder() .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);
  }
/*
  private static String encrypt(char[] source, String sk) throws Exception
  {
      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);
  }
*/
  private static Cipher getCipher(int cipherMode, char[] source, String sk, byte[] salt)
      throws Exception
  {
    //--final byte[] secret = sk.getBytes(StandardCharsets.UTF_8);
    //--final byte[] passAndSalt = concat(secret, salt);

    //byte[] keyAndIv = getKeyAndIv(passAndSalt);
    byte[] keyAndIv = getNewKeyAndIvThatSupportPBKDF(sk, 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) throws Exception
  {
    final byte[] shouldBeMagic = Arrays.copyOfRange(inBytes, 0,
                                                    magic.length);
    if (!Arrays.equals(shouldBeMagic, magic))
    {
      throw new Exception("Bad magic number");
    }
  }


  private static byte[] getNewKeyAndIvThatSupportPBKDF(String secret,  byte[] salt) throws Exception
  {
      return SecretKeyFactory.getInstance("PBKDF2withHmacSHA256")
          .generateSecret( new PBEKeySpec(secret.toCharArray(), salt, 10000, (keylen+ivlen)*8)
          ).getEncoded();
  }
/*
  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;
  }
*/
}

Java相关问答推荐

Spring Webocket:尽管凭据设置为False,但MLhttpsify和Fetch请求之间的CORS行为存在差异

Annotation @ Memphier无法正常工作,并表示:class需要一个bean,但找到了2个bean:

如何将kotlin代码转换为java

Quarkus keycloat配置不工作.quarkus. keycloak. policy—enforcer. enable = true在. yaml表示中不工作

如何以干净的方式访问深度嵌套的对象S属性?

Java中如何根据Font.canDisplay方法对字符串进行分段

滚动视图&不能在alert 对话框中工作(&Q;&Q;)

具有阻塞方法的开源库是否应该为执行提供异步选项?

解释左移在Java中的工作原理

更新AWS凭据

为什么同步数据块无效?

Java堆中的许多java.time.ZoneRegion实例.ZoneId实例不应该被缓存吗?

项目react 堆中doOnComplete()和Subscribe()的第三个参数之间的差异

有没有办法知道在合并中执行了什么操作?

如何制作回文程序?

如何通过用户ID向用户发送私信

为什么Instant没有从UTC转换为PostgreSQL的时区?

如何设置默认序列生成器分配大小

如果c不为null,Arrays.sort(T[]a,Comparator<;?super T>;c)是否会引发ClassCastException?

使用原子整数的共享计数器并发增量