본문 바로가기

Java Security/AES with JDBC

AES Encrypt, Decrype with JDBC

AES 알고리듬을 이용하여 평문을 암호화하고 데이터베이스에 저장 및 추출하는 예



관련참조



암호화된 데이터를 저장할 데이터베이스 테이블의 구조

암호화된 데이터는 byte[] 형으로 표현되므로 BLOB 형의 컬럼을 생성하여 byte[]을 저장할 수 있도록 한다

CREATE TABLE ENC_TB ( NUM NUMBER, ENC_DATA BLOB )



AES알고리듬을 이용하여 암호화 복호화 데이터베이스 입출력 예제 완전한 코드

암호화된 데이터를 Base64 인코딩/디코딩 기능도 포함되어 있으므로 웹사이트 제작시에도 참조하면 된다

사용된 Base64클래스 라이브러리 

commons-codec-1.9-bin.zip


package org.kdea.java.security;

import java.security.Key;
import java.sql.*;
import java.util.Arrays;

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

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

public class AES_DB_Test {

	private Connection getConn() 
	{
		Connection conn;

		String jdbc_driver = "oracle.jdbc.OracleDriver";
		String db_url = "jdbc:oracle:thin:@localhost:1521:XE";
		 try{
			 Class.forName(jdbc_driver);
		     conn = DriverManager.getConnection(db_url,"scott","tiger");
		     return conn;
		 }catch(Exception e){
			 e.printStackTrace();
		 }finally {
		 }
		 return null;
	}
	
	/**
	 * 평문을 파라미터로 받아서 AES 암호화한 후에 byte[]을 데이터베이스에 저장하고 성공여부를 리턴함
	 * @param plainStr AES 알고리즘으로 암호화하기 위한 평문
	 * @return 암호화된 데이터(byte[])를 데이터베이스에 성공적으로 저장했는지 여부(true, false)
	 */
	public boolean insertEncStr (String plainStr) 
	{
        String key = "Bar12345Bar12345"; // 128 bit key

        Connection conn = null;
		PreparedStatement pstmt = null;
		
        try {
	        // Create key and cipher
	        Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
	        Cipher cipher = Cipher.getInstance("AES");
	
	        // encrypt the text
	        cipher.init(Cipher.ENCRYPT_MODE, aesKey);
	        byte[] encrypted = cipher.doFinal(plainStr.getBytes());
	
	        // 필요하다면 아래처럼 Base64 문자열로 인코딩하여 웹상의 URL 등에서도 사용할 수 있다
	        String base64Str = Base64Enc(encrypted);
	        System.out.println("Base64 인코딩 문자열="+base64Str);
	        
	        // Base64 인코딩된 문자열을 다시 원래의 byte[]형으로 복원하려면...
	        byte[] decodedBytes = Base64Dec(base64Str);
	        System.out.println("Base64디코딩 결과="+Arrays.equals(encrypted, decodedBytes));
	        
	        String enc_str =  new String(encrypted);
	        System.out.println("암호화 결과="+enc_str);
			
			String sql = "insert into enc_tb (num, enc_data) values (1,?)";
			
			conn = getConn();

			pstmt = conn.prepareStatement(sql);
			pstmt.setBytes(1, encrypted);

			int n = pstmt.executeUpdate();
			return n>0 ? true : false;
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			try {
				pstmt.close();
				conn.close();
			} catch (SQLException e) {

			}
		}
		return false;
	}
	
	/**
	 * 데이터베이스의 BLOB 컬럼에 저장된 암호화된 데이터를 추출하여 복호화하고 원래 문자열로 인코딩하여 리턴함
	 * @return 복호화하고 원래 문자열로 인코딩된 문자열
	 */
	public String getEncStr() {

        String key = "Bar12345Bar12345"; // 128 bit key
        
        Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
        try {
			String sql = "select * from enc_tb where num=1";
			
			conn = getConn();
		
			pstmt = conn.prepareStatement(sql);

			rs = pstmt.executeQuery();
			
			if(rs.next()) {
				byte[] encrypted = rs.getBytes("ENC_DATA");

				Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
		        Cipher cipher = Cipher.getInstance("AES");

		        // decrypt the text
		        cipher.init(Cipher.DECRYPT_MODE, aesKey);
		        String decrypted = new String(cipher.doFinal(encrypted));

		        System.out.println("복호화된 결과:" + decrypted);
		        return decrypted;
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			try {
				rs.close();
				pstmt.close();
				conn.close();
			} catch (SQLException e) {

			}
		}
		return null;
	}
	
	// 암호화된 데이터(byte[]형)를 받아서 Base64문자열로 인코딩하여 리턴한다
	private String Base64Enc(byte[] encrypted) {
		Base64 base64 = new Base64();
		String base64Str = new String(base64.encode(encrypted));
		return base64Str;
	}
	
	// Base64인코딩된 문자열을 원래의 데이터(byte[]형)로 디코딩한다
	private byte[] Base64Dec(String base64Str) {
		Base64 base64 = new Base64();
		byte[] restoredBytes = base64.decode(base64Str.getBytes());
		return restoredBytes;
	}

	/**
	 * 위의 기능을 테스트하기 위한 main 메소드
	 * @param args
	 */
    public static void main(String[] args) {

    	AES_DB_Test app = new AES_DB_Test();

    	//암호화, DB저장, DB출력, 복호화 수행 테스트
    	String plainText = "Test 문자열 123";
    	
    	//평문을 암호화하여 DB에 byte[] 형으로 저장함
    	app.insertEncStr(plainText);
    	
    	//DB에 저장된 암호화된 데이터를 byte[] 형으로 추출하고 복호화하여 원래의 문자열로 복원함
    	String db_out = app.getEncStr();
    	
    	//원래의 문자열을 암호화, DB저장, DB출력, 복호화, 문자열화 과정을 거친후
    	//최종적인 문자열과 원래의 문자열을 비교하여 동일한지 테스트한다
    	System.out.println("복호화결과 원래의 데이터와 동일성 여부="+plainText.equals(db_out));

    }
}