Oracle-11g

在 Oracle pl/sql 中復製或呼叫 java 加密函式

  • January 22, 2019

我正在嘗試在 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。我正在為面臨類似問題的人寫這篇文章。

  1. 通過Putty登錄到安裝Oracle數據庫的伺服器(windows的命令行提示符)
  2. 使用 WinSCP 將 Java 文件放在伺服器中。
  3. 使用命令查找 oracle home 中存在的 Java 編譯器
find / -name javac
  1. 使用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)
  1. 如果未設置,則設置 ORACLE_HOME
export ORACLE_HOME=/database/ora11gr2/product/11.2.0/dbhome_1/
  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用於瘦客戶端
  1. 載入類後,在其上創建一個包裝器函式,以便它可以在數據庫中使用
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';
  1. 然後可以像使用任何其他 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') 
   );

引用自:https://dba.stackexchange.com/questions/47696