如何在Android中加密和解密文件?


74

我想加密文件并将其存储在SD卡中。我想解密该加密文件,然后再次将其存储在SD卡中。我试图通过将其作为文件流打开并对其进行加密来对其进行加密,但是它不起作用。我想知道如何执行此操作。

Answers:


68

使用一个CipherOutputStreamCipherInputStream一个Cipher和你FileInputStream/ FileOutputStream

我建议Cipher.getInstance("AES/CBC/PKCS5Padding")创建Cipher类的东西。对于非随机明文, CBC模式是安全的,并且没有ECB模式漏洞。它应该存在于任何通用密码库中,以确保高度兼容性。

如果要使用同一密钥加密多个文件,请不要忘记使用由安全随机生成器生成的初始化向量(IV)。您可以在密文的开头添加普通IV前缀。它的大小始终总是一个块(16个字节)。

如果要使用密码,请确保使用良好的密钥派生机制(查找基于密码的加密或基于密码的密钥派生)。PBKDF2是最常用的基于密码的密钥派生方案,并且在大多数Java运行时中存在包括在内的。请注意,SHA-1是有点过时的哈希函数,但在PBKDF2中应该没问题,并且当前提供了最兼容的选项。

在对字符串进行编码/解码时,请始终指定字符编码,否则平台编码与前一个编码不同时会遇到麻烦。换句话说,不要使用,String.getBytes()而是使用String.getBytes(StandardCharsets.UTF_8)

为了使其更加安全,请通过在密文和IV上添加安全的校验和(MAC或HMAC)来添加加密完整性和真实性,最好使用其他密钥。没有身份验证标签,密文可能会以无法检测到更改的方式更改。

警告CipherInputStream 可能 不会报告BadPaddingException,这包括BadPaddingException为诸如GCM之类的已认证密码生成的。对于这些经过身份验证的密码,这将使流不兼容且不安全。


6
为“总是在编码/解码字符串时指定字符编码” +1 :)
敬请原谅

1
@abhy从Java 7开始,您可以使用该StandardCharsets功能以方便使用。显然,static importofStandardCharsets也可能有用。
Maarten Bodewes

感谢您的更新。我真的很感激。
2012年

1
我假设“ IV”代表“初始化向量”,对于那些不认识的人,您应该至少说一次,也许是第一次提到它。同样,很高兴有链接解释为什么需要特定的Cipher配置。
哈米德

@Hamid OK,对文本进行了一些更改,我没想到这个相当普遍的建议会变得如此受欢迎:)
Maarten Bodewes

57

我有一个类似的问题,对于加密/解密,我想出了以下解决方案:

public static byte[] generateKey(String password) throws Exception
{
    byte[] keyStart = password.getBytes("UTF-8");

    KeyGenerator kgen = KeyGenerator.getInstance("AES");
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
    sr.setSeed(keyStart);
    kgen.init(128, sr);
    SecretKey skey = kgen.generateKey();
    return skey.getEncoded();
}

public static byte[] encodeFile(byte[] key, byte[] fileData) throws Exception
{

    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
    byte[] encrypted = cipher.doFinal(fileData);

    return encrypted;
}

public static byte[] decodeFile(byte[] key, byte[] fileData) throws Exception
{
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
    Cipher cipher = Cipher.getInstance("AES");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec);

    byte[] decrypted = cipher.doFinal(fileData);

    return decrypted;
}

要将加密文件保存到sd中,请执行以下操作:

File file = new File(Environment.getExternalStorageDirectory() + File.separator + "your_folder_on_sd", "file_name");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
byte[] yourKey = generateKey("password");
byte[] filesBytes = encodeFile(yourKey, yourByteArrayContainigDataToEncrypt);
bos.write(fileBytes);
bos.flush();
bos.close();

要解码文件,请使用:

byte[] yourKey = generateKey("password");
byte[] decodedData = decodeFile(yourKey, bytesOfYourFile);

为了将文件读入字节数组,有另外一种方法。范例:http : //examples.javacodegeeks.com/core-java/io/fileinputstream/read-file-in-byte-array-with-fileinputstream/


我尝试使用此解决方案,但是如果我从Android设备加密文件,则无法从计算机解密文件。似乎生成的密钥不一致。您知道解决方案吗?
minhaz1 2013年

4
这是Android代码段的副本,它使用相同的,不正确的密钥派生方法。使用它,您可能会丢失数据。
Maarten Bodewes 2014年

2
@MaartenBodewes,请论证您的陈述,为什么您认为导出密钥的方法不正确?如何改善?
Ayaz Alifov '16

4
这使用随机数生成器来导出密钥。该RNG不需要仅依赖种子,并且没有指定确切的算法。而是查找正确使用PBKDF2或类似的东西。
Maarten Bodewes,2016年

3
加密货币现已在android N中贬值-android-developers.googleblog.com/2016/06/…–
杰克

0

您可以使用java-aes-cryptoFacebook的Conceal

java-aes-crypto

从回购报价

一个用于加密和解密字符串的简单Android类,旨在避免大多数此类遭受的经典错误。

Facebook的隐瞒

从回购报价

Conceal提供了简单的Android API,用于执行数据的快速加密和身份验证

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.