数据的本地加密和解密

时间:2018-10-29 18:32:41

标签: java encryption

您好,stackoverflow的人们,

我目前正在我的应用程序中开发/实施安全措施,并且在某些数据的加密和解密方面遇到了一些问题。

事实上,昨天我能够加密一条消息,然后使用该类的相同实例解密该加密的消息-但反之亦然。这就是我今天要发布的(关于此问题)-

从我工作过的linux系统中推送最新更改并尝试继续在Windows pc上工作后,抛出了以下错误:

    java.security.InvalidKeyException: Illegal key size or default parameters
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1026)
    at javax.crypto.Cipher.implInit(Cipher.java:801)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
    at javax.crypto.Cipher.init(Cipher.java:1249)
    at javax.crypto.Cipher.init(Cipher.java:1186)
    at com.x.backend.security.Decrypter.encrypt(Decrypter.java:43)
    at crypto.CryptoTest.main(CryptoTest.java:11)
java.lang.NullPointerException
    at javax.crypto.spec.IvParameterSpec.<init>(IvParameterSpec.java:53)
    at com.x.backend.security.Decrypter.decrypt(Decrypter.java:54)
    at crypto.CryptoTest.main(CryptoTest.java:12)

所以我尝试找到一种解决方案,但没有找到任何解决方案,所以这是我到目前为止尝试过的:

  • 升级到JDK 9/10/11对我来说不是一个选择,我尝试了一下,我惨败了,如果我想升级,那就太适应了(这不值得)到目前为止的努力)

  • 我已经阅读了有关Java密码学扩展(JCE)的内容,但这不适用于我,因为我正在运行JDK版本 1.8.66 (从1.8.55开始)不再需要在Java目录中安装任何类型的文件)

  • 无效的缓存(IntelliJ)+重新启动我的PC

  • 将项目状态重置为初始提交(git硬重置)

我的课:

public class Decrypter {

    private static Decrypter instance;

    private Cipher cipher;

    private byte[] IV;

    private SecretKeySpec secretKeySpec;

    private Decrypter() {
        initialize();
    }

    private void initialize() {
        try {
            final byte[] salt = "@1jq3#-o1_uHvaL:".getBytes();
            final String key = "hehexd";
            final int iterationCount = 12;
            final int keyStrength = 256;
            this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            this.secretKeySpec = new SecretKeySpec(SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(new PBEKeySpec(key.toCharArray(), salt, iterationCount, keyStrength)).getEncoded(), "AES");
        } catch (InvalidKeySpecException | NoSuchAlgorithmException | NoSuchPaddingException e) {
            e.printStackTrace();
        }
    }

    public final String encrypt(String data) {
        try {
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            IV = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
            return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public final String decrypt(String base64EncryptedData) {
        try {
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(IV));
            byte[] decryptedData = Base64.getDecoder().decode(base64EncryptedData);
            byte[] utf8 = cipher.doFinal(decryptedData);
            return new String(utf8, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public static Decrypter getInstance() {
        return instance == null ? instance = new Decrypter() : instance;
    }
}

我的考试班:

    public class CryptoTest {

    public static void main(String[] args) {
        String encrypted = Decrypter.getInstance().encrypt("lol");
        String decrypted = Decrypter.getInstance().decrypt(encrypted);
        System.out.println("Verification: PLAINTEXT -> ENCRYPT: " + encrypted);
        System.out.println("Verification: ENCRYPT -> DECRYPT: " + decrypted);
    }
}

请不要介意任何常规的错误/错误做法,在密码学方面,我是新来的人(目前正在读懂我的方法)

任何帮助或投入将不胜感激!

编辑:

感谢您的即时答复!

很不幸,我遇到了另一个错误。 完整输出:

    Verification: PLAINTEXT -> ENCRYPT: 
java.security.InvalidKeyException: Illegal key size
Verification: PLAINTEXT -> DECRYPT: 
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)
    at javax.crypto.Cipher.implInit(Cipher.java:805)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
    at javax.crypto.Cipher.init(Cipher.java:1396)
    at javax.crypto.Cipher.init(Cipher.java:1327)
    at com.x.backend.security.Decrypter.encrypt(Decrypter.java:48)
    at crypto.CryptoTest.main(CryptoTest.java:11)
java.security.InvalidKeyException: No installed provider supports this key: javax.crypto.spec.SecretKeySpec
    at javax.crypto.Cipher.chooseProvider(Cipher.java:893)
    at javax.crypto.Cipher.init(Cipher.java:1396)
    at javax.crypto.Cipher.init(Cipher.java:1327)
    at com.x.backend.security.Decrypter.decrypt(Decrypter.java:58)
    at crypto.CryptoTest.main(CryptoTest.java:12)

更改代码:

 public final String encrypt(String data) {
        try {
            IV = new IvParameterSpec("testtesttesttest".getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, IV);
            return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

2 个答案:

答案 0 :(得分:2)

我不知道您从何处获得有关JDK 1.8.66具有无限强度JCE的信息。美国境外情况并非如此。

您仍然需要从Oracle下载并安装无限强度的JCE JAR。

如果您确定 拥有无限的JCE实力,请尝试添加到jre/lib/security/java.security

crypto.policy=unlimited

默认情况下,仅从Java SE 8u161开始才启用无限强度。因此,这里不需要此设置。


另一方面,可以改善您的错误处理。最好将e.printStackTrace()替换为throw new RuntimeException(e),以将所有这些初始化错误都视为致命错误(在那个阶段,它们 会破坏交易)。

答案 1 :(得分:0)

结果是,对最新JDK的更新修复了所有已发生的问题。现在,我可以轻松地独立解密和加密内容了!

感谢所有参与寻找解决方案的人!