Java openssl加密/解密密钥生成

Java openssl加密/解密密钥生成,java,openssl,cryptography,aes,sha256,Java,Openssl,Cryptography,Aes,Sha256,我正在使用Java8,并试图用Java模拟以下openssl调用 加密: echo-n'hello world'| openssl enc-a-aes-256-cbc-md sha256-pass:97DE:4F76 U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc= 解密: echo U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc=| openssl enc-d-a-aes-256-cbc-md sha256-pas

我正在使用Java8,并试图用Java模拟以下openssl调用

加密:

echo-n'hello world'| openssl enc-a-aes-256-cbc-md sha256-pass:97DE:4F76

U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc=

解密:

echo U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc=| openssl enc-d-a-aes-256-cbc-md sha256-pass-pass:97DE:4F76

你好,世界

问题:

  • 我的实现不起作用。我访问了许多其他的StackOverflow答案,但没有找到正确的实现。有人能为我指出解决这个问题的正确方向吗
  • 上面示例中的openssl系统调用使用摘要sha256。如果我在Java实现中使用sha1,是否只是将
    PBKDF2WithHmacSHA256
    更改为
    PBKDF2WithHmacSHA1
  • Test.java

    package test;
    
    import java.security.spec.KeySpec;
    
    import javax.crypto.Cipher;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.PBEKeySpec;
    import javax.crypto.spec.SecretKeySpec;
    import javax.xml.bind.DatatypeConverter;
    
    public class Test {
    
        public static final String PASSWORD = "97DE:4F76";
    
        public static String encryptString(String clearText, String password) {
            return "";
        }
    
        // echo U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc= | openssl enc -d -a -aes-256-cbc -md sha256 -pass pass:97DE:4F76
        //
        // see https://stackoverflow.com/a/992413, https://stackoverflow.com/a/15595200,
        // https://stackoverflow.com/a/22445878, https://stackoverflow.com/a/11786924
        public static String decryptString(String cypherText, String password) {
            byte[] dataBase64 = DatatypeConverter.parseBase64Binary(cypherText);
            byte[] salt = {
                    (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0,
                    (byte)0x0, (byte)0x0, (byte)0x0, (byte)0x0
            };
    
            try {
                // generate the key
                SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); // "PBKDF2WithHmacSHA1"
                KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
                SecretKey tmp = factory.generateSecret(spec);
                SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
    
                // decrypt the message
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
                cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
    
                byte[] decrypted = cipher.doFinal(dataBase64);
                String answer = new String(decrypted, "UTF-8");
                return answer;
    
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return "";
        }
    
        public static void main(String[] args) {
            System.out.println(decryptString("U2FsdGVkX18PnO/NLSxJ1pg6OKoLyZApMz7aBRfKhJc=", PASSWORD));
        }
    }
    
    这是运行上述代码的当前输出:

    java.security.InvalidKeyException: Illegal key size     at
             javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)  at
             javax.crypto.Cipher.init(Cipher.java:1393)     at
             javax.crypto.Cipher.init(Cipher.java:1327)     at
             test.Test.decryptString(Test.java:42)  at
             test.Test.main(Test.java:55)
    

    更新: 这是我在使用这个答案后最终实现的代码:->包含EVP_BytesToKey的其余常量和实现

    public static String decryptString(String cypherText, String password) {
            try {
                // decode the base64 cypherText into salt and encryptedString
                byte[] dataBase64 = DatatypeConverter.parseBase64Binary(cypherText);
                byte[] salt = Arrays.copyOfRange(dataBase64, SALT_OFFSET, SALT_OFFSET + SALT_SIZE);
                byte[] encrypted = Arrays.copyOfRange(dataBase64, CIPHERTEXT_OFFSET, dataBase64.length);
                System.out.println("dataBase64 = " + new String(dataBase64));
                System.out.println("salt: " + new BigInteger(1, salt).toString(16));
                System.out.println("encrypted: " + new BigInteger(1, encrypted).toString(16));    
    
                // --- specify cipher and digest for EVP_BytesToKey method ---
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
                MessageDigest sha1 = MessageDigest.getInstance("SHA-256");
    
                // create key and IV
                final byte[][] keyAndIV = EVP_BytesToKey(
                        KEY_SIZE_BITS / Byte.SIZE,
                        cipher.getBlockSize(),
                        sha1,
                        salt,
                        password.getBytes("ASCII"),
                        ITERATIONS);
                SecretKeySpec key = new SecretKeySpec(keyAndIV[INDEX_KEY], "AES");
                IvParameterSpec iv = new IvParameterSpec(keyAndIV[INDEX_IV]);
    
                // initialize the Encryption Mode
                cipher.init(Cipher.DECRYPT_MODE, key, iv);
    
                // decrypt the message
                byte[] decrypted = cipher.doFinal(encrypted);
                String answer = new String(decrypted, "UTF-8"); // should this be "ASCII"?
                return answer;
    
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return "";
        }
    

    由于某些法律原因,256位AES在Java中受到限制。您需要在JDK中显式启用强加密。搜索“无限制力量管辖权政策”您的2)可能。试试看。@Thilo,早些时候我下载了JCE,并将其与其他JAR一起放入java文件夹。然而,我刚刚意识到我安装了多个版本的java,并且我将这些JAR放在了错误的文件夹版本中。明天早上我回来工作的时候,我会用正确的java版本再试一次。我已经把这个标记为重复,因为另一个答案解决了我的问题@蒂洛,关于JCE你是对的。此外,从EVP_BytesToKey的另一个答案中实现算法也很有魅力!用于某些内部组件。以前使用MD5,1.1.0切换到SHA256。请注意,此更改不会影响
    EVP\u BytesToKey
    openssl enc
    等命令。