본문 바로가기
개발/Web

[Tomcat] JNDI 정보 암호화(DB정보 : url, username, passowrd) / KDF 알고리즘 이용

by ynzu🤍 2021. 11. 30.
반응형

1. url, username, password를 encrypt 한다.

  • KDFEncrypted.java
import java.security.MessageDigest;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Hex;


public class KDFEncrypted {
	
	public static void main(String[] args) {
		
	String key = "test";
		
        String url = "jdbc:tibero:thin:@10.10.10.XX:XXXX:tibero";
        String username = "root";
        String password= "1q2w3e4r";
        
        try {
	        System.out.println("########### Encrypt ############");
	        byte[] enc_url = encrypt("AES", key.getBytes(),  url.getBytes());
	        byte[] enc_username = encrypt("AES", key.getBytes(), username.getBytes());
	        byte[] enc_password = encrypt("AES", key.getBytes(),  password.getBytes());
	        
	        String hex_url = new String(Hex.encodeHex(enc_url));
	        String hex_username = new String(Hex.encodeHex(enc_username));
	        String hex_password = new String(Hex.encodeHex(enc_password));
	        System.out.println("enc_hex_url : " + hex_url);
	        System.out.println("enc_hex_username : " + hex_username);
	        System.out.println("enc_hex_password : " + hex_password);
	        
        }catch (Exception e){
        	e.printStackTrace();
        }
	}
	
	
	public static byte[] encrypt(String symmAlg, byte[] passwd, byte[] tbeData) throws Exception {
		byte[] encData = null;
		MessageDigest md = null;
		
		//try {
		md = MessageDigest.getInstance("SHA-256");
		
		md.update(passwd);
		byte[] hashVal = md.digest();
	
		byte[] key = new byte[16];
		System.arraycopy(hashVal, 0, key, 0, 16);
		byte[] iv = new byte[16];
		System.arraycopy(hashVal, 4, iv, 0, 16);
				
		String encAlg = (symmAlg + "/CBC/PKCS5Padding");
		Cipher cipher = Cipher.getInstance(encAlg);
		cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, symmAlg), new IvParameterSpec(iv));
		encData = cipher.doFinal(tbeData);
		
		return encData;
	}
}

=> KDF Encrypt 후 Hex Encoding, key값은 decrypt할 때 사용한다.(해당 예제에서 key는 test라는 string data)

 

2. Server.xml에 JNDI를 등록한다

<Context allowCasualMultipartParsing="true" docBase="project1" 
	path="/sample" reloadable="true" source="org.eclipse.jst.jee.server:project1"> 
				
					
	<Resource auth="Container" 
		defaultAutoCommit="false" 
		driverClassName="com.tmax.tibero.jdbc.TbDriver" 
		factory="com.project1.framework.jndi.KDFDecryptedDataSourceFactory"
		initialSize="1" maxActive="2" 
		maxWait="10000" minIdle="2" 
		name="jdbc/project1" 
		url="ac0973fa30774730995c2ff93353836ac102d1a795207b10ec353e6dbd01dd6e0d1ded3d41cbc9cce87c78b6b1ec6a8d" 
		username="5c5f0fc1f068b4c54698e71fc0982f1b" 
		password="f334da1d60b3e0e0d8d89802cf5209d3" 
		type="javax.sql.DataSource" 
		validationQuery="select 1 from dual" />
		
</Context>

=> 여기서 주의할 점은 factory, url, username, password이다.

KDFEncrypted.java로 부터 얻은 url, username, password를 세팅해주며, factory는 3번을 참고한다.

 

 

3. KDFDecryptedDataSourceFactory.java

package com.project1.framework.jndi;

import java.security.MessageDigest;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.StringRefAddr;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.dbcp.BasicDataSourceFactory;

public class KDFDecryptedDataSourceFactory extends BasicDataSourceFactory {
	
	private final String key = "test";
	private final String symmAlg = "AES";
	
	public static String randomIv(int len) {
		StringBuffer strBuffer = new StringBuffer();
		String iv = null, ivS = null;
		
		Random rd = new Random();
		
		for( int i = 0; i < len; i++ ) {
			if( iv == null || iv.length() < len ){
				ivS = Integer.toHexString(rd.nextInt());
				iv = strBuffer.append(ivS).toString();
			}
			if( iv.length() > len ) {
				iv = iv.substring(0, len);
				break;
			}
			if( iv.length() == len ) break;
		}

		return iv;
	}
	
	public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {

		if (obj instanceof Reference) {

			setUsername((Reference) obj);

			setPassword((Reference) obj);

			setUrl((Reference) obj);

		}

		return super.getObjectInstance(obj, name, nameCtx, environment);

	}

	private void setUrl(Reference ref) throws Exception {
		findDecryptAndReplace("url", ref);
	}

	private void setUsername(Reference ref) throws Exception {
		findDecryptAndReplace("username", ref);
	}

	private void setPassword(Reference ref) throws Exception {
		findDecryptAndReplace("password", ref);
	}
	
	private void findDecryptAndReplace( String refType, Reference ref) throws Exception {
		int idx = find(refType, ref);
		String decrypted = decrypt(ref.get(idx).getContent().toString());
		replace(idx, refType, decrypted, ref);
	}

	private void replace(int idx, String refType, String newValue, Reference ref) throws Exception {
		ref.remove(idx);
		ref.add(idx, new StringRefAddr(refType, newValue));
	}

	private int find(String addrType, Reference ref) throws Exception {
		Enumeration enu = ref.getAll();
		for (int i = 0; enu.hasMoreElements(); i++) {
			RefAddr addr = (RefAddr) enu.nextElement();
			if (addr.getType().compareTo(addrType) == 0)
				return i;
		}
		throw new Exception("The \"" + addrType + "\" name/value pair was not found"
				+ " in the Reference object.  The reference Object is" + " " + ref.toString());
	}

	// 복호화
	private String decrypt(String ciphertext) throws Exception {
		MessageDigest md = null;
		md = MessageDigest.getInstance("SHA-256");			
		md.update(key.getBytes());
		byte[] hashVal = md.digest();
	
		byte[] key = new byte[16];
		System.arraycopy(hashVal, 0, key, 0, 16);
		byte[] iv = new byte[16];
		System.arraycopy(hashVal, 4, iv, 0, 16);
		
		String encAlg = (symmAlg + "/CBC/PKCS5Padding");
		Cipher cipher = Cipher.getInstance(encAlg);
		
		cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, symmAlg), new IvParameterSpec(iv));
		
		String decryptedVal = new String( cipher.doFinal(Hex.decodeHex(ciphertext.toCharArray())) );
		
		return decryptedVal;
	}

}
728x90
반응형

댓글