尝试使用Java解密时出现“错误的算法”错误

时间:2012-03-12 16:08:07

标签: java sqlite encryption encoding aes

我首先要描述我遇到的问题,然后给出我想要做的事情的一些背景知识。最后,我将粘贴一些相关的代码片段。

我正在尝试使用https://stackoverflow.com/a/992413/171993中指定的方法实现密钥加密/解密。如果我按原样使用该示例,它可以工作(虽然我确实注意到我需要重新实例化Cipher类,否则解密会产生垃圾)。但是,在我的实现中,我得到以下异常:

java.security.InvalidKeyException: Wrong algorithm: AES or Rijndael required
    at com.sun.crypto.provider.AESCrypt.init(AESCrypt.java:77)
    at com.sun.crypto.provider.CipherBlockChaining.init(CipherBlockChaining.java:91)
    at com.sun.crypto.provider.CipherCore.init(CipherCore.java:469)
    at com.sun.crypto.provider.AESCipher.engineInit(AESCipher.java:217)
    at javax.crypto.Cipher.implInit(Cipher.java:790)
    at javax.crypto.Cipher.chooseProvider(Cipher.java:848)
    at javax.crypto.Cipher.init(Cipher.java:1347)
    at javax.crypto.Cipher.init(Cipher.java:1281)
    at securitytest.SecurityManager.getCipher(SecurityManager.java:175)
    at securitytest.SecurityManager.decryptSecretKey(SecurityManager.java:379)
    at securitytest.SecurityManager.<init>(SecurityManager.java:82)
    at securitytest.Test.main(Test.java:44)

为了击败这个显而易见的问题,是的,我使用相同的算法:事实上,我将AES/CBC/PKCS5Padding分配给一个常量,并使用它来实例化Cipher类进行加密和解密。我还尝试仅使用AES实例化Cipher进行解密,但这也不起作用。

我要做的是使用AES / CBC / PKCS5Padding对密钥进行密码保护。我生成一个随机盐和初始化矢量。在加密密钥后,我将初始化向量(字节数组)附加到加密值(也是一个字节数组,创建一个新数组)。然后,我在Base64中对此值进行编码,并将其与salt一起存储在Sqlite数据库中(为简单起见,我将其存储为以逗号分隔的值字符串)。但是当我尝试解密时,我得到了上述异常。我可以在调用加密方法之后直接验证,并且直接在解密方法之前验证,以下值完全相同(转换为Base64以便我可以将其打印出来):

  1. 初始化向量
  2. 加密的密钥(即密文)
  3. 我尝试过Java 6和7:两者都给出了相同的结果。我还排除了无限强度管辖权政策文件的问题。事实上,如果我用另一种算法替换“AES”并相应地调整盐的长度(例如“Blowfish”,IV长度为8,产生java.security.InvalidKeyException: Wrong algorithm: Blowfish required),我会得到类似的错误。

    谷歌无法帮助我解决这个问题。如果有人能够对此有所了解,我将非常感激。

    以下是一些代码片段(道歉,这有点粗糙):

    private static final int INIT_VECTOR_LENGTH = 16;
    private static final int PRIVATE_KEY_LENGTH = 128;
    private static final int SALT_LENGTH = 16;
    private static final int PBE_KEYSPEC_ITERATIONS = 65536;
    
    private static final String CIPHER_ALGORITHM = "AES";
    private static final String CIPHER_ALGORITHM_MODE = "CBC";
    private static final String CIPHER_ALGORITHM_PADDING = "PKCS5Padding";
    private static final String DIGEST = "SHA1";
    private static final String PLAINTEXT_ENCODING = "UTF8";
    private static final String PRNG = DIGEST + "PRNG";
    private static final String SECRET_KEY_FACTORY = "PBKDF2WithHmac" + DIGEST;
    
    private static final String CIPHER = CIPHER_ALGORITHM + "/" + CIPHER_ALGORITHM_MODE + "/" + CIPHER_ALGORITHM_PADDING;
    
    private IvParameterSpec ivSpec;
    private final BASE64Encoder encoder = new BASE64Encoder();
    private final BASE64Decoder decoder = new BASE64Decoder();
    
    private Cipher getCipher(SecretKey key, int mode) {
    
        Cipher cipher = null;
    
        try {
            cipher = Cipher.getInstance(CIPHER);
        }
        catch (NoSuchAlgorithmException e) {System.err.println(System.err.println(e.getMessage());}
        catch (NoSuchPaddingException e) {System.err.println(e.getMessage());}
    
        try {
            if (mode == Cipher.ENCRYPT_MODE) {
                cipher.init(mode, key);
                AlgorithmParameters params = cipher.getParameters();
                ivSpec = params.getParameterSpec(IvParameterSpec.class);
            }
            else {
                /* This is my point-of-failure. */
                cipher.init(mode, key, ivSpec);
            }
        }
        catch (InvalidKeyException e) {System.err.println(e.getMessage());}
        catch (InvalidAlgorithmParameterException e) {System.err.println(e.getMessage());}
        catch (InvalidParameterSpecException e) {System.err.println(e.getMessage());}
    
        return cipher;
    
    }
    
    private SecurityData.Secrets generateSecrets(SecretKey decryptedKey, byte[] salt, String passphrase) {
    
        /* Generate a new key for encrypting the secret key. */
        byte[] raw = null;
        PBEKey key = null;
        PBEKeySpec password = new PBEKeySpec(passphrase.toCharArray(), salt, PBE_KEYSPEC_ITERATIONS, PRIVATE_KEY_LENGTH);
        SecretKeyFactory factory = null;
        byte[] initVector = null;
        byte[] secretKeyBytes = decryptedKey.getEncoded();
    
        try {
            factory = SecretKeyFactory.getInstance(SECRET_KEY_FACTORY);
            key = (PBEKey) factory.generateSecret(password);
        }
        catch (NoSuchAlgorithmException e) {System.err.println(e.getMessage());}
        catch (InvalidKeySpecException e) {System.err.println(e.getMessage());}
    
        SecretKeySpec newKey = new SecretKeySpec(key.getEncoded(), CIPHER_ALGORITHM);
    
        /* Encrypt the secret key. */
        IvParameterSpec ivSpec = new IvParameterSpec(initVector);
        Cipher cipher = getCipher(newKey, ivSpec, Cipher.ENCRYPT_MODE);
    
        try {
            raw = cipher.doFinal(secretKeyBytes);
        }
        catch (IllegalBlockSizeException e) {System.err.println(e.getMessage());}
        catch (BadPaddingException e) {System.err.println(e.getMessage());}
    
        return new SecurityData.Secrets(encoder.encode(concatByteArrays(initVector, raw)), joinByteArray(salt));
    
    }
    
    private SecretKey decryptSecretKey(String encryptedKey, String salt, String passphrase) {
    
        /* Get initialisation vector. */
        byte[] raw = null, decoded = null, initVector = new byte[INIT_VECTOR_LENGTH];
        try {
            decoded = decoder.decodeBuffer(encryptedKey);
        } catch (IOException e) {System.err.println(e.getMessage());}
        System.arraycopy(decoded, 0, initVector, 0, INIT_VECTOR_LENGTH);
        raw = new byte[decoded.length-INIT_VECTOR_LENGTH];
        System.arraycopy(decoded, INIT_VECTOR_LENGTH, raw, 0, decoded.length-INIT_VECTOR_LENGTH);
        IvParameterSpec ivSpec = new IvParameterSpec(initVector);
    
        /* Generate the key. */
        byte[] rawSalt = splitByteArrayString(salt);
        PBEKeySpec password = new PBEKeySpec(passphrase.toCharArray(), rawSalt, PBE_KEYSPEC_ITERATIONS, PRIVATE_KEY_LENGTH);
        SecretKeyFactory factory = null;
        PBEKey key = null;
        try {
            factory = SecretKeyFactory.getInstance(SECRET_KEY_FACTORY);
            key = (PBEKey) factory.generateSecret(password);
        }
        catch (NoSuchAlgorithmException e) {System.err.println(e.getMessage());}
        catch (InvalidKeySpecException e) {System.err.println(e.getMessage());}
    
        Cipher cipher = getCipher(key, Cipher.DECRYPT_MODE);
    
        /* Decrypt the message. */
        byte[] stringBytes = null;
        try {
            stringBytes = cipher.doFinal(raw);
        }
        catch (IllegalBlockSizeException e) {System.err.println(e.getMessage());}
        catch (BadPaddingException e) {System.err.println(e.getMessage());}
    
        /* Converts the decoded message to a String. */
        String clear = null;
        try {
            clear = new String(stringBytes, PLAINTEXT_ENCODING);
        }
        catch (UnsupportedEncodingException e) {System.err.println(e.getMessage());}
    
        return new SecretKeySpec(clear.getBytes(), CIPHER_ALGORITHM);
    
    }
    

1 个答案:

答案 0 :(得分:5)

SecretKey对象需要从其getAlgorithm()方法返回“AES”。这就是为什么这个例子有这些步骤的原因:

SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");