/*******************************************************************************
*	All Rights reserved,Copyright (c) K-Opticom
********************************************************************************
*＜プログラム内容＞
*	システム名		：eo顧客基幹システム
*   モジュール名    ：JCCejbEncryptionUtil
*   ソースファイル名：JCCejbEncryptionUtil.java
*   作成者          ：富士通
*   日付            ：2011年12月27日
*＜機能概要＞
*   文字列暗号化及び復号化を行う共通部品です。暗号化の方式にはAES256を使用します。
*＜修正履歴＞
*   バージョン  修正日       修正者      修正内容
*   v1.00.00    2011/12/27   EK)909308    新規作成
*   v32.00.00   2017/05/26   FJ)河邊     【OM-2017-0000488】オープンカーソルエラー
*
**********************************************************************/

package eo.ejb.common;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.fujitsu.futurity.model.base.CAANConnectionMgr;
import com.fujitsu.futurity.model.base.CAANMsg;
import com.fujitsu.futurity.model.ejb.common.JSYejbConnection;
import com.fujitsu.futurity.model.ejb.common.fw.AgentDispatchContext;

import eo.common.util.JCCFrameworkException;
import eo.common.util.JCCcomEncryptionUtil;



/**
 * 文字列暗号化及び復号化を行うクラス。<p>
 * <BR>
 * @author 富士通
 */
public class JCCejbEncryptionUtil
{	
	
	/**
	 * 文字列暗号化処理です。入力された文字列を暗号化して結果の文字列を返却します。
	 *
	 * @param inMsg CAANMsg
	 * @param context AgentDispatchContext
	 * @param inStr 暗号化対象の文字列
	 * @return 暗号化結果の文字列
	 * @throws JCCFrameworkException
	 */
	public static String getEncryptResult(CAANMsg inMsg, AgentDispatchContext context, Object inStr) throws JCCFrameworkException
	{
		// 入力パラメータのnullチェック
		if(null == inMsg)
		{
			throw new JCCFrameworkException("入力パラメータ[CAANMsg]がnullです。");
		}
		if(null == context)
		{
			throw new JCCFrameworkException("入力パラメータ[AgentDispatchContext]がnullです。");
		}
		if(null == inStr || "".equals(inStr))
		{
			throw new JCCFrameworkException("入力パラメータ[暗号化対象の文字列]が設定されていません。");
		}
		
		// 入力パラメータのオブジェクト文字列をString型にキャスト
		String input = (String)inStr;
		
		// PL/SQLから結果を取得するためのbyte配列領域
		byte[] bytes = null;
		
		// SQL文の組立て領域
		StringBuffer sqlSelect = new StringBuffer();
		
		// プリペアステートメント
		PreparedStatement stmt = null;
		ResultSet rs = null;
		Connection con = null;
		
		// 暗号化結果の取得領域
		String rslt = null;
		try
		{
			// 暗号化キー生成
			String encKey = JCCModelCommon.getApplicationConst("ENCRYPT_KEY");
			if(null == encKey)
			{
				throw new JCCFrameworkException("APLConstに暗号化キーを復号化するための値が設定されていません。");
			}
			String key = JCCModelCommon.getApplicationConst("AES256_KEY");
			if(null == key)
			{
				throw new JCCFrameworkException("APLConstに暗号化キーが設定されていません。");
			}
			key = JCCcomEncryptionUtil.decrypt(encKey, key);
			
			// 暗号化用PL/SQL名取得
			String encProcNm = JCCModelCommon.getApplicationConst("ENC_PROC_NM");
			if(null == encProcNm)
			{
				throw new JCCFrameworkException("APLConstに暗号化用PL/SQL名が設定されていません。");
			}
			
			// SQL文の生成
			sqlSelect.append("SELECT (")
					.append(encProcNm)
					.append("( ?, ? ) ) ENC_RSLT ")
					.append("FROM DUAL");
			
			// コネクションの取得
			con = JSYejbConnection.getConnection("DUAL");
			
			// バインド変数に値を設定
			stmt = con.prepareStatement(sqlSelect.toString());
			stmt.setObject(1, input);
			stmt.setObject(2, key);
			
			// SQL発行
			rs = stmt.executeQuery();
			
			// 結果の取得
			if(rs.next() == true)
			{
				bytes = (byte[])rs.getObject("ENC_RSLT");
				
				// byte配列をStringに変換
				StringBuffer buf = new StringBuffer(bytes.length * 2);
				for(int i = 0; i < bytes.length; i++)
				{
					int bt = bytes[i] & 0xff;
					if(bt < 0x10)
					{
						buf.append("0");
					}
					buf.append(Integer.toHexString(bt));
				}
				rslt = buf.toString();
			}
			else
			{
				throw new JCCFrameworkException("PL/SQLの実行後に暗号化文字列を取得できませんでした。");
			}
		}
		catch(Throwable th)
		{
			throw new JCCFrameworkException(th.getMessage() + "(文字列の暗号化に失敗しました。)", th);
		}
		finally
		{
			// 資源の解放
			try
			{
				if(null != stmt)
				{
					stmt.close();
				}
				if(null != rs)
				{
					rs.close();
				}
// OM-2017-0000488 2017/05/26 ADD START
				if (null != con)
				{
					CAANConnectionMgr.getInstance().close(con);
				}
// OM-2017-0000488 2017/05/26 ADD END
			}
			catch(SQLException e)
			{
				throw new JCCFrameworkException(e);
			}
		}
		return rslt;
	}
	
	/**
	 * 文字列復号化処理です。入力された文字列を復号化して結果の文字列を返却します。
	 * 
	 * @param inMsg CAANMsg
	 * @param context AgentDispatchContext
	 * @param inStr 復号化対象の文字列
	 * @return 復号化結果の文字列
	 * @throws JCCFrameworkException
	 */
	public static String getDecryptResult(CAANMsg inMsg, AgentDispatchContext context, Object inStr) throws JCCFrameworkException
	{
		// 入力パラメータのnullチェック
		if(null == inMsg)
		{
			throw new JCCFrameworkException("入力パラメータ[CAANMsg]がnullです。");
		}
		if(null == context)
		{
			throw new JCCFrameworkException("入力パラメータ[AgentDispatchContext]がnullです。");
		}
		if(null == inStr || "".equals(inStr))
		{
			throw new JCCFrameworkException("入力パラメータ[復号化対象の文字列]が設定されていません。");
		}
		
		// 入力パラメータのオブジェクト文字列をString型にキャスト
		String input = (String)inStr;
		
		// PL/SQLに渡すためのbyte配列領域
		byte[] bytes = null;
		
		// SQL文の組立て領域
		StringBuffer sqlSelect = new StringBuffer();
		
		// プリペアステートメント
		PreparedStatement stmt = null;
		ResultSet rs = null;
		Connection con = null;
		
		// 復号化結果の取得領域
		String rslt = null;
		
		try
		{
			// 復号化キー生成
			String encKey = JCCModelCommon.getApplicationConst("ENCRYPT_KEY");
			if(null == encKey)
			{
				throw new JCCFrameworkException("APLConstに復号化キーを復号化するための値が設定されていません。");
			}
			String key = JCCModelCommon.getApplicationConst("AES256_KEY");
			if(null == key)
			{
				throw new JCCFrameworkException("APLConstに復号化キーが設定されていません。");
			}
			key = JCCcomEncryptionUtil.decrypt(encKey, key);
			
			// 復号化用PL/SQL名取得
			String decProcNm = JCCModelCommon.getApplicationConst("DEC_PROC_NM");
			if(null == decProcNm)
			{
				throw new JCCFrameworkException("APLConstに復号化用PL/SQL名が設定されていません。");
			}
			
			// String型文字列をbyte配列に変換
			bytes = new byte[input.length() / 2];
			for(int i = 0; i < bytes.length; i++)
			{
				bytes[i] = (byte)Integer.parseInt(input.substring(i * 2, (i + 1) * 2), 16);
			}
			
			// SQL文の生成
			sqlSelect.append("SELECT (")
					.append(decProcNm)
					.append("( ?, ? )) DEC_RSLT ")
					.append("FROM DUAL");
			
			// コネクションの取得
			con = JSYejbConnection.getConnection("DUAL");
			
			// バインド変数に値を設定
			stmt = con.prepareStatement(sqlSelect.toString());
			stmt.setObject(1, bytes);
			stmt.setObject(2, key);
			
			// SQL発行
			rs = stmt.executeQuery();
			
			// 結果の取得
			if(rs.next() == true)
			{
				rslt = (String)rs.getObject("DEC_RSLT");
			}
			else
			{
				throw new JCCFrameworkException("PL/SQLの実行後に復号化文字列を取得できませんでした。");
			}
		}
		catch(Throwable th)
		{
			throw new JCCFrameworkException(th.getMessage() + "(文字列の復号化に失敗しました。)", th);
		}
		finally
		{
			// 資源の解放
			try
			{
				if(null != stmt)
				{
					stmt.close();
				}
				if(null != rs)
				{
					rs.close();
				}
// OM-2017-0000488 2017/05/26 ADD START
				if (null != con)
				{
					CAANConnectionMgr.getInstance().close(con);
				}
// OM-2017-0000488 2017/05/26 ADD END
			}
			catch(SQLException e)
			{
				throw new JCCFrameworkException(e);
			}
		}
		return rslt;
	}
}
