You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编程加密解密设备内部存储Download目录下的docFolder文件夹

Hey there! Let's break down how to encrypt that docFolder in your Download directory programmatically, and then decrypt it when you need to use the files. I'll assume you're working on Android since you mentioned internal storage—this approach uses AES-GCM (a secure, authenticated encryption standard) which is perfect for this scenario.

Core Concept

We'll use symmetric encryption (same key for encrypting and decrypting) with AES-GCM, which adds a built-in integrity check to make sure files haven't been tampered with. We'll recursively traverse every file in the folder, encrypt each one individually, and store the necessary metadata (IV and authentication tag) alongside the encrypted content. For decryption, we'll reverse the process: read the metadata, decrypt the content, and restore the original files.

Prerequisites

  • Secure Key Storage: Don't hardcode keys! Use Android's Keystore system to generate and store your AES key—this keeps the key safe from being extracted from your app's memory or storage.
  • File Stream Handling: Process files in chunks to avoid loading large files entirely into memory (which can cause out-of-memory crashes).

Encryption Implementation

Step 1: Generate a Secure AES Key

First, create a function to generate or retrieve an AES key from Android Keystore. This key will be used for both encryption and decryption.

import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import java.security.KeyStore
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey

fun getOrGenerateAESKey(keyAlias: String): SecretKey {
    val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
    
    // Check if the key already exists in Keystore
    return if (keyStore.containsAlias(keyAlias)) {
        keyStore.getKey(keyAlias, null) as SecretKey
    } else {
        // Generate a new 256-bit AES key for GCM mode
        val keyGenerator = KeyGenerator.getInstance(
            KeyProperties.KEY_ALGORITHM_AES, 
            "AndroidKeyStore"
        )
        val keySpec = KeyGenParameterSpec.Builder(
            keyAlias,
            KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
        )
            .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
            .setKeySize(256)
            .build()
        
        keyGenerator.init(keySpec)
        keyGenerator.generateKey()
    }
}

Step 2: Encrypt a Single File

This function takes an input file, encrypts its content using the AES key, and writes the encrypted data (plus IV and authentication tag) to an output file. We'll add a .encrypted suffix to distinguish encrypted files.

import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.security.SecureRandom

private const val IV_SIZE = 12 // GCM recommends 12-byte IV for better security
private const val TAG_SIZE = 128 // 128-bit authentication tag

fun encryptSingleFile(inputFile: File, outputFile: File, secretKey: SecretKey) {
    // Generate a random IV (Initialization Vector) for each file
    val iv = ByteArray(IV_SIZE).apply { SecureRandom().nextBytes(this) }
    
    val cipher = Cipher.getInstance("AES/GCM/NoPadding").apply {
        init(Cipher.ENCRYPT_MODE, secretKey, GCMParameterSpec(TAG_SIZE, iv))
    }

    // Read the original file and write encrypted content
    FileInputStream(inputFile).use { inputStream ->
        FileOutputStream(outputFile).use { outputStream ->
            // Write IV first (we'll need this for decryption)
            outputStream.write(iv)
            
            // Process file in 8KB chunks to save memory
            val buffer = ByteArray(8192)
            var bytesRead: Int
            while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                val encryptedChunk = cipher.update(buffer, 0, bytesRead)
                encryptedChunk?.let { outputStream.write(it) }
            }
            
            // Write the final authentication tag
            val finalChunk = cipher.doFinal()
            finalChunk?.let { outputStream.write(it) }
        }
    }
}

Step 3: Recursively Encrypt the Entire Folder

This function traverses the folder (including subfolders) and encrypts every file it finds.

fun encryptFolder(targetFolder: File, secretKey: SecretKey) {
    if (!targetFolder.isDirectory) return
    
    targetFolder.listFiles()?.forEach { file ->
        if (file.isDirectory) {
            // Recursively encrypt subfolders
            encryptFolder(file, secretKey)
        } else {
            // Create encrypted file with .encrypted suffix
            val encryptedFile = File(file.parentFile, "${file.name}.encrypted")
            encryptSingleFile(file, encryptedFile, secretKey)
            
            // Optional: Delete the original file (only do this after verifying encryption works!)
            // file.delete()
        }
    }
}

Decryption Implementation

Step 1: Retrieve the AES Key

Use the same getOrGenerateAESKey function from the encryption section to get your key (make sure to use the same keyAlias!).

Step 2: Decrypt a Single File

This function reads the encrypted file, extracts the IV, decrypts the content, and writes the original file back (removing the .encrypted suffix).

fun decryptSingleFile(inputFile: File, outputFile: File, secretKey: SecretKey) {
    FileInputStream(inputFile).use { inputStream ->
        // Read the IV from the start of the file
        val iv = ByteArray(IV_SIZE)
        inputStream.read(iv)
        
        val cipher = Cipher.getInstance("AES/GCM/NoPadding").apply {
            init(Cipher.DECRYPT_MODE, secretKey, GCMParameterSpec(TAG_SIZE, iv))
        }

        // Write decrypted content to output file
        FileOutputStream(outputFile).use { outputStream ->
            val buffer = ByteArray(8192)
            var bytesRead: Int
            while (inputStream.read(buffer).also { bytesRead = it } != -1) {
                val decryptedChunk = cipher.update(buffer, 0, bytesRead)
                decryptedChunk?.let { outputStream.write(it) }
            }
            
            // Finalize decryption and verify authentication tag
            val finalChunk = cipher.doFinal()
            finalChunk?.let { outputStream.write(it) }
        }
    }
}

Step 3: Recursively Decrypt the Entire Folder

Traverse the encrypted folder and decrypt all .encrypted files back to their original form.

fun decryptFolder(targetFolder: File, secretKey: SecretKey) {
    if (!targetFolder.isDirectory) return
    
    targetFolder.listFiles()?.forEach { file ->
        if (file.isDirectory) {
            // Recursively decrypt subfolders
            decryptFolder(file, secretKey)
        } else if (file.name.endsWith(".encrypted")) {
            // Remove .encrypted suffix to get original filename
            val originalFileName = file.name.substringBeforeLast(".encrypted")
            val decryptedFile = File(file.parentFile, originalFileName)
            decryptSingleFile(file, decryptedFile, secretKey)
            
            // Optional: Delete the encrypted file after successful decryption
            // file.delete()
        }
    }
}

Key Things to Keep in Mind

  • Key Security: Never hardcode keys or store them in plaintext. Android Keystore is designed to keep keys secure—use it!
  • Error Handling: Add try-catch blocks around file operations and encryption/decryption to handle exceptions like missing files, invalid keys, or tampered encrypted data.
  • Backup: Always backup the original folder before encrypting—if something goes wrong during encryption, you don't want to lose your files.
  • Performance: Processing files in chunks (like 8KB) prevents memory issues with large files (e.g., high-res images or videos).
  • Tamper Protection: AES-GCM automatically checks if the encrypted file has been modified—if the authentication tag doesn't match, decryption will fail, alerting you to tampering.

内容的提问来源于stack exchange,提问作者Jean-Pascal MEWENEMESSE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:43:08