[英]How to decrypt file in Java encrypted with openssl command using AES?
[英]Decrypt aes encrypted file in java sha1 openssl
我試圖通過引用此代碼來實現文件解密:
加密部分我已經做了這樣的方式:HTTPS // stackoverflow.com /問題/ 64423926 /加密文件功能於Java的和解密功能於的OpenSSL與鍵-AES
而且加密文件我可以用openssl解密。
但是在java中解密到文件導致錯誤:
java.lang.IllegalArgumentException: Illegal base64 character 5f
at java.util.Base64$Decoder.decode0(Unknown Source)
at java.util.Base64$Decoder.decode(Unknown Source)
at java.util.Base64$Decoder.decode(Unknown Source)
at aes.AesEncryptTask.decryptNew(AesEncryptTask.java:107)
at aes.AesEncryptTask.main(AesEncryptTask.java:58)
我的加密文件中的內容是:
Salted__¨‹–1ž#¡ð=—ÖÏùá•NEÄ
注意:開始加鹽的部分不是 base64 編碼的。 以下數據被編碼。
請建議正確實現文件解密。
static void decryptNew(String path,String password, String outPath) {
try{
FileInputStream fis = new FileInputStream(path);
FileOutputStream fos = new FileOutputStream(outPath);
final byte[] pass = password.getBytes(StandardCharsets.US_ASCII);
//final byte[] inBytes = Base64.getDecoder().decode(source);
String source = getFileContent(fis);
final Decoder decoder = Base64.getDecoder();
final byte[] inBytes = decoder.decode(source);
//final byte[] inBytes =source.getBytes();//DatatypeConverter.parseBase64Binary(source);
final byte[] shouldBeMagic = Arrays.copyOfRange(inBytes, 0, SALTED_MAGIC.length);
if (!Arrays.equals(shouldBeMagic, SALTED_MAGIC)) {
throw new IllegalArgumentException("Initial bytes from input do not match OpenSSL SALTED_MAGIC salt value.");
}
final byte[] salt = Arrays.copyOfRange(inBytes, SALTED_MAGIC.length, SALTED_MAGIC.length + 8);
final byte[] passAndSalt = array_concat(pass, salt);
byte[] hash = new byte[0];
byte[] keyAndIv = new byte[0];
for (int i = 0; i < 3 && keyAndIv.length < 48; i++) {
final byte[] hashData = array_concat(hash, passAndSalt);
MessageDigest md = null;
md = MessageDigest.getInstance("SHA-1");
hash = md.digest(hashData);
keyAndIv = array_concat(keyAndIv, hash);
}
final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
final byte[] clear = cipher.doFinal(inBytes, 16, inBytes.length - 16);
String contentDecoded = new String(clear, StandardCharsets.UTF_8);
fos.write(contentDecoded.getBytes());
fos.close();
//cipher.init(Cipher.DECRYPT_MODE, sks);
/*CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[8];
while((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();*/
System.out.println("Decrypt is completed");
}catch(Exception e){
e.printStackTrace();
}
}
下面的代碼正在做一個完整的文件加密和解密,並且兼容 OpenSSL 命令
encrypt: openssl enc -aes-256-cbc -pass pass:testpass -d -p -in plaintext.txt -out plaintext.txt.crypt -md md5
decrypt: openssl aes-256-cbc -d -in plaintext.txt.crypt -out plaintext1.txt -k testpass -md md5
我遺漏了一些變量,因為它們沒有在解密方法中使用,另一方面用純 Java 版本替換了 byte[] 連接。
簡單的輸出是:
encrypt done plaintext.txt
ciphertext: plaintext.txt
Decrypt is completed
安全警告:密鑰派生已棄用,不應再使用。 該代碼沒有任何異常處理,僅用於教育目的。
代碼:
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.Arrays;
public class MainSo {
public static void main(String[] args) {
System.out.println("https://stackoverflow.com/questions/64443373/decrypt-aes-encrypted-file-in-java-sha1-openssl?noredirect=1#comment113960588_64443373");
String plaintextFilename = "plaintext.txt";
String ciphertextFilename = "plaintext.txt.crypt";
String decryptedtextFilename = "plaintextDecrypted.txt";
String password = "testpass";
// openssl equivalent:
// decrypt: openssl aes-256-cbc -d -in plaintext.txt.crypt -out plaintext1.txt -k testpass -md md5
// encrypt: openssl enc -aes-256-cbc -pass pass:testpass -d -p -in sample.crypt -out sample.txt -md md5
String ciphertext = encryptfile(plaintextFilename, password);
System.out.println("ciphertext: " + ciphertext);
decryptNew(ciphertextFilename, password, decryptedtextFilename);
}
public static String encryptfile(String path, String password) {
try {
FileInputStream fis = new FileInputStream(path);
FileOutputStream fos = new FileOutputStream(path.concat(".crypt"));
final byte[] pass = password.getBytes(StandardCharsets.UTF_8);
final byte[] salt = (new SecureRandom()).generateSeed(8);
fos.write("Salted__".getBytes(StandardCharsets.UTF_8));
fos.write(salt);
final byte[] passAndSalt = concatenateByteArrays(pass, salt);
byte[] hash = new byte[0];
byte[] keyAndIv = new byte[0];
for (int i = 0; i < 3 && keyAndIv.length < 48; i++) {
final byte[] hashData = concatenateByteArrays(hash, passAndSalt);
final MessageDigest md = MessageDigest.getInstance("MD5");
hash = md.digest(hashData);
keyAndIv = concatenateByteArrays(keyAndIv, hash);
}
final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
int b;
byte[] d = new byte[8];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
cos.flush();
cos.close();
fis.close();
System.out.println("encrypt done " + path);
} catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return path;
}
static void decryptNew(String path,String password, String outPath) {
byte[] SALTED_MAGIC = "Salted__".getBytes(StandardCharsets.UTF_8);
try{
FileInputStream fis = new FileInputStream(path);
FileOutputStream fos = new FileOutputStream(outPath);
final byte[] pass = password.getBytes(StandardCharsets.US_ASCII);
final byte[] inBytes = Files.readAllBytes(Paths.get(path));
final byte[] shouldBeMagic = Arrays.copyOfRange(inBytes, 0, SALTED_MAGIC.length);
if (!Arrays.equals(shouldBeMagic, SALTED_MAGIC)) {
throw new IllegalArgumentException("Initial bytes from input do not match OpenSSL SALTED_MAGIC salt value.");
}
final byte[] salt = Arrays.copyOfRange(inBytes, SALTED_MAGIC.length, SALTED_MAGIC.length + 8);
final byte[] passAndSalt = concatenateByteArrays(pass, salt);
byte[] hash = new byte[0];
byte[] keyAndIv = new byte[0];
for (int i = 0; i < 3 && keyAndIv.length < 48; i++) {
final byte[] hashData = concatenateByteArrays(hash, passAndSalt);
MessageDigest md = null;
md = MessageDigest.getInstance("MD5");
hash = md.digest(hashData);
keyAndIv = concatenateByteArrays(keyAndIv, hash);
}
final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
final byte[] clear = cipher.doFinal(inBytes, 16, inBytes.length - 16);
String contentDecoded = new String(clear, StandardCharsets.UTF_8);
fos.write(contentDecoded.getBytes());
fos.close();
System.out.println("Decrypt is completed");
}catch(Exception e){
e.printStackTrace();
}
}
public static byte[] concatenateByteArrays(byte[] a, byte[] b) {
return ByteBuffer
.allocate(a.length + b.length)
.put(a).put(b)
.array();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.