我想创建可用于解密文件的 jar 文件。代码如下所示:
package org.example;
import com.goterl.lazysodium.LazySodium;
import com.goterl.lazysodium.LazySodiumJava;
import com.goterl.lazysodium.SodiumJava;
import com.goterl.lazysodium.interfaces.AEAD;
import com.goterl.lazysodium.utils.Key;
import javax.crypto.AEADBadTagException;
import javax.xml.bind.DatatypeConverter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) {
if (args.length != 4) {
System.out.println("Usage: java -jar YourJarFileName.jar cryptoContentFilePath nonceHex keyHex additionalHex");
System.exit(1);
}
String cryptoContentFilePath = args[0];
String nonceHex = args[1];
String keyHex = args[2];
String additionalHex = args[3];
byte[] nonceBytes = DatatypeConverter.parseHexBinary(nonceHex);
byte[] keyBytes = DatatypeConverter.parseHexBinary(keyHex);
Key key = Key.fromBytes(keyBytes);
LazySodium sodium = new LazySodiumJava(new SodiumJava());
try (FileInputStream fis = new FileInputStream(cryptoContentFilePath)) {
byte[] cryptoContentBytes = new byte[fis.available()];
fis.read(cryptoContentBytes);
String rawData = sodium.decrypt(new String(cryptoContentBytes), additionalHex, nonceBytes, key, AEAD.Method.CHACHA20_POLY1305);
System.out.println(rawData);
// Write decrypted content to a text file
writeToFile("decrypted_output.jpg", rawData);
} catch (IOException | AEADBadTagException e) {
throw new RuntimeException(e);
}
}
private static void writeToFile(String filePath, String content) {
try (FileOutputStream fos = new FileOutputStream(filePath)) {
fos.write(content.getBytes());
} catch (IOException e) {
throw new RuntimeException("Error writing to file", e);
}
}
}
我将使用以下命令来运行解密过程:
java -jar decrypt.jar encrypted.jpg nonceHex keyHex additionalHex"
使用适当的随机数、密钥和附加值时,解密过程似乎可以正常工作。然而,当我尝试打开已经解密的文件时,我遇到了困难,根本无法打开它。该文件似乎已损坏,解密文件和原始文件之间的文件大小不同表明了这一点。
使用 VS Code 检查两个文件的字节文本后,我发现它们包含完全相同的内容。这表明解密逻辑运行正常。该问题似乎与在解密文件中保留元数据有关。
我的解密文件似乎缺少元数据。例如,在解密音频文件时,生成的解密文件不包含原始文件中存在的持续时间或采样率等信息。
我做错了什么?如何使用 libsodium 正确解密文件。谢谢你。
我终于通过理解 read(byte[] b) 不能保证读取 b.length 字节来解决了我的问题。感谢@Topaco 的评论,现在它成功解密了整个文件。
首先,我还需要自己修改libsodium,因为libsodium的解密函数不支持接收[]byte,所以我fork了官方的libsodium并自己修改了解密函数,这样就可以直接接收[]byte。然后我编译为 .jar 文件并将其放入我的应用程序 gradle 中。你可以在这里看到我的叉子。
这是我的最终代码:
package org.example;
import com.goterl.lazysodium.LazySodium;
import com.goterl.lazysodium.LazySodiumJava;
import com.goterl.lazysodium.SodiumJava;
import com.goterl.lazysodium.interfaces.AEAD;
import com.goterl.lazysodium.utils.Key;
import javax.crypto.AEADBadTagException;
import javax.xml.bind.DatatypeConverter;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
if (args.length != 5) {
System.out.println("Usage: java -jar YourJarFileName.jar cryptoContentFilePath decryptedOutputPath nonceHex keyHex additionalHex");
System.exit(1);
}
String cryptoContentFilePath = args[0];
String decryptedOutputPath = args[1];
String nonceHex = args[2];
String keyHex = args[3];
String additionalHex = args[4];
byte[] nonceBytes = DatatypeConverter.parseHexBinary(nonceHex);
byte[] keyBytes = DatatypeConverter.parseHexBinary(keyHex);
Key key = Key.fromBytes(keyBytes);
LazySodium sodium = new LazySodiumJava(new SodiumJava());
try (FileInputStream fis = new FileInputStream(cryptoContentFilePath)) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096]; // You can adjust the buffer size as needed
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
baos.write(buffer, 0, bytesRead);
}
byte[] rawData = baos.toByteArray();
int divideSize = 1024*1024; // You can adjust the divideSize as needed
int appendSize = divideSize + AEAD.CHACHA20POLY1305_ABYTES;
int totalCount = (rawData.length / appendSize) + ((rawData.length % appendSize) > 0 ? 1 : 0);
byte[] finalData = new byte[rawData.length - (totalCount * AEAD.CHACHA20POLY1305_ABYTES)];
for (int i = 0; i < totalCount; i++) {
int tempSize = (i == totalCount - 1) ? rawData.length - (i * appendSize) : appendSize;
byte[] tempData = new byte[tempSize];
System.arraycopy(rawData, i * appendSize, tempData, 0, tempSize);
byte[] endData = sodium.decrypt(tempData, additionalHex, nonceBytes, key, AEAD.Method.CHACHA20_POLY1305);
System.arraycopy(endData, 0, finalData, i * divideSize, endData.length);
}
// Write decrypted content to a text file
writeToFile(decryptedOutputPath, finalData);
System.out.println("File successfully decrypted: " + decryptedOutputPath);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static void writeToFile(String filePath, byte[] content) {
try (FileOutputStream fos = new FileOutputStream(filePath)) {
fos.write(content);
} catch (IOException e) {
throw new RuntimeException("Error writing to file", e);
}
}
}