利用otter对敏感数据加密

来源:这里教程网 时间:2026-03-01 16:01:57 作者:

1、需求    mysql的敏感字段,在同步到从库时,利用aes加密存储在从库。2、方法    

package com.alibaba.otter;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Objects;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang.StringUtils;
import com.alibaba.otter.node.extend.processor.AbstractEventProcessor;
import com.alibaba.otter.shared.etl.model.EventColumn;
import com.alibaba.otter.shared.etl.model.EventData;
import com.alibaba.otter.shared.etl.model.EventType;
public class TransferProcessor extends AbstractEventProcessor {
	private static final String DEFAULT_KEY = "223081629e274cecaxxxxxx"; //秘钥
	public boolean process(EventData eventData) {
		String eventType = eventData.getEventType().getValue();
		if (eventType.equals(EventType.QUERY.getValue())) {
			return true;
		}
		ColumnInfoEnum[] values = ColumnInfoEnum.values();
		for (ColumnInfoEnum cie : values) {
			EventColumn column = getColumn(eventData, cie.getColumnKey());
			if (Objects.nonNull(column)) {
				if (StringUtils.isNotBlank(column.getColumnValue())) {
					column.setColumnValue(aes_encrypt(column.getColumnValue(), DEFAULT_KEY));
				}
			}
		}
		return true;
	}
	/******************************
	 * 字符串转字节数组 开始
	 ****************************************/
	/**
	 * 
	 * mysql 加密一直的SecretKeySpec
	 * 
	 * @param key
	 * 
	 * @return
	 * 
	 */
	public static SecretKeySpec gener(String key) {
		try {
			byte[] finalKey = new byte[16];
			int i = 0;
			for (byte b : key.getBytes("utf-8")) {
				finalKey[i++ % 16] ^= b;
			}
			return new SecretKeySpec(finalKey, "AES");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}
	public static String aes_encrypt(String password, String strKey) {
		try {
			byte[] keyBytes = Arrays.copyOf(strKey.getBytes("ASCII"), 16);
			// 通用的
			// SecretKey key = new SecretKeySpec(keyBytes, "AES");
			// 生成和mysql一直的加密数据
			SecretKeySpec key = gener(strKey);
			Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, key);
			byte[] cleartext = password.getBytes("UTF-8");
			byte[] ciphertextBytes = cipher.doFinal(cleartext);
			return new String(Hex.encodeHexString(ciphertextBytes));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	public static SecretKeySpec generateMySQLAESKey(final String key, final String encoding) {
		try {
			final byte[] finalKey = new byte[16];
			int i = 0;
			for (byte b : key.getBytes(encoding))
				finalKey[i++ % 16] ^= b;
			return new SecretKeySpec(finalKey, "AES");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}
	public static String aes_decrypt(String content, String aesKey) {
		try {
			SecretKey key = generateMySQLAESKey(aesKey, "ASCII");
			Cipher cipher = Cipher.getInstance("AES");
			cipher.init(Cipher.DECRYPT_MODE, key);
			byte[] cleartext = Hex.decodeHex(content.toCharArray());
			byte[] ciphertextBytes = cipher.doFinal(cleartext);
			return new String(ciphertextBytes, "UTF-8");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	/******************************
	 * 字符串转字节数组 结束
	 ****************************************/
	private String replace(String sourceValue, int prefixLength, int subffixLength) {
		sourceValue = sourceValue.trim();
		if (StringUtils.isBlank(sourceValue)) {
			return "";
		}
		int length = sourceValue.length();
		if (length < (prefixLength + subffixLength)) {
			return "";
		}
		sourceValue = sourceValue.replaceAll("(\\s)", "*");
		System.out.println(sourceValue);
		int placeHolderLenth = length - prefixLength - subffixLength;
		String pattern = "(\\S{" + (prefixLength) + "})\\S{" + placeHolderLenth + "}(\\S{" + subffixLength + "})";
		StringBuilder placeHolder = new StringBuilder("$1");
		for (int i = 0; i < placeHolderLenth; i++) {
			placeHolder.append("*");
		}
		placeHolder.append("$2");
		return sourceValue.replaceAll(pattern, placeHolder.toString());
	}
	enum ColumnInfoEnum {
		
		FIRST_NAME("first_name",1,0),
		FULL_NAME("full_name",1,0),
		LAST_NAME("last_name",1,0); //将要加密的字段放在这,后面的数字没啥用
		ColumnInfoEnum(String columnKey, int prefixLength, int subffixLength) {
			this.columnKey = columnKey;
			this.prefixLength = prefixLength;
			this.subffixLength = subffixLength;
		}
		private String columnKey;
		private int prefixLength;
		private int subffixLength;
		public String getColumnKey() {
			return columnKey;
		}
		public int getPrefixLength() {
			return prefixLength;
		}
		public int getSubffixLength() {
			return subffixLength;
		}
	}
}

    这样,数据就可以加密存储在从库中了:     可以用mysql的自带函数解密     

相关推荐