Oracle、Java採用DES/CBC/ZeroPadding加解密一致

Oracle的寫法:

--DES 加密
create or replace function des_encrypt(p_text varchar2, p_key varchar2)
  return varchar2 is
  v_text   varchar2(2048);
  v_key    varchar2(2048);
  v_enc    varchar2(2048);
  v_filllen pls_integer;
begin
  v_key := rpad(p_key,8,substr(p_key,lengthb(p_key)-1,1));
  --文本分組不足8位補充0
  v_filllen := ceil(lengthb(p_text) / 8) * 8 - lengthb(p_text);
  v_text    := p_text;
  while (v_filllen > 0) loop
    v_text    := v_text || chr(0);
    v_filllen := v_filllen - 1;
  end loop;
  --DES內置加密
  dbms_obfuscation_toolkit.desencrypt(input_string     => v_text,
                                      key_string       => v_key,
                                      encrypted_string => v_enc);
  return rawtohex(utl_raw.cast_to_raw(v_enc));
exception
  when others then
    return null;
end;

--DES 解密
create or replace function des_decrypt(p_text varchar2, p_key varchar2)
  return varchar2 is
  v_text varchar2(2048);
  v_key  varchar2(2048);
  v_enc  varchar2(2048);
begin
  v_key := rpad(p_key,8,substr(p_key,lengthb(p_key)-1,1));
  --密文16進制轉換爲普通字符串
  v_enc := utl_raw.cast_to_varchar2(hextoraw(p_text));
  --內置des解密
  dbms_obfuscation_toolkit.desdecrypt(input_string     => v_enc,
                                      key_string       => v_key,
                                      decrypted_string => v_text);
  return rtrim(v_text, chr(0));
exception
  when others then
    return null;
end;
###
select des_encrypt('123456','001') from dual;
select des_decrypt('812ACE1C7235843D','001') from dual;

Java實現方法:

package org.jeecg.common.util.encryption;

import groovy.util.logging.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.xml.bind.DatatypeConverter;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * DES加密解密
 */
@Slf4j
@Component
public class DesEncryptUtil {
    private static final String SECRET_KEY_FACTORY_ALGORITHM = "DES";
    /**
     * 加密算法:DES
     * 加密模式:CBC,每一組的加密模式與之前一組的加密進行強關聯。
     * 位數不足填充模式:不要自動填充,填充由程序實現,使用0填充。
     */
    private static final String CIPHER_ALGORITHM = "DES/CBC/NoPadding";
    /**
     * 分組長
     */
    private final static int BLOCK_SIZE = 8;
    /**
     * Map類型
     */
    private final static String JAVA_UTIL_MAP = "java.util.Map";
    /**
     * 字符格式
     */
    private final static String UTF_8 = "UTF-8";
    /**
     * 加密方法
     * @param data 要加密的數據
     * @param key 加密key
     * @return 加密的結果
     * @throws Exception
     */
    public static String encrypt(String data, String key) throws Exception {
        if(StringUtils.isBlank(data) || StringUtils.isBlank(key)){
            return null;
        }
        try{
            String desKeyValue = StringUtils.rightPad(key,BLOCK_SIZE,key.substring(key.length() - 1));
            DESKeySpec desKey = new DESKeySpec(desKeyValue.getBytes(UTF_8));
            SecretKey securekey = SecretKeyFactory.getInstance(SECRET_KEY_FACTORY_ALGORITHM).generateSecret(desKey);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, securekey, new IvParameterSpec(new byte[BLOCK_SIZE]));
            byte[] inBytes = new byte[((int) (data.getBytes(UTF_8).length / BLOCK_SIZE) + 1) * BLOCK_SIZE];
            for(int i = 0; i < data.getBytes(UTF_8).length; i++){
                inBytes[i] = data.getBytes(UTF_8)[i];
            }
            byte[] enBytes = cipher.doFinal(inBytes);
            String hexStr = DatatypeConverter.printHexBinary(enBytes);
            return new String(hexStr);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 解密方法
     * @param data 要解密的數據
     * @param key  解密key
     * @return 解密的結果
     * @throws Exception
     */
    public static String decrypt(String data, String key) throws Exception {
        if(StringUtils.isBlank(data) || StringUtils.isBlank(key)){
            return null;
        }
        try {
            String desKeyValue = StringUtils.rightPad(key,BLOCK_SIZE,key.substring(key.length() - 1));
            DESKeySpec desKey = new DESKeySpec(desKeyValue.getBytes(UTF_8));
            SecretKey securekey = SecretKeyFactory.getInstance(SECRET_KEY_FACTORY_ALGORITHM).generateSecret(desKey);
            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, securekey, new IvParameterSpec(new byte[BLOCK_SIZE]));
            byte[] decryptBytes = cipher.doFinal(Hex.decodeHex(data.toCharArray()));
            return new String(decryptBytes,UTF_8).trim();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根據傳入的對象進行全部字段加密
     * @param tClass 對象class類型,同時支持Map類型
     * @param source 加密對象
     * @param key 加密key
     * @throws BeansException
     */
    public static void encryptClass(Class<?> tClass, Object source, String key) throws Exception {
        encryptClass(tClass, source, key, (String[])null);
    }
    /**
     * 根據傳入的對象進行指定字段加密
     * @param tClass 對象class類型,同時支持Map類型
     * @param source 加密對象
     * @param key 加密key
     * @param ignoreProperties 忽視加密的屬性字段
     * @throws BeansException
     */
    public static void encryptClass(Class<?> tClass, Object source, String key, String... ignoreProperties) throws Exception {
        PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(tClass);
        List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
        if(null != tClass && null != tClass.getName() && tClass.getName().equals(JAVA_UTIL_MAP)){
            //Map類型
            Map map = (Map) source;
            if(null == map || map.isEmpty()){
                return;
            }
            Iterator iterator = map.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                if (entry.getKey() != null && entry.getValue() != null && (ignoreList == null || !ignoreList.contains(entry.getKey()))) {
                    entry.setValue(encrypt((String) entry.getValue(),key));
                }
            }
            source = map;
            return;
        }
        PropertyDescriptor[] propertyDescriptors = targetPds;
        for(int i = 0; i < targetPds.length; ++i){
            PropertyDescriptor targetPd = propertyDescriptors[i];
            Method writeMethod = targetPd.getWriteMethod();
            if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
                PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
                if (sourcePd != null) {
                    Method readMethod = sourcePd.getReadMethod();
                    if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
                        try {
                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                readMethod.setAccessible(true);
                            }
                            Object value = readMethod.invoke(source);
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }
                            String encryptValue = encrypt((String) value,key);
                            writeMethod.invoke(source, encryptValue);
                        } catch (Throwable e) {
                            throw new FatalBeanException("Could not encrypt property '" + targetPd.getName() + "' to source", e);
                        }
                    }
                }
            }
        }
    }

    /**
     * 根據傳入的對象進行全部字段解密
     * @param tClass 對象class類型,同時支持Map類型
     * @param source 解密對象
     * @param key 解密key
     * @throws BeansException
     */
    public static void decryptClass(Class<?> tClass, Object source, String key) throws Exception {
        decryptClass(tClass, source, key, (String[])null);
    }
    /**
     * 根據傳入的對象進行指定字段解密
     * @param tClass 對象class類型,同時支持Map類型
     * @param source 解密對象
     * @param key 解密key
     * @param ignoreProperties 忽視解密的屬性字段
     * @throws BeansException
     */
    public static void decryptClass(Class<?> tClass, Object source, String key, String... ignoreProperties) throws Exception {
        PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(tClass);
        List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
        if(null != tClass && null != tClass.getName() && tClass.getName().equals(JAVA_UTIL_MAP)){
            //Map類型
            Map map = (Map) source;
            if(null == map || map.isEmpty()){
                return;
            }
            Iterator iterator = map.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                if (entry.getKey() != null && entry.getValue() != null && (ignoreList == null || !ignoreList.contains(entry.getKey()))) {
                    entry.setValue(decrypt((String) entry.getValue(),key));
                }
            }
            source = map;
            return;
        }
        PropertyDescriptor[] propertyDescriptors = targetPds;
        for(int i = 0; i < targetPds.length; ++i){
            PropertyDescriptor targetPd = propertyDescriptors[i];
            Method writeMethod = targetPd.getWriteMethod();
            if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
                PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
                if (sourcePd != null) {
                    Method readMethod = sourcePd.getReadMethod();
                    if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
                        try {
                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                readMethod.setAccessible(true);
                            }
                            Object value = readMethod.invoke(source);
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }
                            String decryptValue = decrypt((String) value,key);
                            writeMethod.invoke(source, decryptValue);
                        } catch (Throwable e) {
                            throw new FatalBeanException("Could not decrypt property '" + targetPd.getName() + "' to source", e);
                        }
                    }
                }
            }
        }
    }

    /**
     * 獲取某個class類型指定的屬性字段數組
     * @param tClass 對象class類型
     * @param ignoreProperties 過濾的屬性字段
     * @return
     * @throws Exception
     */
    public static String[] getClassAttributes(Class<?> tClass,String... ignoreProperties) throws Exception {
        List<String> list = new ArrayList<>();
        PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(tClass);
        List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
        PropertyDescriptor[] propertyDescriptors = targetPds;
        for(int i = 0; i < targetPds.length; ++i){
            PropertyDescriptor targetPd = propertyDescriptors[i];
            Method writeMethod = targetPd.getWriteMethod();
            if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
                list.add(targetPd.getName());
            }
        }
        if(null == list || list.isEmpty()){
            return null;
        }
        String[] str = new String[list.size()];
        for(int i = 0; i < list.size(); i++){
            str[i] = list.get(i);
        }
        return str;
    }
    /**
     * 獲取某個Map類型指定的屬性字段數組
     * @param map 傳入的實例map對象
     * @param ignoreProperties 過濾的屬性字段
     * @return
     * @throws Exception
     */
    public static String[] getMapAttributes(Map map,String... ignoreProperties) throws Exception {
        if(null == map || map.isEmpty()){
            return null;
        }
        List<String> list = new ArrayList<>();
        List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
        Iterator iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry) iterator.next();
            if (entry.getKey() != null && (ignoreList == null || !ignoreList.contains(entry.getKey()))) {
                list.add((String) entry.getKey());
            }
        }
        if(null == list || list.isEmpty()){
            return null;
        }
        String[] str = new String[list.size()];
        for(int i = 0; i < list.size(); i++){
            str[i] = list.get(i);
        }
        return str;
    }

    /**
     * 測試
     * @param args
     */
    /*public static void main(String[] args) throws Exception {
        String str = "123456";
        String key = "encryptk";
        String enCode = encrypt(str,key);
        String deCode = decrypt(enCode,key);
        System.out.println(enCode);
        System.out.println(deCode);
    }*/
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章