package com.apobates.forum.utils;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * @see http://www.java2s.com/Code/Java/Security/EncryptingaStringwithDES.htm
 * @see https://community.oracle.com/thread/1528090
 * @author xiaofanku
 * @since 20200521
 */
public final class TripleDesCryp {
	private final String algorithm = "DESede/CBC/PKCS5Padding"; // "DESede/CBC/NoPadding"
	private IvParameterSpec iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
	/**
	 * 加密工具
	 */
	private final Cipher encryptCipher;
	/**
	 * 解密工具
	 */
	private final Cipher decryptCipher;

	/**
	 * 
	 * @param secretString
	 *            秘钥
	 * @throws GeneralSecurityException
	 */
	public TripleDesCryp(String secretString) throws GeneralSecurityException {
		byte[] keyBytes = secretString.getBytes();
		int l = keyBytes.length;
		// java.security.InvalidKeyException: Wrong key size
		if (keyBytes.length < 24) { // short key ? .. extend to 24 byte key
			byte[] tmpKey = new byte[24];
			System.arraycopy(keyBytes, 0, tmpKey, 0, l); 
			keyBytes = tmpKey;
		}
		SecretKey key = new SecretKeySpec(keyBytes, "DESede");
		Cipher eCipher = Cipher.getInstance(algorithm);
		eCipher.init(Cipher.ENCRYPT_MODE, key, iv);
		this.encryptCipher = eCipher;
		//
		Cipher dCipher = Cipher.getInstance(algorithm);
		dCipher.init(Cipher.DECRYPT_MODE, key, iv);
		this.decryptCipher = dCipher;

	}

	private byte[] encrypt(byte[] bytes) throws GeneralSecurityException {
		byte[] utf8String = encryptCipher.doFinal(bytes);
		//
		Base64.Encoder encoder = Base64.getEncoder();
		return encoder.encode(utf8String);
	}

	private byte[] decrypt(byte[] bytes) throws GeneralSecurityException {
		Base64.Decoder decoder = Base64.getDecoder();
		byte[] encryptedTextByte = decoder.decode(bytes);
		//
		return decryptCipher.doFinal(encryptedTextByte);
	}

	/**
	 * 加密字符串
	 *
	 * @param strIn
	 *            需加密的字符串
	 * @return 加密后的字符串
	 * @throws java.io.UnsupportedEncodingException
	 * @throws java.security.GeneralSecurityException
	 */
	public String encrypt(String strIn) throws UnsupportedEncodingException, GeneralSecurityException {
		byte[] utf8String = strIn.getBytes("UTF8");
		return new String(encrypt(utf8String), "UTF8");
	}

	/**
	 * 解密字符串
	 *
	 * @param strIn
	 *            需解密的字符串
	 * @return 解密后的字符串
	 * @throws java.io.UnsupportedEncodingException
	 * @throws java.security.GeneralSecurityException
	 */
	public String decrypt(String strIn) throws UnsupportedEncodingException, GeneralSecurityException {
		byte[] utf8String = strIn.getBytes("UTF8");
		return new String(decrypt(utf8String), "UTF8");
	}
}
