使用Java对文件进行加密,然后使用OpenSSL和AES密钥进行解密。

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

Encrypt file in java and decrypt in openssl with key aes

问题

我参考了这个链接来在Java中进行文件加密(成功创建了加密文件)

之后我想使用openssl进行解密。
我尝试了以下命令,但似乎都不起作用。
请建议正确的openssl解密命令。

openssl aes-256-cbc -d -in sample.crypt -out sample.txt -k testpass
>> 显示 "bad magic number"

openssl enc -aes-256-cbc -base64 -pass pass:testpass -d -p -in sample.crypt -out sample.txt
>> 显示 "error reading input file"

以下是我的加密Java代码:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class EncryptTest {
    private static final String SALTED_STR = "Salted__";
    private static final byte[] SALTED_MAGIC = SALTED_STR.getBytes(US_ASCII);
    static String password = "testpass";

    public static String encryptfile(Context context, String path, int category) {
        // 加密代码...
        return path;
    }
}

注意:上述是提供给您的代码翻译。如果您需要任何关于代码或加密过程的解释或指导,请随时提问。

英文:

I referred this link to do encrypt a file in java(encrypted file is created successfully)

And later i want to decrypt it using openssl.
I tried below commands but none of them seems to work.
Please suggest correct command to decrypt in openssl.

openssl aes-256-cbc -d -in sample.crypt -out sample.txt -k testpass

>> shows "bad magic number"

openssl enc -aes-256-cbc -base64 -pass pass:testpass -d -p -in sample.crypt -out sample.txt

>> shows "error reading input file"

And here is my encryption java code:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.nio.charset.StandardCharsets.UTF_8;

public class EncryptTest {

    private static final String SALTED_STR = "Salted__";
    private static final byte[] SALTED_MAGIC = SALTED_STR.getBytes(US_ASCII);
    static String password = "testpass";

    public static String encryptfile(Context context, String path, int category) {
            try {
                FileInputStream fis = new FileInputStream(path);
                FileOutputStream fos = new FileOutputStream(path.concat(".crypt"));
                final byte[] pass = password.getBytes(US_ASCII);
                final byte[] salt = (new SecureRandom()).generateSeed(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);
                    final MessageDigest md = MessageDigest.getInstance("MD5");
                    hash = md.digest(hashData);
                    keyAndIv = array_concat(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();
                Log.e(TAG, "encrypt done " + path);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
                e.printStackTrace();
            }
        }

        return path;
}	

答案1

得分: 4

OpenSSL期望一个特殊的格式,即Salted__的ASCII编码值,后跟8字节的盐,然后是实际的密文。在发布的Java代码中,第一个块(ASCII编码的Salted__加上盐)没有被写入,因此必须添加,例如:

	...
	final byte[] salt = (new SecureRandom()).generateSeed(8);
	fos.write(SALTED_MAGIC);
	fos.write(salt);
	...

通过这个改变,密文包含了解密所需的信息和格式。

值得注意的是,OpenSSL在早期版本中使用MD5作为默认摘要,而从v1.1.0版本开始使用SHA256。因此,在后一版本中,OpenSSL语句中必须添加-md md5(在早期版本中是可选的)。

这两个发布的OpenSSL语句成功解密了在我的机器上使用(修改后的)Java代码创建的密文(在第二个语句中,必须去除-base64选项,因为Java代码没有对密文进行Base64编码):

	openssl aes-256-cbc -d -in sample.crypt -out sample.txt -k testpass -md md5
	openssl enc -aes-256-cbc -pass pass:testpass -d -p -in sample.crypt -out sample.txt -md md5

还应该提到,OpenSSL应用了EVP_BytesToKey()函数来派生密钥和初始化向量(IV)。这个函数不是标准的,被认为相对不安全,可以在这里看到详细信息2。OpenSSL的新版本会生成相应的警告(警告: 使用了不推荐的密钥派生)。

英文:

OpenSSL expects a special format, namely the ASCII encoded value of Salted__, followed by the 8 bytes salt, followed by the actual ciphertext. In the posted Java code the first block (the ASCII encoded Salted__ plus the salt) is not written, i.e. this must be added, e.g.:

<!-- language: lang-java -->
...
final byte[] salt = (new SecureRandom()).generateSeed(8);
fos.write(SALTED_MAGIC);
fos.write(salt);
...

With this change, the ciphertext contains the information and format required for decryption with OpenSSL.

It should be noted that OpenSSL used MD5 as default digest in earlier versions and SHA256 from version v1.1.0 on. For the latter versions, thus a -md md5 must be added to the OpenSSL statement (for earlier versions it's optional).

Both posted OpenSSL statements successfully decrypt a ciphertext created with the (modified) Java code on my machine (in the 2nd statement the -base64 option must be removed, because the Java code does not Base64 encode the ciphertext):

<!-- language: none -->
openssl aes-256-cbc -d -in sample.crypt -out sample.txt -k testpass -md md5
openssl enc -aes-256-cbc -pass pass:testpass -d -p -in sample.crypt -out sample.txt -md md5

It should also be mentioned that OpenSSL applies the EVP_BytesToKey() function to derive the key and IV. This function is not a standard and is considered relatively insecure, see e.g. here. New versions of OpenSSL generate a corresponding warning (WARNING : deprecated key derivation used).

huangapple
  • 本文由 发表于 2020年10月19日 16:45:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/64423926.html
匿名

发表评论

匿名网友

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

确定