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

Pra*_*tik 65 security encryption android

我想加密文件并将其存储在SD卡中.我想解密该加密文件并再次将其存储在SD卡中.我试图通过打开文件流加密文件并加密但是它不起作用.我想知道如何做到这一点.

Maa*_*wes 65

使用a CipherOutputStreamCipherInputStreama Cipher和你的FileInputStream/ FileOutputStream.

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

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

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

在编码/解码字符串时始终指定字符编码,否则当平台编码与前一个编码不同时,您将遇到麻烦.换句话说,不要使用String.getBytes()但使用String.getBytes(StandardCharsets.UTF_8).

为了使其更安全,请通过在密文和IV上添加安全校验和(MAC或HMAC)来添加加密完整性和真实性,最好使用不同的密钥.如果没有认证标签,则可以以不能检测到改变的方式改变密文.

请注意,CipherInputStream 可能 不会报告BadPaddingException,这包括BadPaddingException为经过身份验证的密码生成,例如GCM.这将使流不兼容并且对于这种经过验证的密码不安全.

  • +"始终在编码/解码字符串时指定字符编码":) (5认同)

Zer*_*Tek 50

我有类似的问题,加密/解密我提出了这个解决方案:

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;
}
Run Code Online (Sandbox Code Playgroud)

要将加密文件保存到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();
Run Code Online (Sandbox Code Playgroud)

解码文件使用:

byte[] yourKey = generateKey("password");
byte[] decodedData = decodeFile(yourKey, bytesOfYourFile);
Run Code Online (Sandbox Code Playgroud)

对于将文件读入字节数组,有不同的方法.例如:http://examples.javacodegeeks.com/core-java/io/fileinputstream/read-file-in-byte-array-with-fileinputstream/

  • 这是Android代码段的副本,它使用相同的,**错误的**方法来获取密钥.使用此选项可能会丢失数据. (4认同)
  • 这使用随机数生成器来导出密钥.该RNG不需要仅依赖于种子,并且未指定精确算法.而是查找正确使用PBKDF2或类似的. (3认同)
  • Crypto现已在Android N中折旧 - https://android-developers.googleblog.com/2016/06/security-crypto-provider-deprecated-in.html (3认同)
  • @MaartenBodewes,请论证你的陈述,为什么你认为导出密钥的方法不正确?怎么改进? (2认同)
  • 这个答案现在已经4岁了,那时甚至还不够好。 (2认同)