java加密shell解密的实现

文章目录

前言

有个需求,需要用java加密,然后在linux上用shell命令解密,想到用openssl实现,按例网上找了一堆,apache的common-codec有相关aes对称加解密算法的实现,但是该加密的秘文拿到linux终端就不好使了:echo 密文 | openssl enc -aes-128-cbc -a -d -pass pass:密钥,参考了一篇,其加密后在linux上能解密,但是java不能解密,自己修改了一下,最终java能加密解密,linux上也能加解密.参考文章: https://blog.csdn.net/weixin_35698738/article/details/114205175

代码实现

package org.lmj.util;

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

import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class OpensslJavaEDkey {

    /**
     * OpenSSL's magic initial bytes.
     */
    private static final String SALTED_STR = "Salted__";
    private static final byte[] SALTED_MAGIC = SALTED_STR.getBytes(US_ASCII);

    /**
     * @param password The password / key to encrypt with.
     * @return A base64 encoded string containing the encrypted data.
     */
    static String encrypt(String password, String clearText) throws Exception {
        final byte[] pass = password.getBytes(US_ASCII);
        final byte[] salt = (new SecureRandom()).generateSeed(8);
        final byte[] inBytes = clearText.getBytes(UTF_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);
        }
        /**
         * common-codec是这样加密的,这样整出来的密文在linux上用openssl enc解不出来
         * final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
         * final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
         */
        final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 16);
        final byte[] iv = Arrays.copyOfRange(keyAndIv, 16, 32);
        final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
        final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
        byte[] data = cipher.doFinal(inBytes);
        data = array_concat(array_concat(SALTED_MAGIC, salt), data);
        return Base64.getEncoder().encodeToString(data);
    }

    /**
     * @param password
     * @param source The encrypted data
     * @return
     */
    static String decrypt(String password, String source) throws Exception {
        final byte[] pass = password.getBytes(US_ASCII);
        final byte[] inBytes = Base64.getDecoder().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);
            final MessageDigest md = MessageDigest.getInstance("MD5");
            hash = md.digest(hashData);
            keyAndIv = array_concat(keyAndIv, hash);
        }
        final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 16);
        final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
        final byte[] iv = Arrays.copyOfRange(keyAndIv, 16, 32);
        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);
        return new String(clear, UTF_8);
    }

    private static byte[] array_concat(final byte[] a, final byte[] b) {
        final byte[] c = new byte[a.length + b.length];
        System.arraycopy(a, 0, c, 0, a.length);
        System.arraycopy(b, 0, c, a.length, b.length);
        return c;
    }

    public static void main(String[] args) {
        try {
            String secretKey = "123abc@+/#^sxyz";
            String a = encrypt(secretKey, "hello world");
            System.out.println(a);
            String tecmint = decrypt(secretKey, a);
            System.out.println(tecmint);
        } catch (Exception e) {
            System.out.println(e);
            /**
             * 参考文章: https://blog.csdn.net/weixin_35698738/article/details/114205175
             * shell 调用系统函数解密:SPASS=$(echo ${SPASS} | openssl enc -aes-128-cbc -a -d -pass pass:tecmint)
             */
            //pass不能识别的特殊字符 !& # ^
            //echo 密文 | openssl enc -aes-128-cbc -a -d -pass pass:123abc@+/#^sxyz
            //echo U2FsdGVkX194fc1OUffImRJfsNVjlU5aMdMfqYNepUw=| openssl enc -aes-128-cbc -a -d -pass pass:123abc@+/#^sxyz
        }
    }
}
上一篇:python - flow control


下一篇:MyBatis_动态SQL