Reputation: 166
I want to create jar file that I can use to decrypt a file. The code as shown below:
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);
}
}
}
I will use the following command to run the decryption process:
java -jar decrypt.jar encrypted.jpg nonceHex keyHex additionalHex"
It appears that the decryption process works correctly when using the appropriate nonce, key, and additional values. However, when attempting to open the already decrypted file, I encountered difficulties and couldn't open it at all. The file seems to be corrupted, as indicated by the differing file sizes between the decrypted and original files.
Upon inspecting the byte text of both files using VS Code, I observed that they contain exactly the same content. This suggests that the decryption logic is functioning properly. The issue seems to be related to preserving metadata in the decrypted file.
It seems that my decrypted file lacks metadata. For instance, when decrypting an audio file, the resulting decrypted file does not include information such as duration or sample rate, which is present in the original file.
What am I doing wrong? How to properly decrypt a file using libsodium. Thank you.
Upvotes: 0
Views: 154
Reputation: 166
I finally solved my problem by understanding that read(byte[] b) does not guarantee that b.length bytes will be read. Thanks to @Topaco's comment, it now successfully decrypts the entire file.
Firstly, I also need to modify libsodium by myself since libsodium decrypt function does not support receiving []byte, therefore I forked the official libsodium and modify decrypt function by myself, so it will be able to receive []byte directly. I then compile to .jar file and put this into my application gradle. You can see my fork here.
here is my final code:
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);
}
}
}
Upvotes: 0