android - CipherOutputStream 损坏 Android 中的 header

标签 android encryption aes encryption-symmetric pbkdf2

我正在使用一个简单的 CipherInput/OutputStream 来尝试在 android 中加密/解密文件。

我遇到的问题是它似乎损坏了文件的前几个字节,但没有损坏其余部分。下面是一个简单文本文件的输出示例:

原文:

"Test for Android cipher. The quick brown fox jumps over the lazy dog."

通过加密和解密循环:

@ÍØJ­b¢çc°ÌHOšpher. The quick brown fox jumps over the the lazy dog. 

这是我的代码:

public static SecretKey generateKey(Context c, char[] passphraseOrPin) throws NoSuchAlgorithmException, InvalidKeySpecException {
    // Number of PBKDF2 hardening rounds to use. Larger values increase
    // computation time. You should select a value that causes computation
    // to take >100ms.
    byte[] salt = Settings.Secure.getString(c.getContentResolver(),
            Settings.Secure.ANDROID_ID).getBytes();

    final int iterations = 1000;

    final int outputKeyLength = 128;

    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
    SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
    Log.d("HIDEMYPICS","Secret Key: " + toHex(secretKey.getEncoded()) );
    return secretKey;
}

public static boolean decryptFileFromUri(Context context, Uri file, String keyphrase) {
    try {
        File f = new File(getRealPathFromURI(context, file));
        FileInputStream fis = new FileInputStream(f);

        File ef = new File(f.toString().replace(".epf", ""));
        FileOutputStream fos = new FileOutputStream(ef);

        Log.d("HIDEMYPICS","Decrypting: " + f.toString());

        SecretKey key = generateKey(context, keyphrase.toCharArray());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, key);
        // Wrap the output stream
        CipherOutputStream cos = new CipherOutputStream(fos, cipher);
        // Write bytes
        int b;
        byte[] d = new byte[8];
        while ((b = fis.read(d)) != -1) {
            cos.write(d, 0, b);
        }
        // Flush and close streams.
        cos.flush();
        cos.close();
        fis.close();

        Log.d("HIDEMYPICS","Decrypted to: " + ef.toString());
        return true;
    } catch (IOException e){
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    }
    return false;
}

public static boolean encryptFileFromUri(Context context, Uri file, String keyphrase) {
    try {
        File f = new File(getRealPathFromURI(context, file));
        FileInputStream fis = new FileInputStream(f);

        File ef = new File(f.toString() + ".epf");
        FileOutputStream fos = new FileOutputStream(ef);

        Log.d("HIDEMYPICS","Encrypting: " + f.toString());

        SecretKey key = generateKey(context, keyphrase.toCharArray());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        // Wrap the output stream
        CipherOutputStream cos = new CipherOutputStream(fos, cipher);
        // Write bytes
        int b;
        byte[] d = new byte[8];
        while ((b = fis.read(d)) != -1) {
            cos.write(d, 0, b);
        }
        // Flush and close streams.
        cos.flush();
        cos.close();
        fis.close();
        Log.d("HIDEMYPICS","Encrypted to: " + ef.toString());
        return true;
    } catch (IOException e){
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    }
    return false;
}

更新:

建议在密码设置中显式添加一个随机 IV,并添加/修改以下代码行以促进它:

SecureRandom r = new SecureRandom();
        byte[] ivBytes = new byte[16];
        r.nextBytes(ivBytes);

        SecretKey key = generateKey(context, keyphrase.toCharArray());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivBytes));

结果是一样的。文本文件的前几个字节仍然损坏。

最终答案:

不确定我做了什么,但根据下面的建议,我尝试了一个静态 IV,它仍然表现出相同的行为,但我移动了声明并且发生了一些事情;可能某处有错字。这个问题现在已经解决了,这是最终的工作代码。感谢所有提供帮助的人!

private static final byte[] ivBytes = {109,15,57,79,75,112,50,91,18,18,107,127,65,68,12,69};

public static SecretKey generateKey(Context c, char[] passphraseOrPin) throws NoSuchAlgorithmException, InvalidKeySpecException {
    // Number of PBKDF2 hardening rounds to use. Larger values increase
    // computation time. You should select a value that causes computation
    // to take >100ms.
    byte[] salt = Settings.Secure.getString(c.getContentResolver(),
            Settings.Secure.ANDROID_ID).getBytes();

    final int iterations = 1000;

    final int outputKeyLength = 128;

    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
    SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
    return secretKey;
}

public static boolean decryptFileFromUri(Context context, Uri file, String keyphrase) {
    try {
        File f = new File(getRealPathFromURI(context, file));
        FileInputStream fis = new FileInputStream(f);

        File ef = new File(f.toString().replace(".epf", ""));
        FileOutputStream fos = new FileOutputStream(ef);

        SecretKey key = generateKey(context, keyphrase.toCharArray());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivBytes));
        // Wrap the output stream
        CipherInputStream cis = new CipherInputStream(fis, cipher);
        // Write bytes
        int b;
        byte[] d = new byte[8];
        while ((b = cis.read(d)) != -1) {
            fos.write(d, 0, b);
            fos.flush();
        }
        // Flush and close streams.
        fos.close();
        cis.close();

        f.delete();
        return true;
    } catch (IOException e){
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
    return false;
}

public static boolean encryptFileFromUri(Context context, Uri file, String keyphrase) {
    try {
        File f = new File(getRealPathFromURI(context, file));
        FileInputStream fis = new FileInputStream(f);

        File ef = new File(f.toString() + ".epf");
        FileOutputStream fos = new FileOutputStream(ef);

        SecretKey key = generateKey(context, keyphrase.toCharArray());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivBytes));
        // Wrap the output stream
        CipherOutputStream cos = new CipherOutputStream(fos, cipher);
        // Write bytes
        int b;
        byte[] d = new byte[8];
        while ((b = fis.read(d)) != -1) {
            cos.write(d, 0, b);
            cos.flush();
        }
        // Flush and close streams.
        cos.close();
        fis.close();
        f.delete();
        return true;
    } catch (IOException e){
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        e.printStackTrace();
    } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }
    return false;
}

最佳答案

明确设置一个随机 IV 并将其包含在您的密文中。

关于android - CipherOutputStream 损坏 Android 中的 header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36680037/

相关文章:

android - sleep 期间未收到警报

php - 为什么我的 mysql 表的后续结果没有在 ListView 中创建新对象?

c# - CryptDeriveKey 算法名称

encryption - 是否可以对 AES256 进行逆向工程?

javascript - JS/Ruby AES 256 对称性

java - 检索 Firebase 对象空指针异常

android - 在 webview 和 chrome 之间共享 cookie

mysql - 加密 mysql 数据库,因此系统管理员也无法访问数据

java - 如何使用另一个 RSAKey 加密一个 RSAKey?

java - 安卓解密: Last block (16 bytes) is missing in result file