2014-04-01

Oracle 9i SHA-256알고리즘 데이터 암호화 적용절차.



1. 아래의 사이트에서 오라클 9I에 적용된 Oracle JVM JDK1.3 버젼에 맞는 확장 라이브러리를 다운로드 받는다.
    
      http://www.bouncycastle.org/latest_releases.html

       >>> http://www.bouncycastle.org/download/jce-jdk13-150.jar

       >>> http://www.bouncycastle.org/download/jce-ext-jdk13-150.jar

2. LoadJava 툴을 이용하여 다운로드 받은 라이브러리를 오라클에 등록시킨다.
     
          C:\>loadjava -u sys/비밀번호@서비스명 jce*150.jar

3. 오라클에 sys (sysdba)로 접속하여 로드된 자바 클랙스 라이브러리의 상태를 확인하고 invalid상태의 오브젝트를 다시 컴파일 한다.

/* Formatted on 2014/04/01 09:55 (Formatter Plus v4.8.7) */
BEGIN    
    FOR rec IN (SELECT *                  
             FROM all_objects                 
             WHERE status <> 'VALID' 
             AND object_type = 'JAVA CLASS')    
     LOOP       
         BEGIN          
              EXECUTE IMMEDIATE    'ALTER JAVA CLASS SYS."'       || rec.object_name        || '" COMPILE';       
         EXCEPTION          
               WHEN OTHERS          THEN             
                    DBMS_OUTPUT.put_line (SQLERRM);       
         END;    
     END LOOP;
END;

4.  라이브러리를 이용하여 실제 데이터를 암호화, 복호화 하는 클랙스를 생성한다.

CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "DCrypto" AS
import java.security.MessageDigest;
import java.security.Security;
import java.security.NoSuchAlgorithmException;

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

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jcajce.provider.digest.BCMessageDigest;
import org.bouncycastle.jcajce.provider.digest.SHA256;

import sun.misc.BASE64Encoder;


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

/*  참조 사이트 */
/* http://stackoverflow.com/questions/2208374/how-can-i-create-an-sha512-digest-string-in-java-using-bouncy-castle */
/* http://blog.daum.net/_blog/BlogTypeView.do?blogid=0ZDJJ&articleno=25&_bloghome_menu=recenttext */

public class DCrypto {

private static byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
private static byte[] IV = new byte[] { 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00 };
private static SecretKeySpec key = null;
private static String secKey = "SEED" ;  
private static String seedMethod = "SEED/CBC/PKCS5Padding";

/* 데이터 암호와 복호화를 위해  SEED 알고리즘을 사용한다. */
        /* srcStr 을 암호화 한다. */
public static String encrypt(String srcStr) throws Exception {
byte[] input = srcStr.getBytes(); 
Security.addProvider(new BouncyCastleProvider());

      key = new SecretKeySpec(keyBytes, secKey); 
IvParameterSpec ivSpec = new IvParameterSpec(IV); 
Cipher cipher = Cipher.getInstance(seedMethod, "BC"); 
cipher.init(Cipher.ENCRYPT_MODE, key,ivSpec); 
byte[] cipherText = cipher.doFinal(input); 


return String.valueOf(Hex.encodeHex(cipherText));

/* 암호화된 문자열을 복호화 한다. */
public static String decrypt(String encStr) throws Exception {

   byte[] input = (Hex.decodeHex(encStr.toCharArray()));
   Security.addProvider(new BouncyCastleProvider());
   key = new SecretKeySpec(keyBytes, secKey);
   IvParameterSpec ivSpec = new IvParameterSpec(IV); 
   Cipher cipher = Cipher.getInstance(seedMethod, "BC"); 
   cipher.init(Cipher.DECRYPT_MODE, key,ivSpec); 
   byte[] decryptedText = cipher.doFinal(input); 
   return new String(decryptedText);

/*  비밀번호 암호화를 위해   SHA-256, SHA-512 알고리즘을 이용한다. */
public static String decrytSHA256(String sourceStr) {
String result = "";
try {
Security.addProvider(new BouncyCastleProvider());
MessageDigest mda = MessageDigest.getInstance("SHA-256", "BC");
byte [] digesta = mda.digest(sourceStr.getBytes());

BASE64Encoder encoder = new BASE64Encoder();
result = encoder.encode(digesta);
} catch(Exception e) {
    result = ""; //e.getMessage();
}
return result;
}

public static String decryptSHA512(String sourceStr) {
String result = "";
try {
Security.addProvider(new BouncyCastleProvider());
MessageDigest mda = MessageDigest.getInstance("SHA-512", "BC");
byte [] digesta = mda.digest(sourceStr.getBytes());

BASE64Encoder encoder = new BASE64Encoder();
result = encoder.encode(digesta);
} catch(Exception e) {
    result = ""; //e.getMessage();
}
return result;
}
}

/


5. 해당 자바클랙스를 호출하여 쿼리문에서 사용할 수 있도록 패키지 또는 함수를 생성한다.

/* Formatted on 2014/04/01 10:12 (Formatter Plus v4.8.7) */
CREATE OR REPLACE PACKAGE cryptoAS    
FUNCTION decrypt (str_in VARCHAR2)       RETURN VARCHAR2;    
FUNCTION encrypt (str_in VARCHAR2)       RETURN VARCHAR2;    
FUNCTION encryptsha256 (str_in VARCHAR2)       RETURN VARCHAR2;    
FUNCTION encryptsha512 (str_in VARCHAR2)       RETURN VARCHAR2;
END;
/ 

CREATE OR REPLACE PACKAGE BODY cryptoAS    
    FUNCTION decrypt (str_in VARCHAR2)       RETURN VARCHAR2    
    AS       
        LANGUAGE JAVA       NAME 'DCrypto.decrypt(java.lang.String) return java.lang.String';    

    FUNCTION encrypt (str_in VARCHAR2)       RETURN VARCHAR2    
    AS       
        LANGUAGE JAVA       NAME 'DCrypto.encrypt(java.lang.String) return java.lang.String';    

    FUNCTION encryptsha256 (str_in VARCHAR2)       RETURN VARCHAR2    
    AS       
        LANGUAGE JAVA       NAME 'DCrypto.encryptSHA256(java.lang.String) return java.lang.String';    

    FUNCTION encryptsha512 (str_in VARCHAR2)       RETURN VARCHAR2    
    AS       
        LANGUAGE JAVA       NAME 'DCrypto.encryptSHA256(java.lang.String) return java.lang.String';
END;
/

6. sys유저로 생성된 객체를 다른 유저(스키마)에서 사용가능 하도록 시노님을 생성하고 권한을 부여한다.

CREATE PUBLIC SYNONYM CRYPTO FOR SYS.CRYPTO;

GRANT EXECUTE ON SYS.CRYPTO TO {데이터베이스유저1};

GRANT EXECUTE ON SYS.CRYPTO TO {데이터베이스유저2};

 7. 실제 사용 예제는 다음과 같다.

6번항목에서 권한을 부여한 사용자로 로그인 해서 아래의 쿼리로 테스트 한다. select CRYPTO.encrypt('test') from dual; 
select crypto.decrypt(crypto.encrypt('test')) from dual; 
select crypto.encryptSha256('010-5210-6848') from dual; 
select crypto.encryptSha512('010-5210-6848') from dual;

(실행결과)
——————————————————————
CRYPTO.ENCRYPT('TEST')                                                         
--------------------------------------------------------------------------------
UGOrhKh0YPlRJPX15DwIzQ==                                                       

1 row selected.

CRYPTO.DECRYPT(CRYPTO.ENCRYPT('TEST'))                                         
--------------------------------------------------------------------------------
test                                                                           

1 row selected.

CRYPTO.ENCRYPTSHA256('010-5210-6848')                                          
--------------------------------------------------------------------------------
AXLKeNy6+BmgogkI4blEcDlPIyKoPFWyNJtaK1l1wzE=                                   

1 row selected.

CRYPTO.ENCRYPTSHA512('010-5210-6848')                                          
--------------------------------------------------------------------------------
WPlGpM9F+E8mne0RiO3Da5mcb7gNHPUfNXzHQDQB6dQe/bNu3ZCPiHRpLrEipeWv/HsOnykdRvAh   
depIDUKUYg==                                                                   
                                                                               

1 row selected.

댓글 10개:

  1. 컴파일 완료후에 프로시져나 함수 패키지를 통해 해당 클래스를 사용하고자 할때 권한 관련 오류가 발생하면 아래와 같이 권한을 부여하도록 한다.

    Security.addProvider(new BouncyCastleProvider()); 이 문장때문에 권한이 필요하다.

    exec dbms_java.grant_permission( {오라클유저명}, 'SYS:java.security.SecurityPermission', 'putProviderProperty.BC', '' );

    exec dbms_java.grant_permission( {오라클유저명}, 'SYS:java.security.SecurityPermission', 'insertProvider.BC', '' )

    답글삭제
  2. 안녕하세요. 종이없는 연말정산 관련 내용 잘 보았습니다.
    그런데 한가지 문제점이 있는데 xmltype에서 xml이 길어지면 문제가 발생하던데 해결방법좀
    여쭈어 봐도 되겠습니까?

    답글삭제
  3. 어떤 에러가 발생하던가요?

    답글삭제
    답글
    1. 댓글이 등록이 안되었나봅니다.
      xml이 길어질 경우에
      "[Error] Execution (10: 37): ORA-01704: 문자열이 너무 깁니다"
      라는 문제가 발생합니다.

      삭제
    2. 9i에서 잠깐 테스트 해봤는데 에러가 발생하는 군요...xmltype의 최대 용량을 초과해서 발생하는 문제라 지금으로선 대처 방안이 생각나질 않네요...ㅡㅡ;;;

      삭제
  4. 설치하는 자바클래스의 라이센스가 상용소프트웨어에서 사용해도 되나요?

    답글삭제
  5. 라이브러리가 상용일 경우 라이센스를 구입해야 할것 같습니다...

    답글삭제
  6. 안녕하세여.
    암호화 관련 한 내용을 오라클에 적용할려고 여기 저기 찾는도중 도움을 주실 수 있을거 같아 문의 드립니다.

    AES256암호화를 java로 만들고 그 내용을 오라클에 loadjava를 이용하여 업로드 이후 호출 할려고 하는데 잘 안되어 문의 드립니다.

    환경
    oracle : 9i
    JDK : 1.3
    import jar파일
    loadjava -resolve -verbose -grant public -user bcshqadm/bcshqadm jce1_2_2.jar
    loadjava -resolve -verbose -grant public -user bcshqadm/bcshqadm US_export_policy.jar
    loadjava -resolve -verbose -grant public -user bcshqadm/bcshqadm local_policy.jar
    loadjava -resolve -verbose -grant public -user bcshqadm/bcshqadm sunjce_provider.jar

    위와 같이 필요한 jar파일을 loadjava를 이용하여 올린 후
    AES256관련 JAVA파일을 올렸습니다.

    loadjava를 이용하여 import한 java파일이 INVALID난곳이 없는데

    java파일을 FUNCTION으로 생성한 것을 오라클에서 호출하면 아래와 같은 메세지가 나옵니다.

    Execution (7: 1): ORA-29532: 자바 호출이 잡혀지지 않은 자바 예외로 인해 종료되었습니다: java.lang.NoClassDefFoundError
    위와 같은 오류가 나오구 실행이 되지 않습니다.

    혹시 아시는 해결방안이 있으시면 고견 부탁드립니다.

    답글삭제
    답글
    1. 자바클래스 자체에 오류가 있는 경우에도 에러가 발생합니다. 자바객체를 오라클에 정상적으로 로드 되었더라도 자바 자체의 오류가 있을 경우에는 실행시 오류가 발생할 수 있습니다. 일단은 간단한 클래스(덧셈 뺄셈등..)를 하나 만드셔서 loadjava로 올려서 적용해보시고 해당 정상적으로 처리됨을 확인하시고 해당 절차대로 원하는 클래스나 라이브러리를 로딩하셔서 테스트 해보셔야 할듯 합니다.

      삭제
  7. 작성자가 댓글을 삭제했습니다.

    답글삭제

-------------------------------------------------------
스마트폰 기종 :
OS버젼 :
-------------------------------------------------------
문제점 및문의 :