我想加密文件并将其存储在SD卡中。我想解密该加密文件并再次将其存储在SD卡中。我试图通过打开文件流加密文件并加密但是它不起作用。我想知道如何做到这一点。
答案 0 :(得分:61)
使用CipherOutputStream
或CipherInputStream
与Cipher
和FileInputStream
/ FileOutputStream
。
我建议使用Cipher.getInstance("AES/CBC/PKCS5Padding")
之类的内容来创建Cipher
类。 CBC模式是安全的,没有vulnerabilities of ECB mode for non-random plaintexts。它应该存在于任何通用加密库中,以确保高兼容性。
如果要使用相同的密钥加密多个文件,请不要忘记使用Initialization Vector生成的secure random generator(IV)。您可以在密文开头加上普通IV的前缀。它总是正好一个块(16字节)。
如果您想使用密码,请确保使用良好的密钥派生机制(查找基于密码的加密或基于密码的密钥派生)。 PBKDF2是最常用的基于密码的密钥派生方案,它是present in most Java runtimes,包括Android。请注意,SHA-1是一个有点过时的哈希函数,但它在PBKDF2中应该没问题,并且目前提供最兼容的选项。
在编码/解码字符串时始终指定字符编码,否则当平台编码与前一个编码不同时,您将遇到麻烦。换句话说,请勿使用String.getBytes()
,而是使用String.getBytes(StandardCharsets.UTF_8)
。
为了使其更安全,请通过在密文和IV上添加安全校验和(MAC或HMAC)来添加加密完整性和真实性,最好使用不同的密钥。如果没有身份验证标记,则可能会以无法检测到更改的方式更改密文。
警告CipherInputStream
可能 不报告BadPaddingException
,其中包括BadPaddingException
为经过身份验证的密码生成,例如GCM。这会使流与这些经过身份验证的密码不兼容且不安全。
答案 1 :(得分:48)
我有类似的问题,对于加密/解密,我提出了这个解决方案:
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/
答案 2 :(得分:0)
您可以使用java-aes-crypto或Facebook's Conceal
java-aes-crypto
从存储库中报价
一个用于加密和解密字符串的简单Android类,旨在 避免大多数此类课程遭受的经典错误。
Facebook隐藏的内容
从存储库中报价
Conceal提供了简单的Android API,用于执行快速加密和 数据认证
答案 3 :(得分:-5)
将CipherOutputStream或CipherInputStream与Cipher和FileOutputStream / FileInputStream一起使用。
答案 4 :(得分:-6)
我们遇到了同样的问题,并且我的问题线程中有人解决了这个问题。 您应该看看:CipherInputStream和CipherOutputStream。它们用于加密和解密字节流。 有关详细源代码,请查看此链接中的Kiril答案:How to encrypt file from SD card using AES in Android?
答案 5 :(得分:-7)
我遇到了同样的问题,我从这段代码中得到了解决方案。
private static final String ALGO = "AES";
private static final byte[] keyValue = new byte[] { 'o', 'n', 'e', 'n','e', 't', 'e','d', 'o', 'c', 'e', 'i', 'r', 's', 'r', 'p' };
public static String decrypt(String encryptedData){
String decryptedValue = null;
try{
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
byte[] decValue = c.doFinal(decordedValue);
decryptedValue = new String(decValue);
}catch(Exception e){
//LOGGER.error("In TD:" + e);
//Teneno_StartupService.loadForConnectionFailed();
}
return decryptedValue;
}
private static Key generateKey(){
Key key = new SecretKeySpec(keyValue, ALGO);
return key;
}