利用otter對敏感資料加密

czxin788發表於2021-09-15

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的自帶函式解密

    

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28916011/viewspace-2792209/,如需轉載,請註明出處,否則將追究法律責任。

相關文章