02.Oracle/DataBase2009. 4. 28. 13:13
반응형

오라클에서의 데이터 암호화 기능

1. 설 명

☞ Bulletin no : 12036 참고

 
Oracle 8i Release2(8.1.6)에서는 데이터를 암호화하여 저장할 수 있는
향상된 기능(DES Encryption)을 제공 합니다
 
 
신용카드번호, 패스워드 등 보안이 필요한 데이터를 암호화된 형태로 저장하여
기존의 3rd Party Tool이나, Application Logic으로 구현하던 암호화 정책을
데이터베이스 차원에서 구현할 수 있도록 해줍니다.
 
일단 암호화의 결과의 길이는 8의 배수로 나옵니다.
자리수가 8이하는 8자리, 8초과 16이하는 16자리...
'123'을 암호화하면 그 자리수는 8자리가 나오지요

 
DBMS_OBFUSCATION_TOOLKIT

암호화 기능을 이용하려면 DBMS_OBFUSCATION_TOOLKIT을 이용해야 합니다.
 
 
이 패키지는 4개의 프로시져로 이루어져 있습니다.

- VARCHAR2 타입을 Encrypt/Decrypt할 수 있는 2개의 프로시져

- RAW 타입을 Encrypt/Decrypt할 수 있는 2개의 프로시져
(다른 타입은 지원하지 않으므로 number인 경우는 to_char 이용)
 
 

DBMS_OBFUSCATION_TOOLKIT을 이용하기 위해서는 :

1) SYS 유저로 아래의 스크립트를 실행 시킵니다.

   @$ORACLE_HOME/rdbms/admin/dbmsobtk.sql
   @$ORACLE_HOME/rdbms/admin/prvtobtk.plb
   
2) 권한을 부여 합니다.

   SQL>GRANT execute ON dbms_obfuscation_toolkit TO public;



2. 패키지 실행하기



--> 패키지 선언부 생성

CREATE OR REPLACE PACKAGE CryptIT AS
   FUNCTION encrypt( Str VARCHAR2,  
                     hash VARCHAR2 ) RETURN VARCHAR2;

   FUNCTION decrypt( xCrypt VARCHAR2,
                     hash VARCHAR2 ) RETURN VARCHAR2;
END CryptIT;
/
 
 
 
--> 패키지 본체 생성

CREATE OR REPLACE PACKAGE BODY CryptIT AS
   crypted_string VARCHAR2(2000);
 
   FUNCTION encrypt( Str VARCHAR2,  
                     hash VARCHAR2 ) RETURN VARCHAR2 AS
   pieces_of_eight INTEGER := ((FLOOR(LENGTH(Str)/8 + .9)) * 8);
 
   BEGIN
 
      dbms_obfuscation_toolkit.DESEncrypt(
               input_string     => RPAD( Str, pieces_of_eight ),
               key_string       => RPAD(hash,8,’#’),
               encrypted_string => crypted_string );
      RETURN crypted_string;
   END;
 
   FUNCTION decrypt( xCrypt VARCHAR2,
                     hash VARCHAR2 ) RETURN VARCHAR2 AS
   BEGIN
      dbms_obfuscation_toolkit.DESDecrypt(
               input_string     => xCrypt,
               key_string       => RPAD(hash,8,’#’),
               decrypted_string => crypted_string );
      RETURN trim(crypted_string);
   END;
END CryptIT;
/

 



3. 실행 예제


1) Encrypt하여 데이터 입력

-- 테스트 테이블을 생성 합니다.

SQL>create table encrypt_table( id number, passwd varchar(20) );


 
-- 테스트 데이트럴 입력 합니다.
-- CryptIT.encrypt(비밀번호, 키값)

SQL>INSERT INTO encrypt_table VALUES( 1, CryptIT.encrypt(’1234’, ’storm’));
1 개의 행이 만들어졌습니다.

 
SQL>INSERT INTO encrypt_table VALUES( 2, CryptIT.encrypt(’5678’, ’oramaster’));
1 개의 행이 만들어졌습니다.

 
 
2) Decrypt하여 데이터 조회
 
--> Decrypt하지 않으면 암호화된 데이터와 비교되서 결과값이 출력되지 않습니다.
SQL> select id, passwd from encrypt_table where passwd = ’1234’;
 
선택된 레코드가 없습니다.
 
 
--> 저장장치에 Encrypt된 값으로 저장 됩니다.

SQL> col passwd format a60
SQL> select id, dump(passwd) passwd from encrypt_table;

         ID PASSWD
---------- -------------------------------------------------------------
         1 Typ=1 Len=8: 246,27,80,184,227,225,245,31
         2 Typ=1 Len=8: 175,231,213,125,85,223,46,133
 


--> Encrypt할 때 사용한 Key로만 Decrypt할 수 있습니다.
 
SQL>SELECT id, CryptIT.decrypt(passwd,’storm’) passwd
       FROM encrypt_table
       WHERE CryptIT.decrypt(passwd,’storm’) = ’1234’;
 
        ID PASSWD
---------- -----------
         1 1234
 
 
SQL>SELECT id, CryptIT.decrypt(passwd,’oramaster’) passwd
    FROM encrypt_table
    WHERE CryptIT.decrypt(passwd,’oramaster’) = ’5678’;
 
        ID PASSWD
---------- -----------
         2 5678
 
 
주의) Table에 접근 권한이 있는 다른 유저도 Key값을 알면 Decrypt할 수 있습니다.
 
 
 
4) 관련 ORA error number
 
ORA error 28231 "Invalid input to Obfuscation toolkit"
- input data, key값이 NULL일 경우 발생
 
ORA error 28232 "Invalid input size for Obfuscation toolkit"
- input data가 8 bytes 배수가 아닐 경우 발생
 
ORA error 28233 "Double encryption not supported by DESEncrypt in Obfuscation toolkit"
- encrypt data를 다시 encrypt경우 발생
 

관 련 자 료
===========
Oracle8i Supplied PL/SQL Packages Reference Release 2 (8.1.6)

 
암호화 하는 프로시저 소스를 암호화하여 보안하자~
암호화 Stored Function을 하나 만들어 wrap사용하시면 됩니다.

복호화는 만들지 안으시는게 좋습니다. (정히 필요하시면 만드시고)
복호화 함수가 있으면 개발자에 의하여 노출될 우려가 있습니다.

암호화 Stored Function => sf_encrypt
wrap iname=/mydir/sf_encrypt.sql oname=/mydir/sf_encrypt.plb
/mydir/sf_encrypt.plb 파일를 이용하여 DB에 rap된 sf_encrypt를 만들고


입력
INSERT INTO encrypt_table VALUES( 1, sf_encrypt('1234'));

SELECT id, '*****' as passwd
FROM encrypt_table
WHERE passwd = sf_encrypt('1234');

이런식으로 사용하시면 인덱스 사용 가능합니다.
 
 
 
========================================================================================================================
========================================================================================================================
 
 
 
일부 서비스에 대해 오라클 DB 버전을 9i에서 10g로 변경하면서, 암호화 패키지 CRYPTIT에서 일부 문제가 있었다.

9i에서 암호화된 테이블을 10g로 가져와서 다음과 같이 decrypt 를 쿼리하면 에러가 발생했다.

select CRYPTIT.decrypt(passwd, 'keyvalue) from user_tbl

ORA-28232: obfuscation 툴킷에 부적합한 입력 길이입니다.
ORA-06512: "SYS.DBMS_OBFUSCATION_TOOLKIT_FFI", 줄 40에서
ORA-06512: "SYS.DBMS_OBFUSCATION_TOOLKIT", 줄 153에서
ORA-06512: "WLOWN.CRYPTIT", 줄 20에서


처음에는 일부 데이터는 정상으로 조회되길래 무슨 문제인가 찾아봐도 뽀죡한 답변을 못찾았다.

좀 삽질하다가 9i와 10g의 sys user의 DBMS_OBFUSCATION_TOOLKIT의 함수내용이 틀린 것을 보고,
암호화 데이터를 다시 갱신해 줫다.

update user_tbl set passwd = CRYPTIT.encrypt(raw_pass, 'keyvalue')

그런후 다시 조회하니 잘 된다. 역시 오라클 버전이 틀려짐에 따라 암호화 내용이 달라진 거 같다.



=========================================================================================================================

=========================================================================================================================




CREATE OR REPLACE PACKAGE CRYPTIT
AS
   FUNCTION ENCRYPT (STR VARCHAR2)
      RETURN VARCHAR2;

   FUNCTION DECRYPT (XCRYPT VARCHAR2)
      RETURN VARCHAR2;
END CRYPTIT;
/



CREATE OR REPLACE PACKAGE BODY CRYPTIT
AS
   CRYPTED_STRING   VARCHAR2 (2000);
   HASH_KEY   VARCHAR2 (10) := '암호화키';

   FUNCTION ENCRYPT (STR VARCHAR2)
      RETURN VARCHAR2
   AS
      PIECES_OF_EIGHT   INTEGER := ((FLOOR (LENGTH (STR) / 8 + .9)) * 8);
   BEGIN
      DBMS_OBFUSCATION_TOOLKIT.DESENCRYPT (INPUT_STRING          => RPAD (STR, PIECES_OF_EIGHT)
                                         , KEY_STRING            => RPAD (HASH_KEY, 8, '#')
                                         , ENCRYPTED_STRING      => CRYPTED_STRING
                                          );
      RETURN CRYPTED_STRING;
   END;

   FUNCTION DECRYPT (XCRYPT VARCHAR2)
      RETURN VARCHAR2
   AS
   BEGIN
      DBMS_OBFUSCATION_TOOLKIT.DESDECRYPT (INPUT_STRING          => XCRYPT
                                         , KEY_STRING            => RPAD (HASH_KEY, 8, '#')
                                         , DECRYPTED_STRING      => CRYPTED_STRING
                                          );
      RETURN TRIM (CRYPTED_STRING);
   END;
END CRYPTIT;
/

Posted by 1010