如何在android中使用初始化向量进行AES-256加密和解密

时间:2012-02-28 13:47:19

标签: android encryption aes

在我的应用程序中,我希望通过加密来存储一些安全数据。当用户希望我需要通过解密来向他显示它。 这工作正常。 但问题是我需要为每条消息存储加密消息和初始化向量。这个初始化向量是在加密时生成的,我必须在解密时使用它来获取原始消息。

因此,如果用户存储1000条消息,我需要存储这1000条加密消息和相应的1000条初始化向量。我想避免为每条消息存储初始化向量。

请告诉我使用初始化矢量进行AES-256加密的方法。

以下是我的加密和解密代码

/*
     * This method will do the AES-256 encryption.
     */
    private byte[] encrypt(char[] raw, String cardno) {
     //  This raw is some unique key like password.      
        SecretKeyFactory factory = null;
        SecretKey tmp = null;
        Cipher cipher = null;
        byte[] ciphertext = null;
        AlgorithmParameters params = null;
        try {
            factory = SecretKeyFactory.getInstance("PBEWITHSHA-256AND256BITAES-CBC-BC");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        KeySpec spec = new PBEKeySpec(raw, mSalt, 1024, 256);

        try {
            if (factory != null)
                tmp = factory.generateSecret(spec);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        if (tmp != null)
            mSecret = new SecretKeySpec(tmp.getEncoded(), "AES");

        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
        try {
            if (cipher != null)
                cipher.init(Cipher.ENCRYPT_MODE, mSecret);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        if (cipher != null)
            params = cipher.getParameters();
        try {

            mIV = params.getParameterSpec(IvParameterSpec.class).getIV();

        } catch (InvalidParameterSpecException e) {
            e.printStackTrace();
        }
        try {
            ciphertext = cipher.doFinal(cardno.getBytes("UTF-8"));
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return ciphertext;

    }





/*
     * This will decrypt the encrypted data based on provided key
     */
    private byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
        //This raw is initialization vector generated while encrypting 
        Cipher cipher = null;
        byte[] decrypted = null;

        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
        try {
            cipher.init(Cipher.DECRYPT_MODE, mSecret, new IvParameterSpec(raw));
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        try {
            decrypted = cipher.doFinal(encrypted);
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }


        return decrypted;
    }

2 个答案:

答案 0 :(得分:5)

更好的方法是在您保存的每个加密消息的开头添加初始化向量。由于填充已经可以在消息中添加一些字节,因此对于用例而言这应该不重要。

不要忘记,对于特定的块密码,IV总是具有固定的大小:块大小,您可以使用Java中的cipher.getBlockSize()来检索。检索IV后,您只需使用cipher.doFinal(buf, offset, length)代替cipher.doFinal(buf)

如果你真的不想存储IV,你可以从完整路径名(绝对路径,或从某个根,如果需要)计算IV,并在其上执行SHA-256等散列。只要路径是唯一的,SHA-256应该相对接近已知但随机的IV,这是最安全的。当然,如果你重命名/移动文件......

请注意,您试图仅保护自己大约16KB的初始化向量(1000 x 16,即块大小)。那不是很多。

答案 1 :(得分:2)

为了安全起见,您必须为每条消息使用初始化向量(和唯一的向量)。没有办法解决它。