英文:
Swift AES GCM encryptor and Java decryption - File issues
问题
Here are the translated code sections:
public class FileDecryptor {
static String secret = "my-xxx-bit-secret-my-secret-my-s";
static String nonce = "fv1nixTVoYpSvpdA";
// The following values are obtained from the Swift encryptor class print statements
static String tag = "KaryGdpX0t1KwXaDFXEnkw==";
static String cipherText = "UoRsEQ==";
public static void main(String args[]) throws Exception {
// Decrypt with cipher and tag - WORKS
String decryptedValue = decrypt(cipherText, tag);
System.out.println("output from cipher and tag: " + decryptedValue);
// Decrypt from file content which has nonce, tag, ciphertext combined - DOES NOT WORK
System.out.println("going to decrypt from file which has nonce, tag, ciphertext combined");
String inputFileName = "a_e.txt";
String inputFileContent = FileUtils.readFileToString(new File(inputFileName)); // ciphertext and tag are included
System.println("inputFileContent:" + inputFileContent);
String decryptedValue2 = decrypt(inputFileContent.getBytes());
System.out.println("output: " + decryptedValue2);
}
// The rest of the code remains the same.
}
I hope this helps with your code translation. If you have any more questions or need further assistance, please let me know.
英文:
I need to encrypt with swift and decrypt with java around 1000 files in a directory.
I tested a prototype with a string and it works thanks to answer from https://stackoverflow.com/users/1831987/vgr at
https://stackoverflow.com/questions/75918859/swift-aes-gcm-encryptor-and-java-decryption-padding-issues
But when I place that string in a file, it does not work. It works if I print cipher text and tag during encryption and use them separately to decrypt in java, but that's not how it can be done in real world. The file content which is cipher text+nonce+tag, must be decrypted as a whole.
What am I doing wrong here please?
SWIFT ENCRYPTOR
static func encryptDecryptSingleTestFile() {
do {
//encrypt
let data = try Data(contentsOf: URL(fileURLWithPath: filePath1))
print("data in original file \(String(decoding: data, as: UTF8.self))")
let sealedBox = try! AES.GCM.seal(data, using: symKey, nonce: nonce)
let ciphertext = sealedBox.ciphertext.base64EncodedString()
print("ciphertext of sealedbox in file: \(ciphertext)")
let tag = sealedBox.tag
print("tag of sealedbox in file: \(tag.base64EncodedString())")
try sealedBox.combined!.write(to: URL(fileURLWithPath: filePath2))
//DECRYPT - just for testing, actual decrypting will happen in java code
let data2 = try Data(contentsOf: URL(fileURLWithPath: filePath2))
print("data in encrypted file \(String(decoding: data2, as: UTF8.self))")
let sealedBox2 = try AES.GCM.SealedBox(combined: data2)
let decryptedData = try AES.GCM.open(sealedBox2, using: symKey)
try decryptedData.write(to: URL(fileURLWithPath: filePath3))
let ciphertext2 = sealedBox2.ciphertext.base64EncodedString()
let dataInDecryptedFile = try Data(contentsOf: URL(fileURLWithPath: filePath3))
print("data in decrypted file \(String(decoding: dataInDecryptedFile, as: UTF8.self))")
} catch {
print(error)
}
}
OUTPUT
data in original file: abc
ciphertext of sealedbox in file: UoRsEQ==
tag of sealedbox in file: KaryGdpX0t1KwXaDFXEnkw==
data in encrypted file: ~�g�ա�R��@R�l)���W��J�v�q'�
data in decrypted file: abc
JAVA DECRYPTOR
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.io.FileUtils;
public class FileDecryptro {
static String secret = "my-xxx-bit-secret-my-secret-my-s";
static String nonce = "fv1nixTVoYpSvpdA";
//below values are obtained from the swift encryptor class print statements
static String tag = "KaryGdpX0t1KwXaDFXEnkw==";
static String cipherText = "UoRsEQ==";
public static void main(String args[]) throws Exception {
//decrypt with cipher and tag - WORKS
String decriptedValue = decrypt(cipherText,tag);
System.out.println("output from cipher and tag:" + decriptedValue);
//decrypt from file content which has nonce,tag,ciphertext combined. - DOES NOT WORK
System.out.println("going to decrypt from file which has nonce, tag, ciphertext combined");
String inputFileName = "a_e.txt";
String inputFileContent = FileUtils.readFileToString(new File(inputFileName));///ciphertext and tag is included
System.out.println("inputFileContent:"+inputFileContent);
String decriptedValue2 = decrypt(inputFileContent.getBytes());
System.out.println("output:" + decriptedValue2);
}
static String decrypt(byte[] ciphertextWithTagBytes) throws Exception {
byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
byte[] nonceBytes = Base64.getDecoder().decode(nonce);
//decrypt
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, nonceBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec);
byte[] plaintextBytes = cipher.doFinal(ciphertextWithTagBytes);
String plaintext = new String(plaintextBytes, StandardCharsets.UTF_8);
return plaintext;
}
static String decrypt(String cipherText, String tag) throws Exception {
byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
byte[] nonceBytes = Base64.getDecoder().decode(nonce);
//append tagBytes to cipherText
byte[] tagBytes = Base64.getDecoder().decode(tag);
Base64.Decoder decoder = Base64.getDecoder();
byte[] decodedCipherText = decoder.decode(cipherText);
byte[] decodedTag = decoder.decode(tag);
byte[] ciphertextBytes = new byte[decodedCipherText.length + decodedTag.length];
ByteBuffer.wrap(ciphertextBytes).put(decodedCipherText).put(decodedTag);
//decrypt
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, nonceBytes);
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmSpec);
byte[] plaintextBytes = cipher.doFinal(ciphertextBytes);
String plaintext = new String(plaintextBytes, StandardCharsets.UTF_8);
return plaintext;
}
}
OUTPUT
output from cipher and tag:abc
going to decrypt from file which has nonce, tag, ciphertext combined
inputFileContent:~�g�ա�R��@R�l)���W��J�v�q'�
Exception in thread "main" javax.crypto.AEADBadTagException: Tag mismatch!
答案1
得分: 2
以下是翻译好的部分:
它是二进制(也称为比特)。 密文以及其他与加密相关的数据,如签名、标记、随机数或盐,都是由比特组成的二进制数据,而不是字符。Java的String
只能处理字符,因此将二进制文件读入String
然后尝试对其进行getBytes
会导致部分错误数据,而现代密码学只能使用完全正确的数据。
你需要将文件以字节形式读取,并且需要从文件中读取随机数和密文+标记(Java密码处理为单个单元)。有至少几种方法可以做到这一点:
-
可能最直接的方法是以流的方式打开文件(旧的I/O类型,而不是Java 8类型)并
read
每个部分。你需要分配具有正确大小的缓冲区,这不难。 -
以字节形式读取整个文件,然后从字节数组中复制各个部分。
-
以字节形式读取整个文件,将内容放入
ByteBuffer
中,并get
每个部分;同样,你需要分配正确的大小。 -
以字节形式读取整个文件,然后将该数组的部分传递给加密例程。
以下代码展示了这四种可能性,只是我把#4放在前面,因为它使代码结构略微简化:
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
byte[] key = "my-xxx-bit-secret-my-secret-my-s".getBytes(), nonce, ct_tag;
File f = new File(args[0]);
if (args.length == 1) { // 省略以表示#4
byte[] all = Files.readAllBytes(f.toPath());
c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, all, 0, 12));
byte[] dec = c.doFinal(all, 12, all.length - 12);
System.out.write(dec);
System.exit(0);
}
if (args[1].equals("1")) {
nonce = new byte[12];
ct_tag = new byte[(int) f.length() - 12];
try (InputStream is = new FileInputStream(f)) {
is.read(nonce);
is.read(ct_tag);
}
} else if (args[1].equals("2")) {
byte[] all = Files.readAllBytes(f.toPath());
nonce = Arrays.copyOf(all, 12);
ct_tag = Arrays.copyOfRange(all, 12, all.length);
} else if (args[1].equals("3")) {
byte[] all = Files.readAllBytes(f.toPath());
nonce = new byte[12];
ct_tag = new byte[all.length - 12];
ByteBuffer.wrap(all).get(nonce).get(ct_tag);
} else {
throw new Exception("bad second arg");
}
c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, nonce));
byte[] dec = c.doFinal(ct_tag);
System.out.write(dec);
希望这能帮助你!
英文:
It's binary (aka bits). Ciphertext, and other crypto-related data like signature, tag, nonce, or salt, is binary data made up only of bits, not characters. Java's String
only works on characters, so reading your binary file into a String
and then trying to getBytes
on it gives partly wrong data, and modern cryptography only works with completely right data.
You need to read the file as bytes, AND you need to read both the nonce and the ciphertext+tag (which Java crypto treats as a single unit) from the file. There are at least several ways to do this:
-
probably most straightforward, open the file as a stream (the older I/O type not the java8 type) and
read
each piece. You need to allocate buffers with the correct size, which isn't hard. -
read the whole file as bytes then copy the pieces from the byte array.
-
read the whole file as bytes, put the contents in a
ByteBuffer
andget
each piece; again you need to allocate the correct size. -
read the whole file as bytes, then pass parts of that array to the crypto routines
The following code shows the four possibilities, except I put #4 first because it makes the code structure a bit simpler:
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
byte[] key = "my-xxx-bit-secret-my-secret-my-s".getBytes(), nonce, ct_tag;
File f = new File (args[0]);
if( args.length == 1 ){ // omit entirely to indicate #4
byte[] all = Files.readAllBytes(f.toPath());
c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key,"AES"), new GCMParameterSpec(128,all,0,12));
byte[] dec = c.doFinal(all,12,all.length-12);
System.out.write(dec); System.exit(0);
}
if( args[1].equals("1") ){
nonce = new byte[12]; ct_tag = new byte[(int)f.length()-12];
try(InputStream is = new FileInputStream (f) ){ is.read(nonce); is.read(ct_tag); }
}else if( args[1].equals("2") ){
byte[] all = Files.readAllBytes(f.toPath());
nonce = Arrays.copyOf(all, 12); ct_tag = Arrays.copyOfRange(all, 12, all.length);
}else if( args[1].equals("3") ){
byte[] all = Files.readAllBytes(f.toPath());
nonce = new byte[12]; ct_tag = new byte[all.length-12];
ByteBuffer.wrap(all).get(nonce).get(ct_tag);
}else throw new Exception ("bad second arg");
c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key,"AES"), new GCMParameterSpec(128, nonce));
byte[] dec = c.doFinal(ct_tag);
System.out.write(dec);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论