我正在编写一个应用程序,让您通过 ssh 连接到远程计算机。 我想保护 ssh 密钥,所以我的想法是对其进行加密,然后在应用程序内部对其进行解密。
这是我正在使用的功能:
fun decryptFileWithPBKDF2(
encryptedFile: File,
decryptedFile: File,
password: String,
iterations: Int = 10000,
keyLength: Int = 256
) {
val saltSize = 8 // OpenSSL salt is 8 bytes
val ivSize = 16 // AES block size is 16 bytes for CBC mode
val headerSize = 8 // Salted__ is the first 8 bytes
FileInputStream(encryptedFile).use { fis ->
val fileBytes = fis.readBytes()
// Check if the file is at least large enough to contain the header, salt, and IV
if (fileBytes.size < headerSize + saltSize + ivSize) {
throw IllegalArgumentException("Invalid encrypted file format.")
}
// Extract the salt (bytes 8 to 15) and IV (bytes 16 to 31)
val salt = fileBytes.sliceArray(headerSize until headerSize + saltSize)
val iv = fileBytes.sliceArray(headerSize + saltSize until headerSize + saltSize + ivSize)
// Ciphertext starts after "Salted__", salt, and IV (total 32 bytes)
val cipherText = fileBytes.sliceArray(headerSize + saltSize + ivSize until fileBytes.size)
// Derive the key using PBKDF2 with the same parameters as OpenSSL
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
val spec: KeySpec = PBEKeySpec(password.toCharArray(), salt, iterations, keyLength)
val tmp = factory.generateSecret(spec)
val secretKey = SecretKeySpec(tmp.encoded, "AES")
// Initialize AES cipher for decryption (AES/CBC/PKCS5Padding)
val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
cipher.init(Cipher.DECRYPT_MODE, secretKey, IvParameterSpec(iv))
// Decrypt the file
val decryptedBytes = cipher.doFinal(cipherText)
// Write the decrypted content to the output file
FileOutputStream(decryptedFile).use { fos ->
fos.write(decryptedBytes)
}
}
}
这是我的 test.txt 中的全文: “这是一条严肃的信息!我不知道为什么解密会毁掉这段精彩的文字:(” 由于某种原因,解密后看起来像这样: “这是一条严肃的信息!我不知道为什么解密会毁掉这个精彩的文本:(”
我加密了这样的文件:
openssl enc -aes-256-cbc -pbkdf2 -salt -in test.txt -out test.enc -k "password" -p
你能帮我解决这个问题吗?
我尝试使用所有三大主要人工智能助手,但没有成功。
OpenSSL 语句生成的数据结构如下(
|
表示串联):
<ASCII encoding of Salted__>|<8 bytes salt>|<ciphertext>
因此,使用 PBKDF2 从密码和盐中派生出密钥和 IV。
然而,您在 Kotlin 代码中错误地假设 IV 也包含在数据中,但事实并非如此。相反,IV 必须与密钥一起导出,例如如下:
...
// Extract the salt (bytes 8 to 15)
val salt = fileBytes.sliceArray(headerSize until headerSize + saltSize)
// Ciphertext starts after "Salted__", salt (total 16 bytes)
val cipherText = fileBytes.sliceArray(headerSize + saltSize until fileBytes.size)
// Derive the key and IV using PBKDF2 with the same parameters as OpenSSL
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
val spec: KeySpec = PBEKeySpec(password.toCharArray(), salt, iterations, keyLength + ivSize * 8)
val tmp = factory.generateSecret(spec)
val key = tmp.encoded.sliceArray(0 until keyLength/8)
val iv = tmp.encoded.sliceArray(keyLength/8 until keyLength/8 + ivSize)
val secretKey = SecretKeySpec(key, "AES")
...
通过此更改,解密有效。