====== Oracle DMBS Crypto ======
* [[https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_crypto.htm#BJFGFDFG|DBMS_CRYPTO]]
* DB 의존적인 암호화 코드 사용은 절대 **비권장**
===== 활성화 및 권한 부여 =====
Oracle 에 ''SYS'' 계정으로 접근하여
@$ORACLE_HOME/rdbms/admin/dbmsobtk.sql
@$ORACLE_HOME/rdbms/admin/prvtobtk.plb
grant execute on dbms_crypto to [계정명];
grant execute on dbms_obfuscation_toolkit to [계정명];
-- 모든 사용자에게 권한 추가
-- grant execute on dbms_crypto to public;
-- grant execute on dbms_obfuscation_toolkit to public;
===== 함수 =====
* ''DBMS_CRYPTO.ENCRYPT'' : 암호화 수행. 암호화 데이터 인자로 byte 배열(RAW)를 받음. byte 배열(RAW) 반환.
* ''DBMS_CRYPTO.DECRYPT'' : 복호화 수행. 복호화 데이터 인자로 hex 문자열 받음. byte 배열(RAW) 반환.
===== DBMS_CRYOPTO 상수 읽기 =====
* ''DBMS_CRYPTO.*'' 의 상수들은 PL/SQL 블럭에서만 읽을 수 있다.
begin
dbms_output.put_line(dbms_crypto.DES_CBC_PKCS5);
end;
/
===== 알고리즘 =====
* Oracle ''dbms_crypto.DES_CBC_PKCS5'' -> Java ''DES/CBC/PKCS5Padding''
===== Key =====
* 암호화의 비밀번호
===== Vector =====
* ''CBC'' 모드 등에서 필요하다.
* 필수는 아니다.
* 벡터가 필요 없는 상황에서 Java 는 아래와 같이 empty vector 를 사용하면 된다.
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
===== Oracle 암호화 -> Java 복호화 =====
* Oracle은 표준 암호화를 사용하기 때문에 표준을 이해하면 Java 전환이 어렵지 않다.
* [[https://www.esentri.com/oracle-dbms_crypto-to-java-the-first-steps/|Oracle DBMS_Crypto to Java: The First Steps - esentri AG]] : Java <-> Oracle 상호간 암호화/복호화에 대한 기본 이론.
-- byte 배열(RAW) 결과
select DBMS_CRYPTO.encrypt(UTL_RAW.CAST_TO_RAW ('Secret Data'), 4353
, UTL_RAW.CAST_TO_RAW ('MYKEY123'),UTL_RAW.CAST_TO_RAW('01234567')) from dual;
-- VARCHAR2 로 cast 하면 hex 문자열이 나온다.
SELECT CAST(DBMS_CRYPTO.encrypt(UTL_RAW.CAST_TO_RAW ('Secret Data'), 4353, UTL_RAW.CAST_TO_RAW ('MYKEY123'),UTL_RAW.CAST_TO_RAW('01234567')) AS VARCHAR2(100)) FROM dual;
-- 결과 : 963C9ABD5C20382996DF9E0849F28C45
* ''UTL_RAW.CAST_TO_RAW ('Secret Data')'' 암호화할 데이터(''Secret Data'')를 binary로
* 유니코드의 경우 ''UTL_I18N.STRING_TO_RAW('암호화할 데이터', 'AL32UTF8')'' 형태로 ''UTF-8'' byte로.
* 유니코드에서 RAW(byte[])를 다시 문자열로 변경은 ''UTL_I18N.RAW_TO_CHAR('RAW 데이터', 'AL32UTF8')''
* ''4353'' 알고리즘 ID : ''dbms_crypto.DES_CBC_PKCS5'' 값이다. 이는 사실 여러 알고리즘을 나타내는''DBMS_CRYPTO.상수'' 들의 합이다.
* ''UTL_RAW.CAST_TO_RAW ('MYKEY123')'' : 비밀번호(Key) binary
* ''UTL_RAW.CAST_TO_RAW('01234567')'' Vector. 선택적임.
위와 같이 암호화된 데이터를 Java 로 복호화
public void testDecryption() {
String CIPHER = "DES/CBC/PKCS5Padding";
byte[] key = DatatypeConverter.parseHexBinary("4D594B4559313233"); // "MYKEY123".getBytes("UTF-8") 와 같다.
byte[] value =
DatatypeConverter.parseHexBinary("963C9ABD5C20382996DF9E0849F28C45"); // 암호화 결과의 hex
String INIT_VECTOR =
new String(DatatypeConverter.parseHexBinary("3031323334353637"));
SecretKeySpec secretKeySpec=new SecretKeySpec(key, "DES");
IvParameterSpec ivParameterSpec=null;
try {
ivParameterSpec=new IvParameterSpec(INIT_VECTOR.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
Cipher decryptCipher=null;
try {
decryptCipher= Cipher.getInstance(CIPHER);
decryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec,ivParameterSpec);
} catch (NoSuchAlgorithmException | NoSuchPaddingException |InvalidKeyException
| InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
String result="";
try {
result=new String(decryptCipher.doFinal(value),Charset.forName("UTF-8"));
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
System.out.println("Result " + result); // Result Secret Data
}
* Java 에서는 ''AES256''을 사용하라면 [[java:jce|Java JCE(Java Cryptography Extension)]] 를 설치해야한다.
* Java 에서는 hex 를 byte 배열 로 다시 변환하려면 ''javax.xml.bind.DatatypeConverter#parseHexBinary'' 를 사용한다.
* 반대로 Java 에서 byte 배열을 hex 로 변환하기 - [[https://stackoverflow.com/questions/9655181/how-to-convert-a-byte-array-to-a-hex-string-in-java|bytearray - How to convert a byte array to a hex string in Java? - Stack Overflow]]
byte bytes[] = {(byte)0, (byte)0, (byte)134, (byte)0, (byte)61};
String hex = javax.xml.bind.DatatypeConverter.printHexBinary(bytes);
// 혹은 apache commons codec
import org.apache.commons.codec.binary.Hex;
...
Hex.encodeHexString(someByteArray));
===== 참조 =====
* [[https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_crypto.htm|Database PL/SQL Packages and Types Reference]]
* [[http://kkujunhee.net/bbs/board.php?bo_table=db&wr_id=49|DBMS_CRYPTO 암호화 라이브러리 추가하기 > 데이터베이스 | kkujunhee.net]]
* [[http://www.gurubee.net/lecture/1200|오라클에서의 데이터 암호화 기능]]
* [[https://dzone.com/articles/data-encryptiondecryption-with-oracle|Data Encryption and Decryption With Oracle - DZone Database]]
* [[https://www.programcreek.com/java-api-examples/javax.crypto.Cipher|Java Code Examples for javax.crypto.Cipher]]
* [[http://blog.daum.net/wiznel/4653840|ORACLE AES 암호화]]
* [[https://thebook.io/006696/part04/ch19/01/03/|오라클 SQL과 PL/SQL을 다루는 기술: 암호화 실습]]
* [[http://www.dbguide.net/db.db?cmd=view&boardUid=173073&boardConfigUid=9&categoryUid=216&boardIdx=107&boardStep=1|UTL_I18N]]
* [[https://technet.tmaxsoft.com/upload/download/online/tibero/pver-20160406-000002/tibero_pkg/chap_dbms_crypto.html|제6장 DBMS_CRYPTO]]