解密在Java中使用AES加密的文件,使用SHA-1和OpenSSL。

huangapple go评论81阅读模式
英文:

Decrypt aes encrypted file in java sha1 openssl

问题

我尝试通过参考这个代码来实现文件解密:

加密部分我是按照这种方式完成的:
https//stackoverflow.com/questions/64423926/encrypt-file-in-java-and-decrypt-in-openssl-with-key-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Ä

注意:起始的 "Salted" 部分没有进行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);
        String source = getFileContent(fis);
        final Decoder decoder = Base64.getDecoder();
        final byte[] inBytes = decoder.decode(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();

        System.out.println("Decrypt is completed");
    } catch (Exception e) {
        e.printStackTrace();
    }
}
英文:

Im trying to implement file decryption by referring this code:

Encryption part i have done this way:
https//stackoverflow.com/questions/64423926/encrypt-file-in-java-and-decrypt-in-openssl-with-key-aes

And the encrypted file im able to decrypt with openssl.

But the decrypt to file in java is causing error:

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)

Content in my encrypted file is:

Salted__&#168;‹–1ž#&#161;&#240;=—&#214;&#207;&#249;&#225;•NE&#196;

Note: Starting salted part is not base64encoded. following data is encoded.

Please suggest on correct implementation of file decryption.

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(&quot;Initial bytes from input do not match OpenSSL SALTED_MAGIC salt value.&quot;);
}
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 &lt; 3 &amp;&amp; keyAndIv.length &lt; 48; i++) {
final byte[] hashData = array_concat(hash, passAndSalt);
MessageDigest md = null;
md = MessageDigest.getInstance(&quot;SHA-1&quot;);
hash = md.digest(hashData);
keyAndIv = array_concat(keyAndIv, hash);
}
final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
final SecretKeySpec key = new SecretKeySpec(keyValue, &quot;AES&quot;);
final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
final Cipher cipher = Cipher.getInstance(&quot;AES/CBC/PKCS5Padding&quot;);
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(&quot;Decrypt is completed&quot;);
}catch(Exception e){
e.printStackTrace();
}
}

答案1

得分: 0

以下是翻译好的代码部分:

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";

        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();
    }
}

请注意,此处只提供了翻译的代码部分,代码的功能和逻辑保持不变。

英文:

The below code is doing a complete file encryption and decryption and is compatible to the OpenSSL commands

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

I left out some variables as they are not used in decryption method and on the other hand substituded the byte[]
concatination with a pure Java version.

The simple output is:

encrypt done plaintext.txt
ciphertext: plaintext.txt
Decrypt is completed

Security warning: the key derivation is DEPRECATED and should not used any longer. The code does not have any exception handling and is for educational purpose only.

code:

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(&quot;https://stackoverflow.com/questions/64443373/decrypt-aes-encrypted-file-in-java-sha1-openssl?noredirect=1#comment113960588_64443373&quot;);
String plaintextFilename = &quot;plaintext.txt&quot;;
String ciphertextFilename = &quot;plaintext.txt.crypt&quot;;
String decryptedtextFilename = &quot;plaintextDecrypted.txt&quot;;
String password = &quot;testpass&quot;;
// 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(&quot;ciphertext: &quot; + 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(&quot;.crypt&quot;));
final byte[] pass = password.getBytes(StandardCharsets.UTF_8);
final byte[] salt = (new SecureRandom()).generateSeed(8);
fos.write(&quot;Salted__&quot;.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 &lt; 3 &amp;&amp; keyAndIv.length &lt; 48; i++) {
final byte[] hashData = concatenateByteArrays(hash, passAndSalt);
final MessageDigest md = MessageDigest.getInstance(&quot;MD5&quot;);
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, &quot;AES&quot;);
final Cipher cipher = Cipher.getInstance(&quot;AES/CBC/PKCS5Padding&quot;);
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(&quot;encrypt done &quot; + path);
} catch (IOException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
return path;
}
static void decryptNew(String path,String password, String outPath) {
byte[] SALTED_MAGIC = &quot;Salted__&quot;.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(&quot;Initial bytes from input do not match OpenSSL SALTED_MAGIC salt value.&quot;);
}
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 &lt; 3 &amp;&amp; keyAndIv.length &lt; 48; i++) {
final byte[] hashData = concatenateByteArrays(hash, passAndSalt);
MessageDigest md = null;
md = MessageDigest.getInstance(&quot;MD5&quot;);
hash = md.digest(hashData);
keyAndIv = concatenateByteArrays(keyAndIv, hash);
}
final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
final SecretKeySpec key = new SecretKeySpec(keyValue, &quot;AES&quot;);
final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
final Cipher cipher = Cipher.getInstance(&quot;AES/CBC/PKCS5Padding&quot;);
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(&quot;Decrypt is completed&quot;);
}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();
}
}

huangapple
  • 本文由 发表于 2020年10月20日 18:34:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/64443373.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定