openssl encrpyt java 解密

问题描述 投票:0回答:1

您好,我正在使用 openssl 来加密字符串,并使用 JAVA 代码来解密它。我的

key
是“SUDIPTA123”。我用来加密的命令

encdata=$(echo -n "12345627678" | openssl enc -v -aes-256-cbc -base64 -nosalt -pass "pass:$key")

encdata
包含
/oUakLZnim7aPtpRySLRDw==

现在我使用以下JAVA代码来解密

encdata

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.spec.KeySpec;
import java.util.Base64;

public class AESDecryptor {
    public static void main(String[] args) {
        String encryptedText = "/oUakLZnim7aPtpRySLRDw==";
        String password = "SUDIPTA123";

        try {
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
            byte[] ivBytes = new byte[16];
            System.arraycopy(encryptedBytes, 0, ivBytes, 0, 16);
            byte[] encryptedData = new byte[encryptedBytes.length - 16];
            System.arraycopy(encryptedBytes, 16, encryptedData, 0, encryptedData.length);
            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec spec = new PBEKeySpec(password.toCharArray(), ivBytes, 65536, 256);
            SecretKeySpec secretKeySpec = new 
            SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(ivBytes));

            byte[] decryptedData = cipher.doFinal(encryptedData);

            String decryptedText = new String(decryptedData, "UTF-8");
            System.out.println("Decrypted Text: " + decryptedText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行代码后

decryptedText
是空字符串。我不确定我做错了什么。任何帮助将不胜感激。

java openssl aes public-key-encryption
1个回答
0
投票

解密失败,因为 OpenSSL 语句和 Java 代码应用不同的密钥派生函数 (KDF):在 OpenSSL 语句中使用默认的

EVP_BytesToKey()
,在 Java 代码中使用 PBKDF2。
为了使两种代码兼容,必须应用 same KDF,即如果 OpenSSL 语句是参考,则必须在 Java 代码中使用
EVP_BytesToKey()

网络上有各种针对
EVP_BytesToKey()
的 Java 实现,例如来自 BouncyCastle 的一款。
如果您将 Java 代码中的密钥和 IV 派生部分(即
try {}
内完整的第一个块)替换为(使用 BouncyCastle):

,则解密有效。
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
...
byte[] encryptedData = Base64.getDecoder().decode(encryptedText); // no separation required (since OpenSSL does not concatenate IV and cipertext)
byte[] passwordBytes = password.getBytes("UTF-8");
OpenSSLPBEParametersGenerator pbeGenerator = new OpenSSLPBEParametersGenerator(new SHA256Digest()); // SHA256 as of v1.1.0 (if in OpenSSL the default digest is applied)
pbeGenerator.init(passwordBytes, new byte[0]); // no salt (as you did not apply a salt in the OpenSSL statement)
ParametersWithIV parameters = (ParametersWithIV) pbeGenerator.generateDerivedParameters(256, 128); // 32 bytes key, 16 bytes IV
KeyParameter keyParam = (KeyParameter)parameters.getParameters();
SecretKeySpec secretKeySpec = new SecretKeySpec(keyParam.getKey(), "AES");
byte[] ivBytes = parameters.getIV();
...

安全:

  • EVP_BytesToKey()
    已弃用(因为不安全),不应再使用。可靠的密钥导出函数是 Argon2 或至少 PBKDF2。后者也受到更现代的 OpenSSL 版本的支持(通过 -pbkdf2-iter 选项)。
    在 PBKDF2 的上下文中,使用尽可能大的迭代计数,同时性能可接受(通常为几十万)。
  • 没有盐的密钥派生是不安全的。要在 OpenSSL 语句中使用盐,请删除 -nosalt 选项。然后,您的 OpenSSL 语句返回
    Salted__
    的 ASCII 编码的 Base64 编码,后跟 8 字节盐和实际密文。
    解密过程中必须将盐和密文分开。之后,可以使用密码和盐导出密钥和 IV,最后可以使用导出的密钥和 IV 解密实际的密文。
© www.soinside.com 2019 - 2024. All rights reserved.