Oracle-11g
在 Oracle pl/sql 中復製或呼叫 java 加密函式
我正在嘗試在 Oracle DB 中複製 java 中存在的加密/解密方法,以便可以通過 Oracle 函式對 java 中加密的數據進行解密。
下面是java程式碼:
package com.encr; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class EncrUtil { private static Cipher cipher = null; public static void aesInit(String inKey) throws Exception { String methodName = "aesInit"; try { byte[] inkeyBytes = inKey.getBytes("utf-8"); System.out.println("inkeyBytes="+inkeyBytes.toString()); final SecretKeySpec clientkey = new SecretKeySpec(inkeyBytes, "AES"); cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); final IvParameterSpec iv = new IvParameterSpec(new byte[32]); cipher.init(Cipher.ENCRYPT_MODE,clientkey,iv); } catch (NoSuchAlgorithmException e) { throw new Exception("NoSuchAlgorithmException", e); } catch (NoSuchPaddingException e) { throw new Exception("NoSuchPaddingException", e); } } public static String encrypt(String inData,String inKey) { String methodName = "encrypt"; String strCipherText = null; try { if ( null != inData && null != inKey) { if(EncrUtil.cipher == null){ EncrUtil.aesInit(inKey); } byte[] byteDataToEncrypt = inData.getBytes("utf-8"); System.out.println(byteDataToEncrypt.toString()); byte[] byteCipherText = cipher.doFinal(byteDataToEncrypt); System.out.println(byteCipherText.toString()); strCipherText = new BASE64Encoder().encode(byteCipherText); } } catch (Exception e) { String sErrMsg = "Text to be encrypted: " + inData; sErrMsg = new StringBuffer(methodName).append( sErrMsg) .append( " Message: ") .append(e.getMessage()).toString(); strCipherText = sErrMsg; } return strCipherText; } public static String decrypt(String inData,String inKey) { String methodName = "decrypt"; String strDecryptedText = null; try { byte[] inkeyBytes = inKey.getBytes("utf-8"); final SecretKeySpec clientkey = new SecretKeySpec(inkeyBytes, "AES"); cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); final IvParameterSpec iv = new IvParameterSpec(new byte[16]); cipher.init(Cipher.DECRYPT_MODE,clientkey,iv); byte[] decodedData = new BASE64Decoder().decodeBuffer(inData); byte[] byteDecryptedText = cipher.doFinal(decodedData); strDecryptedText = new String(byteDecryptedText); } catch (Exception e) { String sErrMsg = "Text to be decrypted: " + inData; sErrMsg = new StringBuffer(methodName).append(sErrMsg) .append( "Message:") .append(e.getMessage()).toString(); strDecryptedText = sErrMsg; } return strDecryptedText; } public static void main(String[] args) { String inKey= "84hf763bht096hnf"; String inData= "Vikram"; System.out.println("Word to be encrypted is "+inData); String encrypted = EncrUtil.encrypt(inData,inKey); System.out.println("Encrpted word is"+encrypted); } }
我嘗試複製的 Oracle Pl/sql 函式是
CREATE OR REPLACE PACKAGE BODY SYS.enc_dec AS encryption_type PLS_INTEGER := DBMS_CRYPTO.ENCRYPT_AES + DBMS_CRYPTO.CHAIN_CBC + DBMS_CRYPTO.PAD_PKCS5; encryption_key RAW (32) := UTL_I18N.STRING_TO_RAW ('84hf763bht096hnf', 'AL32UTF8'); FUNCTION encrypt (p_plainText VARCHAR2) RETURN RAW DETERMINISTIC IS encrypted_raw RAW (2000); BEGIN DBMS_OUTPUT.PUT_LINE(UTL_RAW.CAST_TO_VARCHAR2(encryption_key)); encrypted_raw := DBMS_CRYPTO.ENCRYPT ( --src => UTL_RAW.CAST_TO_RAW (p_plainText), src =>UTL_I18N.STRING_TO_RAW (p_plainText,'AL32UTF8'), typ => encryption_type, key => encryption_key ); RETURN encrypted_raw; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(SUBSTR(SQLERRM, 1, 100)); END encrypt; FUNCTION decrypt (p_encryptedText RAW) RETURN VARCHAR2 DETERMINISTIC IS decrypted_raw RAW (2000); BEGIN decrypted_raw := DBMS_CRYPTO.DECRYPT ( src => p_encryptedText, typ => encryption_type, key => encryption_key ); RETURN (UTL_I18N.RAW_TO_CHAR(decrypted_raw,'AL16UTF8')); EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(SUBSTR(SQLERRM, 1, 100)); END decrypt; END;
上面程式碼完成的加密與java中的不同請讓我知道我在oracle函式中哪裡出錯了或者請告訴我如何在oracle中添加java方法,在教程中我找不到如何包含導入甲骨文中的java。
我能夠將 Java 程式碼移至 Oracle。我正在為面臨類似問題的人寫這篇文章。
- 通過Putty登錄到安裝Oracle數據庫的伺服器(windows的命令行提示符)
- 使用 WinSCP 將 Java 文件放在伺服器中。
- 使用命令查找 oracle home 中存在的 Java 編譯器
find / -name javac
- 使用Oracle的Java編譯器編譯Java文件作為數據庫使用的Java版本和通常使用的Java版本會有所不同
$ORACLE_HOME/jdk/bin/javac /home/vikram/EncrUtil.java
注意:可以直接將文件
.class
或文件載入到數據庫中,而不是在數據庫伺服器上編譯。.jar
但請確保使用與數據庫相同的 Java 版本。查找oracle使用的java版本
$ORACLE_HOME/jdk/bin/java -version java version "1.5.0_17" Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_17-b03) Java HotSpot(TM) 64-Bit Server VM (build 1.5.0_17-b03, mixed mode)
- 如果未設置,則設置 ORACLE_HOME
export ORACLE_HOME=/database/ora11gr2/product/11.2.0/dbhome_1/
- 在路徑中添加
loadjava
’s 目錄(即數據庫的 bin 目錄)export PATH=$PATH:$ORACLE_HOME/bin
**注意:**如果發現類未找到異常,請通過“loadjava”檢查是否正確設置了路徑或定義了變數不是定義那些 7. 將類載入到數據庫中
loadjava -user <user>/<password>@xxx.xxx.xxx.xxxx:1521:<instance> \ -thin –resolve /home/vikram/ EncrUtil.class
-resolve
用於.class
在載入到數據庫之前解析文件,因為它易於在數據庫外部調試 Java。-thin
用於瘦客戶端
- 載入類後,在其上創建一個包裝器函式,以便它可以在數據庫中使用
CREATE OR REPLACE FUNCTION TEST_DECRYPTOR(indata IN VARCHAR2) RETURN VARCHAR2 AS LANGUAGE JAVA NAME ' EncrUtil. decrypt (java.lang.String) return java.lang.String'; CREATE OR REPLACE FUNCTION TEST_ENCRYPTOR (indata IN VARCHAR2) RETURN VARCHAR2 AS LANGUAGE JAVA NAME ' EncrUtil. encrypt (java.lang.String) return java.lang.String';
- 然後可以像使用任何其他 Oracle 函式一樣使用此函式:
SELECT TEST_ENCRYPTOR('Vikram') FROM DUAL;
有點晚了,但答案可能有用:
在 Java 中,應更改此行:
final IvParameterSpec iv = new IvParameterSpec(new byte[16]);
進入這個:
final IvParameterSpec iv = new IvParameterSpec(new String(Base64.decode('vector_inicializacion')).getBytes());
其中 vector_inicializacion 是 16 的任意十六進制,但在 PL/SQL 中它必須相同。
和
strDecryptedText = new String(byteDecryptedText);
應該替換為
strDecryptedText = new String(Base64.encodeBytes(byteDecryptedText))
在 PL 中:
encrypted_raw := DBMS_CRYPTO.ENCRYPT ( --src => UTL_RAW.CAST_TO_RAW (p_plainText), src =>UTL_I18N.STRING_TO_RAW (p_plainText,'AL32UTF8'), typ => encryption_type, key => encryption_key IV => UTL_RAW.CAST_TO_RAW ('vector_inicializacion') );