1

我想要一个安全的解决方案,用于在会话期间在其 PC 上缓存用户的密码。

我已经搜索了许多 AES 示例,并且知道这已经在其他地方得到了回答,但我必须说这有点令人困惑。我的aesSecretKeyaesInitialisationVector无法正确解密,但不确定问题出在哪里。

解密导致javax.crypto.BadPaddingException: Given final block not proper padding异常。

我的课看起来像这样

public class LockManagerTest {
    // Need to share the IV and key between encode and decode
    private static byte[] aesInitialisationVector;
    private static SecretKey aesSecretKey;
    private static Cipher aesCipher;

    public LockManagerTest(String sessionKey) {
        try {
            byte[] key = getSecretKey(sessionKey.toCharArray(), getSalt(32),
                                      65536, 128);
            aesSecretKey = new SecretKeySpec(key, "AES");
            aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey);
            AlgorithmParameters params = aesCipher.getParameters();
            aesInitialisationVector =
                    params.getParameterSpec(IvParameterSpec.class).getIV();
        } catch (Exception e) {
            Util.handleException(e);
        }
    }

    private static byte[] getSecretKey(char[] plaintext,
                                       byte[] salt,
                                       int iterations,
                                       int keySize)
            throws Exception {
        PBEKeySpec spec = new PBEKeySpec(plaintext, salt, iterations, keySize);
        SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        return skf.generateSecret(spec).getEncoded();
    }

    private static byte[] getSalt(int keyLength) throws Exception {
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
        byte[] salt = new byte[keyLength];
        random.nextBytes(salt);
        return salt;
    }

    public byte[] encryptedAes(char[] input) throws Exception {
        // WRONG
        // aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey);
        //
        aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey, 
                       new IvParameterSpec(aesInitialisationVector);
        CharBuffer cBuf = CharBuffer.wrap(input);
        byte[] normalised = Charset.forName("UTF-8").encode(cBuf).array();
        byte[] ciphertext = aesCipher.doFinal(normalised);
        return ciphertext;
    }

    public byte[] decryptAes(byte[] ciphertext) throws Exception {
        aesCipher.init(Cipher.DECRYPT_MODE,
                aesSecretKey, new IvParameterSpec(aesInitialisationVector));
        byte[] plaintext = aesCipher.doFinal(ciphertext);
        return plaintext;
    }
}

关于安全级别的评论也受到赞赏。

4

3 回答 3

1

init()打电话时需要通过IV encryptedAes()

于 2013-08-30T02:35:17.730 回答
0

AES 是一种 CBC 算法,将输入分成块。这些块必须具有特定的大小。在 AES 的情况下,我相信它是 16 个字节。如果输入不是 16 字节的倍数,则必须在加密前用空值填充。

于 2013-08-30T02:36:21.460 回答
0

您需要传递用于加密的相同 IV,而不是在解密时生成新的 IV。记住 AES 是对称密码。

编辑:你正在做的是:

public byte[] encryptedAes(char[] input) throws Exception {
        // WRONG
        // aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey);
        //
        aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey, 
                       new IvParameterSpec(aesInitialisationVector);
        CharBuffer cBuf = CharBuffer.wrap(input);
        byte[] normalised = Charset.forName("UTF-8").encode(cBuf).array();
        byte[] ciphertext = aesCipher.doFinal(normalised);
        return ciphertext;
}

而是将 IvParameterSpec 存储为静态,如下所示(您可以在程序中进行适当的变量声明)

    public byte[] encryptedAes(char[] input) throws Exception {
//declare as static so initVector can be reused when decrypting
         IvParamterSpec initVector = new IvParameterSpec(aesSecretKey);       
            aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey, initVector);
            CharBuffer cBuf = CharBuffer.wrap(input);
            byte[] normalised = Charset.forName("UTF-8").encode(cBuf).array();
            byte[] ciphertext = aesCipher.doFinal(normalised);
            return ciphertext;
        }

进行更改,然后运行您的程序。确保在解密时使用相同的 initVector。在您正在创建的程序中new IvParameterSpec(...)

于 2013-08-30T02:57:51.227 回答