目录
如何在Oracle 11g PL / SQL软件包(带有某些JAVA帮助器)中使用RSA公钥加密数据
最近,我需要使用提供的RSA公钥从Oracle PL / sQL包中加密某些信息,以便能够与以这种方式进行身份验证的Web服务进行通信。
在互联网上进行了一些研究之后,我找不到任何可行的解决方案(免费)。找到了许多概念、想法、零碎的解释或付费软件,但是花了比平常更多的时间和精力才能找到一个可行的解决方案,我必须自己动手完成大部分工作。
因此,我决定将其发布以供公众了解。
首先,确保以正确的方式配置环境很重要:
1、您需要确保ORACLE DB已安装JAVA VM。您可以通过以下方式进行检查:
select comp_name, version, status from dba_registry;
如果不存在,则必须以SYS身份登录并执行以下操作:
SQL> @$ORACLE_HOME/javavm/install/initjvm.sql;
一旦安装了JavaVM,便一切就绪。
2、出于本文的目的,我们将使用公共密钥对密码进行加密,因此,它可以在另一端使用相应的私钥进行发送和解密。但是我们将需要:
就我而言,我正在使用Oracle(11g)11.2.0.4。
我们需要了解的第一件事是,ORACLE不提供(在版本11g中)非对称密码学的库。DBMS_CRYPTO软件包将仅提供对称加密。
因此,我们需要创建自己的类来处理它。而且我们将需要使用Java来实现。创建或替换并编译名为rsa_crypto的Java源文件为:
import javax.crypto.*;
import java.security.spec.*;
import java.security.*; //PublicKey
public class RSACrypto
{
public static byte[] Encrypt(byte[] cert, byte[] data)
throws Throwable //NoSuchAlgorithmException, InvalidKeySpecException,
//InvalidKeyException, IllegalBlockSizeException,
//NoSuchPaddingException, BadPaddingException
{
byte[] encryptedData = null;
try {
//Generate Public Key with Cert
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(cert);
PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);
//Encrypt
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
encryptedData = cipher.doFinal(data);
return encryptedData;
} catch (Exception e) {
System.out.println( "Unexpected error - " + e.getMessage());
encryptedData = e.getMessage().getBytes();
throw e;
}
}
}
我们的函数将接收2个字节的数组(证书内容和要加密的数据),并将返回带有加密的Data的字节数组。
我们将创建我们的包,并在其主体内声明以下private函数:
function rsa_encrypt(cert raw, data raw) return raw
AS LANGUAGE JAVA
NAME 'RSACrypto.Encrypt(byte[], byte[]) return byte[]';
然后我们将拥有我们的login函数,该函数将通过以下方式使用我们的JAVA函数:
c_certini constant varchar2(50) := '-----BEGIN PUBLIC KEY-----';
c_certend constant varchar2(50) := '-----END PUBLIC KEY-----';
c_dirname constant varchar2(255) := 'DIRX';
c_key_filename constant varchar2(255) := 'rsa.public';
function login return number is
passpost raw(1024);
res varchar2(1024);
v_fexist boolean;
v_flen number;
v_bsize binary_integer;
v_key utl_file.file_type;
v_cert raw(2048);
v_buffer varchar2(2048);
begin
-- Check and Read Certificate
utl_file.fgetattr(c_dirname, c_key_filename, v_fexist, v_flen, v_bsize);
if not v_fexist then
dbms_output.put_line(c_dirname || '/' || c_key_filename || ' Not Found.');
return -3;
end if;
v_key := utl_file.fopen(c_dirname, c_key_filename,'R');
utl_file.get_raw(v_key,v_cert,v_flen);
utl_file.fclose(v_key);
dbms_output.put_line('Cert Read: ' || utl_raw.cast_to_varchar2(v_cert));
v_buffer := utl_raw.cast_to_varchar2(v_cert);
-- Strip beginning and end.
v_buffer := replace(v_buffer,c_certini,'');
v_buffer := replace(v_buffer,c_certend,'');
v_cert := utl_encode.base64_decode(utl_raw.cast_to_raw(v_buffer));
dbms_output.put_line('Cert Strip: [' || v_buffer || ']');
--Call to JAVA function
begin
passpost:=rsa_encrypt(v_cert,utl_raw.cast_to_raw('Password'));
exception when others then
dbms_output.put_line('Cannot encrypt ' || SQLERRM);
return -4;
end;
if passpost is null then
return -2;
end if;
res:= utl_raw.cast_to_varchar2(utl_encode.base64_encode(passpost));
dbms_output.put_line('Encrypted Signature: ' || res);
return 0;
end;
基本上,我们:打开文件,读取文件内容,并将其传递给Java函数Base64Decoded。Java函数将使用接收到的Content创建一个公共密钥,并用它加密数据并返回它。我们将对返回的数据进行64位编码,然后将其用于我们需要的任何其他内容。