All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.gdface.utils.encrypt.EncryptedProperties Maven / Gradle / Ivy

There is a newer version: 3.2.1
Show newest version
package net.gdface.utils.encrypt;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.InvalidPropertiesFormatException;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Properties;
import static net.gdface.utils.encrypt.AES128ECBNoPadding.wrapDecrypt;
import static net.gdface.utils.encrypt.AES128ECBNoPadding.wrapEncrypt;


/**
 * {@link Properties}的子类,
 * 基于{@link AES128ECBNoPadding}实现对{@link Properties}中指定的property值提供加密保护
 * @author guyadong
 *
 */
public class EncryptedProperties extends Properties {
	private static final long serialVersionUID = 2102942876991337031L;
	/**
	 * 密钥
	 */
	private final String password;
	/**
	 * 需要保护的key集合
	 */
	private final LinkedHashSet protectedKeys = new LinkedHashSet<>();
	/**
	 * 是否保护所有key
	 */
	private final boolean protecteAll;
	/**
	 * 是否需要解密标志,用于控制{@link #get(Object)}对返回的值是否要解密,{@link #put(Object, Object)}对设置的值是否要加密,
	 */
	private boolean trans;
	/**
	 * 构造方法
	 * @param properties 原始的{@link Properties}实例,如果不为{@code null},则全部将其中的property加入当前对象
	 * @param password 密钥,用于加密解密,为{@code null}或空时不实现加密保护
	 * @param protectedKeys 指定需要加密保护的key集合,为{@code null}或空对所有key加密保护
	 */
	public EncryptedProperties(Properties properties, String password, Iterable protectedKeys) {
		this.password = password;
		if(null != protectedKeys){
			for(String protectedKey:protectedKeys){
				if(null != protectedKey && protectedKey.length() > 0){
					this.protectedKeys.add(protectedKey);
				}
			}
			this.protecteAll = this.protectedKeys.isEmpty();
		}else{
			this.protecteAll = true;
		}
		if(null != properties){
			putAll(properties);
		}
		// 要放到putAll后面,因为构造函数中putAll不需要对值加密
		trans = true;
	}
	/**
	 * 构造方法
	 * @param password 密钥,用于加密解密,为{@code null}时不实现加密保护
	 * @param protectedKeys 指定需要加密保护的key集合,为{@code null}时不实现加密保护
	 */
	public EncryptedProperties(String password, Iterable protectedKeys) {
		this(null, password, protectedKeys);
	}
	private EncryptedProperties(Builder builder) {
		this(builder.properties,builder.password,builder.protectedKeys);
	}

	@Override
	public String getProperty(String key) {
        Object oval = get(key);
        String sval = (oval instanceof String) ? (String)oval : null;
        return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
	}
	/** 
	 * 如果指定的key为受保护的key则对返回值解密再返回
	 * @see java.util.Hashtable#get(java.lang.Object)
	 */
	@Override
	public synchronized Object get(Object key) {
		Object value = super.get(key);
		if( trans && value instanceof String 
				&& password != null && password.length() > 0 
				&& (protecteAll || protectedKeys.contains(key))){
			try {
				return wrapDecrypt((String)value, password);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		return value;
	}

	/**
	 * 如果指定的key为受保护的key则对要设置的值加密后再加入hashTable
	 * @see java.util.Hashtable#put(java.lang.Object, java.lang.Object)
	 */
	@Override
	public synchronized Object put(Object key, Object value) {
		if(trans && value instanceof String 
				&& password != null && password.length() > 0 
				&& (protecteAll || protectedKeys.contains(key))){
			try {
				value = wrapEncrypt((String)value, password);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		return super.put(key, value);
	}
	@Override
	public void store(Writer writer, String comments) throws IOException {
		try {
			trans = false;
			super.store(writer, comments);			
		} finally {
			trans = true;
		}
	}

	@Override
	public void store(OutputStream out, String comments) throws IOException {
		try {
			trans = false;
			super.store(out, comments);
		} finally {
			trans = true;
		}
	}
	
	@Override
	public void storeToXML(OutputStream os, String comment) throws IOException {
		try {
			trans = false;
			super.storeToXML(os, comment);
		} finally {
			trans = true;
		}
	}

	@Override
	public void storeToXML(OutputStream os, String comment, String encoding) throws IOException {
		try {
			trans = false;
			super.storeToXML(os, comment, encoding);
		} finally {
			trans = true;
		}
	}

	@Override
	public synchronized void load(Reader reader) throws IOException {
		try {
			trans = false;
			super.load(reader);
		} finally {
			trans = true;
		}
	}

	@Override
	public synchronized void load(InputStream inStream) throws IOException {
		try {
			trans = false;
			super.load(inStream);
		} finally {
			trans = true;
		}
	}

	@Override
	public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException {
		try {
			trans = false;
			super.loadFromXML(in);
		} finally {
			trans = true;
		}
	}
	@Override
	public String toString() {
        int max = size() - 1;
        if (max == -1)
            return "{}";

        StringBuilder sb = new StringBuilder();
        Iterator it = keySet().iterator();

        sb.append('{');
        for (int i = 0; ; i++) {
            Object key = it.next();
            Object value = get(key);
            sb.append(key   == this ? "(this Map)" : key.toString());
            sb.append('=');
            sb.append(value == this ? "(this Map)" : value.toString());

            if (i == max)
                return sb.append('}').toString();
            sb.append(", ");
        }
	}
	/**
	 * @return {@link Builder}实例
	 */
	public static Builder builder(){
		return new Builder();
	}
	
	/**
	 * 将{@link Properties}封装为{@link EncryptedProperties}实例
* 如果{@code properties}已经是{@link EncryptedProperties}实例则直接返回 * @param properties * @param password * @param protectedKeys * @return {@link EncryptedProperties}实例 * @see #EncryptedProperties(Properties, String, Iterable) */ public static EncryptedProperties wrap(Properties properties, String password, Iterable protectedKeys){ if(properties instanceof EncryptedProperties){ return (EncryptedProperties)properties; } return new EncryptedProperties(properties,password,protectedKeys); } public static class Builder{ private Properties properties = new Properties(); private String password; private LinkedHashSet protectedKeys = new LinkedHashSet<>(); private Builder(){ } /** * @param properties 要设置的 properties * @return 当前对象 */ public Builder properties(Properties properties) { if(null != properties){ this.properties = properties; } return this; } /** * 设置密钥 * @param password * @return 当前对象 */ public Builder password(String password) { this.password = password; return this; } /** * 指定要保护的key * @param protectedKeys * @return 当前对象 */ public Builder protectedKeys(Iterable protectedKeys) { if(null != protectedKeys){ for(String key : protectedKeys){ protectedKey(key); } } return this; } /** * 指定要保护的key * @param protectedKeys * @return 当前对象 */ public Builder protectedKeys(String... protectedKeys) { if(null != protectedKeys){ for(String key : protectedKeys){ protectedKey(key); } } return this; } /** * 指定要保护的key * @param protectedKey * @return 当前对象 */ public Builder protectedKey(String protectedKey) { if(null != protectedKey && protectedKey.length() > 0){ this.protectedKeys.add(protectedKey); } return this; } /** * 设置保护所有key * @return 当前对象 */ public Builder protectedAll(){ protectedKeys.clear(); return this; } /** * 根据当前对象提供的参数创建{@link EncryptedProperties}实例 */ public EncryptedProperties build(){ return new EncryptedProperties(this); } public EncryptedProperties wrap(){ return EncryptedProperties.wrap(properties, password, protectedKeys); } } }