简体   繁体   English

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

[英]How to encrypt and decrypt file in Android?

I want to encrypt file and store it in SD card.我想加密文件并将其存储在 SD 卡中。 I want to decrypt that encrypted file and store it in SD card again.我想解密那个加密文件并再次将其存储在 SD 卡中。 I have tried to encrypt file by opening it as file stream and encrypt it but it is not working.我试图通过将文件作为文件流打开并加密来加密文件,但它不起作用。 I want some idea on how to do this.我想知道如何做到这一点。

Use a CipherOutputStream or CipherInputStream with a Cipher and your FileInputStream / FileOutputStream .使用CipherOutputStreamCipherInputStreamCipher和您的FileInputStream / FileOutputStream

I would suggest something like Cipher.getInstance("AES/CBC/PKCS5Padding") for creating the Cipher class.我会建议像Cipher.getInstance("AES/CBC/PKCS5Padding")来创建Cipher类。 CBC mode is secure and does not have the vulnerabilities of ECB mode for non-random plaintexts . CBC 模式是安全的,没有ECB 模式对非随机明文漏洞 It should be present in any generic cryptographic library, ensuring high compatibility.它应该存在于任何通用加密库中,以确保高兼容性。

Don't forget to use a Initialization Vector (IV) generated by a secure random generator if you want to encrypt multiple files with the same key.如果您想使用相同的密钥加密多个文件,请不要忘记使用由安全随机生成器生成的初始化向量(IV)。 You can prefix the plain IV at the start of the ciphertext.您可以在密文开头添加普通 IV 的前缀。 It is always exactly one block (16 bytes) in size.它的大小总是正好是一个块(16 字节)。

If you want to use a password, please make sure you do use a good key derivation mechanism (look up password based encryption or password based key derivation).如果您想使用密码,请确保您确实使用了良好的密钥派生机制(查找基于密码的加密或基于密码的密钥派生)。 PBKDF2 is the most commonly used Password Based Key Derivation scheme and it is present in most Java runtimes , including Android. PBKDF2 是最常用的基于密码的密钥派生方案,它存在于大多数 Java 运行时中,包括 Android。 Note that SHA-1 is a bit outdated hash function, but it should be fine in PBKDF2, and does currently present the most compatible option.请注意,SHA-1 是一个有点过时的哈希函数,但它在 PBKDF2 中应该没问题,并且目前确实提供了最兼容的选项。

Always specify the character encoding when encoding/decoding strings, or you'll be in trouble when the platform encoding differs from the previous one.在编码/解码字符串时总是指定字符编码,否则当平台编码与之前的编码不同时你会遇到麻烦。 In other words, don't use String.getBytes() but use String.getBytes(StandardCharsets.UTF_8) .换句话说,不要使用String.getBytes()而是使用String.getBytes(StandardCharsets.UTF_8)

To make it more secure, please add cryptographic integrity and authenticity by adding a secure checksum (MAC or HMAC) over the ciphertext and IV, preferably using a different key.为了使其更安全,请通过在密文和 IV 上添加安全校验和(MAC 或 HMAC)来添加加密完整性和真实性,最好使用不同的密钥。 Without an authentication tag the ciphertext may be changed in such a way that the change cannot be detected.如果没有身份验证标签,密文可能会以无法检测到的方式更改。

Be warned that CipherInputStream may not report BadPaddingException , this includes BadPaddingException generated for authenticated ciphers such as GCM.请注意, CipherInputStream可能不会报告BadPaddingException ,这包括为经过身份验证的密码(例如 GCM)生成的BadPaddingException This would make the streams incompatible and insecure for these kind of authenticated ciphers.这将使这些类型的经过身份验证的密码的流不兼容和不安全。

I had a similar problem and for encrypt/decrypt i came up with this solution:我有一个类似的问题,对于加密/解密,我想出了这个解决方案:

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;
}

To save a encrypted file to sd do:要将加密文件保存到 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();

To decode a file use:要解码文件,请使用:

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

For reading in a file to a byte Array there a different way out there.为了将文件读入字节数组,有一种不同的方式。 A Example: http://examples.javacodegeeks.com/core-java/io/fileinputstream/read-file-in-byte-array-with-fileinputstream/一个例子: http : //examples.javacodegeeks.com/core-java/io/fileinputstream/read-file-in-byte-array-with-fileinputstream/

You could use java-aes-crypto or Facebook's Conceal您可以使用java-aes-cryptoFacebook 的 Conceal

java-aes-crypto java-aes-crypto

Quoting from the repo从回购报价

A simple Android class for encrypting & decrypting strings, aiming to avoid the classic mistakes that most such classes suffer from.一个用于加密和解密字符串的简单 Android 类,旨在避免大多数此类类所遭受的经典错误。

Facebook's conceal脸书的隐藏

Quoting from the repo从回购报价

Conceal provides easy Android APIs for performing fast encryption and authentication of data Conceal 提供简单的 Android API 来执行数据的快速加密和身份验证

将CipherOutputStream或CipherInputStream与Cipher和FileOutputStream / FileInputStream一起使用。

We have a same problem, and its solved by someone in my question thread. 我们有一个相同的问题,它由我的问题线程中的某个人解决。 You should just take a look at: CipherInputStream and CipherOutputStream. 您应该看看:CipherInputStream和CipherOutputStream。 They are used to encrypt and decrypt byte streams. 它们用于加密和解密字节流。 for the detailed source code check out Kiril answer in this link : How to encrypt file from SD card using AES in Android? 有关详细的源代码,请查看此链接中的Kiril答案: 如何在Android中使用AES从SD卡加密文件?

I had the same problem, i got the solution from this code. 我有同样的问题,我从这段代码中得到了解决方案。

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM